Skip to content

Feature: Centralized File Location Index with Cross-Machine Sync #51

@EricGrill

Description

@EricGrill

Feature: Centralized File Location Index with Cross-Machine Sync

Problem

Projects stores workspace paths in vscode.ExtensionContext.globalState, which is local to each VS Code installation. When Eric works across Ventress (main workstation), Snoke (server), and his laptop, the same project exists at different absolute paths on each machine (e.g., /home/eric/projects/foo vs /Users/eric/projects/foo vs /mnt/ventress/projects/foo). There is no way to share where a file or project lives across devices, forcing manual path bookkeeping or broken workspace links when switching machines.

Proposed Solution

Introduce a File Location Index (FLI) — a machine-agnostic mapping layer that decouples the logical project identity from its physical path on any given host.

Core Data Model

type MachineId = string; // e.g., "ventress", "snoke", "macbook-pro"

type FileLocation = {
  projectId: string;      // UUID or deterministic hash of repo remote/origin
  machineId: MachineId;
  absolutePath: string;
  pathAlias?: string;     // e.g., "~/projects", "$WORKSPACE_ROOT"
  lastVerified: number;   // timestamp
  gitRemote?: string;     // origin URL for disambiguation
};

type ProjectIndexEntry = {
  id: string;
  name: string;
  type: ProjectTypes;
  locations: FileLocation[];
  primaryRemote?: string; // git origin URL
  tags: string[];
};

Sync Backend Options (in order of preference)

  1. GitHub Gist (free, versioned, no infra) — store the index as a JSON file in a private Gist. Use a personal access token scoped to gist.
  2. Self-hosted JSON endpoint (e.g., a tiny Deno/Node server on Snoke) — for users who don't want cloud dependencies.
  3. Local file export/import — manual .projects-index.json that can be rsync'd or dropped into Dropbox/iCloud.

Implementation Plan

  • Phase 1: Machine Identity
    • Add l13Projects.machineId setting (auto-detect hostname, user-overridable).
    • Add l13Projects.sync.enabled and l13Projects.sync.backend settings (gist, http, file).
  • Phase 2: Index Manager
    • Create src/sync/IndexManager.ts that wraps read/write of the FLI.
    • On project save, automatically register (projectId, machineId, absolutePath) to the index.
    • On workspace open, resolve the local path for the current machineId from the index; if missing, prompt to "link this location".
  • Phase 3: Gist Sync Engine
    • Create src/sync/GistSyncProvider.ts implementing a SyncProvider interface.
    • Methods: pullIndex(), pushIndex(index), resolveConflict(local, remote).
    • Use lastModified timestamps from stateInfo for optimistic concurrency.
  • Phase 4: Path Resolution Layer
    • Modify ProjectsState.getByPath() and WorkspacesState.getByPath() to accept a projectId and resolve the local path via the index.
    • Add command: Projects: Open Project on Another Machine — shows a quick-pick of machineIds and copies the SSH/scp path to clipboard.
  • Phase 5: UI Integration
    • In the sidebar tree, show a small "synced" icon (🌐) next to projects that exist in the FLI.
    • Hover tooltip shows: "Also on: ventress, snoke".

Acceptance Criteria

  • Saving a project on Ventress makes it discoverable (by name + git remote) on the laptop within 30 seconds of VS Code startup.
  • Opening a synced project on a machine where it hasn't been linked yet prompts the user to select the local folder, then updates the index.
  • Deleting a project locally does not delete the index entry for other machines.
  • Works offline: index is cached locally and syncs on next connection.

Open Questions

  • Should we use the Git origin URL as the canonical project ID, or a UUID? Git remote is deterministic but fails for non-Git projects.
  • Gist has a ~300KB file limit. Is that sufficient for 500+ projects with full metadata? (Yes, likely ~50KB.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions