agentic-qe 3.7.21 → 3.8.0
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/.claude/helpers/brain-checkpoint.cjs +4 -1
- package/.claude/helpers/statusline-v3.cjs +3 -1
- package/.claude/skills/skills-manifest.json +1 -1
- package/CHANGELOG.md +45 -0
- package/README.md +2 -14
- package/assets/helpers/statusline-v3.cjs +3 -1
- package/dist/cli/brain-commands.js +6 -10
- package/dist/cli/bundle.js +7441 -4327
- package/dist/cli/commands/audit.d.ts +43 -0
- package/dist/cli/commands/audit.js +125 -0
- package/dist/cli/commands/hooks.js +29 -6
- package/dist/cli/commands/init.js +1 -73
- package/dist/cli/commands/learning.js +270 -13
- package/dist/cli/commands/ruvector-commands.d.ts +15 -0
- package/dist/cli/commands/ruvector-commands.js +271 -0
- package/dist/cli/handlers/init-handler.d.ts +0 -1
- package/dist/cli/handlers/init-handler.js +0 -6
- package/dist/cli/index.js +4 -2
- package/dist/context/sources/defect-source.js +2 -2
- package/dist/context/sources/memory-source.js +2 -2
- package/dist/context/sources/requirements-source.js +2 -2
- package/dist/coordination/behavior-tree/decorators.d.ts +108 -0
- package/dist/coordination/behavior-tree/decorators.js +251 -0
- package/dist/coordination/behavior-tree/index.d.ts +12 -0
- package/dist/coordination/behavior-tree/index.js +15 -0
- package/dist/coordination/behavior-tree/nodes.d.ts +165 -0
- package/dist/coordination/behavior-tree/nodes.js +338 -0
- package/dist/coordination/behavior-tree/qe-trees.d.ts +105 -0
- package/dist/coordination/behavior-tree/qe-trees.js +181 -0
- package/dist/coordination/coherence-action-gate.d.ts +284 -0
- package/dist/coordination/coherence-action-gate.js +512 -0
- package/dist/coordination/index.d.ts +4 -0
- package/dist/coordination/index.js +8 -0
- package/dist/coordination/reasoning-qec.d.ts +315 -0
- package/dist/coordination/reasoning-qec.js +585 -0
- package/dist/coordination/task-executor.d.ts +16 -0
- package/dist/coordination/task-executor.js +99 -0
- package/dist/coordination/workflow-orchestrator.d.ts +29 -0
- package/dist/coordination/workflow-orchestrator.js +42 -0
- package/dist/domains/visual-accessibility/cnn-visual-regression.d.ts +135 -0
- package/dist/domains/visual-accessibility/cnn-visual-regression.js +327 -0
- package/dist/domains/visual-accessibility/index.d.ts +1 -0
- package/dist/domains/visual-accessibility/index.js +4 -0
- package/dist/governance/coherence-validator.d.ts +112 -0
- package/dist/governance/coherence-validator.js +180 -0
- package/dist/governance/index.d.ts +1 -0
- package/dist/governance/index.js +2 -0
- package/dist/governance/witness-chain.d.ts +311 -0
- package/dist/governance/witness-chain.js +509 -0
- package/dist/init/index.d.ts +0 -2
- package/dist/init/index.js +0 -1
- package/dist/init/init-wizard-steps.d.ts +10 -0
- package/dist/init/init-wizard-steps.js +87 -1
- package/dist/init/init-wizard.d.ts +1 -9
- package/dist/init/init-wizard.js +3 -69
- package/dist/init/orchestrator.js +0 -1
- package/dist/init/phases/01-detection.js +0 -27
- package/dist/init/phases/07-hooks.js +6 -4
- package/dist/init/phases/phase-interface.d.ts +0 -1
- package/dist/init/settings-merge.js +1 -1
- package/dist/integrations/browser/qe-dashboard/clustering.d.ts +48 -0
- package/dist/integrations/browser/qe-dashboard/clustering.js +183 -0
- package/dist/integrations/browser/qe-dashboard/index.d.ts +12 -0
- package/dist/integrations/browser/qe-dashboard/index.js +15 -0
- package/dist/integrations/browser/qe-dashboard/pattern-explorer.d.ts +165 -0
- package/dist/integrations/browser/qe-dashboard/pattern-explorer.js +260 -0
- package/dist/integrations/browser/qe-dashboard/wasm-vector-store.d.ts +144 -0
- package/dist/integrations/browser/qe-dashboard/wasm-vector-store.js +277 -0
- package/dist/integrations/ruvector/cognitive-container-codec.d.ts +51 -0
- package/dist/integrations/ruvector/cognitive-container-codec.js +180 -0
- package/dist/integrations/ruvector/cognitive-container.d.ts +125 -0
- package/dist/integrations/ruvector/cognitive-container.js +306 -0
- package/dist/integrations/ruvector/coherence-gate.d.ts +309 -0
- package/dist/integrations/ruvector/coherence-gate.js +631 -0
- package/dist/integrations/ruvector/compressed-hnsw-integration.d.ts +176 -0
- package/dist/integrations/ruvector/compressed-hnsw-integration.js +301 -0
- package/dist/integrations/ruvector/dither-adapter.d.ts +122 -0
- package/dist/integrations/ruvector/dither-adapter.js +295 -0
- package/dist/integrations/ruvector/domain-transfer.d.ts +129 -0
- package/dist/integrations/ruvector/domain-transfer.js +220 -0
- package/dist/integrations/ruvector/feature-flags.d.ts +214 -2
- package/dist/integrations/ruvector/feature-flags.js +167 -2
- package/dist/integrations/ruvector/filter-adapter.d.ts +71 -0
- package/dist/integrations/ruvector/filter-adapter.js +285 -0
- package/dist/integrations/ruvector/gnn-wrapper.d.ts +20 -0
- package/dist/integrations/ruvector/gnn-wrapper.js +40 -0
- package/dist/integrations/ruvector/hnsw-health-monitor.d.ts +237 -0
- package/dist/integrations/ruvector/hnsw-health-monitor.js +394 -0
- package/dist/integrations/ruvector/index.d.ts +8 -2
- package/dist/integrations/ruvector/index.js +18 -2
- package/dist/integrations/ruvector/interfaces.d.ts +40 -0
- package/dist/integrations/ruvector/sona-persistence.d.ts +54 -0
- package/dist/integrations/ruvector/sona-persistence.js +162 -0
- package/dist/integrations/ruvector/sona-three-loop.d.ts +392 -0
- package/dist/integrations/ruvector/sona-three-loop.js +814 -0
- package/dist/integrations/ruvector/sona-wrapper.d.ts +97 -0
- package/dist/integrations/ruvector/sona-wrapper.js +147 -3
- package/dist/integrations/ruvector/spectral-math.d.ts +101 -0
- package/dist/integrations/ruvector/spectral-math.js +254 -0
- package/dist/integrations/ruvector/temporal-compression.d.ts +163 -0
- package/dist/integrations/ruvector/temporal-compression.js +318 -0
- package/dist/integrations/ruvector/thompson-sampler.d.ts +61 -0
- package/dist/integrations/ruvector/thompson-sampler.js +118 -0
- package/dist/integrations/ruvector/transfer-coherence-stub.d.ts +80 -0
- package/dist/integrations/ruvector/transfer-coherence-stub.js +63 -0
- package/dist/integrations/ruvector/transfer-verification.d.ts +119 -0
- package/dist/integrations/ruvector/transfer-verification.js +115 -0
- package/dist/kernel/hnsw-adapter.d.ts +52 -1
- package/dist/kernel/hnsw-adapter.js +139 -4
- package/dist/kernel/hnsw-index-provider.d.ts +5 -0
- package/dist/kernel/native-hnsw-backend.d.ts +110 -0
- package/dist/kernel/native-hnsw-backend.js +408 -0
- package/dist/kernel/unified-memory.js +5 -6
- package/dist/learning/aqe-learning-engine.d.ts +2 -0
- package/dist/learning/aqe-learning-engine.js +65 -0
- package/dist/learning/experience-capture-middleware.js +20 -0
- package/dist/learning/experience-capture.d.ts +10 -0
- package/dist/learning/experience-capture.js +34 -0
- package/dist/learning/index.d.ts +2 -2
- package/dist/learning/index.js +4 -4
- package/dist/learning/metrics-tracker.d.ts +11 -0
- package/dist/learning/metrics-tracker.js +29 -13
- package/dist/learning/pattern-lifecycle.d.ts +30 -1
- package/dist/learning/pattern-lifecycle.js +92 -20
- package/dist/learning/pattern-store.d.ts +8 -0
- package/dist/learning/pattern-store.js +8 -2
- package/dist/learning/qe-unified-memory.js +1 -28
- package/dist/learning/regret-tracker.d.ts +201 -0
- package/dist/learning/regret-tracker.js +361 -0
- package/dist/mcp/bundle.js +5915 -474
- package/dist/routing/index.d.ts +4 -2
- package/dist/routing/index.js +3 -1
- package/dist/routing/neural-tiny-dancer-router.d.ts +268 -0
- package/dist/routing/neural-tiny-dancer-router.js +514 -0
- package/dist/routing/queen-integration.js +5 -5
- package/dist/routing/routing-config.d.ts +6 -0
- package/dist/routing/routing-config.js +1 -0
- package/dist/routing/simple-neural-router.d.ts +76 -0
- package/dist/routing/simple-neural-router.js +202 -0
- package/dist/routing/tiny-dancer-router.d.ts +20 -1
- package/dist/routing/tiny-dancer-router.js +21 -2
- package/dist/test-scheduling/dag-attention-scheduler.d.ts +81 -0
- package/dist/test-scheduling/dag-attention-scheduler.js +358 -0
- package/dist/test-scheduling/dag-attention-types.d.ts +81 -0
- package/dist/test-scheduling/dag-attention-types.js +10 -0
- package/dist/test-scheduling/index.d.ts +1 -0
- package/dist/test-scheduling/index.js +4 -0
- package/dist/test-scheduling/pipeline.d.ts +8 -0
- package/dist/test-scheduling/pipeline.js +28 -0
- package/package.json +6 -2
- package/dist/cli/commands/migrate.d.ts +0 -9
- package/dist/cli/commands/migrate.js +0 -566
- package/dist/init/init-wizard-migration.d.ts +0 -52
- package/dist/init/init-wizard-migration.js +0 -345
- package/dist/init/migration/config-migrator.d.ts +0 -31
- package/dist/init/migration/config-migrator.js +0 -149
- package/dist/init/migration/data-migrator.d.ts +0 -72
- package/dist/init/migration/data-migrator.js +0 -232
- package/dist/init/migration/detector.d.ts +0 -44
- package/dist/init/migration/detector.js +0 -105
- package/dist/init/migration/index.d.ts +0 -8
- package/dist/init/migration/index.js +0 -8
- package/dist/learning/v2-to-v3-migration.d.ts +0 -86
- package/dist/learning/v2-to-v3-migration.js +0 -529
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Witness Chain - Hash-Linked Audit Trail for Quality Gate Decisions
|
|
3
|
+
*
|
|
4
|
+
* Implements an append-only, hash-linked witness log for quality gate decisions.
|
|
5
|
+
* Each receipt is cryptographically chained to its predecessor using SHA-256,
|
|
6
|
+
* creating a tamper-evident audit trail.
|
|
7
|
+
*
|
|
8
|
+
* Features:
|
|
9
|
+
* - Append-only witness log with SHA-256 hash linking
|
|
10
|
+
* - Chain integrity verification with tamper detection
|
|
11
|
+
* - SPRT (Sequential Probability Ratio Test) evidence accumulation
|
|
12
|
+
* - Export/import for brain transfer
|
|
13
|
+
* - Feature-flag gated via useWitnessChain
|
|
14
|
+
*
|
|
15
|
+
* @module governance/witness-chain
|
|
16
|
+
* @see ADR-083-coherence-gated-agent-actions.md
|
|
17
|
+
*/
|
|
18
|
+
import { createHash, randomUUID } from 'crypto';
|
|
19
|
+
import { LoggerFactory } from '../logging/index.js';
|
|
20
|
+
import { getRuVectorFeatureFlags } from '../integrations/ruvector/feature-flags.js';
|
|
21
|
+
const logger = LoggerFactory.create('witness-chain');
|
|
22
|
+
// ============================================================================
|
|
23
|
+
// SPRT Accumulator
|
|
24
|
+
// ============================================================================
|
|
25
|
+
/**
|
|
26
|
+
* Sequential Probability Ratio Test accumulator for Pass/Fail decisions.
|
|
27
|
+
*
|
|
28
|
+
* Simplified sequential decision rule with configurable evidence strength.
|
|
29
|
+
* For production use, strength should reflect log-likelihood ratio of the
|
|
30
|
+
* observation under the alternative vs null hypothesis.
|
|
31
|
+
*
|
|
32
|
+
* Accumulates evidence over a sequence of observations to decide between
|
|
33
|
+
* two hypotheses (Pass vs Fail) with controlled error rates.
|
|
34
|
+
*
|
|
35
|
+
* Boundaries:
|
|
36
|
+
* - Upper bound (accept H1 / PASS): ln(1/alpha)
|
|
37
|
+
* - Lower bound (accept H0 / FAIL): ln(beta)
|
|
38
|
+
*
|
|
39
|
+
* Default evidence step: +0.5 for positive, -0.5 for negative.
|
|
40
|
+
* Use addWeightedEvidence() for variable-strength observations.
|
|
41
|
+
*/
|
|
42
|
+
export class SPRTAccumulator {
|
|
43
|
+
logLikelihoodRatio = 0;
|
|
44
|
+
upperBound;
|
|
45
|
+
lowerBound;
|
|
46
|
+
observations = 0;
|
|
47
|
+
/**
|
|
48
|
+
* @param alpha - Type I error rate (false positive). Default: 0.05
|
|
49
|
+
* @param beta - Type II error rate (false negative). Default: 0.05
|
|
50
|
+
*/
|
|
51
|
+
constructor(alpha = 0.05, beta = 0.05) {
|
|
52
|
+
this.upperBound = Math.log(1 / alpha);
|
|
53
|
+
this.lowerBound = Math.log(beta);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Add a weighted observation and return the current decision.
|
|
57
|
+
*
|
|
58
|
+
* The strength parameter controls the log-likelihood step size.
|
|
59
|
+
* For production use, strength should reflect the log-likelihood ratio
|
|
60
|
+
* of the observation under the alternative vs null hypothesis.
|
|
61
|
+
*
|
|
62
|
+
* @param positive - Whether this observation is positive evidence
|
|
63
|
+
* @param strength - Evidence strength (step size). Default 0.5 for backward compat.
|
|
64
|
+
* @returns Current decision: PASS, FAIL, or INCONCLUSIVE
|
|
65
|
+
*/
|
|
66
|
+
addWeightedEvidence(positive, strength) {
|
|
67
|
+
this.logLikelihoodRatio += positive ? strength : -strength;
|
|
68
|
+
this.observations++;
|
|
69
|
+
if (this.logLikelihoodRatio >= this.upperBound)
|
|
70
|
+
return 'PASS';
|
|
71
|
+
if (this.logLikelihoodRatio <= this.lowerBound)
|
|
72
|
+
return 'FAIL';
|
|
73
|
+
return 'INCONCLUSIVE';
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Add an observation with default strength (0.5) and return the current decision.
|
|
77
|
+
*
|
|
78
|
+
* @param positive - Whether this observation is positive evidence
|
|
79
|
+
* @returns Current decision: PASS, FAIL, or INCONCLUSIVE
|
|
80
|
+
*/
|
|
81
|
+
addEvidence(positive) {
|
|
82
|
+
return this.addWeightedEvidence(positive, 0.5);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Get the current log-likelihood ratio.
|
|
86
|
+
*/
|
|
87
|
+
getRatio() {
|
|
88
|
+
return this.logLikelihoodRatio;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Get the total number of observations.
|
|
92
|
+
*/
|
|
93
|
+
getObservations() {
|
|
94
|
+
return this.observations;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Get the SPRT boundaries.
|
|
98
|
+
*/
|
|
99
|
+
getBounds() {
|
|
100
|
+
return { upper: this.upperBound, lower: this.lowerBound };
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Reset the accumulator to its initial state.
|
|
104
|
+
*/
|
|
105
|
+
reset() {
|
|
106
|
+
this.logLikelihoodRatio = 0;
|
|
107
|
+
this.observations = 0;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// ============================================================================
|
|
111
|
+
// Witness Chain
|
|
112
|
+
// ============================================================================
|
|
113
|
+
/** Genesis hash: 64 hex zeros */
|
|
114
|
+
const GENESIS_HASH = '0'.repeat(64);
|
|
115
|
+
/**
|
|
116
|
+
* Append-only, hash-linked witness chain for quality gate decisions.
|
|
117
|
+
*
|
|
118
|
+
* Maintains an ordered sequence of witness receipts where each receipt
|
|
119
|
+
* references the hash of its predecessor, forming a tamper-evident chain.
|
|
120
|
+
*
|
|
121
|
+
* @example
|
|
122
|
+
* ```typescript
|
|
123
|
+
* const chain = new WitnessChain();
|
|
124
|
+
* const receipt = chain.appendWitness({
|
|
125
|
+
* type: 'coherence-gate',
|
|
126
|
+
* decision: 'PASS',
|
|
127
|
+
* context: { energy: 0.23, threshold: 0.4 },
|
|
128
|
+
* });
|
|
129
|
+
* const result = chain.verifyChain();
|
|
130
|
+
* console.log(result.valid); // true
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
export class WitnessChain {
|
|
134
|
+
receipts = [];
|
|
135
|
+
lastHash = GENESIS_HASH;
|
|
136
|
+
sprtAccumulators = new Map();
|
|
137
|
+
/**
|
|
138
|
+
* Append a witness decision to the chain.
|
|
139
|
+
*
|
|
140
|
+
* Creates a new receipt hash-linked to the previous receipt and appends
|
|
141
|
+
* it to the chain. Optionally updates the SPRT accumulator for the
|
|
142
|
+
* decision type.
|
|
143
|
+
*
|
|
144
|
+
* @param decision - The decision to witness
|
|
145
|
+
* @returns The new witness receipt with its chain hash
|
|
146
|
+
*/
|
|
147
|
+
appendWitness(decision) {
|
|
148
|
+
const id = randomUUID();
|
|
149
|
+
const timestamp = Date.now();
|
|
150
|
+
const chainIndex = this.receipts.length;
|
|
151
|
+
// Compute receipt hash: SHA-256(previousHash + JSON(decision) + timestamp)
|
|
152
|
+
const hashPayload = this.lastHash + JSON.stringify(decision) + timestamp;
|
|
153
|
+
const hash = createHash('sha256').update(hashPayload).digest('hex');
|
|
154
|
+
const receipt = {
|
|
155
|
+
id,
|
|
156
|
+
timestamp,
|
|
157
|
+
previousHash: this.lastHash,
|
|
158
|
+
hash,
|
|
159
|
+
decision,
|
|
160
|
+
chainIndex,
|
|
161
|
+
};
|
|
162
|
+
this.receipts.push(receipt);
|
|
163
|
+
this.lastHash = hash;
|
|
164
|
+
// Update SPRT accumulator for this decision type
|
|
165
|
+
this.updateSPRT(decision);
|
|
166
|
+
logger.debug('Witness appended', {
|
|
167
|
+
chainIndex,
|
|
168
|
+
type: decision.type,
|
|
169
|
+
decision: decision.decision,
|
|
170
|
+
hash: hash.slice(0, 16) + '...',
|
|
171
|
+
});
|
|
172
|
+
return receipt;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Verify the integrity of the entire witness chain.
|
|
176
|
+
*
|
|
177
|
+
* Walks the chain from genesis to tip, recomputing each receipt's hash
|
|
178
|
+
* and checking it against the stored value. Reports the first breakage.
|
|
179
|
+
*
|
|
180
|
+
* @returns Verification result with validity, length, and break point
|
|
181
|
+
*/
|
|
182
|
+
verifyChain() {
|
|
183
|
+
if (this.receipts.length === 0) {
|
|
184
|
+
return {
|
|
185
|
+
valid: true,
|
|
186
|
+
length: 0,
|
|
187
|
+
brokenAt: -1,
|
|
188
|
+
message: 'Chain is empty (valid)',
|
|
189
|
+
lastHash: GENESIS_HASH,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
let expectedPrevHash = GENESIS_HASH;
|
|
193
|
+
for (let i = 0; i < this.receipts.length; i++) {
|
|
194
|
+
const receipt = this.receipts[i];
|
|
195
|
+
// Check previousHash link
|
|
196
|
+
if (receipt.previousHash !== expectedPrevHash) {
|
|
197
|
+
return {
|
|
198
|
+
valid: false,
|
|
199
|
+
length: this.receipts.length,
|
|
200
|
+
brokenAt: i,
|
|
201
|
+
message: `Chain broken at index ${i}: previousHash mismatch`,
|
|
202
|
+
lastHash: this.lastHash,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
// Recompute hash
|
|
206
|
+
const hashPayload = receipt.previousHash + JSON.stringify(receipt.decision) + receipt.timestamp;
|
|
207
|
+
const expectedHash = createHash('sha256').update(hashPayload).digest('hex');
|
|
208
|
+
if (receipt.hash !== expectedHash) {
|
|
209
|
+
return {
|
|
210
|
+
valid: false,
|
|
211
|
+
length: this.receipts.length,
|
|
212
|
+
brokenAt: i,
|
|
213
|
+
message: `Chain broken at index ${i}: hash mismatch (tamper detected)`,
|
|
214
|
+
lastHash: this.lastHash,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
expectedPrevHash = receipt.hash;
|
|
218
|
+
}
|
|
219
|
+
return {
|
|
220
|
+
valid: true,
|
|
221
|
+
length: this.receipts.length,
|
|
222
|
+
brokenAt: -1,
|
|
223
|
+
message: `Chain valid (${this.receipts.length} receipts)`,
|
|
224
|
+
lastHash: this.lastHash,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Get receipts from the chain.
|
|
229
|
+
*
|
|
230
|
+
* @param limit - Maximum number of receipts to return (from most recent).
|
|
231
|
+
* If omitted, returns the entire chain.
|
|
232
|
+
* @returns Array of witness receipts
|
|
233
|
+
*/
|
|
234
|
+
getChain(limit) {
|
|
235
|
+
if (limit !== undefined && limit > 0) {
|
|
236
|
+
return [...this.receipts.slice(-limit)];
|
|
237
|
+
}
|
|
238
|
+
return [...this.receipts];
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Get the total number of receipts in the chain.
|
|
242
|
+
*/
|
|
243
|
+
getChainLength() {
|
|
244
|
+
return this.receipts.length;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Get the hash of the most recent receipt (chain tip).
|
|
248
|
+
*/
|
|
249
|
+
getLastHash() {
|
|
250
|
+
return this.lastHash;
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Export the chain as a JSON string for brain transfer.
|
|
254
|
+
*
|
|
255
|
+
* @returns JSON string containing the full chain
|
|
256
|
+
*/
|
|
257
|
+
exportChain() {
|
|
258
|
+
const data = {
|
|
259
|
+
version: '1.0.0',
|
|
260
|
+
exportedAt: Date.now(),
|
|
261
|
+
length: this.receipts.length,
|
|
262
|
+
receipts: this.receipts,
|
|
263
|
+
};
|
|
264
|
+
return JSON.stringify(data, null, 2);
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Import a chain from a JSON string.
|
|
268
|
+
*
|
|
269
|
+
* Validates the imported chain integrity before accepting it.
|
|
270
|
+
* Replaces the current chain if valid.
|
|
271
|
+
*
|
|
272
|
+
* @param data - JSON string from exportChain()
|
|
273
|
+
* @returns true if import was successful, false if data was invalid
|
|
274
|
+
*/
|
|
275
|
+
importChain(data) {
|
|
276
|
+
try {
|
|
277
|
+
const parsed = JSON.parse(data);
|
|
278
|
+
// Validate structure
|
|
279
|
+
if (!parsed || parsed.version !== '1.0.0' || !Array.isArray(parsed.receipts)) {
|
|
280
|
+
logger.warn('Import failed: invalid format');
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
// Validate chain integrity before accepting
|
|
284
|
+
const savedReceipts = this.receipts;
|
|
285
|
+
const savedLastHash = this.lastHash;
|
|
286
|
+
this.receipts = parsed.receipts;
|
|
287
|
+
this.lastHash =
|
|
288
|
+
parsed.receipts.length > 0
|
|
289
|
+
? parsed.receipts[parsed.receipts.length - 1].hash
|
|
290
|
+
: GENESIS_HASH;
|
|
291
|
+
const verification = this.verifyChain();
|
|
292
|
+
if (!verification.valid) {
|
|
293
|
+
// Rollback
|
|
294
|
+
this.receipts = savedReceipts;
|
|
295
|
+
this.lastHash = savedLastHash;
|
|
296
|
+
logger.warn('Import failed: chain integrity check failed', {
|
|
297
|
+
message: verification.message,
|
|
298
|
+
});
|
|
299
|
+
return false;
|
|
300
|
+
}
|
|
301
|
+
logger.info('Chain imported successfully', { length: parsed.receipts.length });
|
|
302
|
+
return true;
|
|
303
|
+
}
|
|
304
|
+
catch (error) {
|
|
305
|
+
logger.warn('Import failed: parse error', {
|
|
306
|
+
error: error instanceof Error ? error.message : String(error),
|
|
307
|
+
});
|
|
308
|
+
return false;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Get or create an SPRT accumulator for a decision type.
|
|
313
|
+
*
|
|
314
|
+
* @param type - The decision type (e.g., 'coherence-gate')
|
|
315
|
+
* @param alpha - Type I error rate (default: 0.05)
|
|
316
|
+
* @param beta - Type II error rate (default: 0.05)
|
|
317
|
+
* @returns The SPRT accumulator for the given type
|
|
318
|
+
*/
|
|
319
|
+
getSPRT(type, alpha, beta) {
|
|
320
|
+
if (!this.sprtAccumulators.has(type)) {
|
|
321
|
+
this.sprtAccumulators.set(type, new SPRTAccumulator(alpha, beta));
|
|
322
|
+
}
|
|
323
|
+
return this.sprtAccumulators.get(type);
|
|
324
|
+
}
|
|
325
|
+
/**
|
|
326
|
+
* Get a receipt by chain index.
|
|
327
|
+
*
|
|
328
|
+
* @param index - The chain index (0-based)
|
|
329
|
+
* @returns The receipt at the given index, or undefined if out of range
|
|
330
|
+
*/
|
|
331
|
+
getReceipt(index) {
|
|
332
|
+
return this.receipts[index];
|
|
333
|
+
}
|
|
334
|
+
// ==========================================================================
|
|
335
|
+
// Private Methods
|
|
336
|
+
// ==========================================================================
|
|
337
|
+
/**
|
|
338
|
+
* Update the SPRT accumulator based on the decision.
|
|
339
|
+
*/
|
|
340
|
+
updateSPRT(decision) {
|
|
341
|
+
const positive = decision.decision === 'PASS' || decision.decision === 'PERMIT';
|
|
342
|
+
const accumulator = this.getSPRT(decision.type);
|
|
343
|
+
accumulator.addEvidence(positive);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* SQLite-backed WitnessChain that persists receipts to the unified database.
|
|
348
|
+
*
|
|
349
|
+
* Extends WitnessChain with optional SQLite persistence. When a persistence
|
|
350
|
+
* backend is provided, each witness receipt is written to SQLite on append,
|
|
351
|
+
* and the chain can be restored from SQLite on startup.
|
|
352
|
+
*
|
|
353
|
+
* @example
|
|
354
|
+
* ```typescript
|
|
355
|
+
* const persistence = createWitnessChainSQLitePersistence(db);
|
|
356
|
+
* const chain = createPersistentWitnessChain(persistence);
|
|
357
|
+
* // Chain is automatically loaded from SQLite on creation
|
|
358
|
+
* ```
|
|
359
|
+
*/
|
|
360
|
+
export class PersistentWitnessChain extends WitnessChain {
|
|
361
|
+
persistence;
|
|
362
|
+
constructor(persistence) {
|
|
363
|
+
super();
|
|
364
|
+
this.persistence = persistence;
|
|
365
|
+
// Restore chain from SQLite
|
|
366
|
+
const storedReceipts = persistence.loadAllReceipts();
|
|
367
|
+
if (storedReceipts.length > 0) {
|
|
368
|
+
const exported = {
|
|
369
|
+
version: '1.0.0',
|
|
370
|
+
exportedAt: Date.now(),
|
|
371
|
+
length: storedReceipts.length,
|
|
372
|
+
receipts: storedReceipts,
|
|
373
|
+
};
|
|
374
|
+
const imported = this.importChain(JSON.stringify(exported));
|
|
375
|
+
if (imported) {
|
|
376
|
+
logger.info('Witness chain restored from SQLite', {
|
|
377
|
+
receipts: storedReceipts.length,
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
else {
|
|
381
|
+
logger.warn('Failed to restore witness chain from SQLite — starting fresh');
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Append a witness and persist it to SQLite.
|
|
387
|
+
*/
|
|
388
|
+
appendWitness(decision) {
|
|
389
|
+
const receipt = super.appendWitness(decision);
|
|
390
|
+
try {
|
|
391
|
+
this.persistence.insertReceipt(receipt);
|
|
392
|
+
}
|
|
393
|
+
catch (err) {
|
|
394
|
+
logger.warn('Failed to persist witness receipt to SQLite', {
|
|
395
|
+
chainIndex: receipt.chainIndex,
|
|
396
|
+
error: err instanceof Error ? err.message : String(err),
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
return receipt;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
/**
|
|
403
|
+
* Create a SQLite persistence backend using better-sqlite3.
|
|
404
|
+
*
|
|
405
|
+
* Creates the `witness_chain_receipts` table if it doesn't exist
|
|
406
|
+
* and provides insert/load methods.
|
|
407
|
+
*
|
|
408
|
+
* @param db - better-sqlite3 Database instance (from unified persistence)
|
|
409
|
+
* @returns IWitnessChainPersistence implementation
|
|
410
|
+
*/
|
|
411
|
+
export function createWitnessChainSQLitePersistence(db) {
|
|
412
|
+
// Create table if not exists
|
|
413
|
+
db.exec(`
|
|
414
|
+
CREATE TABLE IF NOT EXISTS witness_chain_receipts (
|
|
415
|
+
id TEXT PRIMARY KEY,
|
|
416
|
+
chain_index INTEGER NOT NULL,
|
|
417
|
+
timestamp INTEGER NOT NULL,
|
|
418
|
+
previous_hash TEXT NOT NULL,
|
|
419
|
+
hash TEXT NOT NULL,
|
|
420
|
+
decision_type TEXT NOT NULL,
|
|
421
|
+
decision_outcome TEXT NOT NULL,
|
|
422
|
+
decision_context TEXT NOT NULL,
|
|
423
|
+
decision_evidence REAL,
|
|
424
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
425
|
+
)
|
|
426
|
+
`);
|
|
427
|
+
db.exec(`
|
|
428
|
+
CREATE INDEX IF NOT EXISTS idx_witness_chain_index
|
|
429
|
+
ON witness_chain_receipts(chain_index)
|
|
430
|
+
`);
|
|
431
|
+
const insertStmt = db.prepare(`
|
|
432
|
+
INSERT OR REPLACE INTO witness_chain_receipts
|
|
433
|
+
(id, chain_index, timestamp, previous_hash, hash,
|
|
434
|
+
decision_type, decision_outcome, decision_context, decision_evidence)
|
|
435
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
436
|
+
`);
|
|
437
|
+
const loadAllStmt = db.prepare(`
|
|
438
|
+
SELECT * FROM witness_chain_receipts ORDER BY chain_index ASC
|
|
439
|
+
`);
|
|
440
|
+
const countStmt = db.prepare(`
|
|
441
|
+
SELECT COUNT(*) as cnt FROM witness_chain_receipts
|
|
442
|
+
`);
|
|
443
|
+
return {
|
|
444
|
+
insertReceipt(receipt) {
|
|
445
|
+
insertStmt.run(receipt.id, receipt.chainIndex, receipt.timestamp, receipt.previousHash, receipt.hash, receipt.decision.type, receipt.decision.decision, JSON.stringify(receipt.decision.context), receipt.decision.evidence ?? null);
|
|
446
|
+
},
|
|
447
|
+
loadAllReceipts() {
|
|
448
|
+
const rows = loadAllStmt.all();
|
|
449
|
+
return rows.map(row => {
|
|
450
|
+
let context = {};
|
|
451
|
+
try {
|
|
452
|
+
context = JSON.parse(row.decision_context);
|
|
453
|
+
}
|
|
454
|
+
catch {
|
|
455
|
+
logger.warn('Corrupt decision_context in witness receipt, using empty object', {
|
|
456
|
+
receiptId: row.id,
|
|
457
|
+
chainIndex: row.chain_index,
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
return {
|
|
461
|
+
id: row.id,
|
|
462
|
+
chainIndex: row.chain_index,
|
|
463
|
+
timestamp: row.timestamp,
|
|
464
|
+
previousHash: row.previous_hash,
|
|
465
|
+
hash: row.hash,
|
|
466
|
+
decision: {
|
|
467
|
+
type: row.decision_type,
|
|
468
|
+
decision: row.decision_outcome,
|
|
469
|
+
context,
|
|
470
|
+
evidence: row.decision_evidence ?? undefined,
|
|
471
|
+
},
|
|
472
|
+
};
|
|
473
|
+
});
|
|
474
|
+
},
|
|
475
|
+
getReceiptCount() {
|
|
476
|
+
const row = countStmt.get();
|
|
477
|
+
return row.cnt;
|
|
478
|
+
},
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
// ============================================================================
|
|
482
|
+
// Factory
|
|
483
|
+
// ============================================================================
|
|
484
|
+
/**
|
|
485
|
+
* Create a new WitnessChain instance (in-memory).
|
|
486
|
+
*
|
|
487
|
+
* @returns A new empty WitnessChain
|
|
488
|
+
*/
|
|
489
|
+
export function createWitnessChain() {
|
|
490
|
+
return new WitnessChain();
|
|
491
|
+
}
|
|
492
|
+
/**
|
|
493
|
+
* Create a SQLite-backed WitnessChain that persists receipts.
|
|
494
|
+
*
|
|
495
|
+
* @param persistence - SQLite persistence backend
|
|
496
|
+
* @returns A PersistentWitnessChain loaded from SQLite
|
|
497
|
+
*/
|
|
498
|
+
export function createPersistentWitnessChain(persistence) {
|
|
499
|
+
return new PersistentWitnessChain(persistence);
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Check if the witness chain feature is enabled.
|
|
503
|
+
*
|
|
504
|
+
* @returns true if the useWitnessChain feature flag is on
|
|
505
|
+
*/
|
|
506
|
+
export function isWitnessChainFeatureEnabled() {
|
|
507
|
+
return getRuVectorFeatureFlags().useWitnessChain;
|
|
508
|
+
}
|
|
509
|
+
//# sourceMappingURL=witness-chain.js.map
|
package/dist/init/index.d.ts
CHANGED
|
@@ -41,6 +41,4 @@ export type { WindsurfInstallerOptions, WindsurfInstallResult } from './windsurf
|
|
|
41
41
|
export { WindsurfInstaller, createWindsurfInstaller } from './windsurf-installer.js';
|
|
42
42
|
export type { ContinueDevInstallerOptions, ContinueDevInstallResult } from './continuedev-installer.js';
|
|
43
43
|
export { ContinueDevInstaller, createContinueDevInstaller } from './continuedev-installer.js';
|
|
44
|
-
export type { V2DetectionInfo, MigrationResult, } from './migration/index.js';
|
|
45
|
-
export { V2Detector, createV2Detector, V2DataMigrator, createV2DataMigrator, V2ConfigMigrator, createV2ConfigMigrator, } from './migration/index.js';
|
|
46
44
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/init/index.js
CHANGED
|
@@ -24,5 +24,4 @@ export { RooCodeInstaller, createRooCodeInstaller } from './roocode-installer.js
|
|
|
24
24
|
export { CodexInstaller, createCodexInstaller } from './codex-installer.js';
|
|
25
25
|
export { WindsurfInstaller, createWindsurfInstaller } from './windsurf-installer.js';
|
|
26
26
|
export { ContinueDevInstaller, createContinueDevInstaller } from './continuedev-installer.js';
|
|
27
|
-
export { V2Detector, createV2Detector, V2DataMigrator, createV2DataMigrator, V2ConfigMigrator, createV2ConfigMigrator, } from './migration/index.js';
|
|
28
27
|
//# sourceMappingURL=index.js.map
|
|
@@ -6,6 +6,16 @@
|
|
|
6
6
|
* Extracted from init-wizard.ts.
|
|
7
7
|
*/
|
|
8
8
|
import type { AQEInitConfig, PretrainedLibrary } from './types.js';
|
|
9
|
+
/**
|
|
10
|
+
* Read AQE version directly from memory.db without full initialization.
|
|
11
|
+
* Returns undefined if no version is stored.
|
|
12
|
+
*/
|
|
13
|
+
export declare function readVersionFromDb(dbPath: string): string | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* Write AQE version to memory.db in _system namespace.
|
|
16
|
+
* Used by init wizard to mark installation version.
|
|
17
|
+
*/
|
|
18
|
+
export declare function writeVersionToDb(projectRoot: string, version: string): Promise<boolean>;
|
|
9
19
|
/**
|
|
10
20
|
* Initialize the persistence database (REQUIRED).
|
|
11
21
|
* Creates the SQLite database file with proper schema.
|
|
@@ -6,12 +6,98 @@
|
|
|
6
6
|
* Extracted from init-wizard.ts.
|
|
7
7
|
*/
|
|
8
8
|
import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
9
|
-
import { join } from 'path';
|
|
9
|
+
import { join, dirname } from 'path';
|
|
10
10
|
import { createSkillsInstaller } from './skills-installer.js';
|
|
11
11
|
import { createAgentsInstaller } from './agents-installer.js';
|
|
12
12
|
import { createN8nInstaller } from './n8n-installer.js';
|
|
13
13
|
import { toErrorMessage } from '../shared/error-utils.js';
|
|
14
14
|
import { openDatabase } from '../shared/safe-db.js';
|
|
15
|
+
import { safeJsonParse } from '../shared/safe-json.js';
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// Version Management
|
|
18
|
+
// ============================================================================
|
|
19
|
+
/**
|
|
20
|
+
* Read AQE version directly from memory.db without full initialization.
|
|
21
|
+
* Returns undefined if no version is stored.
|
|
22
|
+
*/
|
|
23
|
+
export function readVersionFromDb(dbPath) {
|
|
24
|
+
try {
|
|
25
|
+
const db = openDatabase(dbPath, { readonly: true, fileMustExist: true });
|
|
26
|
+
try {
|
|
27
|
+
const tableExists = db.prepare(`
|
|
28
|
+
SELECT name FROM sqlite_master
|
|
29
|
+
WHERE type='table' AND name='kv_store'
|
|
30
|
+
`).get();
|
|
31
|
+
if (!tableExists) {
|
|
32
|
+
db.close();
|
|
33
|
+
return undefined;
|
|
34
|
+
}
|
|
35
|
+
const row = db.prepare(`
|
|
36
|
+
SELECT value FROM kv_store
|
|
37
|
+
WHERE key = 'aqe_version' AND namespace = '_system'
|
|
38
|
+
`).get();
|
|
39
|
+
db.close();
|
|
40
|
+
if (row) {
|
|
41
|
+
return safeJsonParse(row.value);
|
|
42
|
+
}
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
db.close();
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Write AQE version to memory.db in _system namespace.
|
|
56
|
+
* Used by init wizard to mark installation version.
|
|
57
|
+
*/
|
|
58
|
+
export async function writeVersionToDb(projectRoot, version) {
|
|
59
|
+
const memoryDbPath = join(projectRoot, '.agentic-qe', 'memory.db');
|
|
60
|
+
try {
|
|
61
|
+
const dir = dirname(memoryDbPath);
|
|
62
|
+
if (!existsSync(dir)) {
|
|
63
|
+
mkdirSync(dir, { recursive: true });
|
|
64
|
+
}
|
|
65
|
+
const db = openDatabase(memoryDbPath);
|
|
66
|
+
try {
|
|
67
|
+
db.exec(`
|
|
68
|
+
CREATE TABLE IF NOT EXISTS kv_store (
|
|
69
|
+
key TEXT NOT NULL,
|
|
70
|
+
namespace TEXT NOT NULL,
|
|
71
|
+
value TEXT NOT NULL,
|
|
72
|
+
expires_at INTEGER,
|
|
73
|
+
created_at INTEGER DEFAULT (strftime('%s', 'now') * 1000),
|
|
74
|
+
PRIMARY KEY (namespace, key)
|
|
75
|
+
);
|
|
76
|
+
`);
|
|
77
|
+
const now = Date.now();
|
|
78
|
+
db.prepare(`
|
|
79
|
+
INSERT OR REPLACE INTO kv_store (key, namespace, value, created_at)
|
|
80
|
+
VALUES (?, '_system', ?, ?)
|
|
81
|
+
`).run('aqe_version', JSON.stringify(version), now);
|
|
82
|
+
db.prepare(`
|
|
83
|
+
INSERT OR REPLACE INTO kv_store (key, namespace, value, created_at)
|
|
84
|
+
VALUES (?, '_system', ?, ?)
|
|
85
|
+
`).run('init_timestamp', JSON.stringify(new Date().toISOString()), now);
|
|
86
|
+
db.close();
|
|
87
|
+
console.log(` ✓ Version ${version} written to memory.db`);
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
db.close();
|
|
92
|
+
console.warn(` ⚠ Could not write version: ${toErrorMessage(err)}`);
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
catch (err) {
|
|
97
|
+
console.warn(` ⚠ Could not open memory.db: ${toErrorMessage(err)}`);
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
15
101
|
// ============================================================================
|
|
16
102
|
// Persistence Database
|
|
17
103
|
// ============================================================================
|
|
@@ -6,11 +6,9 @@
|
|
|
6
6
|
*
|
|
7
7
|
* This is a facade module. Implementation details are extracted to:
|
|
8
8
|
* - init-wizard-hooks.ts (hook configuration, MCP, CLAUDE.md generation)
|
|
9
|
-
* - init-wizard-
|
|
10
|
-
* - init-wizard-steps.ts (persistence, learning, workers, skills, agents, config)
|
|
9
|
+
* - init-wizard-steps.ts (persistence, learning, workers, skills, agents, config, version)
|
|
11
10
|
*/
|
|
12
11
|
import type { InitResult, WizardStep, PretrainedLibrary } from './types.js';
|
|
13
|
-
export type { V2DetectionResult } from './init-wizard-migration.js';
|
|
14
12
|
export interface InitOrchestratorOptions {
|
|
15
13
|
/** Project root directory */
|
|
16
14
|
projectRoot: string;
|
|
@@ -31,8 +29,6 @@ export interface InitOrchestratorOptions {
|
|
|
31
29
|
baseUrl?: string;
|
|
32
30
|
apiKey?: string;
|
|
33
31
|
};
|
|
34
|
-
/** Automatically migrate from v2 if detected */
|
|
35
|
-
autoMigrate?: boolean;
|
|
36
32
|
}
|
|
37
33
|
export declare class InitOrchestrator {
|
|
38
34
|
private projectRoot;
|
|
@@ -49,10 +45,6 @@ export declare class InitOrchestrator {
|
|
|
49
45
|
* Get wizard steps
|
|
50
46
|
*/
|
|
51
47
|
getWizardSteps(): WizardStep[];
|
|
52
|
-
/**
|
|
53
|
-
* Handle V2 detection - returns early result if migration not auto, null otherwise.
|
|
54
|
-
*/
|
|
55
|
-
private handleV2Detection;
|
|
56
48
|
/**
|
|
57
49
|
* Run a single initialization step with timing and status tracking
|
|
58
50
|
*/
|