@obsidicore/cascade-engine 0.2.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.
Files changed (75) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cascade/checkpoints.d.ts +55 -0
  3. package/dist/cascade/checkpoints.js +123 -0
  4. package/dist/cascade/checkpoints.js.map +1 -0
  5. package/dist/cascade/engine.d.ts +72 -0
  6. package/dist/cascade/engine.js +170 -0
  7. package/dist/cascade/engine.js.map +1 -0
  8. package/dist/cascade/gates.d.ts +46 -0
  9. package/dist/cascade/gates.js +199 -0
  10. package/dist/cascade/gates.js.map +1 -0
  11. package/dist/cascade/research.d.ts +50 -0
  12. package/dist/cascade/research.js +127 -0
  13. package/dist/cascade/research.js.map +1 -0
  14. package/dist/cli.d.ts +19 -0
  15. package/dist/cli.js +165 -0
  16. package/dist/cli.js.map +1 -0
  17. package/dist/control/kalman.d.ts +53 -0
  18. package/dist/control/kalman.js +83 -0
  19. package/dist/control/kalman.js.map +1 -0
  20. package/dist/control/pid.d.ts +57 -0
  21. package/dist/control/pid.js +95 -0
  22. package/dist/control/pid.js.map +1 -0
  23. package/dist/control/stability.d.ts +42 -0
  24. package/dist/control/stability.js +117 -0
  25. package/dist/control/stability.js.map +1 -0
  26. package/dist/db/index.d.ts +26 -0
  27. package/dist/db/index.js +116 -0
  28. package/dist/db/index.js.map +1 -0
  29. package/dist/db/schema.sql +282 -0
  30. package/dist/graph/amem.d.ts +80 -0
  31. package/dist/graph/amem.js +190 -0
  32. package/dist/graph/amem.js.map +1 -0
  33. package/dist/graph/entities.d.ts +66 -0
  34. package/dist/graph/entities.js +187 -0
  35. package/dist/graph/entities.js.map +1 -0
  36. package/dist/graph/queries.d.ts +48 -0
  37. package/dist/graph/queries.js +176 -0
  38. package/dist/graph/queries.js.map +1 -0
  39. package/dist/hitl/dashboard.d.ts +51 -0
  40. package/dist/hitl/dashboard.js +135 -0
  41. package/dist/hitl/dashboard.js.map +1 -0
  42. package/dist/hitl/interventions.d.ts +36 -0
  43. package/dist/hitl/interventions.js +150 -0
  44. package/dist/hitl/interventions.js.map +1 -0
  45. package/dist/hitl/steering.d.ts +37 -0
  46. package/dist/hitl/steering.js +118 -0
  47. package/dist/hitl/steering.js.map +1 -0
  48. package/dist/index.d.ts +12 -0
  49. package/dist/index.js +701 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/memory/consolidation.d.ts +51 -0
  52. package/dist/memory/consolidation.js +122 -0
  53. package/dist/memory/consolidation.js.map +1 -0
  54. package/dist/memory/ncd.d.ts +40 -0
  55. package/dist/memory/ncd.js +90 -0
  56. package/dist/memory/ncd.js.map +1 -0
  57. package/dist/memory/sm2.d.ts +44 -0
  58. package/dist/memory/sm2.js +119 -0
  59. package/dist/memory/sm2.js.map +1 -0
  60. package/dist/memory/tiers.d.ts +49 -0
  61. package/dist/memory/tiers.js +145 -0
  62. package/dist/memory/tiers.js.map +1 -0
  63. package/dist/server.d.ts +6 -0
  64. package/dist/server.js +6 -0
  65. package/dist/server.js.map +1 -0
  66. package/dist/trust/ingestion.d.ts +38 -0
  67. package/dist/trust/ingestion.js +147 -0
  68. package/dist/trust/ingestion.js.map +1 -0
  69. package/dist/trust/patterns.d.ts +26 -0
  70. package/dist/trust/patterns.js +78 -0
  71. package/dist/trust/patterns.js.map +1 -0
  72. package/dist/trust/scoring.d.ts +39 -0
  73. package/dist/trust/scoring.js +206 -0
  74. package/dist/trust/scoring.js.map +1 -0
  75. package/package.json +58 -0
@@ -0,0 +1,199 @@
1
+ /**
2
+ * Quality Gates — Evaluation between cascade phases
3
+ *
4
+ * Four stopping gates (information-theoretic):
5
+ * 1. Compression plateau — MDL not decreasing
6
+ * 2. Diminishing returns — new findings below threshold
7
+ * 3. Entropy floor — knowledge graph structure stabilized
8
+ * 4. MDL increasing — model growing without explanatory gain
9
+ *
10
+ * Plus inter-phase gates that validate readiness to advance.
11
+ */
12
+ import { getDb } from '../db/index.js';
13
+ /**
14
+ * Check all four stopping conditions.
15
+ * If ANY gate says stop, cascade should conclude.
16
+ */
17
+ export function evaluateStoppingGates(cascadeId) {
18
+ const db = getDb();
19
+ const cascade = db.prepare('SELECT * FROM cascades WHERE id = ?').get(cascadeId);
20
+ if (!cascade)
21
+ throw new Error(`Cascade ${cascadeId} not found`);
22
+ const gates = [];
23
+ // 1. Max rounds reached
24
+ const roundGate = {
25
+ gate: 'max_rounds',
26
+ passed: cascade.current_round < cascade.max_rounds,
27
+ value: cascade.current_round,
28
+ threshold: cascade.max_rounds,
29
+ description: `Round ${cascade.current_round}/${cascade.max_rounds}`,
30
+ };
31
+ gates.push(roundGate);
32
+ // 2. Token budget exhausted
33
+ const tokenGate = {
34
+ gate: 'token_budget',
35
+ passed: cascade.tokens_used < cascade.token_budget,
36
+ value: cascade.tokens_used,
37
+ threshold: cascade.token_budget,
38
+ description: `Tokens ${cascade.tokens_used}/${cascade.token_budget}`,
39
+ };
40
+ gates.push(tokenGate);
41
+ // 3. Diminishing returns — compare findings count between last 2 rounds
42
+ const findingsByRound = db.prepare(`SELECT cascade_round, COUNT(*) as n
43
+ FROM findings WHERE cascade_id = ? AND quarantined = 0
44
+ GROUP BY cascade_round ORDER BY cascade_round DESC LIMIT 2`)
45
+ .all(cascadeId);
46
+ if (findingsByRound.length >= 2) {
47
+ const currentRoundFindings = findingsByRound[0].n;
48
+ const prevRoundFindings = findingsByRound[1].n;
49
+ const ratio = prevRoundFindings > 0 ? currentRoundFindings / prevRoundFindings : 1;
50
+ const dimGate = {
51
+ gate: 'diminishing_returns',
52
+ passed: ratio > 0.3, // Stop if new findings < 30% of previous round
53
+ value: ratio,
54
+ threshold: 0.3,
55
+ description: `New findings ratio: ${Math.round(ratio * 100)}% (${currentRoundFindings} vs ${prevRoundFindings})`,
56
+ };
57
+ gates.push(dimGate);
58
+ }
59
+ // 4. Confidence convergence — average confidence above threshold
60
+ const avgConf = db.prepare(`SELECT AVG(confidence) as avg_conf
61
+ FROM findings WHERE cascade_id = ? AND quarantined = 0`)
62
+ .get(cascadeId);
63
+ if (avgConf?.avg_conf !== null) {
64
+ const confGate = {
65
+ gate: 'confidence_convergence',
66
+ passed: avgConf.avg_conf < 0.85, // Stop if avg confidence very high (saturated)
67
+ value: avgConf.avg_conf,
68
+ threshold: 0.85,
69
+ description: `Avg confidence: ${Math.round(avgConf.avg_conf * 1000) / 1000}`,
70
+ };
71
+ gates.push(confGate);
72
+ }
73
+ // 5. Entropy convergence — check recent entropy metrics
74
+ const entropyMetrics = db.prepare(`SELECT metric_value FROM metrics
75
+ WHERE cascade_id = ? AND metric_name = 'entropy'
76
+ ORDER BY recorded_at DESC LIMIT 3`)
77
+ .all(cascadeId);
78
+ if (entropyMetrics.length >= 3) {
79
+ const deltas = [];
80
+ for (let i = 0; i < entropyMetrics.length - 1; i++) {
81
+ deltas.push(Math.abs(entropyMetrics[i].metric_value - entropyMetrics[i + 1].metric_value));
82
+ }
83
+ const avgDelta = deltas.reduce((s, d) => s + d, 0) / deltas.length;
84
+ const entropyGate = {
85
+ gate: 'entropy_floor',
86
+ passed: avgDelta > 0.01, // Stop if entropy change < 1%
87
+ value: avgDelta,
88
+ threshold: 0.01,
89
+ description: `Entropy delta: ${Math.round(avgDelta * 10000) / 10000}`,
90
+ };
91
+ gates.push(entropyGate);
92
+ }
93
+ const shouldStop = gates.some(g => !g.passed);
94
+ let recommendation = 'Continue research.';
95
+ if (shouldStop) {
96
+ const failedGates = gates.filter(g => !g.passed).map(g => g.gate);
97
+ recommendation = `Stop: ${failedGates.join(', ')}. ${failedGates.includes('max_rounds') ? 'Maximum rounds reached.' :
98
+ failedGates.includes('token_budget') ? 'Token budget exhausted.' :
99
+ failedGates.includes('diminishing_returns') ? 'New findings dropping sharply — research saturated.' :
100
+ failedGates.includes('confidence_convergence') ? 'High confidence across findings — answers converged.' :
101
+ 'Knowledge graph structure stabilized.'}`;
102
+ }
103
+ return { shouldStop, gates, recommendation };
104
+ }
105
+ /**
106
+ * Validate readiness to advance from one phase to the next.
107
+ * Returns issues that should be resolved before advancing.
108
+ */
109
+ export function validatePhaseGate(cascadeId, fromPhase, toPhase) {
110
+ const db = getDb();
111
+ const issues = [];
112
+ switch (fromPhase) {
113
+ case 'identify': {
114
+ // Need at least 1 thread created
115
+ const threads = db.prepare('SELECT COUNT(*) as n FROM threads WHERE cascade_id = ? AND status IN (\'active\',\'done\')').get(cascadeId).n;
116
+ if (threads === 0)
117
+ issues.push('No research threads created. Decompose the question into sub-questions first.');
118
+ break;
119
+ }
120
+ case 'screen': {
121
+ // Need findings to have been screened (trust scores applied)
122
+ const unscored = db.prepare('SELECT COUNT(*) as n FROM findings WHERE cascade_id = ? AND trust_composite = 0.5 AND trust_signals_json IS NULL').get(cascadeId).n;
123
+ if (unscored > 0)
124
+ issues.push(`${unscored} findings haven't been trust-scored yet.`);
125
+ break;
126
+ }
127
+ case 'evaluate': {
128
+ // Need at least some findings with confidence > 0
129
+ const evaluated = db.prepare('SELECT COUNT(*) as n FROM findings WHERE cascade_id = ? AND quarantined = 0').get(cascadeId).n;
130
+ if (evaluated === 0)
131
+ issues.push('No non-quarantined findings. All findings were rejected or quarantined.');
132
+ break;
133
+ }
134
+ case 'consolidate': {
135
+ // Just check we have entities in the graph
136
+ // (consolidation creates entities — so this is post-facto)
137
+ break;
138
+ }
139
+ case 'mature': {
140
+ // Need at least 1 hypothesis
141
+ const hyps = db.prepare('SELECT COUNT(*) as n FROM hypotheses WHERE cascade_id = ?').get(cascadeId).n;
142
+ if (hyps === 0)
143
+ issues.push('No hypotheses to mature. Create at least one hypothesis from findings.');
144
+ break;
145
+ }
146
+ case 'prune': {
147
+ // No hard requirements — pruning is optional
148
+ break;
149
+ }
150
+ case 'synthesize': {
151
+ // Need findings to synthesize
152
+ const findings = db.prepare('SELECT COUNT(*) as n FROM findings WHERE cascade_id = ? AND quarantined = 0').get(cascadeId).n;
153
+ if (findings === 0)
154
+ issues.push('No findings to synthesize.');
155
+ break;
156
+ }
157
+ case 'observe': {
158
+ // Terminal — check stopping conditions
159
+ break;
160
+ }
161
+ }
162
+ return { ready: issues.length === 0, issues };
163
+ }
164
+ /**
165
+ * Calculate information-theoretic metrics for the current round.
166
+ */
167
+ export function calculateRoundMetrics(cascadeId) {
168
+ const db = getDb();
169
+ const cascade = db.prepare('SELECT * FROM cascades WHERE id = ?').get(cascadeId);
170
+ if (!cascade)
171
+ throw new Error(`Cascade ${cascadeId} not found`);
172
+ const plan = cascade.plan_json ? JSON.parse(cascade.plan_json) : null;
173
+ const totalQuestions = plan?.questions?.length || 1;
174
+ // Coverage: what fraction of questions have findings
175
+ const questionsWithFindings = db.prepare(`SELECT COUNT(DISTINCT t.question) as n
176
+ FROM threads t JOIN findings f ON t.id = f.thread_id
177
+ WHERE t.cascade_id = ? AND f.quarantined = 0`)
178
+ .get(cascadeId);
179
+ const coverage = Math.min(1, (questionsWithFindings?.n || 0) / totalQuestions);
180
+ // Depth: average findings per question
181
+ const totalFindings = db.prepare('SELECT COUNT(*) as n FROM findings WHERE cascade_id = ? AND quarantined = 0').get(cascadeId).n;
182
+ const depth = Math.min(1, totalFindings / (totalQuestions * 10)); // 10 findings/question = max depth
183
+ // Confidence: average confidence of non-quarantined findings
184
+ const avgConf = db.prepare('SELECT AVG(confidence) as v FROM findings WHERE cascade_id = ? AND quarantined = 0').get(cascadeId)?.v || 0;
185
+ // Source quality: average trust score
186
+ const avgTrust = db.prepare('SELECT AVG(trust_composite) as v FROM findings WHERE cascade_id = ? AND quarantined = 0').get(cascadeId)?.v || 0.5;
187
+ // Graph density: 2|E|/(|V|(|V|-1)) — but capped at 1
188
+ const V = db.prepare('SELECT COUNT(*) as n FROM kg_entities').get().n;
189
+ const E = db.prepare('SELECT COUNT(*) as n FROM kg_edges').get().n;
190
+ const graphDensity = V > 1 ? Math.min(1, (2 * E) / (V * (V - 1))) : 0;
191
+ return {
192
+ coverage,
193
+ depth,
194
+ confidence: avgConf,
195
+ sourceQuality: avgTrust,
196
+ graphDensity,
197
+ };
198
+ }
199
+ //# sourceMappingURL=gates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gates.js","sourceRoot":"","sources":["../../src/cascade/gates.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Research Integration — Search/fetch pipeline
3
+ *
4
+ * Provides structured interfaces for research operations.
5
+ * The LLM performs actual web_search/web_fetch — this module
6
+ * structures the inputs/outputs and tracks the process.
7
+ */
8
+ export interface SearchPlan {
9
+ cascadeId: string;
10
+ roundIndex: number;
11
+ queries: SearchQuery[];
12
+ explorationBudget: number;
13
+ }
14
+ export interface SearchQuery {
15
+ query: string;
16
+ type: 'exploration' | 'exploitation' | 'validation';
17
+ priority: number;
18
+ threadId?: string;
19
+ }
20
+ export interface RawFinding {
21
+ claim: string;
22
+ evidence?: string;
23
+ sourceUrl?: string;
24
+ sourceType?: 'primary' | 'secondary' | 'tertiary';
25
+ rawConfidence?: number;
26
+ }
27
+ /**
28
+ * Build a search plan from cascade state.
29
+ * Generates queries based on questions, existing findings, and gaps.
30
+ */
31
+ export declare function buildSearchPlan(cascadeId: string): SearchPlan;
32
+ /**
33
+ * Classify a query to determine which model should handle it.
34
+ * Returns routing info for multi-model dispatch.
35
+ */
36
+ export declare function classifyQuery(query: string): {
37
+ type: 'technical' | 'discovery' | 'classification' | 'validation';
38
+ suggestedModel: string;
39
+ suggestedAgent: string;
40
+ reasoning: string;
41
+ };
42
+ /**
43
+ * Batch store findings from a research round.
44
+ * Returns count of new vs duplicate findings.
45
+ */
46
+ export declare function batchStoreFindings(cascadeId: string, roundIndex: number, threadId: string | undefined, findings: RawFinding[]): {
47
+ stored: number;
48
+ duplicates: number;
49
+ };
50
+ //# sourceMappingURL=research.d.ts.map
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Research Integration — Search/fetch pipeline
3
+ *
4
+ * Provides structured interfaces for research operations.
5
+ * The LLM performs actual web_search/web_fetch — this module
6
+ * structures the inputs/outputs and tracks the process.
7
+ */
8
+ import { getDb, contentHash } from '../db/index.js';
9
+ // --- Functions ---
10
+ /**
11
+ * Build a search plan from cascade state.
12
+ * Generates queries based on questions, existing findings, and gaps.
13
+ */
14
+ export function buildSearchPlan(cascadeId) {
15
+ const db = getDb();
16
+ const cascade = db.prepare('SELECT * FROM cascades WHERE id = ?').get(cascadeId);
17
+ if (!cascade)
18
+ throw new Error(`Cascade ${cascadeId} not found`);
19
+ const plan = cascade.plan_json ? JSON.parse(cascade.plan_json) : null;
20
+ const questions = plan?.questions || [cascade.question];
21
+ const roundIndex = cascade.current_round;
22
+ const budget = Math.max(0, 1 - roundIndex / cascade.max_rounds);
23
+ const queries = [];
24
+ // Round 0 (SEED): all questions are exploration
25
+ if (roundIndex === 0) {
26
+ for (const q of questions) {
27
+ queries.push({ query: q, type: 'exploration', priority: 1.0 });
28
+ }
29
+ }
30
+ else {
31
+ // Later rounds: mix of exploration, exploitation, validation
32
+ const explorationCount = Math.ceil(questions.length * budget);
33
+ // Exploration: questions without enough findings
34
+ const threadCoverage = db.prepare(`SELECT t.question, COUNT(f.id) as finding_count
35
+ FROM threads t LEFT JOIN findings f ON t.id = f.thread_id AND f.quarantined = 0
36
+ WHERE t.cascade_id = ?
37
+ GROUP BY t.question
38
+ ORDER BY finding_count ASC`)
39
+ .all(cascadeId);
40
+ for (let i = 0; i < Math.min(explorationCount, threadCoverage.length); i++) {
41
+ queries.push({
42
+ query: threadCoverage[i].question,
43
+ type: 'exploration',
44
+ priority: 1.0 - i * 0.1,
45
+ });
46
+ }
47
+ // Exploitation: deepen high-confidence threads
48
+ const highConfThreads = db.prepare(`SELECT t.id, t.question, AVG(f.confidence) as avg_conf
49
+ FROM threads t JOIN findings f ON t.id = f.thread_id
50
+ WHERE t.cascade_id = ? AND f.quarantined = 0
51
+ GROUP BY t.id
52
+ HAVING avg_conf > 0.5
53
+ ORDER BY avg_conf DESC LIMIT 3`)
54
+ .all(cascadeId);
55
+ for (const thread of highConfThreads) {
56
+ queries.push({
57
+ query: thread.question,
58
+ type: 'exploitation',
59
+ priority: thread.avg_conf,
60
+ threadId: thread.id,
61
+ });
62
+ }
63
+ // Validation: cross-check low-confidence findings
64
+ const lowConfFindings = db.prepare(`SELECT claim FROM findings
65
+ WHERE cascade_id = ? AND quarantined = 0 AND confidence < 0.5
66
+ ORDER BY confidence ASC LIMIT 3`)
67
+ .all(cascadeId);
68
+ for (const f of lowConfFindings) {
69
+ queries.push({
70
+ query: `verify: ${f.claim}`,
71
+ type: 'validation',
72
+ priority: 0.8,
73
+ });
74
+ }
75
+ }
76
+ // Sort by priority
77
+ queries.sort((a, b) => b.priority - a.priority);
78
+ return { cascadeId, roundIndex, queries, explorationBudget: budget };
79
+ }
80
+ /**
81
+ * Classify a query to determine which model should handle it.
82
+ * Returns routing info for multi-model dispatch.
83
+ */
84
+ export function classifyQuery(query) {
85
+ const lower = query.toLowerCase();
86
+ // Classification heuristics (simple — LLM should refine these)
87
+ if (lower.includes('verify') || lower.includes('validate') || lower.includes('confirm') || lower.includes('cross-check')) {
88
+ return { type: 'validation', suggestedModel: 'sonnet', suggestedAgent: 'cross-validator', reasoning: 'Validation query — cross-reference with independent sources' };
89
+ }
90
+ if (lower.includes('how') || lower.includes('implementation') || lower.includes('architecture') || lower.includes('benchmark') || lower.includes('performance')) {
91
+ return { type: 'technical', suggestedModel: 'opus', suggestedAgent: 'deep-investigator', reasoning: 'Technical deep-dive — needs strong reasoning' };
92
+ }
93
+ if (lower.includes('what if') || lower.includes('could') || lower.includes('explore') || lower.includes('design') || lower.includes('philosophy')) {
94
+ return { type: 'discovery', suggestedModel: 'sonnet', suggestedAgent: 'research-planner', reasoning: 'Discovery/open-ended — benefits from diverse exploration' };
95
+ }
96
+ if (lower.includes('categorize') || lower.includes('sort') || lower.includes('tag') || lower.includes('extract')) {
97
+ return { type: 'classification', suggestedModel: 'haiku', suggestedAgent: 'research-planner', reasoning: 'Classification task — lightweight model sufficient' };
98
+ }
99
+ // Default: technical
100
+ return { type: 'technical', suggestedModel: 'sonnet', suggestedAgent: 'deep-investigator', reasoning: 'Default routing — general research query' };
101
+ }
102
+ /**
103
+ * Batch store findings from a research round.
104
+ * Returns count of new vs duplicate findings.
105
+ */
106
+ export function batchStoreFindings(cascadeId, roundIndex, threadId, findings) {
107
+ const db = getDb();
108
+ let stored = 0;
109
+ let duplicates = 0;
110
+ const insertStmt = db.prepare(`INSERT INTO findings (id, thread_id, cascade_id, claim, evidence, source_url, source_type, confidence, cascade_round)
111
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
112
+ ON CONFLICT(id) DO UPDATE SET confidence = MAX(confidence, excluded.confidence)`);
113
+ const transaction = db.transaction(() => {
114
+ for (const f of findings) {
115
+ const id = contentHash(f.claim);
116
+ const existing = db.prepare('SELECT id FROM findings WHERE id = ?').get(id);
117
+ insertStmt.run(id, threadId, cascadeId, f.claim, f.evidence, f.sourceUrl, f.sourceType, f.rawConfidence ?? 0.5, roundIndex);
118
+ if (existing)
119
+ duplicates++;
120
+ else
121
+ stored++;
122
+ }
123
+ });
124
+ transaction();
125
+ return { stored, duplicates };
126
+ }
127
+ //# sourceMappingURL=research.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"research.js","sourceRoot":"","sources":["../../src/cascade/research.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * cascade-engine CLI
4
+ *
5
+ * Usage:
6
+ * cascade-engine serve Start MCP stdio server (default)
7
+ * cascade-engine status Show active cascades and DB stats
8
+ * cascade-engine status <id> Show detailed cascade status
9
+ * cascade-engine graph Show knowledge graph stats
10
+ * cascade-engine notes Show Zettelkasten note stats
11
+ * cascade-engine reset Delete the database and start fresh
12
+ * cascade-engine db-path Print the database file path
13
+ * cascade-engine help Show this help
14
+ *
15
+ * Environment:
16
+ * CASCADE_DB_PATH Override database location (default: ~/.cascade-engine/knowledge.db)
17
+ */
18
+ export {};
19
+ //# sourceMappingURL=cli.d.ts.map
package/dist/cli.js ADDED
@@ -0,0 +1,165 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * cascade-engine CLI
4
+ *
5
+ * Usage:
6
+ * cascade-engine serve Start MCP stdio server (default)
7
+ * cascade-engine status Show active cascades and DB stats
8
+ * cascade-engine status <id> Show detailed cascade status
9
+ * cascade-engine graph Show knowledge graph stats
10
+ * cascade-engine notes Show Zettelkasten note stats
11
+ * cascade-engine reset Delete the database and start fresh
12
+ * cascade-engine db-path Print the database file path
13
+ * cascade-engine help Show this help
14
+ *
15
+ * Environment:
16
+ * CASCADE_DB_PATH Override database location (default: ~/.cascade-engine/knowledge.db)
17
+ */
18
+ import { getDb, closeDb } from './db/index.js';
19
+ import { getGraphStats } from './graph/entities.js';
20
+ import { getNoteStats } from './graph/amem.js';
21
+ import { existsSync, unlinkSync } from 'node:fs';
22
+ import { join } from 'node:path';
23
+ const args = process.argv.slice(2);
24
+ const command = args[0] || 'serve';
25
+ async function main() {
26
+ switch (command) {
27
+ case 'serve':
28
+ case 'start': {
29
+ // Dynamic import to avoid loading the full MCP server for other commands
30
+ const { default: startServer } = await import('./server.js');
31
+ await startServer();
32
+ break;
33
+ }
34
+ case 'status': {
35
+ const db = getDb();
36
+ const cascadeId = args[1];
37
+ if (cascadeId) {
38
+ const cascade = db.prepare('SELECT * FROM cascades WHERE id = ? OR id LIKE ?')
39
+ .get(cascadeId, `${cascadeId}%`);
40
+ if (!cascade) {
41
+ console.log(`Cascade "${cascadeId}" not found.`);
42
+ break;
43
+ }
44
+ const findings = db.prepare('SELECT COUNT(*) as n FROM findings WHERE cascade_id = ? AND quarantined = 0').get(cascade.id).n;
45
+ const quarantined = db.prepare('SELECT COUNT(*) as n FROM findings WHERE cascade_id = ? AND quarantined = 1').get(cascade.id).n;
46
+ const hypotheses = db.prepare('SELECT COUNT(*) as n FROM hypotheses WHERE cascade_id = ?').get(cascade.id).n;
47
+ console.log(`Cascade: ${cascade.id}`);
48
+ console.log(`Question: ${cascade.question}`);
49
+ console.log(`Status: ${cascade.status}`);
50
+ console.log(`Round: ${cascade.current_round}/${cascade.max_rounds}`);
51
+ console.log(`Findings: ${findings} (${quarantined} quarantined)`);
52
+ console.log(`Hypotheses: ${hypotheses}`);
53
+ console.log(`Tokens: ${cascade.tokens_used}/${cascade.token_budget}`);
54
+ console.log(`Created: ${cascade.created_at}`);
55
+ }
56
+ else {
57
+ const cascades = db.prepare("SELECT id, question, status, current_round, max_rounds, created_at FROM cascades ORDER BY updated_at DESC").all();
58
+ if (cascades.length === 0) {
59
+ console.log('No cascades found. Start one with cascade_init.');
60
+ }
61
+ else {
62
+ console.log(`${cascades.length} cascade(s):\n`);
63
+ for (const c of cascades) {
64
+ console.log(` ${c.id.slice(0, 8)} ${c.status.padEnd(13)} R${c.current_round}/${c.max_rounds} ${c.question.slice(0, 60)}`);
65
+ }
66
+ }
67
+ const findings = db.prepare('SELECT COUNT(*) as n FROM findings').get().n;
68
+ const entities = db.prepare('SELECT COUNT(*) as n FROM kg_entities').get().n;
69
+ const edges = db.prepare('SELECT COUNT(*) as n FROM kg_edges').get().n;
70
+ console.log(`\nDB totals: ${findings} findings, ${entities} entities, ${edges} edges`);
71
+ }
72
+ closeDb();
73
+ break;
74
+ }
75
+ case 'graph': {
76
+ const stats = getGraphStats();
77
+ console.log('Knowledge Graph:');
78
+ console.log(` Entities: ${stats.entityCount}`);
79
+ console.log(` Edges: ${stats.edgeCount}`);
80
+ console.log(` Avg degree: ${stats.avgDegree.toFixed(2)}`);
81
+ console.log(` Communities: ${stats.communityCounts}`);
82
+ console.log(` Orphans: ${stats.orphanCount}`);
83
+ console.log(` Tiers: ${JSON.stringify(stats.tierCounts)}`);
84
+ closeDb();
85
+ break;
86
+ }
87
+ case 'notes': {
88
+ const stats = getNoteStats();
89
+ console.log('Zettelkasten Notes:');
90
+ console.log(` Total: ${stats.totalNotes}`);
91
+ console.log(` Links: ${stats.totalLinks}`);
92
+ console.log(` Orphans: ${stats.orphanCount}`);
93
+ console.log(` Maturity: ${JSON.stringify(stats.maturityCounts)}`);
94
+ console.log(` Types: ${JSON.stringify(stats.typeCounts)}`);
95
+ closeDb();
96
+ break;
97
+ }
98
+ case 'db-path': {
99
+ const home = process.env.HOME || process.env.USERPROFILE || '';
100
+ const dbPath = process.env.CASCADE_DB_PATH || join(home, '.cascade-engine', 'knowledge.db');
101
+ console.log(dbPath);
102
+ break;
103
+ }
104
+ case 'reset': {
105
+ const home = process.env.HOME || process.env.USERPROFILE || '';
106
+ const dbPath = process.env.CASCADE_DB_PATH || join(home, '.cascade-engine', 'knowledge.db');
107
+ if (existsSync(dbPath)) {
108
+ unlinkSync(dbPath);
109
+ // Clean up WAL and SHM files
110
+ if (existsSync(dbPath + '-wal'))
111
+ unlinkSync(dbPath + '-wal');
112
+ if (existsSync(dbPath + '-shm'))
113
+ unlinkSync(dbPath + '-shm');
114
+ console.log(`Deleted: ${dbPath}`);
115
+ }
116
+ else {
117
+ console.log('No database found.');
118
+ }
119
+ break;
120
+ }
121
+ case 'help':
122
+ case '--help':
123
+ case '-h': {
124
+ console.log(`cascade-engine — Progressive deep research MCP server
125
+
126
+ Usage:
127
+ cascade-engine serve Start MCP stdio server (default)
128
+ cascade-engine status Show active cascades and DB stats
129
+ cascade-engine status <id> Detailed cascade status
130
+ cascade-engine graph Knowledge graph statistics
131
+ cascade-engine notes Zettelkasten note statistics
132
+ cascade-engine db-path Print database file path
133
+ cascade-engine reset Delete database and start fresh
134
+ cascade-engine help Show this help
135
+
136
+ MCP Integration:
137
+ Add to your .mcp.json (Claude Code) or equivalent:
138
+
139
+ {
140
+ "mcpServers": {
141
+ "cascade-engine": {
142
+ "command": "cascade-engine",
143
+ "args": ["serve"]
144
+ }
145
+ }
146
+ }
147
+
148
+ Environment:
149
+ CASCADE_DB_PATH Override database location
150
+ Default: ~/.cascade-engine/knowledge.db
151
+
152
+ More info: https://github.com/geoff-obsidicore/Research-Cascade`);
153
+ break;
154
+ }
155
+ default:
156
+ console.error(`Unknown command: ${command}`);
157
+ console.error('Run "cascade-engine help" for usage.');
158
+ process.exit(1);
159
+ }
160
+ }
161
+ main().catch((err) => {
162
+ console.error('Fatal:', err);
163
+ process.exit(1);
164
+ });
165
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Kalman Filter — Confidence fusion from multiple noisy sources
3
+ *
4
+ * K = P / (P + R)
5
+ * confidence += K × (measurement - confidence)
6
+ * uncertainty = (1 - K) × P
7
+ *
8
+ * High R (unreliable source) → low K → measurement discounted
9
+ * High P (uncertain claim) → high K → updated aggressively
10
+ */
11
+ export interface KalmanState {
12
+ estimate: number;
13
+ uncertainty: number;
14
+ }
15
+ /**
16
+ * Create initial Kalman state for a new finding.
17
+ */
18
+ export declare function createKalmanState(initialEstimate?: number, initialUncertainty?: number): KalmanState;
19
+ /**
20
+ * Update Kalman estimate with a new measurement.
21
+ *
22
+ * @param state Current Kalman state
23
+ * @param measurement New confidence measurement (0-1)
24
+ * @param measurementNoise R — noise of the measurement source (higher = less reliable)
25
+ * @returns Updated state
26
+ */
27
+ export declare function kalmanUpdate(state: KalmanState, measurement: number, measurementNoise: number): KalmanState;
28
+ /**
29
+ * Fuse multiple measurements at once.
30
+ * Each measurement has its own noise level based on source reliability.
31
+ */
32
+ export declare function fuseConfidence(measurements: {
33
+ value: number;
34
+ noise: number;
35
+ }[], initialEstimate?: number, initialUncertainty?: number): KalmanState;
36
+ /**
37
+ * Map source type to measurement noise.
38
+ * Lower noise = more trusted source.
39
+ */
40
+ export declare function sourceToNoise(sourceType: string | undefined, trustScore: number): number;
41
+ /**
42
+ * Batch update: apply multiple findings' confidence to a single claim.
43
+ * Returns the fused confidence and remaining uncertainty.
44
+ */
45
+ export declare function batchFuseForClaim(existingConfidence: number, existingUncertainty: number, newMeasurements: {
46
+ confidence: number;
47
+ sourceType?: string;
48
+ trustScore: number;
49
+ }[]): {
50
+ confidence: number;
51
+ uncertainty: number;
52
+ };
53
+ //# sourceMappingURL=kalman.d.ts.map