osborn 0.9.162 → 0.9.164

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/bin/cli.js CHANGED
@@ -3,8 +3,7 @@
3
3
  import { spawn } from 'child_process'
4
4
  import { fileURLToPath } from 'url'
5
5
  import { dirname, join } from 'path'
6
- import { readFileSync, existsSync, symlinkSync, rmSync } from 'fs'
7
- import { homedir } from 'os'
6
+ import { readFileSync } from 'fs'
8
7
 
9
8
  const __filename = fileURLToPath(import.meta.url)
10
9
  const __dirname = dirname(__filename)
@@ -60,21 +59,6 @@ Example:
60
59
  process.exit(0)
61
60
  }
62
61
 
63
- // Ensure ~/.claude → /workspace/.claude symlink exists (Fly cloud machines run
64
- // this binary directly, bypassing entrypoint.sh which normally creates it).
65
- import { symlinkSync, rmSync } from 'fs'
66
- import { homedir } from 'os'
67
- {
68
- const claudeLink = join(homedir(), '.claude')
69
- const claudeTarget = '/workspace/.claude'
70
- if (existsSync(claudeTarget)) {
71
- try {
72
- rmSync(claudeLink, { recursive: true, force: true })
73
- symlinkSync(claudeTarget, claudeLink)
74
- } catch {}
75
- }
76
- }
77
-
78
62
  // Determine mode (default to 'dev' if no mode specified)
79
63
  let mode = 'dev'
80
64
  if (args.includes('start')) {
@@ -85,6 +69,7 @@ if (args.includes('start')) {
85
69
  }
86
70
 
87
71
  // Use src/index.ts (dev) if available, otherwise dist/index.js (npm install)
72
+ import { existsSync } from 'fs'
88
73
  const srcPath = join(__dirname, '..', 'src', 'index.ts')
89
74
  const distPath = join(__dirname, '..', 'dist', 'index.js')
90
75
 
package/dist/config.js CHANGED
@@ -639,63 +639,68 @@ export async function listAllClaudeSessions(limit = 2000) {
639
639
  // 3. Sort by mtime descending, take top N for detailed reads
640
640
  candidates.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
641
641
  const topCandidates = candidates.slice(0, limit);
642
- // 4. Read metadata using existing getSessionPreview + cwd extraction
642
+ // 4. Read metadata in parallel (sequential was ~10ms × N files = seconds at scale)
643
643
  const sessions = [];
644
- for (const c of topCandidates) {
644
+ const results = await Promise.all(topCandidates.map(async (c) => {
645
645
  try {
646
- const [preview, cwd] = await Promise.all([
647
- getSessionPreview(c.filePath),
648
- extractCwd(c.filePath),
649
- ]);
650
- if (preview.messageCount < 2)
651
- continue;
652
- // TWO FIELDS — two distinct purposes. The dashboard uses each for
653
- // exactly one thing:
654
- //
655
- // `projectPath` ← content cwd from JSONL.
656
- // What the session ORIGINALLY recorded as its working directory.
657
- // For native fly sessions that's the same as the slug-derived
658
- // path. For imported sessions (migrated from sprite, copied from
659
- // Codespaces, synced from a Mac) it's the source machine's cwd —
660
- // a path that may not exist on this host. The dashboard groups
661
- // by this so a user who imported sessions from 4 different
662
- // places sees 4 project cards, named after where each came from.
663
- //
664
- // `cwd` ← slug-derived. File LOCATION on disk.
665
- // Forwarded to the agent as `workingDirectory` so Claude Code's
666
- // `--resume` finds the JSONL — Claude Code looks up sessions
667
- // by slug folder, not by content cwd. Always points at the
668
- // real on-disk location regardless of what the JSONL records.
669
- //
670
- // Why NOT use content cwd for routing too: imported sessions still
671
- // live in the LOCAL slug after migration. A session whose content
672
- // cwd is `/workspaces/codespaces-blank` was put in slug `-workspace/`
673
- // when we synced it onto fly, so `--resume` needs cwd=/workspace to
674
- // find it. Forwarding the content cwd would send Claude Code to a
675
- // slug that doesn't exist on this host.
676
- //
677
- // Why NOT use slug-derived path for grouping too: that collapses all
678
- // imported sessions into one "Workspace" card on the dashboard,
679
- // losing the "this came from Codespaces, that came from sprite"
680
- // organization the user thinks of when finding old conversations.
681
- //
682
- // Each field falls back to the other if its preferred source is
683
- // empty — slugToPath returns '' for ambiguous slug encodings, and
684
- // some old JSONL files don't carry a cwd field at all.
685
- const slugPath = slugToPath(c.slug);
686
- sessions.push({
687
- sessionId: c.sessionId,
688
- projectSlug: c.slug,
689
- projectPath: cwd || slugPath, // display / group key (original cwd)
690
- cwd: slugPath || cwd, // resume routing (file location)
691
- timestamp: c.mtime,
692
- lastMessage: preview.lastMessage,
693
- messageCount: preview.messageCount,
694
- filePath: c.filePath,
695
- fileSize: c.size,
696
- });
646
+ const [preview, cwd] = await Promise.all([getSessionPreview(c.filePath), extractCwd(c.filePath)]);
647
+ return { c, preview, cwd };
697
648
  }
698
- catch { }
649
+ catch {
650
+ return null;
651
+ }
652
+ }));
653
+ for (const r of results) {
654
+ if (!r)
655
+ continue;
656
+ const { c, preview, cwd } = r;
657
+ if (preview.messageCount < 2)
658
+ continue;
659
+ // TWO FIELDS — two distinct purposes. The dashboard uses each for
660
+ // exactly one thing:
661
+ //
662
+ // `projectPath` ← content cwd from JSONL.
663
+ // What the session ORIGINALLY recorded as its working directory.
664
+ // For native fly sessions that's the same as the slug-derived
665
+ // path. For imported sessions (migrated from sprite, copied from
666
+ // Codespaces, synced from a Mac) it's the source machine's cwd —
667
+ // a path that may not exist on this host. The dashboard groups
668
+ // by this so a user who imported sessions from 4 different
669
+ // places sees 4 project cards, named after where each came from.
670
+ //
671
+ // `cwd` ← slug-derived. File LOCATION on disk.
672
+ // Forwarded to the agent as `workingDirectory` so Claude Code's
673
+ // `--resume` finds the JSONL — Claude Code looks up sessions
674
+ // by slug folder, not by content cwd. Always points at the
675
+ // real on-disk location regardless of what the JSONL records.
676
+ //
677
+ // Why NOT use content cwd for routing too: imported sessions still
678
+ // live in the LOCAL slug after migration. A session whose content
679
+ // cwd is `/workspaces/codespaces-blank` was put in slug `-workspace/`
680
+ // when we synced it onto fly, so `--resume` needs cwd=/workspace to
681
+ // find it. Forwarding the content cwd would send Claude Code to a
682
+ // slug that doesn't exist on this host.
683
+ //
684
+ // Why NOT use slug-derived path for grouping too: that collapses all
685
+ // imported sessions into one "Workspace" card on the dashboard,
686
+ // losing the "this came from Codespaces, that came from sprite"
687
+ // organization the user thinks of when finding old conversations.
688
+ //
689
+ // Each field falls back to the other if its preferred source is
690
+ // empty — slugToPath returns '' for ambiguous slug encodings, and
691
+ // some old JSONL files don't carry a cwd field at all.
692
+ const slugPath = slugToPath(c.slug);
693
+ sessions.push({
694
+ sessionId: c.sessionId,
695
+ projectSlug: c.slug,
696
+ projectPath: cwd || slugPath, // display / group key (original cwd)
697
+ cwd: slugPath || cwd, // resume routing (file location)
698
+ timestamp: c.mtime,
699
+ lastMessage: preview.lastMessage,
700
+ messageCount: preview.messageCount,
701
+ filePath: c.filePath,
702
+ fileSize: c.size,
703
+ });
699
704
  }
700
705
  return sessions;
701
706
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "osborn",
3
- "version": "0.9.162",
3
+ "version": "0.9.164",
4
4
  "description": "Voice AI coding assistant - local agent that connects to Osborn frontend",
5
5
  "type": "module",
6
6
  "bin": {