@siftd/connect-agent 0.2.25 → 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.
@@ -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;
@@ -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
- import { takeSnapshot, compareSnapshots } from './core/file-tracker.js';
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
- // Track file changes (for gallery)
986
- if (job.beforeSnapshot) {
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
- const afterSnapshot = takeSnapshot(job.workingDir);
989
- const assets = compareSnapshots(job.beforeSnapshot, afterSnapshot);
990
- job.assets = assets;
991
- console.log(`[ORCHESTRATOR] Worker ${id} assets: ${assets.length} files (${assets.filter(a => a.type === 'new').length} new, ${assets.filter(a => a.type === 'modified').length} modified)`);
992
- // Broadcast gallery update
993
- this.broadcastGalleryUpdate();
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 track assets: ${err}`);
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
  /**
@@ -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
- import { takeSnapshot, compareSnapshots } from '../core/file-tracker.js';
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
- // Track file changes (for gallery)
204
- const beforeSnapshot = this.fileSnapshots.get(jobId);
205
- if (beforeSnapshot) {
206
- try {
207
- const afterSnapshot = takeSnapshot(currentJob.workspace);
208
- const assets = compareSnapshots(beforeSnapshot, afterSnapshot);
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@siftd/connect-agent",
3
- "version": "0.2.25",
3
+ "version": "0.2.26",
4
4
  "description": "Master orchestrator agent - control Claude Code remotely via web",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",