beecork 1.3.11 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -4
- package/dist/channels/command-handler.js +0 -14
- package/dist/channels/telegram.js +80 -93
- package/dist/channels/types.d.ts +0 -2
- package/dist/cli/channel.js +0 -1
- package/dist/cli/setup.js +5 -82
- package/dist/config.js +9 -25
- package/dist/daemon.js +5 -21
- package/dist/db/index.js +1 -2
- package/dist/db/migrations.js +10 -11
- package/dist/index.js +0 -23
- package/dist/mcp/server.js +5 -10
- package/dist/session/manager.d.ts +0 -1
- package/dist/session/manager.js +5 -32
- package/dist/tasks/scheduler.js +0 -3
- package/dist/types.d.ts +2 -17
- package/package.json +16 -18
- package/dist/machines/index.d.ts +0 -1
- package/dist/machines/index.js +0 -1
- package/dist/machines/registry.d.ts +0 -15
- package/dist/machines/registry.js +0 -46
- package/dist/memory/extractor.d.ts +0 -5
- package/dist/memory/extractor.js +0 -157
- package/dist/pipe/anthropic-client.d.ts +0 -14
- package/dist/pipe/anthropic-client.js +0 -98
- package/dist/pipe/brain.d.ts +0 -22
- package/dist/pipe/brain.js +0 -160
- package/dist/pipe/memory-store.d.ts +0 -10
- package/dist/pipe/memory-store.js +0 -50
- package/dist/pipe/project-scanner.d.ts +0 -6
- package/dist/pipe/project-scanner.js +0 -26
- package/dist/pipe/types.d.ts +0 -46
- package/dist/pipe/types.js +0 -1
package/dist/pipe/brain.js
DELETED
|
@@ -1,160 +0,0 @@
|
|
|
1
|
-
import { PipeAnthropicClient } from './anthropic-client.js';
|
|
2
|
-
import { PipeMemoryStore } from './memory-store.js';
|
|
3
|
-
import { scanForProjects } from './project-scanner.js';
|
|
4
|
-
import { parseTabMessage } from '../util/text.js';
|
|
5
|
-
import { logger } from '../util/logger.js';
|
|
6
|
-
export class PipeBrain {
|
|
7
|
-
client;
|
|
8
|
-
memory;
|
|
9
|
-
config;
|
|
10
|
-
tabManager;
|
|
11
|
-
notifyCallback = null;
|
|
12
|
-
constructor(config, tabManager) {
|
|
13
|
-
this.config = config;
|
|
14
|
-
this.tabManager = tabManager;
|
|
15
|
-
this.client = new PipeAnthropicClient(config.pipe.anthropicApiKey, config.pipe.routingModel, config.pipe.complexModel);
|
|
16
|
-
this.memory = new PipeMemoryStore();
|
|
17
|
-
}
|
|
18
|
-
setNotifyCallback(cb) {
|
|
19
|
-
this.notifyCallback = cb;
|
|
20
|
-
}
|
|
21
|
-
/** Main entry point: process a user message with intelligence */
|
|
22
|
-
async process(message, context) {
|
|
23
|
-
const decisions = [];
|
|
24
|
-
// Step 1: Route the message to the right tab/project
|
|
25
|
-
const route = await this.route(message, decisions);
|
|
26
|
-
// Step 2: Ensure the tab exists with the right working directory
|
|
27
|
-
if (route.projectPath) {
|
|
28
|
-
this.tabManager.ensureTab(route.tabName, route.projectPath);
|
|
29
|
-
this.memory.updateProjectLastUsed(route.projectPath);
|
|
30
|
-
}
|
|
31
|
-
// Step 3: Send to Claude Code
|
|
32
|
-
let result;
|
|
33
|
-
try {
|
|
34
|
-
result = await this.tabManager.sendMessage(route.tabName, message, { skipExtraction: true, projectPath: route.projectPath ?? undefined });
|
|
35
|
-
}
|
|
36
|
-
catch (err) {
|
|
37
|
-
return {
|
|
38
|
-
tabName: route.tabName,
|
|
39
|
-
response: { text: `Error: ${err instanceof Error ? err.message : err}`, error: true, costUsd: 0, durationMs: 0 },
|
|
40
|
-
decisions,
|
|
41
|
-
goalStatus: null,
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
// Step 4: Evaluate if the goal was achieved
|
|
45
|
-
let goalStatus = null;
|
|
46
|
-
if (!result.error && result.text && result.durationMs > 3000) {
|
|
47
|
-
goalStatus = await this.evaluateAndFollowUp(message, result, route.tabName, decisions);
|
|
48
|
-
}
|
|
49
|
-
// Step 5: Learn from the conversation (fire and forget)
|
|
50
|
-
this.learn(route.tabName, message, result.text).catch(err => {
|
|
51
|
-
logger.error('Pipe learning failed:', err);
|
|
52
|
-
});
|
|
53
|
-
return {
|
|
54
|
-
tabName: route.tabName,
|
|
55
|
-
response: { text: result.text, error: result.error, costUsd: result.costUsd, durationMs: result.durationMs },
|
|
56
|
-
decisions,
|
|
57
|
-
goalStatus,
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
/** Route a message to the right project/tab */
|
|
61
|
-
async route(message, decisions) {
|
|
62
|
-
// Check for manual /tab override first
|
|
63
|
-
if (message.startsWith('/tab ')) {
|
|
64
|
-
const parsed = parseTabMessage(message);
|
|
65
|
-
if (parsed.tabName !== 'default') {
|
|
66
|
-
decisions.push(`📌 Manual routing to "${parsed.tabName}"`);
|
|
67
|
-
return { tabName: parsed.tabName, projectPath: null, confidence: 1.0, reason: 'Manual override', needsConfirmation: false };
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
const projects = this.memory.getProjects();
|
|
71
|
-
const recentRouting = this.memory.getRecentRouting(5);
|
|
72
|
-
// If no projects and no API key, just use default
|
|
73
|
-
if (projects.length === 0 || !this.config.pipe.anthropicApiKey) {
|
|
74
|
-
decisions.push('📍 Routing to default tab (no projects discovered)');
|
|
75
|
-
return { tabName: 'default', projectPath: null, confidence: 1.0, reason: 'No projects', needsConfirmation: false };
|
|
76
|
-
}
|
|
77
|
-
try {
|
|
78
|
-
const route = await this.client.route(message, projects, recentRouting);
|
|
79
|
-
// Record the routing decision
|
|
80
|
-
this.memory.recordRouting(message, route.tabName, route.projectPath, route.confidence);
|
|
81
|
-
if (route.confidence >= this.config.pipe.confidenceThreshold) {
|
|
82
|
-
decisions.push(`🧠 Routing to "${route.tabName}" (${Math.round(route.confidence * 100)}% confidence) — ${route.reason}`);
|
|
83
|
-
}
|
|
84
|
-
else {
|
|
85
|
-
decisions.push(`🤔 Low confidence routing to "${route.tabName}" (${Math.round(route.confidence * 100)}%) — ${route.reason}. Using default.`);
|
|
86
|
-
route.tabName = 'default';
|
|
87
|
-
}
|
|
88
|
-
return route;
|
|
89
|
-
}
|
|
90
|
-
catch (err) {
|
|
91
|
-
logger.error('Pipe routing failed, using default:', err);
|
|
92
|
-
decisions.push('⚠️ Routing failed, using default tab');
|
|
93
|
-
return { tabName: 'default', projectPath: null, confidence: 0.5, reason: 'Routing error', needsConfirmation: false };
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
/** Evaluate if the goal was achieved and send follow-ups if needed */
|
|
97
|
-
async evaluateAndFollowUp(originalGoal, lastResult, tabName, decisions) {
|
|
98
|
-
let currentResult = lastResult;
|
|
99
|
-
let followUpCount = 0;
|
|
100
|
-
const maxFollowUps = this.config.pipe.maxFollowUps;
|
|
101
|
-
while (followUpCount < maxFollowUps) {
|
|
102
|
-
try {
|
|
103
|
-
const evaluation = await this.client.evaluateGoal(originalGoal, currentResult.text);
|
|
104
|
-
if (evaluation.status === 'done') {
|
|
105
|
-
decisions.push(`✅ Goal achieved: ${evaluation.reason}`);
|
|
106
|
-
return evaluation;
|
|
107
|
-
}
|
|
108
|
-
if (evaluation.status === 'failed') {
|
|
109
|
-
decisions.push(`❌ Goal failed: ${evaluation.reason}`);
|
|
110
|
-
return evaluation;
|
|
111
|
-
}
|
|
112
|
-
// PARTIAL — send follow-up
|
|
113
|
-
followUpCount++;
|
|
114
|
-
const followUpMsg = evaluation.followUp || `Continue working on the original goal: "${originalGoal}". You haven't finished yet.`;
|
|
115
|
-
decisions.push(`🔄 Follow-up ${followUpCount}/${maxFollowUps}: ${evaluation.reason}`);
|
|
116
|
-
// Notify user about the follow-up
|
|
117
|
-
await this.notifyCallback?.(`🔄 [${tabName}] Sending follow-up (${followUpCount}/${maxFollowUps}): ${evaluation.reason}`);
|
|
118
|
-
// Send follow-up to Claude Code
|
|
119
|
-
currentResult = await this.tabManager.sendMessage(tabName, followUpMsg);
|
|
120
|
-
if (currentResult.error) {
|
|
121
|
-
decisions.push(`❌ Follow-up failed with error`);
|
|
122
|
-
return { status: 'failed', reason: currentResult.text, followUp: null };
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
catch (err) {
|
|
126
|
-
logger.error('Goal evaluation failed:', err);
|
|
127
|
-
return { status: 'done', reason: 'Evaluation error — assuming done', followUp: null };
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
decisions.push(`⚠️ Max follow-ups (${maxFollowUps}) reached`);
|
|
131
|
-
return { status: 'partial', reason: `Reached max ${maxFollowUps} follow-ups`, followUp: null };
|
|
132
|
-
}
|
|
133
|
-
/** Learn from a completed conversation */
|
|
134
|
-
async learn(tabName, userMessage, response) {
|
|
135
|
-
if (!response || response.length < 100)
|
|
136
|
-
return;
|
|
137
|
-
try {
|
|
138
|
-
const existingFacts = this.memory.getKnowledge('', 10);
|
|
139
|
-
const entries = await this.client.extractKnowledge(`User: ${userMessage}\n\nAssistant: ${response}`, existingFacts);
|
|
140
|
-
for (const entry of entries) {
|
|
141
|
-
entry.tabName = tabName;
|
|
142
|
-
this.memory.addKnowledge(entry);
|
|
143
|
-
}
|
|
144
|
-
if (entries.length > 0) {
|
|
145
|
-
logger.info(`Pipe learned ${entries.length} facts from ${tabName}`);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
catch (err) {
|
|
149
|
-
logger.error('Pipe learning error:', err);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
/** Discover projects on the filesystem */
|
|
153
|
-
async discoverProjects() {
|
|
154
|
-
const projects = scanForProjects(this.config.pipe.projectScanPaths);
|
|
155
|
-
for (const project of projects) {
|
|
156
|
-
this.memory.upsertProject(project);
|
|
157
|
-
}
|
|
158
|
-
return projects.length;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import type { Project, KnowledgeEntry } from './types.js';
|
|
2
|
-
export declare class PipeMemoryStore {
|
|
3
|
-
getProjects(): Project[];
|
|
4
|
-
upsertProject(project: Project): void;
|
|
5
|
-
updateProjectLastUsed(path: string): void;
|
|
6
|
-
getRecentRouting(limit?: number): string[];
|
|
7
|
-
recordRouting(messagePreview: string, tabName: string, projectPath: string | null, confidence: number): void;
|
|
8
|
-
addKnowledge(entry: KnowledgeEntry): void;
|
|
9
|
-
getKnowledge(query: string, limit?: number): string[];
|
|
10
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { v4 as uuidv4 } from 'uuid';
|
|
2
|
-
import { getDb } from '../db/index.js';
|
|
3
|
-
export class PipeMemoryStore {
|
|
4
|
-
// ─── Projects ───
|
|
5
|
-
getProjects() {
|
|
6
|
-
const db = getDb();
|
|
7
|
-
const rows = db.prepare('SELECT * FROM projects ORDER BY last_used_at DESC NULLS LAST').all();
|
|
8
|
-
return rows.map(r => ({
|
|
9
|
-
id: r.id,
|
|
10
|
-
name: r.name,
|
|
11
|
-
path: r.path,
|
|
12
|
-
type: r.type || 'user-project',
|
|
13
|
-
lastUsedAt: r.last_used_at,
|
|
14
|
-
createdAt: r.created_at,
|
|
15
|
-
}));
|
|
16
|
-
}
|
|
17
|
-
upsertProject(project) {
|
|
18
|
-
const db = getDb();
|
|
19
|
-
db.prepare(`INSERT INTO projects (id, name, path, type)
|
|
20
|
-
VALUES (?, ?, ?, ?)
|
|
21
|
-
ON CONFLICT(name) DO UPDATE SET
|
|
22
|
-
path=excluded.path, type=excluded.type, last_used_at=datetime('now')
|
|
23
|
-
`).run(project.id || uuidv4(), project.name, project.path, project.type || 'user-project');
|
|
24
|
-
}
|
|
25
|
-
updateProjectLastUsed(path) {
|
|
26
|
-
const db = getDb();
|
|
27
|
-
db.prepare('UPDATE projects SET last_used_at = datetime("now") WHERE path = ?').run(path);
|
|
28
|
-
}
|
|
29
|
-
// ─── Routing History ───
|
|
30
|
-
getRecentRouting(limit = 10) {
|
|
31
|
-
const db = getDb();
|
|
32
|
-
const rows = db.prepare('SELECT message_preview, tab_name, confidence FROM routing_history ORDER BY created_at DESC LIMIT ?').all(limit);
|
|
33
|
-
return rows.map(r => `"${r.message_preview}" → ${r.tab_name} (${Math.round(r.confidence * 100)}%)`);
|
|
34
|
-
}
|
|
35
|
-
recordRouting(messagePreview, tabName, projectPath, confidence) {
|
|
36
|
-
const db = getDb();
|
|
37
|
-
db.prepare('INSERT INTO routing_history (message_preview, tab_name, project_path, confidence) VALUES (?, ?, ?, ?)').run(messagePreview.slice(0, 200), tabName, projectPath, confidence);
|
|
38
|
-
}
|
|
39
|
-
// ─── Knowledge ───
|
|
40
|
-
addKnowledge(entry) {
|
|
41
|
-
const db = getDb();
|
|
42
|
-
const content = entry.category ? `[${entry.category}] ${entry.content}` : entry.content;
|
|
43
|
-
db.prepare('INSERT INTO memories (content, tab_name, source) VALUES (?, ?, ?)').run(content, entry.tabName, entry.source);
|
|
44
|
-
}
|
|
45
|
-
getKnowledge(query, limit = 20) {
|
|
46
|
-
const db = getDb();
|
|
47
|
-
const rows = db.prepare('SELECT content FROM memories WHERE content LIKE ? ORDER BY created_at DESC LIMIT ?').all(`%${query}%`, limit);
|
|
48
|
-
return rows.map(r => r.content);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import type { Project } from './types.js';
|
|
2
|
-
/**
|
|
3
|
-
* Read projects from the database (populated by discoverProjects() at daemon startup).
|
|
4
|
-
* Falls back to an empty list if the DB is not yet initialized.
|
|
5
|
-
*/
|
|
6
|
-
export declare function scanForProjects(_scanPaths: string[]): Project[];
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { getDb } from '../db/index.js';
|
|
2
|
-
import { logger } from '../util/logger.js';
|
|
3
|
-
/**
|
|
4
|
-
* Read projects from the database (populated by discoverProjects() at daemon startup).
|
|
5
|
-
* Falls back to an empty list if the DB is not yet initialized.
|
|
6
|
-
*/
|
|
7
|
-
export function scanForProjects(_scanPaths) {
|
|
8
|
-
try {
|
|
9
|
-
const db = getDb();
|
|
10
|
-
const rows = db.prepare('SELECT * FROM projects ORDER BY last_used_at DESC').all();
|
|
11
|
-
const projects = rows.map(r => ({
|
|
12
|
-
id: r.id,
|
|
13
|
-
name: r.name,
|
|
14
|
-
path: r.path,
|
|
15
|
-
type: r.type,
|
|
16
|
-
lastUsedAt: r.last_used_at,
|
|
17
|
-
createdAt: r.created_at,
|
|
18
|
-
}));
|
|
19
|
-
logger.info(`Project scanner: found ${projects.length} projects from DB`);
|
|
20
|
-
return projects;
|
|
21
|
-
}
|
|
22
|
-
catch (err) {
|
|
23
|
-
logger.warn('Project scanner: failed to read from DB, returning empty list:', err);
|
|
24
|
-
return [];
|
|
25
|
-
}
|
|
26
|
-
}
|
package/dist/pipe/types.d.ts
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
export interface Project {
|
|
2
|
-
id: string;
|
|
3
|
-
name: string;
|
|
4
|
-
path: string;
|
|
5
|
-
type: string;
|
|
6
|
-
lastUsedAt: string;
|
|
7
|
-
createdAt: string;
|
|
8
|
-
/** Populated at scan time, not persisted in DB */
|
|
9
|
-
description?: string;
|
|
10
|
-
/** Populated at scan time, not persisted in DB */
|
|
11
|
-
languages?: string[];
|
|
12
|
-
}
|
|
13
|
-
export interface RouteDecision {
|
|
14
|
-
tabName: string;
|
|
15
|
-
projectPath: string | null;
|
|
16
|
-
confidence: number;
|
|
17
|
-
reason: string;
|
|
18
|
-
needsConfirmation: boolean;
|
|
19
|
-
}
|
|
20
|
-
export interface GoalEvaluation {
|
|
21
|
-
status: 'done' | 'partial' | 'failed';
|
|
22
|
-
reason: string;
|
|
23
|
-
followUp: string | null;
|
|
24
|
-
}
|
|
25
|
-
export interface KnowledgeEntry {
|
|
26
|
-
content: string;
|
|
27
|
-
category: 'project' | 'preference' | 'decision' | 'fact';
|
|
28
|
-
tabName: string | null;
|
|
29
|
-
source: 'scan' | 'conversation' | 'user' | 'pipe';
|
|
30
|
-
}
|
|
31
|
-
export interface ChatContext {
|
|
32
|
-
chatId: number;
|
|
33
|
-
userId: number;
|
|
34
|
-
messageId: number;
|
|
35
|
-
}
|
|
36
|
-
export interface PipeResult {
|
|
37
|
-
tabName: string;
|
|
38
|
-
response: {
|
|
39
|
-
text: string;
|
|
40
|
-
error: boolean;
|
|
41
|
-
costUsd: number;
|
|
42
|
-
durationMs: number;
|
|
43
|
-
};
|
|
44
|
-
decisions: string[];
|
|
45
|
-
goalStatus: GoalEvaluation | null;
|
|
46
|
-
}
|
package/dist/pipe/types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|