mindforge-cc 11.0.0 → 11.2.1
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/.agent/hooks/mindforge-statusline.js +2 -2
- package/.mindforge/config.json +14 -4
- package/CHANGELOG.md +137 -0
- package/MINDFORGE.md +5 -5
- package/RELEASENOTES.md +1 -1
- package/bin/autonomous/audit-writer.js +108 -86
- package/bin/autonomous/auto-runner.js +304 -19
- package/bin/autonomous/dependency-dag.js +59 -0
- package/bin/autonomous/mesh-self-healer.js +101 -28
- package/bin/autonomous/wave-executor.js +20 -1
- package/bin/browser/regression-writer.js +45 -3
- package/bin/browser/session-manager.js +21 -17
- package/bin/council-cli.js +161 -0
- package/bin/dashboard/approval-handler.js +3 -1
- package/bin/dashboard/server.js +1 -1
- package/bin/dashboard/sse-bridge.js +9 -12
- package/bin/engine/council-runtime.js +124 -0
- package/bin/engine/logic-drift-detector.js +14 -6
- package/bin/engine/logic-validator.js +155 -25
- package/bin/engine/orbital-guardian.js +56 -10
- package/bin/engine/otel-exporter.js +123 -0
- package/bin/engine/reason-source-aligner.js +19 -6
- package/bin/engine/remediation-engine.js +1 -1
- package/bin/engine/self-corrective-synthesizer.js +1 -1
- package/bin/engine/sre-manager.js +33 -6
- package/bin/engine/temporal-cli.js +4 -2
- package/bin/engine/verification-runner.js +131 -0
- package/bin/engine/verify-cli.js +34 -0
- package/bin/eval/eval-harness.js +82 -0
- package/bin/eval/golden-set-retrieval.json +46 -0
- package/bin/governance/audit-hash.js +12 -0
- package/bin/governance/audit-verifier.js +60 -0
- package/bin/governance/policy-engine.js +17 -4
- package/bin/governance/quantum-crypto.js +63 -9
- package/bin/governance/ztai-archiver.js +74 -9
- package/bin/governance/ztai-manager.js +33 -5
- package/bin/hindsight-injector.js +5 -6
- package/bin/hooks/instinct-capture-hook.js +186 -0
- package/bin/installer-core.js +31 -2
- package/bin/memory/auto-shadow.js +32 -3
- package/bin/memory/eis-client.js +45 -4
- package/bin/memory/identity-synthesizer.js +2 -2
- package/bin/memory/knowledge-store.js +30 -6
- package/bin/memory/retrieval-fusion.js +58 -0
- package/bin/memory/semantic-hub.js +2 -2
- package/bin/memory/vector-hub.js +143 -6
- package/bin/mindforge-cli.js +4 -5
- package/bin/models/anthropic-provider.js +13 -4
- package/bin/models/cost-tracker.js +3 -1
- package/bin/models/difficulty-scorer.js +54 -0
- package/bin/models/gemini-provider.js +6 -2
- package/bin/models/model-router.js +31 -18
- package/bin/models/openai-provider.js +6 -3
- package/bin/models/pricing-registry.js +128 -0
- package/bin/review/ads-engine.js +1 -1
- package/bin/review/finding-synthesizer.js +35 -6
- package/bin/security/trust-boundaries.js +194 -0
- package/bin/security/trust-gate-hook.js +49 -0
- package/bin/skill-registry.js +34 -22
- package/bin/skills-builder/marketplace-cli.js +5 -3
- package/bin/skills-builder/skill-registrar.js +4 -6
- package/bin/sre/sentinel.js +7 -5
- package/bin/sre/shadow-mirror.js +90 -40
- package/bin/utils/append-queue.js +67 -0
- package/bin/utils/file-io.js +29 -80
- package/bin/utils/version-check.js +75 -0
- package/bin/verify-audit.js +12 -0
- package/bin/wizard/theme.js +1 -2
- package/package.json +1 -1
- package/bin/dashboard/team-tracker.js +0 -0
package/bin/utils/file-io.js
CHANGED
|
@@ -3,56 +3,46 @@
|
|
|
3
3
|
const fs = require('fs');
|
|
4
4
|
const fsp = require('fs/promises');
|
|
5
5
|
const path = require('path');
|
|
6
|
-
const crypto = require('crypto');
|
|
7
|
-
const zlib = require('zlib');
|
|
8
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Hash-chained audit writer (class API preserved for nexus-tracer + policy-engine).
|
|
9
|
+
*
|
|
10
|
+
* UC-04b: this class previously maintained a SECOND, DIVERGENT chain implementation
|
|
11
|
+
* (it hashed {...entry, timestamp, previous_hash} — injecting timestamp into the
|
|
12
|
+
* material differently from the canonical writer), so entries it wrote could never
|
|
13
|
+
* verify against bin/governance/audit-verifier.js. It now delegates every write to
|
|
14
|
+
* the SINGLE shared `appendAuditEntrySync` (canonical hashAuditEntry, synchronous +
|
|
15
|
+
* fsync-durable), so there is ONE hasher and ONE on-disk chain per file.
|
|
16
|
+
*
|
|
17
|
+
* The async API (write/flush/close returning promises) is kept because callers do
|
|
18
|
+
* `await this._auditWriter.write(entry)`; the underlying append is now synchronous
|
|
19
|
+
* and durable, so flush()/close() are no-ops retained for API compatibility.
|
|
20
|
+
*/
|
|
9
21
|
class AuditWriter {
|
|
10
22
|
constructor(filePath) {
|
|
11
23
|
this._path = filePath;
|
|
12
|
-
|
|
13
|
-
|
|
24
|
+
// Retained for API compatibility; the unified append is synchronous so there
|
|
25
|
+
// is no longer an internal buffer or timer to manage.
|
|
14
26
|
this._lastHash = null;
|
|
15
27
|
}
|
|
16
28
|
|
|
17
|
-
write(entry) {
|
|
18
|
-
//
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
this._lastHash = crypto.createHash('sha256').update(serialized).digest('hex');
|
|
26
|
-
entryWithHash._hash = this._lastHash;
|
|
27
|
-
|
|
28
|
-
this._buffer.push(JSON.stringify(entryWithHash));
|
|
29
|
-
|
|
30
|
-
if (this._buffer.length >= 10) {
|
|
31
|
-
return this.flush();
|
|
32
|
-
}
|
|
33
|
-
if (!this._flushTimer) {
|
|
34
|
-
this._flushTimer = setTimeout(() => this.flush(), 100);
|
|
35
|
-
}
|
|
36
|
-
return Promise.resolve();
|
|
29
|
+
async write(entry) {
|
|
30
|
+
// Lazy require (not module-top-level) to keep this leaf utility free of a
|
|
31
|
+
// load-time dependency on the autonomous layer and avoid any future require
|
|
32
|
+
// cycle: bin/autonomous/audit-writer.js is the canonical durable-append site.
|
|
33
|
+
const { appendAuditEntrySync } = require('../autonomous/audit-writer');
|
|
34
|
+
const chained = appendAuditEntrySync(this._path, entry);
|
|
35
|
+
this._lastHash = chained._hash;
|
|
36
|
+
return chained;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
async flush() {
|
|
40
|
-
if (this._buffer.length === 0) return;
|
|
41
|
-
clearTimeout(this._flushTimer);
|
|
42
|
-
this._flushTimer = null;
|
|
39
|
+
async flush() { /* no-op: appendAuditEntrySync is synchronous + fsync-durable */ }
|
|
43
40
|
|
|
44
|
-
|
|
45
|
-
const content = lines.join('\n') + '\n';
|
|
46
|
-
|
|
47
|
-
await fsp.mkdir(path.dirname(this._path), { recursive: true });
|
|
48
|
-
await fsp.appendFile(this._path, content);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
async close() {
|
|
52
|
-
await this.flush();
|
|
53
|
-
}
|
|
41
|
+
async close() { /* no-op: nothing buffered */ }
|
|
54
42
|
|
|
55
43
|
async initLastHash() {
|
|
44
|
+
// The unified append seeds its own chain head from the file tail; this remains
|
|
45
|
+
// for callers that expect to prime _lastHash explicitly.
|
|
56
46
|
try {
|
|
57
47
|
const content = await fsp.readFile(this._path, 'utf8');
|
|
58
48
|
const lines = content.trim().split('\n').filter(Boolean);
|
|
@@ -120,45 +110,4 @@ async function atomicWriteJSONAsync(filePath, data) {
|
|
|
120
110
|
await fsp.rename(tmpPath, filePath);
|
|
121
111
|
}
|
|
122
112
|
|
|
123
|
-
|
|
124
|
-
constructor(options = {}) {
|
|
125
|
-
this.maxLines = options.maxLines || 5000;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
shouldRotate(filePath) {
|
|
129
|
-
if (!fs.existsSync(filePath)) return false;
|
|
130
|
-
const content = fs.readFileSync(filePath, 'utf8');
|
|
131
|
-
const lineCount = content.split('\n').filter(l => l.trim()).length;
|
|
132
|
-
return lineCount >= this.maxLines;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
rotate(filePath, archiveDir) {
|
|
136
|
-
const dir = archiveDir || path.join(path.dirname(filePath), '..', 'audit-archive');
|
|
137
|
-
if (!fs.existsSync(dir)) {
|
|
138
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
142
|
-
const baseName = path.basename(filePath, path.extname(filePath));
|
|
143
|
-
const archiveName = `${baseName}-${timestamp}.jsonl.gz`;
|
|
144
|
-
const archivePath = path.join(dir, archiveName);
|
|
145
|
-
|
|
146
|
-
// Crash-safe: write archive FIRST, then truncate source
|
|
147
|
-
const content = fs.readFileSync(filePath);
|
|
148
|
-
const compressed = zlib.gzipSync(content);
|
|
149
|
-
fs.writeFileSync(archivePath, compressed);
|
|
150
|
-
|
|
151
|
-
const lines = content.toString('utf8').split('\n').filter(l => l.trim());
|
|
152
|
-
const carryover = lines.slice(-100).join('\n') + '\n';
|
|
153
|
-
const tmpPath = filePath + '.tmp.' + process.pid;
|
|
154
|
-
const fd = fs.openSync(tmpPath, 'w');
|
|
155
|
-
fs.writeSync(fd, carryover);
|
|
156
|
-
fs.fsyncSync(fd);
|
|
157
|
-
fs.closeSync(fd);
|
|
158
|
-
fs.renameSync(tmpPath, filePath);
|
|
159
|
-
|
|
160
|
-
return archivePath;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
module.exports = { AuditWriter, AuditRotator, readJSON, writeJSON, readJSONL, readJSONSync, atomicWriteJSON, atomicWriteJSONAsync };
|
|
113
|
+
module.exports = { AuditWriter, readJSON, writeJSON, readJSONL, readJSONSync, atomicWriteJSON, atomicWriteJSONAsync };
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/**
|
|
3
|
+
* MindForge version single-source-of-truth + drift detector.
|
|
4
|
+
* package.json is canonical; everything else must agree.
|
|
5
|
+
*/
|
|
6
|
+
const fs = require('fs');
|
|
7
|
+
const path = require('path');
|
|
8
|
+
// Use the repo's stricter reader: returns null only on ENOENT and RE-THROWS on
|
|
9
|
+
// parse errors. Re-throwing on a corrupt JSON source is the fail-closed
|
|
10
|
+
// behavior we want — a file we cannot parse means we cannot establish truth.
|
|
11
|
+
const { readJSONSync } = require('./file-io');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Extracts `[VERSION] = X` from MINDFORGE.md. Returns null when the file is
|
|
15
|
+
* absent or the marker is missing (treated as skip, not drift).
|
|
16
|
+
*/
|
|
17
|
+
function readMindforgeMdVersion(projectRoot) {
|
|
18
|
+
const mdPath = path.join(projectRoot, 'MINDFORGE.md');
|
|
19
|
+
if (!fs.existsSync(mdPath)) return null;
|
|
20
|
+
const text = fs.readFileSync(mdPath, 'utf8');
|
|
21
|
+
const match = text.match(/\[VERSION\]\s*=\s*([^\s]+)/);
|
|
22
|
+
return match ? match[1].trim() : null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @param {string} projectRoot
|
|
27
|
+
* @returns {{ canonical: string|null, sources: Record<string,string|null>, drift: string[] }}
|
|
28
|
+
*/
|
|
29
|
+
function checkVersionConsistency(projectRoot) {
|
|
30
|
+
const pkg = readJSONSync(path.join(projectRoot, 'package.json'));
|
|
31
|
+
const canonical = pkg ? pkg.version : null;
|
|
32
|
+
|
|
33
|
+
const configJson = readJSONSync(path.join(projectRoot, '.mindforge', 'config.json'));
|
|
34
|
+
const sdkPkg = readJSONSync(path.join(projectRoot, 'sdk', 'package.json'));
|
|
35
|
+
const mindforgeMdVersion = readMindforgeMdVersion(projectRoot);
|
|
36
|
+
// Runtime coverage now spans every source the test suite knows about, so
|
|
37
|
+
// drift in any of them halts `auto` — not just the live config. Absent
|
|
38
|
+
// optional sources (no sdk/, no MINDFORGE.md) read as null and are SKIPPED
|
|
39
|
+
// (not counted as drift); only a present-but-mismatched source flags drift.
|
|
40
|
+
const sources = {
|
|
41
|
+
'package.json': canonical,
|
|
42
|
+
'.mindforge/config.json': configJson ? configJson.version : null,
|
|
43
|
+
'sdk/package.json': sdkPkg ? sdkPkg.version : null,
|
|
44
|
+
'MINDFORGE.md': mindforgeMdVersion,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const drift = [];
|
|
48
|
+
// Fail-closed: if we cannot establish the canonical version (package.json
|
|
49
|
+
// missing or its `version` field absent), treat it as a drift/error condition
|
|
50
|
+
// rather than silently passing. A genuinely corrupt package.json would have
|
|
51
|
+
// already thrown out of readJSONSync above.
|
|
52
|
+
if (!canonical) {
|
|
53
|
+
drift.push('package.json version could not be determined (canonical source missing or unparseable)');
|
|
54
|
+
return { canonical, sources, drift };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
for (const [file, version] of Object.entries(sources)) {
|
|
58
|
+
if (version && version !== canonical) {
|
|
59
|
+
drift.push(`${file} declares ${version} but canonical (package.json) is ${canonical}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return { canonical, sources, drift };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Fail-closed assertion for pre-flight. Throws on drift.
|
|
67
|
+
*/
|
|
68
|
+
function assertVersionConsistency(projectRoot) {
|
|
69
|
+
const { drift } = checkVersionConsistency(projectRoot);
|
|
70
|
+
if (drift.length > 0) {
|
|
71
|
+
throw new Error('Version drift detected (fail-closed):\n - ' + drift.join('\n - '));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
module.exports = { checkVersionConsistency, assertVersionConsistency };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
const { verifyAuditChain } = require('./governance/audit-verifier');
|
|
4
|
+
const auditPath = process.argv[2] || '.planning/AUDIT.jsonl';
|
|
5
|
+
const result = verifyAuditChain(auditPath);
|
|
6
|
+
if (result.valid) {
|
|
7
|
+
process.stdout.write(`✅ audit chain valid: ${result.count} entries\n`);
|
|
8
|
+
process.exit(0);
|
|
9
|
+
} else {
|
|
10
|
+
process.stderr.write(`❌ audit chain BROKEN at entry ${result.brokenAt}: ${result.reason}\n`);
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
package/bin/wizard/theme.js
CHANGED
|
@@ -177,8 +177,7 @@ const Theme = {
|
|
|
177
177
|
},
|
|
178
178
|
|
|
179
179
|
// --- Aliases for legacy compatibility ---
|
|
180
|
-
status(label, state) { this.printStatus(label, state); }
|
|
181
|
-
printSuccess(runtime, scope, stats) { this.printSuccessV2(runtime, scope, stats); }
|
|
180
|
+
status(label, state) { this.printStatus(label, state); }
|
|
182
181
|
};
|
|
183
182
|
|
|
184
183
|
module.exports = Theme;
|
package/package.json
CHANGED
|
File without changes
|