dual-brain 0.2.29 → 0.3.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/.dual-brain/docs/claude-code-extension-points.md +32 -0
- package/.dual-brain/docs/data-tools-capabilities.md +181 -0
- package/.dual-brain/docs/ecosystem-tools.md +91 -0
- package/.dual-brain/docs/panel-handoff.md +124 -0
- package/.dual-brain/docs/ruflo-analysis.md +48 -0
- package/bin/dual-brain.mjs +122 -51
- package/dist/mcp-server/index.d.ts +27 -0
- package/dist/mcp-server/index.js +359 -0
- package/dist/mcp-server/index.js.map +1 -0
- package/dist/src/agent-protocol.d.ts +163 -0
- package/dist/src/agent-protocol.js +368 -0
- package/dist/src/agent-protocol.js.map +1 -0
- package/dist/src/agents/registry.d.ts +52 -0
- package/dist/src/agents/registry.js +393 -0
- package/dist/src/agents/registry.js.map +1 -0
- package/dist/src/awareness.d.ts +93 -0
- package/dist/src/awareness.js +406 -0
- package/dist/src/awareness.js.map +1 -0
- package/dist/src/brief.d.ts +48 -0
- package/dist/src/brief.js +179 -0
- package/dist/src/brief.js.map +1 -0
- package/dist/src/calibration.d.ts +32 -0
- package/dist/src/calibration.js +133 -0
- package/dist/src/calibration.js.map +1 -0
- package/dist/src/checkpoint.d.ts +33 -0
- package/dist/src/checkpoint.js +99 -0
- package/dist/src/checkpoint.js.map +1 -0
- package/dist/src/ci-triage.d.ts +33 -0
- package/dist/src/ci-triage.js +193 -0
- package/dist/src/ci-triage.js.map +1 -0
- package/dist/src/cognitive-loop.d.ts +56 -0
- package/dist/src/cognitive-loop.js +495 -0
- package/dist/src/cognitive-loop.js.map +1 -0
- package/dist/src/collaboration.d.ts +147 -0
- package/dist/src/collaboration.js +438 -0
- package/dist/src/collaboration.js.map +1 -0
- package/dist/src/context-intel.d.ts +47 -0
- package/dist/src/context-intel.js +156 -0
- package/dist/src/context-intel.js.map +1 -0
- package/dist/src/context.d.ts +53 -0
- package/dist/src/context.js +332 -0
- package/dist/src/context.js.map +1 -0
- package/dist/src/continuity.d.ts +89 -0
- package/dist/src/continuity.js +230 -0
- package/dist/src/continuity.js.map +1 -0
- package/dist/src/cost-tracker.d.ts +47 -0
- package/dist/src/cost-tracker.js +170 -0
- package/dist/src/cost-tracker.js.map +1 -0
- package/dist/src/debrief.d.ts +53 -0
- package/dist/src/debrief.js +222 -0
- package/dist/src/debrief.js.map +1 -0
- package/dist/src/decide.d.ts +96 -0
- package/dist/src/decide.js +744 -0
- package/dist/src/decide.js.map +1 -0
- package/dist/src/decompose.d.ts +39 -0
- package/dist/src/decompose.js +218 -0
- package/dist/src/decompose.js.map +1 -0
- package/dist/src/detect.d.ts +91 -0
- package/dist/src/detect.js +544 -0
- package/dist/src/detect.js.map +1 -0
- package/dist/src/dispatch.d.ts +154 -0
- package/dist/src/dispatch.js +1306 -0
- package/dist/src/dispatch.js.map +1 -0
- package/dist/src/doctor.d.ts +421 -0
- package/dist/src/doctor.js +1689 -0
- package/dist/src/doctor.js.map +1 -0
- package/dist/src/engine.d.ts +70 -0
- package/dist/src/engine.js +155 -0
- package/dist/src/engine.js.map +1 -0
- package/dist/src/envelope.d.ts +36 -0
- package/dist/src/envelope.js +80 -0
- package/dist/src/envelope.js.map +1 -0
- package/dist/src/failure-memory.d.ts +55 -0
- package/dist/src/failure-memory.js +175 -0
- package/dist/src/failure-memory.js.map +1 -0
- package/dist/src/fx.d.ts +87 -0
- package/dist/src/fx.js +272 -0
- package/dist/src/fx.js.map +1 -0
- package/dist/src/governance.d.ts +93 -0
- package/dist/src/governance.js +261 -0
- package/dist/src/governance.js.map +1 -0
- package/dist/src/handoff.d.ts +11 -0
- package/dist/src/handoff.js +90 -0
- package/dist/src/handoff.js.map +1 -0
- package/dist/src/head-protocol.d.ts +76 -0
- package/dist/src/head-protocol.js +109 -0
- package/dist/src/head-protocol.js.map +1 -0
- package/dist/src/head.d.ts +222 -0
- package/dist/src/head.js +765 -0
- package/dist/src/head.js.map +1 -0
- package/dist/src/health.d.ts +132 -0
- package/dist/src/health.js +435 -0
- package/dist/src/health.js.map +1 -0
- package/dist/src/inbox.d.ts +70 -0
- package/dist/src/inbox.js +218 -0
- package/dist/src/inbox.js.map +1 -0
- package/dist/src/index.d.ts +33 -0
- package/dist/src/index.js +38 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/install-hooks.d.ts +13 -0
- package/dist/src/install-hooks.js +88 -0
- package/dist/src/install-hooks.js.map +1 -0
- package/dist/src/integrity.d.ts +59 -0
- package/dist/src/integrity.js +206 -0
- package/dist/src/integrity.js.map +1 -0
- package/dist/src/intelligence.d.ts +104 -0
- package/dist/src/intelligence.js +391 -0
- package/dist/src/intelligence.js.map +1 -0
- package/dist/src/ledger.d.ts +54 -0
- package/dist/src/ledger.js +179 -0
- package/dist/src/ledger.js.map +1 -0
- package/dist/src/living-docs.d.ts +14 -0
- package/dist/src/living-docs.js +197 -0
- package/dist/src/living-docs.js.map +1 -0
- package/dist/src/memory-tiers.d.ts +37 -0
- package/dist/src/memory-tiers.js +160 -0
- package/dist/src/memory-tiers.js.map +1 -0
- package/dist/src/model-profiles.d.ts +65 -0
- package/dist/src/model-profiles.js +568 -0
- package/dist/src/model-profiles.js.map +1 -0
- package/dist/src/models.d.ts +58 -0
- package/dist/src/models.js +327 -0
- package/dist/src/models.js.map +1 -0
- package/dist/src/narrative.d.ts +54 -0
- package/dist/src/narrative.js +163 -0
- package/dist/src/narrative.js.map +1 -0
- package/dist/src/nextstep.d.ts +16 -0
- package/dist/src/nextstep.js +103 -0
- package/dist/src/nextstep.js.map +1 -0
- package/dist/src/observer.d.ts +18 -0
- package/dist/src/observer.js +251 -0
- package/dist/src/observer.js.map +1 -0
- package/dist/src/outcome.d.ts +110 -0
- package/dist/src/outcome.js +377 -0
- package/dist/src/outcome.js.map +1 -0
- package/dist/src/pipeline.d.ts +167 -0
- package/dist/src/pipeline.js +1503 -0
- package/dist/src/pipeline.js.map +1 -0
- package/dist/src/playbook.d.ts +59 -0
- package/dist/src/playbook.js +238 -0
- package/dist/src/playbook.js.map +1 -0
- package/dist/src/pr-agent.d.ts +97 -0
- package/dist/src/pr-agent.js +195 -0
- package/dist/src/pr-agent.js.map +1 -0
- package/dist/src/predictive.d.ts +57 -0
- package/dist/src/predictive.js +230 -0
- package/dist/src/predictive.js.map +1 -0
- package/dist/src/profile.d.ts +294 -0
- package/dist/src/profile.js +1347 -0
- package/dist/src/profile.js.map +1 -0
- package/dist/src/prompt-audit.d.ts +22 -0
- package/dist/src/prompt-audit.js +194 -0
- package/dist/src/prompt-audit.js.map +1 -0
- package/dist/src/prompt-intel.d.ts +12 -0
- package/dist/src/prompt-intel.js +321 -0
- package/dist/src/prompt-intel.js.map +1 -0
- package/dist/src/provider-context.d.ts +121 -0
- package/dist/src/provider-context.js +222 -0
- package/dist/src/provider-context.js.map +1 -0
- package/dist/src/provider-manager.d.ts +92 -0
- package/dist/src/provider-manager.js +428 -0
- package/dist/src/provider-manager.js.map +1 -0
- package/dist/src/receipt.d.ts +87 -0
- package/dist/src/receipt.js +326 -0
- package/dist/src/receipt.js.map +1 -0
- package/dist/src/recommendations.d.ts +13 -0
- package/dist/src/recommendations.js +291 -0
- package/dist/src/recommendations.js.map +1 -0
- package/dist/src/redact.d.ts +15 -0
- package/dist/src/redact.js +129 -0
- package/dist/src/redact.js.map +1 -0
- package/dist/src/replit.d.ts +397 -0
- package/dist/src/replit.js +1160 -0
- package/dist/src/replit.js.map +1 -0
- package/dist/src/repo.d.ts +149 -0
- package/dist/src/repo.js +416 -0
- package/dist/src/repo.js.map +1 -0
- package/dist/src/revert.d.ts +30 -0
- package/dist/src/revert.js +166 -0
- package/dist/src/revert.js.map +1 -0
- package/dist/src/room.d.ts +102 -0
- package/dist/src/room.js +212 -0
- package/dist/src/room.js.map +1 -0
- package/dist/src/routing-advisor.d.ts +57 -0
- package/dist/src/routing-advisor.js +221 -0
- package/dist/src/routing-advisor.js.map +1 -0
- package/dist/src/self-correct.d.ts +40 -0
- package/dist/src/self-correct.js +137 -0
- package/dist/src/self-correct.js.map +1 -0
- package/dist/src/session-lock.d.ts +35 -0
- package/dist/src/session-lock.js +134 -0
- package/dist/src/session-lock.js.map +1 -0
- package/dist/src/session.d.ts +267 -0
- package/dist/src/session.js +1660 -0
- package/dist/src/session.js.map +1 -0
- package/dist/src/settings-tui.d.ts +5 -0
- package/dist/src/settings-tui.js +422 -0
- package/dist/src/settings-tui.js.map +1 -0
- package/dist/src/setup-flow.d.ts +63 -0
- package/dist/src/setup-flow.js +233 -0
- package/dist/src/setup-flow.js.map +1 -0
- package/dist/src/signal.d.ts +19 -0
- package/dist/src/signal.js +122 -0
- package/dist/src/signal.js.map +1 -0
- package/dist/src/simmer.d.ts +85 -0
- package/dist/src/simmer.js +224 -0
- package/dist/src/simmer.js.map +1 -0
- package/dist/src/state-export.d.ts +129 -0
- package/dist/src/state-export.js +233 -0
- package/dist/src/state-export.js.map +1 -0
- package/dist/src/strategy.d.ts +54 -0
- package/dist/src/strategy.js +95 -0
- package/dist/src/strategy.js.map +1 -0
- package/dist/src/subscription.d.ts +40 -0
- package/dist/src/subscription.js +189 -0
- package/dist/src/subscription.js.map +1 -0
- package/dist/src/templates.d.ts +208 -0
- package/dist/src/templates.js +238 -0
- package/dist/src/templates.js.map +1 -0
- package/dist/src/test.d.ts +9 -0
- package/dist/src/test.js +1173 -0
- package/dist/src/test.js.map +1 -0
- package/dist/src/think-engine.d.ts +67 -0
- package/dist/src/think-engine.js +412 -0
- package/dist/src/think-engine.js.map +1 -0
- package/dist/src/tui.d.ts +71 -0
- package/dist/src/tui.js +242 -0
- package/dist/src/tui.js.map +1 -0
- package/dist/src/types.d.ts +177 -0
- package/dist/src/types.js +6 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/update-check.d.ts +7 -0
- package/dist/src/update-check.js +36 -0
- package/dist/src/update-check.js.map +1 -0
- package/dist/src/wave-planner.d.ts +30 -0
- package/dist/src/wave-planner.js +281 -0
- package/dist/src/wave-planner.js.map +1 -0
- package/hooks/head-guard.sh +41 -0
- package/hooks/task-classifier.mjs +328 -0
- package/hooks/vibe-router.mjs +387 -0
- package/package.json +29 -153
- package/src/agents/registry.mjs +0 -405
- package/src/awareness.mjs +0 -425
- package/src/brief.mjs +0 -266
- package/src/calibration.mjs +0 -148
- package/src/checkpoint.mjs +0 -109
- package/src/ci-triage.mjs +0 -191
- package/src/cognitive-loop.mjs +0 -562
- package/src/collaboration.mjs +0 -545
- package/src/context-intel.mjs +0 -158
- package/src/context.mjs +0 -389
- package/src/continuity.mjs +0 -298
- package/src/cost-tracker.mjs +0 -184
- package/src/debrief.mjs +0 -228
- package/src/decide.mjs +0 -1099
- package/src/decompose.mjs +0 -331
- package/src/detect.mjs +0 -702
- package/src/dispatch.mjs +0 -1447
- package/src/doctor.mjs +0 -1607
- package/src/envelope.mjs +0 -139
- package/src/failure-memory.mjs +0 -178
- package/src/fx.mjs +0 -276
- package/src/governance.mjs +0 -279
- package/src/handoff.mjs +0 -85
- package/src/head-protocol.mjs +0 -128
- package/src/head.mjs +0 -952
- package/src/health.mjs +0 -528
- package/src/inbox.mjs +0 -195
- package/src/index.mjs +0 -44
- package/src/install-hooks.mjs +0 -100
- package/src/integrity.mjs +0 -245
- package/src/intelligence.mjs +0 -447
- package/src/ledger.mjs +0 -196
- package/src/living-docs.mjs +0 -210
- package/src/memory-tiers.mjs +0 -193
- package/src/models.mjs +0 -363
- package/src/narrative.mjs +0 -169
- package/src/nextstep.mjs +0 -100
- package/src/observer.mjs +0 -241
- package/src/outcome.mjs +0 -386
- package/src/pipeline.mjs +0 -1689
- package/src/playbook.mjs +0 -257
- package/src/pr-agent.mjs +0 -214
- package/src/predictive.mjs +0 -250
- package/src/profile.mjs +0 -1411
- package/src/prompt-audit.mjs +0 -231
- package/src/prompt-intel.mjs +0 -325
- package/src/provider-context.mjs +0 -257
- package/src/receipt.mjs +0 -344
- package/src/recommendations.mjs +0 -291
- package/src/redact.mjs +0 -192
- package/src/replit.mjs +0 -1210
- package/src/repo.mjs +0 -445
- package/src/revert.mjs +0 -149
- package/src/routing-advisor.mjs +0 -200
- package/src/self-correct.mjs +0 -146
- package/src/session-lock.mjs +0 -160
- package/src/session.mjs +0 -1655
- package/src/settings-tui.mjs +0 -373
- package/src/setup-flow.mjs +0 -215
- package/src/signal.mjs +0 -114
- package/src/simmer.mjs +0 -241
- package/src/strategy.mjs +0 -235
- package/src/subscription.mjs +0 -212
- package/src/templates.mjs +0 -260
- package/src/think-engine.mjs +0 -428
- package/src/tui.mjs +0 -276
- package/src/update-check.mjs +0 -35
- package/src/wave-planner.mjs +0 -294
package/src/living-docs.mjs
DELETED
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
// living-docs.mjs — Living document system for .dualbrain/.
|
|
2
|
-
// Manages project.json, vision.md, roadmap.md, state.md, actions.jsonl, decisions.jsonl, checkpoints.jsonl.
|
|
3
|
-
|
|
4
|
-
import { readFileSync, writeFileSync, appendFileSync, mkdirSync, existsSync } from 'node:fs';
|
|
5
|
-
import { join } from 'node:path';
|
|
6
|
-
import { execSync } from 'node:child_process';
|
|
7
|
-
|
|
8
|
-
const DIR = '.dualbrain';
|
|
9
|
-
|
|
10
|
-
function docsDir(cwd = process.cwd()) {
|
|
11
|
-
return join(cwd, DIR);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
function ensureDir(cwd) {
|
|
15
|
-
mkdirSync(docsDir(cwd), { recursive: true });
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function filePath(name, cwd) {
|
|
19
|
-
return join(docsDir(cwd), name);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function readFileSafe(name, cwd, fallback = '') {
|
|
23
|
-
try {
|
|
24
|
-
return readFileSync(filePath(name, cwd), 'utf8');
|
|
25
|
-
} catch {
|
|
26
|
-
return fallback;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function readJsonSafe(name, cwd, fallback = {}) {
|
|
31
|
-
try {
|
|
32
|
-
return JSON.parse(readFileSync(filePath(name, cwd), 'utf8'));
|
|
33
|
-
} catch {
|
|
34
|
-
return fallback;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function readPackageJson(cwd) {
|
|
39
|
-
try {
|
|
40
|
-
return JSON.parse(readFileSync(join(cwd, 'package.json'), 'utf8'));
|
|
41
|
-
} catch {
|
|
42
|
-
return {};
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function gitExec(cmd, cwd) {
|
|
47
|
-
try {
|
|
48
|
-
return execSync(cmd, { cwd, stdio: ['ignore', 'pipe', 'pipe'] }).toString().trim();
|
|
49
|
-
} catch {
|
|
50
|
-
return null;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export function initLivingDocs(cwd = process.cwd()) {
|
|
55
|
-
const dir = docsDir(cwd);
|
|
56
|
-
const existed = existsSync(dir);
|
|
57
|
-
ensureDir(cwd);
|
|
58
|
-
|
|
59
|
-
const pkg = readPackageJson(cwd);
|
|
60
|
-
|
|
61
|
-
if (!existsSync(filePath('project.json', cwd))) {
|
|
62
|
-
const project = {
|
|
63
|
-
name: pkg.name ?? '',
|
|
64
|
-
version: pkg.version ?? '0.0.1',
|
|
65
|
-
created: new Date().toISOString(),
|
|
66
|
-
workStyle: 'balanced',
|
|
67
|
-
userCalibration: { specificity: 3, corrections: 3, autonomy: 3 },
|
|
68
|
-
team: [],
|
|
69
|
-
providers: {},
|
|
70
|
-
};
|
|
71
|
-
writeFileSync(filePath('project.json', cwd), JSON.stringify(project, null, 2));
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (!existsSync(filePath('vision.md', cwd))) {
|
|
75
|
-
writeFileSync(filePath('vision.md', cwd), '# Vision\n\n_Not yet defined. Type your vision and HEAD will maintain this document._\n');
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (!existsSync(filePath('roadmap.md', cwd))) {
|
|
79
|
-
writeFileSync(filePath('roadmap.md', cwd), '# Roadmap\n\n_No roadmap yet. As you work, HEAD will build this from your actions._\n');
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (!existsSync(filePath('state.md', cwd))) {
|
|
83
|
-
writeFileSync(filePath('state.md', cwd), '# Current State\n\n_Fresh project. No history yet._\n');
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
for (const log of ['actions.jsonl', 'decisions.jsonl', 'checkpoints.jsonl']) {
|
|
87
|
-
if (!existsSync(filePath(log, cwd))) {
|
|
88
|
-
writeFileSync(filePath(log, cwd), '');
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
return { created: !existed, path: dir };
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export function appendAction(action, cwd = process.cwd()) {
|
|
96
|
-
ensureDir(cwd);
|
|
97
|
-
const entry = {
|
|
98
|
-
id: `act_${Date.now()}_${Math.random().toString(36).slice(2, 6)}`,
|
|
99
|
-
timestamp: new Date().toISOString(),
|
|
100
|
-
type: 'task',
|
|
101
|
-
intent: '',
|
|
102
|
-
status: 'started',
|
|
103
|
-
owner: 'head',
|
|
104
|
-
files: [],
|
|
105
|
-
proof: null,
|
|
106
|
-
cost: null,
|
|
107
|
-
result: null,
|
|
108
|
-
...action,
|
|
109
|
-
};
|
|
110
|
-
appendFileSync(filePath('actions.jsonl', cwd), JSON.stringify(entry) + '\n');
|
|
111
|
-
return entry;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
export function appendDecision(decision, cwd = process.cwd()) {
|
|
115
|
-
ensureDir(cwd);
|
|
116
|
-
const entry = {
|
|
117
|
-
id: `dec_${Date.now()}`,
|
|
118
|
-
timestamp: new Date().toISOString(),
|
|
119
|
-
question: '',
|
|
120
|
-
decision: '',
|
|
121
|
-
reasoning: '',
|
|
122
|
-
participants: [],
|
|
123
|
-
supersedes: null,
|
|
124
|
-
...decision,
|
|
125
|
-
};
|
|
126
|
-
appendFileSync(filePath('decisions.jsonl', cwd), JSON.stringify(entry) + '\n');
|
|
127
|
-
return entry;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
export function createCheckpoint(summary, cwd = process.cwd()) {
|
|
131
|
-
ensureDir(cwd);
|
|
132
|
-
const gitRef = gitExec('git rev-parse HEAD', cwd) ?? 'unknown';
|
|
133
|
-
const branch = gitExec('git rev-parse --abbrev-ref HEAD', cwd) ?? 'unknown';
|
|
134
|
-
const stateSnapshot = readFileSafe('state.md', cwd, '');
|
|
135
|
-
const entry = {
|
|
136
|
-
id: `cp_${Date.now()}`,
|
|
137
|
-
timestamp: new Date().toISOString(),
|
|
138
|
-
gitRef,
|
|
139
|
-
branch,
|
|
140
|
-
summary,
|
|
141
|
-
stateSnapshot,
|
|
142
|
-
};
|
|
143
|
-
appendFileSync(filePath('checkpoints.jsonl', cwd), JSON.stringify(entry) + '\n');
|
|
144
|
-
return entry;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
export function updateState(newContent, cwd = process.cwd()) {
|
|
148
|
-
ensureDir(cwd);
|
|
149
|
-
writeFileSync(filePath('state.md', cwd), newContent);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
export function updateRoadmap(newContent, cwd = process.cwd()) {
|
|
153
|
-
ensureDir(cwd);
|
|
154
|
-
writeFileSync(filePath('roadmap.md', cwd), newContent);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
export function updateVision(newContent, cwd = process.cwd()) {
|
|
158
|
-
ensureDir(cwd);
|
|
159
|
-
const prev = readFileSafe('vision.md', cwd, '');
|
|
160
|
-
writeFileSync(filePath('vision.md', cwd), newContent);
|
|
161
|
-
if (prev !== newContent) {
|
|
162
|
-
appendDecision({
|
|
163
|
-
question: 'What is the project vision?',
|
|
164
|
-
decision: newContent.slice(0, 200),
|
|
165
|
-
reasoning: 'Vision document updated.',
|
|
166
|
-
participants: ['head'],
|
|
167
|
-
supersedes: null,
|
|
168
|
-
}, cwd);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
export function getProjectState(cwd = process.cwd()) {
|
|
173
|
-
const project = readJsonSafe('project.json', cwd, {});
|
|
174
|
-
const state = readFileSafe('state.md', cwd, '');
|
|
175
|
-
const actions = getRecentActions(cwd, 20);
|
|
176
|
-
const decisions = readLastLines('decisions.jsonl', cwd, 5);
|
|
177
|
-
const checkpoints = readLastLines('checkpoints.jsonl', cwd, 1);
|
|
178
|
-
return {
|
|
179
|
-
project,
|
|
180
|
-
state,
|
|
181
|
-
recentActions: actions,
|
|
182
|
-
recentDecisions: decisions,
|
|
183
|
-
lastCheckpoint: checkpoints[0] ?? null,
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
function readLastLines(name, cwd, n) {
|
|
188
|
-
const raw = readFileSafe(name, cwd, '');
|
|
189
|
-
const lines = raw.split('\n').filter(l => l.trim());
|
|
190
|
-
return lines.slice(-n).map(l => { try { return JSON.parse(l); } catch { return null; } }).filter(Boolean);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
export function getRecentActions(cwd = process.cwd(), limit = 20) {
|
|
194
|
-
return readLastLines('actions.jsonl', cwd, limit);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
export function getOpenTasks(cwd = process.cwd()) {
|
|
198
|
-
const raw = readFileSafe('actions.jsonl', cwd, '');
|
|
199
|
-
const lines = raw.split('\n').filter(l => l.trim());
|
|
200
|
-
const entries = lines.map(l => { try { return JSON.parse(l); } catch { return null; } }).filter(Boolean);
|
|
201
|
-
return entries.filter(e => e.status === 'started' || e.status === 'blocked');
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
export function updateProject(updates, cwd = process.cwd()) {
|
|
205
|
-
ensureDir(cwd);
|
|
206
|
-
const current = readJsonSafe('project.json', cwd, {});
|
|
207
|
-
const merged = { ...current, ...updates };
|
|
208
|
-
writeFileSync(filePath('project.json', cwd), JSON.stringify(merged, null, 2));
|
|
209
|
-
return merged;
|
|
210
|
-
}
|
package/src/memory-tiers.mjs
DELETED
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
// memory-tiers.mjs — Hot/Warm/Cold memory with active paging.
|
|
2
|
-
//
|
|
3
|
-
// Hot: loaded every turn (narrative + active simmer). Always in HEAD's context.
|
|
4
|
-
// Warm: loaded on demand (recent debriefs, narrative history, relevant past decisions).
|
|
5
|
-
// Cold: past sessions, archived patterns. Only retrieved when explicitly needed.
|
|
6
|
-
//
|
|
7
|
-
// The paging mechanism: HEAD doesn't decide what to load — this module does,
|
|
8
|
-
// based on what the current situation seems to need.
|
|
9
|
-
|
|
10
|
-
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
11
|
-
import { join } from 'node:path';
|
|
12
|
-
import * as narrative from './narrative.mjs';
|
|
13
|
-
import * as simmer from './simmer.mjs';
|
|
14
|
-
|
|
15
|
-
const STATE_DIR = join(process.cwd(), '.dualbrain');
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* @typedef {object} MemoryContext
|
|
19
|
-
* @property {string} narrative - Current running narrative
|
|
20
|
-
* @property {string} simmerBrief - What's brewing
|
|
21
|
-
* @property {Array} warmItems - Paged-in warm memory items
|
|
22
|
-
* @property {string} combined - Single string ready to inject into HEAD's context
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Load hot memory — always returned, every turn.
|
|
27
|
-
* This is the minimum context HEAD needs to be "in the song."
|
|
28
|
-
*
|
|
29
|
-
* @returns {{narrative: string, simmerBrief: string, combined: string}}
|
|
30
|
-
*/
|
|
31
|
-
export function loadHot() {
|
|
32
|
-
const narr = narrative.load();
|
|
33
|
-
const simmering = simmer.brief();
|
|
34
|
-
|
|
35
|
-
const parts = [];
|
|
36
|
-
if (narr) parts.push(narr);
|
|
37
|
-
if (simmering) parts.push(`[Simmering]\n${simmering}`);
|
|
38
|
-
|
|
39
|
-
return {
|
|
40
|
-
narrative: narr,
|
|
41
|
-
simmerBrief: simmering,
|
|
42
|
-
combined: parts.join('\n\n'),
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Load warm memory — contextually relevant items paged in based on signals.
|
|
48
|
-
*
|
|
49
|
-
* @param {object} signals - What the current turn is about
|
|
50
|
-
* @param {string} signals.userMessage - The user's message
|
|
51
|
-
* @param {string[]} signals.files - Files being discussed
|
|
52
|
-
* @param {string} signals.intent - Detected intent (from HEAD's perception)
|
|
53
|
-
* @returns {Array<{source: string, content: string}>}
|
|
54
|
-
*/
|
|
55
|
-
export function loadWarm(signals = {}) {
|
|
56
|
-
const items = [];
|
|
57
|
-
|
|
58
|
-
// Recent narrative history if we're resuming or context feels thin
|
|
59
|
-
if (_looksLikeResume(signals.userMessage) || !narrative.load()) {
|
|
60
|
-
const history = narrative.recentHistory(3);
|
|
61
|
-
if (history.length > 0) {
|
|
62
|
-
items.push({
|
|
63
|
-
source: 'narrative-history',
|
|
64
|
-
content: history.map(h => h.text).join('\n---\n'),
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Recent debriefs if we're continuing dispatch work
|
|
70
|
-
if (signals.intent === 'dispatch' || signals.intent === 'proceed') {
|
|
71
|
-
const debriefs = _loadRecentDebriefs(3);
|
|
72
|
-
if (debriefs.length > 0) {
|
|
73
|
-
items.push({
|
|
74
|
-
source: 'recent-debriefs',
|
|
75
|
-
content: debriefs.map(d => `[${d.status}] ${d.objective || d.summary || ''}`).join('\n'),
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Routing decisions if making a new routing choice
|
|
81
|
-
if (signals.intent === 'route' || signals.intent === 'dispatch') {
|
|
82
|
-
const decisions = _loadRecentDecisions(5);
|
|
83
|
-
if (decisions.length > 0) {
|
|
84
|
-
items.push({
|
|
85
|
-
source: 'routing-history',
|
|
86
|
-
content: decisions.map(d => `${d.provider}/${d.model}: ${d.reason || ''}`).join('\n'),
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return items;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Load cold memory — only when explicitly requested or when signals strongly indicate need.
|
|
96
|
-
*
|
|
97
|
-
* @param {string} query - What we're looking for
|
|
98
|
-
* @returns {Array<{source: string, content: string}>}
|
|
99
|
-
*/
|
|
100
|
-
export function loadCold(query) {
|
|
101
|
-
const items = [];
|
|
102
|
-
|
|
103
|
-
// Search past handoffs (from continuity.mjs)
|
|
104
|
-
const handoffs = _searchHandoffs(query);
|
|
105
|
-
if (handoffs.length > 0) {
|
|
106
|
-
items.push({
|
|
107
|
-
source: 'past-sessions',
|
|
108
|
-
content: handoffs.map(h => `[${h.timestamp}] ${h.task || ''}: ${h.resumeHint || ''}`).join('\n'),
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
return items;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Full context assembly — combines hot + warm based on current signals.
|
|
117
|
-
* This is what gets injected into HEAD's turn context.
|
|
118
|
-
*
|
|
119
|
-
* @param {object} signals
|
|
120
|
-
* @returns {MemoryContext}
|
|
121
|
-
*/
|
|
122
|
-
export function assemble(signals = {}) {
|
|
123
|
-
const hot = loadHot();
|
|
124
|
-
const warm = loadWarm(signals);
|
|
125
|
-
|
|
126
|
-
const parts = [];
|
|
127
|
-
if (hot.combined) parts.push(hot.combined);
|
|
128
|
-
|
|
129
|
-
if (warm.length > 0) {
|
|
130
|
-
const warmText = warm.map(w => `[${w.source}]\n${w.content}`).join('\n\n');
|
|
131
|
-
parts.push(warmText);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return {
|
|
135
|
-
narrative: hot.narrative,
|
|
136
|
-
simmerBrief: hot.simmerBrief,
|
|
137
|
-
warmItems: warm,
|
|
138
|
-
combined: parts.join('\n\n---\n\n'),
|
|
139
|
-
};
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// ── Internal helpers ──────────────────────────────────────────────────────────
|
|
143
|
-
|
|
144
|
-
function _looksLikeResume(msg) {
|
|
145
|
-
if (!msg) return false;
|
|
146
|
-
const lower = msg.toLowerCase();
|
|
147
|
-
return /continue|where were we|pick up|resume|what's next|whats next/.test(lower);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function _loadRecentDebriefs(n) {
|
|
151
|
-
try {
|
|
152
|
-
const loopFile = join(STATE_DIR, 'cognitive-loop.json');
|
|
153
|
-
if (!existsSync(loopFile)) return [];
|
|
154
|
-
const loop = JSON.parse(readFileSync(loopFile, 'utf8'));
|
|
155
|
-
return (loop.debriefs || []).slice(-n);
|
|
156
|
-
} catch {
|
|
157
|
-
return [];
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function _loadRecentDecisions(n) {
|
|
162
|
-
try {
|
|
163
|
-
const file = join(STATE_DIR, 'decisions.jsonl');
|
|
164
|
-
if (!existsSync(file)) return [];
|
|
165
|
-
const lines = readFileSync(file, 'utf8').trim().split('\n').filter(Boolean);
|
|
166
|
-
return lines.slice(-n).map(l => { try { return JSON.parse(l); } catch { return null; } }).filter(Boolean);
|
|
167
|
-
} catch {
|
|
168
|
-
return [];
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
function _searchHandoffs(query) {
|
|
173
|
-
try {
|
|
174
|
-
const handoffDir = join(STATE_DIR, 'handoffs');
|
|
175
|
-
if (!existsSync(handoffDir)) return [];
|
|
176
|
-
const files = readdirSync(handoffDir).filter(f => f.endsWith('.json')).slice(-10);
|
|
177
|
-
const results = [];
|
|
178
|
-
const queryLower = query.toLowerCase();
|
|
179
|
-
|
|
180
|
-
for (const f of files) {
|
|
181
|
-
try {
|
|
182
|
-
const data = JSON.parse(readFileSync(join(handoffDir, f), 'utf8'));
|
|
183
|
-
const text = JSON.stringify(data).toLowerCase();
|
|
184
|
-
if (text.includes(queryLower)) {
|
|
185
|
-
results.push(data);
|
|
186
|
-
}
|
|
187
|
-
} catch {}
|
|
188
|
-
}
|
|
189
|
-
return results.slice(-3);
|
|
190
|
-
} catch {
|
|
191
|
-
return [];
|
|
192
|
-
}
|
|
193
|
-
}
|