@evomap/evolver-core 2.0.0-beta.1 → 2.0.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/assets/gep/genes.jsonl +5 -0
  2. package/dist/algo/candidateAssembly.js +23 -14
  3. package/dist/algo/capabilityCandidates.d.ts +2 -0
  4. package/dist/algo/capabilityCandidates.js +5 -0
  5. package/dist/algo/conversationSniffer.d.ts +18 -0
  6. package/dist/algo/conversationSniffer.js +132 -0
  7. package/dist/algo/cycleEngine.d.ts +11 -0
  8. package/dist/algo/cycleEngine.js +14 -6
  9. package/dist/algo/cycleFailureClassifier.d.ts +1 -1
  10. package/dist/algo/cycleFailureClassifier.js +13 -5
  11. package/dist/algo/geneIntake.d.ts +14 -4
  12. package/dist/algo/geneIntake.js +37 -9
  13. package/dist/algo/geneSelection.d.ts +18 -1
  14. package/dist/algo/geneSelection.js +42 -18
  15. package/dist/algo/index.d.ts +2 -0
  16. package/dist/algo/index.js +2 -0
  17. package/dist/algo/memoryGraph.d.ts +62 -0
  18. package/dist/algo/memoryGraph.js +86 -0
  19. package/dist/algo/orchestrator.d.ts +3 -0
  20. package/dist/algo/orchestrator.js +14 -2
  21. package/dist/assetstore/assetSidecarRecords.d.ts +23 -0
  22. package/dist/assetstore/assetSidecarRecords.js +142 -0
  23. package/dist/assetstore/assetSidecarRecovery.d.ts +48 -0
  24. package/dist/assetstore/assetSidecarRecovery.js +288 -0
  25. package/dist/assetstore/assetStoreHealth.d.ts +75 -0
  26. package/dist/assetstore/assetStoreHealth.js +277 -0
  27. package/dist/assetstore/assetStoreLayout.d.ts +2 -0
  28. package/dist/assetstore/assetStoreLayout.js +6 -0
  29. package/dist/assetstore/assetStoreStorage.d.ts +42 -0
  30. package/dist/assetstore/assetStoreStorage.js +318 -0
  31. package/dist/assetstore/assetSyncLedger.d.ts +32 -0
  32. package/dist/assetstore/assetSyncLedger.js +66 -0
  33. package/dist/assetstore/index.d.ts +5 -1
  34. package/dist/assetstore/index.js +5 -1
  35. package/dist/assetstore/localJsonl.d.ts +10 -2
  36. package/dist/assetstore/localJsonl.js +93 -37
  37. package/dist/assetstore/pendingSignals.js +3 -1
  38. package/dist/assetstore/provenance.d.ts +20 -2
  39. package/dist/assetstore/provenance.js +92 -56
  40. package/dist/assetstore/provider.d.ts +2 -0
  41. package/dist/assetstore/reviewFilter.js +5 -2
  42. package/dist/assetstore/reviewLedger.d.ts +14 -2
  43. package/dist/assetstore/reviewLedger.js +78 -43
  44. package/dist/assetstore/seedGenes.d.ts +3 -0
  45. package/dist/assetstore/seedGenes.js +134 -0
  46. package/dist/benchmark/antiGeneBenchmark.d.ts +2 -0
  47. package/dist/benchmark/antiGeneBenchmark.js +11 -1
  48. package/dist/benchmark/antiGeneImpact.d.ts +16 -0
  49. package/dist/benchmark/antiGeneImpact.js +34 -0
  50. package/dist/benchmark/antiGeneRollout.d.ts +2 -0
  51. package/dist/benchmark/antiGeneRollout.js +13 -1
  52. package/dist/benchmark/index.d.ts +2 -1
  53. package/dist/benchmark/index.js +2 -1
  54. package/dist/benchmark/triggerShift.d.ts +62 -0
  55. package/dist/benchmark/triggerShift.js +106 -0
  56. package/dist/events/eventArchive.d.ts +65 -0
  57. package/dist/events/eventArchive.js +343 -0
  58. package/dist/events/eventStore.js +2 -12
  59. package/dist/events/ingest.d.ts +1 -1
  60. package/dist/events/ingest.js +2 -0
  61. package/dist/events/paths.d.ts +1 -1
  62. package/dist/events/paths.js +2 -2
  63. package/dist/events/public.d.ts +3 -1
  64. package/dist/events/public.js +2 -1
  65. package/dist/events/retention.d.ts +24 -1
  66. package/dist/events/retention.js +133 -37
  67. package/dist/exec/autoExec.d.ts +6 -1
  68. package/dist/exec/autoExec.js +34 -0
  69. package/dist/exec/autonomousCycle.d.ts +2 -0
  70. package/dist/exec/autonomousCycle.js +5 -0
  71. package/dist/exec/claudeBridge.d.ts +7 -2
  72. package/dist/exec/claudeBridge.js +115 -14
  73. package/dist/exec/prompt.js +9 -0
  74. package/dist/exec/runnerRegistry.d.ts +64 -18
  75. package/dist/exec/runnerRegistry.js +341 -38
  76. package/dist/exec/selfPrObfuscation.d.ts +2 -1
  77. package/dist/exec/selfPrObfuscation.js +19 -6
  78. package/dist/hub/agentDirectory.d.ts +90 -0
  79. package/dist/hub/agentDirectory.js +104 -0
  80. package/dist/hub/bindings.js +23 -3
  81. package/dist/hub/capability.d.ts +14 -2
  82. package/dist/hub/fake.d.ts +4 -2
  83. package/dist/hub/fake.js +3 -2
  84. package/dist/hub/index.d.ts +1 -0
  85. package/dist/hub/index.js +1 -0
  86. package/dist/mailbox/catalog.js +3 -0
  87. package/dist/mailbox/ipcServer.js +2 -2
  88. package/dist/mailbox/store.d.ts +14 -0
  89. package/dist/mailbox/store.js +44 -2
  90. package/dist/material/consumer.js +9 -6
  91. package/dist/material/index.d.ts +1 -0
  92. package/dist/material/index.js +1 -0
  93. package/dist/material/materialArchive.d.ts +81 -0
  94. package/dist/material/materialArchive.js +466 -0
  95. package/dist/material/materialStore.d.ts +1 -0
  96. package/dist/material/materialStore.js +6 -13
  97. package/dist/ops/savingsCore.js +1 -2
  98. package/dist/ops/selfUpdate.d.ts +10 -1
  99. package/dist/ops/selfUpdate.js +64 -15
  100. package/dist/schema/common.d.ts +1 -1
  101. package/dist/schema/common.js +1 -1
  102. package/dist/schema/material.d.ts +5 -5
  103. package/dist/trace/trajectoryExport.js +2 -2
  104. package/dist/util/fileLock.d.ts +19 -2
  105. package/dist/util/fileLock.js +166 -31
  106. package/dist/wire/geneHints.d.ts +42 -1
  107. package/dist/wire/geneHints.js +52 -1
  108. package/dist/wire/index.d.ts +14 -2
  109. package/dist/wire/index.js +1 -1
  110. package/package.json +6 -1
@@ -21,7 +21,7 @@ export type Watermark = z.infer<typeof watermark>;
21
21
  export declare const material: z.ZodEffects<z.ZodObject<{
22
22
  materialId: z.ZodString;
23
23
  /** Runtime agent that produced a session/tool source. Absent for agent-agnostic origins (proxy trace), #95. */
24
- sourceAgent: z.ZodOptional<z.ZodEnum<["claude-code", "codex", "cursor", "gemini", "kimi", "kiro", "opencode", "generic-chat"]>>;
24
+ sourceAgent: z.ZodOptional<z.ZodEnum<["claude-code", "codex", "cursor", "gemini", "antigravity", "kimi", "kiro", "opencode", "generic-chat"]>>;
25
25
  /** Origin class: a runtime agent session, or the proxy gateway's LLM trace (agent-agnostic), #95.
26
26
  * Defaults to runtime_session so pre-#95 records (which only ever held sessions) parse unchanged. */
27
27
  sourceKind: z.ZodDefault<z.ZodEnum<["runtime_session", "proxy_trace"]>>;
@@ -76,7 +76,7 @@ export declare const material: z.ZodEffects<z.ZodObject<{
76
76
  consumerGroup: string;
77
77
  feedsMaterial: boolean;
78
78
  extensions: Record<string, unknown>;
79
- sourceAgent?: "claude-code" | "codex" | "cursor" | "gemini" | "kimi" | "kiro" | "opencode" | "generic-chat" | undefined;
79
+ sourceAgent?: "claude-code" | "codex" | "cursor" | "gemini" | "antigravity" | "kimi" | "kiro" | "opencode" | "generic-chat" | undefined;
80
80
  payloadRef?: {
81
81
  path: string;
82
82
  sha256: string;
@@ -95,7 +95,7 @@ export declare const material: z.ZodEffects<z.ZodObject<{
95
95
  };
96
96
  capturedAt: string;
97
97
  consumerGroup: string;
98
- sourceAgent?: "claude-code" | "codex" | "cursor" | "gemini" | "kimi" | "kiro" | "opencode" | "generic-chat" | undefined;
98
+ sourceAgent?: "claude-code" | "codex" | "cursor" | "gemini" | "antigravity" | "kimi" | "kiro" | "opencode" | "generic-chat" | undefined;
99
99
  sourceKind?: "runtime_session" | "proxy_trace" | undefined;
100
100
  payloadRef?: {
101
101
  path: string;
@@ -120,7 +120,7 @@ export declare const material: z.ZodEffects<z.ZodObject<{
120
120
  consumerGroup: string;
121
121
  feedsMaterial: boolean;
122
122
  extensions: Record<string, unknown>;
123
- sourceAgent?: "claude-code" | "codex" | "cursor" | "gemini" | "kimi" | "kiro" | "opencode" | "generic-chat" | undefined;
123
+ sourceAgent?: "claude-code" | "codex" | "cursor" | "gemini" | "antigravity" | "kimi" | "kiro" | "opencode" | "generic-chat" | undefined;
124
124
  payloadRef?: {
125
125
  path: string;
126
126
  sha256: string;
@@ -139,7 +139,7 @@ export declare const material: z.ZodEffects<z.ZodObject<{
139
139
  };
140
140
  capturedAt: string;
141
141
  consumerGroup: string;
142
- sourceAgent?: "claude-code" | "codex" | "cursor" | "gemini" | "kimi" | "kiro" | "opencode" | "generic-chat" | undefined;
142
+ sourceAgent?: "claude-code" | "codex" | "cursor" | "gemini" | "antigravity" | "kimi" | "kiro" | "opencode" | "generic-chat" | undefined;
143
143
  sourceKind?: "runtime_session" | "proxy_trace" | undefined;
144
144
  payloadRef?: {
145
145
  path: string;
@@ -1558,7 +1558,7 @@ function runtimeSessionId(input) {
1558
1558
  return explicit;
1559
1559
  const sourcePath = stringValue(input.sourcePath);
1560
1560
  const base = sourcePath.split(/[\\/]/).filter(Boolean).pop() ?? '';
1561
- return base.replace(/\.jsonl?$/i, '') || 'unknown';
1561
+ return redactString(base.replace(/\.jsonl?$/i, '')) || 'unknown';
1562
1562
  }
1563
1563
  function nativeCallHasField(call, key) {
1564
1564
  return Object.prototype.hasOwnProperty.call(call, key);
@@ -1704,7 +1704,7 @@ export function buildCodingTrajectoryFromSessionLog(input) {
1704
1704
  session_id: sessionId,
1705
1705
  source_kind: 'runtime_session',
1706
1706
  source_agent: sourceAgent,
1707
- source_path: sourcePath,
1707
+ source_path: redactString(sourcePath),
1708
1708
  ...(sessionModel ? { session_model: sessionModel } : {}),
1709
1709
  ...(provider !== sourceAgent ? { session_provider: provider } : {}),
1710
1710
  ...(sessionTools !== undefined ? { session_tools: redactRuntimeStructuredValue(sessionTools) } : {}),
@@ -1,8 +1,15 @@
1
1
  export declare function syncSleep(ms: number): void;
2
2
  export declare class LockTimeoutError extends Error {
3
3
  readonly code = "LOCK_TIMEOUT";
4
- constructor(lockPath: string);
4
+ constructor(_lockPath?: string);
5
5
  }
6
+ export type UnsafeLockPathReason = 'symlink' | 'not_regular_file' | 'owner_too_large' | 'path_changed' | 'permission_denied' | 'invalid_owner';
7
+ export declare class UnsafeLockPathError extends Error {
8
+ readonly reason: UnsafeLockPathReason;
9
+ readonly code = "UNSAFE_LOCK_PATH";
10
+ constructor(reason: UnsafeLockPathReason);
11
+ }
12
+ export declare const MAX_LOCK_OWNER_BYTES = 4096;
6
13
  export interface AcquireLockOptions {
7
14
  maxTries?: number;
8
15
  waitMs?: number;
@@ -21,4 +28,14 @@ export interface AcquireLockOptions {
21
28
  * synchronous critical sections (append-only writes).
22
29
  */
23
30
  export declare function acquireLock(lockPath: string, opts?: AcquireLockOptions): void;
24
- export declare function releaseLock(lockPath: string): void;
31
+ export type ReleaseLockReason = 'released' | 'missing' | 'ownership_changed' | 'not_owned' | 'released_with_cleanup_error' | UnsafeLockPathReason | 'release_failed';
32
+ export interface ReleaseLockResult {
33
+ released: boolean;
34
+ reason: ReleaseLockReason;
35
+ }
36
+ export declare function releaseLock(lockPath: string): ReleaseLockResult;
37
+ export declare class LockReleaseError extends Error {
38
+ readonly reason: ReleaseLockReason;
39
+ readonly code = "LOCK_RELEASE_FAILED";
40
+ constructor(reason: ReleaseLockReason);
41
+ }
@@ -1,5 +1,5 @@
1
1
  import { randomUUID } from 'node:crypto';
2
- import { readFileSync, renameSync, unlinkSync, writeFileSync } from 'node:fs';
2
+ import { closeSync, constants, fstatSync, lstatSync, openSync, readSync, renameSync, unlinkSync, writeFileSync, } from 'node:fs';
3
3
  import { basename, dirname, join, resolve } from 'node:path';
4
4
  export function syncSleep(ms) {
5
5
  Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
@@ -7,11 +7,21 @@ export function syncSleep(ms) {
7
7
  const ownedLocks = new Map();
8
8
  export class LockTimeoutError extends Error {
9
9
  code = 'LOCK_TIMEOUT';
10
- constructor(lockPath) {
11
- super(`获取文件锁超时: ${lockPath}`);
10
+ constructor(_lockPath) {
11
+ super('获取文件锁超时');
12
12
  this.name = 'LockTimeoutError';
13
13
  }
14
14
  }
15
+ export class UnsafeLockPathError extends Error {
16
+ reason;
17
+ code = 'UNSAFE_LOCK_PATH';
18
+ constructor(reason) {
19
+ super(`不安全的文件锁路径: ${reason}`);
20
+ this.reason = reason;
21
+ this.name = 'UnsafeLockPathError';
22
+ }
23
+ }
24
+ export const MAX_LOCK_OWNER_BYTES = 4096;
15
25
  function lockKey(lockPath) {
16
26
  return resolve(lockPath);
17
27
  }
@@ -24,6 +34,73 @@ function serializeOwner(owner) {
24
34
  function isErrno(error, code) {
25
35
  return typeof error === 'object' && error !== null && error.code === code;
26
36
  }
37
+ function noFollowFlag() {
38
+ return constants['O_NOFOLLOW'] ?? 0;
39
+ }
40
+ function assertRegularOwnerStat(stat) {
41
+ if (stat.isSymbolicLink())
42
+ throw new UnsafeLockPathError('symlink');
43
+ if (!stat.isFile())
44
+ throw new UnsafeLockPathError('not_regular_file');
45
+ if (stat.size > BigInt(MAX_LOCK_OWNER_BYTES))
46
+ throw new UnsafeLockPathError('owner_too_large');
47
+ }
48
+ function currentOwnerStat(path) {
49
+ try {
50
+ const stat = lstatSync(path, { bigint: true });
51
+ assertRegularOwnerStat(stat);
52
+ return stat;
53
+ }
54
+ catch (error) {
55
+ if (isErrno(error, 'ENOENT'))
56
+ return null;
57
+ if (isErrno(error, 'EACCES') || isErrno(error, 'EPERM')) {
58
+ throw new UnsafeLockPathError('permission_denied');
59
+ }
60
+ throw error;
61
+ }
62
+ }
63
+ function readOwnerBounded(path) {
64
+ const before = currentOwnerStat(path);
65
+ if (before === null)
66
+ return null;
67
+ let fd;
68
+ try {
69
+ fd = openSync(path, constants.O_RDONLY | noFollowFlag());
70
+ }
71
+ catch (error) {
72
+ if (isErrno(error, 'ENOENT'))
73
+ return null;
74
+ if (isErrno(error, 'ELOOP'))
75
+ throw new UnsafeLockPathError('symlink');
76
+ if (isErrno(error, 'EACCES') || isErrno(error, 'EPERM')) {
77
+ throw new UnsafeLockPathError('permission_denied');
78
+ }
79
+ throw error;
80
+ }
81
+ try {
82
+ const opened = fstatSync(fd, { bigint: true });
83
+ assertRegularOwnerStat(opened);
84
+ const current = currentOwnerStat(path);
85
+ if (current === null || current.dev !== opened.dev || current.ino !== opened.ino) {
86
+ throw new UnsafeLockPathError('path_changed');
87
+ }
88
+ const buffer = Buffer.alloc(MAX_LOCK_OWNER_BYTES + 1);
89
+ let total = 0;
90
+ while (total < buffer.length) {
91
+ const read = readSync(fd, buffer, total, buffer.length - total, total);
92
+ if (read === 0)
93
+ break;
94
+ total += read;
95
+ }
96
+ if (total > MAX_LOCK_OWNER_BYTES)
97
+ throw new UnsafeLockPathError('owner_too_large');
98
+ return buffer.subarray(0, total).toString('utf8');
99
+ }
100
+ finally {
101
+ closeSync(fd);
102
+ }
103
+ }
27
104
  /** True if pid is a live process (cross-platform via signal 0; EPERM = exists but owned by another user). */
28
105
  function pidAlive(pid) {
29
106
  if (!Number.isInteger(pid) || pid <= 0)
@@ -73,10 +150,13 @@ function parseOwner(raw) {
73
150
  /** Owner recorded in the lock file; null if missing/unparseable. */
74
151
  function lockOwner(lockPath) {
75
152
  try {
76
- return parseOwner(readFileSync(lockPath, 'utf8'));
153
+ const raw = readOwnerBounded(lockPath);
154
+ return raw === null ? null : parseOwner(raw);
77
155
  }
78
156
  catch (error) {
79
- if (isErrno(error, 'ENOENT'))
157
+ // A valid owner can release and another waiter can acquire between lstat/open/fstat. Treat that snapshot as
158
+ // transiently unavailable: callers remain conservative (no steal/delete) and the acquire loop retries.
159
+ if (error instanceof UnsafeLockPathError && error.reason === 'path_changed')
80
160
  return null;
81
161
  throw error;
82
162
  }
@@ -100,17 +180,30 @@ function removeFileIfExists(path) {
100
180
  }
101
181
  }
102
182
  function createLockFile(lockPath, owner, trackOwnership) {
103
- try {
104
- writeFileSync(lockPath, serializeOwner(owner), { flag: 'wx', mode: 0o600 });
105
- if (trackOwnership)
106
- ownedLocks.set(lockKey(lockPath), owner);
107
- return true;
108
- }
109
- catch (error) {
110
- if (isErrno(error, 'EEXIST'))
111
- return false;
112
- throw error;
183
+ for (let permissionAttempt = 0; permissionAttempt < 2; permissionAttempt++) {
184
+ try {
185
+ writeFileSync(lockPath, serializeOwner(owner), { flag: 'wx', mode: 0o600 });
186
+ if (trackOwnership)
187
+ ownedLocks.set(lockKey(lockPath), { owner, releasePending: false });
188
+ return true;
189
+ }
190
+ catch (error) {
191
+ if (isErrno(error, 'EEXIST'))
192
+ return false;
193
+ if (isErrno(error, 'EACCES') || isErrno(error, 'EPERM')) {
194
+ // Windows can report EPERM instead of EEXIST during contention. A regular owner is busy; if the owner
195
+ // disappeared before lstat, retry create once to distinguish that release race from a persistent ACL
196
+ // failure. Unsafe/inaccessible paths still throw from currentOwnerStat and remain fail closed.
197
+ if (currentOwnerStat(lockPath) !== null)
198
+ return false;
199
+ if (permissionAttempt === 0)
200
+ continue;
201
+ throw new UnsafeLockPathError('permission_denied');
202
+ }
203
+ throw error;
204
+ }
113
205
  }
206
+ throw new UnsafeLockPathError('permission_denied');
114
207
  }
115
208
  function tryAcquireMutationGuard(lockPath) {
116
209
  const guardPath = mutationGuardPath(lockPath);
@@ -185,6 +278,12 @@ function reclaimStaleLock(lockPath) {
185
278
  * synchronous critical sections (append-only writes).
186
279
  */
187
280
  export function acquireLock(lockPath, opts = {}) {
281
+ const pending = ownedLocks.get(lockKey(lockPath));
282
+ if (pending?.releasePending) {
283
+ const released = releaseLock(lockPath);
284
+ if (!released.released)
285
+ throw new LockReleaseError(released.reason);
286
+ }
188
287
  const maxTries = opts.maxTries ?? 300;
189
288
  const waitMs = opts.waitMs ?? 10;
190
289
  for (let i = 0; i < maxTries; i++) {
@@ -200,28 +299,64 @@ export function acquireLock(lockPath, opts = {}) {
200
299
  }
201
300
  syncSleep(waitMs);
202
301
  }
203
- throw new LockTimeoutError(lockPath);
302
+ throw new LockTimeoutError();
204
303
  }
205
304
  export function releaseLock(lockPath) {
206
305
  const key = lockKey(lockPath);
207
- const owner = ownedLocks.get(key);
208
- if (owner === undefined)
209
- return;
306
+ const owned = ownedLocks.get(key);
307
+ if (owned === undefined)
308
+ return { released: true, reason: 'not_owned' };
309
+ const failed = (reason) => {
310
+ owned.releasePending = true;
311
+ return { released: false, reason };
312
+ };
313
+ // Release must not use lockOwner(): that helper intentionally folds path_changed into a conservative null
314
+ // for acquire retries. Here, an inconclusive read marks a pending release so the next acquire can retry or
315
+ // surface LOCK_RELEASE_FAILED instead of silently timing out behind this process's own PID.
316
+ let raw;
210
317
  try {
211
- if (!sameOwner(lockOwner(lockPath), owner))
212
- return;
213
- const releasedPath = sidecarPath(lockPath, 'released');
214
- try {
215
- renameSync(lockPath, releasedPath);
216
- }
217
- catch (error) {
218
- if (isErrno(error, 'ENOENT'))
219
- return;
220
- throw error;
318
+ raw = readOwnerBounded(lockPath);
319
+ }
320
+ catch (error) {
321
+ return failed(error instanceof UnsafeLockPathError ? error.reason : 'release_failed');
322
+ }
323
+ if (raw === null) {
324
+ ownedLocks.delete(key);
325
+ return { released: true, reason: 'missing' };
326
+ }
327
+ const current = parseOwner(raw);
328
+ if (current === null)
329
+ return failed('invalid_owner');
330
+ if (!sameOwner(current, owned.owner)) {
331
+ ownedLocks.delete(key);
332
+ return { released: true, reason: 'ownership_changed' };
333
+ }
334
+ const releasedPath = sidecarPath(lockPath, 'released');
335
+ try {
336
+ renameSync(lockPath, releasedPath);
337
+ }
338
+ catch (error) {
339
+ if (isErrno(error, 'ENOENT')) {
340
+ ownedLocks.delete(key);
341
+ return { released: true, reason: 'missing' };
221
342
  }
343
+ return failed('release_failed');
344
+ }
345
+ ownedLocks.delete(key);
346
+ try {
222
347
  removeFileIfExists(releasedPath);
223
348
  }
224
- finally {
225
- ownedLocks.delete(key);
349
+ catch {
350
+ return { released: true, reason: 'released_with_cleanup_error' };
351
+ }
352
+ return { released: true, reason: 'released' };
353
+ }
354
+ export class LockReleaseError extends Error {
355
+ reason;
356
+ code = 'LOCK_RELEASE_FAILED';
357
+ constructor(reason) {
358
+ super(`文件锁释放未完成: ${reason}`);
359
+ this.reason = reason;
360
+ this.name = 'LockReleaseError';
226
361
  }
227
362
  }
@@ -34,13 +34,45 @@ export interface GeneToolPolicy {
34
34
  deny?: string[];
35
35
  severity?: ToolPolicySeverity;
36
36
  }
37
+ /**
38
+ * Provenance classification (V1 #302 classifyProvenance, aligned with TaskGenome Bench §3.1): a Gene's value
39
+ * depends on WHERE it came from, not on being short. The three tiers:
40
+ * evolved -- distilled from a real solve -> fail -> mutate -> pass trajectory; beats Skills (+8.7..+15.5pp)
41
+ * distilled -- transcribed from reference/teacher text with no real failing trajectory; WORSE than Skills (-3.2..-11.2pp)
42
+ * manual -- pure human transcription, no execution evidence at all
43
+ * The high-value payload of an evolved Gene is the corrective_insight that flipped the outcome.
44
+ */
45
+ export declare const GENERATION_SOURCES: readonly ["evolved", "distilled", "manual"];
46
+ export type GenerationSource = (typeof GENERATION_SOURCES)[number];
47
+ export interface GeneGenerationHeuristics {
48
+ strategy_steps?: number;
49
+ avoid_count?: number;
50
+ validation_declared_count?: number;
51
+ validation_runnable_count?: number;
52
+ signals_extracted?: number;
53
+ preconditions_extracted?: number;
54
+ trajectory_depth?: number;
55
+ has_corrective_insight?: boolean;
56
+ }
57
+ /**
58
+ * The full provenance + quality metadata block (V1 `gene._source`). Lives on Gene as the v2-delta field
59
+ * `generation_meta`. `source` is the only required key; the rest is descriptive for reviewers / future
60
+ * governance. `quality_score` is a coarse [0,1] tier-anchored score (evolved 0.7 / distilled 0.4 / manual 0.3
61
+ * baseline + bonuses); `overcame_errors` is the mutation_log copy that the trajectory overcame.
62
+ */
63
+ export interface GenerationMeta {
64
+ source: GenerationSource;
65
+ quality_score?: number;
66
+ quality_heuristics?: GeneGenerationHeuristics;
67
+ overcame_errors?: string[];
68
+ }
37
69
  /**
38
70
  * The v2-delta hint field names, in one place — the intake gate strips these before the gep-sdk schema check.
39
71
  * IMPORTANT: when a gep-sdk gene-schema bump makes one of these first-class, REMOVE it from this list in the
40
72
  * same change. Otherwise intakeGene keeps stripping a now-validated field before validateWire (fail-open — the
41
73
  * field's new schema constraints go unchecked at intake) while asset_id still commits it.
42
74
  */
43
- export declare const GENE_HINT_FIELDS: readonly ["routing_hint", "tool_policy"];
75
+ export declare const GENE_HINT_FIELDS: readonly ["routing_hint", "tool_policy", "generation_meta"];
44
76
  /**
45
77
  * Normalize an arbitrary routing_hint fragment to a strict { tier?, reasoning_level? } object, or null.
46
78
  * Unknown enum values are dropped (a stray tier would fail the consumer's exhaustive match and route as if
@@ -60,5 +92,14 @@ export declare function normalizeRoutingHint(raw: unknown): GeneRoutingHint | nu
60
92
  * defaults to 'warn' when a list is present; the whole object collapses to null when neither list survives.
61
93
  */
62
94
  export declare function normalizeToolPolicy(raw: unknown): GeneToolPolicy | null;
95
+ /**
96
+ * Normalize an arbitrary generation_meta fragment to a strict { source, quality_score?, quality_heuristics?,
97
+ * overcame_errors? } object, or null. Lossy (mirrors normalizeRoutingHint / normalizeToolPolicy): unknown source
98
+ * values are dropped (the whole block collapses to null — a generation_meta with no recognized source carries no
99
+ * usable provenance signal); quality_score is clamped to [0,1]; heuristics keeps only its numeric/boolean fields;
100
+ * overcame_errors keeps only non-empty strings. A block with a valid source but all-else-empty still survives (source
101
+ * alone is a meaningful provenance tag); only a missing/unknown source yields null.
102
+ */
103
+ export declare function normalizeGenerationMeta(raw: unknown): GenerationMeta | null;
63
104
  /** Strip the v2-delta hint fields from a gene-shaped object (used to validate the gep-sdk-known core). */
64
105
  export declare function stripGeneHints(gene: Record<string, unknown>): Record<string, unknown>;
@@ -22,13 +22,22 @@
22
22
  export const ROUTING_TIERS = ['cheap', 'mid', 'expensive'];
23
23
  export const REASONING_LEVELS = ['off', 'low', 'medium', 'high'];
24
24
  export const TOOL_POLICY_SEVERITIES = ['warn', 'block'];
25
+ /**
26
+ * Provenance classification (V1 #302 classifyProvenance, aligned with TaskGenome Bench §3.1): a Gene's value
27
+ * depends on WHERE it came from, not on being short. The three tiers:
28
+ * evolved -- distilled from a real solve -> fail -> mutate -> pass trajectory; beats Skills (+8.7..+15.5pp)
29
+ * distilled -- transcribed from reference/teacher text with no real failing trajectory; WORSE than Skills (-3.2..-11.2pp)
30
+ * manual -- pure human transcription, no execution evidence at all
31
+ * The high-value payload of an evolved Gene is the corrective_insight that flipped the outcome.
32
+ */
33
+ export const GENERATION_SOURCES = ['evolved', 'distilled', 'manual'];
25
34
  /**
26
35
  * The v2-delta hint field names, in one place — the intake gate strips these before the gep-sdk schema check.
27
36
  * IMPORTANT: when a gep-sdk gene-schema bump makes one of these first-class, REMOVE it from this list in the
28
37
  * same change. Otherwise intakeGene keeps stripping a now-validated field before validateWire (fail-open — the
29
38
  * field's new schema constraints go unchecked at intake) while asset_id still commits it.
30
39
  */
31
- export const GENE_HINT_FIELDS = ['routing_hint', 'tool_policy'];
40
+ export const GENE_HINT_FIELDS = ['routing_hint', 'tool_policy', 'generation_meta'];
32
41
  function includesEnum(set, v) {
33
42
  return typeof v === 'string' && set.includes(v);
34
43
  }
@@ -89,6 +98,48 @@ function cleanToolList(raw) {
89
98
  const cleaned = raw.filter((x) => typeof x === 'string' && x.length > 0);
90
99
  return cleaned.length > 0 ? cleaned : undefined;
91
100
  }
101
+ /**
102
+ * Normalize an arbitrary generation_meta fragment to a strict { source, quality_score?, quality_heuristics?,
103
+ * overcame_errors? } object, or null. Lossy (mirrors normalizeRoutingHint / normalizeToolPolicy): unknown source
104
+ * values are dropped (the whole block collapses to null — a generation_meta with no recognized source carries no
105
+ * usable provenance signal); quality_score is clamped to [0,1]; heuristics keeps only its numeric/boolean fields;
106
+ * overcame_errors keeps only non-empty strings. A block with a valid source but all-else-empty still survives (source
107
+ * alone is a meaningful provenance tag); only a missing/unknown source yields null.
108
+ */
109
+ export function normalizeGenerationMeta(raw) {
110
+ if (!raw || typeof raw !== 'object')
111
+ return null;
112
+ const r = raw;
113
+ const source = r['source'];
114
+ if (!includesEnum(GENERATION_SOURCES, source))
115
+ return null;
116
+ const out = { source };
117
+ const qs = r['quality_score'];
118
+ if (typeof qs === 'number' && Number.isFinite(qs))
119
+ out.quality_score = Math.max(0, Math.min(1, qs));
120
+ const eh = r['quality_heuristics'];
121
+ if (eh && typeof eh === 'object') {
122
+ const h = eh;
123
+ const heuristics = {};
124
+ const numFields = [
125
+ 'strategy_steps', 'avoid_count', 'validation_declared_count', 'validation_runnable_count',
126
+ 'signals_extracted', 'preconditions_extracted', 'trajectory_depth',
127
+ ];
128
+ for (const k of numFields) {
129
+ const v = h[k];
130
+ if (typeof v === 'number' && Number.isFinite(v))
131
+ heuristics[k] = v;
132
+ }
133
+ if (typeof h['has_corrective_insight'] === 'boolean')
134
+ heuristics.has_corrective_insight = h['has_corrective_insight'];
135
+ if (Object.keys(heuristics).length > 0)
136
+ out.quality_heuristics = heuristics;
137
+ }
138
+ const errs = cleanToolList(r['overcame_errors']);
139
+ if (errs)
140
+ out.overcame_errors = errs;
141
+ return out;
142
+ }
92
143
  /** Strip the v2-delta hint fields from a gene-shaped object (used to validate the gep-sdk-known core). */
93
144
  export function stripGeneHints(gene) {
94
145
  const hidden = GENE_HINT_FIELDS;
@@ -2,12 +2,18 @@
2
2
  * 资产 wire 层. SSOT = @evomap/gep-sdk/schemas/*.schema.json (D19).
3
3
  * 字段一律 snake_case 锁定 (asset_id 跨实现契约); 本仓不发明 wire 字段, 只镜像 + 重导出工具.
4
4
  */
5
- import type { GeneRoutingHint, GeneToolPolicy } from './geneHints.js';
5
+ import type { GeneRoutingHint, GeneToolPolicy, GenerationMeta } from './geneHints.js';
6
6
  export { SCHEMA_VERSION, canonicalize, computeAssetId, verifyAssetId } from '@evomap/gep-sdk';
7
7
  export type GepCategory = typeof import('@evomap/gep-sdk').GEP_GENE_CATEGORIES[number];
8
8
  export type OutcomeStatus = typeof import('@evomap/gep-sdk').GEP_OUTCOME_STATUSES[number];
9
9
  export type SourceType = typeof import('@evomap/gep-sdk').GEP_SOURCE_TYPES[number];
10
10
  export type RiskLevel = typeof import('@evomap/gep-sdk').GEP_RISK_LEVELS[number];
11
+ export type CapsuleVisibility = typeof import('@evomap/gep-sdk').GEP_CAPSULE_VISIBILITIES[number];
12
+ export type CapsuleCostTier = typeof import('@evomap/gep-sdk').GEP_CAPSULE_COST_TIERS[number];
13
+ export interface CapsuleAuthor {
14
+ handle: string;
15
+ evox_install_id: string;
16
+ }
11
17
  /** Gene = 基因型/方法论 (gene.schema.json). */
12
18
  export interface Gene {
13
19
  type: 'Gene';
@@ -28,6 +34,7 @@ export interface Gene {
28
34
  anti_patterns?: unknown[];
29
35
  routing_hint?: GeneRoutingHint | null;
30
36
  tool_policy?: GeneToolPolicy | null;
37
+ generation_meta?: GenerationMeta | null;
31
38
  asset_id: string;
32
39
  }
33
40
  /** Capsule = 表现型/纯进化产物 (capsule.schema.json). */
@@ -49,6 +56,11 @@ export interface Capsule {
49
56
  };
50
57
  resolution_status?: 'pending' | 'suppressed_observationally' | 'resolved_by_evidence' | 'regressed' | 'inconclusive';
51
58
  proof_of_work?: unknown;
59
+ visibility?: CapsuleVisibility | null;
60
+ scope?: string[] | null;
61
+ cost_tier?: CapsuleCostTier | null;
62
+ pack_of?: string[] | null;
63
+ author?: CapsuleAuthor | null;
52
64
  execution_trace?: unknown[];
53
65
  trigger_context?: unknown;
54
66
  asset_id: string;
@@ -88,4 +100,4 @@ export interface Mutation {
88
100
  risk_level: RiskLevel;
89
101
  }
90
102
  export { validateWire, schemaProperties, type WireValidation } from './schemaGate.js';
91
- export { ROUTING_TIERS, REASONING_LEVELS, TOOL_POLICY_SEVERITIES, GENE_HINT_FIELDS, normalizeRoutingHint, normalizeToolPolicy, stripGeneHints, type RoutingTier, type ReasoningLevel, type ToolPolicySeverity, type GeneRoutingHint, type GeneToolPolicy, } from './geneHints.js';
103
+ export { ROUTING_TIERS, REASONING_LEVELS, TOOL_POLICY_SEVERITIES, GENERATION_SOURCES, GENE_HINT_FIELDS, normalizeRoutingHint, normalizeToolPolicy, normalizeGenerationMeta, stripGeneHints, type RoutingTier, type ReasoningLevel, type ToolPolicySeverity, type GenerationSource, type GeneRoutingHint, type GeneToolPolicy, type GeneGenerationHeuristics, type GenerationMeta, } from './geneHints.js';
@@ -1,3 +1,3 @@
1
1
  export { SCHEMA_VERSION, canonicalize, computeAssetId, verifyAssetId } from '@evomap/gep-sdk';
2
2
  export { validateWire, schemaProperties } from './schemaGate.js';
3
- export { ROUTING_TIERS, REASONING_LEVELS, TOOL_POLICY_SEVERITIES, GENE_HINT_FIELDS, normalizeRoutingHint, normalizeToolPolicy, stripGeneHints, } from './geneHints.js';
3
+ export { ROUTING_TIERS, REASONING_LEVELS, TOOL_POLICY_SEVERITIES, GENERATION_SOURCES, GENE_HINT_FIELDS, normalizeRoutingHint, normalizeToolPolicy, normalizeGenerationMeta, stripGeneHints, } from './geneHints.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evomap/evolver-core",
3
- "version": "2.0.0-beta.1",
3
+ "version": "2.0.0-beta.3",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "hub-无关核心: 算法引擎/原材料/mailbox/资产库/workflow",
@@ -17,12 +17,17 @@
17
17
  "zod": "^3.24.1",
18
18
  "ulid": "^2.3.0"
19
19
  },
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/EvoMap/evolver.git"
23
+ },
20
24
  "publishConfig": {
21
25
  "access": "public",
22
26
  "tag": "v2-beta"
23
27
  },
24
28
  "files": [
25
29
  "dist/",
30
+ "assets/",
26
31
  "README.md",
27
32
  "package.json"
28
33
  ]