@venturewild/workspace 0.6.10 → 0.6.11

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": "@venturewild/workspace",
3
- "version": "0.6.10",
3
+ "version": "0.6.11",
4
4
  "description": "Claude Code Web — Replit/Lovable-style chat-first browser UI that wraps the AI agent already installed on your machine.",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -33,7 +33,7 @@ import {
33
33
  import { PairingStore } from './pairing.mjs';
34
34
  import { verifyGoogleVouch, emailMatches } from './google-vouch.mjs';
35
35
  import { listDir, readFile, fullTree, workspaceSummary, safeResolve } from './fs.mjs';
36
- import { browseDir, browseRoots } from './lobby-browse.mjs';
36
+ import { browseDir, browseRoots, listDrives } from './lobby-browse.mjs';
37
37
  import { InboxWatcher } from './inbox.mjs';
38
38
  import { ActivityBus } from './activity.mjs';
39
39
  import { createWorkspacePresence } from './workspace-presence.mjs';
@@ -2194,7 +2194,11 @@ export async function createServer(overrides = {}) {
2194
2194
  const reqPath = c.req.query('path');
2195
2195
  try {
2196
2196
  const listing = browseDir(reqPath && reqPath.trim() ? reqPath.trim() : home);
2197
- return c.json({ ...listing, roots: browseRoots({ home, workspacesHome }) });
2197
+ return c.json({
2198
+ ...listing,
2199
+ roots: browseRoots({ home, workspacesHome }),
2200
+ drives: listDrives(), // "This PC" — jump to any drive (D:, E:, …)
2201
+ });
2198
2202
  } catch (e) {
2199
2203
  return c.json({ error: e.code || 'browse_failed', message: String(e.message || e) }, 400);
2200
2204
  }
@@ -22,6 +22,24 @@ function isDirSafe(p) {
22
22
  }
23
23
  }
24
24
 
25
+ // The filesystem roots ("This PC"): on Windows each drive (C:\, D:\, …) is a
26
+ // SEPARATE root with no common parent — without this, the picker is trapped on
27
+ // the home drive (you could never browse to D:). We probe C–Z (A/B are legacy
28
+ // floppies; probing them can stall on some setups) and keep the ones that exist.
29
+ // On POSIX there's a single root, `/`.
30
+ export function listDrives() {
31
+ if (process.platform !== 'win32') {
32
+ return isDirSafe('/') ? [{ name: '/', dir: '/' }] : [];
33
+ }
34
+ const drives = [];
35
+ for (let code = 'C'.charCodeAt(0); code <= 'Z'.charCodeAt(0); code += 1) {
36
+ const letter = String.fromCharCode(code);
37
+ const root = `${letter}:\\`;
38
+ if (isDirSafe(root)) drives.push({ name: `${letter}:`, dir: root });
39
+ }
40
+ return drives;
41
+ }
42
+
25
43
  // Quick-access roots offered beside the listing — only the ones that actually
26
44
  // exist, de-duped by resolved path (Home/Desktop/Documents can coincide).
27
45
  export function browseRoots({ home, workspacesHome } = {}) {
@@ -77,7 +95,10 @@ export function browseDir(target) {
77
95
  }
78
96
  const entries = dirents
79
97
  .filter((d) => {
80
- if (d.name.startsWith('.')) return false; // hidden / dotfolders
98
+ if (d.name.startsWith('.')) return false; // hidden / dotfolders (POSIX + tooling)
99
+ // Windows system clutter that shows at every drive root ($RECYCLE.BIN,
100
+ // $WinREAgent, System Volume Information) — not pickable workspaces.
101
+ if (d.name.startsWith('$') || d.name === 'System Volume Information') return false;
81
102
  if (d.isDirectory()) return true;
82
103
  // Follow symlinks: a link to a directory is still a pickable folder.
83
104
  if (d.isSymbolicLink()) return isDirSafe(path.join(abs, d.name));