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.
- package/dist/index.js +23 -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
|
-
|
|
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).
|