mindforge-cc 5.3.0 → 5.6.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/CHANGELOG.md +46 -0
- package/RELEASENOTES.md +12 -0
- package/bin/engine/nexus-tracer.js +67 -1
- package/bin/engine/temporal-hindsight.js +27 -0
- package/bin/governance/impact-analyzer.js +32 -8
- package/bin/memory/federated-sync.js +113 -27
- package/bin/skill-registry.js +66 -1
- package/bin/skill-validator.js +27 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,51 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [5.6.0] - 2026-03-28
|
|
4
|
+
### Added
|
|
5
|
+
- **Pillar IV: Supply Chain Trust (Binary Runtime Attestation)**.
|
|
6
|
+
- Cryptographic skill signing in `SkillRegistry` via ZTAIManager Tier 3 Enclaves.
|
|
7
|
+
- JIT Attestation in `SkillValidator` to verify skill integrity before agent execution.
|
|
8
|
+
- `SIGNATURES.json` tracking for all enterprise-grade skills.
|
|
9
|
+
|
|
10
|
+
## [5.5.0] - 2026-03-28
|
|
11
|
+
### Added
|
|
12
|
+
- **Pillar III: Predictive Agentic Reliability (Reasoning Entropy Monitoring)**.
|
|
13
|
+
- Reasoning Entropy Scoring (RES) in `NexusTracer` to detect semantic stagnation and loops.
|
|
14
|
+
- Proactive Self-Healing trigger for high-similarity thought sequences.
|
|
15
|
+
- Steering Vector generation in `TemporalHindsight` to break agentic deadlocks.
|
|
16
|
+
|
|
17
|
+
## [5.4.0] — Beast Mode Hardening — 2026-03-28
|
|
18
|
+
|
|
19
|
+
# Release Notes - MindForge v5.6.0 "Sentinel Execution"
|
|
20
|
+
|
|
21
|
+
MindForge v5.6.0 introduces the final pillars of the Hyper-Enterprise roadmap: Proactive Reliability and Zero-Trust Skill Execution.
|
|
22
|
+
|
|
23
|
+
## Highlights
|
|
24
|
+
- **Reasoning Entropy Monitoring (PAR)**: Proactively prevents token-burning reasoning loops.
|
|
25
|
+
- **Binary Runtime Attestation (ZTS)**: Cryptographically ensures that skills have not been tampered with before they are loaded by the agent.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## [5.6.0] - Sentinel Execution
|
|
30
|
+
- Implemented JIT Attestation for Skill Registry.
|
|
31
|
+
- Added Skill Signing utility in `mindforge-cc sign`.
|
|
32
|
+
|
|
33
|
+
## [5.5.0] - Predictive Reliability
|
|
34
|
+
- Implemented RES (Reasoning Entropy Scoring) in Nexus Tracer.
|
|
35
|
+
- Added Steering Vector injection for proactive loop breaking.
|
|
36
|
+
|
|
37
|
+
🚀 **MindForge v5.4.0 — Enterprise Resilience (Hardened Edition)**
|
|
38
|
+
|
|
39
|
+
This update elevates the v5.3.0 "Hyper-Enterprise" features to maximum robustness ("Beast Mode"), implementing critical safety systems and advanced observability.
|
|
40
|
+
|
|
41
|
+
### 🛡️ Beast Mode Hardening (v5.4.0)
|
|
42
|
+
|
|
43
|
+
- **Circuit Breaker Pattern**: Implemented a stateful `CircuitBreaker` in `federated-sync.js` to prevent network floods. Automatically disables mesh sync for 1 hour after 3 consecutive EIS failures.
|
|
44
|
+
- **Critical-Path Protection**: Automated "Blast Radius" score of 100 in `impact-analyzer.js` for sensitive files (`.env`, `*.pem`, `id_rsa`, `package-lock.json`, etc.).
|
|
45
|
+
- **Recursive Depth Penalty**: Introduced a 1.5x impact multiplier for actions deeper than 5 directory levels, preventing mass-scale silent modifications.
|
|
46
|
+
- **Failure Telemetry**: Added `sync-history.jsonl` and `sync-telemetry.jsonl` for detailed conflict resolution and error auditability.
|
|
47
|
+
- **Resilient Execution**: Raised default scores for `EXECUTE` and `GRANT` actions to increase governance oversight.
|
|
48
|
+
|
|
3
49
|
## [5.3.0] — Dynamic Blast Radius — 2026-03-28
|
|
4
50
|
|
|
5
51
|
🚀 **MindForge v5.3.0 — Pillar II Implementation (APO v2)**
|
package/RELEASENOTES.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
# MindForge v5.4.0 — Beast Mode Hardening
|
|
2
|
+
## Top Summary
|
|
3
|
+
The v5.4.0 release elevates the "Hyper-Enterprise" features to maximum robustness ("Beast Mode"), implementing critical safety systems, automated blast-radius protection for sensitive files, and advanced failure telemetry.
|
|
4
|
+
|
|
5
|
+
## Highlights
|
|
6
|
+
- **Circuit Breaker Pattern**: Stateful resilience in `federated-sync.js` to prevent network floods during outages.
|
|
7
|
+
- **Critical-Path Protection**: Automated "Blast Radius" score of 100 for high-risk files (secrets, locks, audits).
|
|
8
|
+
- **Depth-Aware Governance**: 1.5x impact multiplier for deep directory modifications to prevent mass-scale silent regressions.
|
|
9
|
+
- **Enhanced Observability**: Detailed conflict resolution and sync telemetry logs for enterprise auditing.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
1
13
|
# MindForge v5.3.0 — Dynamic Blast Radius
|
|
2
14
|
## Top Summary
|
|
3
15
|
The v5.3.0 release introduces real-time impact analysis and automated risk-based guardrails for agentic actions, preventing architectural regressions and accidental deletions.
|
|
@@ -21,6 +21,10 @@ class NexusTracer {
|
|
|
21
21
|
this.enableZtai = config.enableZtai !== false;
|
|
22
22
|
this.sreManager = new SREManager();
|
|
23
23
|
|
|
24
|
+
// v5 Pillar III: Reasoning Entropy Monitoring (RES)
|
|
25
|
+
this.RES_THRESHOLD = 0.8; // Similarity threshold for stagnation
|
|
26
|
+
this.entropyCache = new Map(); // spanId -> [thoughtHistories]
|
|
27
|
+
|
|
24
28
|
// v5 Pillar IV: Agentic SBOM
|
|
25
29
|
this.sbom = {
|
|
26
30
|
manifest_version: '1.0.0',
|
|
@@ -123,12 +127,74 @@ class NexusTracer {
|
|
|
123
127
|
sanitizedThought = this.sreManager.sanitizeThoughtChain(thought, span.attributes.enclave_id);
|
|
124
128
|
}
|
|
125
129
|
|
|
130
|
+
// v5 Pillar III: PES (Proactive Equilibrium Scoring)
|
|
131
|
+
const entropy = this.calculateEntropy(spanId, sanitizedThought);
|
|
132
|
+
const isStagnant = entropy > this.RES_THRESHOLD;
|
|
133
|
+
|
|
126
134
|
this._recordEvent('reasoning_trace', {
|
|
127
135
|
span_id: spanId,
|
|
128
136
|
agent,
|
|
129
137
|
thought: sanitizedThought,
|
|
130
|
-
resolution
|
|
138
|
+
resolution,
|
|
139
|
+
entropy: parseFloat(entropy.toFixed(4)),
|
|
140
|
+
is_stagnant: isStagnant
|
|
131
141
|
});
|
|
142
|
+
|
|
143
|
+
if (isStagnant) {
|
|
144
|
+
const history = this.entropyCache.get(spanId) || [];
|
|
145
|
+
const stagnationCount = history.filter(h => h.entropy > this.RES_THRESHOLD).length;
|
|
146
|
+
|
|
147
|
+
if (stagnationCount >= 3) {
|
|
148
|
+
this._recordEvent('vulnerability_detected', {
|
|
149
|
+
span_id: spanId,
|
|
150
|
+
type: 'REASONING_LOOP',
|
|
151
|
+
severity: 'HIGH',
|
|
152
|
+
description: 'Agent reasoning entropy dropped below threshold (stagnation detected). Triggering proactive RCA.',
|
|
153
|
+
entropy_score: entropy
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// Signal proactive recovery
|
|
157
|
+
this.recordSelfHeal(spanId, {
|
|
158
|
+
type: 'PROACTIVE_RCA',
|
|
159
|
+
cause: 'REASONING_STAGNATION',
|
|
160
|
+
suggestion: 'Entropy threshold exceeded. Switch reasoning strategy.'
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Calculates "Reasoning Entropy" (Similarity to previous thoughts).
|
|
168
|
+
* Range 0.0 (High Entropy/New) to 1.0 (Low Entropy/Repetitive).
|
|
169
|
+
*/
|
|
170
|
+
calculateEntropy(spanId, currentThought) {
|
|
171
|
+
if (!this.entropyCache.has(spanId)) {
|
|
172
|
+
this.entropyCache.set(spanId, []);
|
|
173
|
+
}
|
|
174
|
+
const history = this.entropyCache.get(spanId);
|
|
175
|
+
|
|
176
|
+
if (history.length === 0) {
|
|
177
|
+
history.push({ thought: currentThought, entropy: 0 });
|
|
178
|
+
return 0;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Simple Jaccard Similarity approach for stagnation detection
|
|
182
|
+
const getTokens = (str) => new Set(str.toLowerCase().split(/\s+/).filter(t => t.length > 3));
|
|
183
|
+
const currentTokens = getTokens(currentThought);
|
|
184
|
+
|
|
185
|
+
let maxSimilarity = 0;
|
|
186
|
+
for (const prev of history) {
|
|
187
|
+
const prevTokens = getTokens(prev.thought);
|
|
188
|
+
const intersection = new Set([...currentTokens].filter(x => prevTokens.has(x)));
|
|
189
|
+
const union = new Set([...currentTokens, ...prevTokens]);
|
|
190
|
+
const similarity = union.size === 0 ? 0 : intersection.size / union.size;
|
|
191
|
+
if (similarity > maxSimilarity) maxSimilarity = similarity;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
history.push({ thought: currentThought, entropy: maxSimilarity });
|
|
195
|
+
if (history.length > 5) history.shift(); // Sliding window of 5 thoughts
|
|
196
|
+
|
|
197
|
+
return maxSimilarity;
|
|
132
198
|
}
|
|
133
199
|
|
|
134
200
|
/**
|
|
@@ -83,6 +83,33 @@ class TemporalHindsight {
|
|
|
83
83
|
autoApplyStatus: 'PENDING_SIGNATURE',
|
|
84
84
|
};
|
|
85
85
|
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* v5 Pillar III: Proactive Loop Recovery
|
|
89
|
+
* Generates a "Steering Vector" to break agentic Reasoning Stagnation.
|
|
90
|
+
*/
|
|
91
|
+
handleProactiveRecovery(traceId, entropyScore) {
|
|
92
|
+
console.log(`[TemporalHindsight] Proactive Recovery triggered for trace ${traceId} (Entropy: ${entropyScore})`);
|
|
93
|
+
|
|
94
|
+
const steeringVectors = [
|
|
95
|
+
"CRITICAL: Stagnation detected. You have repeated similar reasoning steps 3 times. STOP your current approach and decompose the problem into smaller, independent sub-tasks.",
|
|
96
|
+
"STATIONARY LOOP: Your recent thoughts show high similarity. Change your technical layer—if you were editing code, try running a diagnostic command instead.",
|
|
97
|
+
"REASONING DEADLOCK: Entropy too low. Request human intervention or switch to the 'Architect' persona to re-evaluate the plan.",
|
|
98
|
+
"DIVERGENCE ALERT: Proactive reset. Clear your context window of the last 3 reasoning steps and start fresh from the last successful checkpoint."
|
|
99
|
+
];
|
|
100
|
+
|
|
101
|
+
// Pick a vector based on entropy severity
|
|
102
|
+
const index = Math.min(Math.floor(entropyScore * steeringVectors.length), steeringVectors.length - 1);
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
timestamp: new Date().toISOString(),
|
|
106
|
+
trace_id: traceId,
|
|
107
|
+
event: 'STEERING_VECTOR_GENERATED',
|
|
108
|
+
entropy: entropyScore,
|
|
109
|
+
instruction: steeringVectors[index],
|
|
110
|
+
action: 'INJECT_SYSTEM_PROMPT'
|
|
111
|
+
};
|
|
112
|
+
}
|
|
86
113
|
}
|
|
87
114
|
|
|
88
115
|
module.exports = TemporalHindsight;
|
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* MindForge v5.
|
|
2
|
+
* MindForge v5.4.0 — Impact Analyzer (Hardened Edition)
|
|
3
3
|
* Calculates the 'Blast Radius' score of a proposed intent.
|
|
4
4
|
*/
|
|
5
5
|
'use strict';
|
|
6
6
|
|
|
7
7
|
class ImpactAnalyzer {
|
|
8
|
+
static CRITICAL_PATHS = [
|
|
9
|
+
'.env',
|
|
10
|
+
'id_rsa',
|
|
11
|
+
'*.pem',
|
|
12
|
+
'package-lock.json',
|
|
13
|
+
'yarn.lock',
|
|
14
|
+
'AUDIT.jsonl',
|
|
15
|
+
'STATE.md'
|
|
16
|
+
];
|
|
17
|
+
|
|
8
18
|
static SENSITIVE_NAMESPACES = [
|
|
9
19
|
'.mindforge',
|
|
10
20
|
'bin/',
|
|
11
21
|
'config/',
|
|
12
|
-
'.
|
|
22
|
+
'.agent/',
|
|
13
23
|
'security/'
|
|
14
24
|
];
|
|
15
25
|
|
|
@@ -17,30 +27,44 @@ class ImpactAnalyzer {
|
|
|
17
27
|
'READ': 1,
|
|
18
28
|
'WRITE': 5,
|
|
19
29
|
'DELETE': 10,
|
|
20
|
-
'EXECUTE': 8
|
|
21
|
-
'GRANT': 15
|
|
30
|
+
'EXECUTE': 15, // Raised from 8
|
|
31
|
+
'GRANT': 20 // Raised from 15
|
|
22
32
|
};
|
|
23
33
|
|
|
24
34
|
/**
|
|
25
|
-
* Scores an intent based on action type
|
|
35
|
+
* Scores an intent based on action type, target path sensitivity, and recursion depth.
|
|
26
36
|
* Score Range: 0 - 100
|
|
27
37
|
*/
|
|
28
38
|
static analyze(intent) {
|
|
29
39
|
const { action, target, namespace } = intent;
|
|
30
40
|
|
|
41
|
+
// 1. Critical Path Protection (Score 100)
|
|
42
|
+
const isCritical = this.CRITICAL_PATHS.some(cp =>
|
|
43
|
+
(target && (target.endsWith(cp) || target.includes(`/${cp}`)))
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
if (isCritical && (action === 'WRITE' || action === 'DELETE')) {
|
|
47
|
+
return 100; // Automatic CRITICAL block
|
|
48
|
+
}
|
|
49
|
+
|
|
31
50
|
let score = this.ACTION_SCORES[action] || 5;
|
|
32
51
|
|
|
33
|
-
//
|
|
52
|
+
// 2. Sensitive Namespace Multiplier
|
|
34
53
|
const isSensitive = this.SENSITIVE_NAMESPACES.some(ns =>
|
|
35
54
|
(target && target.includes(ns)) || (namespace && namespace.includes(ns))
|
|
36
55
|
);
|
|
37
56
|
|
|
38
57
|
if (isSensitive) {
|
|
39
|
-
score *= 4;
|
|
58
|
+
score *= 4;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// 3. Recursive Depth Penalty (Beast Mode)
|
|
62
|
+
if (target && target.split('/').length > 5) {
|
|
63
|
+
score *= 1.5; // Deeper actions are riskier (mass-scale silent mods)
|
|
40
64
|
}
|
|
41
65
|
|
|
42
66
|
// Cap the score at 100
|
|
43
|
-
return Math.min(score, 100);
|
|
67
|
+
return Math.min(Math.round(score), 100);
|
|
44
68
|
}
|
|
45
69
|
|
|
46
70
|
/**
|
|
@@ -17,6 +17,56 @@ class FederatedSync {
|
|
|
17
17
|
this.client = new EISClient(config);
|
|
18
18
|
this.localStore = Store;
|
|
19
19
|
this.syncHistoryPath = path.join(Store.getPaths().MEMORY_DIR, 'sync-history.jsonl');
|
|
20
|
+
this.circuitBreakerPath = path.join(Store.getPaths().MEMORY_DIR, 'circuit-breaker.json');
|
|
21
|
+
this.MAX_FAILURES = 3;
|
|
22
|
+
this.COOLDOWN_MS = 3600000; // 1 hour
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* [BEAST] Checks if the circuit is open.
|
|
27
|
+
*/
|
|
28
|
+
isCircuitOpen() {
|
|
29
|
+
if (!fs.existsSync(this.circuitBreakerPath)) return false;
|
|
30
|
+
try {
|
|
31
|
+
const state = JSON.parse(fs.readFileSync(this.circuitBreakerPath, 'utf8'));
|
|
32
|
+
if (state.status === 'OPEN' && (Date.now() - state.trippedAt < this.COOLDOWN_MS)) {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
// Reset if cooldown passed
|
|
36
|
+
if (state.status === 'OPEN') {
|
|
37
|
+
this.resetCircuit();
|
|
38
|
+
}
|
|
39
|
+
return false;
|
|
40
|
+
} catch {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
tripCircuit(reason) {
|
|
46
|
+
console.warn(`[BEAST] ⚠️ Circuit Breaker TRIPPED: ${reason}. Mesh sync disabled for 1hr.`);
|
|
47
|
+
const state = { status: 'OPEN', trippedAt: Date.now(), reason };
|
|
48
|
+
fs.writeFileSync(this.circuitBreakerPath, JSON.stringify(state, null, 2));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
resetCircuit() {
|
|
52
|
+
if (fs.existsSync(this.circuitBreakerPath)) {
|
|
53
|
+
fs.unlinkSync(this.circuitBreakerPath);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
handleSyncFailure(err) {
|
|
58
|
+
const statsPath = path.join(this.localStore.getPaths().MEMORY_DIR, 'sync-stats.json');
|
|
59
|
+
let stats = { failures: 0 };
|
|
60
|
+
if (fs.existsSync(statsPath)) {
|
|
61
|
+
stats = JSON.parse(fs.readFileSync(statsPath, 'utf8'));
|
|
62
|
+
}
|
|
63
|
+
stats.failures = (stats.failures || 0) + 1;
|
|
64
|
+
stats.last_error = err.message;
|
|
65
|
+
fs.writeFileSync(statsPath, JSON.stringify(stats, null, 2));
|
|
66
|
+
|
|
67
|
+
if (stats.failures >= this.MAX_FAILURES) {
|
|
68
|
+
this.tripCircuit(err.message);
|
|
69
|
+
}
|
|
20
70
|
}
|
|
21
71
|
|
|
22
72
|
/**
|
|
@@ -24,37 +74,58 @@ class FederatedSync {
|
|
|
24
74
|
* This pushes local high-confidence entries and pulls new organizational knowledge.
|
|
25
75
|
*/
|
|
26
76
|
async fullSync() {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const localEntries = this.localStore.readAll(false).filter(e => e.confidence > 0.8 && !e.deprecated);
|
|
31
|
-
|
|
32
|
-
// 2. Filter out already synced entries
|
|
33
|
-
const unsynced = localEntries.filter(e => !e.global && !this.isRecentlySynced(e.id));
|
|
34
|
-
|
|
35
|
-
// 3. Push to EIS
|
|
36
|
-
if (unsynced.length > 0) {
|
|
37
|
-
const auth = await this.client.getAuthHeader('push', 'kb/global');
|
|
38
|
-
const results = await this.client.push(unsynced, { headers: auth });
|
|
39
|
-
this.logSyncEvent(results);
|
|
77
|
+
if (this.isCircuitOpen()) {
|
|
78
|
+
console.warn('🛑 Federated Intelligence Sync: Circuit is OPEN. Skipping network calls.');
|
|
79
|
+
return { status: 'CIRCUIT_OPEN' };
|
|
40
80
|
}
|
|
81
|
+
|
|
82
|
+
console.log('🔄 Initiating Federated Intelligence Sync (v5.4.0 BEAST)...');
|
|
41
83
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
84
|
+
try {
|
|
85
|
+
// 1. Get promotable entries (Tiers 1-3)
|
|
86
|
+
const localEntries = this.localStore.readAll(false).filter(e => e.confidence > 0.8 && !e.deprecated);
|
|
87
|
+
|
|
88
|
+
// 2. Filter out already synced entries
|
|
89
|
+
const unsynced = localEntries.filter(e => !e.global && !this.isRecentlySynced(e.id));
|
|
90
|
+
|
|
91
|
+
// 3. Push to EIS
|
|
92
|
+
if (unsynced.length > 0) {
|
|
93
|
+
const auth = await this.client.getAuthHeader('push', 'kb/global');
|
|
94
|
+
const results = await this.client.push(unsynced, { headers: auth });
|
|
95
|
+
this.logSyncEvent(results);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// 4. [HARDEN] Delta Pull from EIS
|
|
99
|
+
const lastSync = this.getLastSyncTimestamp();
|
|
100
|
+
const authPull = await this.client.getAuthHeader('pull', 'kb/global');
|
|
101
|
+
const remoteEntries = await this.client.pull({
|
|
102
|
+
orgId: this.client.orgId,
|
|
103
|
+
since: lastSync,
|
|
104
|
+
headers: authPull
|
|
105
|
+
});
|
|
50
106
|
|
|
51
|
-
|
|
52
|
-
|
|
107
|
+
if (remoteEntries.length > 0) {
|
|
108
|
+
this.mergeRemoteKnowledge(remoteEntries);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
this.updateLastSyncTimestamp();
|
|
112
|
+
this.resetFailures(); // Reset on success
|
|
113
|
+
console.log(`✅ Federated Intelligence Mesh: Sync complete. (Delta since ${lastSync})`);
|
|
114
|
+
return { pushed: unsynced.length, pulled: remoteEntries.length };
|
|
115
|
+
} catch (err) {
|
|
116
|
+
console.error('❌ Federated Intelligence Sync FAILED:', err.message);
|
|
117
|
+
this.handleSyncFailure(err);
|
|
118
|
+
throw err;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
resetFailures() {
|
|
123
|
+
const statsPath = path.join(this.localStore.getPaths().MEMORY_DIR, 'sync-stats.json');
|
|
124
|
+
if (fs.existsSync(statsPath)) {
|
|
125
|
+
const stats = JSON.parse(fs.readFileSync(statsPath, 'utf8'));
|
|
126
|
+
stats.failures = 0;
|
|
127
|
+
fs.writeFileSync(statsPath, JSON.stringify(stats, null, 2));
|
|
53
128
|
}
|
|
54
|
-
|
|
55
|
-
this.updateLastSyncTimestamp();
|
|
56
|
-
console.log(`✅ Federated Intelligence Mesh: Sync complete. (Delta since ${lastSync})`);
|
|
57
|
-
return { pushed: unsynced.length, pulled: remoteEntries.length };
|
|
58
129
|
}
|
|
59
130
|
|
|
60
131
|
getLastSyncTimestamp() {
|
|
@@ -133,6 +204,7 @@ class FederatedSync {
|
|
|
133
204
|
if (similarity > 0.9) {
|
|
134
205
|
if (new Date(remote.timestamp) > new Date(local.timestamp)) {
|
|
135
206
|
this.writeToGlobalKB(remote, globalPath);
|
|
207
|
+
this.logConflictTelemetry(local.id, 'LWW', similarity);
|
|
136
208
|
console.log(` └─ [LWW] Auto-resolved via timestamp.`);
|
|
137
209
|
}
|
|
138
210
|
return;
|
|
@@ -143,6 +215,7 @@ class FederatedSync {
|
|
|
143
215
|
console.log(` └─ [ADS] Triggering Autonomous Knowledge Synthesis...`);
|
|
144
216
|
const merged = await this.triggerADSMerging(local, remote);
|
|
145
217
|
this.writeToGlobalKB(merged, globalPath);
|
|
218
|
+
this.logConflictTelemetry(local.id, 'ADS_MERGE', similarity);
|
|
146
219
|
return;
|
|
147
220
|
}
|
|
148
221
|
|
|
@@ -150,12 +223,25 @@ class FederatedSync {
|
|
|
150
223
|
if (similarity > 0.6) {
|
|
151
224
|
console.log(` └─ [DHH] High disagreement. Triggering Nexus Handover...`);
|
|
152
225
|
this.localStore.markConflict(local.id, remote);
|
|
226
|
+
this.logConflictTelemetry(local.id, 'DHH_HANDOVER', similarity);
|
|
153
227
|
return;
|
|
154
228
|
}
|
|
155
229
|
|
|
156
230
|
// 4. Collision Isolation (< 0.6) - Topic Mismatch
|
|
157
231
|
console.log(` └─ [ISO] Semantic collision (Topic mismatch). Isolating entries.`);
|
|
158
232
|
this.writeToGlobalKB({ ...remote, id: `${remote.id}_collision_${Date.now()}` }, globalPath);
|
|
233
|
+
this.logConflictTelemetry(local.id, 'COLLISION_ISOLATION', similarity);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
logConflictTelemetry(id, resolution, similarity) {
|
|
237
|
+
const telePath = path.join(this.localStore.getPaths().MEMORY_DIR, 'sync-telemetry.jsonl');
|
|
238
|
+
const entry = JSON.stringify({
|
|
239
|
+
id,
|
|
240
|
+
resolution,
|
|
241
|
+
similarity,
|
|
242
|
+
timestamp: new Date().toISOString()
|
|
243
|
+
}) + '\n';
|
|
244
|
+
fs.appendFileSync(telePath, entry);
|
|
159
245
|
}
|
|
160
246
|
|
|
161
247
|
async triggerADSMerging(local, remote) {
|
package/bin/skill-registry.js
CHANGED
|
@@ -19,7 +19,7 @@ function main() {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
// Handle cases where the action might be missing if called incorrectly
|
|
22
|
-
const validActions = ['install', 'register', 'audit'];
|
|
22
|
+
const validActions = ['install', 'register', 'audit', 'sign'];
|
|
23
23
|
if (!validActions.includes(ACTION)) {
|
|
24
24
|
console.error(`❌ Invalid or missing action: ${ACTION}`);
|
|
25
25
|
console.error(` Expected one of: ${validActions.join(', ')}`);
|
|
@@ -36,12 +36,77 @@ function main() {
|
|
|
36
36
|
case 'audit':
|
|
37
37
|
handleAudit();
|
|
38
38
|
break;
|
|
39
|
+
case 'sign':
|
|
40
|
+
handleSign();
|
|
41
|
+
break;
|
|
39
42
|
default:
|
|
40
43
|
console.error(`❌ Unknown action: ${ACTION}`);
|
|
41
44
|
process.exit(1);
|
|
42
45
|
}
|
|
43
46
|
}
|
|
44
47
|
|
|
48
|
+
async function handleSign() {
|
|
49
|
+
const skillName = ARGS[1];
|
|
50
|
+
const ztai = require('./governance/ztai-manager');
|
|
51
|
+
const crypto = require('node:crypto');
|
|
52
|
+
|
|
53
|
+
if (!skillName) {
|
|
54
|
+
console.error('❌ Missing skill name to sign');
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Find the skill file
|
|
59
|
+
const bases = [
|
|
60
|
+
'.mindforge/skills',
|
|
61
|
+
'.mindforge/org/skills',
|
|
62
|
+
'.mindforge/project-skills'
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
let targetPath = null;
|
|
66
|
+
for (const base of bases) {
|
|
67
|
+
const p = path.join(process.cwd(), base, skillName, 'SKILL.md');
|
|
68
|
+
if (fs.existsSync(p)) {
|
|
69
|
+
targetPath = p;
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (!targetPath) {
|
|
75
|
+
console.error(`❌ Skill ${skillName} not found in any registry path.`);
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
console.log(`🛡️ Signing skill: ${skillName}...`);
|
|
80
|
+
const content = fs.readFileSync(targetPath, 'utf8');
|
|
81
|
+
const hash = crypto.createHash('sha256').update(content).digest('hex');
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
// We use a dedicated System DID for skill signing (Tier 3)
|
|
85
|
+
const systemDid = await ztai.registerAgent('MindForge-System-Secretary', 3);
|
|
86
|
+
const signature = await ztai.signData(systemDid, hash);
|
|
87
|
+
|
|
88
|
+
const sigPath = path.join(process.cwd(), '.mindforge', 'org', 'skills', 'SIGNATURES.json');
|
|
89
|
+
let signatures = {};
|
|
90
|
+
if (fs.existsSync(sigPath)) {
|
|
91
|
+
signatures = JSON.parse(fs.readFileSync(sigPath, 'utf8'));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
signatures[skillName] = {
|
|
95
|
+
hash,
|
|
96
|
+
signature,
|
|
97
|
+
did: systemDid,
|
|
98
|
+
timestamp: new Date().toISOString()
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
fs.writeFileSync(sigPath, JSON.stringify(signatures, null, 2));
|
|
102
|
+
console.log(`✅ Skill ${skillName} signed and registered in SIGNATURES.json`);
|
|
103
|
+
process.exit(0);
|
|
104
|
+
} catch (err) {
|
|
105
|
+
console.error(`❌ Signing failed: ${err.message}`);
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
45
110
|
function handleInstall() {
|
|
46
111
|
const skillName = ARGS[1];
|
|
47
112
|
const tierFlag = ARGS.indexOf('--tier');
|
package/bin/skill-validator.js
CHANGED
|
@@ -38,7 +38,33 @@ function main() {
|
|
|
38
38
|
console.log('─'.repeat(60));
|
|
39
39
|
|
|
40
40
|
const content = fs.readFileSync(filePath, 'utf8');
|
|
41
|
-
const results = { schema: [], content: [], quality: [], valid: true };
|
|
41
|
+
const results = { schema: [], content: [], quality: [], valid: true, attestation: { ok: true, msg: 'No signature found (optional)' } };
|
|
42
|
+
|
|
43
|
+
// ── Level 0: Binary Runtime Attestation (v5 Pillar IV) ──────────────────────
|
|
44
|
+
const sigPath = path.join(process.cwd(), '.mindforge', 'org', 'skills', 'SIGNATURES.json');
|
|
45
|
+
if (fs.existsSync(sigPath)) {
|
|
46
|
+
const crypto = require('node:crypto');
|
|
47
|
+
const ztai = require('./governance/ztai-manager');
|
|
48
|
+
const signatures = JSON.parse(fs.readFileSync(sigPath, 'utf8'));
|
|
49
|
+
const skillNameCandidate = path.basename(path.dirname(filePath));
|
|
50
|
+
const sigRecord = signatures[skillNameCandidate];
|
|
51
|
+
|
|
52
|
+
if (sigRecord) {
|
|
53
|
+
const currentHash = crypto.createHash('sha256').update(content).digest('hex');
|
|
54
|
+
const isHashValid = currentHash === sigRecord.hash;
|
|
55
|
+
const isSigValid = ztai.verifySignature(sigRecord.did, currentHash, sigRecord.signature);
|
|
56
|
+
|
|
57
|
+
if (!isHashValid || !isSigValid) {
|
|
58
|
+
results.attestation = { ok: false, msg: `INTEGRITY FAILURE: Signature mismatch [Hash: ${isHashValid}, Sig: ${isSigValid}]` };
|
|
59
|
+
results.valid = false;
|
|
60
|
+
} else {
|
|
61
|
+
results.attestation = { ok: true, msg: `VERIFIED: Signed by ${sigRecord.did}` };
|
|
62
|
+
}
|
|
63
|
+
} else if (ARGS.includes('--enterprise')) {
|
|
64
|
+
results.attestation = { ok: false, msg: 'REQUIRED: No signature found for this skill in Enterprise Mode' };
|
|
65
|
+
results.valid = false;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
42
68
|
|
|
43
69
|
// ── Level 1: Schema ─────────────────────────────────────────────────────────
|
|
44
70
|
const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
|