@evomap/evolver-core 2.0.0-beta.19 → 2.0.0-beta.22
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/assets/gep/genes.jsonl +5 -5
- package/dist/algo/bans.d.ts +10 -1
- package/dist/algo/bans.js +56 -6
- package/dist/algo/candidateAssembly.d.ts +25 -2
- package/dist/algo/candidateAssembly.js +143 -20
- package/dist/algo/capabilityCandidates.js +10 -0
- package/dist/algo/cycleEngine.d.ts +40 -5
- package/dist/algo/cycleEngine.js +277 -37
- package/dist/algo/evolutionEvent.d.ts +26 -0
- package/dist/algo/evolutionEvent.js +32 -0
- package/dist/algo/exploration.d.ts +7 -0
- package/dist/algo/exploration.js +16 -3
- package/dist/algo/geneHealth.d.ts +34 -1
- package/dist/algo/geneHealth.js +42 -0
- package/dist/algo/geneIntake.d.ts +46 -1
- package/dist/algo/geneIntake.js +121 -10
- package/dist/algo/geneSelection.d.ts +115 -6
- package/dist/algo/geneSelection.js +459 -32
- package/dist/algo/index.d.ts +4 -1
- package/dist/algo/index.js +4 -1
- package/dist/algo/kautoProjection.d.ts +41 -0
- package/dist/algo/kautoProjection.js +95 -0
- package/dist/algo/kautoValidator.d.ts +68 -0
- package/dist/algo/kautoValidator.js +256 -0
- package/dist/algo/orchestrator.d.ts +14 -1
- package/dist/algo/orchestrator.js +9 -2
- package/dist/algo/solidify.d.ts +11 -2
- package/dist/algo/solidify.js +37 -7
- package/dist/algo/ucb1.d.ts +53 -0
- package/dist/algo/ucb1.js +156 -0
- package/dist/assetrepair/hubRejection.d.ts +12 -0
- package/dist/assetrepair/hubRejection.js +109 -0
- package/dist/assetrepair/index.d.ts +2 -0
- package/dist/assetrepair/index.js +2 -0
- package/dist/assetrepair/repair.d.ts +33 -0
- package/dist/assetrepair/repair.js +155 -0
- package/dist/assetstore/assetSidecarRecords.js +5 -1
- package/dist/assetstore/assetStoreHealth.d.ts +2 -3
- package/dist/assetstore/assetStoreHealth.js +4 -10
- package/dist/assetstore/foreignJsonlSource.d.ts +48 -0
- package/dist/assetstore/foreignJsonlSource.js +150 -0
- package/dist/assetstore/index.d.ts +3 -0
- package/dist/assetstore/index.js +3 -0
- package/dist/assetstore/learningHistory.js +3 -3
- package/dist/assetstore/localAssetStoreSnapshot.d.ts +51 -0
- package/dist/assetstore/localAssetStoreSnapshot.js +329 -0
- package/dist/assetstore/localJsonl.d.ts +8 -0
- package/dist/assetstore/localJsonl.js +128 -3
- package/dist/assetstore/provenance.d.ts +38 -3
- package/dist/assetstore/provenance.js +103 -45
- package/dist/assetstore/provider.d.ts +4 -0
- package/dist/assetstore/reviewFilter.d.ts +19 -1
- package/dist/assetstore/reviewFilter.js +36 -0
- package/dist/assetstore/unionReadStore.d.ts +25 -0
- package/dist/assetstore/unionReadStore.js +119 -0
- package/dist/benchmark/antiGeneBenchmark.d.ts +2 -0
- package/dist/benchmark/antiGeneBenchmark.js +4 -3
- package/dist/benchmark/antiGeneRollout.d.ts +2 -0
- package/dist/benchmark/antiGeneRollout.js +4 -3
- package/dist/benchmark/index.d.ts +2 -1
- package/dist/benchmark/index.js +2 -1
- package/dist/benchmark/selectionFlatAbstention.d.ts +152 -0
- package/dist/benchmark/selectionFlatAbstention.js +481 -0
- package/dist/bootstrap/envFingerprint.d.ts +9 -0
- package/dist/bootstrap/envFingerprint.js +5 -0
- package/dist/bootstrap/index.d.ts +2 -1
- package/dist/bootstrap/index.js +2 -1
- package/dist/bootstrap/lifecycleBootstrap.d.ts +111 -0
- package/dist/bootstrap/lifecycleBootstrap.js +433 -0
- package/dist/bootstrap/v1EnvCompat.d.ts +3 -0
- package/dist/bootstrap/v1EnvCompat.js +48 -1
- package/dist/events/eventArchive.d.ts +2 -0
- package/dist/events/eventArchive.js +13 -3
- package/dist/events/eventSchema.d.ts +7 -7
- package/dist/events/eventStore.d.ts +2 -0
- package/dist/events/eventStore.js +5 -1
- package/dist/events/ingest.d.ts +2 -1
- package/dist/events/ingest.js +6 -0
- package/dist/exec/autoExec.d.ts +30 -3
- package/dist/exec/autoExec.js +294 -29
- package/dist/exec/autonomousCycle.d.ts +7 -0
- package/dist/exec/autonomousCycle.js +2 -0
- package/dist/exec/claudeBridge.d.ts +28 -6
- package/dist/exec/claudeBridge.js +411 -258
- package/dist/exec/executionBinding.d.ts +414 -0
- package/dist/exec/executionBinding.js +588 -0
- package/dist/exec/index.d.ts +1 -0
- package/dist/exec/index.js +1 -0
- package/dist/exec/proofOfWork.d.ts +1 -1
- package/dist/exec/proofOfWork.js +2 -2
- package/dist/exec/runnerRegistry.d.ts +5 -0
- package/dist/exec/runnerRegistry.js +54 -14
- package/dist/hub/capability.d.ts +40 -1
- package/dist/hub/conversationDistiller.d.ts +19 -0
- package/dist/hub/conversationDistiller.js +115 -37
- package/dist/hub/fake.d.ts +1 -0
- package/dist/hub/fake.js +1 -0
- package/dist/hub/index.d.ts +1 -0
- package/dist/hub/index.js +1 -0
- package/dist/hub/recipeCompose.d.ts +27 -0
- package/dist/hub/recipeCompose.js +90 -0
- package/dist/hub/sanitize.js +119 -5
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/mailbox/ipcServer.d.ts +2 -0
- package/dist/mailbox/ipcServer.js +20 -0
- package/dist/mailbox/store.d.ts +52 -2
- package/dist/mailbox/store.js +546 -81
- package/dist/modelCompatibility.d.ts +164 -0
- package/dist/modelCompatibility.js +309 -0
- package/dist/observers/valueDigestObserver.d.ts +9 -0
- package/dist/observers/valueDigestObserver.js +35 -2
- package/dist/ops/cleanup.js +1 -1
- package/dist/ops/evolutionGraphProjection.d.ts +20 -0
- package/dist/ops/evolutionGraphProjection.js +315 -0
- package/dist/ops/index.d.ts +2 -1
- package/dist/ops/index.js +2 -1
- package/dist/ops/selfUpdate.d.ts +8 -0
- package/dist/ops/selfUpdate.js +24 -8
- package/dist/ops/valueOutreach.d.ts +3 -1
- package/dist/ops/valueOutreach.js +5 -1
- package/dist/personality/schema.d.ts +18 -18
- package/dist/schema/evolutionGraph.d.ts +784 -0
- package/dist/schema/evolutionGraph.js +187 -0
- package/dist/schema/index.d.ts +1 -0
- package/dist/schema/index.js +1 -0
- package/dist/schema/proofOfWork.d.ts +125 -6
- package/dist/schema/proofOfWork.js +102 -4
- package/dist/shadow/shadowHub.js +1 -0
- package/dist/signals/expand.d.ts +15 -1
- package/dist/signals/expand.js +148 -0
- package/dist/signals/index.d.ts +3 -1
- package/dist/signals/index.js +3 -1
- package/dist/signals/scopeVocabulary.d.ts +75 -0
- package/dist/signals/scopeVocabulary.js +91 -0
- package/dist/signals/taskDomain.d.ts +22 -0
- package/dist/signals/taskDomain.js +43 -0
- package/dist/trace/learningTrace.d.ts +7 -0
- package/dist/trace/learningTrace.js +22 -0
- package/dist/trace/trajectory.d.ts +8 -0
- package/dist/trace/trajectory.js +14 -2
- package/dist/util/fileLock.d.ts +92 -5
- package/dist/util/fileLock.js +809 -70
- package/dist/util/index.d.ts +2 -1
- package/dist/util/index.js +1 -1
- package/dist/verify/index.d.ts +2 -1
- package/dist/verify/index.js +1 -1
- package/dist/verify/sandboxRunner.d.ts +2 -0
- package/dist/verify/sandboxRunner.js +154 -10
- package/dist/verify/sandboxedValidation.d.ts +7 -2
- package/dist/verify/sandboxedValidation.js +102 -24
- package/dist/verify/validation.d.ts +24 -3
- package/dist/verify/validation.js +141 -24
- package/dist/wire/geneHints.d.ts +88 -16
- package/dist/wire/geneHints.js +124 -15
- package/dist/wire/index.d.ts +8 -3
- package/dist/wire/index.js +2 -2
- package/dist/wire/schemaGate.d.ts +21 -0
- package/dist/wire/schemaGate.js +119 -10
- package/package.json +5 -4
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", "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"];
|
|
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", "execution.binding.created", "execution.started", "execution.decision", "execution.terminal", "execution.recovered", "governance.projection.revoked", "governance.projection.reinstated"];
|
|
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;
|
|
@@ -25,6 +25,7 @@ export declare class Ingestor {
|
|
|
25
25
|
constructor(opts: IngestorOptions);
|
|
26
26
|
ingest(raw: RawEvent): Promise<RootEvent>;
|
|
27
27
|
readAll(): RootEvent[];
|
|
28
|
+
readAllStrict(): RootEvent[];
|
|
28
29
|
iterate(fromSeq?: number): Generator<RootEvent>;
|
|
29
30
|
tail(n?: number): RootEvent[];
|
|
30
31
|
recover(): {
|
package/dist/events/ingest.js
CHANGED
|
@@ -20,6 +20,11 @@ export const EVENT_TYPES = [
|
|
|
20
20
|
'reflection.recorded',
|
|
21
21
|
'material.batch_ready',
|
|
22
22
|
'value.reuse_hit', 'value.inject', 'value.reuse_outcome', 'value.recall',
|
|
23
|
+
'execution.binding.created', 'execution.started', 'execution.decision', 'execution.terminal', 'execution.recovered',
|
|
24
|
+
// K_auto EvidenceProjection: coordinate-level partial revocation over (version, claim, scope, runtime,
|
|
25
|
+
// verifier). A revoked event distrusts one (coordinate, value) pair; a reinstated event withdraws it. The
|
|
26
|
+
// authoritative root-event stream is the single source of truth (see algo/kautoProjection.projectRevocations).
|
|
27
|
+
'governance.projection.revoked', 'governance.projection.reinstated',
|
|
23
28
|
];
|
|
24
29
|
const knownTypes = new Set(EVENT_TYPES);
|
|
25
30
|
export function registerEventType(t) { knownTypes.add(t); }
|
|
@@ -63,6 +68,7 @@ export class Ingestor {
|
|
|
63
68
|
}
|
|
64
69
|
// 读 passthrough (写只能经 ingest)
|
|
65
70
|
readAll() { return this.store.readAll(); }
|
|
71
|
+
readAllStrict() { return this.store.readAllStrict(); }
|
|
66
72
|
iterate(fromSeq = 0) { return this.store.iterate(fromSeq); }
|
|
67
73
|
tail(n = 1) { return this.store.tail(n); }
|
|
68
74
|
recover() { return this.store.recover(); }
|
package/dist/exec/autoExec.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
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
|
-
import type { GeneCandidateInput } from '../algo/geneSelection.js';
|
|
5
|
-
import type { CycleEngine, ExecutionFailureKind, SolidifyPermitGate } from '../algo/cycleEngine.js';
|
|
4
|
+
import type { GeneCandidateInput, SelectionGuardMode } from '../algo/geneSelection.js';
|
|
5
|
+
import type { CycleEngine, ExecutionFailureKind, ExecutionResult, SolidifyPermitGate } from '../algo/cycleEngine.js';
|
|
6
6
|
import { type AutonomousSafety } from './autonomousCycle.js';
|
|
7
7
|
import { type GitRunner, type ValidateHook } from './claudeBridge.js';
|
|
8
8
|
import type { AgentRunner } from './runnerRegistry.js';
|
|
@@ -10,8 +10,10 @@ 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
12
|
import type { MemoryGraphProvider } from '../algo/memoryGraph.js';
|
|
13
|
+
import type { SelectionPolicy } from '../algo/ucb1.js';
|
|
13
14
|
import { type LearningPacketSink, type TraceSink } from '../trace/learningTrace.js';
|
|
14
15
|
import type { TraceReadOptions } from '../trace/trajectoryExport.js';
|
|
16
|
+
import { ExecutionBindingJournal, type BindingAuthorityChecks, type ExecutionBindingInput } from './executionBinding.js';
|
|
15
17
|
export interface AutoExecTask {
|
|
16
18
|
id: string;
|
|
17
19
|
repo: string;
|
|
@@ -31,10 +33,18 @@ export interface AutoExecTask {
|
|
|
31
33
|
/** Optional explicit strategy preset name for this task; wins over daemon default and meta-signal auto-detection. */
|
|
32
34
|
strategyName?: string;
|
|
33
35
|
validationCmds?: readonly string[];
|
|
36
|
+
/** Frozen external execution binding; bound tasks never fall back to unbound execution. */
|
|
37
|
+
execution_binding?: ExecutionBindingInput;
|
|
34
38
|
}
|
|
35
39
|
export interface AutoExecVerdict {
|
|
36
40
|
taskId: string;
|
|
37
|
-
status: 'refused' | 'skipped' | 'solidified' | 'failed' | 'innovated';
|
|
41
|
+
status: 'refused' | 'skipped' | 'solidified' | 'failed' | 'innovated' | 'unsafe_to_replay';
|
|
42
|
+
binding_digest?: `sha256:${string}`;
|
|
43
|
+
run_id?: string;
|
|
44
|
+
execution_terminal?: ExecutionResult['executionTerminal'];
|
|
45
|
+
hub_lifecycle?: {
|
|
46
|
+
state: 'not_submitted';
|
|
47
|
+
};
|
|
38
48
|
reason?: string;
|
|
39
49
|
finalStage?: string;
|
|
40
50
|
outcome?: {
|
|
@@ -85,6 +95,15 @@ export interface AutoExecDeps {
|
|
|
85
95
|
validate?: (task: AutoExecTask) => ValidateHook;
|
|
86
96
|
/** Optional adapter/runtime permit gate. Core owns only the seam; adapters own the verification policy. */
|
|
87
97
|
solidifyPermit?: SolidifyPermitGate;
|
|
98
|
+
/** Bound execution uses the existing root-event journal; composition supplies its authoritative external checks. */
|
|
99
|
+
executionBinding?: {
|
|
100
|
+
journal: ExecutionBindingJournal;
|
|
101
|
+
authority: BindingAuthorityChecks;
|
|
102
|
+
now?: () => number;
|
|
103
|
+
maxRuntimeMs?: number;
|
|
104
|
+
maxFiles?: number;
|
|
105
|
+
maxLines?: number;
|
|
106
|
+
};
|
|
88
107
|
/**
|
|
89
108
|
* Optional open-PR dedup: when set, before spawning an agent the task's signals are compared against open PR
|
|
90
109
|
* titles/branches; a strong overlap yields a 'skipped' verdict so the daemon never re-implements work that is
|
|
@@ -106,6 +125,14 @@ export interface AutoExecDeps {
|
|
|
106
125
|
memoryGraph?: MemoryGraphProvider;
|
|
107
126
|
/** Optional daemon-level explicit strategy preset name, e.g. EVOLVE_STRATEGY. */
|
|
108
127
|
strategyName?: string;
|
|
128
|
+
/** Emergency rollback for semantic IDF selection. Omit to keep IDF enabled. */
|
|
129
|
+
disableSemanticIdf?: boolean;
|
|
130
|
+
/** Experimental plateau selection policy. Omit to preserve engine-health + legacy drift. */
|
|
131
|
+
selectionPolicy?: SelectionPolicy;
|
|
132
|
+
/** Production relevance-guard rollout. Omit only for legacy/custom composition. */
|
|
133
|
+
selectionGuard?: SelectionGuardMode;
|
|
134
|
+
/** Optional score floor canary. Omit to keep the selector default of zero. */
|
|
135
|
+
selectionFloor?: number;
|
|
109
136
|
/** Optional evolvable personality store shared with CycleEngine and the exec prompt. */
|
|
110
137
|
personality?: PersonalityStore;
|
|
111
138
|
/** Test/custom seam: inject a runner instead of spawning a real agent. */
|
package/dist/exec/autoExec.js
CHANGED
|
@@ -4,10 +4,12 @@ import { mergePendingSignalsForStore } from '../assetstore/pendingSignals.js';
|
|
|
4
4
|
import { intakeGene } from '../algo/geneIntake.js';
|
|
5
5
|
import { runEvolutionCycle } from '../algo/orchestrator.js';
|
|
6
6
|
import { makeSafeExecute, makeTrustedGeneResolver } from './autonomousCycle.js';
|
|
7
|
-
import { isWithinRoot } from './claudeBridge.js';
|
|
7
|
+
import { defaultGitRunner, isWithinRoot } from './claudeBridge.js';
|
|
8
8
|
import { findSignalHints } from './openPrRegistry.js';
|
|
9
9
|
import { AgentRunTraceRecorder, buildLearningPacketDraft } from '../trace/learningTrace.js';
|
|
10
10
|
import { collectRunLlmTurns } from '../trace/proxyTurns.js';
|
|
11
|
+
import { uniqueSessionId } from '../trace/trajectory.js';
|
|
12
|
+
import { ExecutionBindingError, ExecutionBindingJournal, freezeExecutionBinding, preflightExecutionBinding, } from './executionBinding.js';
|
|
11
13
|
/** Same path-containment as the bridge guard — used here to refuse before running anything (clean verdict). */
|
|
12
14
|
function withinAllowlist(repo, roots) {
|
|
13
15
|
return roots.some((root) => isWithinRoot(repo, root));
|
|
@@ -92,6 +94,78 @@ export async function runAutoExecTask(deps, rawTask, safety) {
|
|
|
92
94
|
if (!withinAllowlist(task.repo, safety.allowedRoots)) {
|
|
93
95
|
return { taskId: task.id, status: 'refused', reason: `repo not in allowlist: ${task.repo}` };
|
|
94
96
|
}
|
|
97
|
+
const cycleId = `autoexec-${task.id}`;
|
|
98
|
+
let binding;
|
|
99
|
+
let bindingClaimed = false;
|
|
100
|
+
let baseValidate;
|
|
101
|
+
if (task.execution_binding !== undefined) {
|
|
102
|
+
try {
|
|
103
|
+
binding = freezeExecutionBinding(task.execution_binding);
|
|
104
|
+
if (!deps.executionBinding)
|
|
105
|
+
throw new ExecutionBindingError('binding_missing', 'execution binding journal and authority checks are required');
|
|
106
|
+
const recovery = deps.executionBinding.journal.recover(task.id, binding.binding_digest);
|
|
107
|
+
if (recovery.kind === 'terminal') {
|
|
108
|
+
const recoveredStatus = recovery.terminal.disposition === 'unsafe_to_replay'
|
|
109
|
+
? 'unsafe_to_replay'
|
|
110
|
+
: recovery.terminal.disposition === 'completed' && recovery.terminal.final_stage === 'solidified'
|
|
111
|
+
? 'solidified'
|
|
112
|
+
: recovery.terminal.disposition === 'completed' && recovery.terminal.final_stage === 'innovated'
|
|
113
|
+
? 'innovated'
|
|
114
|
+
: recovery.terminal.disposition === 'denied'
|
|
115
|
+
? 'refused'
|
|
116
|
+
: 'failed';
|
|
117
|
+
return {
|
|
118
|
+
taskId: task.id,
|
|
119
|
+
status: recoveredStatus,
|
|
120
|
+
binding_digest: recovery.binding_digest,
|
|
121
|
+
run_id: binding.correlation.run_id,
|
|
122
|
+
execution_terminal: {
|
|
123
|
+
status: recovery.terminal.outcome?.status === 'success' ? 'success' : 'failed',
|
|
124
|
+
disposition: recovery.terminal.disposition,
|
|
125
|
+
},
|
|
126
|
+
hub_lifecycle: { state: 'not_submitted' },
|
|
127
|
+
...(recovery.terminal.outcome ? { outcome: recovery.terminal.outcome } : {}),
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
if (recovery.kind === 'unsafe_to_replay' || recovery.kind === 'mismatched') {
|
|
131
|
+
return { taskId: task.id, status: 'unsafe_to_replay', binding_digest: recovery.binding_digest, run_id: binding.correlation.run_id, reason: recovery.reason };
|
|
132
|
+
}
|
|
133
|
+
await preflightExecutionBinding(binding, {
|
|
134
|
+
taskId: task.id,
|
|
135
|
+
runId: binding.correlation.run_id,
|
|
136
|
+
cycleId,
|
|
137
|
+
repoPath: task.repo,
|
|
138
|
+
target: task.target,
|
|
139
|
+
expectedEffect: task.expectedEffect,
|
|
140
|
+
allowedRoots: safety.allowedRoots,
|
|
141
|
+
now: deps.executionBinding.now ?? Date.now,
|
|
142
|
+
currentRevision: binding.target_descriptor.base_revision === null
|
|
143
|
+
? null
|
|
144
|
+
: (deps.git ?? defaultGitRunner)(['rev-parse', 'HEAD'], task.repo).then((revision) => revision.trim() || null),
|
|
145
|
+
maxRuntimeMs: deps.executionBinding.maxRuntimeMs ?? safety.timeoutMs,
|
|
146
|
+
maxFiles: deps.executionBinding.maxFiles,
|
|
147
|
+
maxLines: deps.executionBinding.maxLines,
|
|
148
|
+
requiredConsentScope: 'execution',
|
|
149
|
+
authoritative: deps.executionBinding.authority,
|
|
150
|
+
});
|
|
151
|
+
if (!deps.validate && binding.resource_grant.validation_commands.length > 0) {
|
|
152
|
+
throw new ExecutionBindingError('binding_acceptance_invalid', 'bound execution requires the declared validation plan to be wired to a validator');
|
|
153
|
+
}
|
|
154
|
+
baseValidate = deps.validate?.({ ...task, validationCmds: binding.resource_grant.validation_commands });
|
|
155
|
+
if (baseValidate && baseValidate.length < 4) {
|
|
156
|
+
throw new ExecutionBindingError('binding_acceptance_invalid', 'bound execution validator must accept AbortSignal');
|
|
157
|
+
}
|
|
158
|
+
if (recovery.kind === 'new')
|
|
159
|
+
await deps.executionBinding.journal.recordCreated(binding);
|
|
160
|
+
if (recovery.kind === 'claimed')
|
|
161
|
+
bindingClaimed = true;
|
|
162
|
+
}
|
|
163
|
+
catch (error) {
|
|
164
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
165
|
+
const unsafe = error instanceof ExecutionBindingError && error.unsafeToReplay;
|
|
166
|
+
return { taskId: task.id, status: unsafe ? 'unsafe_to_replay' : 'refused', ...(binding ? { binding_digest: binding.binding_digest, run_id: binding.correlation.run_id } : {}), reason: detail };
|
|
167
|
+
}
|
|
168
|
+
}
|
|
95
169
|
// Open-PR dedup (opt-in): if an open PR already covers this task's signals, skip before spawning an agent
|
|
96
170
|
// so the daemon doesn't re-implement in-flight work. Graceful — a lister that returns [] is a no-op.
|
|
97
171
|
if (deps.prLister) {
|
|
@@ -131,7 +205,6 @@ export async function runAutoExecTask(deps, rawTask, safety) {
|
|
|
131
205
|
// in the same selection pool as local genes. Reuse is an optimization, never a hard dependency — a seam
|
|
132
206
|
// that throws degrades to solving fresh (no hub candidates) rather than failing the task.
|
|
133
207
|
let hubCandidates = [];
|
|
134
|
-
const cycleId = `autoexec-${task.id}`;
|
|
135
208
|
// Learning trace (slice 2): one recorder per task run, traceId = cycleId so the trace joins the event log.
|
|
136
209
|
// Purely observational — every recorder call and the packet submit are wrapped so they can never change
|
|
137
210
|
// the verdict or fail the task.
|
|
@@ -164,15 +237,26 @@ export async function runAutoExecTask(deps, rawTask, safety) {
|
|
|
164
237
|
// (verifier 'automated_test'). Observation is a pass-through wrapper: the hook's result reaches the
|
|
165
238
|
// bridge unchanged, and a run where validation never fired keeps the evaluation placeholder.
|
|
166
239
|
let observedVerification;
|
|
167
|
-
|
|
240
|
+
baseValidate ??= deps.validate?.(task);
|
|
168
241
|
const observingValidate = baseValidate
|
|
169
|
-
? async (mutation, decision, cwd) => {
|
|
170
|
-
const v = await baseValidate(mutation, decision, cwd);
|
|
242
|
+
? async (mutation, decision, cwd, signal) => {
|
|
243
|
+
const v = await baseValidate(mutation, decision, cwd, signal);
|
|
171
244
|
observedVerification = { verifier: 'automated_test', passed: v.passed, ...(v.score !== undefined ? { score: v.score } : {}) };
|
|
172
245
|
return v;
|
|
173
246
|
}
|
|
174
247
|
: undefined;
|
|
175
|
-
const
|
|
248
|
+
const observedProvenance = {
|
|
249
|
+
gene_ids: [], capsule_ids: [], tool_decisions: [],
|
|
250
|
+
policy_decisions: [], validator: null,
|
|
251
|
+
result_asset_refs: [], proof_refs: [], terminal_disposition: 'crashed',
|
|
252
|
+
};
|
|
253
|
+
const executionObserver = binding ? {
|
|
254
|
+
onToolDecision: (decision) => { observedProvenance.tool_decisions.push(decision); },
|
|
255
|
+
onPolicyDecision: (decision) => { observedProvenance.policy_decisions.push(decision); },
|
|
256
|
+
onValidatorDecision: (decision) => { observedProvenance.validator = decision; },
|
|
257
|
+
onProofReference: (reference) => { observedProvenance.proof_refs.push(reference); },
|
|
258
|
+
} : undefined;
|
|
259
|
+
const safeExecute = makeSafeExecute(task.repo, deps.store, safety, {
|
|
176
260
|
...(deps.provenance ? { provenance: deps.provenance } : {}),
|
|
177
261
|
...(deps.review ? { review: deps.review } : {}),
|
|
178
262
|
...(deps.includeProbation ? { includeProbation: true } : {}),
|
|
@@ -182,7 +266,84 @@ export async function runAutoExecTask(deps, rawTask, safety) {
|
|
|
182
266
|
...(deps.agent ? { agent: deps.agent } : {}),
|
|
183
267
|
...(deps.git ? { git: deps.git } : {}),
|
|
184
268
|
...(traceRecorder ? { traceRecorder } : {}),
|
|
269
|
+
...(executionObserver ? { executionObserver } : {}),
|
|
270
|
+
...(binding ? { executionLimits: {
|
|
271
|
+
maxRuntimeMs: binding.resource_grant.max_runtime_ms,
|
|
272
|
+
maxFiles: binding.resource_grant.max_files,
|
|
273
|
+
maxLines: binding.resource_grant.max_lines,
|
|
274
|
+
} } : {}),
|
|
185
275
|
});
|
|
276
|
+
const execute = binding && deps.executionBinding
|
|
277
|
+
? async (mutation, decision) => {
|
|
278
|
+
const selectedContext = binding.selected_context;
|
|
279
|
+
try {
|
|
280
|
+
if (selectedContext.capsule_id !== null || selectedContext.capsule_asset_id !== null) {
|
|
281
|
+
throw new ExecutionBindingError('binding_mismatched', 'preselected capsule context is not supported by the CycleEngine execution seam');
|
|
282
|
+
}
|
|
283
|
+
if (selectedContext.gene_id !== null && decision.selectedGeneId !== selectedContext.gene_id) {
|
|
284
|
+
throw new ExecutionBindingError('binding_mismatched', 'selected gene_id does not match frozen binding context');
|
|
285
|
+
}
|
|
286
|
+
if (selectedContext.gene_asset_id !== null && decision.selectedAssetId !== selectedContext.gene_asset_id) {
|
|
287
|
+
throw new ExecutionBindingError('binding_mismatched', 'selected gene_asset_id does not match frozen binding context');
|
|
288
|
+
}
|
|
289
|
+
if (!bindingClaimed) {
|
|
290
|
+
await preflightExecutionBinding(binding, {
|
|
291
|
+
taskId: task.id,
|
|
292
|
+
runId: binding.correlation.run_id,
|
|
293
|
+
cycleId,
|
|
294
|
+
repoPath: task.repo,
|
|
295
|
+
target: task.target,
|
|
296
|
+
expectedEffect: task.expectedEffect,
|
|
297
|
+
allowedRoots: safety.allowedRoots,
|
|
298
|
+
now: deps.executionBinding.now ?? Date.now,
|
|
299
|
+
currentRevision: binding.target_descriptor.base_revision === null
|
|
300
|
+
? null
|
|
301
|
+
: (deps.git ?? defaultGitRunner)(['rev-parse', 'HEAD'], task.repo).then((revision) => revision.trim() || null),
|
|
302
|
+
maxRuntimeMs: deps.executionBinding.maxRuntimeMs ?? safety.timeoutMs,
|
|
303
|
+
maxFiles: deps.executionBinding.maxFiles,
|
|
304
|
+
maxLines: deps.executionBinding.maxLines,
|
|
305
|
+
requiredConsentScope: 'execution',
|
|
306
|
+
authoritative: deps.executionBinding.authority,
|
|
307
|
+
});
|
|
308
|
+
const started = await deps.executionBinding.journal.claim(binding);
|
|
309
|
+
if (started.kind !== 'claimed')
|
|
310
|
+
throw new ExecutionBindingError('binding_replay_unsafe', `binding execution claim ended in ${started.kind}`, true);
|
|
311
|
+
bindingClaimed = true;
|
|
312
|
+
}
|
|
313
|
+
const result = await safeExecute(mutation, decision);
|
|
314
|
+
const policyDenied = observedProvenance.policy_decisions.some((policy) => !policy.allowed);
|
|
315
|
+
const disposition = result.outcome.status === 'success'
|
|
316
|
+
? 'completed'
|
|
317
|
+
: result.failureKind === 'timeout'
|
|
318
|
+
? 'timed_out'
|
|
319
|
+
: result.failureKind === 'cancelled'
|
|
320
|
+
? 'cancelled'
|
|
321
|
+
: policyDenied ? 'denied' : 'rejected';
|
|
322
|
+
observedProvenance.terminal_disposition = disposition;
|
|
323
|
+
return {
|
|
324
|
+
...result,
|
|
325
|
+
provenance: { ...observedProvenance, terminal_disposition: disposition },
|
|
326
|
+
bindingCorrelation: { bindingDigest: binding.binding_digest, runId: binding.correlation.run_id },
|
|
327
|
+
executionTerminal: { status: result.outcome.status, disposition },
|
|
328
|
+
hubLifecycle: { state: 'not_submitted' },
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
catch (error) {
|
|
332
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
333
|
+
const disposition = error instanceof ExecutionBindingError
|
|
334
|
+
? error.unsafeToReplay ? 'unsafe_to_replay' : 'denied'
|
|
335
|
+
: 'crashed';
|
|
336
|
+
observedProvenance.terminal_disposition = disposition;
|
|
337
|
+
return {
|
|
338
|
+
outcome: { status: 'failed', score: 0, reason: message },
|
|
339
|
+
bindingCorrelation: { bindingDigest: binding.binding_digest, runId: binding.correlation.run_id },
|
|
340
|
+
executionTerminal: { status: 'failed', disposition },
|
|
341
|
+
provenance: { ...observedProvenance, terminal_disposition: disposition },
|
|
342
|
+
hubLifecycle: { state: 'not_submitted' },
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
: safeExecute;
|
|
186
347
|
const strategyName = task.strategyName ?? deps.strategyName;
|
|
187
348
|
// Intentional semantics (see #308 review M1): a task carrying `strategy` — even without an
|
|
188
349
|
// explicit forcedGeneId — force-selects the gene seeded from that strategy above, rather than
|
|
@@ -199,29 +360,119 @@ export async function runAutoExecTask(deps, rawTask, safety) {
|
|
|
199
360
|
memoryGraphAdvice = undefined;
|
|
200
361
|
}
|
|
201
362
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
363
|
+
let res;
|
|
364
|
+
try {
|
|
365
|
+
res = await runEvolutionCycle(deps.engine, deps.store, {
|
|
366
|
+
...(deps.provenance ? { provenance: deps.provenance } : {}),
|
|
367
|
+
...(deps.review ? { review: deps.review } : {}),
|
|
368
|
+
...(deps.includeProbation ? { includeProbation: true } : {}),
|
|
369
|
+
...(hubCandidates.length > 0 ? { hubCandidates } : {}),
|
|
370
|
+
...(deps.solidifyPermit ? { solidifyPermit: deps.solidifyPermit } : {}),
|
|
371
|
+
...(binding ? { executionBinding: binding } : {}),
|
|
372
|
+
...(deps.reuseOutcomes ? { reuseOutcomes: deps.reuseOutcomes } : {}),
|
|
373
|
+
...(deps.recallEvents ? { recallEvents: deps.recallEvents } : {}),
|
|
374
|
+
...(memoryGraphAdvice ? { memoryGraphAdvice } : {}),
|
|
375
|
+
...(strategyName !== undefined ? { strategyName } : {}),
|
|
376
|
+
...(deps.disableSemanticIdf ? { disableSemanticIdf: true } : {}),
|
|
377
|
+
...(deps.selectionPolicy ? { selectionPolicy: deps.selectionPolicy } : {}),
|
|
378
|
+
...(deps.selectionGuard ? { selectionGuard: deps.selectionGuard } : {}),
|
|
379
|
+
...(deps.selectionFloor !== undefined ? { selectionFloor: deps.selectionFloor } : {}),
|
|
380
|
+
...(cycleForcedGeneId !== undefined ? { forcedGeneId: cycleForcedGeneId } : {}),
|
|
381
|
+
cycleId,
|
|
382
|
+
problem: {
|
|
383
|
+
id: task.id, signature: `sig:${task.id}`, signatureV: 1,
|
|
384
|
+
firstSeenAt: new Date(0).toISOString(), lastSeenAt: new Date(0).toISOString(),
|
|
385
|
+
occurrences: 1, linkedSignals: cycleSignals, resolvedBy: null, status: 'open',
|
|
386
|
+
value: { severity: 0.7, reach: 1, strategicFit: 0.9, novelty: 0, costEst: 0.2 },
|
|
387
|
+
consecutiveFailures: 0, cooldownUntil: null, extensions: {},
|
|
388
|
+
},
|
|
389
|
+
signals: cycleSignals, category: 'repair', target: task.target, expectedEffect: task.expectedEffect,
|
|
390
|
+
summary: `autonomous: ${task.id}`, confidence: 0.85, execute, consumePendingSignals: false,
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
catch (error) {
|
|
394
|
+
if (binding && deps.executionBinding) {
|
|
395
|
+
const recovery = deps.executionBinding.journal.recover(task.id, binding.binding_digest);
|
|
396
|
+
if (recovery.kind === 'unsafe_to_replay') {
|
|
397
|
+
try {
|
|
398
|
+
await deps.executionBinding.journal.recordTerminal({
|
|
399
|
+
binding_digest: binding.binding_digest,
|
|
400
|
+
task_id: task.id,
|
|
401
|
+
run_id: binding.correlation.run_id,
|
|
402
|
+
disposition: 'unsafe_to_replay',
|
|
403
|
+
outcome: { status: 'failed', score: 0, reason: recovery.reason },
|
|
404
|
+
provenance: { ...observedProvenance, terminal_disposition: 'unsafe_to_replay' },
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
catch { /* the existing started marker remains fail-closed on recovery */ }
|
|
408
|
+
return { taskId: task.id, status: 'unsafe_to_replay', binding_digest: binding.binding_digest, run_id: binding.correlation.run_id, reason: `binding_replay_unsafe: ${recovery.reason}` };
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
412
|
+
return { taskId: task.id, status: 'failed', ...(binding ? { binding_digest: binding.binding_digest, run_id: binding.correlation.run_id } : {}), reason: detail };
|
|
413
|
+
}
|
|
414
|
+
if (binding && deps.executionBinding) {
|
|
415
|
+
const execution = res.execution;
|
|
416
|
+
if (!execution?.provenance || !execution.executionTerminal) {
|
|
417
|
+
const deniedReason = res.reasons.join('; ') || `cycle ended at ${res.finalStage} before execution`;
|
|
418
|
+
try {
|
|
419
|
+
await deps.executionBinding.journal.recordTerminal({
|
|
420
|
+
binding_digest: binding.binding_digest,
|
|
421
|
+
task_id: task.id,
|
|
422
|
+
run_id: binding.correlation.run_id,
|
|
423
|
+
disposition: 'denied',
|
|
424
|
+
final_stage: res.finalStage,
|
|
425
|
+
outcome: { status: 'failed', score: 0, reason: deniedReason },
|
|
426
|
+
provenance: { ...observedProvenance, terminal_disposition: 'denied' },
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
catch (error) {
|
|
430
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
431
|
+
return { taskId: task.id, status: 'failed', binding_digest: binding.binding_digest, run_id: binding.correlation.run_id, reason: `binding_provenance_unavailable: ${detail}` };
|
|
432
|
+
}
|
|
433
|
+
return {
|
|
434
|
+
taskId: task.id,
|
|
435
|
+
status: 'refused',
|
|
436
|
+
binding_digest: binding.binding_digest,
|
|
437
|
+
run_id: binding.correlation.run_id,
|
|
438
|
+
execution_terminal: { status: 'failed', disposition: 'denied' },
|
|
439
|
+
hub_lifecycle: { state: 'not_submitted' },
|
|
440
|
+
reason: deniedReason,
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
const terminal = {
|
|
444
|
+
binding_digest: binding.binding_digest,
|
|
445
|
+
task_id: task.id,
|
|
446
|
+
run_id: binding.correlation.run_id,
|
|
447
|
+
disposition: execution.executionTerminal.disposition,
|
|
448
|
+
final_stage: res.finalStage,
|
|
449
|
+
outcome: execution.outcome,
|
|
450
|
+
...(execution.proofOfWork ? { proof_of_work: execution.proofOfWork } : {}),
|
|
451
|
+
provenance: {
|
|
452
|
+
...execution.provenance,
|
|
453
|
+
gene_ids: res.decision?.selectedGeneId ? [res.decision.selectedGeneId] : [],
|
|
454
|
+
capsule_ids: res.capsule?.asset_id ? [res.capsule.asset_id] : [],
|
|
455
|
+
result_asset_refs: res.capsule?.asset_id ? [res.capsule.asset_id] : [],
|
|
456
|
+
proof_refs: execution.provenance.proof_refs.length > 0
|
|
457
|
+
? execution.provenance.proof_refs
|
|
458
|
+
: execution.proofOfWork?.kind === 'git_diff' && execution.proofOfWork.git_diff?.patch_ref
|
|
459
|
+
? [{ kind: 'git_diff', ref: execution.proofOfWork.git_diff.patch_ref }]
|
|
460
|
+
: execution.provenance.proof_refs,
|
|
461
|
+
},
|
|
462
|
+
};
|
|
463
|
+
try {
|
|
464
|
+
await deps.executionBinding.journal.recordTerminal(terminal);
|
|
465
|
+
}
|
|
466
|
+
catch (error) {
|
|
467
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
468
|
+
return { taskId: task.id, status: 'failed', binding_digest: binding.binding_digest, run_id: binding.correlation.run_id, reason: `binding_provenance_unavailable: ${detail}` };
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
const status = res.execution?.executionTerminal?.disposition === 'unsafe_to_replay'
|
|
472
|
+
? 'unsafe_to_replay'
|
|
473
|
+
: res.execution?.executionTerminal?.disposition === 'denied'
|
|
474
|
+
? 'refused'
|
|
475
|
+
: res.finalStage === 'solidified' ? 'solidified' : res.finalStage === 'failed' ? 'failed' : res.finalStage === 'aborted' ? 'refused' : 'innovated';
|
|
225
476
|
const cap = res.capsule;
|
|
226
477
|
if (traceRecorder && deps.learningTrace) {
|
|
227
478
|
// Proxy llm_turn fold (slice 5): fold the run window's per-request turns BEFORE run.completed so the
|
|
@@ -231,6 +482,16 @@ export async function runAutoExecTask(deps, rawTask, safety) {
|
|
|
231
482
|
const proxyTraces = deps.learningTrace.proxyTraces;
|
|
232
483
|
if (proxyTraces) {
|
|
233
484
|
const turns = collectRunLlmTurns(proxyTraces.dir, { startMs: runStartMs, endMs: proxyTraceClock() }, proxyTraces.readOptions ? { readOptions: proxyTraces.readOptions } : {});
|
|
485
|
+
// Exact-join key for Darwin: bind the unique proxy session before folding turns so
|
|
486
|
+
// every subsequent event (and backfilled earlier ones) carries the same sessionId.
|
|
487
|
+
// Fail closed when 0 or >1 sessions appear — never invent a correlation key.
|
|
488
|
+
const sid = uniqueSessionId(turns);
|
|
489
|
+
if (sid !== null) {
|
|
490
|
+
try {
|
|
491
|
+
traceRecorder.bindSessionId(sid);
|
|
492
|
+
}
|
|
493
|
+
catch { /* observability only */ }
|
|
494
|
+
}
|
|
234
495
|
for (const turn of turns)
|
|
235
496
|
traceRecorder.recordLlmTurn(turn);
|
|
236
497
|
}
|
|
@@ -286,6 +547,10 @@ export async function runAutoExecTask(deps, rawTask, safety) {
|
|
|
286
547
|
...(cap?.proof_of_work ? { proofOfWork: cap.proof_of_work } : {}),
|
|
287
548
|
...(res.failureKind !== undefined ? { failureKind: res.failureKind } : {}),
|
|
288
549
|
...(res.exitCode !== undefined ? { exitCode: res.exitCode } : {}),
|
|
550
|
+
...(res.bindingDigest ? { binding_digest: res.bindingDigest } : {}),
|
|
551
|
+
...(res.runId ? { run_id: res.runId } : {}),
|
|
552
|
+
...(res.execution ? { execution_terminal: res.execution.executionTerminal } : {}),
|
|
553
|
+
...(res.execution?.hubLifecycle ? { hub_lifecycle: res.execution.hubLifecycle } : {}),
|
|
289
554
|
...(usedAssetIds.length > 0 ? { usedAssetIds } : {}),
|
|
290
555
|
};
|
|
291
556
|
}
|
|
@@ -7,6 +7,7 @@ import type { ExecutionResult } from '../algo/cycleEngine.js';
|
|
|
7
7
|
import { type GeneResolver, type ValidateHook, type AgentRunnerOptions, type AgentSessionResume, type RunnerName, type AgentRunner, type GitRunner } from './claudeBridge.js';
|
|
8
8
|
import type { PersonalityStore } from '../personality/store.js';
|
|
9
9
|
import type { AgentRunTraceRecorder } from '../trace/learningTrace.js';
|
|
10
|
+
import type { ExecutionObserver } from './claudeBridge.js';
|
|
10
11
|
/**
|
|
11
12
|
* Resolve a gene's strategy from the store and whether it is safe to EMBED into an autonomous agent's prompt —
|
|
12
13
|
* the exec-side link from #30 (provenance ledger) and the review-state gate to #45 (requireTrustedGene gate). A
|
|
@@ -65,4 +66,10 @@ export declare function makeSafeExecute(repo: string, store: AssetStoreProvider,
|
|
|
65
66
|
git?: GitRunner;
|
|
66
67
|
/** Optional learning-trace recorder forwarded to the exec bridge (Learning Ops slice 2). */
|
|
67
68
|
traceRecorder?: AgentRunTraceRecorder;
|
|
69
|
+
executionObserver?: ExecutionObserver;
|
|
70
|
+
executionLimits?: {
|
|
71
|
+
maxRuntimeMs: number;
|
|
72
|
+
maxFiles: number;
|
|
73
|
+
maxLines: number;
|
|
74
|
+
};
|
|
68
75
|
}): (mutation: Mutation, decision: GeneDecision) => Promise<ExecutionResult>;
|
|
@@ -117,6 +117,8 @@ export function makeSafeExecute(repo, store, safety, opts = {}) {
|
|
|
117
117
|
...(opts.agent ? { agent: opts.agent } : {}),
|
|
118
118
|
...(opts.git ? { git: opts.git } : {}),
|
|
119
119
|
...(opts.traceRecorder ? { traceRecorder: opts.traceRecorder } : {}),
|
|
120
|
+
...(opts.executionObserver ? { executionObserver: opts.executionObserver } : {}),
|
|
121
|
+
...(opts.executionLimits ? { executionLimits: opts.executionLimits } : {}),
|
|
120
122
|
allowedRoots: safety.allowedRoots,
|
|
121
123
|
...(runner ? { runner } : {}),
|
|
122
124
|
...(safety.resume ? { resume: safety.resume } : {}),
|
|
@@ -4,6 +4,7 @@ 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 { AgentRunTraceRecorder } from '../trace/learningTrace.js';
|
|
7
|
+
import type { PolicyDecision, ProofReference, ToolDecision, ValidatorEvidence } from './executionBinding.js';
|
|
7
8
|
import { type AgentRunner, type AgentRunnerOptions, type AgentSessionResume, type RunnerName } from './runnerRegistry.js';
|
|
8
9
|
export { resolveSpawnCommand, spawnCapture, DEFAULT_MAX_CAPTURE_BYTES, MAX_AGENT_SESSION_ID_CHARS, AgentSessionResumeError, validateAgentSessionResume, UnboundedSkipPermissionsError, UnsupportedCodexPermissionOptionsError, UnsupportedCursorAllowedToolsError, UnsupportedCursorSkipPermissionsError, UnsupportedCursorWorkspaceTrustError, UnsupportedGeminiPermissionOptionsError, claudeRunnerArgs, makeClaudeHeadlessRunner, claudeHeadlessRunner, codexRunnerArgs, makeCodexHeadlessRunner, cursorRunnerArgs, makeCursorHeadlessRunner, getRunnerSpec, hasBoundedClaudeFileAccess, CLAUDE_SAFE_AUTONOMOUS_TOOLS, geminiRunnerArgs, makeGeminiHeadlessRunner, classifyGeminiRunnerResult, } from './runnerRegistry.js';
|
|
9
10
|
export type { AgentRunContext, AgentRunResult, AgentRunner, RunnerName, AgentRunnerOptions, ClaudeRunnerOptions, CodexRunnerOptions, AgentRunnerSpec, AgentSessionResume, } from './runnerRegistry.js';
|
|
@@ -18,13 +19,18 @@ onDestinationOpened?: () => void) => Promise<void>;
|
|
|
18
19
|
/** Resolve the selected gene's learned strategy (for prompt enrichment). */
|
|
19
20
|
export type GeneResolver = (geneId: string) => Promise<GeneStrategyInfo | null> | GeneStrategyInfo | null;
|
|
20
21
|
/** Decide success from the post-run working tree (e.g. run the gene's validation plan). */
|
|
21
|
-
export
|
|
22
|
+
export interface ValidateHookResult {
|
|
22
23
|
passed: boolean;
|
|
23
24
|
score?: number;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
validator?: ValidatorEvidence;
|
|
26
|
+
}
|
|
27
|
+
export type ValidateHook = (mutation: Mutation, decision: GeneDecision, cwd: string, signal: AbortSignal) => Promise<ValidateHookResult> | ValidateHookResult;
|
|
28
|
+
export interface ExecutionObserver {
|
|
29
|
+
onToolDecision?(decision: ToolDecision, signal?: AbortSignal): Promise<void> | void;
|
|
30
|
+
onPolicyDecision?(decision: PolicyDecision, signal?: AbortSignal): Promise<void> | void;
|
|
31
|
+
onValidatorDecision?(decision: ValidatorEvidence, signal?: AbortSignal): Promise<void> | void;
|
|
32
|
+
onProofReference?(reference: ProofReference, signal?: AbortSignal): Promise<void> | void;
|
|
33
|
+
}
|
|
28
34
|
export interface ExecBridgeOptions {
|
|
29
35
|
/** Working directory the agent edits and git is measured in. */
|
|
30
36
|
cwd: string;
|
|
@@ -60,7 +66,7 @@ export interface ExecBridgeOptions {
|
|
|
60
66
|
/**
|
|
61
67
|
* Run the agent in a throwaway git worktree of `cwd` instead of the repo's real working tree (finding #39.4):
|
|
62
68
|
* the agent's edits land in an isolated checkout, never touching the user's working tree. The diff is measured
|
|
63
|
-
* there, captured as a patch (proof.
|
|
69
|
+
* there, captured as a patch (proof.git_diff.patch_ref), and the worktree is removed. `cwd` must be a git repo.
|
|
64
70
|
*/
|
|
65
71
|
isolation?: 'worktree';
|
|
66
72
|
/**
|
|
@@ -74,12 +80,20 @@ export interface ExecBridgeOptions {
|
|
|
74
80
|
timeoutMs?: number;
|
|
75
81
|
/** Cooperative cancellation propagated to the runner process tree. */
|
|
76
82
|
signal?: AbortSignal;
|
|
83
|
+
/** Binding hard limits are intersected with the existing policy/runner controls; never widen local safety. */
|
|
84
|
+
executionLimits?: {
|
|
85
|
+
maxRuntimeMs: number;
|
|
86
|
+
maxFiles: number;
|
|
87
|
+
maxLines: number;
|
|
88
|
+
};
|
|
77
89
|
/** Optional: enrich the prompt with the selected gene's strategy. */
|
|
78
90
|
resolveGene?: GeneResolver;
|
|
79
91
|
/** Optional: validation commands surfaced in the prompt's done-criteria. */
|
|
80
92
|
validationCmds?: readonly string[];
|
|
81
93
|
/** Optional: authoritative success decision after the agent runs. Falls back to "agent ok + produced a diff". */
|
|
82
94
|
validate?: ValidateHook;
|
|
95
|
+
/** Bound execution provenance observer. Failures are authoritative and fail the execution closed. */
|
|
96
|
+
executionObserver?: ExecutionObserver;
|
|
83
97
|
/**
|
|
84
98
|
* Optional evolvable personality (use-case ①): when set, the agent prompt gets a behavioral-style block
|
|
85
99
|
* rendered from the store's CURRENT persisted state. CycleEngine's applySelectForRun has already run and
|
|
@@ -143,6 +157,14 @@ export declare function scrubAgentEnv(env: NodeJS.ProcessEnv, opts?: {
|
|
|
143
157
|
allowKeys?: readonly string[];
|
|
144
158
|
allowPrefixes?: readonly string[];
|
|
145
159
|
}): NodeJS.ProcessEnv;
|
|
160
|
+
/**
|
|
161
|
+
* 绑定执行不能接受无法收到权威截止时间取消信号的旧验证器或写入器。
|
|
162
|
+
* AbortSignal 本身是协作式的;先拒绝不暴露该信号的回调,避免旧 hook
|
|
163
|
+
* 被静默地当作无界工作运行。
|
|
164
|
+
*/
|
|
165
|
+
export declare class ExecBridgeCancellationContractError extends Error {
|
|
166
|
+
constructor(hook: 'validate' | 'gitPatchWriter');
|
|
167
|
+
}
|
|
146
168
|
/** Default git runner: every incomplete command result fails closed. */
|
|
147
169
|
export declare const defaultGitRunner: GitRunner;
|
|
148
170
|
export declare const defaultGitPatchWriter: GitPatchWriter;
|