osborn 0.9.20 → 0.9.22

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.
@@ -16,8 +16,17 @@ RUN apt-get update -qq && \
16
16
  python-is-python3 && \
17
17
  rm -rf /var/lib/apt/lists/*
18
18
 
19
- # Install osborn + claude-code globally
20
- RUN npm install -g osborn@latest @anthropic-ai/claude-code
19
+ # Pin osborn to an explicit version so Docker layer cache invalidates whenever
20
+ # the version changes. Earlier `RUN npm install -g osborn@latest` looked correct
21
+ # but it never invalidated: `latest` is a tag resolved by npm at install time,
22
+ # but Docker's layer cache keys on the literal RUN command string. So every
23
+ # rebuild reused the cached layer from when "latest" was a previous version,
24
+ # producing images labeled :0.9.21 that actually contained osborn 0.9.19 inside.
25
+ #
26
+ # Pass --build-arg OSBORN_VERSION=X.Y.Z when building. image-build-check.ts
27
+ # does this automatically using the npm-registry-resolved latest version.
28
+ ARG OSBORN_VERSION=latest
29
+ RUN npm install -g "osborn@${OSBORN_VERSION}" @anthropic-ai/claude-code
21
30
 
22
31
  # Persistent workspace + claude config dirs
23
32
  RUN mkdir -p /workspace /root/.claude
package/dist/index.js CHANGED
@@ -397,22 +397,18 @@ function startApiServer(workingDir, port) {
397
397
  const destSlug = join(projectsDir, effectiveSlug);
398
398
  mkdirSync(destSlug, { recursive: true });
399
399
  const sourceSlugPath = join(effectiveSource, sourceSlug);
400
- // Always rewrite EVERY `"cwd":"<anything>"` to the target workspace dir
401
- // when targetWorkDir is provided. Earlier version tried to derive the
402
- // source cwd from the slug name via dash-to-slash substitution, but
403
- // slug encoding is ambiguous (hyphens in path components like
404
- // `codespaces-blank` get expanded into directory boundaries). That
405
- // version only caught the canonical sprite cwd and missed laptop +
406
- // codespaces references inside the JSONL bodies. Migration test on
407
- // bj2zgt → fly machine found 12 files still pointing at /Users/...
408
- // or /workspaces/codespaces-blank after the old rewrite. The brute-
409
- // force regex below is bulletproof: any `cwd` reference becomes the
410
- // runtime workspace dir, period.
411
- const destCwd = targetWorkDir ?? slugToCwd(effectiveSlug);
412
- const needsCwdRewrite = !!targetWorkDir;
413
- void sourceSlugPath; // silence linter — used below in walk
414
- const cwdRewriteRe = /"cwd":"[^"]*"/g;
415
- const cwdReplacement = `"cwd":"${destCwd}"`;
400
+ // NO content mutation. Earlier versions rewrote the embedded `"cwd":"..."`
401
+ // field inside JSONL entries to match the destination workspace. That was
402
+ // wrong on two counts:
403
+ // 1. The cwd field is documentary metadata, not how Claude Code resolves
404
+ // a session at resume time — resume uses the slug directory name.
405
+ // 2. Mutating contents breaks roundtripability (laptop cloud laptop
406
+ // ends up with /workspace cwd on laptop), corrupting historical data
407
+ // across environment hops.
408
+ // What's actually needed is just the slug rename (handled by `effectiveSlug`
409
+ // below). File contents stay byte-exact across every transfer direction.
410
+ void sourceSlugPath;
411
+ void targetWorkDir;
416
412
  // Walk the source slug directory and copy files individually so we can:
417
413
  // (a) skip AppleDouble per-file too (in case nested)
418
414
  // (b) rewrite cwd inside .jsonl files when remapping across workspaces
@@ -444,17 +440,10 @@ function startApiServer(workingDir, port) {
444
440
  catch { /* dst doesn't exist — write it */ }
445
441
  if (!shouldWrite)
446
442
  continue;
447
- if (needsCwdRewrite && e.name.endsWith('.jsonl')) {
448
- // Regex-rewrite every `"cwd":"<anything>"` target. Catches all
449
- // possible source cwds in one pass (laptop, codespaces, sprite,
450
- // etc.) without depending on slug-derived heuristics.
451
- const content = readFileSync(sp, 'utf8');
452
- const rewritten = content.replace(cwdRewriteRe, cwdReplacement);
453
- writeFileSync(dp, rewritten);
454
- }
455
- else {
456
- cpSync(sp, dp, { force: true });
457
- }
443
+ // Copy byte-exact — no content mutation. The slug rename above is
444
+ // the only structural change; file contents are immutable historical
445
+ // record and must roundtrip cleanly between environments.
446
+ cpSync(sp, dp, { force: true });
458
447
  filesWritten++;
459
448
  }
460
449
  // skip symlinks, sockets, etc.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "osborn",
3
- "version": "0.9.20",
3
+ "version": "0.9.22",
4
4
  "description": "Voice AI coding assistant - local agent that connects to Osborn frontend",
5
5
  "type": "module",
6
6
  "bin": {