osborn 0.9.73 → 0.9.75

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/dist/index.js +23 -2
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ initializeLogger({ pretty: true, level: 'info' });
10
10
  import { setMaxListeners } from 'node:events';
11
11
  setMaxListeners(50);
12
12
  import { createServer } from 'http';
13
- import { existsSync, readdirSync, readFileSync, mkdirSync, writeFileSync, mkdtempSync, cpSync, rmSync, statSync, createWriteStream } from 'node:fs';
13
+ import { existsSync, readdirSync, readFileSync, mkdirSync, writeFileSync, mkdtempSync, cpSync, rmSync, statSync, utimesSync, createWriteStream } from 'node:fs';
14
14
  import { dirname, join } from 'node:path';
15
15
  import { fileURLToPath } from 'node:url';
16
16
  import { spawn } from 'node:child_process';
@@ -603,6 +603,18 @@ function startApiServer(workingDir, port) {
603
603
  // the only structural change; file contents are immutable historical
604
604
  // record and must roundtrip cleanly between environments.
605
605
  cpSync(sp, dp, { force: true });
606
+ // 0.9.75: preserve the source mtime on the copy. cpSync stamps the
607
+ // destination with "now", which scrambled session ordering after
608
+ // every sync — the frontend's auto-resume picks most-recent-by-mtime,
609
+ // so a fresh import made a random tar-order file (often a tiny
610
+ // months-old session) look newest, and users kept "resuming" into
611
+ // stale June sessions (confirmed in prod 2026-07-27, 3× in a row).
612
+ // The tarball carries original mtimes; copying must not discard them.
613
+ try {
614
+ const srcStat = statSync(sp);
615
+ utimesSync(dp, srcStat.atime, srcStat.mtime);
616
+ }
617
+ catch { /* best-effort — ordering degrades gracefully */ }
606
618
  filesWritten++;
607
619
  }
608
620
  // skip symlinks, sockets, etc.
@@ -739,7 +751,16 @@ function startApiServer(workingDir, port) {
739
751
  return;
740
752
  }
741
753
  }
742
- const targetWorkDir = url.searchParams.get('targetWorkDir');
754
+ // 0.9.74: default targetWorkDir to this machine's own working directory.
755
+ // Stale sync clients that omit the param used to get source slugs written
756
+ // verbatim — those sessions LIST fine (the scanner walks all slugs) but
757
+ // silently fail to RESUME (the SDK resumes at cwd=workingDir, whose slug
758
+ // they don't match). Confirmed in prod 2026-07-27 after a stale-skill
759
+ // upload. On a cloud machine, remapping into our own workspace is always
760
+ // the right default; a client that genuinely wants source slugs preserved
761
+ // (e.g. laptop→laptop mirroring) must now opt in with preserveSlugs=1.
762
+ const targetWorkDir = url.searchParams.get('targetWorkDir')
763
+ ?? (url.searchParams.get('preserveSlugs') === '1' ? null : workingDir);
743
764
  const tmpDir = mkdtempSync(join(tmpdir(), 'osborn-import-'));
744
765
  const tarProc = spawn('tar', ['-xf', '-', '-C', tmpDir]);
745
766
  // Stream-sniff the first chunk to detect gzip magic bytes (0x1f 0x8b).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "osborn",
3
- "version": "0.9.73",
3
+ "version": "0.9.75",
4
4
  "description": "Voice AI coding assistant - local agent that connects to Osborn frontend",
5
5
  "type": "module",
6
6
  "bin": {