@siftd/connect-agent 0.2.56 → 0.2.57

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.
@@ -75,6 +75,7 @@ export declare class MasterOrchestrator {
75
75
  private initialized;
76
76
  private currentFileScope;
77
77
  private forceTeamWorkingDir;
78
+ private recentFileWrites;
78
79
  private bashTool;
79
80
  private webTools;
80
81
  private workerTools;
@@ -210,6 +211,8 @@ export declare class MasterOrchestrator {
210
211
  private getFileScopeOverrides;
211
212
  private rewriteFilesAlias;
212
213
  private resolveFilesWritePath;
214
+ private toFilesVirtualPath;
215
+ private finalizeResponse;
213
216
  private getFileScopeSystemNote;
214
217
  /**
215
218
  * Check if verbose mode is enabled
@@ -258,6 +258,7 @@ export class MasterOrchestrator {
258
258
  initialized = false;
259
259
  currentFileScope = 'personal';
260
260
  forceTeamWorkingDir = false;
261
+ recentFileWrites = [];
261
262
  // New tools from whatsapp-claude
262
263
  bashTool;
263
264
  webTools;
@@ -937,6 +938,52 @@ export class MasterOrchestrator {
937
938
  }
938
939
  return resolved;
939
940
  }
941
+ toFilesVirtualPath(rawPath, resolvedPath) {
942
+ const trimmed = rawPath.trim();
943
+ if (!trimmed)
944
+ return '/files';
945
+ const lower = trimmed.toLowerCase();
946
+ if (lower.startsWith('/files')) {
947
+ const suffix = trimmed.slice('/files'.length).replace(/\\/g, '/');
948
+ return `/files${suffix}`;
949
+ }
950
+ if (lower.startsWith('files/')) {
951
+ const suffix = trimmed.slice('files'.length).replace(/\\/g, '/');
952
+ return `/files${suffix}`;
953
+ }
954
+ if (trimmed.startsWith('/')) {
955
+ const teamDir = this.currentFileScope === 'team' ? this.getTeamFilesDir() : null;
956
+ const baseDir = teamDir || getSharedOutputPath();
957
+ try {
958
+ const resolved = resolve(resolvedPath || trimmed);
959
+ const baseResolved = resolve(baseDir);
960
+ if (resolved === baseResolved)
961
+ return '/files';
962
+ if (resolved.startsWith(`${baseResolved}${sep}`)) {
963
+ const rel = resolved.slice(baseResolved.length + 1).replace(/\\/g, '/');
964
+ return `/files/${rel}`;
965
+ }
966
+ }
967
+ catch {
968
+ return '/files';
969
+ }
970
+ }
971
+ const cleaned = trimmed.replace(/^\/+/, '').replace(/^files\/?/i, '');
972
+ return cleaned ? `/files/${cleaned}` : '/files';
973
+ }
974
+ finalizeResponse(text) {
975
+ const trimmed = text.trim();
976
+ if (this.recentFileWrites.length === 0)
977
+ return trimmed || text;
978
+ const uniquePaths = Array.from(new Set(this.recentFileWrites));
979
+ const confirmation = uniquePaths.length === 1
980
+ ? `Saved ${uniquePaths[0]}.`
981
+ : `Saved files:\n${uniquePaths.map((path) => `- ${path}`).join('\n')}`;
982
+ if (!trimmed)
983
+ return confirmation;
984
+ const mentionsPath = uniquePaths.some((path) => trimmed.includes(path)) || /\/files\b/i.test(trimmed);
985
+ return mentionsPath ? trimmed : `${trimmed}\n\n${confirmation}`;
986
+ }
940
987
  getFileScopeSystemNote() {
941
988
  if (this.currentFileScope !== 'team')
942
989
  return null;
@@ -1454,6 +1501,7 @@ ${hubContextStr}
1454
1501
  const forcedToolChoice = this.getToolChoice(currentMessages);
1455
1502
  let retriedForcedTool = false;
1456
1503
  let retriedTodoCal = false;
1504
+ this.recentFileWrites = [];
1457
1505
  while (iterations < maxIterations) {
1458
1506
  iterations++;
1459
1507
  const toolChoice = forcedToolChoice ?? this.getToolChoice(currentMessages);
@@ -1516,7 +1564,7 @@ ${hubContextStr}
1516
1564
  ];
1517
1565
  continue;
1518
1566
  }
1519
- return this.extractText(response.content);
1567
+ return this.finalizeResponse(this.extractText(response.content));
1520
1568
  }
1521
1569
  const toolUseBlocks = response.content.filter((block) => block.type === 'tool_use');
1522
1570
  const toolNames = toolUseBlocks.map((block) => block.name);
@@ -1554,7 +1602,7 @@ ${hubContextStr}
1554
1602
  { role: 'user', content: toolResults }
1555
1603
  ];
1556
1604
  }
1557
- return 'Maximum iterations reached.';
1605
+ return this.finalizeResponse('Maximum iterations reached.');
1558
1606
  }
1559
1607
  /**
1560
1608
  * Get tool definitions for the orchestrator
@@ -2258,7 +2306,9 @@ Unlike lia_plan (internal only), this creates a VISIBLE todo list that appears i
2258
2306
  const targetPath = this.resolveFilesWritePath(pathValue);
2259
2307
  mkdirSync(dirname(targetPath), { recursive: true });
2260
2308
  writeFileSync(targetPath, content, 'utf8');
2261
- result = { success: true, output: 'Saved file to /files.' };
2309
+ const virtualPath = this.toFilesVirtualPath(pathValue, targetPath);
2310
+ this.recentFileWrites.push(virtualPath);
2311
+ result = { success: true, output: `Saved file to ${virtualPath}.` };
2262
2312
  }
2263
2313
  catch (error) {
2264
2314
  const message = error instanceof Error ? error.message : String(error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@siftd/connect-agent",
3
- "version": "0.2.56",
3
+ "version": "0.2.57",
4
4
  "description": "Master orchestrator agent - control Claude Code remotely via web",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",