@siftd/connect-agent 0.2.20 → 0.2.21
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/dist/core/hub.d.ts +45 -0
- package/dist/core/hub.js +231 -0
- package/dist/orchestrator.js +14 -1
- package/package.json +1 -1
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hub - The Agent's Brain Home
|
|
3
|
+
*
|
|
4
|
+
* Manages structured memory files in ~/.connect-hub/
|
|
5
|
+
* Human-readable markdown files that the orchestrator reads/writes.
|
|
6
|
+
*/
|
|
7
|
+
export interface HubContext {
|
|
8
|
+
agentIdentity: string;
|
|
9
|
+
landmarks: string;
|
|
10
|
+
projectBio: string | null;
|
|
11
|
+
projectName: string | null;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Ensure hub directory structure exists
|
|
15
|
+
*/
|
|
16
|
+
export declare function ensureHubExists(): void;
|
|
17
|
+
/**
|
|
18
|
+
* Load hub context for a session
|
|
19
|
+
* Reads AGENTS.md, LANDMARKS.md, and relevant project bio
|
|
20
|
+
*/
|
|
21
|
+
export declare function loadHubContext(message?: string): HubContext;
|
|
22
|
+
/**
|
|
23
|
+
* Format hub context for inclusion in system prompt
|
|
24
|
+
*/
|
|
25
|
+
export declare function formatHubContext(ctx: HubContext): string;
|
|
26
|
+
/**
|
|
27
|
+
* Append to action log
|
|
28
|
+
*/
|
|
29
|
+
export declare function logAction(action: string, project?: string, details?: string): void;
|
|
30
|
+
/**
|
|
31
|
+
* Update or create a project bio
|
|
32
|
+
*/
|
|
33
|
+
export declare function updateProjectBio(projectName: string, content: string): void;
|
|
34
|
+
/**
|
|
35
|
+
* Append learning to a project bio
|
|
36
|
+
*/
|
|
37
|
+
export declare function appendToProjectBio(projectName: string, section: string, content: string): void;
|
|
38
|
+
/**
|
|
39
|
+
* Log a mistake for learning
|
|
40
|
+
*/
|
|
41
|
+
export declare function logMistake(what: string, rootCause: string, fix: string, lesson: string): void;
|
|
42
|
+
/**
|
|
43
|
+
* Update LANDMARKS.md with current state
|
|
44
|
+
*/
|
|
45
|
+
export declare function updateLandmarks(content: string): void;
|
package/dist/core/hub.js
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hub - The Agent's Brain Home
|
|
3
|
+
*
|
|
4
|
+
* Manages structured memory files in ~/.connect-hub/
|
|
5
|
+
* Human-readable markdown files that the orchestrator reads/writes.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, readFileSync, writeFileSync, appendFileSync, mkdirSync } from 'fs';
|
|
8
|
+
import { join } from 'path';
|
|
9
|
+
import { homedir } from 'os';
|
|
10
|
+
const HUB_DIR = join(homedir(), '.connect-hub');
|
|
11
|
+
const PROJECTS_DIR = join(HUB_DIR, 'projects');
|
|
12
|
+
/**
|
|
13
|
+
* Ensure hub directory structure exists
|
|
14
|
+
*/
|
|
15
|
+
export function ensureHubExists() {
|
|
16
|
+
if (!existsSync(HUB_DIR)) {
|
|
17
|
+
mkdirSync(HUB_DIR, { recursive: true });
|
|
18
|
+
}
|
|
19
|
+
if (!existsSync(PROJECTS_DIR)) {
|
|
20
|
+
mkdirSync(PROJECTS_DIR, { recursive: true });
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Read a hub file safely
|
|
25
|
+
*/
|
|
26
|
+
function readHubFile(filename) {
|
|
27
|
+
const path = join(HUB_DIR, filename);
|
|
28
|
+
if (existsSync(path)) {
|
|
29
|
+
try {
|
|
30
|
+
return readFileSync(path, 'utf-8');
|
|
31
|
+
}
|
|
32
|
+
catch (e) {
|
|
33
|
+
console.error(`[HUB] Failed to read ${filename}:`, e);
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Read a project bio
|
|
41
|
+
*/
|
|
42
|
+
function readProjectBio(projectName) {
|
|
43
|
+
// Normalize project name (lowercase, hyphens)
|
|
44
|
+
const normalized = projectName.toLowerCase().replace(/[^a-z0-9-]/g, '-');
|
|
45
|
+
const path = join(PROJECTS_DIR, `${normalized}.md`);
|
|
46
|
+
if (existsSync(path)) {
|
|
47
|
+
try {
|
|
48
|
+
return readFileSync(path, 'utf-8');
|
|
49
|
+
}
|
|
50
|
+
catch (e) {
|
|
51
|
+
console.error(`[HUB] Failed to read project bio ${normalized}:`, e);
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Detect project name from message content
|
|
59
|
+
*/
|
|
60
|
+
function detectProject(message) {
|
|
61
|
+
// Common project patterns
|
|
62
|
+
const patterns = [
|
|
63
|
+
/\b(connect[-_]?app[-_]?2?)\b/i,
|
|
64
|
+
/\b(lia[-_]?live)\b/i,
|
|
65
|
+
/\b(game[-_]?001)\b/i,
|
|
66
|
+
/\bproj(?:ect)?[-_:]?\s*([a-z0-9-]+)/i,
|
|
67
|
+
/\bin\s+([a-z0-9-]+)\s+(?:project|repo|codebase)/i,
|
|
68
|
+
];
|
|
69
|
+
for (const pattern of patterns) {
|
|
70
|
+
const match = message.match(pattern);
|
|
71
|
+
if (match) {
|
|
72
|
+
return match[1].toLowerCase().replace(/[^a-z0-9-]/g, '-');
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Load hub context for a session
|
|
79
|
+
* Reads AGENTS.md, LANDMARKS.md, and relevant project bio
|
|
80
|
+
*/
|
|
81
|
+
export function loadHubContext(message) {
|
|
82
|
+
ensureHubExists();
|
|
83
|
+
const agentIdentity = readHubFile('AGENTS.md') || '';
|
|
84
|
+
const landmarks = readHubFile('LANDMARKS.md') || '';
|
|
85
|
+
let projectBio = null;
|
|
86
|
+
let projectName = null;
|
|
87
|
+
// Try to detect project from message
|
|
88
|
+
if (message) {
|
|
89
|
+
projectName = detectProject(message);
|
|
90
|
+
if (projectName) {
|
|
91
|
+
projectBio = readProjectBio(projectName);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
agentIdentity,
|
|
96
|
+
landmarks,
|
|
97
|
+
projectBio,
|
|
98
|
+
projectName
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Format hub context for inclusion in system prompt
|
|
103
|
+
*/
|
|
104
|
+
export function formatHubContext(ctx) {
|
|
105
|
+
const parts = [];
|
|
106
|
+
if (ctx.landmarks) {
|
|
107
|
+
parts.push(`## Current State (LANDMARKS)\n\n${ctx.landmarks}`);
|
|
108
|
+
}
|
|
109
|
+
if (ctx.projectBio && ctx.projectName) {
|
|
110
|
+
parts.push(`## Project Context: ${ctx.projectName}\n\n${ctx.projectBio}`);
|
|
111
|
+
}
|
|
112
|
+
return parts.join('\n\n---\n\n');
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Append to action log
|
|
116
|
+
*/
|
|
117
|
+
export function logAction(action, project, details) {
|
|
118
|
+
ensureHubExists();
|
|
119
|
+
const logPath = join(HUB_DIR, 'ACTION-LOG.md');
|
|
120
|
+
const now = new Date();
|
|
121
|
+
const timestamp = now.toISOString().slice(0, 16).replace('T', ' ');
|
|
122
|
+
const projectPart = project ? ` — ${project}` : '';
|
|
123
|
+
const detailsPart = details ? ` — ${details}` : '';
|
|
124
|
+
const entry = `${timestamp}${projectPart} — ${action}${detailsPart}\n`;
|
|
125
|
+
try {
|
|
126
|
+
appendFileSync(logPath, entry);
|
|
127
|
+
}
|
|
128
|
+
catch (e) {
|
|
129
|
+
console.error('[HUB] Failed to write action log:', e);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Update or create a project bio
|
|
134
|
+
*/
|
|
135
|
+
export function updateProjectBio(projectName, content) {
|
|
136
|
+
ensureHubExists();
|
|
137
|
+
const normalized = projectName.toLowerCase().replace(/[^a-z0-9-]/g, '-');
|
|
138
|
+
const path = join(PROJECTS_DIR, `${normalized}.md`);
|
|
139
|
+
try {
|
|
140
|
+
writeFileSync(path, content);
|
|
141
|
+
console.log(`[HUB] Updated project bio: ${normalized}`);
|
|
142
|
+
}
|
|
143
|
+
catch (e) {
|
|
144
|
+
console.error(`[HUB] Failed to write project bio ${normalized}:`, e);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Append learning to a project bio
|
|
149
|
+
*/
|
|
150
|
+
export function appendToProjectBio(projectName, section, content) {
|
|
151
|
+
ensureHubExists();
|
|
152
|
+
const normalized = projectName.toLowerCase().replace(/[^a-z0-9-]/g, '-');
|
|
153
|
+
const path = join(PROJECTS_DIR, `${normalized}.md`);
|
|
154
|
+
try {
|
|
155
|
+
let existing = '';
|
|
156
|
+
if (existsSync(path)) {
|
|
157
|
+
existing = readFileSync(path, 'utf-8');
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
existing = `# Project: ${projectName}\n\n`;
|
|
161
|
+
}
|
|
162
|
+
// Append under the section
|
|
163
|
+
const sectionHeader = `## ${section}`;
|
|
164
|
+
if (existing.includes(sectionHeader)) {
|
|
165
|
+
// Append to existing section
|
|
166
|
+
const parts = existing.split(sectionHeader);
|
|
167
|
+
const afterSection = parts[1] || '';
|
|
168
|
+
const nextSectionIndex = afterSection.indexOf('\n## ');
|
|
169
|
+
if (nextSectionIndex > -1) {
|
|
170
|
+
// Insert before next section
|
|
171
|
+
const sectionContent = afterSection.slice(0, nextSectionIndex);
|
|
172
|
+
const rest = afterSection.slice(nextSectionIndex);
|
|
173
|
+
existing = parts[0] + sectionHeader + sectionContent + '\n' + content + '\n' + rest;
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
// Append at end
|
|
177
|
+
existing = existing + '\n' + content + '\n';
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
// Create new section
|
|
182
|
+
existing = existing + `\n${sectionHeader}\n\n${content}\n`;
|
|
183
|
+
}
|
|
184
|
+
writeFileSync(path, existing);
|
|
185
|
+
}
|
|
186
|
+
catch (e) {
|
|
187
|
+
console.error(`[HUB] Failed to append to project bio ${normalized}:`, e);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Log a mistake for learning
|
|
192
|
+
*/
|
|
193
|
+
export function logMistake(what, rootCause, fix, lesson) {
|
|
194
|
+
ensureHubExists();
|
|
195
|
+
const path = join(HUB_DIR, 'MISTAKES.md');
|
|
196
|
+
const now = new Date();
|
|
197
|
+
const date = now.toISOString().slice(0, 10);
|
|
198
|
+
const entry = `
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## ${date} — ${what}
|
|
202
|
+
|
|
203
|
+
**What happened**: ${what}
|
|
204
|
+
|
|
205
|
+
**Root cause**: ${rootCause}
|
|
206
|
+
|
|
207
|
+
**Fix**: ${fix}
|
|
208
|
+
|
|
209
|
+
**Lesson**: ${lesson}
|
|
210
|
+
`;
|
|
211
|
+
try {
|
|
212
|
+
appendFileSync(path, entry);
|
|
213
|
+
}
|
|
214
|
+
catch (e) {
|
|
215
|
+
console.error('[HUB] Failed to write mistake log:', e);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Update LANDMARKS.md with current state
|
|
220
|
+
*/
|
|
221
|
+
export function updateLandmarks(content) {
|
|
222
|
+
ensureHubExists();
|
|
223
|
+
const path = join(HUB_DIR, 'LANDMARKS.md');
|
|
224
|
+
try {
|
|
225
|
+
writeFileSync(path, content);
|
|
226
|
+
console.log('[HUB] Updated LANDMARKS.md');
|
|
227
|
+
}
|
|
228
|
+
catch (e) {
|
|
229
|
+
console.error('[HUB] Failed to update LANDMARKS.md:', e);
|
|
230
|
+
}
|
|
231
|
+
}
|
package/dist/orchestrator.js
CHANGED
|
@@ -16,6 +16,7 @@ import { WebTools } from './tools/web.js';
|
|
|
16
16
|
import { WorkerTools } from './tools/worker.js';
|
|
17
17
|
import { SharedState } from './workers/shared-state.js';
|
|
18
18
|
import { getKnowledgeForPrompt } from './genesis/index.js';
|
|
19
|
+
import { loadHubContext, formatHubContext, logAction } from './core/hub.js';
|
|
19
20
|
const SYSTEM_PROMPT = `You are a MASTER ORCHESTRATOR - NOT a worker. You delegate ALL file/code work to Claude Code CLI workers.
|
|
20
21
|
|
|
21
22
|
CRITICAL IDENTITY:
|
|
@@ -331,11 +332,18 @@ export class MasterOrchestrator {
|
|
|
331
332
|
if (slashResponse) {
|
|
332
333
|
return slashResponse;
|
|
333
334
|
}
|
|
335
|
+
// Load hub context (AGENTS.md identity, LANDMARKS.md state, project bio if relevant)
|
|
336
|
+
const hubContext = loadHubContext(message);
|
|
337
|
+
const hubContextStr = formatHubContext(hubContext);
|
|
334
338
|
// Build context from memory
|
|
335
339
|
const memoryContext = await this.getMemoryContext(message);
|
|
336
|
-
// Build system prompt with genesis knowledge and memory context
|
|
340
|
+
// Build system prompt with hub context, genesis knowledge, and memory context
|
|
337
341
|
const genesisKnowledge = getKnowledgeForPrompt();
|
|
338
342
|
let systemWithContext = SYSTEM_PROMPT + genesisKnowledge;
|
|
343
|
+
// Add hub context (landmarks + project bio)
|
|
344
|
+
if (hubContextStr) {
|
|
345
|
+
systemWithContext += `\n\n---\n\nHUB CONTEXT:\n${hubContextStr}`;
|
|
346
|
+
}
|
|
339
347
|
if (memoryContext) {
|
|
340
348
|
systemWithContext += `\n\nRELEVANT MEMORIES:\n${memoryContext}`;
|
|
341
349
|
}
|
|
@@ -348,6 +356,11 @@ export class MasterOrchestrator {
|
|
|
348
356
|
const response = await this.runAgentLoop(messages, systemWithContext, sendMessage, apiKey);
|
|
349
357
|
// Auto-remember important things from the conversation
|
|
350
358
|
await this.autoRemember(message, response);
|
|
359
|
+
// Log significant actions to hub
|
|
360
|
+
if (response.length > 100) {
|
|
361
|
+
const action = message.length > 50 ? message.slice(0, 50) + '...' : message;
|
|
362
|
+
logAction(action, hubContext.projectName || undefined, `Response: ${response.length} chars`);
|
|
363
|
+
}
|
|
351
364
|
return response;
|
|
352
365
|
}
|
|
353
366
|
catch (error) {
|