@siftd/connect-agent 0.2.25 → 0.2.27

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:
@@ -919,19 +961,10 @@ Be specific about what you want done.`,
919
961
  prompt = `Context: ${context}\n\nTask: ${task}`;
920
962
  }
921
963
  // Add brief instruction
922
- prompt += `\n\nBe concise. Output results directly.`;
964
+ prompt += `\n\nBe concise. Output results directly. Do NOT open browsers or start servers - just create files and report paths.`;
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,
@@ -123,6 +154,7 @@ IMPORTANT - Progress & Logging:
123
154
  - Output findings as you go, don't wait until the end
124
155
  - Print discoveries and insights immediately as you find them
125
156
  - Report on each file/step before moving to the next
157
+ - Do NOT open browsers or start servers - just create files and report paths
126
158
 
127
159
  REQUIRED - Log Export:
128
160
  At the END of your work, create a final log file at: ${logFile}
@@ -200,24 +232,12 @@ This ensures nothing is lost even if your output gets truncated.`;
200
232
  if (stderr && code !== 0) {
201
233
  currentJob.error = stderr.trim();
202
234
  }
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
- }
235
+ // Extract files from worker output (workers mention what they created)
236
+ const assets = extractFilesFromOutput(finalResult);
237
+ if (assets.length > 0) {
238
+ currentJob.assets = assets;
239
+ console.log(`[WORKER] ${jobId} created ${assets.length} files: ${assets.map(a => a.name).join(', ')}`);
240
+ this.broadcastGalleryUpdate();
221
241
  }
222
242
  this.saveJob(currentJob);
223
243
  }
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.27",
4
4
  "description": "Master orchestrator agent - control Claude Code remotely via web",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",