@cordfuse/crosstalk 6.0.0-alpha.5 → 6.0.0-alpha.6

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/dlq.ts +26 -5
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cordfuse/crosstalk",
3
- "version": "6.0.0-alpha.5",
3
+ "version": "6.0.0-alpha.6",
4
4
  "description": "Crosstalk runtime — async messaging between agents over git, across machines.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/dlq.ts CHANGED
@@ -13,6 +13,7 @@ import {
13
13
  } from 'fs';
14
14
  import { resolve, join, dirname } from 'path';
15
15
  import { pathToFileURL } from 'url';
16
+ import { spawnSync } from 'child_process';
16
17
  import { now } from './filenames.js';
17
18
  import { serializeFrontmatter, parseFrontmatter } from './frontmatter.js';
18
19
  import { stateDir, cursorPath } from './state.js';
@@ -162,16 +163,36 @@ if (isEntry) {
162
163
  process.exit(1);
163
164
  }
164
165
  const { data } = parseFrontmatter<DlqEntry>(readFileSync(path, 'utf-8'));
165
- const cursor = cursorPath(transportRoot, data.actor, data.channel);
166
- if (existsSync(cursor)) {
167
- mkdirSync(dirname(cursor), { recursive: true });
168
- writeFileSync(cursor, '');
166
+ const cursorFile = cursorPath(transportRoot, data.actor, data.channel);
167
+
168
+ // Find the commit that introduced the failed message and rewind to its
169
+ // parent. This ensures the next dispatch tick re-sees the message.
170
+ // Fallback: if git log fails, wipe the cursor so a full re-scan runs
171
+ // (less targeted but still recovers the message).
172
+ const relPath = `data/channels/${data.channel}/${data.messageRelPath}`;
173
+ const logResult = spawnSync('git', ['log', '--format=%H', '-1', '--', relPath], {
174
+ cwd: transportRoot,
175
+ encoding: 'utf-8',
176
+ });
177
+ const msgCommit = logResult.status === 0 ? logResult.stdout.trim() : '';
178
+ let rewindTo = '';
179
+ if (msgCommit) {
180
+ const parentResult = spawnSync('git', ['rev-parse', `${msgCommit}^`], {
181
+ cwd: transportRoot,
182
+ encoding: 'utf-8',
183
+ });
184
+ if (parentResult.status === 0) rewindTo = parentResult.stdout.trim();
169
185
  }
186
+
187
+ mkdirSync(dirname(cursorFile), { recursive: true });
188
+ writeFileSync(cursorFile, rewindTo ? rewindTo + '\n' : '');
189
+
170
190
  if (data.quarantined) {
171
191
  data.quarantined = false;
172
192
  writeFileSync(path, serializeFrontmatter(data as unknown as Record<string, unknown>, data.error));
173
193
  }
174
- console.log(`Retried ${retryId}: cursor for ${data.actor}@${data.channel.slice(0, 8)} rewound; quarantine cleared.`);
194
+ const rewindDesc = rewindTo ? rewindTo.slice(0, 12) : 'start (full re-scan)';
195
+ console.log(`Retried ${retryId}: cursor for ${data.actor}@${data.channel.slice(0, 8)} rewound to ${rewindDesc}; quarantine cleared.`);
175
196
  console.log(' Entry kept — re-evaluated on next dispatch tick.');
176
197
  } else {
177
198
  const files = existsSync(dir) ? readdirSync(dir).filter((f) => f.endsWith('.md')).sort() : [];