@cordfuse/crosstalk 6.0.0-alpha.7 → 6.0.0-alpha.8

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cordfuse/crosstalk",
3
- "version": "6.0.0-alpha.7",
3
+ "version": "6.0.0-alpha.8",
4
4
  "description": "Crosstalk runtime — async messaging between agents over git, across machines.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/src/actor.ts CHANGED
@@ -1,8 +1,31 @@
1
1
  import { existsSync, readFileSync, readdirSync } from 'fs';
2
2
  import { join } from 'path';
3
- import { hostname as osHostname } from 'os';
3
+ import { hostname as osHostname, platform } from 'os';
4
+ import { spawnSync } from 'child_process';
4
5
  import { parseFrontmatter } from './frontmatter.js';
5
6
 
7
+ // Collect the names this machine might be known by. On macOS, the kernel
8
+ // hostname (`os.hostname()`) drifts with DHCP/VPN/Tailscale when the static
9
+ // HostName is unset — `scutil --get LocalHostName` is the stable Bonjour
10
+ // name (e.g. `Steves-MacBook-Air`), and host files commonly use the `.local`
11
+ // form. Trying all variants makes auto-detect deterministic across network
12
+ // state without forcing every Mac operator to pin `--host`.
13
+ function candidateHostNames(): string[] {
14
+ const names = new Set<string>();
15
+ names.add(osHostname());
16
+ if (platform() === 'darwin') {
17
+ const r = spawnSync('scutil', ['--get', 'LocalHostName'], { encoding: 'utf-8' });
18
+ if (r.status === 0) {
19
+ const local = r.stdout.trim();
20
+ if (local) {
21
+ names.add(local);
22
+ names.add(`${local}.local`);
23
+ }
24
+ }
25
+ }
26
+ return [...names];
27
+ }
28
+
6
29
  export interface HostActorTier {
7
30
  cli: string;
8
31
  count?: number;
@@ -36,13 +59,15 @@ export function findHostFile(transportRoot: string, override?: string): HostFile
36
59
  if (!target) throw new Error(`Host file '${override}' not found in ${dir}`);
37
60
  return parseHostFile(join(dir, target));
38
61
  }
39
- const hostName = osHostname();
62
+ const names = candidateHostNames();
40
63
  for (const f of files) {
41
64
  const parsed = parseHostFile(join(dir, f));
42
- if (parsed.hostname === hostName || parsed.alias === hostName) return parsed;
65
+ for (const n of names) {
66
+ if (parsed.hostname === n || parsed.alias === n) return parsed;
67
+ }
43
68
  }
44
69
  throw new Error(
45
- `No host file matches hostname '${hostName}' in ${dir}. ` +
70
+ `No host file matches any of [${names.join(', ')}] in ${dir}. ` +
46
71
  `Pass --host <alias> to override.`,
47
72
  );
48
73
  }
package/src/dispatch.ts CHANGED
@@ -362,17 +362,23 @@ async function dispatchTick(): Promise<TickResult> {
362
362
  const pending: PendingDispatch[] = [];
363
363
 
364
364
  for (const channelUuid of channels) {
365
- const cursor = readCursor(transportRoot, actorName, channelUuid);
366
- if (cursor === head) continue;
365
+ const persistedCursor = readCursor(transportRoot, actorName, channelUuid);
366
+ if (persistedCursor === head) continue;
367
367
 
368
368
  // First encounter: seed to the commit that introduced this actor's host
369
369
  // file. Messages sent after the host joined are delivered (store-and-
370
370
  // forward); pre-join history is ignored. Seeding to HEAD would silently
371
371
  // drop messages sent while the dispatcher was offline — the wrong trade.
372
- if (cursor === null) {
372
+ // Fall through after seeding so this tick processes the post-join backlog
373
+ // (otherwise `--once` users hit a seed-then-dispatch two-tick gotcha).
374
+ let cursor: string;
375
+ if (persistedCursor === null) {
373
376
  const joinCommit = hostFileCommit(transportRoot, host.alias);
374
- writeCursor(transportRoot, actorName, channelUuid, joinCommit ?? head);
375
- continue;
377
+ cursor = joinCommit ?? head;
378
+ writeCursor(transportRoot, actorName, channelUuid, cursor);
379
+ if (cursor === head) continue;
380
+ } else {
381
+ cursor = persistedCursor;
376
382
  }
377
383
 
378
384
  const messages = listChannelMessages(transportRoot, channelUuid);