dual-brain 0.2.30 → 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 +56 -56
- 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 -87
- 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 -400
- package/src/pipeline.mjs +0 -1711
- 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 -296
- 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 -204
- package/src/self-correct.mjs +0 -147
- 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 -223
- package/src/signal.mjs +0 -115
- 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
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
// simmer.mjs — Ideas that aren't tasks yet. They sit, gather heat, and crystallize.
|
|
2
|
+
//
|
|
3
|
+
// The "song" insight: users drop ideas casually. HEAD tends to acknowledge them
|
|
4
|
+
// verbally then move on. The simmer buffer catches these — every idea gets stored
|
|
5
|
+
// with a heat score. Heat rises when: the idea recurs, evidence supports it,
|
|
6
|
+
// adjacent work makes it more relevant, or time passes and it keeps nagging.
|
|
7
|
+
// When heat crosses a threshold, the idea crystallizes into an actionable item
|
|
8
|
+
// and surfaces to HEAD during deliberation.
|
|
9
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
10
|
+
import { join } from 'node:path';
|
|
11
|
+
const STATE_DIR = join(process.cwd(), '.dualbrain');
|
|
12
|
+
const SIMMER_FILE = join(STATE_DIR, 'simmer.json');
|
|
13
|
+
const CRYSTALLIZE_THRESHOLD = 5;
|
|
14
|
+
const MAX_ITEMS = 30;
|
|
15
|
+
const HEAT_DECAY_PER_HOUR = 0.3;
|
|
16
|
+
/**
|
|
17
|
+
* @typedef {object} SimmerItem
|
|
18
|
+
* @property {string} id
|
|
19
|
+
* @property {string} idea - The raw idea in prose
|
|
20
|
+
* @property {string} origin - Where it came from (user quote, observation, debrief finding)
|
|
21
|
+
* @property {number} heat - Current heat score
|
|
22
|
+
* @property {number} createdAt
|
|
23
|
+
* @property {number} lastHeated - Last time heat was added
|
|
24
|
+
* @property {string[]} signals - Evidence trail (why heat was added)
|
|
25
|
+
* @property {boolean} crystallized - Whether it's crossed the threshold
|
|
26
|
+
* @property {string|null} crystallizedAs - What it became (task description, architecture decision, etc)
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* Add a new idea to the simmer buffer.
|
|
30
|
+
* If a similar idea already exists (fuzzy match), heat it instead of duplicating.
|
|
31
|
+
*
|
|
32
|
+
* @param {string} idea - The idea in natural language
|
|
33
|
+
* @param {object} opts
|
|
34
|
+
* @param {string} opts.origin - Where this came from
|
|
35
|
+
* @param {number} opts.initialHeat - Starting heat (default 1)
|
|
36
|
+
* @returns {SimmerItem} The created or heated item
|
|
37
|
+
*/
|
|
38
|
+
export function add(idea, { origin = 'observation', initialHeat = 1 } = {}) {
|
|
39
|
+
const items = _load();
|
|
40
|
+
// Check for similar existing idea
|
|
41
|
+
const existing = _findSimilar(items, idea);
|
|
42
|
+
if (existing) {
|
|
43
|
+
return heat(existing.id, initialHeat, `Recurrence: "${idea.slice(0, 60)}"`);
|
|
44
|
+
}
|
|
45
|
+
const item = {
|
|
46
|
+
id: Date.now().toString(36) + Math.random().toString(36).slice(2, 5),
|
|
47
|
+
idea,
|
|
48
|
+
origin,
|
|
49
|
+
heat: initialHeat,
|
|
50
|
+
createdAt: Date.now(),
|
|
51
|
+
lastHeated: Date.now(),
|
|
52
|
+
signals: [`Created from: ${origin}`],
|
|
53
|
+
crystallized: false,
|
|
54
|
+
crystallizedAs: null,
|
|
55
|
+
};
|
|
56
|
+
items.push(item);
|
|
57
|
+
_save(items);
|
|
58
|
+
return item;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Add heat to an existing item. If it crosses the threshold, mark as crystallized.
|
|
62
|
+
*
|
|
63
|
+
* @param {string} id
|
|
64
|
+
* @param {number} amount - Heat to add (default 1)
|
|
65
|
+
* @param {string} signal - Why heat is being added
|
|
66
|
+
* @returns {SimmerItem|null}
|
|
67
|
+
*/
|
|
68
|
+
export function heat(id, amount = 1, signal = '') {
|
|
69
|
+
const items = _load();
|
|
70
|
+
const item = items.find(i => i.id === id);
|
|
71
|
+
if (!item)
|
|
72
|
+
return null;
|
|
73
|
+
item.heat += amount;
|
|
74
|
+
item.lastHeated = Date.now();
|
|
75
|
+
if (signal)
|
|
76
|
+
item.signals.push(signal);
|
|
77
|
+
// Cap signals array
|
|
78
|
+
if (item.signals.length > 10) {
|
|
79
|
+
item.signals = item.signals.slice(-10);
|
|
80
|
+
}
|
|
81
|
+
// Check crystallization
|
|
82
|
+
if (!item.crystallized && item.heat >= CRYSTALLIZE_THRESHOLD) {
|
|
83
|
+
item.crystallized = true;
|
|
84
|
+
}
|
|
85
|
+
_save(items);
|
|
86
|
+
return item;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Get all items that have crystallized but haven't been surfaced yet.
|
|
90
|
+
* These should be presented to HEAD during deliberation.
|
|
91
|
+
*
|
|
92
|
+
* @returns {SimmerItem[]}
|
|
93
|
+
*/
|
|
94
|
+
export function harvest() {
|
|
95
|
+
const items = _load();
|
|
96
|
+
return items.filter(i => i.crystallized && !i.crystallizedAs);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Mark a crystallized item as actioned — record what it became.
|
|
100
|
+
*
|
|
101
|
+
* @param {string} id
|
|
102
|
+
* @param {string} became - Description of what action was taken
|
|
103
|
+
*/
|
|
104
|
+
export function resolve(id, became) {
|
|
105
|
+
const items = _load();
|
|
106
|
+
const item = items.find(i => i.id === id);
|
|
107
|
+
if (!item)
|
|
108
|
+
return;
|
|
109
|
+
item.crystallizedAs = became;
|
|
110
|
+
_save(items);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Get all active (non-resolved) simmering items, sorted by heat descending.
|
|
114
|
+
* Used by the narrative to include "what's brewing" context.
|
|
115
|
+
*
|
|
116
|
+
* @returns {SimmerItem[]}
|
|
117
|
+
*/
|
|
118
|
+
export function active() {
|
|
119
|
+
const items = _load();
|
|
120
|
+
_applyDecay(items);
|
|
121
|
+
return items
|
|
122
|
+
.filter(i => !i.crystallizedAs)
|
|
123
|
+
.sort((a, b) => b.heat - a.heat);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Check if an idea already exists in the buffer (for deduplication).
|
|
127
|
+
* @param {string} idea
|
|
128
|
+
* @returns {SimmerItem|null}
|
|
129
|
+
*/
|
|
130
|
+
export function find(idea) {
|
|
131
|
+
const items = _load();
|
|
132
|
+
return _findSimilar(items, idea);
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Generate a brief for HEAD showing what's simmering.
|
|
136
|
+
* Included in the narrative context so HEAD is aware of brewing ideas.
|
|
137
|
+
*
|
|
138
|
+
* @returns {string} Prose summary of active simmer items, or empty string
|
|
139
|
+
*/
|
|
140
|
+
export function brief() {
|
|
141
|
+
const items = active();
|
|
142
|
+
if (items.length === 0)
|
|
143
|
+
return '';
|
|
144
|
+
const crystallized = items.filter(i => i.crystallized);
|
|
145
|
+
const hot = items.filter(i => !i.crystallized && i.heat >= 3);
|
|
146
|
+
const warm = items.filter(i => !i.crystallized && i.heat >= 1.5 && i.heat < 3);
|
|
147
|
+
const parts = [];
|
|
148
|
+
if (crystallized.length > 0) {
|
|
149
|
+
parts.push(`Crystallized (ready to act): ${crystallized.map(i => i.idea.slice(0, 80)).join('; ')}`);
|
|
150
|
+
}
|
|
151
|
+
if (hot.length > 0) {
|
|
152
|
+
parts.push(`Hot (building momentum): ${hot.map(i => `${i.idea.slice(0, 60)} [heat:${i.heat.toFixed(1)}]`).join('; ')}`);
|
|
153
|
+
}
|
|
154
|
+
if (warm.length > 0 && parts.length < 2) {
|
|
155
|
+
parts.push(`Warm: ${warm.slice(0, 3).map(i => i.idea.slice(0, 50)).join('; ')}`);
|
|
156
|
+
}
|
|
157
|
+
return parts.join('\n');
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Prune resolved and cold-dead items.
|
|
161
|
+
*/
|
|
162
|
+
export function prune() {
|
|
163
|
+
let items = _load();
|
|
164
|
+
_applyDecay(items);
|
|
165
|
+
// Remove: resolved items older than 1h, or items with heat <= 0
|
|
166
|
+
const cutoff = Date.now() - 60 * 60 * 1000;
|
|
167
|
+
items = items.filter(i => {
|
|
168
|
+
if (i.crystallizedAs && i.lastHeated < cutoff)
|
|
169
|
+
return false;
|
|
170
|
+
if (i.heat <= 0)
|
|
171
|
+
return false;
|
|
172
|
+
return true;
|
|
173
|
+
});
|
|
174
|
+
_save(items);
|
|
175
|
+
}
|
|
176
|
+
// ── Internal ──────────────────────────────────────────────────────────────────
|
|
177
|
+
function _load() {
|
|
178
|
+
try {
|
|
179
|
+
if (existsSync(SIMMER_FILE)) {
|
|
180
|
+
return JSON.parse(readFileSync(SIMMER_FILE, 'utf8'));
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
catch { }
|
|
184
|
+
return [];
|
|
185
|
+
}
|
|
186
|
+
function _save(items) {
|
|
187
|
+
// Cap total items
|
|
188
|
+
if (items.length > MAX_ITEMS) {
|
|
189
|
+
items.sort((a, b) => b.heat - a.heat);
|
|
190
|
+
items = items.slice(0, MAX_ITEMS);
|
|
191
|
+
}
|
|
192
|
+
mkdirSync(STATE_DIR, { recursive: true });
|
|
193
|
+
writeFileSync(SIMMER_FILE, JSON.stringify(items, null, 2));
|
|
194
|
+
}
|
|
195
|
+
function _applyDecay(items) {
|
|
196
|
+
const now = Date.now();
|
|
197
|
+
for (const item of items) {
|
|
198
|
+
if (item.crystallized)
|
|
199
|
+
continue; // Crystallized items don't decay
|
|
200
|
+
const hoursSinceHeat = (now - item.lastHeated) / (60 * 60 * 1000);
|
|
201
|
+
if (hoursSinceHeat > 1) {
|
|
202
|
+
item.heat -= HEAT_DECAY_PER_HOUR * hoursSinceHeat;
|
|
203
|
+
if (item.heat < 0)
|
|
204
|
+
item.heat = 0;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
function _findSimilar(items, idea) {
|
|
209
|
+
const normalized = idea.toLowerCase().replace(/[^a-z0-9\s]/g, '');
|
|
210
|
+
const words = normalized.split(/\s+/).filter(w => w.length > 4);
|
|
211
|
+
if (words.length === 0)
|
|
212
|
+
return null;
|
|
213
|
+
for (const item of items) {
|
|
214
|
+
if (item.crystallizedAs)
|
|
215
|
+
continue; // Skip resolved
|
|
216
|
+
const itemNorm = item.idea.toLowerCase().replace(/[^a-z0-9\s]/g, '');
|
|
217
|
+
const matchCount = words.filter(w => itemNorm.includes(w)).length;
|
|
218
|
+
if (matchCount >= Math.ceil(words.length * 0.5)) {
|
|
219
|
+
return item;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return null;
|
|
223
|
+
}
|
|
224
|
+
//# sourceMappingURL=simmer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"simmer.js","sourceRoot":"","sources":["../../src/simmer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* state-export.ts — JSON state export for external consumers (web panels, dashboards).
|
|
3
|
+
*
|
|
4
|
+
* Writes orchestrator state to `.dual-brain/state/` as typed JSON files.
|
|
5
|
+
* All writes are atomic (write .tmp then rename) for crash safety.
|
|
6
|
+
* All functions are non-throwing.
|
|
7
|
+
*/
|
|
8
|
+
export interface ExportedProviderEntry {
|
|
9
|
+
provider: string;
|
|
10
|
+
status: string;
|
|
11
|
+
lastCheck: string;
|
|
12
|
+
lastSuccess: string;
|
|
13
|
+
cooldownUntil?: string;
|
|
14
|
+
remainingCapacity: number;
|
|
15
|
+
recentDispatches: number;
|
|
16
|
+
consecutiveFailures: number;
|
|
17
|
+
}
|
|
18
|
+
export interface ExportedProviders {
|
|
19
|
+
exportedAt: string;
|
|
20
|
+
providers: ExportedProviderEntry[];
|
|
21
|
+
}
|
|
22
|
+
export interface ExportedRoutingPerformer {
|
|
23
|
+
cell: string;
|
|
24
|
+
model: string;
|
|
25
|
+
ema: number;
|
|
26
|
+
observations: number;
|
|
27
|
+
}
|
|
28
|
+
export interface ExportedRouting {
|
|
29
|
+
exportedAt: string;
|
|
30
|
+
totalObservations: number;
|
|
31
|
+
topPerformers: ExportedRoutingPerformer[];
|
|
32
|
+
worstPerformers: ExportedRoutingPerformer[];
|
|
33
|
+
cells: Record<string, Record<string, {
|
|
34
|
+
ema: number;
|
|
35
|
+
observations: number;
|
|
36
|
+
}>>;
|
|
37
|
+
}
|
|
38
|
+
export interface ExportedRoomEntry {
|
|
39
|
+
id: string;
|
|
40
|
+
status: string;
|
|
41
|
+
taskDescription: string;
|
|
42
|
+
created: string;
|
|
43
|
+
workerCount: number;
|
|
44
|
+
workerStatuses: Record<string, string>;
|
|
45
|
+
}
|
|
46
|
+
export interface ExportedRooms {
|
|
47
|
+
exportedAt: string;
|
|
48
|
+
rooms: ExportedRoomEntry[];
|
|
49
|
+
}
|
|
50
|
+
export interface ExportedDecisionEntry {
|
|
51
|
+
timestamp: string;
|
|
52
|
+
promptSummary: string;
|
|
53
|
+
model: string;
|
|
54
|
+
provider: string;
|
|
55
|
+
tier: string;
|
|
56
|
+
reason: string;
|
|
57
|
+
}
|
|
58
|
+
export interface ExportedDecisions {
|
|
59
|
+
exportedAt: string;
|
|
60
|
+
decisions: ExportedDecisionEntry[];
|
|
61
|
+
}
|
|
62
|
+
export interface ExportedCosts {
|
|
63
|
+
exportedAt: string;
|
|
64
|
+
period: string;
|
|
65
|
+
totalCost: number;
|
|
66
|
+
totalTokens: number;
|
|
67
|
+
totalActions: number;
|
|
68
|
+
cacheHits: number;
|
|
69
|
+
tokensSaved: number;
|
|
70
|
+
costSaved: number;
|
|
71
|
+
savingsRate: number;
|
|
72
|
+
byTier: Record<string, {
|
|
73
|
+
count: number;
|
|
74
|
+
tokens: number;
|
|
75
|
+
cost: number;
|
|
76
|
+
}>;
|
|
77
|
+
byModel: Record<string, {
|
|
78
|
+
count: number;
|
|
79
|
+
tokens: number;
|
|
80
|
+
cost: number;
|
|
81
|
+
}>;
|
|
82
|
+
trend: string;
|
|
83
|
+
}
|
|
84
|
+
export interface ExportedOutcomeEntry {
|
|
85
|
+
timestamp: string;
|
|
86
|
+
roomId: string;
|
|
87
|
+
outcome: Record<string, unknown>;
|
|
88
|
+
}
|
|
89
|
+
export interface ExportedOutcomes {
|
|
90
|
+
exportedAt: string;
|
|
91
|
+
outcomes: ExportedOutcomeEntry[];
|
|
92
|
+
}
|
|
93
|
+
export interface ExportedState {
|
|
94
|
+
exportedAt: string;
|
|
95
|
+
providers: ExportedProviders;
|
|
96
|
+
routing: ExportedRouting;
|
|
97
|
+
rooms: ExportedRooms;
|
|
98
|
+
decisions: ExportedDecisions;
|
|
99
|
+
costs: ExportedCosts;
|
|
100
|
+
outcomes: ExportedOutcomes;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Export full orchestrator state to `.dual-brain/state/`.
|
|
104
|
+
* Writes providers.json, routing.json, rooms.json, decisions.json, costs.json.
|
|
105
|
+
* Non-throwing: returns true on success, false on failure.
|
|
106
|
+
*/
|
|
107
|
+
export declare function exportState(cwd?: string): boolean;
|
|
108
|
+
/**
|
|
109
|
+
* Append a routing decision to decisions.json (ring buffer, max 50 entries).
|
|
110
|
+
* Non-throwing.
|
|
111
|
+
*/
|
|
112
|
+
export declare function exportDecision(decision: {
|
|
113
|
+
provider?: string;
|
|
114
|
+
model?: string;
|
|
115
|
+
tier?: string;
|
|
116
|
+
explanation?: string;
|
|
117
|
+
[key: string]: unknown;
|
|
118
|
+
}, prompt: string, cwd?: string): void;
|
|
119
|
+
/**
|
|
120
|
+
* Append an outcome to outcomes.json log.
|
|
121
|
+
* Non-throwing.
|
|
122
|
+
*/
|
|
123
|
+
export declare function exportOutcome(roomId: string, outcome: Record<string, unknown>, cwd?: string): void;
|
|
124
|
+
/**
|
|
125
|
+
* Read all exported state files and return a combined object.
|
|
126
|
+
* Suitable for HTTP API or MCP tool responses.
|
|
127
|
+
* Non-throwing: returns partial data if some files are missing/corrupt.
|
|
128
|
+
*/
|
|
129
|
+
export declare function getExportedState(cwd?: string): ExportedState;
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* state-export.ts — JSON state export for external consumers (web panels, dashboards).
|
|
3
|
+
*
|
|
4
|
+
* Writes orchestrator state to `.dual-brain/state/` as typed JSON files.
|
|
5
|
+
* All writes are atomic (write .tmp then rename) for crash safety.
|
|
6
|
+
* All functions are non-throwing.
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from 'node:fs';
|
|
9
|
+
import { join, dirname } from 'node:path';
|
|
10
|
+
import { getAllProviderStates } from './provider-manager.js';
|
|
11
|
+
import { getRoutingStats } from './routing-advisor.js';
|
|
12
|
+
import { listRooms, getWorkerStatuses } from './room.js';
|
|
13
|
+
import { getCostSummary } from './cost-tracker.js';
|
|
14
|
+
// ─── Constants ────────────────────────────────────────────────────────────
|
|
15
|
+
const STATE_DIR = '.dual-brain/state';
|
|
16
|
+
const MAX_DECISIONS = 50;
|
|
17
|
+
const MAX_OUTCOMES = 200;
|
|
18
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────
|
|
19
|
+
function stateDir(cwd) {
|
|
20
|
+
return join(cwd || process.cwd(), STATE_DIR);
|
|
21
|
+
}
|
|
22
|
+
function stateFile(name, cwd) {
|
|
23
|
+
return join(stateDir(cwd), name);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Atomic write: write to .tmp then rename for crash safety.
|
|
27
|
+
*/
|
|
28
|
+
function atomicWrite(filePath, data) {
|
|
29
|
+
const dir = dirname(filePath);
|
|
30
|
+
mkdirSync(dir, { recursive: true });
|
|
31
|
+
const tmp = `${filePath}.tmp.${process.pid}.${Date.now()}`;
|
|
32
|
+
const json = JSON.stringify(data, null, 2) + '\n';
|
|
33
|
+
writeFileSync(tmp, json, 'utf8');
|
|
34
|
+
renameSync(tmp, filePath);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Safely read and parse a JSON file. Returns null on any error.
|
|
38
|
+
*/
|
|
39
|
+
function readJson(filePath) {
|
|
40
|
+
try {
|
|
41
|
+
if (!existsSync(filePath))
|
|
42
|
+
return null;
|
|
43
|
+
const raw = readFileSync(filePath, 'utf8');
|
|
44
|
+
return JSON.parse(raw);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Truncate a prompt to a short summary for the decisions log.
|
|
52
|
+
*/
|
|
53
|
+
function summarizePrompt(prompt) {
|
|
54
|
+
const cleaned = prompt.replace(/\s+/g, ' ').trim();
|
|
55
|
+
if (cleaned.length <= 120)
|
|
56
|
+
return cleaned;
|
|
57
|
+
return cleaned.slice(0, 117) + '...';
|
|
58
|
+
}
|
|
59
|
+
// ─── Public API ───────────────────────────────────────────────────────────
|
|
60
|
+
/**
|
|
61
|
+
* Export full orchestrator state to `.dual-brain/state/`.
|
|
62
|
+
* Writes providers.json, routing.json, rooms.json, decisions.json, costs.json.
|
|
63
|
+
* Non-throwing: returns true on success, false on failure.
|
|
64
|
+
*/
|
|
65
|
+
export function exportState(cwd) {
|
|
66
|
+
try {
|
|
67
|
+
const now = new Date().toISOString();
|
|
68
|
+
const resolvedCwd = cwd || process.cwd();
|
|
69
|
+
// ── providers.json
|
|
70
|
+
const providerStates = getAllProviderStates(resolvedCwd);
|
|
71
|
+
const providers = {
|
|
72
|
+
exportedAt: now,
|
|
73
|
+
providers: providerStates.map((ps) => ({
|
|
74
|
+
provider: ps.provider,
|
|
75
|
+
status: ps.status,
|
|
76
|
+
lastCheck: ps.lastCheck,
|
|
77
|
+
lastSuccess: ps.lastSuccess,
|
|
78
|
+
cooldownUntil: ps.cooldownUntil,
|
|
79
|
+
remainingCapacity: ps.remainingCapacity,
|
|
80
|
+
recentDispatches: ps.recentDispatches,
|
|
81
|
+
consecutiveFailures: ps.consecutiveFailures,
|
|
82
|
+
})),
|
|
83
|
+
};
|
|
84
|
+
atomicWrite(stateFile('providers.json', resolvedCwd), providers);
|
|
85
|
+
// ── routing.json
|
|
86
|
+
const stats = getRoutingStats(resolvedCwd);
|
|
87
|
+
const routing = {
|
|
88
|
+
exportedAt: now,
|
|
89
|
+
totalObservations: stats.totalObservations,
|
|
90
|
+
topPerformers: stats.topPerformers,
|
|
91
|
+
worstPerformers: stats.worstPerformers,
|
|
92
|
+
cells: stats.cells,
|
|
93
|
+
};
|
|
94
|
+
atomicWrite(stateFile('routing.json', resolvedCwd), routing);
|
|
95
|
+
// ── rooms.json
|
|
96
|
+
const roomSummaries = listRooms(resolvedCwd);
|
|
97
|
+
const roomEntries = roomSummaries.map((rs) => ({
|
|
98
|
+
id: rs.id,
|
|
99
|
+
status: rs.status,
|
|
100
|
+
taskDescription: rs.taskDescription,
|
|
101
|
+
created: rs.created,
|
|
102
|
+
workerCount: rs.workerCount,
|
|
103
|
+
workerStatuses: getWorkerStatuses(rs.id, resolvedCwd),
|
|
104
|
+
}));
|
|
105
|
+
const rooms = {
|
|
106
|
+
exportedAt: now,
|
|
107
|
+
rooms: roomEntries,
|
|
108
|
+
};
|
|
109
|
+
atomicWrite(stateFile('rooms.json', resolvedCwd), rooms);
|
|
110
|
+
// ── decisions.json — preserve existing, just update exportedAt
|
|
111
|
+
const existingDecisions = readJson(stateFile('decisions.json', resolvedCwd));
|
|
112
|
+
const decisions = {
|
|
113
|
+
exportedAt: now,
|
|
114
|
+
decisions: existingDecisions?.decisions ?? [],
|
|
115
|
+
};
|
|
116
|
+
atomicWrite(stateFile('decisions.json', resolvedCwd), decisions);
|
|
117
|
+
// ── costs.json
|
|
118
|
+
const costSummary = getCostSummary(resolvedCwd, 7);
|
|
119
|
+
const costs = {
|
|
120
|
+
exportedAt: now,
|
|
121
|
+
period: costSummary.period,
|
|
122
|
+
totalCost: costSummary.totalCost,
|
|
123
|
+
totalTokens: costSummary.totalTokens,
|
|
124
|
+
totalActions: costSummary.totalActions,
|
|
125
|
+
cacheHits: costSummary.cacheHits,
|
|
126
|
+
tokensSaved: costSummary.tokensSaved,
|
|
127
|
+
costSaved: costSummary.costSaved,
|
|
128
|
+
savingsRate: costSummary.savingsRate,
|
|
129
|
+
byTier: costSummary.byTier,
|
|
130
|
+
byModel: costSummary.byModel,
|
|
131
|
+
trend: costSummary.trend,
|
|
132
|
+
};
|
|
133
|
+
atomicWrite(stateFile('costs.json', resolvedCwd), costs);
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Append a routing decision to decisions.json (ring buffer, max 50 entries).
|
|
142
|
+
* Non-throwing.
|
|
143
|
+
*/
|
|
144
|
+
export function exportDecision(decision, prompt, cwd) {
|
|
145
|
+
try {
|
|
146
|
+
const resolvedCwd = cwd || process.cwd();
|
|
147
|
+
const filePath = stateFile('decisions.json', resolvedCwd);
|
|
148
|
+
const existing = readJson(filePath);
|
|
149
|
+
const entries = existing?.decisions ?? [];
|
|
150
|
+
const entry = {
|
|
151
|
+
timestamp: new Date().toISOString(),
|
|
152
|
+
promptSummary: summarizePrompt(prompt),
|
|
153
|
+
model: decision.model ?? 'unknown',
|
|
154
|
+
provider: decision.provider ?? 'unknown',
|
|
155
|
+
tier: decision.tier ?? 'unknown',
|
|
156
|
+
reason: decision.explanation ?? '',
|
|
157
|
+
};
|
|
158
|
+
entries.push(entry);
|
|
159
|
+
// Ring buffer: keep only the last MAX_DECISIONS entries
|
|
160
|
+
const trimmed = entries.length > MAX_DECISIONS
|
|
161
|
+
? entries.slice(entries.length - MAX_DECISIONS)
|
|
162
|
+
: entries;
|
|
163
|
+
const output = {
|
|
164
|
+
exportedAt: new Date().toISOString(),
|
|
165
|
+
decisions: trimmed,
|
|
166
|
+
};
|
|
167
|
+
atomicWrite(filePath, output);
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
// non-throwing
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Append an outcome to outcomes.json log.
|
|
175
|
+
* Non-throwing.
|
|
176
|
+
*/
|
|
177
|
+
export function exportOutcome(roomId, outcome, cwd) {
|
|
178
|
+
try {
|
|
179
|
+
const resolvedCwd = cwd || process.cwd();
|
|
180
|
+
const filePath = stateFile('outcomes.json', resolvedCwd);
|
|
181
|
+
const existing = readJson(filePath);
|
|
182
|
+
const entries = existing?.outcomes ?? [];
|
|
183
|
+
const entry = {
|
|
184
|
+
timestamp: new Date().toISOString(),
|
|
185
|
+
roomId,
|
|
186
|
+
outcome,
|
|
187
|
+
};
|
|
188
|
+
entries.push(entry);
|
|
189
|
+
// Keep bounded (MAX_OUTCOMES)
|
|
190
|
+
const trimmed = entries.length > MAX_OUTCOMES
|
|
191
|
+
? entries.slice(entries.length - MAX_OUTCOMES)
|
|
192
|
+
: entries;
|
|
193
|
+
const output = {
|
|
194
|
+
exportedAt: new Date().toISOString(),
|
|
195
|
+
outcomes: trimmed,
|
|
196
|
+
};
|
|
197
|
+
atomicWrite(filePath, output);
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
// non-throwing
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Read all exported state files and return a combined object.
|
|
205
|
+
* Suitable for HTTP API or MCP tool responses.
|
|
206
|
+
* Non-throwing: returns partial data if some files are missing/corrupt.
|
|
207
|
+
*/
|
|
208
|
+
export function getExportedState(cwd) {
|
|
209
|
+
const resolvedCwd = cwd || process.cwd();
|
|
210
|
+
const now = new Date().toISOString();
|
|
211
|
+
const providers = readJson(stateFile('providers.json', resolvedCwd))
|
|
212
|
+
?? { exportedAt: now, providers: [] };
|
|
213
|
+
const routing = readJson(stateFile('routing.json', resolvedCwd))
|
|
214
|
+
?? { exportedAt: now, totalObservations: 0, topPerformers: [], worstPerformers: [], cells: {} };
|
|
215
|
+
const rooms = readJson(stateFile('rooms.json', resolvedCwd))
|
|
216
|
+
?? { exportedAt: now, rooms: [] };
|
|
217
|
+
const decisions = readJson(stateFile('decisions.json', resolvedCwd))
|
|
218
|
+
?? { exportedAt: now, decisions: [] };
|
|
219
|
+
const costs = readJson(stateFile('costs.json', resolvedCwd))
|
|
220
|
+
?? { exportedAt: now, period: '7 days', totalCost: 0, totalTokens: 0, totalActions: 0, cacheHits: 0, tokensSaved: 0, costSaved: 0, savingsRate: 0, byTier: {}, byModel: {}, trend: 'stable' };
|
|
221
|
+
const outcomes = readJson(stateFile('outcomes.json', resolvedCwd))
|
|
222
|
+
?? { exportedAt: now, outcomes: [] };
|
|
223
|
+
return {
|
|
224
|
+
exportedAt: now,
|
|
225
|
+
providers,
|
|
226
|
+
routing,
|
|
227
|
+
rooms,
|
|
228
|
+
decisions,
|
|
229
|
+
costs,
|
|
230
|
+
outcomes,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
//# sourceMappingURL=state-export.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-export.js","sourceRoot":"","sources":["../../src/state-export.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
interface StrategyApplicability {
|
|
2
|
+
maxFiles?: number;
|
|
3
|
+
maxComplexity?: string;
|
|
4
|
+
maxRisk?: string;
|
|
5
|
+
minFiles?: number;
|
|
6
|
+
minComplexity?: string;
|
|
7
|
+
minRisk?: string;
|
|
8
|
+
}
|
|
9
|
+
interface StrategyDef {
|
|
10
|
+
id: string;
|
|
11
|
+
label: string;
|
|
12
|
+
description: string;
|
|
13
|
+
applicability: StrategyApplicability;
|
|
14
|
+
cost: number;
|
|
15
|
+
}
|
|
16
|
+
export declare const STRATEGIES: Record<string, StrategyDef>;
|
|
17
|
+
interface Detection {
|
|
18
|
+
fileCount?: number;
|
|
19
|
+
files?: number;
|
|
20
|
+
complexity?: string;
|
|
21
|
+
risk?: string;
|
|
22
|
+
prompt?: string;
|
|
23
|
+
description?: string;
|
|
24
|
+
}
|
|
25
|
+
interface StrategyResult {
|
|
26
|
+
strategy: string;
|
|
27
|
+
reason: string;
|
|
28
|
+
alternatives: string[];
|
|
29
|
+
}
|
|
30
|
+
export declare function selectStrategy(detection: Detection, decision: {
|
|
31
|
+
model?: string;
|
|
32
|
+
}, profile: {
|
|
33
|
+
workStyle?: string;
|
|
34
|
+
bias?: string;
|
|
35
|
+
}): StrategyResult;
|
|
36
|
+
export declare function describeStrategy(strategyId: string): string;
|
|
37
|
+
interface PlanStep {
|
|
38
|
+
role: string;
|
|
39
|
+
model: string;
|
|
40
|
+
description: string;
|
|
41
|
+
}
|
|
42
|
+
interface StrategyWithPlan extends StrategyResult {
|
|
43
|
+
plan: {
|
|
44
|
+
steps: PlanStep[];
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
export declare function getStrategyForTask(detection: Detection, cwd?: string): StrategyWithPlan;
|
|
48
|
+
export declare function listStrategies(): {
|
|
49
|
+
id: string;
|
|
50
|
+
label: string;
|
|
51
|
+
description: string;
|
|
52
|
+
cost: number;
|
|
53
|
+
}[];
|
|
54
|
+
export {};
|