@evo-dev/core 0.0.1-alpha.5 → 0.0.1-alpha.7

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
@@ -120,6 +120,7 @@ __export(exports_candidates, {
120
120
  readEvolutionReviewSnapshot: () => readEvolutionReviewSnapshot,
121
121
  readEvolutionRepoProposalById: () => readEvolutionRepoProposalById,
122
122
  readEvolutionKnowledgeRecordById: () => readEvolutionKnowledgeRecordById,
123
+ markEvolutionRepoProposalApplied: () => markEvolutionRepoProposalApplied,
123
124
  listEvolutionKnowledgeReviewHistory: () => listEvolutionKnowledgeReviewHistory,
124
125
  listEvolutionKnowledgeRecords: () => listEvolutionKnowledgeRecords,
125
126
  listEvolutionEvosCases: () => listEvolutionEvosCases
@@ -1167,23 +1168,64 @@ async function updateEvolutionRepoProposalReviewState(input) {
1167
1168
  }
1168
1169
  };
1169
1170
  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 });
1171
+ await writeRepoProposalAndIndex({ homeDir: input.homeDir, proposal: next, changedAt });
1172
+ return { path, record: next, changed: true };
1173
+ });
1174
+ }
1175
+ async function markEvolutionRepoProposalApplied(input) {
1176
+ return await withEvolutionReviewDecisionLock({ homeDir: input.homeDir, kind: "repo-proposal", itemId: input.proposalId }, async () => {
1177
+ const record = await readEvolutionRepoProposalById(input);
1178
+ if (!hasConcreteRepoProposalChanges(record)) {
1179
+ throw new Error("Repo proposal has no concrete repository changes to apply.");
1180
+ }
1181
+ if (input.expectedReviewState !== undefined && record.reviewState !== input.expectedReviewState) {
1182
+ throw new Error("Repo proposal review state changed before it was marked applied.");
1183
+ }
1184
+ const paths = resolveEvolutionPaths({
1185
+ homeDir: input.homeDir,
1186
+ projectKey: record.projectKey,
1187
+ runId: record.provenance.runId
1188
+ });
1189
+ const path = join3(paths.repoProposalsDir, `${record.id}.json`);
1190
+ if (record.reviewState === "applied")
1191
+ return { path, record, changed: false };
1192
+ if (record.reviewState !== "accepted") {
1193
+ throw new Error("Only accepted repo proposals can be marked applied.");
1194
+ }
1195
+ const changedAt = normalizeTimestamp2(input.now);
1196
+ const next = {
1197
+ ...record,
1198
+ reviewState: "applied",
1199
+ reviewStateChangedAt: changedAt
1200
+ };
1201
+ validateEvolutionRepoProposal(next);
1202
+ await writeRepoProposalAndIndex({ homeDir: input.homeDir, proposal: next, changedAt });
1184
1203
  return { path, record: next, changed: true };
1185
1204
  });
1186
1205
  }
1206
+ async function writeRepoProposalAndIndex(input) {
1207
+ const paths = resolveEvolutionPaths({
1208
+ homeDir: input.homeDir,
1209
+ projectKey: input.proposal.projectKey,
1210
+ runId: input.proposal.provenance.runId
1211
+ });
1212
+ await writeJsonFile(join3(paths.repoProposalsDir, `${input.proposal.id}.json`), input.proposal, {
1213
+ overwrite: true
1214
+ });
1215
+ const allRunProposals = await readJsonFiles(paths.repoProposalsDir, parseRepoProposal);
1216
+ await writeJsonFile(paths.repoProposalsIndexPath, {
1217
+ schemaVersion: 1,
1218
+ projectKey: input.proposal.projectKey,
1219
+ runId: input.proposal.provenance.runId,
1220
+ updatedAt: input.changedAt,
1221
+ proposals: allRunProposals.map((proposal) => ({
1222
+ id: proposal.id,
1223
+ kind: proposal.kind,
1224
+ title: proposal.title,
1225
+ reviewState: proposal.reviewState
1226
+ }))
1227
+ }, { overwrite: true });
1228
+ }
1187
1229
  function parseKnowledgeReviewHistoryRecord(value) {
1188
1230
  if (!isRecord2(value))
1189
1231
  throw new Error("Knowledge review history record must be an object.");
@@ -4567,16 +4609,6 @@ var DEFAULT_AGENT_PERMISSIONS = {
4567
4609
  };
4568
4610
  var FORBIDDEN_INPUTS = ["rawPrompts", "secrets", "rawCommandLogs", "sourceCorpus"];
4569
4611
  var SAFE_AGENT_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,99}$/;
4570
- var PRIVACY_ADVISORY_PATTERN = /raw prompt|rawprompt|source corpus|sourcecorpus|secret|\.env|raw command|raw log|internal url|private url|network|write files|run commands|spawn agents|write memory/i;
4571
- var LENS_TO_EXPERTISE = {
4572
- review: ["code-review"],
4573
- qa: ["qa", "verification"],
4574
- security: ["security", "privacy"],
4575
- release: ["release", "packaging"],
4576
- architecture: ["architecture"],
4577
- migration: ["migration", "impact-analysis"],
4578
- test: ["testing"]
4579
- };
4580
4612
  function createDefaultAgentPermissions() {
4581
4613
  return { ...DEFAULT_AGENT_PERMISSIONS };
4582
4614
  }
@@ -4623,50 +4655,6 @@ function parseAgentProfile(value) {
4623
4655
  async function readAgentProfile(path) {
4624
4656
  return parseAgentProfile(JSON.parse(await readFile4(path, "utf8")));
4625
4657
  }
4626
- function composeAgentDryRun(input) {
4627
- const mode = input.contract.route.mode;
4628
- const workflowId = input.workflowId ?? input.contract.route.workflowId;
4629
- const warnings = [];
4630
- const permissions = createDefaultAgentPermissions();
4631
- const requestedLenses = dedupeLenses(input.lenses ?? []);
4632
- const advisories = collectPrivacyBoundaryAdvisories(input.contract, requestedLenses, workflowId);
4633
- if (mode === "minimal") {
4634
- return {
4635
- ok: advisories.length === 0,
4636
- taskId: input.contract.taskId,
4637
- mode,
4638
- workflowId,
4639
- agents: [],
4640
- permissions,
4641
- mergePlan: createMergePlan([]),
4642
- warnings,
4643
- advisories,
4644
- rationale: "Minimal mode does not force dynamic agents by default."
4645
- };
4646
- }
4647
- const selectedLenses = selectLenses(mode, requestedLenses, workflowId, input.contract.route.requiredReview);
4648
- const agents = selectedLenses.map((lens) => ({
4649
- profile: createDynamicProfile(lens, input.contract, permissions),
4650
- lens,
4651
- reason: createLensReason(lens, mode, workflowId),
4652
- plannedOnly: true
4653
- }));
4654
- if (mode === "standard" && agents.length > 1) {
4655
- warnings.push("Standard mode advisory selected more than one reviewer/triager.");
4656
- }
4657
- return {
4658
- ok: advisories.length === 0,
4659
- taskId: input.contract.taskId,
4660
- mode,
4661
- workflowId,
4662
- agents,
4663
- permissions,
4664
- mergePlan: createMergePlan(agents),
4665
- warnings,
4666
- advisories,
4667
- rationale: agents.length === 0 ? "No dynamic agents selected; deterministic verification may be sufficient." : `Selected ${agents.length} planned-only agent(s) based on mode/workflow/lenses.`
4668
- };
4669
- }
4670
4658
  function loadAgentContextDryRun(profile) {
4671
4659
  const parsed = parseAgentProfile(profile);
4672
4660
  return {
@@ -4760,36 +4748,6 @@ function mergeReviewFindings(outputs) {
4760
4748
  }
4761
4749
  return { acceptedFindings: [...byKey.values()], unresolvedConflicts: conflicts };
4762
4750
  }
4763
- function formatAgentComposeDryRun(plan) {
4764
- return [
4765
- "EvoDev agent compose dry-run",
4766
- "",
4767
- `Task: ${plan.taskId}`,
4768
- `Mode: ${plan.mode ?? "not routed"}`,
4769
- `Workflow: ${plan.workflowId ?? "none"}`,
4770
- `Rationale: ${plan.rationale}`,
4771
- "No-write/no-spawn: true",
4772
- "Privacy: local-private, metadata-only, raw prompts/source/secrets/logs forbidden",
4773
- "Agents:",
4774
- ...plan.agents.length === 0 ? [" - none"] : plan.agents.map((agent) => ` - ${agent.profile.id} [${agent.lens}] traits=${agent.profile.traits.expertise.join(",")} schema=${agent.profile.output.schema} plannedOnly=${agent.plannedOnly}`),
4775
- "Inputs:",
4776
- ...plan.agents.length === 0 ? [" - none"] : [
4777
- ` - required: ${plan.agents[0].profile.inputs.required.join(",")}`,
4778
- ` - optional: ${plan.agents[0].profile.inputs.optional.join(",")}`,
4779
- ` - forbidden: ${plan.agents[0].profile.inputs.forbidden.join(",")}`
4780
- ],
4781
- "Permissions:",
4782
- ...Object.entries(plan.permissions).map(([key, value]) => ` - ${key}: ${value}`),
4783
- "Merge plan:",
4784
- ` - strategy: ${plan.mergePlan.strategy}`,
4785
- ` - outputSchema: ${plan.mergePlan.outputSchema ?? "none"}`,
4786
- "Warnings:",
4787
- ...plan.warnings.length === 0 ? [" - none"] : plan.warnings.map((warning) => ` - ${warning}`),
4788
- "Advisories:",
4789
- ...plan.advisories.length === 0 ? [" - none"] : plan.advisories.map((advisory) => ` - ${advisory}`)
4790
- ].join(`
4791
- `);
4792
- }
4793
4751
  function formatAgentContextDryRun(bundle) {
4794
4752
  return [
4795
4753
  "EvoDev agent load-context dry-run",
@@ -4807,98 +4765,6 @@ function formatAgentContextDryRun(bundle) {
4807
4765
  ].join(`
4808
4766
  `);
4809
4767
  }
4810
- function createDynamicProfile(lens, contract, permissions) {
4811
- return {
4812
- version: 1,
4813
- id: `dynamic-${lens}-${contract.taskId}`.slice(0, 100),
4814
- name: `Dynamic ${lens} reviewer`,
4815
- persistence: "dynamic",
4816
- description: `Task-scoped ${lens} profile for metadata-only dry-run planning.`,
4817
- traits: {
4818
- expertise: LENS_TO_EXPERTISE[lens],
4819
- stance: ["skeptical-reviewer"],
4820
- approach: ["evidence-first", "advisory"],
4821
- domain: ["software-rd"]
4822
- },
4823
- inputs: {
4824
- required: ["taskContract", "scope", "evidenceSummary"],
4825
- optional: ["workflowPlan"],
4826
- forbidden: FORBIDDEN_INPUTS
4827
- },
4828
- permissions,
4829
- output: {
4830
- schema: "review-findings-v1",
4831
- requiredFields: ["summary", "findings", "confidence", "evidenceRefs"]
4832
- },
4833
- privacy: {
4834
- classification: "local-private",
4835
- metadataOnly: true,
4836
- rawPromptStored: false,
4837
- sourceContentStored: false
4838
- }
4839
- };
4840
- }
4841
- function selectLenses(mode, requested, workflowId, requiredReview) {
4842
- if (requested.length > 0)
4843
- return mode === "standard" ? requested.slice(0, 1) : requested;
4844
- if (mode === "standard")
4845
- return requiredReview.length > 0 ? ["review"] : [];
4846
- if (mode === "rigorous") {
4847
- if (workflowId?.includes("security"))
4848
- return ["security", "review"];
4849
- if (workflowId?.includes("release"))
4850
- return ["release", "security"];
4851
- if (workflowId?.includes("migration"))
4852
- return ["migration", "architecture"];
4853
- if (workflowId?.includes("architecture"))
4854
- return ["architecture", "review"];
4855
- return requiredReview.length > 0 ? ["review", "qa"] : [];
4856
- }
4857
- return [];
4858
- }
4859
- function createMergePlan(agents) {
4860
- if (agents.length === 0)
4861
- return {
4862
- strategy: "none",
4863
- outputSchema: null,
4864
- dedupeBy: [],
4865
- conflictPolicy: [],
4866
- advisoryCategories: []
4867
- };
4868
- if (agents.length === 1)
4869
- return {
4870
- strategy: "single-output",
4871
- outputSchema: agents[0].profile.output.schema,
4872
- dedupeBy: [],
4873
- conflictPolicy: [],
4874
- advisoryCategories: []
4875
- };
4876
- return {
4877
- strategy: "dedupe-preserve-conflicts",
4878
- outputSchema: "review-findings-v1",
4879
- dedupeBy: ["category", "path", "line", "title"],
4880
- conflictPolicy: ["preserve dissent", "keep higher severity unless evidence refutes"],
4881
- advisoryCategories: ["security", "privacy", "release"]
4882
- };
4883
- }
4884
- function createLensReason(lens, mode, workflowId) {
4885
- return `${lens} lens selected for ${mode ?? "unrouted"} mode${workflowId ? ` and workflow ${workflowId}` : ""}.`;
4886
- }
4887
- function collectPrivacyBoundaryAdvisories(contract, lenses, workflowId) {
4888
- const text2 = [
4889
- contract.source.summary,
4890
- contract.currentState.summary,
4891
- contract.targetState.summary,
4892
- contract.route.rationale,
4893
- workflowId ?? "",
4894
- ...contract.scope.allowedOperations,
4895
- ...contract.scope.requiresUserConfirmation,
4896
- ...lenses
4897
- ].join(" ");
4898
- return PRIVACY_ADVISORY_PATTERN.test(text2) ? [
4899
- "Agent planning detected privacy/risky context requiring raw data, writes, commands, network, spawning, or memory."
4900
- ] : [];
4901
- }
4902
4768
  function validateRequiredObject(output, fields) {
4903
4769
  if (!isRecord4(output))
4904
4770
  return { ok: false, errors: ["Output must be an object."] };
@@ -4911,9 +4777,6 @@ function normalizeAgentPermissions(value) {
4911
4777
  function isKnownOutputSchema(value) {
4912
4778
  return value === "review-findings-v1" || value === "verification-summary-v1" || value === "design-options-v1";
4913
4779
  }
4914
- function dedupeLenses(lenses) {
4915
- return [...new Set(lenses)];
4916
- }
4917
4780
  function severityRank(severity) {
4918
4781
  return { info: 0, low: 1, medium: 2, high: 3, critical: 4 }[severity];
4919
4782
  }
@@ -5141,8 +5004,12 @@ __export(exports_code_agent_traces, {
5141
5004
  listCodeAgentTraceRefs: () => listCodeAgentTraceRefs,
5142
5005
  createCodeAgentTraceRef: () => createCodeAgentTraceRef
5143
5006
  });
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";
5007
+ import { mkdir as mkdir5, readFile as readFile7, readdir as readdir7, stat as stat5, writeFile as writeFile4 } from "node:fs/promises";
5008
+ import { dirname as dirname6, isAbsolute as isAbsolute5, join as join8, normalize, relative as relative5 } from "node:path";
5009
+
5010
+ // packages/core/src/projects/index.ts
5011
+ import { lstat, readFile as readFile6, readdir as readdir6, realpath, stat as stat4 } from "node:fs/promises";
5012
+ import { basename, dirname as dirname5, isAbsolute as isAbsolute4, join as join7, parse } from "node:path";
5146
5013
 
5147
5014
  // packages/core/src/runtime-logs/index.ts
5148
5015
  var exports_runtime_logs = {};
@@ -5613,6 +5480,299 @@ function isRecord5(value) {
5613
5480
  return typeof value === "object" && value !== null && !Array.isArray(value);
5614
5481
  }
5615
5482
 
5483
+ // packages/core/src/projects/index.ts
5484
+ class ProjectRegistrationError extends Error {
5485
+ code;
5486
+ constructor(code, message) {
5487
+ super(message);
5488
+ this.name = "ProjectRegistrationError";
5489
+ this.code = code;
5490
+ }
5491
+ }
5492
+ function resolveProjectRegistryPaths(homeDir) {
5493
+ const paths = resolveEvoDevPaths(homeDir);
5494
+ const discoveredDir = join7(paths.stateDir, "projects", "discovered");
5495
+ const registeredDir = join7(paths.rootDir, "projects");
5496
+ return {
5497
+ discoveredDir,
5498
+ registeredDir,
5499
+ discoveredPath: (projectKey) => join7(discoveredDir, `${projectKey}.json`),
5500
+ registeredPath: (projectKey) => join7(registeredDir, projectKey, "workspace.json")
5501
+ };
5502
+ }
5503
+ async function resolveProjectWorkspaceFromCwd(input) {
5504
+ if (!isAbsolute4(input.cwd))
5505
+ return null;
5506
+ let cwd;
5507
+ try {
5508
+ const info = await stat4(input.cwd);
5509
+ if (!info.isDirectory())
5510
+ return null;
5511
+ cwd = await realpath(input.cwd);
5512
+ } catch (error) {
5513
+ if (isNotFoundError(error))
5514
+ return null;
5515
+ throw error;
5516
+ }
5517
+ const gitRoot = await findNearestGitRoot(cwd);
5518
+ const workspaceRoot = gitRoot ?? cwd;
5519
+ return {
5520
+ projectKey: sanitizeStorageId(resolveProjectLogKey(input.homeDir, workspaceRoot), "project"),
5521
+ displayName: basename(workspaceRoot) || parse(workspaceRoot).root,
5522
+ workspaceRoot,
5523
+ workspaceKind: gitRoot === null ? "directory" : "git",
5524
+ cwd
5525
+ };
5526
+ }
5527
+ async function recordDiscoveredProject(input) {
5528
+ const workspace = await resolveProjectWorkspaceFromCwd(input);
5529
+ if (workspace === null)
5530
+ return null;
5531
+ const now = normalizeTimestamp(input.now);
5532
+ const paths = resolveProjectRegistryPaths(input.homeDir);
5533
+ const path = paths.discoveredPath(workspace.projectKey);
5534
+ const existing = await readDiscoveredProject(path);
5535
+ const record = {
5536
+ schemaVersion: 1,
5537
+ kind: "discovered-project",
5538
+ projectKey: workspace.projectKey,
5539
+ displayName: workspace.displayName,
5540
+ workspaceRoot: workspace.workspaceRoot,
5541
+ lastCwd: workspace.cwd,
5542
+ workspaceKind: workspace.workspaceKind,
5543
+ sourceTargets: mergeTargets(existing?.sourceTargets ?? [], [input.target]),
5544
+ lastSessionKey: normalizeSessionKey(input.sessionKey ?? existing?.lastSessionKey ?? null),
5545
+ firstSeenAt: existing?.firstSeenAt ?? now,
5546
+ lastSeenAt: now,
5547
+ localOnly: true,
5548
+ sourceContentStored: false
5549
+ };
5550
+ await writeJsonFile(path, record);
5551
+ return { record, path };
5552
+ }
5553
+ async function listDiscoveredProjects(input) {
5554
+ const paths = resolveProjectRegistryPaths(input.homeDir);
5555
+ const records = new Map;
5556
+ for (const path of await listJsonFilePaths(paths.discoveredDir)) {
5557
+ const record = await readDiscoveredProject(path);
5558
+ if (record !== null)
5559
+ mergeDiscoveredRecord(records, record);
5560
+ }
5561
+ for (const binding of await listLegacyHookBindings(input.homeDir)) {
5562
+ if (binding.cwd === null)
5563
+ continue;
5564
+ const workspace = await resolveProjectWorkspaceFromCwd({
5565
+ homeDir: input.homeDir,
5566
+ cwd: binding.cwd
5567
+ });
5568
+ if (workspace === null)
5569
+ continue;
5570
+ mergeDiscoveredRecord(records, {
5571
+ schemaVersion: 1,
5572
+ kind: "discovered-project",
5573
+ projectKey: workspace.projectKey,
5574
+ displayName: workspace.displayName,
5575
+ workspaceRoot: workspace.workspaceRoot,
5576
+ lastCwd: workspace.cwd,
5577
+ workspaceKind: workspace.workspaceKind,
5578
+ sourceTargets: [binding.target],
5579
+ lastSessionKey: normalizeSessionKey(binding.sessionKey),
5580
+ firstSeenAt: binding.updatedAt,
5581
+ lastSeenAt: binding.updatedAt,
5582
+ localOnly: true,
5583
+ sourceContentStored: false
5584
+ });
5585
+ }
5586
+ return [...records.values()].sort((left, right) => right.lastSeenAt.localeCompare(left.lastSeenAt) || left.projectKey.localeCompare(right.projectKey));
5587
+ }
5588
+ async function listRegisteredProjects(input) {
5589
+ const { registeredDir } = resolveProjectRegistryPaths(input.homeDir);
5590
+ const records = [];
5591
+ for (const projectKey of await listDirectoryNames2(registeredDir)) {
5592
+ const record = await readRegisteredProject(join7(registeredDir, projectKey, "workspace.json"));
5593
+ if (record !== null && record.projectKey === projectKey)
5594
+ records.push(record);
5595
+ }
5596
+ return records.sort((left, right) => right.lastSeenAt.localeCompare(left.lastSeenAt) || left.projectKey.localeCompare(right.projectKey));
5597
+ }
5598
+ async function registerDiscoveredProject(input) {
5599
+ assertProjectKey(input.projectKey);
5600
+ const paths = resolveProjectRegistryPaths(input.homeDir);
5601
+ const path = paths.registeredPath(input.projectKey);
5602
+ const existing = await readRegisteredProject(path);
5603
+ if (existing !== null)
5604
+ return { record: existing, path, changed: false };
5605
+ const discovered = (await listDiscoveredProjects({ homeDir: input.homeDir })).find((record2) => record2.projectKey === input.projectKey);
5606
+ if (discovered === undefined) {
5607
+ throw new ProjectRegistrationError("not-found", "The project must be discovered by a local Code Agent session before it can be added.");
5608
+ }
5609
+ const record = {
5610
+ schemaVersion: 1,
5611
+ kind: "registered-project",
5612
+ projectKey: discovered.projectKey,
5613
+ displayName: discovered.displayName,
5614
+ workspaceRoot: discovered.workspaceRoot,
5615
+ workspaceKind: discovered.workspaceKind,
5616
+ registeredAt: normalizeTimestamp(input.now),
5617
+ lastSeenAt: discovered.lastSeenAt,
5618
+ localOnly: true,
5619
+ sourceContentStored: false
5620
+ };
5621
+ try {
5622
+ await writeJsonFile(path, record, { overwrite: false });
5623
+ return { record, path, changed: true };
5624
+ } catch (error) {
5625
+ if (!isFileExistsError(error))
5626
+ throw error;
5627
+ const concurrent = await readRegisteredProject(path);
5628
+ if (concurrent !== null)
5629
+ return { record: concurrent, path, changed: false };
5630
+ throw new ProjectRegistrationError("conflict", "The project registration already exists.");
5631
+ }
5632
+ }
5633
+ async function findNearestGitRoot(cwd) {
5634
+ let current = cwd;
5635
+ for (;; ) {
5636
+ try {
5637
+ const marker = await lstat(join7(current, ".git"));
5638
+ if (marker.isDirectory() || marker.isFile())
5639
+ return current;
5640
+ } catch (error) {
5641
+ if (!isNotFoundError(error))
5642
+ throw error;
5643
+ }
5644
+ const parent = dirname5(current);
5645
+ if (parent === current)
5646
+ return null;
5647
+ current = parent;
5648
+ }
5649
+ }
5650
+ async function readDiscoveredProject(path) {
5651
+ try {
5652
+ return parseDiscoveredProject(JSON.parse(await readFile6(path, "utf8")));
5653
+ } catch (error) {
5654
+ if (isNotFoundError(error) || error instanceof ProjectRegistrationError)
5655
+ return null;
5656
+ throw error;
5657
+ }
5658
+ }
5659
+ async function readRegisteredProject(path) {
5660
+ try {
5661
+ return parseRegisteredProject(JSON.parse(await readFile6(path, "utf8")));
5662
+ } catch (error) {
5663
+ if (isNotFoundError(error) || error instanceof ProjectRegistrationError)
5664
+ return null;
5665
+ throw error;
5666
+ }
5667
+ }
5668
+ function parseDiscoveredProject(value) {
5669
+ const record = requireRecord(value);
5670
+ if (record.schemaVersion !== 1 || record.kind !== "discovered-project" || !isProjectKey(record.projectKey) || !isNonEmptyString2(record.displayName) || !isAbsoluteString(record.workspaceRoot) || !isAbsoluteString(record.lastCwd) || !isWorkspaceKind(record.workspaceKind) || !isDiscoveryTargetArray(record.sourceTargets) || !(record.lastSessionKey === null || isNonEmptyString2(record.lastSessionKey)) || !isNonEmptyString2(record.firstSeenAt) || !isNonEmptyString2(record.lastSeenAt) || record.localOnly !== true || record.sourceContentStored !== false) {
5671
+ throw new ProjectRegistrationError("invalid", "Discovered project record is invalid.");
5672
+ }
5673
+ return record;
5674
+ }
5675
+ function parseRegisteredProject(value) {
5676
+ const record = requireRecord(value);
5677
+ if (record.schemaVersion !== 1 || record.kind !== "registered-project" || !isProjectKey(record.projectKey) || !isNonEmptyString2(record.displayName) || !isAbsoluteString(record.workspaceRoot) || !isWorkspaceKind(record.workspaceKind) || !isNonEmptyString2(record.registeredAt) || !isNonEmptyString2(record.lastSeenAt) || record.localOnly !== true || record.sourceContentStored !== false) {
5678
+ throw new ProjectRegistrationError("invalid", "Registered project record is invalid.");
5679
+ }
5680
+ return record;
5681
+ }
5682
+ function mergeDiscoveredRecord(records, next) {
5683
+ const previous = records.get(next.projectKey);
5684
+ if (previous === undefined) {
5685
+ records.set(next.projectKey, next);
5686
+ return;
5687
+ }
5688
+ const newer = next.lastSeenAt >= previous.lastSeenAt ? next : previous;
5689
+ records.set(next.projectKey, {
5690
+ ...newer,
5691
+ sourceTargets: mergeTargets(previous.sourceTargets, next.sourceTargets),
5692
+ firstSeenAt: previous.firstSeenAt <= next.firstSeenAt ? previous.firstSeenAt : next.firstSeenAt,
5693
+ lastSeenAt: previous.lastSeenAt >= next.lastSeenAt ? previous.lastSeenAt : next.lastSeenAt
5694
+ });
5695
+ }
5696
+ function mergeTargets(left, right) {
5697
+ return [...new Set([...left, ...right])].sort();
5698
+ }
5699
+ function normalizeSessionKey(value) {
5700
+ if (value === null || value === undefined)
5701
+ return null;
5702
+ return /^session-[a-f0-9]{16}$/u.test(value) ? value : `session-${sha256Short(value)}`;
5703
+ }
5704
+ async function listLegacyHookBindings(homeDir) {
5705
+ const roots = [
5706
+ join7(homeDir, ".evodev", "state", "hooks", "sessions"),
5707
+ join7(homeDir, ".evodev", "STATE", "hooks", "sessions")
5708
+ ];
5709
+ const bindings = [];
5710
+ for (const root of roots) {
5711
+ for (const sessionDir of await listDirectoryNames2(root)) {
5712
+ try {
5713
+ const value = JSON.parse(await readFile6(join7(root, sessionDir, "binding.json"), "utf8"));
5714
+ if (value === null || value.target !== "claude" && value.target !== "codex" || !isNonEmptyString2(value.sessionKey) || !(value.cwd === null || isAbsoluteString(value.cwd)) || !isNonEmptyString2(value.updatedAt)) {
5715
+ continue;
5716
+ }
5717
+ bindings.push({
5718
+ target: value.target,
5719
+ sessionKey: value.sessionKey,
5720
+ cwd: value.cwd,
5721
+ updatedAt: value.updatedAt
5722
+ });
5723
+ } catch (error) {
5724
+ if (!isNotFoundError(error) && !(error instanceof SyntaxError))
5725
+ throw error;
5726
+ }
5727
+ }
5728
+ }
5729
+ return bindings;
5730
+ }
5731
+ async function listJsonFilePaths(path) {
5732
+ try {
5733
+ return (await readdir6(path, { withFileTypes: true })).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => join7(path, entry.name)).sort();
5734
+ } catch (error) {
5735
+ if (isNotFoundError(error))
5736
+ return [];
5737
+ throw error;
5738
+ }
5739
+ }
5740
+ async function listDirectoryNames2(path) {
5741
+ try {
5742
+ return (await readdir6(path, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort();
5743
+ } catch (error) {
5744
+ if (isNotFoundError(error))
5745
+ return [];
5746
+ throw error;
5747
+ }
5748
+ }
5749
+ function assertProjectKey(value) {
5750
+ if (!isProjectKey(value)) {
5751
+ throw new ProjectRegistrationError("invalid", "projectKey is invalid.");
5752
+ }
5753
+ }
5754
+ function isProjectKey(value) {
5755
+ return typeof value === "string" && value !== "." && value !== ".." && /^[A-Za-z0-9._-]{1,120}$/.test(value);
5756
+ }
5757
+ function isNonEmptyString2(value) {
5758
+ return typeof value === "string" && value.trim() !== "";
5759
+ }
5760
+ function isAbsoluteString(value) {
5761
+ return isNonEmptyString2(value) && isAbsolute4(value);
5762
+ }
5763
+ function isWorkspaceKind(value) {
5764
+ return value === "git" || value === "directory";
5765
+ }
5766
+ function isDiscoveryTargetArray(value) {
5767
+ return Array.isArray(value) && value.length > 0 && value.every((item) => item === "claude" || item === "codex");
5768
+ }
5769
+ function requireRecord(value) {
5770
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
5771
+ throw new ProjectRegistrationError("invalid", "Project record must be an object.");
5772
+ }
5773
+ return value;
5774
+ }
5775
+
5616
5776
  // packages/core/src/code-agent-traces/index.ts
5617
5777
  var CODE_AGENT_TRACE_TARGETS = ["claude", "codex"];
5618
5778
  var CODE_AGENT_TRACE_REF_SOURCES = [
@@ -5624,11 +5784,11 @@ var CODE_AGENT_TRACE_REF_SOURCES = [
5624
5784
  var SENSITIVE_IDENTIFIER_PATTERN = /https?:\/\/\S+|(^|[^a-z0-9])(secret|token|password|passwd|private|internal|api[_-]?key|apikey|credential|credentials|stdout|stderr|transcript|formattedresponse|additionalcontext)([^a-z0-9]|$)|raw[\s_-]?(payload|prompt|output|source)|source[\s_-]?dump/i;
5625
5785
  var SENSITIVE_PATH_PATTERN = /(^|[/\\._-])(secret|token|password|passwd|api[_-]?key|apikey|credential|credentials)([/\\._-]|$)/i;
5626
5786
  function resolveCodeAgentTraceRefPaths(homeDir) {
5627
- const rootDir = join7(resolveEvoDevPaths(homeDir).stateDir, "code-agent-traces");
5787
+ const rootDir = join8(resolveEvoDevPaths(homeDir).stateDir, "code-agent-traces");
5628
5788
  return {
5629
5789
  rootDir,
5630
- claudeDir: join7(rootDir, "claude"),
5631
- codexDir: join7(rootDir, "codex")
5790
+ claudeDir: join8(rootDir, "claude"),
5791
+ codexDir: join8(rootDir, "codex")
5632
5792
  };
5633
5793
  }
5634
5794
  function createCodeAgentTraceRef(input) {
@@ -5701,7 +5861,7 @@ async function writeCodeAgentTraceRef(input) {
5701
5861
  target: ref.target,
5702
5862
  sessionKey: ref.sessionKey
5703
5863
  });
5704
- await mkdir5(dirname5(path), { recursive: true });
5864
+ await mkdir5(dirname6(path), { recursive: true });
5705
5865
  await writeFile4(path, `${JSON.stringify(ref, null, 2)}
5706
5866
  `, "utf8");
5707
5867
  return { ref, path };
@@ -5713,7 +5873,7 @@ async function readCodeAgentTraceRef(input) {
5713
5873
  target: targetAndSession.target,
5714
5874
  sessionKey: targetAndSession.sessionKey
5715
5875
  });
5716
- const ref = sanitizeCodeAgentTraceRefForWrite(parseCodeAgentTraceRef(JSON.parse(await readFile6(path, "utf8"))));
5876
+ const ref = sanitizeCodeAgentTraceRefForWrite(parseCodeAgentTraceRef(JSON.parse(await readFile7(path, "utf8"))));
5717
5877
  if (ref.id !== input.id)
5718
5878
  throw new Error(`Code Agent trace ref id mismatch: ${input.id}`);
5719
5879
  return { ref, path };
@@ -5727,8 +5887,8 @@ async function listCodeAgentTraceRefs(input) {
5727
5887
  for (const entry of entries) {
5728
5888
  if (!entry.isFile() || !entry.name.endsWith(".json"))
5729
5889
  continue;
5730
- const path = join7(dir, entry.name);
5731
- const ref = sanitizeCodeAgentTraceRefForWrite(parseCodeAgentTraceRef(JSON.parse(await readFile6(path, "utf8"))));
5890
+ const path = join8(dir, entry.name);
5891
+ const ref = sanitizeCodeAgentTraceRefForWrite(parseCodeAgentTraceRef(JSON.parse(await readFile7(path, "utf8"))));
5732
5892
  if (input.projectKey !== undefined && ref.projectKey !== input.projectKey)
5733
5893
  continue;
5734
5894
  if (input.runId !== undefined && ref.runId !== input.runId)
@@ -5763,15 +5923,17 @@ async function recordCodeAgentTraceRefFromHook(input) {
5763
5923
  payload: input.payload,
5764
5924
  environment
5765
5925
  });
5926
+ const cwd = optionalString4(input.payload.cwd);
5927
+ const workspace = team === null && cwd !== null ? await resolveProjectWorkspaceFromCwd({ homeDir: input.homeDir, cwd }) : null;
5766
5928
  const source = sessionIdFromPayload !== null || tracePathFromPayload !== null ? "hook-payload" : "environment";
5767
5929
  const ref = createCodeAgentTraceRef({
5768
5930
  target: input.target,
5769
5931
  sessionKey: resolveTraceSessionKey(input.payload),
5770
5932
  nativeSessionId,
5771
- projectKey: team?.projectKey ?? null,
5933
+ projectKey: team?.projectKey ?? workspace?.projectKey ?? null,
5772
5934
  runId: team?.runId ?? null,
5773
5935
  roleId: team?.roleId ?? null,
5774
- cwd: optionalString4(input.payload.cwd),
5936
+ cwd,
5775
5937
  discoveredAt: input.now,
5776
5938
  source,
5777
5939
  tracePath: normalizedPath,
@@ -5799,7 +5961,7 @@ function sanitizeCodeAgentTraceRefForWrite(ref) {
5799
5961
  });
5800
5962
  }
5801
5963
  function resolveCodeAgentTraceRefPath(input) {
5802
- return join7(resolveCodeAgentTraceRefTargetDir(input.homeDir, input.target), `${sanitizePersistentIdentifier2(input.sessionKey, "session")}.json`);
5964
+ return join8(resolveCodeAgentTraceRefTargetDir(input.homeDir, input.target), `${sanitizePersistentIdentifier2(input.sessionKey, "session")}.json`);
5803
5965
  }
5804
5966
  function resolveCodeAgentTraceRefTargetDir(homeDir, target) {
5805
5967
  const paths = resolveCodeAgentTraceRefPaths(homeDir);
@@ -5816,7 +5978,7 @@ function parseTraceRefId(id) {
5816
5978
  }
5817
5979
  async function readDirectoryEntries(dir) {
5818
5980
  try {
5819
- return await readdir6(dir, { withFileTypes: true });
5981
+ return await readdir7(dir, { withFileTypes: true });
5820
5982
  } catch (error) {
5821
5983
  if (isNotFoundError2(error))
5822
5984
  return [];
@@ -5842,7 +6004,7 @@ function normalizeTracePathForInspection(value, notes) {
5842
6004
  notes.push("trace path omitted: URLs are not stored");
5843
6005
  return null;
5844
6006
  }
5845
- if (!isAbsolute4(trimmed)) {
6007
+ if (!isAbsolute5(trimmed)) {
5846
6008
  notes.push("trace path omitted: relative paths are not trusted");
5847
6009
  return null;
5848
6010
  }
@@ -5868,7 +6030,7 @@ async function inspectTracePath(input) {
5868
6030
  const notes = [];
5869
6031
  let exists = null;
5870
6032
  try {
5871
- await stat4(input.tracePath);
6033
+ await stat5(input.tracePath);
5872
6034
  exists = true;
5873
6035
  } catch (error) {
5874
6036
  if (isNotFoundError2(error)) {
@@ -5886,11 +6048,11 @@ async function inspectTracePath(input) {
5886
6048
  return { exists, trusted, notes };
5887
6049
  }
5888
6050
  function resolveTargetUserDir(input) {
5889
- return normalize(join7(stripTrailingSlash3(input.homeDir), input.target === "claude" ? ".claude" : ".codex"));
6051
+ return normalize(join8(stripTrailingSlash3(input.homeDir), input.target === "claude" ? ".claude" : ".codex"));
5890
6052
  }
5891
6053
  function isDescendant(parent, child) {
5892
6054
  const relation = relative5(normalize(parent), normalize(child));
5893
- return relation === "" || !relation.startsWith("..") && !isAbsolute4(relation);
6055
+ return relation === "" || !relation.startsWith("..") && !isAbsolute5(relation);
5894
6056
  }
5895
6057
  function hasRawTraversalSegment(path) {
5896
6058
  return path.split(/[/\\]+/).some((part) => part === "..");
@@ -6039,6 +6201,7 @@ __export(exports_session_memory, {
6039
6201
  readSessionCursor: () => readSessionCursor,
6040
6202
  readLineRange: () => readLineRange,
6041
6203
  parseSessionMemoryPolicy: () => parseSessionMemoryPolicy,
6204
+ listSessionMemoryStates: () => listSessionMemoryStates,
6042
6205
  listSessionEvidenceSegments: () => listSessionEvidenceSegments,
6043
6206
  createDefaultSessionMemoryPolicy: () => createDefaultSessionMemoryPolicy,
6044
6207
  appendRawEvent: () => appendRawEvent,
@@ -6046,24 +6209,24 @@ __export(exports_session_memory, {
6046
6209
  });
6047
6210
 
6048
6211
  // packages/core/src/evolution/evidence/session-memory/paths.ts
6049
- import { join as join8 } from "node:path";
6212
+ import { join as join9 } from "node:path";
6050
6213
  function resolveSessionMemoryPaths(input) {
6051
- const rootDir = join8(resolveEvoDevPaths(input.homeDir).stateDir, "session-memory");
6214
+ const rootDir = join9(resolveEvoDevPaths(input.homeDir).stateDir, "session-memory");
6052
6215
  const projectKey = sanitizeStorageId(input.projectKey, "project");
6053
6216
  const sessionKey = sanitizeStorageId(input.sessionKey, "session");
6054
- const projectDir = join8(rootDir, projectKey);
6055
- const sessionDir = join8(projectDir, sessionKey);
6056
- const segmentsDir = join8(sessionDir, "segments");
6217
+ const projectDir = join9(rootDir, projectKey);
6218
+ const sessionDir = join9(projectDir, sessionKey);
6219
+ const segmentsDir = join9(sessionDir, "segments");
6057
6220
  return {
6058
6221
  rootDir,
6059
6222
  projectDir,
6060
6223
  sessionDir,
6061
- statePath: join8(sessionDir, "state.json"),
6062
- cursorPath: join8(sessionDir, "cursor.json"),
6063
- eventsPath: join8(sessionDir, "events.jsonl"),
6224
+ statePath: join9(sessionDir, "state.json"),
6225
+ cursorPath: join9(sessionDir, "cursor.json"),
6226
+ eventsPath: join9(sessionDir, "events.jsonl"),
6064
6227
  segmentsDir,
6065
- segmentPath: (segmentId) => join8(segmentsDir, `${sanitizeStorageId(segmentId, "segment")}.json`),
6066
- indexPath: join8(sessionDir, "index.json")
6228
+ segmentPath: (segmentId) => join9(segmentsDir, `${sanitizeStorageId(segmentId, "segment")}.json`),
6229
+ indexPath: join9(sessionDir, "index.json")
6067
6230
  };
6068
6231
  }
6069
6232
  // packages/core/src/evolution/evidence/session-memory/policy.ts
@@ -6093,8 +6256,8 @@ function parseSessionMemoryPolicy(value) {
6093
6256
  };
6094
6257
  }
6095
6258
  // 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";
6259
+ import { appendFile as appendFile2, mkdir as mkdir6, readFile as readFile8, readdir as readdir8, writeFile as writeFile5 } from "node:fs/promises";
6260
+ import { dirname as dirname7, join as join10 } from "node:path";
6098
6261
 
6099
6262
  // packages/core/src/evolution/evidence/session-memory/constants.ts
6100
6263
  var DEFAULT_MAX_RAW_EVENT_BYTES = 64 * 1024;
@@ -6113,8 +6276,8 @@ class SessionMemoryEvidenceError extends Error {
6113
6276
  }
6114
6277
  }
6115
6278
  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];
6279
+ const rootDir = join10(resolveEvoDevPaths(input.homeDir).stateDir, "session-memory");
6280
+ const projectDirs = input.projectKey === undefined ? await listDirectoryNames3(rootDir) : [input.projectKey];
6118
6281
  const segments = [];
6119
6282
  for (const projectKey of projectDirs) {
6120
6283
  const paths = resolveSessionMemoryPaths({
@@ -6122,7 +6285,7 @@ async function listSessionEvidenceSegments(input) {
6122
6285
  projectKey,
6123
6286
  sessionKey: "list"
6124
6287
  });
6125
- for (const sessionKey of await listDirectoryNames2(paths.projectDir)) {
6288
+ for (const sessionKey of await listDirectoryNames3(paths.projectDir)) {
6126
6289
  const sessionPaths = resolveSessionMemoryPaths({
6127
6290
  homeDir: input.homeDir,
6128
6291
  projectKey,
@@ -6130,17 +6293,33 @@ async function listSessionEvidenceSegments(input) {
6130
6293
  });
6131
6294
  for (const entry of await listJsonFiles(sessionPaths.segmentsDir)) {
6132
6295
  try {
6133
- segments.push(parseSessionEvidenceSegment(JSON.parse(await readFile7(entry, "utf8"))));
6296
+ segments.push(parseSessionEvidenceSegment(JSON.parse(await readFile8(entry, "utf8"))));
6134
6297
  } catch {}
6135
6298
  }
6136
6299
  }
6137
6300
  }
6138
6301
  return segments.sort((left, right) => right.createdAt.localeCompare(left.createdAt));
6139
6302
  }
6303
+ async function listSessionMemoryStates(input) {
6304
+ const rootDir = join10(resolveEvoDevPaths(input.homeDir).stateDir, "session-memory");
6305
+ const projectDirs = input.projectKey === undefined ? await listDirectoryNames3(rootDir) : [input.projectKey];
6306
+ const states = [];
6307
+ for (const projectKey of projectDirs) {
6308
+ const projectDir = join10(rootDir, projectKey);
6309
+ for (const sessionKey of await listDirectoryNames3(projectDir)) {
6310
+ try {
6311
+ const state = parseSessionMemoryState(JSON.parse(await readFile8(join10(projectDir, sessionKey, "state.json"), "utf8")));
6312
+ if (state.projectKey === projectKey && state.sessionKey === sessionKey)
6313
+ states.push(state);
6314
+ } catch {}
6315
+ }
6316
+ }
6317
+ return states.sort((left, right) => right.updatedAt.localeCompare(left.updatedAt) || left.sessionKey.localeCompare(right.sessionKey));
6318
+ }
6140
6319
  async function readSessionEvidenceSegment(input) {
6141
6320
  const paths = resolveSessionMemoryPaths(input);
6142
6321
  try {
6143
- const segment = parseSessionEvidenceSegment(JSON.parse(await readFile7(paths.segmentPath(input.segmentId), "utf8")));
6322
+ const segment = parseSessionEvidenceSegment(JSON.parse(await readFile8(paths.segmentPath(input.segmentId), "utf8")));
6144
6323
  if (segment.id !== input.segmentId || segment.projectKey !== input.projectKey || segment.sessionKey !== input.sessionKey) {
6145
6324
  throw new SessionMemoryEvidenceError("invalid", "Session evidence identity does not match its storage path.");
6146
6325
  }
@@ -6156,7 +6335,7 @@ async function readSessionEvidenceSegment(input) {
6156
6335
  }
6157
6336
  async function readSessionState(path) {
6158
6337
  try {
6159
- return JSON.parse(await readFile7(path, "utf8"));
6338
+ return JSON.parse(await readFile8(path, "utf8"));
6160
6339
  } catch (error) {
6161
6340
  if (isNotFoundError(error))
6162
6341
  return null;
@@ -6165,7 +6344,7 @@ async function readSessionState(path) {
6165
6344
  }
6166
6345
  async function readSessionCursor(path, sessionKey, sourcePath, now) {
6167
6346
  try {
6168
- return JSON.parse(await readFile7(path, "utf8"));
6347
+ return JSON.parse(await readFile8(path, "utf8"));
6169
6348
  } catch (error) {
6170
6349
  if (!isNotFoundError(error))
6171
6350
  throw error;
@@ -6184,13 +6363,13 @@ async function readSessionCursor(path, sessionKey, sourcePath, now) {
6184
6363
  }
6185
6364
  async function appendRawEvent(path, event) {
6186
6365
  const existingLineCount = await countJsonlLines(path);
6187
- await mkdir6(dirname6(path), { recursive: true });
6366
+ await mkdir6(dirname7(path), { recursive: true });
6188
6367
  await appendFile2(path, `${JSON.stringify(event)}
6189
6368
  `, "utf8");
6190
6369
  return { lineNumber: existingLineCount + 1 };
6191
6370
  }
6192
6371
  async function readLineRange(path, fromLine, toLine) {
6193
- const text2 = await readFile7(path, "utf8");
6372
+ const text2 = await readFile8(path, "utf8");
6194
6373
  const lines = text2.split(`
6195
6374
  `).filter((line) => line.trim() !== "");
6196
6375
  const selected = lines.slice(Math.max(0, fromLine - 1), toLine);
@@ -6229,13 +6408,13 @@ async function writeSessionIndex(paths, state, segment, now) {
6229
6408
  });
6230
6409
  }
6231
6410
  async function writeJson2(path, value) {
6232
- await mkdir6(dirname6(path), { recursive: true });
6411
+ await mkdir6(dirname7(path), { recursive: true });
6233
6412
  await writeFile5(path, `${JSON.stringify(value, null, 2)}
6234
6413
  `, "utf8");
6235
6414
  }
6236
6415
  async function countJsonlLines(path) {
6237
6416
  try {
6238
- const text2 = await readFile7(path, "utf8");
6417
+ const text2 = await readFile8(path, "utf8");
6239
6418
  return text2.split(`
6240
6419
  `).filter((line) => line.trim() !== "").length;
6241
6420
  } catch (error) {
@@ -6246,7 +6425,7 @@ async function countJsonlLines(path) {
6246
6425
  }
6247
6426
  async function readSessionIndex(path) {
6248
6427
  try {
6249
- const parsed = JSON.parse(await readFile7(path, "utf8"));
6428
+ const parsed = JSON.parse(await readFile8(path, "utf8"));
6250
6429
  if (!Array.isArray(parsed.segments))
6251
6430
  return { segments: [] };
6252
6431
  return {
@@ -6274,9 +6453,19 @@ function parseSessionEvidenceSegment(value) {
6274
6453
  }
6275
6454
  return segment;
6276
6455
  }
6277
- async function listDirectoryNames2(path) {
6456
+ function parseSessionMemoryState(value) {
6457
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
6458
+ throw new SessionMemoryEvidenceError("invalid", "Session Memory state must be an object.");
6459
+ }
6460
+ const state = value;
6461
+ if (state.schemaVersion !== 1 || state.kind !== "session-memory-state" || typeof state.projectKey !== "string" || typeof state.sessionKey !== "string" || !(state.runId === null || typeof state.runId === "string") || !(state.roleId === null || typeof state.roleId === "string") || typeof state.createdAt !== "string" || typeof state.updatedAt !== "string" || typeof state.counters !== "object" || state.counters === null) {
6462
+ throw new SessionMemoryEvidenceError("invalid", "Session Memory state fields are invalid.");
6463
+ }
6464
+ return state;
6465
+ }
6466
+ async function listDirectoryNames3(path) {
6278
6467
  try {
6279
- return (await readdir7(path, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort();
6468
+ return (await readdir8(path, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort();
6280
6469
  } catch (error) {
6281
6470
  if (isNotFoundError(error))
6282
6471
  return [];
@@ -6285,7 +6474,7 @@ async function listDirectoryNames2(path) {
6285
6474
  }
6286
6475
  async function listJsonFiles(path) {
6287
6476
  try {
6288
- return (await readdir7(path, { withFileTypes: true })).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => join9(path, entry.name)).sort();
6477
+ return (await readdir8(path, { withFileTypes: true })).filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => join10(path, entry.name)).sort();
6289
6478
  } catch (error) {
6290
6479
  if (isNotFoundError(error))
6291
6480
  return [];
@@ -6293,7 +6482,7 @@ async function listJsonFiles(path) {
6293
6482
  }
6294
6483
  }
6295
6484
  // packages/core/src/evolution/evidence/session-memory/updater.ts
6296
- import { join as join11 } from "node:path";
6485
+ import { join as join12 } from "node:path";
6297
6486
 
6298
6487
  // packages/core/src/evolution/triggers/index.ts
6299
6488
  var exports_triggers = {};
@@ -6308,8 +6497,8 @@ __export(exports_triggers, {
6308
6497
  enqueueSegmentEvolutionTrigger: () => enqueueSegmentEvolutionTrigger,
6309
6498
  enqueueEvolutionTrigger: () => enqueueEvolutionTrigger
6310
6499
  });
6311
- import { readFile as readFile8 } from "node:fs/promises";
6312
- import { join as join10 } from "node:path";
6500
+ import { readFile as readFile9 } from "node:fs/promises";
6501
+ import { join as join11 } from "node:path";
6313
6502
 
6314
6503
  // packages/core/src/evolution/triggers/classification.ts
6315
6504
  function normalizeEvolutionEventType(value) {
@@ -6444,19 +6633,19 @@ async function enqueueEvolutionTrigger(input) {
6444
6633
  };
6445
6634
  validateEvolutionTriggerRecord(trigger);
6446
6635
  const paths = resolveEvolutionPaths({ homeDir: input.homeDir, projectKey, runId });
6447
- await writeJsonFile(join10(paths.triggersDir, `${trigger.id}.json`), trigger, { overwrite: false });
6636
+ await writeJsonFile(join11(paths.triggersDir, `${trigger.id}.json`), trigger, { overwrite: false });
6448
6637
  return trigger;
6449
6638
  }
6450
6639
  async function listEvolutionTriggers(input) {
6451
6640
  const paths = resolveEvoDevPaths(input.homeDir);
6452
- const evolutionStateDir = join10(paths.stateDir, "evolution");
6641
+ const evolutionStateDir = join11(paths.stateDir, "evolution");
6453
6642
  const projectKeys = input.projectKey === undefined ? await listDirectoryNames(evolutionStateDir) : [sanitizeStorageId2("projectKey", input.projectKey)];
6454
6643
  const triggers = [];
6455
6644
  for (const projectKey of projectKeys) {
6456
- const projectStateDir = join10(evolutionStateDir, projectKey);
6645
+ const projectStateDir = join11(evolutionStateDir, projectKey);
6457
6646
  const runIds = input.runId === undefined ? await listDirectoryNames(projectStateDir) : [sanitizeStorageId2("runId", input.runId)];
6458
6647
  for (const runId of runIds) {
6459
- const runTriggers = await readJsonFiles(join10(projectStateDir, runId, "triggers"), parseTrigger);
6648
+ const runTriggers = await readJsonFiles(join11(projectStateDir, runId, "triggers"), parseTrigger);
6460
6649
  triggers.push(...runTriggers.filter((trigger) => input.status === undefined || trigger.status === input.status));
6461
6650
  }
6462
6651
  }
@@ -6497,16 +6686,16 @@ async function enqueueSegmentEvolutionTrigger(input) {
6497
6686
  } catch (error) {
6498
6687
  if (!isFileExistsError(error))
6499
6688
  throw error;
6500
- return parseSegmentTrigger(JSON.parse(await readFile8(path, "utf8")));
6689
+ return parseSegmentTrigger(JSON.parse(await readFile9(path, "utf8")));
6501
6690
  }
6502
6691
  }
6503
6692
  async function listSegmentEvolutionTriggers(input) {
6504
6693
  const paths = resolveEvoDevPaths(input.homeDir);
6505
- const evolutionStateDir = join10(paths.stateDir, "evolution");
6694
+ const evolutionStateDir = join11(paths.stateDir, "evolution");
6506
6695
  const projectKeys = input.projectKey === undefined ? await listDirectoryNames(evolutionStateDir) : [sanitizeStorageId2("projectKey", input.projectKey)];
6507
6696
  const triggers = [];
6508
6697
  for (const projectKey of projectKeys) {
6509
- const projectSegmentsDir = join10(evolutionStateDir, projectKey, "segments");
6698
+ const projectSegmentsDir = join11(evolutionStateDir, projectKey, "segments");
6510
6699
  const projectTriggers = await readJsonFiles(projectSegmentsDir, parseSegmentTrigger);
6511
6700
  triggers.push(...projectTriggers.filter((trigger) => {
6512
6701
  if (input.status !== undefined && trigger.status !== input.status)
@@ -6543,7 +6732,7 @@ async function updateTriggers(homeDir, triggers, patch) {
6543
6732
  projectKey: next.projectKey,
6544
6733
  runId: next.runId
6545
6734
  });
6546
- await writeJsonFile(join10(paths.triggersDir, `${next.id}.json`), next, { overwrite: true });
6735
+ await writeJsonFile(join11(paths.triggersDir, `${next.id}.json`), next, { overwrite: true });
6547
6736
  }
6548
6737
  }
6549
6738
  async function updateSegmentTriggers(homeDir, triggers, patch) {
@@ -6562,7 +6751,7 @@ async function updateSegmentTriggers(homeDir, triggers, patch) {
6562
6751
  }
6563
6752
  function resolveSegmentEvolutionTriggerPath(homeDir, trigger) {
6564
6753
  const paths = resolveEvoDevPaths(homeDir);
6565
- return join10(paths.stateDir, "evolution", sanitizeStorageId2("projectKey", trigger.projectKey), "segments", `${sanitizeStorageId2("segmentTrigger", trigger.id)}.json`);
6754
+ return join11(paths.stateDir, "evolution", sanitizeStorageId2("projectKey", trigger.projectKey), "segments", `${sanitizeStorageId2("segmentTrigger", trigger.id)}.json`);
6566
6755
  }
6567
6756
 
6568
6757
  // packages/core/src/evolution/evidence/session-memory/segment.ts
@@ -6877,7 +7066,9 @@ async function updateSessionMemoryFromHook(input) {
6877
7066
  environment: input.environment,
6878
7067
  payload: input.rawPayload
6879
7068
  });
6880
- const projectKey = sanitizeStorageId(team?.projectKey ?? resolveProjectLogKey(input.homeDir, optionalString(input.rawPayload.cwd) ?? input.homeDir), "project");
7069
+ const cwd = optionalString(input.rawPayload.cwd);
7070
+ const workspace = team === null && cwd !== null ? await resolveProjectWorkspaceFromCwd({ homeDir: input.homeDir, cwd }) : null;
7071
+ const projectKey = sanitizeStorageId(team?.projectKey ?? workspace?.projectKey ?? resolveProjectLogKey(input.homeDir, cwd ?? input.homeDir), "project");
6881
7072
  const sessionKey = sanitizeStorageId(resolveTraceSessionKey(input.rawPayload), "session");
6882
7073
  const paths = resolveSessionMemoryPaths({ homeDir: input.homeDir, projectKey, sessionKey });
6883
7074
  const now = normalizeTimestamp(input.receivedAt ?? input.event.time.receivedAt);
@@ -6971,7 +7162,7 @@ async function updateSessionMemoryFromHook(input) {
6971
7162
  await writeJson2(paths.cursorPath, cursor);
6972
7163
  stateWrites.push(paths.statePath, paths.cursorPath);
6973
7164
  if (queuedSegmentTriggerId !== null) {
6974
- stateWrites.push(join11(input.homeDir, ".evodev", "state", "evolution", projectKey, "segments", `${queuedSegmentTriggerId}.json`));
7165
+ stateWrites.push(join12(input.homeDir, ".evodev", "state", "evolution", projectKey, "segments", `${queuedSegmentTriggerId}.json`));
6975
7166
  }
6976
7167
  return {
6977
7168
  state,
@@ -6993,577 +7184,13 @@ function emptyResult() {
6993
7184
  };
6994
7185
  }
6995
7186
  // packages/core/src/hooks/index.ts
6996
- import { mkdir as mkdir9, readFile as readFile11, writeFile as writeFile8 } from "node:fs/promises";
7187
+ import { mkdir as mkdir8, readFile as readFile11, writeFile as writeFile7 } from "node:fs/promises";
6997
7188
  import { dirname as dirname9, join as join14 } from "node:path";
6998
7189
 
6999
- // packages/core/src/task/index.ts
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";
7002
- var FORBIDDEN_TASK_PATHS = ["CLAUDE.md", "AGENTS.md", ".claude/**", ".codex/**"];
7003
- var FORBIDDEN_TASK_WRITE_SEGMENTS = new Set([".claude", ".codex"]);
7004
- var FORBIDDEN_PROJECT_ASSET_SEGMENTS = new Set(["packages", "src"]);
7005
- var FORBIDDEN_TASK_WRITE_FILES = new Set(["agents.md", "claude.md", "package.json", "readme.md"]);
7006
- var FORBIDDEN_RAW_KEYS2 = new Set([
7007
- "rawoutput",
7008
- "raw_output",
7009
- "stdout",
7010
- "stderr",
7011
- "source",
7012
- "sourcecontent",
7013
- "source_content",
7014
- "sourcetext",
7015
- "source_text",
7016
- "prompt",
7017
- "prompttext",
7018
- "prompt_text",
7019
- "transcript",
7020
- "transcripttext",
7021
- "transcript_text",
7022
- "secret",
7023
- "secretvalue",
7024
- "secret_value"
7025
- ]);
7026
- var ALLOWED_VERIFICATION_KEYS = new Set([
7027
- "acceptanceResults",
7028
- "antiCriteriaResults",
7029
- "commands",
7030
- "evidence",
7031
- "exitCode",
7032
- "id",
7033
- "status",
7034
- "summary",
7035
- "type"
7036
- ]);
7037
- var SENSITIVE_TEXT_PATTERN3 = /https?:\/\/\S+|\b(secret|token|password|passwd|private|internal|api[_-]?key|apikey|credential|credentials|raw log|raw source|raw prompt)\b/gi;
7038
- function createTaskContract(input) {
7039
- const taskId = createTaskId(input.title);
7040
- const summary = input.summary ?? input.title;
7041
- const acceptanceCriteria = input.acceptanceCriteria === undefined || input.acceptanceCriteria.length === 0 ? [
7042
- {
7043
- id: "AC1",
7044
- category: "engineering",
7045
- statement: "Task outcome satisfies the requested target state.",
7046
- requiredEvidence: ["verification-summary"],
7047
- status: "not-run"
7048
- }
7049
- ] : input.acceptanceCriteria.map((criterion) => ({
7050
- id: sanitizeId2(criterion.id),
7051
- category: criterion.category,
7052
- statement: sanitizeText2(criterion.statement),
7053
- requiredEvidence: uniqueSanitizedIds2(criterion.requiredEvidence ?? []),
7054
- status: "not-run"
7055
- }));
7056
- const defaultAntiCriteria = [
7057
- {
7058
- id: "ANTI1",
7059
- category: "privacy",
7060
- statement: "Do not collect source code, prompts, raw command output, secrets, or internal links.",
7061
- status: "unknown"
7062
- },
7063
- {
7064
- id: "ANTI2",
7065
- category: "scope",
7066
- statement: "Do not write outside approved task storage or approved implementation scope.",
7067
- status: "unknown"
7068
- }
7069
- ];
7070
- return {
7071
- version: 1,
7072
- taskId,
7073
- status: "draft",
7074
- classification: "local-private",
7075
- source: { summary: sanitizeText2(summary), rawPromptStored: false },
7076
- context: {
7077
- projectId: input.projectId === undefined || input.projectId === null ? null : sanitizeText2(input.projectId),
7078
- relatedFiles: [],
7079
- assumptions: [],
7080
- openQuestions: []
7081
- },
7082
- currentState: { summary: "To be completed by the task owner.", evidenceRefs: [] },
7083
- targetState: { summary: sanitizeText2(input.title), nonGoals: [], constraints: [] },
7084
- scope: {
7085
- allowedPaths: sanitizeTextList(input.allowedPaths ?? []),
7086
- forbiddenPaths: FORBIDDEN_TASK_PATHS,
7087
- allowedOperations: input.allowedOperations === undefined || input.allowedOperations.length === 0 ? ["read", "edit-approved-files", "run-local-tests"] : sanitizeTextList(input.allowedOperations),
7088
- requiresUserConfirmation: sanitizeTextList(input.requiresUserConfirmation ?? [])
7089
- },
7090
- acceptanceCriteria,
7091
- antiCriteria: [
7092
- ...defaultAntiCriteria,
7093
- ...(input.antiCriteria ?? []).map((criterion) => ({
7094
- id: sanitizeId2(criterion.id),
7095
- category: criterion.category,
7096
- statement: sanitizeText2(criterion.statement),
7097
- status: "unknown"
7098
- }))
7099
- ],
7100
- route: {
7101
- mode: null,
7102
- workflowId: null,
7103
- rationale: "Not routed yet.",
7104
- requiredReview: [],
7105
- requiredVerification: uniqueSanitizedIds2(input.requiredVerification ?? [])
7106
- },
7107
- verification: {
7108
- policy: "advisory",
7109
- commands: [],
7110
- acceptanceResults: [],
7111
- antiCriteriaResults: [],
7112
- status: "not-run",
7113
- summary: "Verification has not run."
7114
- },
7115
- evidence: { metadataOnly: true, items: [] },
7116
- learningCandidates: []
7117
- };
7118
- }
7119
- function routeTaskContract(contract) {
7120
- const mode = selectMode(contract);
7121
- const requiredVerification = uniqueSanitizedIds2([
7122
- ...contract.route.requiredVerification ?? [],
7123
- "verification-summary"
7124
- ]);
7125
- return {
7126
- ...contract,
7127
- status: "routed",
7128
- route: {
7129
- mode,
7130
- workflowId: selectWorkflowId(contract, mode),
7131
- rationale: createRouteRationale(contract, mode),
7132
- requiredReview: mode === "rigorous" ? ["security-boundary", "verification"] : [],
7133
- requiredVerification
7134
- }
7135
- };
7136
- }
7137
- function verifyTaskContract(contract, input) {
7138
- assertMetadataOnly(input);
7139
- const commands = (input.commands ?? []).map((command) => ({
7140
- id: sanitizeId2(command.id),
7141
- status: assertVerificationCommandStatus(command.status, `command ${command.id}`),
7142
- exitCode: command.exitCode,
7143
- summary: sanitizeText2(command.summary ?? `${command.id}: ${command.status}`),
7144
- rawOutputStored: false
7145
- }));
7146
- const acceptanceResults = (input.acceptanceResults ?? []).map((result) => ({
7147
- id: sanitizeId2(result.id),
7148
- status: assertAcceptanceResultStatus(result.status, `acceptance ${result.id}`),
7149
- summary: sanitizeText2(result.summary ?? `${result.id}: ${result.status}`)
7150
- }));
7151
- const antiCriteriaResults = (input.antiCriteriaResults ?? []).map((result) => ({
7152
- id: sanitizeId2(result.id),
7153
- status: assertAntiCriteriaResultStatus(result.status, `anti-criteria ${result.id}`),
7154
- summary: sanitizeText2(result.summary ?? `${result.id}: ${result.status}`)
7155
- }));
7156
- const evidence = (input.evidence ?? []).map((item) => ({
7157
- type: assertEvidenceType(item.type, `evidence ${item.id}`),
7158
- id: sanitizeId2(item.id),
7159
- status: assertVerificationStatus(item.status, `evidence ${item.id}`),
7160
- summary: sanitizeText2(item.summary ?? `${item.id}: ${item.status}`),
7161
- rawOutputStored: false,
7162
- sourceContentStored: false
7163
- }));
7164
- const failures = collectVerificationFailures(contract, commands, acceptanceResults, antiCriteriaResults, evidence);
7165
- const ok = failures.length === 0;
7166
- const summary = ok ? "Verification passed." : `Verification failed: ${failures.join("; ")}`;
7167
- return {
7168
- ok,
7169
- summary,
7170
- contract: {
7171
- ...contract,
7172
- status: ok ? "verified" : "failed",
7173
- acceptanceCriteria: contract.acceptanceCriteria.map((criterion) => ({
7174
- ...criterion,
7175
- status: acceptanceResults.find((result) => result.id === criterion.id)?.status ?? criterion.status
7176
- })),
7177
- antiCriteria: contract.antiCriteria.map((criterion) => ({
7178
- ...criterion,
7179
- status: antiCriteriaResults.find((result) => result.id === criterion.id)?.status ?? criterion.status
7180
- })),
7181
- verification: {
7182
- policy: "advisory",
7183
- commands,
7184
- acceptanceResults,
7185
- antiCriteriaResults,
7186
- status: ok ? "pass" : "fail",
7187
- summary
7188
- },
7189
- evidence: {
7190
- metadataOnly: true,
7191
- items: evidence
7192
- }
7193
- }
7194
- };
7195
- }
7196
- async function readTaskContract(path) {
7197
- return parseTaskContract(JSON.parse(await readFile9(path, "utf8")));
7198
- }
7199
- async function writeTaskContract(path, contract, options = {}) {
7200
- await assertTaskContractWritePathAllowed(path);
7201
- await mkdir7(dirname7(path), { recursive: true });
7202
- await writeFile6(path, `${JSON.stringify(contract, null, 2)}
7203
- `, {
7204
- encoding: "utf8",
7205
- flag: options.overwrite === true ? "w" : "wx"
7206
- });
7207
- }
7208
- async function resolveTaskContractOutputPath(input) {
7209
- if (input.outputDir !== undefined) {
7210
- const outputPath = join12(input.outputDir, input.taskId, "contract.json");
7211
- await assertTaskContractWritePathAllowed(outputPath);
7212
- return outputPath;
7213
- }
7214
- if (input.projectDir !== undefined) {
7215
- const projectContextPath = join12(input.projectDir, ".evodev", "project.json");
7216
- if (!await pathExists4(projectContextPath)) {
7217
- throw new Error("Project mode requires existing .evodev/project.json; use --output-dir instead.");
7218
- }
7219
- const outputPath = join12(input.projectDir, ".evodev", "tasks", input.taskId, "contract.json");
7220
- await assertTaskContractWritePathAllowed(outputPath);
7221
- return outputPath;
7222
- }
7223
- throw new Error("Task writes require --output-dir or --project-dir with existing project context.");
7224
- }
7225
- function formatTaskContract(contract) {
7226
- return [
7227
- "EvoDev task contract",
7228
- "",
7229
- `Task id: ${contract.taskId}`,
7230
- `Status: ${contract.status}`,
7231
- `Summary: ${contract.source.summary}`,
7232
- `Mode: ${contract.route.mode ?? "not routed"}`,
7233
- `Workflow: ${contract.route.workflowId ?? "not routed"}`,
7234
- `Required verification: ${formatList(contract.route.requiredVerification)}`,
7235
- `Required review: ${formatList(contract.route.requiredReview)}`,
7236
- `Route rationale: ${contract.route.rationale}`,
7237
- `Verification: ${contract.verification.status}`,
7238
- `Verification summary: ${contract.verification.summary}`
7239
- ].join(`
7240
- `);
7241
- }
7242
- function selectMode(contract) {
7243
- if (selectRigorousTrigger(contract) !== null) {
7244
- return "rigorous";
7245
- }
7246
- const allowedPaths = contract.scope.allowedPaths ?? [];
7247
- if (allowedPaths.length <= 1 && contract.acceptanceCriteria.length <= 1) {
7248
- return "minimal";
7249
- }
7250
- return "standard";
7251
- }
7252
- function selectWorkflowId(contract, mode) {
7253
- const text2 = collectRouteText(contract);
7254
- if (text2.includes("release") || text2.includes("publish"))
7255
- return "rd-release-readiness";
7256
- if (hasSecurityBoundaryTerms(text2) || mode === "rigorous") {
7257
- return "rd-security-boundary-review";
7258
- }
7259
- if (text2.includes("bug"))
7260
- return "rd-bug-fix";
7261
- if (text2.includes("refactor"))
7262
- return "rd-refactor";
7263
- if (text2.includes("review"))
7264
- return "rd-code-review";
7265
- if (text2.includes("doc"))
7266
- return "rd-docs-update";
7267
- if (text2.includes("test"))
7268
- return "rd-test-generation";
7269
- if (mode === "minimal")
7270
- return "rd-docs-update";
7271
- return "rd-feature-implementation";
7272
- }
7273
- function collectRouteText(contract) {
7274
- return [
7275
- contract.taskId,
7276
- contract.source.summary,
7277
- contract.currentState.summary,
7278
- ...contract.currentState.evidenceRefs,
7279
- contract.targetState.summary,
7280
- ...contract.targetState.nonGoals,
7281
- ...contract.targetState.constraints,
7282
- ...contract.context.relatedFiles.map((file) => `${file.path} ${file.reason}`),
7283
- ...contract.context.assumptions,
7284
- ...contract.context.openQuestions,
7285
- ...contract.scope.allowedPaths ?? [],
7286
- ...contract.scope.allowedOperations ?? [],
7287
- ...contract.scope.requiresUserConfirmation ?? [],
7288
- ...contract.acceptanceCriteria.map((criterion) => criterion.statement),
7289
- ...contract.acceptanceCriteria.flatMap((criterion) => criterion.requiredEvidence),
7290
- ...contract.route.requiredVerification ?? []
7291
- ].join(" ").toLowerCase();
7292
- }
7293
- function createRouteRationale(contract, mode) {
7294
- const trigger = selectRigorousTrigger(contract);
7295
- if (mode === "rigorous")
7296
- return `Selected rigorous due to ${trigger ?? "high-risk"} trigger.`;
7297
- if (mode === "minimal")
7298
- return "Selected minimal for narrow scope and simple acceptance criteria.";
7299
- return "Selected standard for bounded engineering work requiring Task Contract verification.";
7300
- }
7301
- function selectRigorousTrigger(contract) {
7302
- const text2 = collectRouteText(contract);
7303
- if (text2.includes("[redacted]") || hasSecurityBoundaryTerms(text2))
7304
- return "privacy/security";
7305
- if (/\b(release|publish|publishing|package distribution|npm publish)\b/.test(text2)) {
7306
- return "release/publish";
7307
- }
7308
- if (/\b(hook|hooks|learning|memory|telemetry|observability)\b/.test(text2)) {
7309
- return "hook/learning/telemetry";
7310
- }
7311
- if (/\b(migration|migrate|hard to rollback|hard-to-rollback|irreversible|destructive)\b/.test(text2)) {
7312
- return "hard-to-rollback";
7313
- }
7314
- if (hasHighRiskOperationTerms(text2)) {
7315
- return "high-risk operation";
7316
- }
7317
- if ((contract.scope.requiresUserConfirmation ?? []).length > 0) {
7318
- return "explicit user confirmation";
7319
- }
7320
- for (const path of contract.scope.allowedPaths ?? []) {
7321
- const trigger = selectRigorousPathTrigger(path);
7322
- if (trigger !== null)
7323
- return trigger;
7324
- }
7325
- for (const operation of contract.scope.allowedOperations ?? []) {
7326
- if (hasHighRiskOperationTerms(operation))
7327
- return "high-risk operation";
7328
- }
7329
- return null;
7330
- }
7331
- function hasSecurityBoundaryTerms(text2) {
7332
- return /\b(security|privacy|private data|auth|authentication|authorization|credential|credentials|secret|secrets|token|tokens|api key|api-key|apikey|password|passwd)\b/.test(text2);
7333
- }
7334
- function selectRigorousPathTrigger(path) {
7335
- const normalized = path.trim().replace(/\\/g, "/").toLowerCase();
7336
- if (/^~\/\.(evodev|claude|codex)(\/|$)/.test(normalized)) {
7337
- return "user-level Code Agent/EvoDev path";
7338
- }
7339
- if (normalized === ".evodev" || normalized.startsWith(".evodev/") || normalized.includes("/.evodev/")) {
7340
- return "project .evodev path";
7341
- }
7342
- if (normalized === ".claude" || normalized.startsWith(".claude/") || normalized.includes("/.claude/") || normalized === ".codex" || normalized.startsWith(".codex/") || normalized.includes("/.codex/")) {
7343
- return "project Code Agent config path";
7344
- }
7345
- const fileName = basename(normalized);
7346
- if (fileName === "claude.md" || fileName === "agents.md")
7347
- return "agent instruction file";
7348
- return null;
7349
- }
7350
- function hasHighRiskOperationTerms(text2) {
7351
- const normalized = text2.toLowerCase().replace(/[_-]+/g, " ");
7352
- return /\b(delete|remove|publish|release|install|uninstall|network|external|external service|external api|write user config|user config|write project context|project context|hook|learning|memory|telemetry)\b/.test(normalized);
7353
- }
7354
- function collectVerificationFailures(contract, commands, acceptanceResults, antiCriteriaResults, evidence) {
7355
- const failures = [];
7356
- if (!isVerificationReady(contract)) {
7357
- failures.push("task contract must be routed before verification");
7358
- }
7359
- failures.push(...collectDuplicateIdFailures("command", commands));
7360
- failures.push(...collectDuplicateIdFailures("evidence", evidence));
7361
- failures.push(...collectDuplicateIdFailures("acceptance result", acceptanceResults));
7362
- failures.push(...collectDuplicateIdFailures("anti-criteria result", antiCriteriaResults));
7363
- for (const requiredId of contract.route.requiredVerification ?? []) {
7364
- const matches = [
7365
- ...commands.filter((command) => command.id === requiredId),
7366
- ...evidence.filter((item) => item.id === requiredId)
7367
- ];
7368
- if (matches.length === 0) {
7369
- failures.push(`missing required verification: ${requiredId}`);
7370
- continue;
7371
- }
7372
- if (matches.some((item) => !isSatisfyingVerificationItem(item))) {
7373
- failures.push(`required verification ${requiredId} is not satisfied`);
7374
- }
7375
- }
7376
- for (const criterion of contract.acceptanceCriteria) {
7377
- const result = acceptanceResults.find((candidate) => candidate.id === criterion.id);
7378
- if (result === undefined || result.status !== "pass" && result.status !== "not-applicable") {
7379
- failures.push(`acceptance ${criterion.id} is not satisfied`);
7380
- }
7381
- for (const evidenceId of criterion.requiredEvidence) {
7382
- const matches = evidence.filter((item) => item.id === evidenceId);
7383
- if (matches.length === 0) {
7384
- failures.push(`missing evidence for ${criterion.id}: ${evidenceId}`);
7385
- continue;
7386
- }
7387
- if (matches.some((item) => !isSatisfyingEvidenceItem(item))) {
7388
- failures.push(`evidence for ${criterion.id} is not satisfied: ${evidenceId}`);
7389
- }
7390
- }
7391
- }
7392
- for (const criterion of contract.antiCriteria) {
7393
- const result = antiCriteriaResults.find((candidate) => candidate.id === criterion.id);
7394
- if (result === undefined || result.status === "unknown" || result.status === "triggered") {
7395
- failures.push(`anti-criteria ${criterion.id} is not clear`);
7396
- }
7397
- }
7398
- return failures;
7399
- }
7400
- function collectDuplicateIdFailures(label, items) {
7401
- const seen = new Set;
7402
- const duplicates = new Set;
7403
- for (const item of items) {
7404
- if (seen.has(item.id))
7405
- duplicates.add(item.id);
7406
- seen.add(item.id);
7407
- }
7408
- return Array.from(duplicates).map((id) => `duplicate ${label} id: ${id}`);
7409
- }
7410
- function isSatisfyingVerificationItem(item) {
7411
- if ("rawOutputStored" in item && "type" in item)
7412
- return isSatisfyingEvidenceItem(item);
7413
- return item.status === "pass";
7414
- }
7415
- function isSatisfyingEvidenceItem(item) {
7416
- if (item.type === "command-result")
7417
- return item.status === "pass";
7418
- return item.status === "pass" || item.status === "clear";
7419
- }
7420
- function isVerificationReady(contract) {
7421
- return contract.status !== "draft" && contract.route.mode !== null && contract.route.workflowId !== null && (contract.route.requiredVerification ?? []).length > 0;
7422
- }
7423
- function parseTaskContract(value) {
7424
- if (!isRecord7(value) || value.version !== 1 || typeof value.taskId !== "string") {
7425
- throw new Error("Invalid Task Contract JSON.");
7426
- }
7427
- return value;
7428
- }
7429
- function assertMetadataOnly(value) {
7430
- if (Array.isArray(value)) {
7431
- for (const item of value)
7432
- assertMetadataOnly(item);
7433
- return;
7434
- }
7435
- if (!isRecord7(value)) {
7436
- if (typeof value === "string" && containsSensitiveText(value)) {
7437
- throw new Error("Verification input contains sensitive content in metadata field.");
7438
- }
7439
- return;
7440
- }
7441
- for (const [key, child] of Object.entries(value)) {
7442
- const normalizedKey = key.toLowerCase().replace(/[^a-z0-9]/g, "");
7443
- if (FORBIDDEN_RAW_KEYS2.has(key) || FORBIDDEN_RAW_KEYS2.has(normalizedKey)) {
7444
- throw new Error(`Verification input contains forbidden raw field: ${key}`);
7445
- }
7446
- if (!ALLOWED_VERIFICATION_KEYS.has(key)) {
7447
- throw new Error(`Verification input contains unsupported field: ${key}`);
7448
- }
7449
- assertMetadataOnly(child);
7450
- }
7451
- }
7452
- function assertVerificationCommandStatus(value, label) {
7453
- if (value === "pass" || value === "fail" || value === "not-run")
7454
- return value;
7455
- throw new Error(`Invalid verification command status for ${label}: ${String(value)}`);
7456
- }
7457
- function assertAcceptanceResultStatus(value, label) {
7458
- if (value === "pass" || value === "fail" || value === "not-run" || value === "not-applicable") {
7459
- return value;
7460
- }
7461
- throw new Error(`Invalid acceptance result status for ${label}: ${String(value)}`);
7462
- }
7463
- function assertAntiCriteriaResultStatus(value, label) {
7464
- if (value === "clear" || value === "triggered" || value === "unknown")
7465
- return value;
7466
- throw new Error(`Invalid anti-criteria result status for ${label}: ${String(value)}`);
7467
- }
7468
- function assertVerificationStatus(value, label) {
7469
- if (value === "pass" || value === "fail" || value === "not-run" || value === "not-applicable" || value === "unknown" || value === "triggered" || value === "clear") {
7470
- return value;
7471
- }
7472
- throw new Error(`Invalid verification status for ${label}: ${String(value)}`);
7473
- }
7474
- function assertEvidenceType(value, label) {
7475
- if (value === "command-result" || value === "manual-check" || value === "review")
7476
- return value;
7477
- throw new Error(`Invalid evidence type for ${label}: ${String(value)}`);
7478
- }
7479
- function sanitizeText2(value) {
7480
- return value.replace(SENSITIVE_TEXT_PATTERN3, "[redacted]").slice(0, 500);
7481
- }
7482
- function containsSensitiveText(value) {
7483
- SENSITIVE_TEXT_PATTERN3.lastIndex = 0;
7484
- return SENSITIVE_TEXT_PATTERN3.test(value);
7485
- }
7486
- async function assertTaskContractWritePathAllowed(path) {
7487
- assertTaskContractWritePathSegmentsAllowed(resolve3(path));
7488
- assertTaskContractWritePathSegmentsAllowed(await resolveTaskWriteRealPath(path));
7489
- }
7490
- function assertTaskContractWritePathSegmentsAllowed(path) {
7491
- const segments = path.replace(/\\/g, "/").split("/").filter((segment) => segment.length > 0).map((segment) => segment.toLowerCase());
7492
- const protectedSegment = segments.find((segment) => FORBIDDEN_TASK_WRITE_SEGMENTS.has(segment));
7493
- if (protectedSegment !== undefined) {
7494
- throw new Error(`Task contract write path is protected: ${protectedSegment}`);
7495
- }
7496
- if (!isTaskStoragePath(segments)) {
7497
- const protectedProjectAssetSegment = segments.find((segment) => FORBIDDEN_PROJECT_ASSET_SEGMENTS.has(segment));
7498
- if (protectedProjectAssetSegment !== undefined) {
7499
- throw new Error(`Task contract write path is protected: ${protectedProjectAssetSegment}`);
7500
- }
7501
- }
7502
- const protectedFile = segments.find((segment) => FORBIDDEN_TASK_WRITE_FILES.has(segment));
7503
- if (protectedFile !== undefined) {
7504
- throw new Error(`Task contract write path is protected: ${protectedFile}`);
7505
- }
7506
- }
7507
- async function resolveTaskWriteRealPath(path) {
7508
- let currentPath = resolve3(path);
7509
- const missingSegments = [];
7510
- while (true) {
7511
- try {
7512
- await lstat(currentPath);
7513
- return join12(await realpath(currentPath), ...missingSegments.reverse());
7514
- } catch (error) {
7515
- if (!isMissingPathError(error))
7516
- throw error;
7517
- const parentPath = dirname7(currentPath);
7518
- if (parentPath === currentPath)
7519
- return resolve3(path);
7520
- missingSegments.push(basename(currentPath));
7521
- currentPath = parentPath;
7522
- }
7523
- }
7524
- }
7525
- function isTaskStoragePath(segments) {
7526
- return segments.some((segment, index) => segment === ".evodev" && (segments[index + 1] === "tasks" || segments[index + 1] === "state" && segments[index + 2] === "tasks"));
7527
- }
7528
- function sanitizeTextList(values) {
7529
- return values.map((value) => sanitizeText2(value)).filter((value) => value.length > 0);
7530
- }
7531
- function sanitizeId2(value) {
7532
- const sanitized = sanitizeText2(value).replace(/\[redacted\]/gi, "redacted").replace(/[^a-zA-Z0-9._-]/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
7533
- return sanitized || "item";
7534
- }
7535
- function uniqueSanitizedIds2(values) {
7536
- return Array.from(new Set(values.map((value) => sanitizeId2(value))));
7537
- }
7538
- function formatList(values) {
7539
- return values.length === 0 ? "none" : values.join(", ");
7540
- }
7541
- function createTaskId(title) {
7542
- const slug = sanitizeId2(title.toLowerCase()) || "task";
7543
- return `task-${slug}`.slice(0, 80);
7544
- }
7545
- async function pathExists4(path) {
7546
- try {
7547
- await stat5(path);
7548
- return true;
7549
- } catch (error) {
7550
- if (error instanceof Error && "code" in error && error.code === "ENOENT") {
7551
- return false;
7552
- }
7553
- throw error;
7554
- }
7555
- }
7556
- function isMissingPathError(error) {
7557
- return error instanceof Error && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR");
7558
- }
7559
- function isRecord7(value) {
7560
- return typeof value === "object" && value !== null && !Array.isArray(value);
7561
- }
7562
-
7563
7190
  // packages/core/src/team/index.ts
7564
7191
  import { spawn } from "node:child_process";
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";
7192
+ import { appendFile as appendFile3, cp, mkdir as mkdir7, readFile as readFile10, readdir as readdir9, stat as stat6, writeFile as writeFile6 } from "node:fs/promises";
7193
+ import { basename as basename2, dirname as dirname8, extname, isAbsolute as isAbsolute6, join as join13, relative as relative6, resolve as resolve3 } from "node:path";
7567
7194
 
7568
7195
  // packages/core/src/team/prompts.ts
7569
7196
  var TEAM_ROLE_STARTUP_PROMPT_TEMPLATE = [
@@ -7764,8 +7391,8 @@ function createTeamRunStore(homeDir) {
7764
7391
  paths: paths2,
7765
7392
  async createRunDirs(runId) {
7766
7393
  await migrateLegacyRunDirIfNeeded(paths2, runId);
7767
- await mkdir8(paths2.runDir(runId), { recursive: true });
7768
- await mkdir8(paths2.agentsDir(runId), { recursive: true });
7394
+ await mkdir7(paths2.runDir(runId), { recursive: true });
7395
+ await mkdir7(paths2.agentsDir(runId), { recursive: true });
7769
7396
  },
7770
7397
  async writeRun(run) {
7771
7398
  await this.createRunDirs(run.runId);
@@ -7776,7 +7403,7 @@ function createTeamRunStore(homeDir) {
7776
7403
  return parseTeamRunRecord(JSON.parse(await readFile10(paths2.runPath(runId), "utf8")));
7777
7404
  },
7778
7405
  async writeLatestRunId(runId) {
7779
- await mkdir8(paths2.runsDir, { recursive: true });
7406
+ await mkdir7(paths2.runsDir, { recursive: true });
7780
7407
  await writeJson3(paths2.latestRunPath, { version: 1, runId });
7781
7408
  },
7782
7409
  async readLatestRunId() {
@@ -7810,7 +7437,7 @@ function createTeamRunStore(homeDir) {
7810
7437
  async readAgents(runId) {
7811
7438
  await migrateLegacyRunDirIfNeeded(paths2, runId);
7812
7439
  try {
7813
- const entries = await readdir8(paths2.agentsDir(runId));
7440
+ const entries = await readdir9(paths2.agentsDir(runId));
7814
7441
  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)))));
7815
7442
  return agents.sort((left, right) => left.roleId.localeCompare(right.roleId));
7816
7443
  } catch {
@@ -7895,12 +7522,12 @@ function resolveTeamRunPaths(homeDir) {
7895
7522
  }
7896
7523
  async function migrateLegacyRunDirIfNeeded(paths2, runId) {
7897
7524
  const nextDir = paths2.runDir(runId);
7898
- if (await pathExists5(nextDir))
7525
+ if (await pathExists4(nextDir))
7899
7526
  return;
7900
7527
  const legacyDir = paths2.legacyRunDir(runId);
7901
- if (!await pathExists5(legacyDir))
7528
+ if (!await pathExists4(legacyDir))
7902
7529
  return;
7903
- await mkdir8(dirname8(nextDir), { recursive: true });
7530
+ await mkdir7(dirname8(nextDir), { recursive: true });
7904
7531
  await cp(legacyDir, nextDir, { recursive: true, errorOnExist: false, force: false });
7905
7532
  }
7906
7533
  async function writeTeamStatusSnapshot(input) {
@@ -8430,7 +8057,7 @@ async function listTeamRuns(input = {}) {
8430
8057
  const entries = new Set;
8431
8058
  for (const runsDir of [store.paths.runsDir, store.paths.legacyRunsDir]) {
8432
8059
  try {
8433
- for (const entry of await readdir8(runsDir))
8060
+ for (const entry of await readdir9(runsDir))
8434
8061
  entries.add(entry);
8435
8062
  } catch (error) {
8436
8063
  if (!isNotFoundError3(error))
@@ -8763,7 +8390,7 @@ async function listTeamAgents(input = {}) {
8763
8390
  }
8764
8391
  async function resolveTeamOverlay(input) {
8765
8392
  const repoTeamPath = join13(input.repoRoot, ".evodev", "team", "team.md");
8766
- if (await pathExists5(repoTeamPath)) {
8393
+ if (await pathExists4(repoTeamPath)) {
8767
8394
  return {
8768
8395
  source: "repo",
8769
8396
  teamPath: repoTeamPath,
@@ -8771,7 +8398,7 @@ async function resolveTeamOverlay(input) {
8771
8398
  };
8772
8399
  }
8773
8400
  const globalTeamPath = resolveGlobalTeamMarkdownPath(input.homeDir);
8774
- if (await pathExists5(globalTeamPath)) {
8401
+ if (await pathExists4(globalTeamPath)) {
8775
8402
  return {
8776
8403
  source: "global",
8777
8404
  teamPath: globalTeamPath,
@@ -8830,12 +8457,12 @@ function resolveTeamAgentReference(input) {
8830
8457
  if (reference.includes(":")) {
8831
8458
  throw new Error(`Unsupported team agent reference for ${input.roleId}: ${reference}`);
8832
8459
  }
8833
- if (isAbsolute5(reference)) {
8460
+ if (isAbsolute6(reference)) {
8834
8461
  throw new Error(`Team agent path for ${input.roleId} must be repo-relative.`);
8835
8462
  }
8836
- const sourcePath = resolve4(input.repoRoot, reference);
8463
+ const sourcePath = resolve3(input.repoRoot, reference);
8837
8464
  const relativePath = relative6(input.repoRoot, sourcePath);
8838
- if (relativePath === "" || relativePath.startsWith("..") || isAbsolute5(relativePath) || extname(sourcePath) !== ".md") {
8465
+ if (relativePath === "" || relativePath.startsWith("..") || isAbsolute6(relativePath) || extname(sourcePath) !== ".md") {
8839
8466
  throw new Error(`Team agent path for ${input.roleId} must be a repo-local Markdown file.`);
8840
8467
  }
8841
8468
  return {
@@ -8860,7 +8487,7 @@ async function readTeamAgentDefinition(input) {
8860
8487
  const reference = resolveTeamAgentReference(input);
8861
8488
  const markdown = await readTeamAgentMarkdown(reference);
8862
8489
  const parsed = parseMarkdownWithFrontmatter(markdown);
8863
- const evodev = isRecord8(parsed.frontmatter.evodev) ? parsed.frontmatter.evodev : {};
8490
+ const evodev = isRecord7(parsed.frontmatter.evodev) ? parsed.frontmatter.evodev : {};
8864
8491
  return {
8865
8492
  roleId: input.roleId,
8866
8493
  name: optionalString5(parsed.frontmatter.name) ?? defaultRoleName(input.roleId),
@@ -8977,7 +8604,7 @@ async function resolveTeamRole(input) {
8977
8604
  };
8978
8605
  }
8979
8606
  function parseTeamRoleDefinition(value, defaults) {
8980
- const input = isRecord8(value) ? value : {};
8607
+ const input = isRecord7(value) ? value : {};
8981
8608
  const roleId = optionalString5(input.roleId) ?? defaults.roleId;
8982
8609
  assertSafeId(roleId, "roleId");
8983
8610
  const runtime = parseRuntime(input.runtime, defaults.defaultRuntime);
@@ -9201,7 +8828,7 @@ class TmuxRuntimeAdapter {
9201
8828
 
9202
8829
  class NodeTeamRuntimeCommandRunner {
9203
8830
  async run(command, args, options = {}) {
9204
- return new Promise((resolve5, reject) => {
8831
+ return new Promise((resolve4, reject) => {
9205
8832
  const child = spawn(command, args, { stdio: ["pipe", "pipe", "pipe"] });
9206
8833
  let stdout = "";
9207
8834
  let stderr = "";
@@ -9215,7 +8842,7 @@ class NodeTeamRuntimeCommandRunner {
9215
8842
  });
9216
8843
  child.once("error", reject);
9217
8844
  child.once("close", (code) => {
9218
- resolve5({ exitCode: code ?? 1, stdout, stderr });
8845
+ resolve4({ exitCode: code ?? 1, stdout, stderr });
9219
8846
  });
9220
8847
  child.stdin.end(options.input ?? "");
9221
8848
  });
@@ -9506,7 +9133,7 @@ async function listDefaultTeamOverlayAssets(assetsRootDir) {
9506
9133
  await assertReadableFile(teamPath, "Default team asset");
9507
9134
  let entries;
9508
9135
  try {
9509
- entries = await readdir8(agentsDir, { withFileTypes: true });
9136
+ entries = await readdir9(agentsDir, { withFileTypes: true });
9510
9137
  } catch (error) {
9511
9138
  throw new Error(`Cannot read default team agents directory ${agentsDir}: ${describeError2(error)}`);
9512
9139
  }
@@ -9541,8 +9168,8 @@ async function writeTextFileIfMissing(path, content) {
9541
9168
  throw new Error(`Cannot inspect ${path}: ${describeError2(error)}`);
9542
9169
  }
9543
9170
  }
9544
- await mkdir8(dirname8(path), { recursive: true });
9545
- await writeFile7(path, content.endsWith(`
9171
+ await mkdir7(dirname8(path), { recursive: true });
9172
+ await writeFile6(path, content.endsWith(`
9546
9173
  `) ? content : `${content}
9547
9174
  `, "utf8");
9548
9175
  return true;
@@ -9550,7 +9177,7 @@ async function writeTextFileIfMissing(path, content) {
9550
9177
  function parseTeamDefinitionAgents(value) {
9551
9178
  if (value === undefined)
9552
9179
  return {};
9553
- if (!isRecord8(value))
9180
+ if (!isRecord7(value))
9554
9181
  throw new Error("team.md agents must be a role-id map.");
9555
9182
  const agents = {};
9556
9183
  for (const [roleId, reference] of Object.entries(value)) {
@@ -9616,7 +9243,7 @@ function parseSimpleYaml(content) {
9616
9243
  throw new Error(`Invalid YAML line: ${trimmed}`);
9617
9244
  const key = trimmed.slice(0, separator).trim();
9618
9245
  const rawValue = trimmed.slice(separator + 1).trim();
9619
- if (!isRecord8(parent))
9246
+ if (!isRecord7(parent))
9620
9247
  throw new Error(`Invalid YAML parent for key ${key}.`);
9621
9248
  if (rawValue === "") {
9622
9249
  const next = findNextYamlContentLine(lines, index + 1);
@@ -9681,7 +9308,7 @@ function resolveGlobalTeamMarkdownPath(homeDir) {
9681
9308
  return join13(resolveEvoDevPaths(homeDir).rootDir, "team", "team.md");
9682
9309
  }
9683
9310
  function parseRolePermissions(value, main) {
9684
- const input = isRecord8(value) ? value : {};
9311
+ const input = isRecord7(value) ? value : {};
9685
9312
  return {
9686
9313
  writeMode: parseWriteMode(input.writeMode, "repo-write"),
9687
9314
  canUseTeamsMcp: optionalBoolean2(input.canUseTeamsMcp) ?? true,
@@ -9690,14 +9317,14 @@ function parseRolePermissions(value, main) {
9690
9317
  };
9691
9318
  }
9692
9319
  function parseRolePolicy(value, recordTranscript) {
9693
- const input = isRecord8(value) ? value : {};
9320
+ const input = isRecord7(value) ? value : {};
9694
9321
  return {
9695
9322
  roleInstancePolicy: "single-per-role",
9696
9323
  recordTranscript: optionalBoolean2(input.recordTranscript) ?? recordTranscript
9697
9324
  };
9698
9325
  }
9699
9326
  function parseTeamRunRecord(value) {
9700
- if (!isRecord8(value) || value.version !== 1)
9327
+ if (!isRecord7(value) || value.version !== 1)
9701
9328
  throw new Error("Invalid team run record.");
9702
9329
  const run = value;
9703
9330
  assertSafeId(run.runId, "runId");
@@ -9707,7 +9334,7 @@ function parseTeamRunRecord(value) {
9707
9334
  return run;
9708
9335
  }
9709
9336
  function parseTeamAgentRecord(value) {
9710
- if (!isRecord8(value) || value.version !== 1)
9337
+ if (!isRecord7(value) || value.version !== 1)
9711
9338
  throw new Error("Invalid team agent record.");
9712
9339
  const agent = value;
9713
9340
  assertSafeId(agent.agentId, "agentId");
@@ -9728,7 +9355,7 @@ function parseTeamAgentRecord(value) {
9728
9355
  ].includes(agent.status)) {
9729
9356
  throw new Error("Invalid agent status.");
9730
9357
  }
9731
- const nativeSessionValue = isRecord8(value.nativeSession) ? value.nativeSession : {};
9358
+ const nativeSessionValue = isRecord7(value.nativeSession) ? value.nativeSession : {};
9732
9359
  return {
9733
9360
  ...agent,
9734
9361
  nativeSession: {
@@ -9738,7 +9365,7 @@ function parseTeamAgentRecord(value) {
9738
9365
  };
9739
9366
  }
9740
9367
  function parseTeamMessageRecord(value) {
9741
- if (!isRecord8(value) || value.version !== 1)
9368
+ if (!isRecord7(value) || value.version !== 1)
9742
9369
  throw new Error("Invalid team message record.");
9743
9370
  const message = value;
9744
9371
  assertSafeId(message.messageId, "messageId");
@@ -9767,7 +9394,7 @@ function parseTeamPendingMessageRecord(value) {
9767
9394
  };
9768
9395
  }
9769
9396
  function parseTeamMessageListFile(value) {
9770
- if (!isRecord8(value) || value.version !== 1)
9397
+ if (!isRecord7(value) || value.version !== 1)
9771
9398
  throw new Error("Invalid team message list.");
9772
9399
  const messages = Array.isArray(value.messages) ? value.messages.map(parseTeamPendingMessageRecord) : [];
9773
9400
  return {
@@ -9777,7 +9404,7 @@ function parseTeamMessageListFile(value) {
9777
9404
  };
9778
9405
  }
9779
9406
  function parseTeamEventRecord(value) {
9780
- if (!isRecord8(value) || value.version !== 1)
9407
+ if (!isRecord7(value) || value.version !== 1)
9781
9408
  throw new Error("Invalid team event record.");
9782
9409
  const event = value;
9783
9410
  assertSafeId(event.eventId, "eventId");
@@ -9949,7 +9576,7 @@ async function readTeamBindingConfig(path) {
9949
9576
  }
9950
9577
  }
9951
9578
  function parseTeamBindingConfig(value) {
9952
- if (!isRecord8(value) || value.version !== 1)
9579
+ if (!isRecord7(value) || value.version !== 1)
9953
9580
  throw new Error("Invalid team binding config.");
9954
9581
  const updatedAt = optionalString5(value.updatedAt) ?? "unknown";
9955
9582
  const rolesValue = Array.isArray(value.roles) ? value.roles : [];
@@ -9960,7 +9587,7 @@ function parseTeamBindingConfig(value) {
9960
9587
  };
9961
9588
  }
9962
9589
  function parseTeamBindingRecord(value) {
9963
- if (!isRecord8(value) || value.version !== 1) {
9590
+ if (!isRecord7(value) || value.version !== 1) {
9964
9591
  throw new Error("Invalid team binding record.");
9965
9592
  }
9966
9593
  const roleId = optionalString5(value.roleId);
@@ -9994,7 +9621,7 @@ function mergeTeamRoleBindings(global, project) {
9994
9621
  function isNotFoundError3(error) {
9995
9622
  return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
9996
9623
  }
9997
- async function pathExists5(path) {
9624
+ async function pathExists4(path) {
9998
9625
  try {
9999
9626
  await stat6(path);
10000
9627
  return true;
@@ -10005,20 +9632,20 @@ async function pathExists5(path) {
10005
9632
  }
10006
9633
  }
10007
9634
  async function writeJson3(path, value) {
10008
- await mkdir8(dirname8(path), { recursive: true });
10009
- await writeFile7(path, `${JSON.stringify(value, null, 2)}
9635
+ await mkdir7(dirname8(path), { recursive: true });
9636
+ await writeFile6(path, `${JSON.stringify(value, null, 2)}
10010
9637
  `, "utf8");
10011
9638
  }
10012
9639
  async function appendJsonLine2(path, value) {
10013
- await mkdir8(dirname8(path), { recursive: true });
9640
+ await mkdir7(dirname8(path), { recursive: true });
10014
9641
  await appendFile3(path, `${JSON.stringify(value)}
10015
9642
  `, "utf8");
10016
9643
  }
10017
- async function readJsonLines(path, parse) {
9644
+ async function readJsonLines(path, parse2) {
10018
9645
  try {
10019
9646
  const text2 = await readFile10(path, "utf8");
10020
9647
  return text2.split(`
10021
- `).filter((line) => line.trim() !== "").map((line) => parse(JSON.parse(line)));
9648
+ `).filter((line) => line.trim() !== "").map((line) => parse2(JSON.parse(line)));
10022
9649
  } catch (error) {
10023
9650
  if (isNotFoundError3(error))
10024
9651
  return [];
@@ -10048,7 +9675,7 @@ function optionalNullableString(value) {
10048
9675
  function optionalBoolean2(value) {
10049
9676
  return typeof value === "boolean" ? value : undefined;
10050
9677
  }
10051
- function isRecord8(value) {
9678
+ function isRecord7(value) {
10052
9679
  return typeof value === "object" && value !== null && !Array.isArray(value);
10053
9680
  }
10054
9681
  function describeError2(error) {
@@ -10108,7 +9735,7 @@ var DEFAULT_EVENT_SETTINGS = {
10108
9735
  WorktreeCreate: true,
10109
9736
  WorktreeRemove: true
10110
9737
  };
10111
- var SENSITIVE_TEXT_PATTERN4 = /https?:\/\/\S+|\b(secret|token|password|passwd|private|internal|api[_-]?key|apikey|credential|credentials|\.env)\b/i;
9738
+ var SENSITIVE_TEXT_PATTERN3 = /https?:\/\/\S+|\b(secret|token|password|passwd|private|internal|api[_-]?key|apikey|credential|credentials|\.env)\b/i;
10112
9739
  var SOURCE_LIKE_PATTERN = /\b(function|class|import|export|const|let|var)\b.*[{};]/s;
10113
9740
  var TEAM_MESSAGE_DELIVERY_EVENTS = new Set([
10114
9741
  "SessionStart",
@@ -10124,6 +9751,12 @@ var CODEX_STOP_EVENTS_WITHOUT_ADDITIONAL_CONTEXT = new Set([
10124
9751
  "Stop",
10125
9752
  "SubagentStop"
10126
9753
  ]);
9754
+ var COMPLETION_EVENTS_WITHOUT_DEVELOPMENT_DIAGNOSTICS = new Set([
9755
+ "Stop",
9756
+ "SubagentStop",
9757
+ "TaskCompleted",
9758
+ "TeammateIdle"
9759
+ ]);
10127
9760
  function createDefaultHookSettings() {
10128
9761
  return {
10129
9762
  enabled: true,
@@ -10152,9 +9785,9 @@ function parseHookSettings(value) {
10152
9785
  const defaults = createDefaultHookSettings();
10153
9786
  if (value === undefined || value === null)
10154
9787
  return defaults;
10155
- if (!isRecord9(value))
9788
+ if (!isRecord8(value))
10156
9789
  throw new Error("Invalid hooks settings; expected object.");
10157
- const observability = isRecord9(value.observability) ? value.observability : undefined;
9790
+ const observability = isRecord8(value.observability) ? value.observability : undefined;
10158
9791
  optionalBoolean3(observability?.metadataOnly, defaults.observability.metadataOnly, "hooks.observability.metadataOnly");
10159
9792
  optionalBoolean3(observability?.rawPayloadStorage, defaults.observability.rawPayloadStorage, "hooks.observability.rawPayloadStorage");
10160
9793
  return {
@@ -10288,8 +9921,7 @@ function resolveHookRuntimeSessionPaths(input) {
10288
9921
  const sessionDir = join14(input.homeDir, ".evodev", "STATE", "hooks", "sessions", input.sessionKey);
10289
9922
  return {
10290
9923
  sessionDir,
10291
- bindingPath: join14(sessionDir, "binding.json"),
10292
- contractPath: join14(sessionDir, "contract.json")
9924
+ bindingPath: join14(sessionDir, "binding.json")
10293
9925
  };
10294
9926
  }
10295
9927
  async function handleHookRuntime(input) {
@@ -10305,7 +9937,13 @@ async function handleHookRuntime(input) {
10305
9937
  summary: `Hook ${input.event.type} ignored because EvoDev hooks are disabled.`
10306
9938
  };
10307
9939
  }
9940
+ if (isActiveClaudeStopHook(input)) {
9941
+ return createRuntimeResult(input, null, {
9942
+ summary: `${input.event.type} re-entry allowed to complete without hook output.`
9943
+ });
9944
+ }
10308
9945
  const diagnostics = await recordTeamNativeSessionFromHook(input);
9946
+ const projectDiagnostics = await recordDiscoveredProjectFromHook(input);
10309
9947
  let result;
10310
9948
  if (input.event.type === "SessionStart")
10311
9949
  result = await handleSessionStart(input);
@@ -10333,7 +9971,8 @@ async function handleHookRuntime(input) {
10333
9971
  const messageDiagnostics = await deliverPendingTeamMessagesFromHook(input, result);
10334
9972
  const scopedContextDiagnostics = await injectScopedKnowledgeContextFromHook(input, result);
10335
9973
  const teamStateDiagnostics = await recordTeamAgentHookStateFromHook(input);
10336
- return appendRuntimeDiagnostics(appendRuntimeDiagnostics(appendRuntimeDiagnostics(appendRuntimeDiagnostics(appendRuntimeDiagnostics(appendRuntimeDiagnostics(result, diagnostics), sessionMemoryDiagnostics), evolutionDiagnostics), messageDiagnostics), scopedContextDiagnostics), teamStateDiagnostics);
9974
+ const completed = appendRuntimeDiagnostics(appendRuntimeDiagnostics(appendRuntimeDiagnostics(appendRuntimeDiagnostics(appendRuntimeDiagnostics(appendRuntimeDiagnostics(appendRuntimeDiagnostics(result, diagnostics), projectDiagnostics), sessionMemoryDiagnostics), evolutionDiagnostics), messageDiagnostics), scopedContextDiagnostics), teamStateDiagnostics);
9975
+ return appendDevelopmentHookDiagnostics(input, completed);
10337
9976
  }
10338
9977
  function formatHookRuntimeOutput(result) {
10339
9978
  return result.output === null ? "" : `${JSON.stringify(result.output)}
@@ -10342,6 +9981,29 @@ function formatHookRuntimeOutput(result) {
10342
9981
  function isHookEventEnabled(settings, target, eventType) {
10343
9982
  return settings.enabled === true && settings.targets[target]?.enabled === true && settings.targets[target]?.events[eventType] === true;
10344
9983
  }
9984
+ async function recordDiscoveredProjectFromHook(input) {
9985
+ if (input.event.type !== "SessionStart" && input.event.type !== "UserPromptSubmit" && input.event.type !== "CwdChanged") {
9986
+ return { stateWrites: [], warnings: [] };
9987
+ }
9988
+ const cwd = optionalPayloadString(input.rawPayload.cwd);
9989
+ if (cwd === null)
9990
+ return { stateWrites: [], warnings: [] };
9991
+ try {
9992
+ const result = await recordDiscoveredProject({
9993
+ homeDir: input.homeDir,
9994
+ cwd,
9995
+ target: input.target,
9996
+ sessionKey: resolveTraceSessionKey(input.rawPayload),
9997
+ now: input.receivedAt === undefined || input.receivedAt === "dry-run" ? undefined : input.receivedAt
9998
+ });
9999
+ return result === null ? { stateWrites: [], warnings: [] } : { stateWrites: [result.path], warnings: [] };
10000
+ } catch {
10001
+ return {
10002
+ stateWrites: [],
10003
+ warnings: ["Local project discovery could not be updated at this hook safe point."]
10004
+ };
10005
+ }
10006
+ }
10345
10007
  async function recordTeamNativeSessionFromHook(input) {
10346
10008
  const environment = input.environment ?? {};
10347
10009
  const runId = optionalPayloadString(environment.EVODEV_TEAM_RUN_ID);
@@ -10580,41 +10242,27 @@ async function handleSessionStart(input) {
10580
10242
  });
10581
10243
  }
10582
10244
  async function handleUserPromptSubmit(input) {
10583
- const classification = classifyUserPrompt(input.rawPayload.prompt ?? input.rawPayload.userPrompt);
10584
10245
  const sessionKey = resolveHookSessionKey(input.rawPayload);
10585
10246
  const paths2 = resolveHookRuntimeSessionPaths({ homeDir: input.homeDir, sessionKey });
10586
- const contract = routeTaskContract(createHookTaskContract(input, classification));
10587
10247
  const previousBinding = await readSessionBinding(input.homeDir, input.rawPayload);
10588
10248
  const teamRuntimeContext = previousBinding?.teamRuntimeContextDeliveredAt === undefined || previousBinding.teamRuntimeContextDeliveredAt === null ? await createTeamRuntimeContextForUserPrompt(input) : null;
10589
- const shouldShowDiagnostics = input.teamRuntimeDisplayMode === "development";
10590
10249
  const teamRuntimeContextDeliveredAt = teamRuntimeContext !== null ? input.receivedAt ?? new Date().toISOString() : previousBinding?.teamRuntimeContextDeliveredAt ?? null;
10591
10250
  const binding = {
10592
10251
  version: 1,
10593
10252
  target: input.target,
10594
10253
  sessionKey,
10595
- taskId: contract.taskId,
10596
- contractPath: paths2.contractPath,
10597
10254
  cwd: optionalPayloadString(input.rawPayload.cwd),
10598
- route: contract.route,
10599
10255
  teamRuntimeContextDeliveredAt,
10600
10256
  updatedAt: input.receivedAt ?? new Date().toISOString()
10601
10257
  };
10602
- await writeTaskContract(paths2.contractPath, contract, { overwrite: true });
10603
10258
  await writeJsonFile2(paths2.bindingPath, binding);
10604
- const visibleContext = createUserPromptVisibleContext({
10605
- classification,
10606
- contract,
10607
- contractPath: paths2.contractPath
10608
- });
10609
- let output = visibleContext === null || !shouldShowDiagnostics ? null : hookOutput(input.event.type, {
10610
- additionalContext: visibleContext
10611
- });
10259
+ let output = null;
10612
10260
  if (teamRuntimeContext !== null) {
10613
10261
  output = appendAdditionalContext(output, input.event.type, teamRuntimeContext);
10614
10262
  }
10615
10263
  return createRuntimeResult(input, output, {
10616
- summary: "User prompt observed; Task Contract prepared.",
10617
- stateWrites: [paths2.contractPath, paths2.bindingPath]
10264
+ summary: "User prompt observed; session binding updated.",
10265
+ stateWrites: [paths2.bindingPath]
10618
10266
  });
10619
10267
  }
10620
10268
  async function createTeamRuntimeContextForUserPrompt(input) {
@@ -10642,40 +10290,11 @@ async function handlePreToolUse(input) {
10642
10290
  });
10643
10291
  }
10644
10292
  async function handlePostToolUse(input) {
10645
- const contract = await readActiveContract(input.homeDir, input.rawPayload);
10646
- const binding = await readSessionBinding(input.homeDir, input.rawPayload);
10647
- if (contract === null || binding?.contractPath === null || binding?.contractPath === undefined) {
10648
- return handleAdditionalContext(input, input.event.type);
10649
- }
10650
- const status = optionalPayloadNumber(input.rawPayload.exit_code ?? input.rawPayload.exitCode);
10651
- const nextContract = {
10652
- ...contract,
10653
- evidence: {
10654
- metadataOnly: true,
10655
- items: [
10656
- ...contract.evidence.items,
10657
- {
10658
- type: "command-result",
10659
- id: input.event.eventId,
10660
- status: status === 0 ? "pass" : status === null ? "unknown" : "fail",
10661
- summary: input.event.payload.summary,
10662
- rawOutputStored: false,
10663
- sourceContentStored: false
10664
- }
10665
- ]
10666
- }
10667
- };
10668
- await writeTaskContract(binding.contractPath, nextContract, { overwrite: true });
10669
- return createRuntimeResult(input, null, {
10670
- summary: "Post-tool metadata evidence recorded.",
10671
- stateWrites: [binding.contractPath]
10672
- });
10293
+ return handleAdditionalContext(input, input.event.type);
10673
10294
  }
10674
10295
  async function handleCompletionObservation(input) {
10675
- const contract = await readActiveContract(input.homeDir, input.rawPayload);
10676
- const suffix = contract === null ? "without an active Task Contract" : `for Task Contract ${contract.taskId}`;
10677
10296
  return createRuntimeResult(input, null, {
10678
- summary: `${input.event.type} observed ${suffix}; no completion control enforced.`
10297
+ summary: `${input.event.type} observed as metadata-only hook context.`
10679
10298
  });
10680
10299
  }
10681
10300
  async function handlePreCompact(input) {
@@ -10726,7 +10345,7 @@ function hookOutput(eventName, output) {
10726
10345
  function appendAdditionalContext(output, eventName, context) {
10727
10346
  if (output === null)
10728
10347
  return hookOutput(eventName, { additionalContext: context });
10729
- const hookSpecificOutput = isRecord9(output.hookSpecificOutput) ? output.hookSpecificOutput : {};
10348
+ const hookSpecificOutput = isRecord8(output.hookSpecificOutput) ? output.hookSpecificOutput : {};
10730
10349
  const previous = typeof hookSpecificOutput.additionalContext === "string" ? hookSpecificOutput.additionalContext : "";
10731
10350
  return {
10732
10351
  ...output,
@@ -10739,6 +10358,34 @@ ${context}`
10739
10358
  }
10740
10359
  };
10741
10360
  }
10361
+ function appendDevelopmentHookDiagnostics(input, result) {
10362
+ if (input.teamRuntimeDisplayMode !== "development" || COMPLETION_EVENTS_WITHOUT_DEVELOPMENT_DIAGNOSTICS.has(input.event.type) || !canDeliverTeamMessagesFromHook(input.target, input.event.type)) {
10363
+ return result;
10364
+ }
10365
+ return {
10366
+ ...result,
10367
+ output: appendAdditionalContext(result.output, input.event.type, formatDevelopmentHookDiagnostics(input))
10368
+ };
10369
+ }
10370
+ function isActiveClaudeStopHook(input) {
10371
+ return input.target === "claude" && (input.event.type === "Stop" || input.event.type === "SubagentStop") && input.rawPayload.stop_hook_active === true;
10372
+ }
10373
+ function formatDevelopmentHookDiagnostics(input) {
10374
+ const metadata = Object.entries(input.event.payload.metadata);
10375
+ const inputFields = Object.keys(input.rawPayload).map((field) => field.replace(/[^A-Za-z0-9._-]/g, "-").slice(0, 80)).filter((field) => field.length > 0).slice(0, 30);
10376
+ return [
10377
+ "EvoDev hook development diagnostics",
10378
+ `Target: ${input.target}`,
10379
+ `Event: ${input.event.type}`,
10380
+ `Summary: ${input.event.payload.summary}`,
10381
+ `Input fields: ${inputFields.join(", ") || "none"}`,
10382
+ "Normalized metadata:",
10383
+ ...metadata.length === 0 ? ["- none"] : metadata.map(([key, value]) => `- ${key}: ${formatMetadataValue(value)}`),
10384
+ `Redactions: ${input.event.payload.redactions.join(", ") || "none"}`,
10385
+ "Raw payload included: false"
10386
+ ].join(`
10387
+ `);
10388
+ }
10742
10389
  function formatTeamInboxContext(messages) {
10743
10390
  const blocks = messages.map((message) => [
10744
10391
  "[EvoDev team message]",
@@ -10762,101 +10409,6 @@ function truncateTeamMessageBody(value) {
10762
10409
  return value;
10763
10410
  return `${value.slice(0, 4000)}...[truncated:${value.length - 4000}]`;
10764
10411
  }
10765
- function createUserPromptVisibleContext(input) {
10766
- if (!input.classification.needsClarification)
10767
- return null;
10768
- return [
10769
- "EvoDev advisory: clarification may be needed before broad changes.",
10770
- `Task Contract: ${input.contractPath}`,
10771
- `Suggested mode: ${input.contract.route.mode ?? "unknown"}`,
10772
- `Suggested workflow: ${input.contract.route.workflowId ?? "none"}`,
10773
- `Reason: ${input.contract.route.rationale}`
10774
- ].join(" ");
10775
- }
10776
- function createHookTaskContract(input, classification) {
10777
- const sessionKey = resolveHookSessionKey(input.rawPayload);
10778
- const targetName = formatHookTargetName(input.target);
10779
- const contract = createTaskContract({
10780
- title: `${targetName} hook task ${sessionKey}`,
10781
- summary: `${targetName} prompt classified as ${classification.kind}; raw prompt is not stored by EvoDev.`,
10782
- projectId: null
10783
- });
10784
- return {
10785
- ...contract,
10786
- currentState: {
10787
- summary: `UserPromptSubmit received through ${targetName} hooks; raw prompt omitted from Task Contract.`,
10788
- evidenceRefs: []
10789
- },
10790
- targetState: {
10791
- summary: `Complete the ${classification.kind} task through EvoDev-controlled workflow.`,
10792
- nonGoals: ["Do not store raw prompts, transcripts, source content, secrets, or raw output."],
10793
- constraints: [
10794
- `prompt-kind:${classification.kind}`,
10795
- ...classification.riskTerms.map((term) => `risk:${term}`)
10796
- ]
10797
- },
10798
- scope: {
10799
- ...contract.scope,
10800
- requiresUserConfirmation: classification.riskTerms
10801
- },
10802
- context: {
10803
- ...contract.context,
10804
- assumptions: [
10805
- `hook-session:${sessionKey}`,
10806
- `cwd:${optionalPayloadString(input.rawPayload.cwd) ?? "unknown"}`
10807
- ],
10808
- openQuestions: classification.needsClarification ? ["User request may need clarification before broad changes."] : []
10809
- }
10810
- };
10811
- }
10812
- function formatHookTargetName(target) {
10813
- return target === "codex" ? "Codex" : "Claude";
10814
- }
10815
- function classifyUserPrompt(value) {
10816
- const text2 = typeof value === "string" ? value.toLowerCase() : "";
10817
- const riskTerms = [
10818
- "security",
10819
- "release",
10820
- "publish",
10821
- "hook",
10822
- "memory",
10823
- "learning",
10824
- "secret",
10825
- "privacy"
10826
- ].filter((term) => text2.includes(term));
10827
- let kind = "feature";
10828
- if (/\bbug|fix|error|failed|failure\b/.test(text2))
10829
- kind = "bugfix";
10830
- if (/\brefactor|migration|migrate\b/.test(text2))
10831
- kind = "refactor";
10832
- if (/\breview|audit\b/.test(text2))
10833
- kind = "review";
10834
- if (/\btest|coverage\b/.test(text2))
10835
- kind = "test";
10836
- if (/\bdoc|readme|guide\b/.test(text2))
10837
- kind = "docs";
10838
- if (riskTerms.includes("security") || riskTerms.includes("privacy"))
10839
- kind = "security";
10840
- if (riskTerms.includes("release") || riskTerms.includes("publish"))
10841
- kind = "release";
10842
- return {
10843
- kind,
10844
- riskTerms,
10845
- needsClarification: text2.trim().length < 12 || /\bmaybe|unclear|not sure\b/.test(text2)
10846
- };
10847
- }
10848
- async function readActiveContract(homeDir, payload) {
10849
- const binding = await readSessionBinding(homeDir, payload);
10850
- if (binding?.contractPath === null || binding?.contractPath === undefined)
10851
- return null;
10852
- try {
10853
- return JSON.parse(await readFile11(binding.contractPath, "utf8"));
10854
- } catch (error) {
10855
- if (isNotFoundError4(error))
10856
- return null;
10857
- throw error;
10858
- }
10859
- }
10860
10412
  async function readSessionBinding(homeDir, payload) {
10861
10413
  const sessionKey = resolveHookSessionKey(payload);
10862
10414
  const paths2 = resolveHookRuntimeSessionPaths({ homeDir, sessionKey });
@@ -10875,8 +10427,8 @@ function resolveHookSessionKey(payload) {
10875
10427
  return `session-${sha256Short(source)}`;
10876
10428
  }
10877
10429
  async function writeJsonFile2(path, value) {
10878
- await mkdir9(dirname9(path), { recursive: true });
10879
- await writeFile8(path, `${JSON.stringify(value, null, 2)}
10430
+ await mkdir8(dirname9(path), { recursive: true });
10431
+ await writeFile7(path, `${JSON.stringify(value, null, 2)}
10880
10432
  `, "utf8");
10881
10433
  }
10882
10434
  function optionalPayloadString(value) {
@@ -10885,9 +10437,6 @@ function optionalPayloadString(value) {
10885
10437
  function safeDiagnosticId(value) {
10886
10438
  return value.replace(/[^A-Za-z0-9._-]/g, "-").slice(0, 120) || "unknown";
10887
10439
  }
10888
- function optionalPayloadNumber(value) {
10889
- return typeof value === "number" && Number.isFinite(value) ? value : null;
10890
- }
10891
10440
  function isNotFoundError4(error) {
10892
10441
  return error instanceof Error && "code" in error && error.code === "ENOENT";
10893
10442
  }
@@ -10901,9 +10450,9 @@ function normalizeHookEventType(type, warnings) {
10901
10450
  throw new Error(`Unsupported hook event type: ${type}`);
10902
10451
  }
10903
10452
  function parseHookTargetSettings(value, defaults, target) {
10904
- const targets = isRecord9(value) ? value : {};
10905
- const targetSettings = isRecord9(targets[target]) ? targets[target] : {};
10906
- const events = isRecord9(targetSettings.events) ? targetSettings.events : {};
10453
+ const targets = isRecord8(value) ? value : {};
10454
+ const targetSettings = isRecord8(targets[target]) ? targets[target] : {};
10455
+ const events = isRecord8(targetSettings.events) ? targetSettings.events : {};
10907
10456
  const parsedEvents = { ...defaults.events };
10908
10457
  for (const eventType of CANONICAL_HOOK_EVENT_TYPES) {
10909
10458
  parsedEvents[eventType] = optionalBoolean3(events[eventType], defaults.events[eventType], `hooks.targets.${target}.events.${eventType}`);
@@ -10915,7 +10464,7 @@ function parseHookTargetSettings(value, defaults, target) {
10915
10464
  }
10916
10465
  function extractMetadata(type, payload, redactions) {
10917
10466
  const metadata = {};
10918
- const toolInput = isRecord9(payload.tool_input) ? payload.tool_input : isRecord9(payload.toolInput) ? payload.toolInput : {};
10467
+ const toolInput = isRecord8(payload.tool_input) ? payload.tool_input : isRecord8(payload.toolInput) ? payload.toolInput : {};
10919
10468
  const toolName = optionalSanitizedString(payload.tool_name ?? payload.toolName, redactions);
10920
10469
  if (toolName !== null)
10921
10470
  metadata.toolName = toolName;
@@ -10962,7 +10511,7 @@ function summarizeEvent(type, metadata) {
10962
10511
  function optionalSanitizedString(value, redactions, options = {}) {
10963
10512
  if (typeof value !== "string" || value.length === 0)
10964
10513
  return null;
10965
- if (SENSITIVE_TEXT_PATTERN4.test(value) || SOURCE_LIKE_PATTERN.test(value)) {
10514
+ if (SENSITIVE_TEXT_PATTERN3.test(value) || SOURCE_LIKE_PATTERN.test(value)) {
10966
10515
  redactions.push(options.classifyOnly ? "sensitive-command" : "sensitive-text");
10967
10516
  return options.classifyOnly ? value : "[redacted]";
10968
10517
  }
@@ -10993,7 +10542,7 @@ function optionalNumber(value) {
10993
10542
  function formatMetadataValue(value) {
10994
10543
  return Array.isArray(value) ? value.join(",") : String(value);
10995
10544
  }
10996
- function isRecord9(value) {
10545
+ function isRecord8(value) {
10997
10546
  return typeof value === "object" && value !== null && !Array.isArray(value);
10998
10547
  }
10999
10548
 
@@ -11295,20 +10844,20 @@ function expectNonNegativeInteger(value, path) {
11295
10844
  return value;
11296
10845
  }
11297
10846
  // packages/core/src/config/store.ts
11298
- import { mkdir as mkdir10, readFile as readFile13, writeFile as writeFile9 } from "node:fs/promises";
10847
+ import { mkdir as mkdir9, readFile as readFile13, writeFile as writeFile8 } from "node:fs/promises";
11299
10848
  import { dirname as dirname10 } from "node:path";
11300
10849
  function createCoreConfigStore(homeDir) {
11301
10850
  const paths2 = resolveEvoDevPaths(homeDir);
11302
10851
  return {
11303
10852
  paths: paths2,
11304
10853
  async ensureBaseDirs() {
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 });
10854
+ await mkdir9(paths2.stateDir, { recursive: true });
10855
+ await mkdir9(paths2.logsDir, { recursive: true });
10856
+ await mkdir9(paths2.knowledgeDir, { recursive: true });
10857
+ await mkdir9(paths2.evosCasesDir, { recursive: true });
10858
+ await mkdir9(paths2.roleAgentsDir, { recursive: true });
10859
+ await mkdir9(paths2.teamsDir, { recursive: true });
10860
+ await mkdir9(paths2.runsDir, { recursive: true });
11312
10861
  },
11313
10862
  async ensureKnowledgeBase() {
11314
10863
  await ensureKnowledgeBaseFiles(paths2);
@@ -11356,8 +10905,8 @@ async function initializeCoreConfig(homeDir) {
11356
10905
  return store;
11357
10906
  }
11358
10907
  async function ensureKnowledgeBaseFiles(paths2) {
11359
- await mkdir10(paths2.knowledgeDir, { recursive: true });
11360
- await mkdir10(paths2.evosCasesDir, { recursive: true });
10908
+ await mkdir9(paths2.knowledgeDir, { recursive: true });
10909
+ await mkdir9(paths2.evosCasesDir, { recursive: true });
11361
10910
  await ensureOkfKnowledgeBase(paths2.homeDir);
11362
10911
  await writeTextIfMissing2(`${paths2.knowledgeDir}/README.md`, [
11363
10912
  "# EvoDev Knowledge",
@@ -11426,7 +10975,7 @@ async function ensureKnowledgeBaseFiles(paths2) {
11426
10975
  teams: []
11427
10976
  });
11428
10977
  }
11429
- async function readJsonFile2(filePath, parse) {
10978
+ async function readJsonFile2(filePath, parse2) {
11430
10979
  let raw;
11431
10980
  try {
11432
10981
  raw = await readFile13(filePath, "utf8");
@@ -11440,7 +10989,7 @@ async function readJsonFile2(filePath, parse) {
11440
10989
  throw new EvoDevConfigError(`Invalid JSON (${describeFileError2(error)})`, filePath);
11441
10990
  }
11442
10991
  try {
11443
- return parse(json);
10992
+ return parse2(json);
11444
10993
  } catch (error) {
11445
10994
  if (error instanceof EvoDevConfigError) {
11446
10995
  throw new EvoDevConfigError(error.message, filePath);
@@ -11448,9 +10997,9 @@ async function readJsonFile2(filePath, parse) {
11448
10997
  throw error;
11449
10998
  }
11450
10999
  }
11451
- async function readJsonFileOrDefault(filePath, parse, fallback) {
11000
+ async function readJsonFileOrDefault(filePath, parse2, fallback) {
11452
11001
  try {
11453
- return await readJsonFile2(filePath, parse);
11002
+ return await readJsonFile2(filePath, parse2);
11454
11003
  } catch (error) {
11455
11004
  if (error instanceof EvoDevConfigError && error.message.includes("ENOENT")) {
11456
11005
  return fallback;
@@ -11486,7 +11035,7 @@ async function writeIndexIfMissingOrMigrate(filePath, kind, defaults) {
11486
11035
  } catch (error) {
11487
11036
  throw new EvoDevConfigError(`Invalid bootstrap index JSON (${describeFileError2(error)})`, filePath);
11488
11037
  }
11489
- if (!isRecord10(existing) || existing.kind !== kind)
11038
+ if (!isRecord9(existing) || existing.kind !== kind)
11490
11039
  return;
11491
11040
  const migrated = { ...defaults, ...existing };
11492
11041
  if (Object.keys(defaults).every((key) => (key in existing)))
@@ -11498,16 +11047,16 @@ async function writeTextIfMissing2(filePath, value) {
11498
11047
  await readFile13(filePath, "utf8");
11499
11048
  } catch (error) {
11500
11049
  if (isNodeError2(error) && error.code === "ENOENT") {
11501
- await mkdir10(dirname10(filePath), { recursive: true });
11502
- await writeFile9(filePath, value, "utf8");
11050
+ await mkdir9(dirname10(filePath), { recursive: true });
11051
+ await writeFile8(filePath, value, "utf8");
11503
11052
  return;
11504
11053
  }
11505
11054
  throw new EvoDevConfigError(`Cannot inspect config file (${describeFileError2(error)})`, filePath);
11506
11055
  }
11507
11056
  }
11508
11057
  async function writeJsonFile3(filePath, value) {
11509
- await mkdir10(dirname10(filePath), { recursive: true });
11510
- await writeFile9(filePath, `${JSON.stringify(value, null, 2)}
11058
+ await mkdir9(dirname10(filePath), { recursive: true });
11059
+ await writeFile8(filePath, `${JSON.stringify(value, null, 2)}
11511
11060
  `, "utf8");
11512
11061
  }
11513
11062
  function describeFileError2(error) {
@@ -11519,12 +11068,12 @@ function describeFileError2(error) {
11519
11068
  function isNodeError2(error) {
11520
11069
  return error instanceof Error && "code" in error;
11521
11070
  }
11522
- function isRecord10(value) {
11071
+ function isRecord9(value) {
11523
11072
  return typeof value === "object" && value !== null && !Array.isArray(value);
11524
11073
  }
11525
11074
  // packages/core/src/daemon/index.ts
11526
11075
  import { randomBytes } from "node:crypto";
11527
- import { mkdir as mkdir13, readFile as readFile16, readdir as readdir11, rm as rm4, stat as stat9, writeFile as writeFile12 } from "node:fs/promises";
11076
+ import { mkdir as mkdir12, readFile as readFile16, readdir as readdir12, rm as rm4, stat as stat9, writeFile as writeFile11 } from "node:fs/promises";
11528
11077
  import { createServer } from "node:http";
11529
11078
  import { dirname as dirname13, join as join19 } from "node:path";
11530
11079
 
@@ -11676,7 +11225,7 @@ __export(exports_processor, {
11676
11225
  });
11677
11226
 
11678
11227
  // packages/core/src/evolution/evidence/analysis.ts
11679
- import { readFile as readFile14, readdir as readdir9 } from "node:fs/promises";
11228
+ import { readFile as readFile14, readdir as readdir10 } from "node:fs/promises";
11680
11229
  import { basename as basename3, join as join15 } from "node:path";
11681
11230
  async function analyzeEvolutionRun(input) {
11682
11231
  const projectKey = resolveEvolutionProjectKey(input);
@@ -11689,8 +11238,8 @@ async function analyzeEvolutionRun(input) {
11689
11238
  const logsDir = resolveEvoDevPaths(input.homeDir).logsDir;
11690
11239
  const projectRunAgentsDir = join15(logsDir, "teams", projectKey, runId, "agents");
11691
11240
  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 }) : [];
11241
+ const agentDirs = await pathExists(projectRunAgentsDir) ? await readdir10(projectRunAgentsDir, { withFileTypes: true }) : [];
11242
+ const legacyAgentDirs = await pathExists(legacyProjectRunAgentsDir) ? await readdir10(legacyProjectRunAgentsDir, { withFileTypes: true }) : [];
11694
11243
  if (agentDirs.length === 0 && legacyAgentDirs.length === 0) {
11695
11244
  warnings.push(`No agent execution event directory found: ${displayPath(input.homeDir, projectRunAgentsDir)}`);
11696
11245
  } else {
@@ -12376,7 +11925,7 @@ function createProvenance(evidenceWindow, createdAt, sourceRefs) {
12376
11925
  };
12377
11926
  }
12378
11927
  // packages/core/src/evolution/processor/process.ts
12379
- import { mkdir as mkdir11, rm as rm3, stat as stat7, writeFile as writeFile10 } from "node:fs/promises";
11928
+ import { mkdir as mkdir10, rm as rm3, stat as stat7, writeFile as writeFile9 } from "node:fs/promises";
12380
11929
  import { dirname as dirname11, join as join17 } from "node:path";
12381
11930
  var PROCESS_LOCK_STALE_MS2 = 5 * 60 * 1000;
12382
11931
  async function processEvolutionTriggers(input) {
@@ -12537,9 +12086,9 @@ async function processEvolutionTriggers(input) {
12537
12086
  async function acquireEvolutionProcessLock(homeDir, now) {
12538
12087
  const paths2 = resolveEvoDevPaths(homeDir);
12539
12088
  const lockPath = join17(paths2.stateDir, "evolution", ".process.lock");
12540
- await mkdir11(dirname11(lockPath), { recursive: true });
12089
+ await mkdir10(dirname11(lockPath), { recursive: true });
12541
12090
  try {
12542
- await writeFile10(lockPath, `${JSON.stringify({
12091
+ await writeFile9(lockPath, `${JSON.stringify({
12543
12092
  schemaVersion: 1,
12544
12093
  kind: "evolution-process-lock",
12545
12094
  createdAt: now,
@@ -12562,7 +12111,7 @@ async function releaseEvolutionProcessLock(lock) {
12562
12111
  await rm3(lock.path, { force: true });
12563
12112
  }
12564
12113
  // packages/core/src/observability/index.ts
12565
- import { mkdir as mkdir12, readFile as readFile15, readdir as readdir10, stat as stat8, writeFile as writeFile11 } from "node:fs/promises";
12114
+ import { mkdir as mkdir11, readFile as readFile15, readdir as readdir11, stat as stat8, writeFile as writeFile10 } from "node:fs/promises";
12566
12115
  import { dirname as dirname12, join as join18 } from "node:path";
12567
12116
  var EVENT_TYPE_TO_DIR = {
12568
12117
  "verification.completed": "verification",
@@ -12570,7 +12119,7 @@ var EVENT_TYPE_TO_DIR = {
12570
12119
  "test-run.completed": "tests",
12571
12120
  "review.finding": "reviews"
12572
12121
  };
12573
- var FORBIDDEN_RAW_KEYS3 = new Set([
12122
+ var FORBIDDEN_RAW_KEYS2 = new Set([
12574
12123
  "commandoutput",
12575
12124
  "memorybodies",
12576
12125
  "memorybody",
@@ -12592,11 +12141,11 @@ var FORBIDDEN_RAW_KEYS3 = new Set([
12592
12141
  "transcriptbody",
12593
12142
  "transcripttext"
12594
12143
  ]);
12595
- var SENSITIVE_TEXT_PATTERN5 = /https?:\/\/\S+|\b(secret|token|password|passwd|private|internal|api[_-]?key|apikey|credential|credentials|raw log|raw source|raw prompt)\b/i;
12144
+ var SENSITIVE_TEXT_PATTERN4 = /https?:\/\/\S+|\b(secret|token|password|passwd|private|internal|api[_-]?key|apikey|credential|credentials|raw log|raw source|raw prompt)\b/i;
12596
12145
  function createObservabilityEvent(input) {
12597
12146
  const event = {
12598
12147
  version: 1,
12599
- eventId: sanitizeId3(input.eventId),
12148
+ eventId: sanitizeId2(input.eventId),
12600
12149
  type: input.type,
12601
12150
  timestamp: input.timestamp ?? new Date().toISOString(),
12602
12151
  scope: input.scope,
@@ -12608,7 +12157,7 @@ function createObservabilityEvent(input) {
12608
12157
  sourceContentStored: false,
12609
12158
  promptStored: false
12610
12159
  },
12611
- summary: sanitizeText3(input.summary),
12160
+ summary: sanitizeText2(input.summary),
12612
12161
  data: sanitizeData(input.data ?? {})
12613
12162
  };
12614
12163
  validateObservabilityEvent(event);
@@ -12631,8 +12180,8 @@ function resolveObservabilityStorePaths(homeDir, type) {
12631
12180
  async function appendObservabilityEvent(homeDir, event) {
12632
12181
  validateObservabilityEvent(event);
12633
12182
  const paths2 = resolveObservabilityStorePaths(homeDir, event.type);
12634
- await mkdir12(dirname12(paths2.eventsPath), { recursive: true });
12635
- await writeFile11(paths2.eventsPath, `${JSON.stringify(event)}
12183
+ await mkdir11(dirname12(paths2.eventsPath), { recursive: true });
12184
+ await writeFile10(paths2.eventsPath, `${JSON.stringify(event)}
12636
12185
  `, { encoding: "utf8", flag: "a" });
12637
12186
  return paths2.eventsPath;
12638
12187
  }
@@ -12641,7 +12190,7 @@ async function listObservabilityEvents(homeDir, type) {
12641
12190
  const events = [];
12642
12191
  for (const eventType of eventTypes) {
12643
12192
  const path = resolveObservabilityStorePaths(homeDir, eventType).eventsPath;
12644
- if (!await pathExists6(path))
12193
+ if (!await pathExists5(path))
12645
12194
  continue;
12646
12195
  const lines = (await readFile15(path, "utf8")).split(`
12647
12196
  `).filter(Boolean);
@@ -12656,7 +12205,7 @@ async function listObservabilityEvents(homeDir, type) {
12656
12205
  async function dryRunObservabilityRetentionCleanup(homeDir) {
12657
12206
  const root = join18(homeDir, ".evodev", "OBSERVABILITY");
12658
12207
  const candidates = [];
12659
- if (!await pathExists6(root))
12208
+ if (!await pathExists5(root))
12660
12209
  return { candidates, totalBytes: 0 };
12661
12210
  for (const file of await collectJsonlFiles(root)) {
12662
12211
  const fileStat = await stat8(file);
@@ -12689,13 +12238,13 @@ function sanitizeData(data) {
12689
12238
  const sanitized = {};
12690
12239
  for (const [key, value] of Object.entries(data)) {
12691
12240
  const normalizedKey = normalizeKey(key);
12692
- if (FORBIDDEN_RAW_KEYS3.has(normalizedKey)) {
12241
+ if (FORBIDDEN_RAW_KEYS2.has(normalizedKey)) {
12693
12242
  throw new Error(`Observability data contains forbidden raw field: ${key}`);
12694
12243
  }
12695
12244
  if (typeof value === "string")
12696
- sanitized[key] = sanitizeText3(value);
12245
+ sanitized[key] = sanitizeText2(value);
12697
12246
  else if (Array.isArray(value))
12698
- sanitized[key] = value.map(sanitizeText3);
12247
+ sanitized[key] = value.map(sanitizeText2);
12699
12248
  else
12700
12249
  sanitized[key] = value;
12701
12250
  }
@@ -12705,7 +12254,7 @@ function assertNoForbiddenContent(value) {
12705
12254
  if (typeof value === "string") {
12706
12255
  if (value === "local-private")
12707
12256
  return;
12708
- if (SENSITIVE_TEXT_PATTERN5.test(value))
12257
+ if (SENSITIVE_TEXT_PATTERN4.test(value))
12709
12258
  throw new Error("Observability event contains sensitive content.");
12710
12259
  return;
12711
12260
  }
@@ -12718,14 +12267,14 @@ function assertNoForbiddenContent(value) {
12718
12267
  return;
12719
12268
  for (const [key, child] of Object.entries(value)) {
12720
12269
  const normalizedKey = normalizeKey(key);
12721
- if (FORBIDDEN_RAW_KEYS3.has(normalizedKey)) {
12270
+ if (FORBIDDEN_RAW_KEYS2.has(normalizedKey)) {
12722
12271
  throw new Error(`Observability event contains forbidden raw field: ${key}`);
12723
12272
  }
12724
12273
  assertNoForbiddenContent(child);
12725
12274
  }
12726
12275
  }
12727
12276
  async function collectJsonlFiles(root) {
12728
- const entries = await readdir10(root, { withFileTypes: true });
12277
+ const entries = await readdir11(root, { withFileTypes: true });
12729
12278
  const files = [];
12730
12279
  for (const entry of entries) {
12731
12280
  const path = join18(root, entry.name);
@@ -12736,7 +12285,7 @@ async function collectJsonlFiles(root) {
12736
12285
  }
12737
12286
  return files.sort();
12738
12287
  }
12739
- async function pathExists6(path) {
12288
+ async function pathExists5(path) {
12740
12289
  try {
12741
12290
  await stat8(path);
12742
12291
  return true;
@@ -12746,10 +12295,10 @@ async function pathExists6(path) {
12746
12295
  throw error;
12747
12296
  }
12748
12297
  }
12749
- function sanitizeText3(value) {
12750
- return value.replace(SENSITIVE_TEXT_PATTERN5, "[redacted]").slice(0, 500);
12298
+ function sanitizeText2(value) {
12299
+ return value.replace(SENSITIVE_TEXT_PATTERN4, "[redacted]").slice(0, 500);
12751
12300
  }
12752
- function sanitizeId3(value) {
12301
+ function sanitizeId2(value) {
12753
12302
  return value.replace(/[^a-zA-Z0-9._-]/g, "-").slice(0, 80) || "event";
12754
12303
  }
12755
12304
  function normalizeKey(key) {
@@ -12758,7 +12307,7 @@ function normalizeKey(key) {
12758
12307
 
12759
12308
  // packages/core/src/daemon/index.ts
12760
12309
  var DEFAULT_PORT = 37645;
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;
12310
+ var SENSITIVE_TEXT_PATTERN5 = /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;
12762
12311
  function resolveDaemonPaths(homeDir) {
12763
12312
  const rootDir = join19(homeDir, ".evodev", "STATE", "daemon");
12764
12313
  return { rootDir, lockPath: join19(rootDir, "lock.json"), tokenPath: join19(rootDir, "token") };
@@ -12801,14 +12350,14 @@ async function writeDaemonState(input) {
12801
12350
  tokenPath: plan.paths.tokenPath,
12802
12351
  versionText: input.versionText ?? "evodev 0.0.1-alpha"
12803
12352
  };
12804
- await mkdir13(dirname13(plan.paths.lockPath), { recursive: true });
12805
- await writeFile12(plan.paths.tokenPath, `${token}
12353
+ await mkdir12(dirname13(plan.paths.lockPath), { recursive: true });
12354
+ await writeFile11(plan.paths.tokenPath, `${token}
12806
12355
  `, {
12807
12356
  encoding: "utf8",
12808
12357
  flag: "wx",
12809
12358
  mode: 384
12810
12359
  });
12811
- await writeFile12(plan.paths.lockPath, `${JSON.stringify(lock, null, 2)}
12360
+ await writeFile11(plan.paths.lockPath, `${JSON.stringify(lock, null, 2)}
12812
12361
  `, {
12813
12362
  encoding: "utf8",
12814
12363
  flag: "wx",
@@ -12818,7 +12367,7 @@ async function writeDaemonState(input) {
12818
12367
  }
12819
12368
  async function readDaemonLock(homeDir) {
12820
12369
  const paths2 = resolveDaemonPaths(homeDir);
12821
- if (!await pathExists7(paths2.lockPath))
12370
+ if (!await pathExists6(paths2.lockPath))
12822
12371
  return null;
12823
12372
  const lock = JSON.parse(await readFile16(paths2.lockPath, "utf8"));
12824
12373
  if (lock.version !== 1 || lock.component !== "evodev-daemon")
@@ -12827,7 +12376,7 @@ async function readDaemonLock(homeDir) {
12827
12376
  }
12828
12377
  async function readDaemonToken(homeDir) {
12829
12378
  const paths2 = resolveDaemonPaths(homeDir);
12830
- if (!await pathExists7(paths2.tokenPath))
12379
+ if (!await pathExists6(paths2.tokenPath))
12831
12380
  return null;
12832
12381
  return (await readFile16(paths2.tokenPath, "utf8")).trim();
12833
12382
  }
@@ -12891,8 +12440,6 @@ async function handleDaemonRequest(input) {
12891
12440
  }
12892
12441
  if (input.method !== "GET")
12893
12442
  return notFound(warnings);
12894
- if (input.path === "/tasks")
12895
- return ok(await collectTaskSummaries(input.homeDir, warnings), warnings);
12896
12443
  if (input.path === "/observability/events")
12897
12444
  return ok(await collectObservabilitySummaries(input.homeDir, warnings), warnings);
12898
12445
  if (input.path === "/memory/candidates")
@@ -12942,14 +12489,14 @@ async function runDaemonForeground(input) {
12942
12489
  }));
12943
12490
  }
12944
12491
  });
12945
- await new Promise((resolve5, reject) => {
12492
+ await new Promise((resolve4, reject) => {
12946
12493
  const onError = (error) => {
12947
12494
  server.off("listening", onListening);
12948
12495
  reject(error);
12949
12496
  };
12950
12497
  const onListening = () => {
12951
12498
  server.off("error", onError);
12952
- resolve5();
12499
+ resolve4();
12953
12500
  };
12954
12501
  server.once("error", onError);
12955
12502
  server.once("listening", onListening);
@@ -12966,11 +12513,11 @@ async function runDaemonForeground(input) {
12966
12513
  processEvolutionTriggers({ homeDir: input.homeDir, limit: 20 }).then(() => clearDaemonEvolutionProcessError(input.homeDir)).catch((error) => recordDaemonEvolutionProcessError(input.homeDir, error));
12967
12514
  }, 5000);
12968
12515
  evolutionInterval.unref();
12969
- await new Promise((resolve5, reject) => {
12516
+ await new Promise((resolve4, reject) => {
12970
12517
  server.once("close", () => {
12971
12518
  clearInterval(reconcileInterval);
12972
12519
  clearInterval(evolutionInterval);
12973
- resolve5();
12520
+ resolve4();
12974
12521
  });
12975
12522
  server.once("error", reject);
12976
12523
  });
@@ -13017,30 +12564,6 @@ function isAllowedLocalOrigin(origin) {
13017
12564
  return false;
13018
12565
  }
13019
12566
  }
13020
- async function collectTaskSummaries(homeDir, warnings) {
13021
- const root = join19(homeDir, ".evodev", "STATE", "tasks");
13022
- if (!await pathExists7(root)) {
13023
- warnings.push("Task store not found; returning empty tasks.");
13024
- return [];
13025
- }
13026
- const contracts = await collectNamedFiles(root, "contract.json");
13027
- const summaries = [];
13028
- for (const file of contracts) {
13029
- try {
13030
- const contract = JSON.parse(await readFile16(file, "utf8"));
13031
- summaries.push(sanitizeMetadata({
13032
- taskId: contract.taskId,
13033
- status: contract.status,
13034
- mode: contract.route?.mode ?? null,
13035
- workflowId: contract.route?.workflowId ?? null,
13036
- verificationStatus: contract.verification?.status ?? null
13037
- }));
13038
- } catch {
13039
- warnings.push(`Skipped unreadable task contract: ${file}`);
13040
- }
13041
- }
13042
- return summaries;
13043
- }
13044
12567
  async function collectObservabilitySummaries(homeDir, warnings) {
13045
12568
  try {
13046
12569
  return (await listObservabilityEvents(homeDir)).map((event) => sanitizeMetadata({
@@ -13057,7 +12580,7 @@ async function collectObservabilitySummaries(homeDir, warnings) {
13057
12580
  }
13058
12581
  async function collectLearningCandidateSummaries(homeDir, warnings) {
13059
12582
  const path = join19(homeDir, ".evodev", "STATE", "learning", "candidates.jsonl");
13060
- if (!await pathExists7(path)) {
12583
+ if (!await pathExists6(path)) {
13061
12584
  warnings.push("Learning candidate store not found; returning empty candidates.");
13062
12585
  return [];
13063
12586
  }
@@ -13289,16 +12812,16 @@ async function resumeDashboardTeamRun(homeDir, body, runtimeAdapter) {
13289
12812
  };
13290
12813
  }
13291
12814
  async function collectDirectorySummaries(root, warnings) {
13292
- if (!await pathExists7(root)) {
12815
+ if (!await pathExists6(root)) {
13293
12816
  warnings.push(`Store not found: ${root}`);
13294
12817
  return [];
13295
12818
  }
13296
- const entries = await readdir11(root, { withFileTypes: true });
12819
+ const entries = await readdir12(root, { withFileTypes: true });
13297
12820
  return entries.filter((entry) => entry.isDirectory()).map((entry) => ({ id: entry.name, metadataOnly: true }));
13298
12821
  }
13299
12822
  function sanitizeMetadata(value) {
13300
12823
  if (typeof value === "string") {
13301
- if (SENSITIVE_TEXT_PATTERN6.test(value))
12824
+ if (SENSITIVE_TEXT_PATTERN5.test(value))
13302
12825
  return "[redacted]";
13303
12826
  return value.slice(0, 500);
13304
12827
  }
@@ -13349,8 +12872,8 @@ function resolveDaemonEvolutionProcessErrorPath(homeDir) {
13349
12872
  async function recordDaemonEvolutionProcessError(homeDir, error) {
13350
12873
  try {
13351
12874
  const path = resolveDaemonEvolutionProcessErrorPath(homeDir);
13352
- await mkdir13(dirname13(path), { recursive: true });
13353
- await writeFile12(path, `${JSON.stringify({
12875
+ await mkdir12(dirname13(path), { recursive: true });
12876
+ await writeFile11(path, `${JSON.stringify({
13354
12877
  schemaVersion: 1,
13355
12878
  kind: "daemon-evolution-process-error",
13356
12879
  updatedAt: new Date().toISOString(),
@@ -13366,7 +12889,7 @@ async function clearDaemonEvolutionProcessError(homeDir) {
13366
12889
  }
13367
12890
  async function readDaemonEvolutionProcessError(homeDir) {
13368
12891
  const path = resolveDaemonEvolutionProcessErrorPath(homeDir);
13369
- if (!await pathExists7(path))
12892
+ if (!await pathExists6(path))
13370
12893
  return null;
13371
12894
  const value = JSON.parse(await readFile16(path, "utf8"));
13372
12895
  return typeof value.summary === "string" && value.summary.length > 0 ? value.summary : null;
@@ -13374,25 +12897,13 @@ async function readDaemonEvolutionProcessError(homeDir) {
13374
12897
  function describeError3(error) {
13375
12898
  return error instanceof Error ? error.message : String(error);
13376
12899
  }
13377
- async function collectNamedFiles(root, name) {
13378
- const entries = await readdir11(root, { withFileTypes: true });
13379
- const files = [];
13380
- for (const entry of entries) {
13381
- const path = join19(root, entry.name);
13382
- if (entry.isDirectory())
13383
- files.push(...await collectNamedFiles(path, name));
13384
- else if (entry.isFile() && entry.name === name)
13385
- files.push(path);
13386
- }
13387
- return files;
13388
- }
13389
12900
  function ok(data, warnings) {
13390
12901
  return { status: 200, body: { ok: true, data: sanitizeMetadata(data), warnings } };
13391
12902
  }
13392
12903
  function notFound(warnings) {
13393
12904
  return { status: 404, body: { ok: false, data: { error: "not found" }, warnings } };
13394
12905
  }
13395
- async function pathExists7(path) {
12906
+ async function pathExists6(path) {
13396
12907
  try {
13397
12908
  await stat9(path);
13398
12909
  return true;
@@ -13418,7 +12929,7 @@ __export(exports_review, {
13418
12929
  resolveLearningCandidateQueuePath: () => resolveLearningCandidateQueuePath,
13419
12930
  readLearningReviewDecisions: () => readLearningReviewDecisions,
13420
12931
  readLearningCandidates: () => readLearningCandidates,
13421
- pathExists: () => pathExists8,
12932
+ pathExists: () => pathExists7,
13422
12933
  parseLearningReviewDecisionRecord: () => parseLearningReviewDecisionRecord,
13423
12934
  parseLearningCandidate: () => parseLearningCandidate,
13424
12935
  listLearningReviewDecisions: () => listLearningReviewDecisions,
@@ -13432,7 +12943,7 @@ __export(exports_review, {
13432
12943
  appendLearningReviewDecision: () => appendLearningReviewDecision,
13433
12944
  appendLearningCandidate: () => appendLearningCandidate
13434
12945
  });
13435
- import { mkdir as mkdir14, readFile as readFile17, stat as stat10, writeFile as writeFile13 } from "node:fs/promises";
12946
+ import { mkdir as mkdir13, readFile as readFile17, stat as stat10, writeFile as writeFile12 } from "node:fs/promises";
13436
12947
  import { dirname as dirname14, join as join20 } from "node:path";
13437
12948
  var LEARNING_CANDIDATE_KINDS = [
13438
12949
  "lesson",
@@ -13455,7 +12966,7 @@ var LEARNING_CONFIDENCE_VALUES = ["low", "medium", "high"];
13455
12966
  var LEARNING_DECISION_VALUES = ["rejected", "deferred"];
13456
12967
  var LEARNING_DECIDED_BY_VALUES = ["user"];
13457
12968
  var LEARNING_CANDIDATE_DECISION_STATUSES = ["rejected", "deferred"];
13458
- var FORBIDDEN_RAW_KEYS4 = new Set([
12969
+ var FORBIDDEN_RAW_KEYS3 = new Set([
13459
12970
  "commandhistory",
13460
12971
  "commandoutput",
13461
12972
  "credential",
@@ -13490,28 +13001,27 @@ var FORBIDDEN_RAW_KEYS4 = new Set([
13490
13001
  "transcriptbody",
13491
13002
  "transcripttext"
13492
13003
  ]);
13493
- var SENSITIVE_TEXT_PATTERN7 = /https?:\/\/\S+|\b(secret|token|password|passwd|private|internal|api[_-]?key|apikey|credential|credentials|raw log|raw logs|raw output|raw source|raw prompt|shell history|command history)\b/i;
13004
+ var SENSITIVE_TEXT_PATTERN6 = /https?:\/\/\S+|\b(secret|token|password|passwd|private|internal|api[_-]?key|apikey|credential|credentials|raw log|raw logs|raw output|raw source|raw prompt|shell history|command history)\b/i;
13494
13005
  var PROTECTED_PATH_PATTERN = /(^|[~/\\])(?:USER|KNOWLEDGE|LEARNING|OBSERVABILITY|PACKS|RELEASES|logs?|memory|\.env[^/\\]*)(?:$|[/\\])|PROJECTS[/\\][^/\\]+[/\\]LEARNING(?:$|[/\\])|\.evodev[/\\](?:USER|KNOWLEDGE|LEARNING|OBSERVABILITY|PACKS|RELEASES)(?:$|[/\\])/i;
13495
13006
  function createLearningCandidate(input) {
13496
13007
  const candidate = {
13497
13008
  version: 1,
13498
- id: sanitizeId4(input.id),
13009
+ id: sanitizeId3(input.id),
13499
13010
  kind: input.kind,
13500
13011
  status: "candidate",
13501
13012
  routingInfluence: false,
13502
13013
  scope: sanitizeScope(input.scope),
13503
13014
  content: {
13504
- summary: sanitizeText4(input.content.summary),
13505
- howToApply: sanitizeText4(input.content.howToApply),
13506
- antiCriteriaImpact: input.content.antiCriteriaImpact.map(sanitizeText4)
13015
+ summary: sanitizeText3(input.content.summary),
13016
+ howToApply: sanitizeText3(input.content.howToApply),
13017
+ antiCriteriaImpact: input.content.antiCriteriaImpact.map(sanitizeText3)
13507
13018
  },
13508
13019
  provenance: {
13509
13020
  taskId: sanitizeNullableId(input.provenance.taskId),
13510
- taskContractRef: sanitizeNullableText(input.provenance.taskContractRef),
13511
13021
  workflowRunId: sanitizeNullableId(input.provenance.workflowRunId),
13512
- evidenceRefs: input.provenance.evidenceRefs.map(sanitizeText4),
13022
+ evidenceRefs: input.provenance.evidenceRefs.map(sanitizeText3),
13513
13023
  sourceType: input.provenance.sourceType,
13514
- createdAt: sanitizeText4(input.provenance.createdAt),
13024
+ createdAt: sanitizeText3(input.provenance.createdAt),
13515
13025
  createdBy: input.provenance.createdBy,
13516
13026
  rawPromptStored: false,
13517
13027
  sourceContentStored: false,
@@ -13530,7 +13040,7 @@ function createLearningCandidate(input) {
13530
13040
  return candidate;
13531
13041
  }
13532
13042
  function validateLearningCandidate(candidate) {
13533
- if (!isRecord11(candidate))
13043
+ if (!isRecord10(candidate))
13534
13044
  throw new Error("Learning candidate must be an object.");
13535
13045
  if (candidate.version !== 1)
13536
13046
  throw new Error("Learning candidate version must be 1.");
@@ -13542,33 +13052,33 @@ function validateLearningCandidate(candidate) {
13542
13052
  if (candidate.routingInfluence !== false) {
13543
13053
  throw new Error("Learning candidate routingInfluence must be false in I5.");
13544
13054
  }
13545
- if (!isRecord11(candidate.scope))
13055
+ if (!isRecord10(candidate.scope))
13546
13056
  throw new Error("Learning candidate scope must be an object.");
13547
13057
  assertEnumValue("scope.level", candidate.scope.level, LEARNING_SCOPE_LEVELS);
13548
- if (!isRecord11(candidate.content)) {
13058
+ if (!isRecord10(candidate.content)) {
13549
13059
  throw new Error("Learning candidate content must be an object.");
13550
13060
  }
13551
13061
  assertStringField("content.summary", candidate.content.summary);
13552
13062
  assertStringField("content.howToApply", candidate.content.howToApply);
13553
13063
  assertStringArrayField("content.antiCriteriaImpact", candidate.content.antiCriteriaImpact);
13554
- if (!isRecord11(candidate.provenance)) {
13064
+ if (!isRecord10(candidate.provenance)) {
13555
13065
  throw new Error("Learning candidate provenance must be an object.");
13556
13066
  }
13557
13067
  assertEnumValue("provenance.sourceType", candidate.provenance.sourceType, LEARNING_SOURCE_TYPES);
13558
13068
  assertEnumValue("provenance.createdBy", candidate.provenance.createdBy, LEARNING_CREATED_BY_VALUES);
13559
13069
  assertStringField("provenance.createdAt", candidate.provenance.createdAt);
13560
13070
  assertStringArrayField("provenance.evidenceRefs", candidate.provenance.evidenceRefs);
13561
- if (!isRecord11(candidate.privacy)) {
13071
+ if (!isRecord10(candidate.privacy)) {
13562
13072
  throw new Error("Learning candidate privacy must be an object.");
13563
13073
  }
13564
13074
  assertEnumValue("privacy.classification", candidate.privacy.classification, ["local-private"]);
13565
- if (!isRecord11(candidate.review))
13075
+ if (!isRecord10(candidate.review))
13566
13076
  throw new Error("Learning candidate review must be an object.");
13567
13077
  assertEnumValue("review.decision", candidate.review.decision, LEARNING_REVIEW_DECISIONS);
13568
13078
  if (candidate.review.decision !== "pending") {
13569
13079
  throw new Error("Learning candidate review decision must be pending.");
13570
13080
  }
13571
- if (!isRecord11(candidate.retention)) {
13081
+ if (!isRecord10(candidate.retention)) {
13572
13082
  throw new Error("Learning candidate retention must be an object.");
13573
13083
  }
13574
13084
  assertEnumValue("confidence", candidate.confidence, LEARNING_CONFIDENCE_VALUES);
@@ -13584,7 +13094,7 @@ function validateLearningCandidate(candidate) {
13584
13094
  assertNoForbiddenContent2(candidate);
13585
13095
  }
13586
13096
  function validateLearningReviewDecisionRecord(record) {
13587
- if (!isRecord11(record))
13097
+ if (!isRecord10(record))
13588
13098
  throw new Error("Learning review decision must be an object.");
13589
13099
  if (record.version !== 1)
13590
13100
  throw new Error("Learning review decision version must be 1.");
@@ -13607,13 +13117,13 @@ function validateLearningReviewDecisionRecord(record) {
13607
13117
  assertNoForbiddenContent2(record);
13608
13118
  }
13609
13119
  function parseLearningCandidate(value) {
13610
- if (!isRecord11(value))
13120
+ if (!isRecord10(value))
13611
13121
  throw new Error("Invalid learning candidate JSON.");
13612
13122
  validateLearningCandidate(value);
13613
13123
  return value;
13614
13124
  }
13615
13125
  function parseLearningReviewDecisionRecord(value) {
13616
- if (!isRecord11(value))
13126
+ if (!isRecord10(value))
13617
13127
  throw new Error("Invalid learning review decision JSON.");
13618
13128
  validateLearningReviewDecisionRecord(value);
13619
13129
  return value;
@@ -13633,20 +13143,20 @@ function resolveLearningDecisionPath(homeDir) {
13633
13143
  async function appendLearningCandidate(homeDir, candidate) {
13634
13144
  validateLearningCandidate(candidate);
13635
13145
  const path = resolveLearningCandidateQueuePath(homeDir);
13636
- await mkdir14(dirname14(path), { recursive: true });
13637
- await writeFile13(path, `${JSON.stringify(candidate)}
13146
+ await mkdir13(dirname14(path), { recursive: true });
13147
+ await writeFile12(path, `${JSON.stringify(candidate)}
13638
13148
  `, { encoding: "utf8", flag: "a" });
13639
13149
  return path;
13640
13150
  }
13641
13151
  async function listLearningCandidates(homeDir) {
13642
13152
  const path = resolveLearningCandidateQueuePath(homeDir);
13643
- if (!await pathExists8(path))
13153
+ if (!await pathExists7(path))
13644
13154
  return [];
13645
13155
  return readLearningCandidates(path);
13646
13156
  }
13647
13157
  async function listLearningReviewDecisions(homeDir) {
13648
13158
  const path = resolveLearningDecisionPath(homeDir);
13649
- if (!await pathExists8(path))
13159
+ if (!await pathExists7(path))
13650
13160
  return [];
13651
13161
  return readLearningReviewDecisions(path);
13652
13162
  }
@@ -13706,7 +13216,7 @@ function lintLearningCandidates(candidates2, options = {}) {
13706
13216
  validateLearningReviewDecisionRecord(decision);
13707
13217
  } catch (error) {
13708
13218
  findings.push({
13709
- candidateId: isRecord11(decision) && typeof decision.candidateId === "string" ? decision.candidateId : "unknown",
13219
+ candidateId: isRecord10(decision) && typeof decision.candidateId === "string" ? decision.candidateId : "unknown",
13710
13220
  severity: "error",
13711
13221
  field: "decision",
13712
13222
  message: error instanceof Error ? error.message : String(error)
@@ -13778,9 +13288,9 @@ function createLearningReviewDecisionRecord(input) {
13778
13288
  const candidateStatus = input.decision === "rejected" ? "rejected" : "deferred";
13779
13289
  const record = {
13780
13290
  version: 1,
13781
- candidateId: sanitizeId4(input.candidateId),
13291
+ candidateId: sanitizeId3(input.candidateId),
13782
13292
  decision: input.decision,
13783
- decidedAt: sanitizeText4(input.decidedAt ?? new Date().toISOString()),
13293
+ decidedAt: sanitizeText3(input.decidedAt ?? new Date().toISOString()),
13784
13294
  decidedBy: "user",
13785
13295
  reason: input.reason === undefined ? null : sanitizeNullableText(input.reason),
13786
13296
  writesAcceptedMemory: false,
@@ -13793,12 +13303,12 @@ function createLearningReviewDecisionRecord(input) {
13793
13303
  async function appendLearningReviewDecision(homeDir, record) {
13794
13304
  validateLearningReviewDecisionRecord(record);
13795
13305
  const path = resolveLearningDecisionPath(homeDir);
13796
- await mkdir14(dirname14(path), { recursive: true });
13797
- await writeFile13(path, `${JSON.stringify(record)}
13306
+ await mkdir13(dirname14(path), { recursive: true });
13307
+ await writeFile12(path, `${JSON.stringify(record)}
13798
13308
  `, { encoding: "utf8", flag: "a" });
13799
13309
  return path;
13800
13310
  }
13801
- async function pathExists8(path) {
13311
+ async function pathExists7(path) {
13802
13312
  try {
13803
13313
  await stat10(path);
13804
13314
  return true;
@@ -13860,13 +13370,7 @@ async function parseJsonOrJsonlFile(path, parseItem) {
13860
13370
  return values.map(parseItem);
13861
13371
  }
13862
13372
  function candidatePathFields(candidate) {
13863
- return [
13864
- ["provenance.taskContractRef", candidate.provenance.taskContractRef],
13865
- ...candidate.provenance.evidenceRefs.map((ref, index) => [
13866
- `provenance.evidenceRefs[${index}]`,
13867
- ref
13868
- ])
13869
- ].filter((entry) => typeof entry[1] === "string");
13373
+ return candidate.provenance.evidenceRefs.map((ref, index) => [`provenance.evidenceRefs[${index}]`, ref]).filter((entry) => typeof entry[1] === "string");
13870
13374
  }
13871
13375
  function isCandidateStale(candidate, now) {
13872
13376
  if (candidate.retention.staleAfter === null)
@@ -13894,7 +13398,7 @@ function assertNoForbiddenContent2(value) {
13894
13398
  if (typeof value === "string") {
13895
13399
  if (value === "local-private")
13896
13400
  return;
13897
- if (SENSITIVE_TEXT_PATTERN7.test(value)) {
13401
+ if (SENSITIVE_TEXT_PATTERN6.test(value)) {
13898
13402
  throw new Error("Learning candidate contains sensitive content.");
13899
13403
  }
13900
13404
  return;
@@ -13904,38 +13408,38 @@ function assertNoForbiddenContent2(value) {
13904
13408
  assertNoForbiddenContent2(item);
13905
13409
  return;
13906
13410
  }
13907
- if (!isRecord11(value))
13411
+ if (!isRecord10(value))
13908
13412
  return;
13909
13413
  for (const [key, child] of Object.entries(value)) {
13910
13414
  const normalizedKey = normalizeKey2(key);
13911
- if (FORBIDDEN_RAW_KEYS4.has(normalizedKey)) {
13415
+ if (FORBIDDEN_RAW_KEYS3.has(normalizedKey)) {
13912
13416
  throw new Error(`Learning candidate contains forbidden raw field: ${key}`);
13913
13417
  }
13914
13418
  assertNoForbiddenContent2(child);
13915
13419
  }
13916
13420
  }
13917
- function sanitizeText4(value) {
13918
- return value.replace(SENSITIVE_TEXT_PATTERN7, "[redacted]").slice(0, 500);
13421
+ function sanitizeText3(value) {
13422
+ return value.replace(SENSITIVE_TEXT_PATTERN6, "[redacted]").slice(0, 500);
13919
13423
  }
13920
13424
  function sanitizeNullableText(value) {
13921
- return value === null ? null : sanitizeText4(value);
13425
+ return value === null ? null : sanitizeText3(value);
13922
13426
  }
13923
- function sanitizeId4(value) {
13924
- const sanitized = sanitizeText4(value).replace(/\[redacted\]/gi, "redacted").replace(/[^a-zA-Z0-9._-]/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "").slice(0, 100);
13427
+ function sanitizeId3(value) {
13428
+ const sanitized = sanitizeText3(value).replace(/\[redacted\]/gi, "redacted").replace(/[^a-zA-Z0-9._-]/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "").slice(0, 100);
13925
13429
  return sanitized || "learning-candidate";
13926
13430
  }
13927
13431
  function sanitizeNullableId(value) {
13928
- return value === null ? null : sanitizeId4(value);
13432
+ return value === null ? null : sanitizeId3(value);
13929
13433
  }
13930
13434
  function normalizeKey2(key) {
13931
13435
  return key.toLowerCase().replace(/[^a-z0-9]/g, "");
13932
13436
  }
13933
- function isRecord11(value) {
13437
+ function isRecord10(value) {
13934
13438
  return typeof value === "object" && value !== null && !Array.isArray(value);
13935
13439
  }
13936
13440
  // packages/core/src/pack/index.ts
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";
13441
+ import { readFile as readFile18, readdir as readdir13, stat as stat11 } from "node:fs/promises";
13442
+ import { isAbsolute as isAbsolute7, join as join21, relative as relative7, sep } from "node:path";
13939
13443
 
13940
13444
  // packages/core/src/protected-zones/index.ts
13941
13445
  var SENSITIVE_DIRECTORY_SEGMENTS = new Set([
@@ -14170,7 +13674,7 @@ async function planPackInstallDryRun(input) {
14170
13674
  };
14171
13675
  }
14172
13676
  function parsePackManifest(value) {
14173
- if (!isRecord12(value))
13677
+ if (!isRecord11(value))
14174
13678
  throw new Error("Pack manifest must be an object.");
14175
13679
  const manifest = value;
14176
13680
  validateManifestTopLevelFields(manifest);
@@ -14180,14 +13684,14 @@ function parsePackManifest(value) {
14180
13684
  const description = requireString(manifest, "description");
14181
13685
  const publisher = optionalString6(manifest, "publisher");
14182
13686
  const license = optionalString6(manifest, "license");
14183
- const compatibility = requireRecord(manifest, "compatibility");
14184
- const assets = parseAssets(requireRecord(manifest, "assets"));
13687
+ const compatibility = requireRecord2(manifest, "compatibility");
13688
+ const assets = parseAssets(requireRecord2(manifest, "assets"));
14185
13689
  const permissions = parsePermissions(manifest.permissions);
14186
- const install = requireRecord(manifest, "install");
14187
- const verify = requireRecord(manifest, "verify");
14188
- const customizations = requireRecord(manifest, "customizations");
14189
- const observability = requireRecord(manifest, "observability");
14190
- const uninstall = requireRecord(manifest, "uninstall");
13690
+ const install = requireRecord2(manifest, "install");
13691
+ const verify = requireRecord2(manifest, "verify");
13692
+ const customizations = requireRecord2(manifest, "customizations");
13693
+ const observability = requireRecord2(manifest, "observability");
13694
+ const uninstall = requireRecord2(manifest, "uninstall");
14191
13695
  validateCompatibilityTargets(id, requireStringArray(compatibility, "targets"));
14192
13696
  validateProtectedZoneDeclarations(manifest.protectedZones);
14193
13697
  if (observability.metadataOnly !== true) {
@@ -14225,7 +13729,7 @@ function parsePackManifest(value) {
14225
13729
  userPath: requireString(customizations, "userPath"),
14226
13730
  projectPath: requireString(customizations, "projectPath")
14227
13731
  },
14228
- protectedZones: isRecord12(manifest.protectedZones) ? {
13732
+ protectedZones: isRecord11(manifest.protectedZones) ? {
14229
13733
  neverInclude: optionalStringArray(manifest.protectedZones, "neverInclude"),
14230
13734
  neverWrite: optionalStringArray(manifest.protectedZones, "neverWrite")
14231
13735
  } : undefined,
@@ -14415,7 +13919,7 @@ function validateGuideReferences(manifest, assets, findings) {
14415
13919
  }
14416
13920
  }
14417
13921
  async function collectPackRelativePaths(packRoot, dir = packRoot) {
14418
- const entries = await readdir12(dir, { withFileTypes: true });
13922
+ const entries = await readdir13(dir, { withFileTypes: true });
14419
13923
  const paths3 = [];
14420
13924
  for (const entry of entries) {
14421
13925
  const absolutePath = join21(dir, entry.name);
@@ -14434,7 +13938,7 @@ function validatePackRelativePath(path, packRoot) {
14434
13938
  if (path.includes("\x00")) {
14435
13939
  return { severity: "error", code: "path-invalid", message: "Path must not contain NUL bytes." };
14436
13940
  }
14437
- if (isAbsolute6(path) || path.startsWith("~")) {
13941
+ if (isAbsolute7(path) || path.startsWith("~")) {
14438
13942
  return {
14439
13943
  severity: "error",
14440
13944
  code: "path-absolute",
@@ -14451,7 +13955,7 @@ function validatePackRelativePath(path, packRoot) {
14451
13955
  }
14452
13956
  const absolute = join21(packRoot, normalized);
14453
13957
  const rel = relative7(packRoot, absolute);
14454
- if (rel === "" || rel.startsWith("..") || isAbsolute6(rel)) {
13958
+ if (rel === "" || rel.startsWith("..") || isAbsolute7(rel)) {
14455
13959
  return {
14456
13960
  severity: "error",
14457
13961
  code: "path-traversal",
@@ -14496,7 +14000,7 @@ function parseAssets(value) {
14496
14000
  function parsePermissions(value) {
14497
14001
  if (value === undefined)
14498
14002
  return {};
14499
- if (!isRecord12(value))
14003
+ if (!isRecord11(value))
14500
14004
  throw new Error("Pack manifest permissions must be an object.");
14501
14005
  const permissions = {};
14502
14006
  const knownKeys = new Set(Object.keys(RISKY_PERMISSION_LABELS));
@@ -14532,9 +14036,9 @@ function requireBoolean(record, key) {
14532
14036
  throw new Error(`Pack manifest missing boolean field: ${key}`);
14533
14037
  return value;
14534
14038
  }
14535
- function requireRecord(record, key) {
14039
+ function requireRecord2(record, key) {
14536
14040
  const value = record[key];
14537
- if (!isRecord12(value))
14041
+ if (!isRecord11(value))
14538
14042
  throw new Error(`Pack manifest missing object field: ${key}`);
14539
14043
  return value;
14540
14044
  }
@@ -14590,7 +14094,7 @@ function validateCompatibilityTargets(packId, targets) {
14590
14094
  function validateProtectedZoneDeclarations(value) {
14591
14095
  if (value === undefined)
14592
14096
  return;
14593
- if (!isRecord12(value))
14097
+ if (!isRecord11(value))
14594
14098
  throw new Error("Pack manifest protectedZones must be an object.");
14595
14099
  const knownFields = new Set(["neverInclude", "neverWrite"]);
14596
14100
  for (const key of Object.keys(value)) {
@@ -14603,7 +14107,7 @@ function validateProtectedZoneDeclarations(value) {
14603
14107
  function isRemotePackInput(packPath) {
14604
14108
  return /^[a-z][a-z0-9+.-]*:\/\//i.test(packPath);
14605
14109
  }
14606
- function isRecord12(value) {
14110
+ function isRecord11(value) {
14607
14111
  return typeof value === "object" && value !== null && !Array.isArray(value);
14608
14112
  }
14609
14113
  function normalizeRelativePath(path) {
@@ -14616,7 +14120,7 @@ function formatError(error) {
14616
14120
  return error instanceof Error ? error.message : String(error);
14617
14121
  }
14618
14122
  // packages/core/src/plugins/capabilities.ts
14619
- import { mkdir as mkdir15, readFile as readFile19, writeFile as writeFile14 } from "node:fs/promises";
14123
+ import { mkdir as mkdir14, readFile as readFile19, writeFile as writeFile13 } from "node:fs/promises";
14620
14124
  import { dirname as dirname15, join as join22 } from "node:path";
14621
14125
  function createUnknownNegotiatedCapabilities(pluginId) {
14622
14126
  return {
@@ -14669,7 +14173,7 @@ function resolveNonCodexCapabilityState(supported, enabled) {
14669
14173
  }
14670
14174
  async function createCodexCapabilityVerificationArtifact(input) {
14671
14175
  const timestamp = input.createdAt ?? new Date().toISOString();
14672
- const detectionMessage = sanitizeText5(input.detection.message);
14176
+ const detectionMessage = sanitizeText4(input.detection.message);
14673
14177
  const diagnostics = [
14674
14178
  "Codex skills are packaged in the EvoDev Codex plugin payload.",
14675
14179
  "Codex agents sync to user-level TOML files under ~/.codex/agents.",
@@ -14732,8 +14236,8 @@ function resolveCodexCapabilityArtifactPath(homeDir) {
14732
14236
  async function writeCodexCapabilityVerificationArtifact(homeDir, artifact) {
14733
14237
  validateCodexCapabilityVerificationArtifact(artifact);
14734
14238
  const path = resolveCodexCapabilityArtifactPath(homeDir);
14735
- await mkdir15(dirname15(path), { recursive: true });
14736
- await writeFile14(path, `${JSON.stringify(artifact, null, 2)}
14239
+ await mkdir14(dirname15(path), { recursive: true });
14240
+ await writeFile13(path, `${JSON.stringify(artifact, null, 2)}
14737
14241
  `, { encoding: "utf8", flag: "wx" });
14738
14242
  return path;
14739
14243
  }
@@ -14795,7 +14299,7 @@ async function runPluginConformance(plugin) {
14795
14299
  }
14796
14300
  return { ok: findings.length === 0, findings };
14797
14301
  }
14798
- function sanitizeText5(value) {
14302
+ function sanitizeText4(value) {
14799
14303
  return value.replace(/https?:\/\/\S+|\b(secret|token|password|private|internal|api[_-]?key)\b/gi, "[redacted]").slice(0, 300);
14800
14304
  }
14801
14305
  function assertNoSensitiveContent(value) {
@@ -14864,364 +14368,8 @@ function createPluginRegistry(plugins = []) {
14864
14368
  function getEnabledPluginIds(settings) {
14865
14369
  return Object.entries(settings.plugins).filter(([, pluginSettings]) => pluginSettings.enabled).map(([pluginId]) => pluginId).sort((left, right) => left.localeCompare(right));
14866
14370
  }
14867
- // packages/core/src/project/index.ts
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";
14870
- var PROJECT_CONTEXT_ALLOWED_RELATIVE_PATHS = [
14871
- ".evodev/project.json",
14872
- ".evodev/profile.md",
14873
- ".evodev/index.json",
14874
- ".evodev/commands.json",
14875
- ".evodev/privacy.json",
14876
- ".evodev/decisions/README.md"
14877
- ];
14878
- var EXCLUDED_DIRECTORY_NAMES = new Set([
14879
- ".git",
14880
- ".claude",
14881
- ".codex",
14882
- "backups",
14883
- "build",
14884
- "coverage",
14885
- "dist",
14886
- "node_modules"
14887
- ]);
14888
- var EXCLUDED_FILE_PREFIXES = [".env"];
14889
- var EXCLUDED_FILE_PARTS = [
14890
- "api-key",
14891
- "api_key",
14892
- "apikey",
14893
- "credential",
14894
- "credentials",
14895
- "internal",
14896
- "internal-link",
14897
- "password",
14898
- "passwords",
14899
- "passwd",
14900
- "private",
14901
- "private-url",
14902
- "secret",
14903
- "token"
14904
- ];
14905
- var EXCLUDED_FILE_EXTENSIONS = [".key", ".pem", ".p12", ".pfx"];
14906
- var DOC_ENTRYPOINTS = new Set(["README.md"]);
14907
- var DEFAULT_EXCLUDED_GLOBS = [
14908
- ".git/**",
14909
- "node_modules/**",
14910
- "dist/**",
14911
- "build/**",
14912
- "coverage/**",
14913
- ".env*",
14914
- "**/*secret*",
14915
- "**/*token*",
14916
- "**/*password*",
14917
- "**/*passwd*",
14918
- "**/*api-key*",
14919
- "**/*api_key*",
14920
- "**/*apikey*",
14921
- "**/*credential*",
14922
- "**/*private*",
14923
- "**/*internal*",
14924
- "**/*.key",
14925
- "**/*.pem",
14926
- ".claude/**",
14927
- ".codex/**",
14928
- ".evodev/backups/**"
14929
- ];
14930
- var PROTECTED_PATTERNS = [
14931
- "secret",
14932
- "token",
14933
- "password",
14934
- "passwd",
14935
- "api-key",
14936
- "credential",
14937
- "private",
14938
- "private-url",
14939
- "internal",
14940
- "internal-link"
14941
- ];
14942
- async function createProjectContextPlan(projectDir) {
14943
- const projectDirStat = await stat12(projectDir);
14944
- if (!projectDirStat.isDirectory()) {
14945
- throw new Error(`Project dir is not a directory: ${projectDir}`);
14946
- }
14947
- const projectId = createProjectId(projectDir);
14948
- const privacy = createProjectPrivacy();
14949
- const files = await collectProjectFileMetadata(projectDir);
14950
- const commands = await collectProjectCommands(projectDir);
14951
- const docs = files.filter((file) => file.kind === "file" && DOC_ENTRYPOINTS.has(basename5(file.path))).map((file) => file.path).sort();
14952
- const index = {
14953
- version: 1,
14954
- mode: "metadata-only",
14955
- projectId,
14956
- generatedAt: null,
14957
- rootName: basename5(projectDir),
14958
- files,
14959
- docs: { entrypoints: docs },
14960
- commands: {
14961
- scripts: commands.scripts,
14962
- testCommandCandidates: commands.scripts.filter((script) => script.commandClass === "test").map((script) => script.name)
14963
- },
14964
- exclusions: privacy.excludedGlobs,
14965
- sourceContentIncluded: false
14966
- };
14967
- const planFiles = await Promise.all(PROJECT_CONTEXT_ALLOWED_RELATIVE_PATHS.map(async (relativePath) => {
14968
- const absolutePath = join23(projectDir, relativePath);
14969
- const exists = await pathExists9(absolutePath);
14970
- return {
14971
- relativePath,
14972
- absolutePath,
14973
- action: exists ? "error" : "create",
14974
- reason: exists ? "Target already exists; I1 does not overwrite." : "Allowed project context file."
14975
- };
14976
- }));
14977
- const errors2 = planFiles.filter((file) => file.action === "error").map((file) => `${file.relativePath}: ${file.reason}`);
14978
- return {
14979
- projectDir,
14980
- projectId,
14981
- files: planFiles,
14982
- index,
14983
- commands,
14984
- privacy,
14985
- warnings: commands.warnings,
14986
- errors: errors2
14987
- };
14988
- }
14989
- async function writeProjectContext(plan) {
14990
- if (plan.errors.length > 0) {
14991
- throw new Error(`Cannot write project context:
14992
- ${plan.errors.join(`
14993
- `)}`);
14994
- }
14995
- const payloads = createProjectContextPayloads(plan);
14996
- const writtenFiles = [];
14997
- for (const relativePath of PROJECT_CONTEXT_ALLOWED_RELATIVE_PATHS) {
14998
- const content = payloads[relativePath];
14999
- const absolutePath = join23(plan.projectDir, relativePath);
15000
- await mkdir16(join23(absolutePath, ".."), { recursive: true });
15001
- await writeFile15(absolutePath, content, { encoding: "utf8", flag: "wx" });
15002
- writtenFiles.push(relativePath);
15003
- }
15004
- return { writtenFiles };
15005
- }
15006
- function formatProjectContextPlan(plan, mode) {
15007
- return [
15008
- "EvoDev project init",
15009
- "",
15010
- `Mode: ${mode}`,
15011
- `Project: ${plan.projectDir}`,
15012
- `Project id: ${plan.projectId}`,
15013
- "",
15014
- "Plan:",
15015
- ...plan.files.map((file) => ` - ${file.action}: ${file.relativePath} (${file.reason})`),
15016
- "",
15017
- "Metadata-only index summary:",
15018
- ` - files: ${plan.index.files.filter((file) => file.kind === "file").length}`,
15019
- ` - directories: ${plan.index.files.filter((file) => file.kind === "directory").length}`,
15020
- ` - docs: ${plan.index.docs.entrypoints.length}`,
15021
- ` - package scripts: ${plan.commands.scripts.length}`,
15022
- ...plan.warnings.map((warning) => `Warning: ${warning}`),
15023
- ...plan.errors.map((error) => `Error: ${error}`)
15024
- ].join(`
15025
- `);
15026
- }
15027
- function createProjectContextPayloads(plan) {
15028
- const profile = {
15029
- version: 1,
15030
- projectId: plan.projectId,
15031
- displayName: basename5(plan.projectDir),
15032
- root: { pathPolicy: "local-only" },
15033
- privacy: {
15034
- classification: "local-private",
15035
- metadataOnly: true,
15036
- sourceContentIncluded: false,
15037
- rawCommandsIncluded: false
15038
- }
15039
- };
15040
- return {
15041
- ".evodev/project.json": `${JSON.stringify(profile, null, 2)}
15042
- `,
15043
- ".evodev/profile.md": createProfileMarkdown(plan),
15044
- ".evodev/index.json": `${JSON.stringify(plan.index, null, 2)}
15045
- `,
15046
- ".evodev/commands.json": `${JSON.stringify(plan.commands, null, 2)}
15047
- `,
15048
- ".evodev/privacy.json": `${JSON.stringify(plan.privacy, null, 2)}
15049
- `,
15050
- ".evodev/decisions/README.md": `# Project Decisions
15051
-
15052
- Record project decisions here.
15053
- `
15054
- };
15055
- }
15056
- function createProfileMarkdown(plan) {
15057
- return [
15058
- `# ${basename5(plan.projectDir)} Project Context`,
15059
- "",
15060
- "This project context was generated as metadata-only local state.",
15061
- "",
15062
- `- Project id: ${plan.projectId}`,
15063
- "- Source content included: false",
15064
- "- Raw package script commands included: false",
15065
- "- External upload: false",
15066
- ""
15067
- ].join(`
15068
- `);
15069
- }
15070
- async function collectProjectFileMetadata(projectDir) {
15071
- const files = [];
15072
- async function visit(dir) {
15073
- const entries = await readdir13(dir, { withFileTypes: true });
15074
- for (const entry of entries) {
15075
- const absolutePath = join23(dir, entry.name);
15076
- const relativePath = relative8(projectDir, absolutePath).replaceAll("\\", "/");
15077
- if (shouldExcludePath(relativePath, entry.isDirectory())) {
15078
- continue;
15079
- }
15080
- if (entry.isDirectory()) {
15081
- files.push({ path: relativePath, kind: "directory" });
15082
- await visit(absolutePath);
15083
- continue;
15084
- }
15085
- if (entry.isFile()) {
15086
- const fileStat = await stat12(absolutePath);
15087
- files.push({ path: relativePath, kind: "file", sizeBytes: fileStat.size });
15088
- }
15089
- }
15090
- }
15091
- await visit(projectDir);
15092
- return files.sort((left, right) => left.path.localeCompare(right.path));
15093
- }
15094
- async function collectProjectCommands(projectDir) {
15095
- const packageJsonPath = join23(projectDir, "package.json");
15096
- const warnings = [];
15097
- if (!await pathExists9(packageJsonPath)) {
15098
- return { version: 1, metadataOnly: true, rawCommandsIncluded: false, scripts: [], warnings };
15099
- }
15100
- let parsed;
15101
- try {
15102
- parsed = JSON.parse(await readFile20(packageJsonPath, "utf8"));
15103
- } catch (error) {
15104
- warnings.push(`package.json scripts skipped: ${describeError4(error)}`);
15105
- return { version: 1, metadataOnly: true, rawCommandsIncluded: false, scripts: [], warnings };
15106
- }
15107
- const scripts = isRecord13(parsed) && isRecord13(parsed.scripts) ? parsed.scripts : {};
15108
- const summaries = [];
15109
- for (const [name, value] of Object.entries(scripts).sort(([left], [right]) => left.localeCompare(right))) {
15110
- if (typeof value !== "string") {
15111
- continue;
15112
- }
15113
- const commandClass = classifyScript(name, value);
15114
- const sensitiveReason = detectSensitiveScript(`${name} ${value}`);
15115
- if (sensitiveReason !== null) {
15116
- const safeName = `redacted-${commandClass}-script`;
15117
- const warning = `Protected ${commandClass} script name/command omitted because it matched protected pattern: ${sensitiveReason}.`;
15118
- warnings.push(warning);
15119
- summaries.push({
15120
- name: safeName,
15121
- commandClass,
15122
- summary: `Protected ${commandClass} script name/command omitted.`,
15123
- rawCommandStored: false,
15124
- redacted: true,
15125
- warning
15126
- });
15127
- continue;
15128
- }
15129
- summaries.push({
15130
- name,
15131
- commandClass,
15132
- summary: `Safe ${commandClass} script command summary only.`,
15133
- rawCommandStored: false,
15134
- redacted: false
15135
- });
15136
- }
15137
- return {
15138
- version: 1,
15139
- metadataOnly: true,
15140
- rawCommandsIncluded: false,
15141
- scripts: summaries,
15142
- warnings
15143
- };
15144
- }
15145
- function classifyScript(name, command) {
15146
- const text2 = `${name} ${command}`.toLowerCase();
15147
- if (text2.includes("typecheck") || text2.includes("tsc"))
15148
- return "typecheck";
15149
- if (text2.includes("lint") || text2.includes("biome") || text2.includes("eslint"))
15150
- return "lint";
15151
- if (text2.includes("test"))
15152
- return "test";
15153
- if (text2.includes("build"))
15154
- return "build";
15155
- if (text2.includes("format") || text2.includes("prettier"))
15156
- return "format";
15157
- if (text2.includes("install"))
15158
- return "install";
15159
- if (text2.includes("release") || text2.includes("publish") || text2.includes("pack"))
15160
- return "release";
15161
- return "other";
15162
- }
15163
- function detectSensitiveScript(command) {
15164
- const lower = command.toLowerCase();
15165
- if (/(^|[^a-z0-9])(secret|token|password|passwd|api[_-]?key|apikey|credential|credentials|private|internal|private-url|internal-link)([^a-z0-9]|$)/.test(lower))
15166
- return "protected-name-or-command";
15167
- if (/https?:\/\//i.test(command))
15168
- return "url";
15169
- if (/\b[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}\b/i.test(command))
15170
- return "email-or-internal-id";
15171
- return null;
15172
- }
15173
- function createProjectPrivacy() {
15174
- return {
15175
- version: 1,
15176
- classification: "local-private",
15177
- metadataOnly: true,
15178
- sourceContentIndex: false,
15179
- promptHistoryIndex: false,
15180
- shellHistoryIndex: false,
15181
- rawCommandOutputIndex: false,
15182
- externalUpload: false,
15183
- excludedGlobs: DEFAULT_EXCLUDED_GLOBS,
15184
- protectedPatterns: PROTECTED_PATTERNS
15185
- };
15186
- }
15187
- function createProjectId(projectDir) {
15188
- return basename5(projectDir).toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "") || "project";
15189
- }
15190
- function shouldExcludePath(relativePath, isDirectory) {
15191
- const segments = relativePath.split("/");
15192
- const name = segments.at(-1) ?? relativePath;
15193
- const lowerName = name.toLowerCase();
15194
- if (isDirectory && EXCLUDED_DIRECTORY_NAMES.has(name))
15195
- return true;
15196
- if (segments.includes(".evodev") && !relativePath.startsWith(".evodev/decisions"))
15197
- return true;
15198
- if (EXCLUDED_FILE_PREFIXES.some((prefix) => name.startsWith(prefix)))
15199
- return true;
15200
- if (EXCLUDED_FILE_PARTS.some((part) => lowerName.includes(part)))
15201
- return true;
15202
- if (EXCLUDED_FILE_EXTENSIONS.some((extension) => lowerName.endsWith(extension)))
15203
- return true;
15204
- return false;
15205
- }
15206
- async function pathExists9(path) {
15207
- try {
15208
- await stat12(path);
15209
- return true;
15210
- } catch (error) {
15211
- if (error instanceof Error && "code" in error && error.code === "ENOENT") {
15212
- return false;
15213
- }
15214
- throw error;
15215
- }
15216
- }
15217
- function isRecord13(value) {
15218
- return typeof value === "object" && value !== null && !Array.isArray(value);
15219
- }
15220
- function describeError4(error) {
15221
- return error instanceof Error ? error.message : String(error);
15222
- }
15223
14371
  // packages/core/src/sync/orchestrator.ts
15224
- import { join as join24 } from "node:path";
14372
+ import { join as join23 } from "node:path";
15225
14373
  async function runSync(options) {
15226
14374
  const store = createCoreConfigStore(options.homeDir);
15227
14375
  const settings = await store.readSettings();
@@ -15364,8 +14512,8 @@ function filterAssetsForTarget(assets, targetPlugin) {
15364
14512
  }
15365
14513
  function resolveAssetScannerPaths(assetsRootDir) {
15366
14514
  return {
15367
- skillsDir: join24(assetsRootDir, "skills"),
15368
- agentsDir: join24(assetsRootDir, "agents")
14515
+ skillsDir: join23(assetsRootDir, "skills"),
14516
+ agentsDir: join23(assetsRootDir, "agents")
15369
14517
  };
15370
14518
  }
15371
14519
  async function readRegistryOrDefault(store) {
@@ -15555,7 +14703,7 @@ async function handleTeamsMcpLine(line, options = {}) {
15555
14703
  try {
15556
14704
  return await handleTeamsMcpMessage(JSON.parse(line), options);
15557
14705
  } catch (error) {
15558
- return jsonRpcError(null, -32700, "Parse error", describeError5(error));
14706
+ return jsonRpcError(null, -32700, "Parse error", describeError4(error));
15559
14707
  }
15560
14708
  }
15561
14709
  async function handleTeamsMcpMessage(message, options = {}) {
@@ -15575,7 +14723,7 @@ async function handleTeamsMcpMessage(message, options = {}) {
15575
14723
  }
15576
14724
  return jsonRpcError(request.id, -32601, `Method not found: ${request.method}`);
15577
14725
  } catch (error) {
15578
- return jsonRpcError(request.id, -32603, describeError5(error));
14726
+ return jsonRpcError(request.id, -32603, describeError4(error));
15579
14727
  }
15580
14728
  }
15581
14729
  async function runTeamsMcpStdioServer(options = {}) {
@@ -15593,7 +14741,7 @@ async function runTeamsMcpStdioServer(options = {}) {
15593
14741
  }
15594
14742
  }
15595
14743
  function initializeResult(request) {
15596
- const params = isRecord14(request.params) ? request.params : {};
14744
+ const params = isRecord12(request.params) ? request.params : {};
15597
14745
  const requestedVersion = typeof params.protocolVersion === "string" ? params.protocolVersion : PROTOCOL_VERSION;
15598
14746
  const protocolVersion = SUPPORTED_PROTOCOL_VERSIONS.has(requestedVersion) ? requestedVersion : PROTOCOL_VERSION;
15599
14747
  return {
@@ -15675,7 +14823,7 @@ function toolResult(structuredContent, isError = false) {
15675
14823
  };
15676
14824
  }
15677
14825
  function parseRequest(message) {
15678
- if (!isRecord14(message))
14826
+ if (!isRecord12(message))
15679
14827
  throw new Error("Invalid JSON-RPC message; expected object.");
15680
14828
  if (message.jsonrpc !== "2.0")
15681
14829
  throw new Error("Invalid JSON-RPC version.");
@@ -15702,7 +14850,7 @@ function jsonRpcError(id, code, message, data) {
15702
14850
  return { jsonrpc: "2.0", id, error: { code, message, data } };
15703
14851
  }
15704
14852
  function expectRecord5(value, path) {
15705
- if (!isRecord14(value))
14853
+ if (!isRecord12(value))
15706
14854
  throw new Error(`Invalid ${path}; expected object.`);
15707
14855
  return value;
15708
14856
  }
@@ -15715,28 +14863,28 @@ function expectString3(value, path) {
15715
14863
  function optionalString7(value) {
15716
14864
  return typeof value === "string" && value.length > 0 ? value : undefined;
15717
14865
  }
15718
- function isRecord14(value) {
14866
+ function isRecord12(value) {
15719
14867
  return typeof value === "object" && value !== null && !Array.isArray(value);
15720
14868
  }
15721
- function describeError5(error) {
14869
+ function describeError4(error) {
15722
14870
  return error instanceof Error ? error.message : String(error);
15723
14871
  }
15724
14872
  // packages/core/src/workflow/index.ts
15725
- import { readFile as readFile21, readdir as readdir14 } from "node:fs/promises";
15726
- import { join as join25 } from "node:path";
14873
+ import { readFile as readFile20, readdir as readdir14 } from "node:fs/promises";
14874
+ import { join as join24 } from "node:path";
15727
14875
  async function scanWorkflowManifests(workflowsDir) {
15728
14876
  const manifests = [];
15729
14877
  const entries = await readdir14(workflowsDir, { withFileTypes: true });
15730
14878
  for (const entry of entries) {
15731
14879
  if (!entry.isDirectory())
15732
14880
  continue;
15733
- const manifestPath = join25(workflowsDir, entry.name, "WORKFLOW.json");
15734
- manifests.push(parseWorkflowManifest(JSON.parse(await readFile21(manifestPath, "utf8"))));
14881
+ const manifestPath = join24(workflowsDir, entry.name, "WORKFLOW.json");
14882
+ manifests.push(parseWorkflowManifest(JSON.parse(await readFile20(manifestPath, "utf8"))));
15735
14883
  }
15736
14884
  return manifests.sort((left, right) => left.id.localeCompare(right.id));
15737
14885
  }
15738
14886
  function parseWorkflowManifest(value) {
15739
- if (!isRecord15(value))
14887
+ if (!isRecord13(value))
15740
14888
  throw new Error("Workflow manifest must be an object.");
15741
14889
  const manifest = value;
15742
14890
  if (typeof manifest.id !== "string" || typeof manifest.version !== "string") {
@@ -15751,20 +14899,12 @@ function parseWorkflowManifest(value) {
15751
14899
  return manifest;
15752
14900
  }
15753
14901
  function planWorkflow(input) {
15754
- const mode = input.contract?.route.mode ?? null;
15755
- const warnings = [];
15756
- const advisories = [];
15757
- if (mode !== null && !input.workflow.modes.includes(mode)) {
15758
- advisories.push(`Workflow ${input.workflow.id} does not list task mode ${mode}.`);
15759
- }
15760
14902
  return {
15761
14903
  workflow: input.workflow,
15762
- taskId: input.contract?.taskId,
15763
- mode,
15764
14904
  steps: input.workflow.steps.map((step) => ({ ...step, plannedOnly: true })),
15765
14905
  requiredEvidence: input.workflow.requiredEvidence,
15766
- warnings,
15767
- advisories
14906
+ warnings: [],
14907
+ advisories: []
15768
14908
  };
15769
14909
  }
15770
14910
  function formatWorkflowList(manifests) {
@@ -15780,8 +14920,6 @@ function formatWorkflowPlan(plan) {
15780
14920
  "EvoDev workflow dry-run",
15781
14921
  "",
15782
14922
  `Workflow: ${plan.workflow.id}`,
15783
- `Task: ${plan.taskId ?? "none"}`,
15784
- `Mode: ${plan.mode ?? "not routed"}`,
15785
14923
  "",
15786
14924
  "Steps:",
15787
14925
  ...plan.steps.map((step) => ` - ${step.id}: ${step.name} [${step.actor}] evidence=${step.evidence.join(",") || "none"}`),
@@ -15793,13 +14931,11 @@ function formatWorkflowPlan(plan) {
15793
14931
  ].join(`
15794
14932
  `);
15795
14933
  }
15796
- function isRecord15(value) {
14934
+ function isRecord13(value) {
15797
14935
  return typeof value === "object" && value !== null && !Array.isArray(value);
15798
14936
  }
15799
14937
  export {
15800
- writeTaskContract,
15801
14938
  writeSessionIndex,
15802
- writeProjectContext,
15803
14939
  writeJson2 as writeJson,
15804
14940
  writeFailedOkfKnowledgePlanArtifact,
15805
14941
  writeEvolutionRepoProposal,
@@ -15809,7 +14945,6 @@ export {
15809
14945
  writeCodexCapabilityVerificationArtifact,
15810
14946
  writeCodeAgentTraceRef,
15811
14947
  withEvolutionReviewDecisionLock,
15812
- verifyTaskContract,
15813
14948
  validatePack,
15814
14949
  validateOkfKnowledgePlanContract,
15815
14950
  validateObservabilityEvent,
@@ -15848,7 +14983,6 @@ export {
15848
14983
  runSync,
15849
14984
  runPluginConformance,
15850
14985
  runDaemonForeground,
15851
- routeTaskContract,
15852
14986
  revokeOkfKnowledgeConcept,
15853
14987
  resumeTeamRun,
15854
14988
  resumeFailedOkfKnowledgePlan,
@@ -15858,9 +14992,10 @@ export {
15858
14992
  resolveTeamRole,
15859
14993
  resolveTeamOverlay,
15860
14994
  resolveTeamAgentReference,
15861
- resolveTaskContractOutputPath,
15862
14995
  resolveSessionMemoryPaths,
15863
14996
  resolveSegmentEvolutionTriggerPath,
14997
+ resolveProjectWorkspaceFromCwd,
14998
+ resolveProjectRegistryPaths,
15864
14999
  resolveProjectLogKey,
15865
15000
  resolveOkfKnowledgePaths,
15866
15001
  resolveObservabilityStorePaths,
@@ -15877,13 +15012,14 @@ export {
15877
15012
  resolveCodeAgentTraceRefPaths,
15878
15013
  renderRoleAgentDefinitionContext,
15879
15014
  renderMainTeamOverlayContext,
15015
+ registerDiscoveredProject,
15880
15016
  recordTeamAgentNativeSession,
15017
+ recordDiscoveredProject,
15881
15018
  recordCodeAgentTraceRefFromHook,
15882
15019
  reconcileTeamRun,
15883
15020
  rebuildOkfKnowledgeIndexes,
15884
15021
  readTeamAgentSummary,
15885
15022
  readTeamAgentDefinition,
15886
- readTaskContract,
15887
15023
  readSessionState,
15888
15024
  readSessionEvidenceSegment,
15889
15025
  readSessionCursor,
@@ -15909,7 +15045,7 @@ export {
15909
15045
  processEvolutionTriggers,
15910
15046
  planWorkflow,
15911
15047
  planPackInstallDryRun,
15912
- pathExists8 as pathExists,
15048
+ pathExists7 as pathExists,
15913
15049
  parseWorkflowManifest,
15914
15050
  parseTeamRoleDefinition,
15915
15051
  parseTeamDefinitionMarkdown,
@@ -15936,14 +15072,17 @@ export {
15936
15072
  mergeAcceptedEvosCasesIntoKnowledgeQuery,
15937
15073
  markTeamMessagesDelivered,
15938
15074
  markOkfKnowledgeConceptStale,
15075
+ markEvolutionRepoProposalApplied,
15939
15076
  loadAgentContextDryRun,
15940
15077
  loadAgentContext,
15941
15078
  loadActiveOkfKnowledgeIndex,
15942
15079
  listTeamRuns,
15943
15080
  listTeamRoleBindings,
15944
15081
  listTeamAgents,
15082
+ listSessionMemoryStates,
15945
15083
  listSessionEvidenceSegments,
15946
15084
  listSegmentEvolutionTriggers,
15085
+ listRegisteredProjects,
15947
15086
  listOkfKnowledgeConcepts,
15948
15087
  listObservabilityEvents,
15949
15088
  listLearningReviewDecisions,
@@ -15952,6 +15091,7 @@ export {
15952
15091
  listEvolutionKnowledgeReviewHistory,
15953
15092
  listEvolutionKnowledgeRecords,
15954
15093
  listEvolutionEvosCases,
15094
+ listDiscoveredProjects,
15955
15095
  listCodeAgentTraceRefs,
15956
15096
  lintOkfKnowledge,
15957
15097
  lintLearningCandidates,
@@ -15973,10 +15113,8 @@ export {
15973
15113
  getEnabledPluginIds,
15974
15114
  formatWorkflowPlan,
15975
15115
  formatWorkflowList,
15976
- formatTaskContract,
15977
15116
  formatScopedKnowledgePromptBlock,
15978
15117
  formatRetentionDryRun,
15979
- formatProjectContextPlan,
15980
15118
  formatPackValidation,
15981
15119
  formatPackInstallDryRun,
15982
15120
  formatOkfKnowledgeQuery,
@@ -15998,7 +15136,6 @@ export {
15998
15136
  formatCodexCapabilityVerificationArtifact,
15999
15137
  formatAgentLoadedContextPromptBlock,
16000
15138
  formatAgentContextDryRun,
16001
- formatAgentComposeDryRun,
16002
15139
  findCandidateConflictOrDuplicate,
16003
15140
  exports_triggers as evolutionTriggers,
16004
15141
  exports_review as evolutionReview,
@@ -16019,9 +15156,7 @@ export {
16019
15156
  createTmuxRuntimeAdapter,
16020
15157
  createTeamRunStore,
16021
15158
  createTeamRoleRuntimeContext,
16022
- createTaskContract,
16023
15159
  createScopedKnowledgeContextPack,
16024
- createProjectContextPlan,
16025
15160
  createPluginRegistry,
16026
15161
  createOkfKnowledgePlanFromDistillationBatch,
16027
15162
  createObservabilityEvent,
@@ -16047,7 +15182,6 @@ export {
16047
15182
  createCodexCapabilityVerificationArtifact,
16048
15183
  createCodeAgentTraceRef,
16049
15184
  createCliLogEntry,
16050
- composeAgentDryRun,
16051
15185
  cleanupDaemonState,
16052
15186
  classifyCommandRisk,
16053
15187
  checkProtectedZonePaths,
@@ -16070,9 +15204,9 @@ export {
16070
15204
  TeamMessageBroker,
16071
15205
  TEAM_INTERNAL_WAKE_SIGNAL,
16072
15206
  SessionMemoryEvidenceError,
15207
+ ProjectRegistrationError,
16073
15208
  PluginRegistryError,
16074
15209
  PluginRegistry,
16075
- PROJECT_CONTEXT_ALLOWED_RELATIVE_PATHS,
16076
15210
  NodeTeamRuntimeCommandRunner,
16077
15211
  EvoDevConfigError,
16078
15212
  EvoDevAssetError,