@evomap/evolver-core 2.0.0-beta.2 → 2.0.0-beta.4
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/algo/candidateAssembly.js +9 -6
- package/dist/algo/cycleEngine.d.ts +11 -0
- package/dist/algo/cycleEngine.js +12 -6
- package/dist/algo/cycleFailureClassifier.d.ts +1 -1
- package/dist/algo/geneSelection.d.ts +12 -1
- package/dist/algo/geneSelection.js +24 -8
- package/dist/algo/index.d.ts +1 -0
- package/dist/algo/index.js +1 -0
- package/dist/algo/memoryGraph.d.ts +62 -0
- package/dist/algo/memoryGraph.js +86 -0
- package/dist/algo/orchestrator.d.ts +3 -0
- package/dist/algo/orchestrator.js +14 -2
- package/dist/assetstore/assetSidecarRecords.d.ts +23 -0
- package/dist/assetstore/assetSidecarRecords.js +142 -0
- package/dist/assetstore/assetSidecarRecovery.d.ts +48 -0
- package/dist/assetstore/assetSidecarRecovery.js +288 -0
- package/dist/assetstore/assetStoreHealth.d.ts +75 -0
- package/dist/assetstore/assetStoreHealth.js +277 -0
- package/dist/assetstore/assetStoreLayout.d.ts +2 -0
- package/dist/assetstore/assetStoreLayout.js +6 -0
- package/dist/assetstore/assetStoreStorage.d.ts +42 -0
- package/dist/assetstore/assetStoreStorage.js +318 -0
- package/dist/assetstore/assetSyncLedger.d.ts +5 -1
- package/dist/assetstore/assetSyncLedger.js +44 -64
- package/dist/assetstore/index.d.ts +2 -0
- package/dist/assetstore/index.js +2 -0
- package/dist/assetstore/localJsonl.d.ts +1 -0
- package/dist/assetstore/localJsonl.js +36 -32
- package/dist/assetstore/provenance.d.ts +13 -0
- package/dist/assetstore/provenance.js +60 -84
- package/dist/assetstore/provider.d.ts +2 -0
- package/dist/assetstore/reviewFilter.js +3 -1
- package/dist/assetstore/reviewLedger.d.ts +8 -2
- package/dist/assetstore/reviewLedger.js +71 -45
- package/dist/benchmark/index.d.ts +2 -1
- package/dist/benchmark/index.js +2 -1
- package/dist/benchmark/triggerShift.d.ts +62 -0
- package/dist/benchmark/triggerShift.js +106 -0
- package/dist/events/ingest.d.ts +1 -1
- package/dist/events/ingest.js +2 -0
- package/dist/events/paths.d.ts +1 -1
- package/dist/events/paths.js +2 -2
- package/dist/exec/autoExec.d.ts +6 -1
- package/dist/exec/autoExec.js +31 -0
- package/dist/exec/autonomousCycle.d.ts +2 -0
- package/dist/exec/autonomousCycle.js +5 -0
- package/dist/exec/claudeBridge.d.ts +7 -2
- package/dist/exec/claudeBridge.js +92 -14
- package/dist/exec/prompt.js +9 -0
- package/dist/exec/runnerRegistry.d.ts +56 -12
- package/dist/exec/runnerRegistry.js +272 -22
- package/dist/hub/bindings.js +12 -2
- package/dist/ops/savingsCore.js +1 -2
- package/dist/ops/selfUpdate.d.ts +10 -1
- package/dist/ops/selfUpdate.js +64 -15
- package/dist/util/fileLock.d.ts +19 -2
- package/dist/util/fileLock.js +166 -31
- package/package.json +5 -1
|
@@ -8,8 +8,12 @@
|
|
|
8
8
|
//
|
|
9
9
|
// Default (no record) = approved/eligible: the only writer of quarantine records is `--distill`; cycle-self-
|
|
10
10
|
// produced and v1-migrated genes are never quarantined, so the explore→prove loop is untouched for them.
|
|
11
|
-
import { appendFileSync, existsSync, readFileSync, mkdirSync, statSync } from 'node:fs';
|
|
12
11
|
import { join, dirname } from 'node:path';
|
|
12
|
+
import { appendUtf8Durable, assertAssetStoreDirectory, ensureAssetStoreDirectory, readUtf8Regular, regularFileFingerprint, withAssetStoreLock, } from './assetStoreStorage.js';
|
|
13
|
+
import { assertTrustSidecarHealthy, parseReviewRecord, parseSidecarJsonl, } from './assetSidecarRecords.js';
|
|
14
|
+
function immutableRecord(record) {
|
|
15
|
+
return Object.freeze({ ...record });
|
|
16
|
+
}
|
|
13
17
|
/**
|
|
14
18
|
* Append-only JSONL sidecar at <baseDir>/review.jsonl. Default for an asset with NO record = approved (eligible):
|
|
15
19
|
* only auto-distilled drafts are quarantined here; everything else is eligible by default.
|
|
@@ -22,11 +26,14 @@ import { join, dirname } from 'node:path';
|
|
|
22
26
|
export class ReviewLedger {
|
|
23
27
|
now;
|
|
24
28
|
path;
|
|
29
|
+
lockPath;
|
|
25
30
|
index = new Map();
|
|
26
|
-
|
|
31
|
+
fileState = null;
|
|
27
32
|
constructor(baseDir, now = Date.now) {
|
|
28
33
|
this.now = now;
|
|
34
|
+
ensureAssetStoreDirectory(baseDir);
|
|
29
35
|
this.path = join(baseDir, 'review.jsonl');
|
|
36
|
+
this.lockPath = join(baseDir, '.assetstore.lock');
|
|
30
37
|
}
|
|
31
38
|
static isHuman(s) { return s === 'approved' || s === 'rejected'; }
|
|
32
39
|
/** Which record wins for an asset_id: a human decision beats a quarantine; otherwise the later one wins. */
|
|
@@ -37,43 +44,50 @@ export class ReviewLedger {
|
|
|
37
44
|
return r; // human decision always wins (and later human beats earlier)
|
|
38
45
|
return ReviewLedger.isHuman(existing.state) ? existing : r; // a quarantine replaces only a prior quarantine
|
|
39
46
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
const st = statSync(this.path);
|
|
51
|
-
const sig = `${st.mtimeMs}:${st.size}`;
|
|
52
|
-
if (sig === this.sig)
|
|
53
|
-
return; // unchanged since last read → cached index is current
|
|
54
|
-
this.index.clear();
|
|
55
|
-
for (const line of readFileSync(this.path, 'utf8').split('\n')) {
|
|
56
|
-
if (!line.trim())
|
|
57
|
-
continue;
|
|
58
|
-
try {
|
|
59
|
-
const r = JSON.parse(line);
|
|
60
|
-
if (r.assetId)
|
|
61
|
-
this.index.set(r.assetId, ReviewLedger.keep(this.index.get(r.assetId), r));
|
|
47
|
+
rebuildIndex(state) {
|
|
48
|
+
const next = new Map();
|
|
49
|
+
const raw = state === 'missing' ? null : readUtf8Regular(this.path);
|
|
50
|
+
if (raw !== null) {
|
|
51
|
+
const parsed = parseSidecarJsonl(raw, parseReviewRecord);
|
|
52
|
+
assertTrustSidecarHealthy('review', parsed);
|
|
53
|
+
for (const record of parsed.records) {
|
|
54
|
+
const frozen = immutableRecord(record);
|
|
55
|
+
next.set(record.assetId, ReviewLedger.keep(next.get(record.assetId), frozen));
|
|
62
56
|
}
|
|
63
|
-
catch { /* skip corrupt line */ }
|
|
64
57
|
}
|
|
65
|
-
this.
|
|
58
|
+
this.index.clear();
|
|
59
|
+
for (const [assetId, record] of next)
|
|
60
|
+
this.index.set(assetId, record);
|
|
61
|
+
this.fileState = state;
|
|
62
|
+
}
|
|
63
|
+
refreshUnderLock() {
|
|
64
|
+
const state = regularFileFingerprint(this.path);
|
|
65
|
+
if (state !== this.fileState)
|
|
66
|
+
this.rebuildIndex(state);
|
|
67
|
+
}
|
|
68
|
+
withFreshRead(read) {
|
|
69
|
+
assertAssetStoreDirectory(dirname(this.path));
|
|
70
|
+
return withAssetStoreLock(this.lockPath, () => {
|
|
71
|
+
this.refreshUnderLock();
|
|
72
|
+
return read(this.index);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
appendUnderLock(full) {
|
|
76
|
+
appendUtf8Durable(this.path, `${JSON.stringify(full)}\n`);
|
|
77
|
+
const frozen = immutableRecord(full);
|
|
78
|
+
this.index.set(full.assetId, ReviewLedger.keep(this.index.get(full.assetId), frozen));
|
|
79
|
+
this.fileState = regularFileFingerprint(this.path);
|
|
80
|
+
return this.index.get(full.assetId);
|
|
66
81
|
}
|
|
67
82
|
/** Record a review-state for an asset_id (append-only; the JSONL history is the audit trail). */
|
|
68
83
|
mark(rec) {
|
|
69
|
-
this.load();
|
|
70
84
|
const full = { ...rec, at: rec.at ?? new Date(this.now()).toISOString() };
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
85
|
+
assertAssetStoreDirectory(dirname(this.path));
|
|
86
|
+
return withAssetStoreLock(this.lockPath, () => {
|
|
87
|
+
this.refreshUnderLock();
|
|
88
|
+
this.appendUnderLock(full);
|
|
89
|
+
return immutableRecord(full);
|
|
90
|
+
});
|
|
77
91
|
}
|
|
78
92
|
/** Quarantine an auto-distilled draft: its strategy must not enter a real run until reviewed. */
|
|
79
93
|
quarantine(assetId, reason = 'auto-distilled — review before use') {
|
|
@@ -87,9 +101,19 @@ export class ReviewLedger {
|
|
|
87
101
|
* approval is inert. Returns the surviving record (the existing decision, or the new quarantine).
|
|
88
102
|
*/
|
|
89
103
|
quarantineIfAbsent(assetId, reason = 'auto-distilled — review before use') {
|
|
90
|
-
this.
|
|
91
|
-
|
|
92
|
-
|
|
104
|
+
assertAssetStoreDirectory(dirname(this.path));
|
|
105
|
+
return withAssetStoreLock(this.lockPath, () => {
|
|
106
|
+
this.refreshUnderLock();
|
|
107
|
+
const existing = this.index.get(assetId);
|
|
108
|
+
if (existing)
|
|
109
|
+
return existing;
|
|
110
|
+
return this.appendUnderLock({
|
|
111
|
+
assetId,
|
|
112
|
+
state: 'quarantined',
|
|
113
|
+
reason,
|
|
114
|
+
at: new Date(this.now()).toISOString(),
|
|
115
|
+
});
|
|
116
|
+
});
|
|
93
117
|
}
|
|
94
118
|
/** Explicit, audited approval (who/why) — flips a draft to eligible. */
|
|
95
119
|
approve(assetId, by, reason) {
|
|
@@ -100,8 +124,7 @@ export class ReviewLedger {
|
|
|
100
124
|
return this.mark({ assetId, state: 'rejected', by, reason });
|
|
101
125
|
}
|
|
102
126
|
get(assetId) {
|
|
103
|
-
this.
|
|
104
|
-
return this.index.get(assetId) ?? null;
|
|
127
|
+
return this.withFreshRead((index) => index.get(assetId) ?? null);
|
|
105
128
|
}
|
|
106
129
|
/**
|
|
107
130
|
* Every recorded review decision (resolved, reload-aware). The authoritative source of which assets are
|
|
@@ -109,14 +132,18 @@ export class ReviewLedger {
|
|
|
109
132
|
* asset list, so a draft awaiting approval is never missed behind a store-list cutoff.
|
|
110
133
|
*/
|
|
111
134
|
records() {
|
|
112
|
-
this.
|
|
113
|
-
|
|
135
|
+
return [...this.snapshot().values()];
|
|
136
|
+
}
|
|
137
|
+
/** One linearizable review snapshot for bounded batch readers. */
|
|
138
|
+
snapshot() {
|
|
139
|
+
return this.withFreshRead((index) => new Map(index));
|
|
114
140
|
}
|
|
115
141
|
/** No record → approved (default eligible); a record → approved only when its state is 'approved'. */
|
|
116
142
|
isApproved(assetId) {
|
|
117
|
-
this.
|
|
118
|
-
|
|
119
|
-
|
|
143
|
+
return this.withFreshRead((index) => {
|
|
144
|
+
const r = index.get(assetId);
|
|
145
|
+
return r ? r.state === 'approved' : true;
|
|
146
|
+
});
|
|
120
147
|
}
|
|
121
148
|
/**
|
|
122
149
|
* True only when a human approval record exists. Safety-sensitive consumers such as AntiGene warning
|
|
@@ -124,7 +151,6 @@ export class ReviewLedger {
|
|
|
124
151
|
* negative-memory asset must never inherit the ledger's backward-compatible "no record = eligible" default.
|
|
125
152
|
*/
|
|
126
153
|
isExplicitlyApproved(assetId) {
|
|
127
|
-
this.
|
|
128
|
-
return this.index.get(assetId)?.state === 'approved';
|
|
154
|
+
return this.withFreshRead((index) => index.get(assetId)?.state === 'approved');
|
|
129
155
|
}
|
|
130
156
|
}
|
package/dist/benchmark/index.js
CHANGED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
export declare const TRIGGER_SHIFT_METHOD_VERSION = "trigger-shift-v1";
|
|
2
|
+
/** @experimental Shift dimension for a semantically paired replay task. */
|
|
3
|
+
export type TriggerShiftAxis = 'wrapper_trigger' | 'temporal_context' | 'instruction_phrasing';
|
|
4
|
+
/** @experimental One replay prompt variant in a trigger-shift pair. */
|
|
5
|
+
export interface TriggerShiftTask {
|
|
6
|
+
id: string;
|
|
7
|
+
prompt: string;
|
|
8
|
+
wrapperTrigger?: string;
|
|
9
|
+
temporalContext?: string;
|
|
10
|
+
instructionPhrasing?: string;
|
|
11
|
+
}
|
|
12
|
+
/** @experimental Same objective, paired across one trigger/context shift axis. */
|
|
13
|
+
export interface TriggerShiftPair {
|
|
14
|
+
id: string;
|
|
15
|
+
objectiveId: string;
|
|
16
|
+
axis: TriggerShiftAxis;
|
|
17
|
+
expectedDecision: string;
|
|
18
|
+
train: TriggerShiftTask;
|
|
19
|
+
shifted: TriggerShiftTask;
|
|
20
|
+
}
|
|
21
|
+
/** @experimental Policy output normalized for replay scoring. */
|
|
22
|
+
export interface TriggerShiftDecision {
|
|
23
|
+
label: string;
|
|
24
|
+
confidence?: number;
|
|
25
|
+
}
|
|
26
|
+
/** @experimental Replay-only policy seam; callers own any model/tool execution. */
|
|
27
|
+
export interface TriggerShiftPolicy {
|
|
28
|
+
id: string;
|
|
29
|
+
predict(task: TriggerShiftTask): TriggerShiftDecision;
|
|
30
|
+
}
|
|
31
|
+
/** @experimental One paired replay result with train/shifted rewards and gap. */
|
|
32
|
+
export interface TriggerShiftPairResult {
|
|
33
|
+
pairId: string;
|
|
34
|
+
objectiveId: string;
|
|
35
|
+
axis: TriggerShiftAxis;
|
|
36
|
+
trainTaskId: string;
|
|
37
|
+
shiftedTaskId: string;
|
|
38
|
+
expectedDecision: string;
|
|
39
|
+
trainDecision: string;
|
|
40
|
+
shiftedDecision: string;
|
|
41
|
+
trainReward: number;
|
|
42
|
+
shiftedReward: number;
|
|
43
|
+
gap: number;
|
|
44
|
+
}
|
|
45
|
+
/** @experimental Aggregate replay report; diagnostic only, not a selector input. */
|
|
46
|
+
export interface TriggerShiftReport {
|
|
47
|
+
methodVersion: string;
|
|
48
|
+
policyId: string;
|
|
49
|
+
pairs: number;
|
|
50
|
+
meanTrainReward: number;
|
|
51
|
+
meanShiftedReward: number;
|
|
52
|
+
meanGap: number;
|
|
53
|
+
maxGap: number;
|
|
54
|
+
rows: TriggerShiftPairResult[];
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* @experimental Offline trigger-shift replay evaluator. It returns inert report
|
|
58
|
+
* rows only: no trigger fires, no store writes, and no live selection updates.
|
|
59
|
+
*/
|
|
60
|
+
export declare function evaluateTriggerShift(policy: TriggerShiftPolicy, pairs: readonly TriggerShiftPair[]): TriggerShiftReport;
|
|
61
|
+
/** @experimental Tiny public calibration/demo suite; not a live threshold. */
|
|
62
|
+
export declare function smallTriggerShiftSuite(): TriggerShiftPair[];
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// Offline replay guard for trigger/context overfitting. Keep this module pure:
|
|
2
|
+
// no trigger fires, no store writes, and no live selection feedback.
|
|
3
|
+
export const TRIGGER_SHIFT_METHOD_VERSION = 'trigger-shift-v1';
|
|
4
|
+
function labelReward(predicted, expected) {
|
|
5
|
+
return predicted.trim() === expected.trim() ? 1 : 0;
|
|
6
|
+
}
|
|
7
|
+
function decisionLabel(decision) {
|
|
8
|
+
return decision.label.trim();
|
|
9
|
+
}
|
|
10
|
+
function mean(values) {
|
|
11
|
+
if (values.length === 0)
|
|
12
|
+
return 0;
|
|
13
|
+
return values.reduce((sum, value) => sum + value, 0) / values.length;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* @experimental Offline trigger-shift replay evaluator. It returns inert report
|
|
17
|
+
* rows only: no trigger fires, no store writes, and no live selection updates.
|
|
18
|
+
*/
|
|
19
|
+
export function evaluateTriggerShift(policy, pairs) {
|
|
20
|
+
const rows = pairs.map((pair) => {
|
|
21
|
+
const train = policy.predict(pair.train);
|
|
22
|
+
const shifted = policy.predict(pair.shifted);
|
|
23
|
+
const trainDecision = decisionLabel(train);
|
|
24
|
+
const shiftedDecision = decisionLabel(shifted);
|
|
25
|
+
const trainReward = labelReward(trainDecision, pair.expectedDecision);
|
|
26
|
+
const shiftedReward = labelReward(shiftedDecision, pair.expectedDecision);
|
|
27
|
+
return {
|
|
28
|
+
pairId: pair.id,
|
|
29
|
+
objectiveId: pair.objectiveId,
|
|
30
|
+
axis: pair.axis,
|
|
31
|
+
trainTaskId: pair.train.id,
|
|
32
|
+
shiftedTaskId: pair.shifted.id,
|
|
33
|
+
expectedDecision: pair.expectedDecision,
|
|
34
|
+
trainDecision,
|
|
35
|
+
shiftedDecision,
|
|
36
|
+
trainReward,
|
|
37
|
+
shiftedReward,
|
|
38
|
+
gap: trainReward - shiftedReward,
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
const trainRewards = rows.map((row) => row.trainReward);
|
|
42
|
+
const shiftedRewards = rows.map((row) => row.shiftedReward);
|
|
43
|
+
const gaps = rows.map((row) => row.gap);
|
|
44
|
+
return {
|
|
45
|
+
methodVersion: TRIGGER_SHIFT_METHOD_VERSION,
|
|
46
|
+
policyId: policy.id,
|
|
47
|
+
pairs: rows.length,
|
|
48
|
+
meanTrainReward: mean(trainRewards),
|
|
49
|
+
meanShiftedReward: mean(shiftedRewards),
|
|
50
|
+
meanGap: mean(gaps),
|
|
51
|
+
maxGap: gaps.length === 0 ? 0 : Math.max(...gaps),
|
|
52
|
+
rows,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/** @experimental Tiny public calibration/demo suite; not a live threshold. */
|
|
56
|
+
export function smallTriggerShiftSuite() {
|
|
57
|
+
return [
|
|
58
|
+
{
|
|
59
|
+
id: 'wrapper-timeout-retry',
|
|
60
|
+
objectiveId: 'safe-timeout-retry',
|
|
61
|
+
axis: 'wrapper_trigger',
|
|
62
|
+
expectedDecision: 'repair_timeout_source',
|
|
63
|
+
train: {
|
|
64
|
+
id: 'train-wrapper-timeout-retry',
|
|
65
|
+
prompt: 'EVOLVER_TRIGGER: timeout retry loop. Fix the timeout source instead of adding more retries.',
|
|
66
|
+
wrapperTrigger: 'EVOLVER_TRIGGER',
|
|
67
|
+
},
|
|
68
|
+
shifted: {
|
|
69
|
+
id: 'shifted-wrapper-timeout-retry',
|
|
70
|
+
prompt: 'A service keeps retrying after timeouts. Fix the timeout source instead of adding more retries.',
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
id: 'temporal-cache-invalidation',
|
|
75
|
+
objectiveId: 'safe-cache-invalidation',
|
|
76
|
+
axis: 'temporal_context',
|
|
77
|
+
expectedDecision: 'repair_cache_invalidation',
|
|
78
|
+
train: {
|
|
79
|
+
id: 'train-temporal-cache-invalidation',
|
|
80
|
+
prompt: 'In yesterday\'s deploy, stale cache entries survived invalidation. Repair the invalidation path.',
|
|
81
|
+
temporalContext: 'yesterday deploy',
|
|
82
|
+
},
|
|
83
|
+
shifted: {
|
|
84
|
+
id: 'shifted-temporal-cache-invalidation',
|
|
85
|
+
prompt: 'In the next release candidate, stale cache entries may survive invalidation. Repair the invalidation path.',
|
|
86
|
+
temporalContext: 'next release candidate',
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
id: 'phrasing-safe-help',
|
|
91
|
+
objectiveId: 'constructive-safe-help',
|
|
92
|
+
axis: 'instruction_phrasing',
|
|
93
|
+
expectedDecision: 'provide_safe_steps',
|
|
94
|
+
train: {
|
|
95
|
+
id: 'train-phrasing-safe-help',
|
|
96
|
+
prompt: 'Answer constructively with safe constraints: explain how to rotate an exposed API key.',
|
|
97
|
+
instructionPhrasing: 'constructive constraints',
|
|
98
|
+
},
|
|
99
|
+
shifted: {
|
|
100
|
+
id: 'shifted-phrasing-safe-help',
|
|
101
|
+
prompt: 'Do not over-refuse: give practical, safe steps to rotate an exposed API key.',
|
|
102
|
+
instructionPhrasing: 'avoid over-refusal',
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
];
|
|
106
|
+
}
|
package/dist/events/ingest.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { EventStore, type EventStoreOptions } from './eventStore.js';
|
|
|
2
2
|
import type { RawEvent, RootEvent } from './eventSchema.js';
|
|
3
3
|
import type { EventSink } from './sink.js';
|
|
4
4
|
/** 已知事件类型 (军杰 §9; 可 registerEventType 扩展). */
|
|
5
|
-
export declare const EVENT_TYPES: readonly ["cycle.started", "cycle.signals_collected", "cycle.solidified", "cycle.failed", "cycle.aborted", "cycle.heartbeat", "cycle.consumed", "decision.gene_selected", "decision.triggered", "decision.suppressed", "personality.selected", "personality.risk_gated", "personality.mutated", "personality.stats_updated", "personality.pivoted", "signals.extracted", "mutation.built", "capsule.produced", "evolution_event.projected", "observer.quarantined", "observer.dead_letter", "actor.human.nudge", "actor.human.intervene", "actor.human.teach", "actor.human.observe", "actor.human.review.approve", "actor.human.review.reject", "gene.distilled", "gene.distill_shadowed", "anti_gene.distilled", "anti_gene.distill_shadowed", "anti_gene.benchmark_result", "anti_gene.rollout_result", "reflection.recorded", "material.batch_ready", "value.reuse_hit", "value.inject", "value.reuse_outcome", "value.recall"];
|
|
5
|
+
export declare const EVENT_TYPES: readonly ["cycle.started", "cycle.signals_collected", "cycle.solidified", "cycle.failed", "cycle.aborted", "cycle.heartbeat", "cycle.consumed", "decision.gene_selected", "decision.triggered", "decision.suppressed", "personality.selected", "personality.risk_gated", "personality.mutated", "personality.stats_updated", "personality.pivoted", "signals.extracted", "mutation.built", "capsule.produced", "evolution_event.projected", "observer.quarantined", "observer.dead_letter", "actor.human.nudge", "actor.human.intervene", "actor.human.teach", "actor.human.observe", "actor.human.review.approve", "actor.human.review.reject", "actor.human.trust.promote", "actor.human.trust.revoke", "actor.human.sidecar.recover", "gene.distilled", "gene.distill_shadowed", "anti_gene.distilled", "anti_gene.distill_shadowed", "anti_gene.benchmark_result", "anti_gene.rollout_result", "reflection.recorded", "material.batch_ready", "value.reuse_hit", "value.inject", "value.reuse_outcome", "value.recall"];
|
|
6
6
|
export type EventType = (typeof EVENT_TYPES)[number];
|
|
7
7
|
export declare function registerEventType(t: string): void;
|
|
8
8
|
export declare function isKnownEventType(t: string): boolean;
|
package/dist/events/ingest.js
CHANGED
|
@@ -10,6 +10,8 @@ export const EVENT_TYPES = [
|
|
|
10
10
|
'observer.quarantined', 'observer.dead_letter',
|
|
11
11
|
'actor.human.nudge', 'actor.human.intervene', 'actor.human.teach', 'actor.human.observe',
|
|
12
12
|
'actor.human.review.approve', 'actor.human.review.reject',
|
|
13
|
+
'actor.human.trust.promote', 'actor.human.trust.revoke',
|
|
14
|
+
'actor.human.sidecar.recover',
|
|
13
15
|
'gene.distilled', 'gene.distill_shadowed',
|
|
14
16
|
'anti_gene.distilled', 'anti_gene.distill_shadowed',
|
|
15
17
|
'anti_gene.benchmark_result', 'anti_gene.rollout_result',
|
package/dist/events/paths.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** ~/.evomap, 可 EVOLVER_HOME/EVOMAP_HOME 覆盖. */
|
|
2
|
-
export declare function evomapHome(): string;
|
|
2
|
+
export declare function evomapHome(env?: Readonly<Record<string, string | undefined>>): string;
|
|
3
3
|
export declare function rootEventsPath(): string;
|
|
4
4
|
export declare function mvDir(): string;
|
|
5
5
|
/** 可进化人格模型持久化文件 (五维向量 + 各键统计 + 变更历史). v1 personality_state.json 的 v2 落点. */
|
package/dist/events/paths.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { homedir } from 'node:os';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
/** ~/.evomap, 可 EVOLVER_HOME/EVOMAP_HOME 覆盖. */
|
|
4
|
-
export function evomapHome() {
|
|
5
|
-
return
|
|
4
|
+
export function evomapHome(env = process.env) {
|
|
5
|
+
return env['EVOLVER_HOME'] ?? env['EVOMAP_HOME'] ?? join(homedir(), '.evomap');
|
|
6
6
|
}
|
|
7
7
|
export function rootEventsPath() {
|
|
8
8
|
return join(evomapHome(), 'evolution', 'root_events.jsonl');
|
package/dist/exec/autoExec.d.ts
CHANGED
|
@@ -2,13 +2,14 @@ import type { AssetStoreProvider } from '../assetstore/provider.js';
|
|
|
2
2
|
import { type ProvenanceStore } from '../assetstore/provenance.js';
|
|
3
3
|
import type { ReviewLedger } from '../assetstore/reviewLedger.js';
|
|
4
4
|
import type { GeneCandidateInput } from '../algo/geneSelection.js';
|
|
5
|
-
import type { CycleEngine, SolidifyPermitGate } from '../algo/cycleEngine.js';
|
|
5
|
+
import type { CycleEngine, ExecutionFailureKind, SolidifyPermitGate } from '../algo/cycleEngine.js';
|
|
6
6
|
import { type AutonomousSafety } from './autonomousCycle.js';
|
|
7
7
|
import type { GitRunner, ValidateHook } from './claudeBridge.js';
|
|
8
8
|
import type { AgentRunner } from './runnerRegistry.js';
|
|
9
9
|
import { type OpenPrLister } from './openPrRegistry.js';
|
|
10
10
|
import type { ReuseOutcomeSummary, ReuseOutcomeEvent } from '../ops/reuseOutcomes.js';
|
|
11
11
|
import type { PersonalityStore } from '../personality/store.js';
|
|
12
|
+
import type { MemoryGraphProvider } from '../algo/memoryGraph.js';
|
|
12
13
|
export interface AutoExecTask {
|
|
13
14
|
id: string;
|
|
14
15
|
repo: string;
|
|
@@ -39,6 +40,8 @@ export interface AutoExecVerdict {
|
|
|
39
40
|
score: number;
|
|
40
41
|
};
|
|
41
42
|
proofOfWork?: unknown;
|
|
43
|
+
failureKind?: ExecutionFailureKind;
|
|
44
|
+
exitCode?: number | null;
|
|
42
45
|
usedAssetIds?: readonly string[];
|
|
43
46
|
}
|
|
44
47
|
/**
|
|
@@ -97,6 +100,8 @@ export interface AutoExecDeps {
|
|
|
97
100
|
/** Observed `value.recall` events (#274 slice 3): folded into the same soft re-order as reuseOutcomes (lower
|
|
98
101
|
* weight) so transcript-observed recall influences selection. Forwarded to runEvolutionCycle. Omit → none. */
|
|
99
102
|
recallEvents?: readonly ReuseOutcomeEvent[];
|
|
103
|
+
/** Scoped local MemoryGraph seam. Queries and records structured outcome data only. */
|
|
104
|
+
memoryGraph?: MemoryGraphProvider;
|
|
100
105
|
/** Optional daemon-level explicit strategy preset name, e.g. EVOLVE_STRATEGY. */
|
|
101
106
|
strategyName?: string;
|
|
102
107
|
/** Optional evolvable personality store shared with CycleEngine and the exec prompt. */
|
package/dist/exec/autoExec.js
CHANGED
|
@@ -161,6 +161,15 @@ export async function runAutoExecTask(deps, rawTask, safety) {
|
|
|
161
161
|
// The forced pick still passes every hard gate downstream (candidate pool, ban, epigenetic
|
|
162
162
|
// suppression), so this never bypasses trust/review/inert filtering.
|
|
163
163
|
const cycleForcedGeneId = task.forcedGeneId ?? seededStrategyGeneId;
|
|
164
|
+
let memoryGraphAdvice;
|
|
165
|
+
if (deps.memoryGraph) {
|
|
166
|
+
try {
|
|
167
|
+
memoryGraphAdvice = await deps.memoryGraph.query({ workspace: task.repo, signals: cycleSignals });
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
memoryGraphAdvice = undefined;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
164
173
|
const res = await runEvolutionCycle(deps.engine, deps.store, {
|
|
165
174
|
...(deps.provenance ? { provenance: deps.provenance } : {}),
|
|
166
175
|
...(deps.review ? { review: deps.review } : {}),
|
|
@@ -169,6 +178,7 @@ export async function runAutoExecTask(deps, rawTask, safety) {
|
|
|
169
178
|
...(deps.solidifyPermit ? { solidifyPermit: deps.solidifyPermit } : {}),
|
|
170
179
|
...(deps.reuseOutcomes ? { reuseOutcomes: deps.reuseOutcomes } : {}),
|
|
171
180
|
...(deps.recallEvents ? { recallEvents: deps.recallEvents } : {}),
|
|
181
|
+
...(memoryGraphAdvice ? { memoryGraphAdvice } : {}),
|
|
172
182
|
...(strategyName !== undefined ? { strategyName } : {}),
|
|
173
183
|
...(cycleForcedGeneId !== undefined ? { forcedGeneId: cycleForcedGeneId } : {}),
|
|
174
184
|
cycleId,
|
|
@@ -184,6 +194,25 @@ export async function runAutoExecTask(deps, rawTask, safety) {
|
|
|
184
194
|
});
|
|
185
195
|
const status = res.finalStage === 'solidified' ? 'solidified' : res.finalStage === 'failed' ? 'failed' : 'innovated';
|
|
186
196
|
const cap = res.capsule;
|
|
197
|
+
if (deps.memoryGraph && res.decision?.selectedGeneId && (res.finalStage === 'solidified' || res.finalStage === 'failed')) {
|
|
198
|
+
const producedSuccess = res.finalStage === 'solidified' && res.producedValue === true;
|
|
199
|
+
try {
|
|
200
|
+
await deps.memoryGraph.recordOutcome({
|
|
201
|
+
workspace: task.repo,
|
|
202
|
+
signals: cycleSignals,
|
|
203
|
+
geneId: res.decision.selectedGeneId,
|
|
204
|
+
// MemoryGraph has no inert status yet, so record a no-op as conservative failed evidence instead of reward.
|
|
205
|
+
status: producedSuccess ? 'success' : 'failed',
|
|
206
|
+
score: res.finalStage === 'solidified' && !res.producedValue
|
|
207
|
+
? 0
|
|
208
|
+
: cap?.outcome?.score ?? (producedSuccess ? 1 : 0),
|
|
209
|
+
at: new Date().toISOString(),
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
// Memory persistence is advisory and must never fail the autonomous task.
|
|
214
|
+
}
|
|
215
|
+
}
|
|
187
216
|
const hubAssetIds = new Set(hubCandidates.map((c) => c.assetId).filter((id) => typeof id === 'string' && id.length > 0));
|
|
188
217
|
const selectedAssetId = res.decision?.selectedAssetId;
|
|
189
218
|
const usedAssetIds = selectedAssetId && hubAssetIds.has(selectedAssetId) ? [selectedAssetId] : [];
|
|
@@ -192,6 +221,8 @@ export async function runAutoExecTask(deps, rawTask, safety) {
|
|
|
192
221
|
...(res.reasons.length > 0 && status !== 'solidified' ? { reason: res.reasons.join('; ') } : {}),
|
|
193
222
|
...(cap?.outcome ? { outcome: cap.outcome } : {}),
|
|
194
223
|
...(cap?.proof_of_work ? { proofOfWork: cap.proof_of_work } : {}),
|
|
224
|
+
...(res.failureKind !== undefined ? { failureKind: res.failureKind } : {}),
|
|
225
|
+
...(res.exitCode !== undefined ? { exitCode: res.exitCode } : {}),
|
|
195
226
|
...(usedAssetIds.length > 0 ? { usedAssetIds } : {}),
|
|
196
227
|
};
|
|
197
228
|
}
|
|
@@ -29,6 +29,8 @@ export interface AutonomousSafety {
|
|
|
29
29
|
/** Only embed trusted gene strategies (#45). Default true. */
|
|
30
30
|
requireTrustedGene?: boolean;
|
|
31
31
|
timeoutMs?: number;
|
|
32
|
+
/** Cooperative cancellation propagated to the spawned runner process tree. */
|
|
33
|
+
signal?: AbortSignal;
|
|
32
34
|
}
|
|
33
35
|
/**
|
|
34
36
|
* Build the fully-hardened `execute` for an autonomous run against `repo`. Composes every exec-bridge control
|
|
@@ -43,12 +43,16 @@ const CODEX_DEFAULT_AGENT_OPTIONS = {};
|
|
|
43
43
|
// auto-approve shell+write, but Cursor has no verified per-run allowlist/sandbox mapping yet, so skipPermissions
|
|
44
44
|
// is refused outright. Use default cursor with worktree isolation until the CLI is run-verified.
|
|
45
45
|
const CURSOR_DEFAULT_AGENT_OPTIONS = {};
|
|
46
|
+
// Gemini's verified safe default is `--approval-mode auto_edit`; shell remains gated and --yolo is refused.
|
|
47
|
+
const GEMINI_DEFAULT_AGENT_OPTIONS = {};
|
|
46
48
|
/** Per-runner safe default agent options — claude bypasses-with-bounds; codex + cursor stay non-bypassing (codex sandboxed; cursor skip refused, #66). */
|
|
47
49
|
function defaultAgentOptions(runner) {
|
|
48
50
|
if (runner === 'codex')
|
|
49
51
|
return CODEX_DEFAULT_AGENT_OPTIONS;
|
|
50
52
|
if (runner === 'cursor')
|
|
51
53
|
return CURSOR_DEFAULT_AGENT_OPTIONS;
|
|
54
|
+
if (runner === 'gemini')
|
|
55
|
+
return GEMINI_DEFAULT_AGENT_OPTIONS;
|
|
52
56
|
return CLAUDE_DEFAULT_AGENT_OPTIONS;
|
|
53
57
|
}
|
|
54
58
|
/**
|
|
@@ -70,6 +74,7 @@ export function makeSafeExecute(repo, store, safety, opts = {}) {
|
|
|
70
74
|
requireTrustedGene: safety.requireTrustedGene ?? true,
|
|
71
75
|
agentOptions: safety.agentOptions ?? defaultAgentOptions(safety.runner),
|
|
72
76
|
...(safety.timeoutMs !== undefined ? { timeoutMs: safety.timeoutMs } : {}),
|
|
77
|
+
...(safety.signal ? { signal: safety.signal } : {}),
|
|
73
78
|
resolveGene: makeTrustedGeneResolver(store, opts.provenance, opts.review, opts.includeProbation ?? false),
|
|
74
79
|
...(opts.validate ? { validate: opts.validate } : {}),
|
|
75
80
|
...(opts.validationCmds ? { validationCmds: opts.validationCmds } : {}),
|
|
@@ -4,10 +4,13 @@ import type { ExecutionResult } from '../algo/cycleEngine.js';
|
|
|
4
4
|
import { type GeneStrategyInfo } from './prompt.js';
|
|
5
5
|
import type { PersonalityStore } from '../personality/store.js';
|
|
6
6
|
import { type AgentRunner, type AgentRunnerOptions, type RunnerName } from './runnerRegistry.js';
|
|
7
|
-
export { resolveSpawnCommand, spawnCapture, UnboundedSkipPermissionsError, UnsupportedCursorSkipPermissionsError, claudeRunnerArgs, makeClaudeHeadlessRunner, claudeHeadlessRunner, codexRunnerArgs, makeCodexHeadlessRunner, cursorRunnerArgs, makeCursorHeadlessRunner, getRunnerSpec, } from './runnerRegistry.js';
|
|
7
|
+
export { resolveSpawnCommand, spawnCapture, UnboundedSkipPermissionsError, UnsupportedCursorSkipPermissionsError, UnsupportedGeminiPermissionOptionsError, claudeRunnerArgs, makeClaudeHeadlessRunner, claudeHeadlessRunner, codexRunnerArgs, makeCodexHeadlessRunner, cursorRunnerArgs, makeCursorHeadlessRunner, getRunnerSpec, geminiRunnerArgs, makeGeminiHeadlessRunner, } from './runnerRegistry.js';
|
|
8
8
|
export type { AgentRunContext, AgentRunResult, AgentRunner, RunnerName, AgentRunnerOptions, ClaudeRunnerOptions, CodexRunnerOptions, AgentRunnerSpec, } from './runnerRegistry.js';
|
|
9
|
+
export interface GitRunnerOptions {
|
|
10
|
+
processSignalMode?: 'cancel' | 'ignore';
|
|
11
|
+
}
|
|
9
12
|
/** Run a git subcommand in cwd and return its stdout. */
|
|
10
|
-
export type GitRunner = (args: readonly string[], cwd: string) => Promise<string>;
|
|
13
|
+
export type GitRunner = (args: readonly string[], cwd: string, signal?: AbortSignal, options?: GitRunnerOptions) => Promise<string>;
|
|
11
14
|
/** Resolve the selected gene's learned strategy (for prompt enrichment). */
|
|
12
15
|
export type GeneResolver = (geneId: string) => Promise<GeneStrategyInfo | null> | GeneStrategyInfo | null;
|
|
13
16
|
/** Decide success from the post-run working tree (e.g. run the gene's validation plan). */
|
|
@@ -57,6 +60,8 @@ export interface ExecBridgeOptions {
|
|
|
57
60
|
requireTrustedGene?: boolean;
|
|
58
61
|
/** Per-run agent timeout. Default 600_000ms (10 min). */
|
|
59
62
|
timeoutMs?: number;
|
|
63
|
+
/** Cooperative cancellation propagated to the runner process tree. */
|
|
64
|
+
signal?: AbortSignal;
|
|
60
65
|
/** Optional: enrich the prompt with the selected gene's strategy. */
|
|
61
66
|
resolveGene?: GeneResolver;
|
|
62
67
|
/** Optional: validation commands surfaced in the prompt's done-criteria. */
|