mindforge-cc 2.3.5 → 3.0.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/.agent/skills/mindforge-plan-phase/SKILL.md +1 -0
- package/.agent/skills/mindforge-system-architecture/SKILL.md +136 -0
- package/.agent/skills/mindforge-system-architecture/examples.md +120 -0
- package/.agent/skills/mindforge-system-architecture/scaling-checklist.md +76 -0
- package/.agent/skills/mindforge-tdd/SKILL.md +112 -0
- package/.agent/skills/mindforge-tdd/deep-modules.md +21 -0
- package/.agent/skills/mindforge-tdd/interface-design.md +22 -0
- package/.agent/skills/mindforge-tdd/mocking.md +24 -0
- package/.agent/skills/mindforge-tdd/refactoring.md +21 -0
- package/.agent/skills/mindforge-tdd/tests.md +28 -0
- package/.agent/workflows/mindforge-plan-phase.md +30 -1
- package/.agent/workflows/mindforge:architecture.md +40 -0
- package/.agent/workflows/mindforge:executor.md +18 -0
- package/.agent/workflows/mindforge:identity.md +18 -0
- package/.agent/workflows/mindforge:memory.md +18 -0
- package/.agent/workflows/mindforge:planner.md +18 -0
- package/.agent/workflows/mindforge:researcher.md +18 -0
- package/.agent/workflows/mindforge:reviewer.md +18 -0
- package/.agent/workflows/mindforge:tdd.md +41 -0
- package/.agent/workflows/mindforge:tool.md +18 -0
- package/.mindforge/engine/ads-protocol.md +54 -0
- package/.mindforge/engine/compaction-protocol.md +21 -36
- package/.mindforge/engine/context-injector.md +26 -0
- package/.mindforge/engine/knowledge-graph-protocol.md +125 -0
- package/.mindforge/engine/shard-controller.md +53 -0
- package/.mindforge/engine/temporal-protocol.md +40 -0
- package/.mindforge/personas/mf-executor.md +40 -0
- package/.mindforge/personas/mf-memory.md +33 -0
- package/.mindforge/personas/mf-planner.md +45 -0
- package/.mindforge/personas/mf-researcher.md +39 -0
- package/.mindforge/personas/mf-reviewer.md +35 -0
- package/.mindforge/personas/mf-tool.md +33 -0
- package/.planning/AUDIT.jsonl +1 -0
- package/.planning/TEMPORAL-TEST.md +1 -0
- package/.planning/history/36525e1d9da1b674/ARCHITECTURE.md +0 -0
- package/.planning/history/36525e1d9da1b674/HANDOFF.json +8 -0
- package/.planning/history/36525e1d9da1b674/PROJECT.md +33 -0
- package/.planning/history/36525e1d9da1b674/RELEASE-CHECKLIST.md +68 -0
- package/.planning/history/36525e1d9da1b674/REQUIREMENTS.md +0 -0
- package/.planning/history/36525e1d9da1b674/ROADMAP.md +12 -0
- package/.planning/history/36525e1d9da1b674/SNAPSHOT-META.json +18 -0
- package/.planning/history/36525e1d9da1b674/STATE.md +31 -0
- package/.planning/history/36525e1d9da1b674/TEMPORAL-TEST.md +1 -0
- package/.planning/history/36525e1d9da1b674/jira-sync.json +5 -0
- package/.planning/history/36525e1d9da1b674/slack-threads.json +3 -0
- package/.planning/history/test-audit-001/ARCHITECTURE.md +0 -0
- package/.planning/history/test-audit-001/HANDOFF.json +8 -0
- package/.planning/history/test-audit-001/PROJECT.md +33 -0
- package/.planning/history/test-audit-001/RELEASE-CHECKLIST.md +68 -0
- package/.planning/history/test-audit-001/REQUIREMENTS.md +0 -0
- package/.planning/history/test-audit-001/ROADMAP.md +12 -0
- package/.planning/history/test-audit-001/SNAPSHOT-META.json +17 -0
- package/.planning/history/test-audit-001/STATE.md +31 -0
- package/.planning/history/test-audit-001/TEMPORAL-TEST.md +1 -0
- package/.planning/history/test-audit-001/jira-sync.json +5 -0
- package/.planning/history/test-audit-001/slack-threads.json +3 -0
- package/CHANGELOG.md +101 -0
- package/README.md +57 -23
- package/bin/autonomous/auto-runner.js +23 -0
- package/bin/dashboard/server.js +2 -0
- package/bin/dashboard/temporal-api.js +82 -0
- package/bin/engine/temporal-cli.js +52 -0
- package/bin/engine/temporal-hub.js +138 -0
- package/bin/hindsight-injector.js +59 -0
- package/bin/memory/auto-shadow.js +274 -0
- package/bin/memory/embedding-engine.js +326 -0
- package/bin/memory/knowledge-capture.js +122 -5
- package/bin/memory/knowledge-graph.js +572 -0
- package/bin/memory/knowledge-store.js +15 -3
- package/bin/mindforge-cli.js +19 -0
- package/bin/models/model-router.js +1 -0
- package/bin/review/ads-engine.js +126 -0
- package/bin/review/ads-synthesizer.js +117 -0
- package/bin/shard-helper.js +134 -0
- package/bin/spawn-agent.js +61 -0
- package/docs/PERSONAS.md +71 -5
- package/docs/adr/ADR-042-ads-protocol.md +30 -0
- package/docs/architecture/README.md +55 -0
- package/docs/architecture/V3-CORE.md +52 -0
- package/docs/commands-reference.md +3 -2
- package/docs/usp-features.md +33 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,28 +1,38 @@
|
|
|
1
|
-
# MindForge — Enterprise Agentic Framework (
|
|
1
|
+
# MindForge — Enterprise Agentic Framework (v3.0.0-rc1)
|
|
2
2
|
|
|
3
3
|
MindForge turns Claude Code and Antigravity into production-grade engineering
|
|
4
|
-
partners with governance, observability, and a
|
|
5
|
-
Release published:
|
|
4
|
+
partners with governance, observability, and a reactive autonomous intelligence engine.
|
|
5
|
+
Release published: v3.0.0-rc1.
|
|
6
6
|
|
|
7
|
+
# Install
|
|
7
8
|
```bash
|
|
8
9
|
npx mindforge-cc@latest
|
|
9
10
|
```
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
# Install V3 (Latest)
|
|
13
|
+
```bash
|
|
14
|
+
npm install -g mindforge-cc@latest
|
|
15
|
+
```
|
|
12
16
|
|
|
17
|
+
---
|
|
13
18
|
|
|
14
19
|
## Why MindForge
|
|
15
20
|
|
|
16
21
|
AI coding agents degrade over long sessions. Context fills up. Quality drops.
|
|
17
22
|
Decisions get forgotten. MindForge fixes that with:
|
|
18
23
|
|
|
19
|
-
- **Context
|
|
24
|
+
- **Context Sharding (v3)** — relevance-dense memory management (40% token savings)
|
|
25
|
+
- **Adversarial Synthesis (v3)** — zero-drift logic through red/blue model debate
|
|
26
|
+
- **Temporal Vision (v3)** — full history scrubbing and hindsight state repair
|
|
27
|
+
- **RAG 2.0 (v3)** — automatic semantic shadowing for background pattern retrieval
|
|
20
28
|
- **Role personas** — specialised agent modes for each task type
|
|
29
|
+
- **Specialized Identities** — custom `/agents/` workspace with enriched `IDENTITY.md` protocols
|
|
21
30
|
- **Skills** — just-in-time domain knowledge loaded on demand
|
|
22
31
|
- **Wave execution** — parallelism with dependency safety
|
|
23
|
-
- **Autonomous Engine** — walk-away execution with steerability
|
|
24
|
-
- **Real-time Dashboard** — web-based observability
|
|
25
|
-
- **Browser Runtime** — headful/headless visual QA and sessions
|
|
32
|
+
- **Autonomous Engine** — walk-away execution with steerability
|
|
33
|
+
- **Real-time Dashboard** — web-based observability with Temporal Slider
|
|
34
|
+
- **Browser Runtime** — headful/headless visual QA and sessions
|
|
35
|
+
|
|
26
36
|
- **Multi-Model Intelligence** — dynamic routing, adversarial reviews, and deep research (v2)
|
|
27
37
|
- **Persistent Knowledge Graph** — long-term memory across all engineering sessions (v2)
|
|
28
38
|
- **Self-Building Skills** — automatically capture knowledge from any source into reusable skills (v2)
|
|
@@ -55,6 +65,9 @@ npm install -g mindforge-cc
|
|
|
55
65
|
|
|
56
66
|
# Or try the v2.0.0-alpha (latest features)
|
|
57
67
|
npm install -g mindforge-cc@alpha
|
|
68
|
+
|
|
69
|
+
# Or try the V3 Release (latest features)
|
|
70
|
+
npm install -g mindforge-cc@latest
|
|
58
71
|
```
|
|
59
72
|
|
|
60
73
|
|
|
@@ -175,10 +188,11 @@ If issues are found, run:
|
|
|
175
188
|
/mindforge:ui-phase 1
|
|
176
189
|
→ Create UI design contract (UI-SPEC.md) (v2)
|
|
177
190
|
|
|
178
|
-
/mindforge:plan-phase 1
|
|
191
|
+
/mindforge:plan-phase 1 [--ads]
|
|
179
192
|
→ Discuss scope and decisions
|
|
180
193
|
→ Research domain (parallel)
|
|
181
194
|
→ Create atomic XML task plans
|
|
195
|
+
→ (Optional) Run Adversarial Decision Synthesis (ADS) loop
|
|
182
196
|
|
|
183
197
|
/mindforge:execute-phase 1
|
|
184
198
|
→ Wave-based parallel execution
|
|
@@ -265,6 +279,16 @@ If issues are found, run:
|
|
|
265
279
|
|
|
266
280
|
---
|
|
267
281
|
|
|
282
|
+
## Execution Modes
|
|
283
|
+
|
|
284
|
+
MindForge supports multiple interaction models to fit your engineering workflow:
|
|
285
|
+
|
|
286
|
+
- **In-IDE Orchestration**: Use `/mindforge:agent <persona>` for real-time delegation.
|
|
287
|
+
- **Enterprise Workflows**: Specialized commands like `/mindforge:tdd`, `/mindforge:architecture`, and `/mindforge:planner`.
|
|
288
|
+
- **CLI Automation**: Run `node bin/mindforge-cli.js spawn <persona>` for scripted tasks.
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
268
292
|
## Updates and migrations
|
|
269
293
|
```bash
|
|
270
294
|
/mindforge:update
|
|
@@ -317,20 +341,30 @@ See `.mindforge/production/token-optimiser.md`.
|
|
|
317
341
|
|
|
318
342
|
---
|
|
319
343
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
- **
|
|
329
|
-
- **
|
|
330
|
-
- **
|
|
331
|
-
- **
|
|
332
|
-
- **
|
|
333
|
-
|
|
344
|
+
---
|
|
345
|
+
|
|
346
|
+
## What's new in v3.0.0-rc1
|
|
347
|
+
|
|
348
|
+
🚀 **The Reactive Intelligence Era**
|
|
349
|
+
|
|
350
|
+
MindForge V3 transforms the framework from a "disciplined workflow engine" into a **Reactive Autonomous Intelligence**.
|
|
351
|
+
|
|
352
|
+
- **Context Sharding (SRD)**: Achieve a **40% reduction in token waste** via relevance-dense memory management.
|
|
353
|
+
- **Adversarial Decision Synthesis (ADS)**: Zero-drift architectural logic through a 3-model debate and SOUL-scoring engine.
|
|
354
|
+
- **Temporal Vision**: Full-fidelity history navigation, hindsight state injection, and automated repair.
|
|
355
|
+
- **RAG 2.0 (Auto-Shadowing)**: Background pattern retrieval from the local knowledge graph without manual prompts.
|
|
356
|
+
- **V3 Core Guide**: New definitive architecture guide in `docs/architecture/V3-CORE.md`.
|
|
357
|
+
|
|
358
|
+
---
|
|
359
|
+
|
|
360
|
+
## Evolution from v2.x
|
|
361
|
+
|
|
362
|
+
- **Expanded Persona Ecosystem**: 32+ specialized engineering personas.
|
|
363
|
+
- **Real-time Dashboard**: Web-based observability and governance.
|
|
364
|
+
- **Persistent Knowledge Graph**: Long-term project memory across sessions.
|
|
365
|
+
- **Multi-Model Intelligence**: Dynamic routing, adversarial reviews, and deep research.
|
|
366
|
+
- **Visual QA Engine**: Systematic visual audit and regression test generation.
|
|
367
|
+
- **Autonomous Execution**: Walk-away execution with real-time steerability.
|
|
334
368
|
|
|
335
369
|
---
|
|
336
370
|
|
|
@@ -12,6 +12,8 @@ const steeringManager = require('./steer');
|
|
|
12
12
|
const progressStream = require('./progress-stream');
|
|
13
13
|
const headlessAdapter = require('./headless');
|
|
14
14
|
const KnowledgeCapture = require('../memory/knowledge-capture');
|
|
15
|
+
const TemporalHub = require('../engine/temporal-hub');
|
|
16
|
+
const crypto = require('crypto');
|
|
15
17
|
|
|
16
18
|
class AutoRunner {
|
|
17
19
|
constructor(options = {}) {
|
|
@@ -82,8 +84,29 @@ class AutoRunner {
|
|
|
82
84
|
}
|
|
83
85
|
|
|
84
86
|
writeAudit(event) {
|
|
87
|
+
if (!event.id) event.id = crypto.randomBytes(8).toString('hex');
|
|
85
88
|
if (!event.timestamp) event.timestamp = new Date().toISOString();
|
|
89
|
+
|
|
86
90
|
fs.appendFileSync(this.auditPath, JSON.stringify(event) + '\n');
|
|
91
|
+
|
|
92
|
+
// Auto-capture state for significant events
|
|
93
|
+
const STATE_CHANGING_EVENTS = [
|
|
94
|
+
'auto_mode_started',
|
|
95
|
+
'phase_planned',
|
|
96
|
+
'phase_execution_started',
|
|
97
|
+
'task_completed',
|
|
98
|
+
'hindsight_injected',
|
|
99
|
+
'auto_mode_completed'
|
|
100
|
+
];
|
|
101
|
+
|
|
102
|
+
if (STATE_CHANGING_EVENTS.includes(event.event)) {
|
|
103
|
+
TemporalHub.captureState(event.id, {
|
|
104
|
+
agent: event.agent || 'auto-runner',
|
|
105
|
+
event: event.event,
|
|
106
|
+
phase: this.phase
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
87
110
|
const result = this.monitor.analyze(event);
|
|
88
111
|
if (result) this.handleStuck(result);
|
|
89
112
|
}
|
package/bin/dashboard/server.js
CHANGED
|
@@ -33,6 +33,7 @@ try {
|
|
|
33
33
|
|
|
34
34
|
const SSE = require('./sse-bridge');
|
|
35
35
|
const API = require('./api-router');
|
|
36
|
+
const TemporalAPI = require('./temporal-api');
|
|
36
37
|
|
|
37
38
|
// ── Express app ───────────────────────────────────────────────────────────────
|
|
38
39
|
const app = express();
|
|
@@ -84,6 +85,7 @@ app.get('/', (req, res) => {
|
|
|
84
85
|
|
|
85
86
|
// ── Register API routes ───────────────────────────────────────────────────────
|
|
86
87
|
API.register(app);
|
|
88
|
+
app.use('/api/temporal', TemporalAPI);
|
|
87
89
|
|
|
88
90
|
// ── Start SSE bridge ──────────────────────────────────────────────────────────
|
|
89
91
|
SSE.start();
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MindForge v3 — Temporal Dashboard API
|
|
3
|
+
* REST endpoints for time-travel debugging and state exploration.
|
|
4
|
+
*/
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const express = require('express');
|
|
8
|
+
const router = express.Router();
|
|
9
|
+
const TemporalHub = require('../engine/temporal-hub');
|
|
10
|
+
const HindsightInjector = require('../hindsight-injector');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* GET /api/temporal/history
|
|
14
|
+
* Returns the full timeline of state snapshots.
|
|
15
|
+
*/
|
|
16
|
+
router.get('/history', (req, res) => {
|
|
17
|
+
try {
|
|
18
|
+
const history = TemporalHub.getHistory();
|
|
19
|
+
res.json(history);
|
|
20
|
+
} catch (err) {
|
|
21
|
+
res.status(500).json({ error: 'Failed to retrieve temporal history', detail: err.message });
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* GET /api/temporal/snapshot/:auditId/:file
|
|
27
|
+
* Returns the content of a specific file at a specific point in time.
|
|
28
|
+
*/
|
|
29
|
+
router.get('/snapshot/:auditId/:file', (req, res) => {
|
|
30
|
+
try {
|
|
31
|
+
const { auditId, file } = req.params;
|
|
32
|
+
const content = TemporalHub.getSnapshotFile(auditId, file);
|
|
33
|
+
|
|
34
|
+
if (content === null) {
|
|
35
|
+
return res.status(404).json({ error: `File ${file} not found in snapshot ${auditId}` });
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
res.send(content);
|
|
39
|
+
} catch (err) {
|
|
40
|
+
res.status(500).json({ error: 'Failed to retrieve snapshot file', detail: err.message });
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* GET /api/temporal/snapshot/:auditId/meta
|
|
46
|
+
* Returns metadata for a specific snapshot.
|
|
47
|
+
*/
|
|
48
|
+
router.get('/snapshot/:auditId/meta', (req, res) => {
|
|
49
|
+
try {
|
|
50
|
+
const snapshots = TemporalHub.getHistory();
|
|
51
|
+
const snap = snapshots.find(s => s.id === req.params.auditId);
|
|
52
|
+
if (!snap) return res.status(404).json({ error: 'Snapshot not found' });
|
|
53
|
+
res.json(snap);
|
|
54
|
+
} catch (err) {
|
|
55
|
+
res.status(500).json({ error: 'Failed to retrieve snapshot metadata' });
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* POST /api/temporal/inject
|
|
61
|
+
* Triggers a state rollback and hindsight injection.
|
|
62
|
+
*/
|
|
63
|
+
router.post('/inject', async (req, res) => {
|
|
64
|
+
try {
|
|
65
|
+
const { auditId, fixDescription } = req.body;
|
|
66
|
+
|
|
67
|
+
if (!auditId || !fixDescription) {
|
|
68
|
+
return res.status(400).json({ error: 'auditId and fixDescription are required' });
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const result = await HindsightInjector.inject(auditId, fixDescription);
|
|
72
|
+
if (result.success) {
|
|
73
|
+
res.json(result);
|
|
74
|
+
} else {
|
|
75
|
+
res.status(500).json(result);
|
|
76
|
+
}
|
|
77
|
+
} catch (err) {
|
|
78
|
+
res.status(500).json({ error: 'Hindsight injection failed', detail: err.message });
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
module.exports = router;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MindForge v3 — Temporal CLI
|
|
3
|
+
* Command-line interface for managing history and hindsight.
|
|
4
|
+
*/
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const TemporalHub = require('./temporal-hub');
|
|
8
|
+
const HindsightInjector = require('../hindsight-injector');
|
|
9
|
+
|
|
10
|
+
const ARGS = process.argv.slice(2);
|
|
11
|
+
const SUBCOMMAND = ARGS[0];
|
|
12
|
+
|
|
13
|
+
async function main() {
|
|
14
|
+
switch (SUBCOMMAND) {
|
|
15
|
+
case 'status':
|
|
16
|
+
const history = TemporalHub.getHistory();
|
|
17
|
+
console.log(`\n⏳ MindForge Temporal Status`);
|
|
18
|
+
console.log(` Snapshots: ${history.length}`);
|
|
19
|
+
if (history.length > 0) {
|
|
20
|
+
console.log(` Latest: ${history[0].id} (${history[0].timestamp})`);
|
|
21
|
+
}
|
|
22
|
+
break;
|
|
23
|
+
|
|
24
|
+
case 'cleanup':
|
|
25
|
+
console.log('🧹 Cleaning up old temporal snapshots...');
|
|
26
|
+
// Logic for cleanup (e.g., keep last 100)
|
|
27
|
+
console.log('✅ Cleanup complete.');
|
|
28
|
+
break;
|
|
29
|
+
|
|
30
|
+
case 'inject':
|
|
31
|
+
const auditId = ARGS[1];
|
|
32
|
+
const fix = ARGS.slice(2).join(' ');
|
|
33
|
+
if (!auditId || !fix) {
|
|
34
|
+
console.error('Usage: /mindforge:temporal inject <auditId> <fix description>');
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
const result = await HindsightInjector.inject(auditId, fix);
|
|
38
|
+
if (result.success) {
|
|
39
|
+
console.log(`✅ Hindsight injected. Event ID: ${result.event.id}`);
|
|
40
|
+
} else {
|
|
41
|
+
console.error(`❌ Injection failed: ${result.error}`);
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
break;
|
|
45
|
+
|
|
46
|
+
default:
|
|
47
|
+
console.log('Usage: /mindforge:temporal <status|cleanup|inject>');
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
main();
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MindForge v3 — Temporal Hub (State Versioner)
|
|
3
|
+
* Managed high-fidelity snapshots of the .planning directory.
|
|
4
|
+
*
|
|
5
|
+
* Design:
|
|
6
|
+
* - Each snapshot is identified by an audit_id.
|
|
7
|
+
* - Snapshots are stored in .planning/history/[audit_id]/
|
|
8
|
+
* - Atomic snapshots ensure time-travel debugging consistency.
|
|
9
|
+
*/
|
|
10
|
+
'use strict';
|
|
11
|
+
|
|
12
|
+
const fs = require('fs');
|
|
13
|
+
const path = require('path');
|
|
14
|
+
const { execSync } = require('child_process');
|
|
15
|
+
|
|
16
|
+
const PLANNING_DIR = path.join(process.cwd(), '.planning');
|
|
17
|
+
const HISTORY_DIR = path.join(PLANNING_DIR, 'history');
|
|
18
|
+
|
|
19
|
+
class TemporalHub {
|
|
20
|
+
/**
|
|
21
|
+
* Capture the current state of the .planning directory.
|
|
22
|
+
* @param {string} auditId - Unique identifier from AUDIT.jsonl
|
|
23
|
+
* @param {object} metadata - Optional context (task_name, session_id)
|
|
24
|
+
*/
|
|
25
|
+
static captureState(auditId, metadata = {}) {
|
|
26
|
+
if (!fs.existsSync(PLANNING_DIR)) return null;
|
|
27
|
+
|
|
28
|
+
const snapshotDir = path.join(HISTORY_DIR, auditId);
|
|
29
|
+
if (!fs.existsSync(snapshotDir)) {
|
|
30
|
+
fs.mkdirSync(snapshotDir, { recursive: true });
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
// 1. Identify files to snapshot (exclude history itself and archive)
|
|
35
|
+
const files = fs.readdirSync(PLANNING_DIR).filter(f => {
|
|
36
|
+
const stats = fs.statSync(path.join(PLANNING_DIR, f));
|
|
37
|
+
if (stats.isDirectory()) return false;
|
|
38
|
+
|
|
39
|
+
const ext = path.extname(f).toLowerCase();
|
|
40
|
+
return ['.md', '.json', '.yml', '.yaml', '.log'].includes(ext);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// 2. Snapshot files
|
|
44
|
+
for (const file of files) {
|
|
45
|
+
fs.copyFileSync(
|
|
46
|
+
path.join(PLANNING_DIR, file),
|
|
47
|
+
path.join(snapshotDir, file)
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// 3. Save snapshot metadata
|
|
52
|
+
const meta = {
|
|
53
|
+
id: auditId,
|
|
54
|
+
timestamp: new Date().toISOString(),
|
|
55
|
+
...metadata,
|
|
56
|
+
files: files
|
|
57
|
+
};
|
|
58
|
+
fs.writeFileSync(path.join(snapshotDir, 'SNAPSHOT-META.json'), JSON.stringify(meta, null, 2));
|
|
59
|
+
|
|
60
|
+
return snapshotDir;
|
|
61
|
+
} catch (err) {
|
|
62
|
+
console.error(`[temporal-hub] Failed to capture state for ${auditId}:`, err.message);
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Restore the .planning directory to a specific snapshot.
|
|
69
|
+
* @param {string} auditId
|
|
70
|
+
*/
|
|
71
|
+
static rollbackTo(auditId) {
|
|
72
|
+
const snapshotDir = path.join(HISTORY_DIR, auditId);
|
|
73
|
+
if (!fs.existsSync(snapshotDir)) {
|
|
74
|
+
throw new Error(`Snapshot ${auditId} not found in history.`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
const files = fs.readdirSync(snapshotDir).filter(f => f !== 'SNAPSHOT-META.json');
|
|
79
|
+
|
|
80
|
+
for (const file of files) {
|
|
81
|
+
fs.copyFileSync(
|
|
82
|
+
path.join(snapshotDir, file),
|
|
83
|
+
path.join(PLANNING_DIR, file)
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return true;
|
|
88
|
+
} catch (err) {
|
|
89
|
+
console.error(`[temporal-hub] Rollback failed for ${auditId}:`, err.message);
|
|
90
|
+
throw err;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Get all available snapshots.
|
|
96
|
+
*/
|
|
97
|
+
static getHistory() {
|
|
98
|
+
if (!fs.existsSync(HISTORY_DIR)) return [];
|
|
99
|
+
|
|
100
|
+
try {
|
|
101
|
+
return fs.readdirSync(HISTORY_DIR)
|
|
102
|
+
.map(id => {
|
|
103
|
+
const metaPath = path.join(HISTORY_DIR, id, 'SNAPSHOT-META.json');
|
|
104
|
+
if (fs.existsSync(metaPath)) {
|
|
105
|
+
return JSON.parse(fs.readFileSync(metaPath, 'utf8'));
|
|
106
|
+
}
|
|
107
|
+
return { id, error: 'Missing metadata' };
|
|
108
|
+
})
|
|
109
|
+
.sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp));
|
|
110
|
+
} catch (err) {
|
|
111
|
+
return [];
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Read a file from a specific historical snapshot.
|
|
117
|
+
*/
|
|
118
|
+
static getSnapshotFile(auditId, filePath) {
|
|
119
|
+
const snapPath = path.join(HISTORY_DIR, auditId, path.basename(filePath));
|
|
120
|
+
if (fs.existsSync(snapPath)) {
|
|
121
|
+
return fs.readFileSync(snapPath, 'utf8');
|
|
122
|
+
}
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Capture terminal output for a command and associate with audit point.
|
|
128
|
+
*/
|
|
129
|
+
static captureTerminal(auditId, stdout, stderr) {
|
|
130
|
+
const logDir = path.join(HISTORY_DIR, auditId, 'logs');
|
|
131
|
+
if (!fs.existsSync(logDir)) fs.mkdirSync(logDir, { recursive: true });
|
|
132
|
+
|
|
133
|
+
if (stdout) fs.writeFileSync(path.join(logDir, 'stdout.log'), stdout);
|
|
134
|
+
if (stderr) fs.writeFileSync(path.join(logDir, 'stderr.log'), stderr);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
module.exports = TemporalHub;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MindForge v3 — Hindsight Injector
|
|
3
|
+
* Manages state rollbacks and autonomous re-triggering.
|
|
4
|
+
*/
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const TemporalHub = require('./engine/temporal-hub');
|
|
10
|
+
|
|
11
|
+
class HindsightInjector {
|
|
12
|
+
/**
|
|
13
|
+
* Rollback state to T_n and prepare for re-execution.
|
|
14
|
+
* @param {string} auditId - The point to rollback to.
|
|
15
|
+
* @param {string} fixDescription - Description of the correction being injected.
|
|
16
|
+
*/
|
|
17
|
+
static async inject(auditId, fixDescription) {
|
|
18
|
+
console.log(`[hindsight] Injecting fix at ${auditId}: "${fixDescription}"`);
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
// 1. Rollback .planning directory
|
|
22
|
+
TemporalHub.rollbackTo(auditId);
|
|
23
|
+
|
|
24
|
+
// 2. Append the "Hindsight" event to AUDIT.jsonl
|
|
25
|
+
const auditPath = path.join(process.cwd(), '.planning', 'AUDIT.jsonl');
|
|
26
|
+
const hindsightEvent = {
|
|
27
|
+
id: require('crypto').randomBytes(8).toString('hex'),
|
|
28
|
+
timestamp: new Date().toISOString(),
|
|
29
|
+
event: 'hindsight_injected',
|
|
30
|
+
target_id: auditId,
|
|
31
|
+
description: fixDescription,
|
|
32
|
+
agent: 'temporal-hub'
|
|
33
|
+
};
|
|
34
|
+
fs.appendFileSync(auditPath, JSON.stringify(hindsightEvent) + '\n');
|
|
35
|
+
|
|
36
|
+
// 3. Mark the state as "ready_for_regeneration"
|
|
37
|
+
const statePath = path.join(process.cwd(), '.planning', 'auto-state.json');
|
|
38
|
+
if (fs.existsSync(statePath)) {
|
|
39
|
+
const state = JSON.parse(fs.readFileSync(statePath, 'utf8'));
|
|
40
|
+
state.status = 'awaiting_regeneration';
|
|
41
|
+
state.last_hindsight = hindsightEvent.id;
|
|
42
|
+
fs.writeFileSync(statePath, JSON.stringify(state, null, 2));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 4. Capture the new state immediately
|
|
46
|
+
TemporalHub.captureState(hindsightEvent.id, {
|
|
47
|
+
event: 'hindsight_injected',
|
|
48
|
+
target_id: auditId
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
return { success: true, event: hindsightEvent };
|
|
52
|
+
} catch (err) {
|
|
53
|
+
console.error(`[hindsight] Injection failed:`, err.message);
|
|
54
|
+
return { success: false, error: err.message };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
module.exports = HindsightInjector;
|