@siftd/connect-agent 0.2.55 → 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;
@@ -721,9 +722,14 @@ export class MasterOrchestrator {
721
722
  return lines.join('\n');
722
723
  }
723
724
  stripTodoSnapshot(message) {
724
- const marker = '\n\nTODO SNAPSHOT';
725
- const index = message.indexOf(marker);
726
- return index === -1 ? message : message.slice(0, index);
725
+ const markers = ['\n\nTODO SNAPSHOT', '\n\nRECENT CONVERSATION'];
726
+ const indices = markers
727
+ .map((marker) => message.indexOf(marker))
728
+ .filter((index) => index !== -1);
729
+ if (indices.length === 0)
730
+ return message;
731
+ const earliest = Math.min(...indices);
732
+ return message.slice(0, earliest);
727
733
  }
728
734
  hasTodoMutation(message) {
729
735
  const lower = this.stripTodoSnapshot(message).toLowerCase();
@@ -932,6 +938,52 @@ export class MasterOrchestrator {
932
938
  }
933
939
  return resolved;
934
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
+ }
935
987
  getFileScopeSystemNote() {
936
988
  if (this.currentFileScope !== 'team')
937
989
  return null;
@@ -950,14 +1002,15 @@ export class MasterOrchestrator {
950
1002
  * Process a user message
951
1003
  */
952
1004
  async processMessage(message, conversationHistory = [], sendMessage) {
953
- this.lastUserMessage = message;
1005
+ const cleanMessage = this.stripTodoSnapshot(message);
1006
+ this.lastUserMessage = cleanMessage;
954
1007
  // Handle slash commands first
955
- const slashResponse = this.handleSlashCommand(message);
1008
+ const slashResponse = this.handleSlashCommand(cleanMessage);
956
1009
  if (slashResponse) {
957
1010
  return slashResponse;
958
1011
  }
959
- this.updateFileScope(message);
960
- const wantsTodoOrCal = this.hasTodoMutation(message) || this.hasCalendarMutation(message);
1012
+ this.updateFileScope(cleanMessage);
1013
+ const wantsTodoOrCal = this.hasTodoMutation(cleanMessage) || this.hasCalendarMutation(cleanMessage);
961
1014
  if (wantsTodoOrCal) {
962
1015
  this.attachmentContext = this.extractAttachmentContext(message);
963
1016
  const toolMessages = [{ role: 'user', content: message }];
@@ -979,11 +1032,11 @@ export class MasterOrchestrator {
979
1032
  // return quickWrite;
980
1033
  // }
981
1034
  // Load hub context (AGENTS.md identity, LANDMARKS.md state, project bio if relevant)
982
- const hubContext = loadHubContext(message);
1035
+ const hubContext = loadHubContext(cleanMessage);
983
1036
  const hubContextStr = formatHubContext(hubContext);
984
1037
  this.attachmentContext = this.extractAttachmentContext(message);
985
1038
  // Build context from memory
986
- const memoryContext = await this.getMemoryContext(message);
1039
+ const memoryContext = await this.getMemoryContext(cleanMessage);
987
1040
  // Build system prompt with hub context, genesis knowledge, and memory context
988
1041
  const genesisKnowledge = getKnowledgeForPrompt();
989
1042
  let systemWithContext = SYSTEM_PROMPT;
@@ -1021,11 +1074,11 @@ ${hubContextStr}
1021
1074
  try {
1022
1075
  const response = await this.runAgentLoop(messages, systemWithContext, sendMessage);
1023
1076
  // Auto-remember important things from the conversation
1024
- await this.autoRemember(message, response);
1025
- void this.autoCaptureContext(message);
1077
+ await this.autoRemember(cleanMessage, response);
1078
+ void this.autoCaptureContext(cleanMessage);
1026
1079
  // Log significant actions to hub
1027
1080
  if (response.length > 100) {
1028
- const action = message.length > 50 ? message.slice(0, 50) + '...' : message;
1081
+ const action = cleanMessage.length > 50 ? cleanMessage.slice(0, 50) + '...' : cleanMessage;
1029
1082
  logAction(action, hubContext.projectName || undefined, `Response: ${response.length} chars`);
1030
1083
  }
1031
1084
  return response;
@@ -1448,6 +1501,7 @@ ${hubContextStr}
1448
1501
  const forcedToolChoice = this.getToolChoice(currentMessages);
1449
1502
  let retriedForcedTool = false;
1450
1503
  let retriedTodoCal = false;
1504
+ this.recentFileWrites = [];
1451
1505
  while (iterations < maxIterations) {
1452
1506
  iterations++;
1453
1507
  const toolChoice = forcedToolChoice ?? this.getToolChoice(currentMessages);
@@ -1510,7 +1564,7 @@ ${hubContextStr}
1510
1564
  ];
1511
1565
  continue;
1512
1566
  }
1513
- return this.extractText(response.content);
1567
+ return this.finalizeResponse(this.extractText(response.content));
1514
1568
  }
1515
1569
  const toolUseBlocks = response.content.filter((block) => block.type === 'tool_use');
1516
1570
  const toolNames = toolUseBlocks.map((block) => block.name);
@@ -1548,7 +1602,7 @@ ${hubContextStr}
1548
1602
  { role: 'user', content: toolResults }
1549
1603
  ];
1550
1604
  }
1551
- return 'Maximum iterations reached.';
1605
+ return this.finalizeResponse('Maximum iterations reached.');
1552
1606
  }
1553
1607
  /**
1554
1608
  * Get tool definitions for the orchestrator
@@ -2252,7 +2306,9 @@ Unlike lia_plan (internal only), this creates a VISIBLE todo list that appears i
2252
2306
  const targetPath = this.resolveFilesWritePath(pathValue);
2253
2307
  mkdirSync(dirname(targetPath), { recursive: true });
2254
2308
  writeFileSync(targetPath, content, 'utf8');
2255
- 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}.` };
2256
2312
  }
2257
2313
  catch (error) {
2258
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.55",
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",