@siftd/connect-agent 0.2.24 → 0.2.26
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/heartbeat.js +18 -1
- package/dist/orchestrator.d.ts +11 -1
- package/dist/orchestrator.js +60 -22
- package/dist/workers/manager.d.ts +0 -1
- package/dist/workers/manager.js +48 -29
- package/package.json +1 -1
package/dist/heartbeat.js
CHANGED
|
@@ -8,9 +8,26 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { hostname } from 'os';
|
|
10
10
|
import { createHash } from 'crypto';
|
|
11
|
+
import { readFileSync } from 'fs';
|
|
12
|
+
import { fileURLToPath } from 'url';
|
|
13
|
+
import { dirname, join } from 'path';
|
|
11
14
|
import { getServerUrl, getAgentToken, getUserId, isCloudMode } from './config.js';
|
|
12
15
|
const HEARTBEAT_INTERVAL = 10000; // 10 seconds
|
|
13
|
-
|
|
16
|
+
// Read version from package.json dynamically
|
|
17
|
+
function getVersion() {
|
|
18
|
+
try {
|
|
19
|
+
// Try to find package.json relative to this file
|
|
20
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
21
|
+
const __dirname = dirname(__filename);
|
|
22
|
+
const pkgPath = join(__dirname, '..', 'package.json');
|
|
23
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
|
|
24
|
+
return pkg.version || '0.0.0';
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return '0.0.0';
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const VERSION = getVersion();
|
|
14
31
|
const state = {
|
|
15
32
|
intervalId: null,
|
|
16
33
|
runnerId: null,
|
package/dist/orchestrator.d.ts
CHANGED
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
* It does NOT do the work itself. Claude Code CLI workers do the work.
|
|
6
6
|
*/
|
|
7
7
|
import type { MessageParam } from '@anthropic-ai/sdk/resources/messages';
|
|
8
|
-
import { WorkerAsset } from './core/file-tracker.js';
|
|
9
8
|
export type MessageSender = (message: string) => Promise<void>;
|
|
10
9
|
export interface WorkerStatus {
|
|
11
10
|
id: string;
|
|
@@ -16,6 +15,17 @@ export interface WorkerStatus {
|
|
|
16
15
|
estimated: number;
|
|
17
16
|
}
|
|
18
17
|
export type WorkerStatusCallback = (workers: WorkerStatus[]) => void;
|
|
18
|
+
export interface WorkerAsset {
|
|
19
|
+
path: string;
|
|
20
|
+
name: string;
|
|
21
|
+
type: 'new' | 'modified' | 'unchanged';
|
|
22
|
+
fileType: 'code' | 'image' | 'pdf' | 'text' | 'other';
|
|
23
|
+
preview?: string;
|
|
24
|
+
diff?: Array<{
|
|
25
|
+
type: 'context' | 'add' | 'remove';
|
|
26
|
+
content: string;
|
|
27
|
+
}>;
|
|
28
|
+
}
|
|
19
29
|
export interface GalleryWorker {
|
|
20
30
|
id: string;
|
|
21
31
|
task: string;
|
package/dist/orchestrator.js
CHANGED
|
@@ -17,7 +17,49 @@ import { WorkerTools } from './tools/worker.js';
|
|
|
17
17
|
import { SharedState } from './workers/shared-state.js';
|
|
18
18
|
import { getKnowledgeForPrompt } from './genesis/index.js';
|
|
19
19
|
import { loadHubContext, formatHubContext, logAction } from './core/hub.js';
|
|
20
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Extract file paths from worker output
|
|
22
|
+
* Workers naturally mention files they create: "Created /tmp/foo.html", "Saved to /path/file"
|
|
23
|
+
*/
|
|
24
|
+
function extractFilesFromOutput(output) {
|
|
25
|
+
const assets = [];
|
|
26
|
+
const seen = new Set();
|
|
27
|
+
// Common patterns for file creation/modification in worker output
|
|
28
|
+
const patterns = [
|
|
29
|
+
/(?:created|wrote|saved|generated|writing|creating)\s+(?:file\s+)?[`"']?([\/~][^\s`"']+\.[a-z0-9]+)[`"']?/gi,
|
|
30
|
+
/(?:output|file|saved)\s*(?:to|:)\s*[`"']?([\/~][^\s`"']+\.[a-z0-9]+)[`"']?/gi,
|
|
31
|
+
/[`"']([\/~][^\s`"']+\.[a-z0-9]+)[`"']\s*(?:created|saved|written)/gi,
|
|
32
|
+
/(?:^|\n)\s*[✓✅]\s*[`"']?([\/~][^\s`"']+\.[a-z0-9]+)[`"']?/gm,
|
|
33
|
+
];
|
|
34
|
+
for (const pattern of patterns) {
|
|
35
|
+
let match;
|
|
36
|
+
while ((match = pattern.exec(output)) !== null) {
|
|
37
|
+
const filePath = match[1].replace(/^~/, process.env.HOME || '/tmp');
|
|
38
|
+
if (!seen.has(filePath)) {
|
|
39
|
+
seen.add(filePath);
|
|
40
|
+
assets.push({
|
|
41
|
+
path: filePath,
|
|
42
|
+
name: filePath.split('/').pop() || filePath,
|
|
43
|
+
type: 'new',
|
|
44
|
+
fileType: getFileType(filePath)
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return assets;
|
|
50
|
+
}
|
|
51
|
+
function getFileType(path) {
|
|
52
|
+
const ext = path.split('.').pop()?.toLowerCase() || '';
|
|
53
|
+
if (['js', 'ts', 'jsx', 'tsx', 'py', 'html', 'css', 'json', 'md', 'sh'].includes(ext))
|
|
54
|
+
return 'code';
|
|
55
|
+
if (['png', 'jpg', 'jpeg', 'gif', 'svg', 'webp'].includes(ext))
|
|
56
|
+
return 'image';
|
|
57
|
+
if (ext === 'pdf')
|
|
58
|
+
return 'pdf';
|
|
59
|
+
if (['txt', 'log', 'csv'].includes(ext))
|
|
60
|
+
return 'text';
|
|
61
|
+
return 'other';
|
|
62
|
+
}
|
|
21
63
|
const SYSTEM_PROMPT = `You are a MASTER ORCHESTRATOR - NOT a worker. You delegate ALL file/code work to Claude Code CLI workers.
|
|
22
64
|
|
|
23
65
|
CRITICAL IDENTITY:
|
|
@@ -923,15 +965,6 @@ Be specific about what you want done.`,
|
|
|
923
965
|
console.log(`[ORCHESTRATOR] Worker ${id} starting: ${task.slice(0, 80)}...`);
|
|
924
966
|
// Estimate task duration
|
|
925
967
|
const estimatedTime = this.estimateTaskDuration(task);
|
|
926
|
-
// Take snapshot of files before worker starts (for asset tracking)
|
|
927
|
-
let beforeSnapshot;
|
|
928
|
-
try {
|
|
929
|
-
beforeSnapshot = takeSnapshot(cwd);
|
|
930
|
-
console.log(`[ORCHESTRATOR] Snapshot: ${beforeSnapshot.files.size} files in ${cwd}`);
|
|
931
|
-
}
|
|
932
|
-
catch (err) {
|
|
933
|
-
console.log(`[ORCHESTRATOR] Could not take snapshot: ${err}`);
|
|
934
|
-
}
|
|
935
968
|
const job = {
|
|
936
969
|
id,
|
|
937
970
|
task: task.slice(0, 200),
|
|
@@ -939,8 +972,7 @@ Be specific about what you want done.`,
|
|
|
939
972
|
startTime: Date.now(),
|
|
940
973
|
output: '',
|
|
941
974
|
estimatedTime,
|
|
942
|
-
workingDir: cwd
|
|
943
|
-
beforeSnapshot
|
|
975
|
+
workingDir: cwd
|
|
944
976
|
};
|
|
945
977
|
// Escape single quotes in prompt for shell safety
|
|
946
978
|
const escapedPrompt = prompt.replace(/'/g, "'\\''");
|
|
@@ -982,21 +1014,27 @@ Be specific about what you want done.`,
|
|
|
982
1014
|
job.endTime = Date.now();
|
|
983
1015
|
const duration = Math.round((job.endTime - job.startTime) / 1000);
|
|
984
1016
|
console.log(`[ORCHESTRATOR] Worker ${id} done in ${duration}s`);
|
|
985
|
-
|
|
986
|
-
|
|
1017
|
+
const result = job.output.trim() || '(No output)';
|
|
1018
|
+
// Extract files from worker output (workers naturally mention what they created)
|
|
1019
|
+
const assets = extractFilesFromOutput(result);
|
|
1020
|
+
job.assets = assets;
|
|
1021
|
+
if (assets.length > 0) {
|
|
1022
|
+
console.log(`[ORCHESTRATOR] Worker ${id} created ${assets.length} files: ${assets.map(a => a.name).join(', ')}`);
|
|
1023
|
+
// Store in memory for gallery queries
|
|
987
1024
|
try {
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
1025
|
+
await this.memory.remember(`Worker ${id} completed task "${job.task}" and created files: ${assets.map(a => a.path).join(', ')}`, {
|
|
1026
|
+
type: 'episodic',
|
|
1027
|
+
source: 'worker_output',
|
|
1028
|
+
tags: ['worker', 'files', id],
|
|
1029
|
+
importance: 0.7
|
|
1030
|
+
});
|
|
994
1031
|
}
|
|
995
1032
|
catch (err) {
|
|
996
|
-
console.log(`[ORCHESTRATOR] Could not
|
|
1033
|
+
console.log(`[ORCHESTRATOR] Could not store worker output in memory: ${err}`);
|
|
997
1034
|
}
|
|
1035
|
+
// Broadcast gallery update
|
|
1036
|
+
this.broadcastGalleryUpdate();
|
|
998
1037
|
}
|
|
999
|
-
const result = job.output.trim() || '(No output)';
|
|
1000
1038
|
// Notify via callback (sends to user via WebSocket)
|
|
1001
1039
|
if (this.workerResultCallback) {
|
|
1002
1040
|
this.workerResultCallback(id, result);
|
|
@@ -13,7 +13,6 @@ export type GalleryCallback = (workers: GalleryWorker[]) => void;
|
|
|
13
13
|
export declare class WorkerManager {
|
|
14
14
|
private config;
|
|
15
15
|
private activeWorkers;
|
|
16
|
-
private fileSnapshots;
|
|
17
16
|
private galleryCallback;
|
|
18
17
|
constructor(workspaceDir: string, configOverrides?: Partial<WorkerConfig>);
|
|
19
18
|
/**
|
package/dist/workers/manager.js
CHANGED
|
@@ -6,11 +6,51 @@ import { spawn } from 'child_process';
|
|
|
6
6
|
import * as fs from 'fs';
|
|
7
7
|
import * as path from 'path';
|
|
8
8
|
import { DEFAULT_WORKER_CONFIG } from './types.js';
|
|
9
|
-
|
|
9
|
+
// Removed file-tracker - now extract files from worker output
|
|
10
|
+
/**
|
|
11
|
+
* Extract file paths from worker output
|
|
12
|
+
*/
|
|
13
|
+
function extractFilesFromOutput(output) {
|
|
14
|
+
const assets = [];
|
|
15
|
+
const seen = new Set();
|
|
16
|
+
const patterns = [
|
|
17
|
+
/(?:created|wrote|saved|generated|writing|creating)\s+(?:file\s+)?[`"']?([\/~][^\s`"']+\.[a-z0-9]+)[`"']?/gi,
|
|
18
|
+
/(?:output|file|saved)\s*(?:to|:)\s*[`"']?([\/~][^\s`"']+\.[a-z0-9]+)[`"']?/gi,
|
|
19
|
+
/[`"']([\/~][^\s`"']+\.[a-z0-9]+)[`"']\s*(?:created|saved|written)/gi,
|
|
20
|
+
/(?:^|\n)\s*[✓✅]\s*[`"']?([\/~][^\s`"']+\.[a-z0-9]+)[`"']?/gm,
|
|
21
|
+
];
|
|
22
|
+
for (const pattern of patterns) {
|
|
23
|
+
let match;
|
|
24
|
+
while ((match = pattern.exec(output)) !== null) {
|
|
25
|
+
const filePath = match[1].replace(/^~/, process.env.HOME || '/tmp');
|
|
26
|
+
if (!seen.has(filePath)) {
|
|
27
|
+
seen.add(filePath);
|
|
28
|
+
const ext = filePath.split('.').pop()?.toLowerCase() || '';
|
|
29
|
+
assets.push({
|
|
30
|
+
path: filePath,
|
|
31
|
+
name: filePath.split('/').pop() || filePath,
|
|
32
|
+
type: 'new',
|
|
33
|
+
fileType: getFileType(ext)
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return assets;
|
|
39
|
+
}
|
|
40
|
+
function getFileType(ext) {
|
|
41
|
+
if (['js', 'ts', 'jsx', 'tsx', 'py', 'html', 'css', 'json', 'md', 'sh'].includes(ext))
|
|
42
|
+
return 'code';
|
|
43
|
+
if (['png', 'jpg', 'jpeg', 'gif', 'svg', 'webp'].includes(ext))
|
|
44
|
+
return 'image';
|
|
45
|
+
if (ext === 'pdf')
|
|
46
|
+
return 'pdf';
|
|
47
|
+
if (['txt', 'log', 'csv'].includes(ext))
|
|
48
|
+
return 'text';
|
|
49
|
+
return 'other';
|
|
50
|
+
}
|
|
10
51
|
export class WorkerManager {
|
|
11
52
|
config;
|
|
12
53
|
activeWorkers = new Map();
|
|
13
|
-
fileSnapshots = new Map(); // Before-snapshots per job
|
|
14
54
|
galleryCallback = null;
|
|
15
55
|
constructor(workspaceDir, configOverrides) {
|
|
16
56
|
this.config = {
|
|
@@ -94,15 +134,6 @@ export class WorkerManager {
|
|
|
94
134
|
// Validate timeout
|
|
95
135
|
const effectiveTimeout = Math.min(timeout, this.config.maxTimeout);
|
|
96
136
|
const jobId = this.generateJobId();
|
|
97
|
-
// Take snapshot before spawning (for asset tracking)
|
|
98
|
-
try {
|
|
99
|
-
const beforeSnapshot = takeSnapshot(workspace);
|
|
100
|
-
this.fileSnapshots.set(jobId, beforeSnapshot);
|
|
101
|
-
console.log(`[WORKER] Snapshot for ${jobId}: ${beforeSnapshot.files.size} files`);
|
|
102
|
-
}
|
|
103
|
-
catch (err) {
|
|
104
|
-
console.log(`[WORKER] Could not take snapshot for ${jobId}: ${err}`);
|
|
105
|
-
}
|
|
106
137
|
const job = {
|
|
107
138
|
id: jobId,
|
|
108
139
|
task,
|
|
@@ -200,24 +231,12 @@ This ensures nothing is lost even if your output gets truncated.`;
|
|
|
200
231
|
if (stderr && code !== 0) {
|
|
201
232
|
currentJob.error = stderr.trim();
|
|
202
233
|
}
|
|
203
|
-
//
|
|
204
|
-
const
|
|
205
|
-
if (
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
currentJob.assets = assets;
|
|
210
|
-
const newCount = assets.filter(a => a.type === 'new').length;
|
|
211
|
-
const modCount = assets.filter(a => a.type === 'modified').length;
|
|
212
|
-
console.log(`[WORKER] ${jobId} assets: ${assets.length} files (${newCount} new, ${modCount} modified)`);
|
|
213
|
-
// Clean up snapshot
|
|
214
|
-
this.fileSnapshots.delete(jobId);
|
|
215
|
-
// Broadcast gallery update
|
|
216
|
-
this.broadcastGalleryUpdate();
|
|
217
|
-
}
|
|
218
|
-
catch (err) {
|
|
219
|
-
console.log(`[WORKER] Could not track assets for ${jobId}: ${err}`);
|
|
220
|
-
}
|
|
234
|
+
// Extract files from worker output (workers mention what they created)
|
|
235
|
+
const assets = extractFilesFromOutput(finalResult);
|
|
236
|
+
if (assets.length > 0) {
|
|
237
|
+
currentJob.assets = assets;
|
|
238
|
+
console.log(`[WORKER] ${jobId} created ${assets.length} files: ${assets.map(a => a.name).join(', ')}`);
|
|
239
|
+
this.broadcastGalleryUpdate();
|
|
221
240
|
}
|
|
222
241
|
this.saveJob(currentJob);
|
|
223
242
|
}
|