git-drive 0.1.0 → 0.1.1

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.
Files changed (68) hide show
  1. package/dist/commands/archive.js +32 -0
  2. package/dist/commands/init.js +27 -0
  3. package/dist/commands/link.js +139 -0
  4. package/dist/commands/list.js +83 -0
  5. package/dist/commands/push.js +99 -0
  6. package/dist/commands/restore.js +30 -0
  7. package/dist/commands/status.js +116 -0
  8. package/dist/config.js +62 -0
  9. package/dist/errors.js +30 -0
  10. package/dist/git.js +60 -0
  11. package/dist/index.js +89 -0
  12. package/dist/server.js +474 -0
  13. package/package.json +46 -14
  14. package/.github/workflows/ci.yml +0 -77
  15. package/.planning/codebase/ARCHITECTURE.md +0 -151
  16. package/.planning/codebase/CONCERNS.md +0 -191
  17. package/.planning/codebase/CONVENTIONS.md +0 -169
  18. package/.planning/codebase/INTEGRATIONS.md +0 -94
  19. package/.planning/codebase/STACK.md +0 -77
  20. package/.planning/codebase/STRUCTURE.md +0 -157
  21. package/.planning/codebase/TESTING.md +0 -156
  22. package/Dockerfile.cli +0 -30
  23. package/Dockerfile.server +0 -32
  24. package/README.md +0 -95
  25. package/docker-compose.yml +0 -48
  26. package/packages/cli/Dockerfile +0 -26
  27. package/packages/cli/package.json +0 -57
  28. package/packages/cli/src/commands/archive.ts +0 -39
  29. package/packages/cli/src/commands/init.ts +0 -34
  30. package/packages/cli/src/commands/link.ts +0 -115
  31. package/packages/cli/src/commands/list.ts +0 -94
  32. package/packages/cli/src/commands/push.ts +0 -64
  33. package/packages/cli/src/commands/restore.ts +0 -36
  34. package/packages/cli/src/commands/status.ts +0 -127
  35. package/packages/cli/src/config.ts +0 -73
  36. package/packages/cli/src/errors.ts +0 -23
  37. package/packages/cli/src/git.ts +0 -55
  38. package/packages/cli/src/index.ts +0 -97
  39. package/packages/cli/src/server.ts +0 -514
  40. package/packages/cli/tsconfig.json +0 -13
  41. package/packages/git-drive-docker/package.json +0 -15
  42. package/packages/server/package.json +0 -44
  43. package/packages/server/src/index.ts +0 -569
  44. package/packages/server/tsconfig.json +0 -9
  45. package/packages/ui/README.md +0 -73
  46. package/packages/ui/eslint.config.js +0 -23
  47. package/packages/ui/index.html +0 -13
  48. package/packages/ui/package.json +0 -42
  49. package/packages/ui/postcss.config.js +0 -6
  50. package/packages/ui/public/vite.svg +0 -1
  51. package/packages/ui/src/App.css +0 -23
  52. package/packages/ui/src/App.tsx +0 -726
  53. package/packages/ui/src/assets/react.svg +0 -8
  54. package/packages/ui/src/assets/vite.svg +0 -3
  55. package/packages/ui/src/index.css +0 -37
  56. package/packages/ui/src/main.tsx +0 -14
  57. package/packages/ui/tailwind.config.js +0 -11
  58. package/packages/ui/tsconfig.app.json +0 -28
  59. package/packages/ui/tsconfig.json +0 -26
  60. package/packages/ui/tsconfig.node.json +0 -12
  61. package/packages/ui/vite.config.ts +0 -7
  62. package/pnpm-workspace.yaml +0 -4
  63. package/rewrite_app.js +0 -731
  64. package/tsconfig.json +0 -14
  65. /package/{packages/cli/ui → ui}/assets/index-Cc2q1t5k.js +0 -0
  66. /package/{packages/cli/ui → ui}/assets/index-DrL7ojPA.css +0 -0
  67. /package/{packages/cli/ui → ui}/index.html +0 -0
  68. /package/{packages/cli/ui → ui}/vite.svg +0 -0
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.archive = archive;
4
+ const fs_1 = require("fs");
5
+ const config_js_1 = require("../config.js");
6
+ const git_js_1 = require("../git.js");
7
+ const push_js_1 = require("./push.js");
8
+ const errors_js_1 = require("../errors.js");
9
+ function archive(args) {
10
+ if (!(0, git_js_1.isGitRepo)()) {
11
+ throw new errors_js_1.GitDriveError("Not in a git repository.");
12
+ }
13
+ const force = args.includes("--force");
14
+ // Check for uncommitted changes
15
+ if (!force) {
16
+ const status = (0, git_js_1.git)("status --porcelain");
17
+ if (status) {
18
+ throw new errors_js_1.GitDriveError("Working tree has uncommitted changes.\nCommit first or use --force to archive anyway.");
19
+ }
20
+ }
21
+ const config = (0, config_js_1.requireConfig)();
22
+ (0, config_js_1.assertDriveMounted)(config.drivePath);
23
+ const projectName = (0, git_js_1.getProjectName)();
24
+ const repoRoot = (0, git_js_1.getRepoRoot)();
25
+ // Push first
26
+ (0, push_js_1.push)([]);
27
+ // Remove local copy
28
+ process.chdir("..");
29
+ (0, fs_1.rmSync)(repoRoot, { recursive: true, force: true });
30
+ console.log(`Archived: ${projectName}`);
31
+ console.log(`Restore with: git drive restore ${projectName}`);
32
+ }
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.init = init;
4
+ const fs_1 = require("fs");
5
+ const path_1 = require("path");
6
+ const config_js_1 = require("../config.js");
7
+ const errors_js_1 = require("../errors.js");
8
+ function init(args) {
9
+ const rawPath = args[0];
10
+ if (!rawPath) {
11
+ throw new errors_js_1.GitDriveError("Usage: git drive init <path>");
12
+ }
13
+ const drivePath = (0, path_1.resolve)(rawPath);
14
+ if (!(0, fs_1.existsSync)(drivePath)) {
15
+ throw new errors_js_1.GitDriveError(`Path not found: ${drivePath}\nIs the drive mounted?`);
16
+ }
17
+ const stat = (0, fs_1.statSync)(drivePath);
18
+ if (!stat.isDirectory()) {
19
+ throw new errors_js_1.GitDriveError(`Path is not a directory: ${drivePath}`);
20
+ }
21
+ const storePath = (0, config_js_1.getDriveStorePath)(drivePath);
22
+ if (!(0, fs_1.existsSync)(storePath)) {
23
+ (0, fs_1.mkdirSync)(storePath, { recursive: true });
24
+ }
25
+ (0, config_js_1.saveConfig)({ drivePath });
26
+ console.log(`Drive configured: ${storePath}`);
27
+ }
@@ -0,0 +1,139 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.link = link;
40
+ const errors_js_1 = require("../errors.js");
41
+ const config_js_1 = require("../config.js");
42
+ const git_js_1 = require("../git.js");
43
+ const prompts_1 = __importDefault(require("prompts"));
44
+ const fs = __importStar(require("fs"));
45
+ const path = __importStar(require("path"));
46
+ async function link(args) {
47
+ try {
48
+ const drives = await (0, git_js_1.listDrives)();
49
+ // Only fetch drives that actually have .git-drive configured
50
+ const configuredDrives = drives
51
+ .filter((drive) => drive.mounted && drive.mounted !== "/")
52
+ .filter((drive) => fs.existsSync(path.join(drive.mounted, ".git-drive")));
53
+ if (configuredDrives.length === 0) {
54
+ console.log("No initialized git-drives found. Please initialize a drive first.");
55
+ return;
56
+ }
57
+ const { drive } = await (0, prompts_1.default)({
58
+ type: "select",
59
+ name: "drive",
60
+ message: "Select a configured git-drive:",
61
+ choices: configuredDrives.map((d) => ({
62
+ title: `${d.filesystem} (${d.mounted})`,
63
+ value: d,
64
+ })),
65
+ });
66
+ if (!drive)
67
+ return;
68
+ const gitDrivePath = path.join(drive.mounted, ".git-drive");
69
+ const existingRepos = fs.readdirSync(gitDrivePath).filter((entry) => {
70
+ const entryPath = path.join(gitDrivePath, entry);
71
+ return (fs.statSync(entryPath).isDirectory() &&
72
+ (entry.endsWith(".git") || fs.existsSync(path.join(entryPath, "HEAD"))));
73
+ });
74
+ const CREATE_NEW = "__CREATE_NEW__";
75
+ const { selectedRepo } = await (0, prompts_1.default)({
76
+ type: "select",
77
+ name: "selectedRepo",
78
+ message: "Select an existing repository to link, or create a new one:",
79
+ choices: [
80
+ { title: "✨ Create new repository...", value: CREATE_NEW },
81
+ ...existingRepos.map((repo) => ({
82
+ title: `📁 ${repo.replace(/\.git$/, "")}`,
83
+ value: repo,
84
+ })),
85
+ ],
86
+ });
87
+ if (!selectedRepo)
88
+ return;
89
+ let targetRepoName = selectedRepo;
90
+ if (selectedRepo === CREATE_NEW) {
91
+ const defaultName = (0, git_js_1.getProjectName)();
92
+ const { newRepoName } = await (0, prompts_1.default)({
93
+ type: "text",
94
+ name: "newRepoName",
95
+ message: "Enter the new repository name:",
96
+ initial: defaultName,
97
+ });
98
+ if (!newRepoName)
99
+ return;
100
+ targetRepoName = newRepoName.endsWith(".git") ? newRepoName : `${newRepoName}.git`;
101
+ const repoPath = path.join(gitDrivePath, targetRepoName);
102
+ if (fs.existsSync(repoPath)) {
103
+ console.log(`Repository ${targetRepoName} already exists in this drive.`);
104
+ return;
105
+ }
106
+ (0, git_js_1.git)(`init --bare "${repoPath}"`);
107
+ console.log(`Created new bare repository: ${targetRepoName}`);
108
+ }
109
+ const repoRoot = (0, git_js_1.getRepoRoot)();
110
+ const finalRepoPath = path.join(gitDrivePath, targetRepoName);
111
+ // Check if remote 'gd' already exists
112
+ let gdExists = false;
113
+ try {
114
+ (0, git_js_1.git)(`remote get-url gd`, repoRoot);
115
+ gdExists = true;
116
+ }
117
+ catch {
118
+ // Remote does not exist
119
+ }
120
+ if (gdExists) {
121
+ console.log("Remote 'gd' already exists. Updating it to point to the new drive.");
122
+ (0, git_js_1.git)(`remote set-url gd "${finalRepoPath}"`, repoRoot);
123
+ }
124
+ else {
125
+ (0, git_js_1.git)(`remote add gd "${finalRepoPath}"`, repoRoot);
126
+ }
127
+ // Persist to global git-drive registry for the Web UI
128
+ (0, config_js_1.saveLink)(repoRoot, drive.mounted, targetRepoName);
129
+ console.log(`\n✅ Successfully linked!`);
130
+ console.log(`Repository: ${targetRepoName.replace(/\.git$/, "")}`);
131
+ console.log(`Drive: ${drive.mounted}`);
132
+ console.log(`\nYou can now push to this remote using:`);
133
+ console.log(` git push gd main`);
134
+ }
135
+ catch (err) {
136
+ (0, errors_js_1.handleError)(err);
137
+ process.exit(1);
138
+ }
139
+ }
@@ -0,0 +1,83 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.list = list;
4
+ const fs_1 = require("fs");
5
+ const path_1 = require("path");
6
+ const os_1 = require("os");
7
+ const node_disk_info_1 = require("node-disk-info");
8
+ function loadLinks() {
9
+ const linksFile = (0, path_1.join)((0, os_1.homedir)(), ".config", "git-drive", "links.json");
10
+ if (!(0, fs_1.existsSync)(linksFile))
11
+ return {};
12
+ try {
13
+ return JSON.parse((0, fs_1.readFileSync)(linksFile, "utf-8"));
14
+ }
15
+ catch {
16
+ return {};
17
+ }
18
+ }
19
+ function getGitDrivePath(mountpoint) {
20
+ return (0, path_1.join)(mountpoint, ".git-drive");
21
+ }
22
+ async function list(_args) {
23
+ console.log("Git Drive - Connected Drives\n");
24
+ // Get all connected drives
25
+ let drives = [];
26
+ try {
27
+ drives = await (0, node_disk_info_1.getDiskInfo)();
28
+ }
29
+ catch (err) {
30
+ console.error("Error detecting drives:", err);
31
+ return;
32
+ }
33
+ // Filter to external/removable drives
34
+ const externalDrives = drives.filter((d) => {
35
+ const mp = d.mounted;
36
+ if (!mp)
37
+ return false;
38
+ if (mp === "/" || mp === "100%")
39
+ return false;
40
+ if (process.platform === "darwin") {
41
+ return mp.startsWith("/Volumes/") && !mp.startsWith("/Volumes/Recovery");
42
+ }
43
+ if (mp.startsWith("/sys") || mp.startsWith("/proc") || mp.startsWith("/run") || mp.startsWith("/snap") || mp.startsWith("/boot"))
44
+ return false;
45
+ if (d.filesystem === "tmpfs" || d.filesystem === "devtmpfs" || d.filesystem === "udev" || d.filesystem === "overlay")
46
+ return false;
47
+ return true;
48
+ });
49
+ if (externalDrives.length === 0) {
50
+ console.log("No external drives detected.");
51
+ console.log("\nConnect an external drive and try again.");
52
+ return;
53
+ }
54
+ // Load links to show which drives are registered
55
+ const links = loadLinks();
56
+ const registeredMountpoints = new Set(Object.values(links).map(l => l.mountpoint));
57
+ for (const drive of externalDrives) {
58
+ const mp = drive.mounted;
59
+ const gitDrivePath = getGitDrivePath(mp);
60
+ const hasGitDrive = (0, fs_1.existsSync)(gitDrivePath);
61
+ const isRegistered = registeredMountpoints.has(mp);
62
+ // Count repos on this drive
63
+ let repoCount = 0;
64
+ if (hasGitDrive) {
65
+ try {
66
+ const entries = (0, fs_1.readdirSync)(gitDrivePath).filter(n => n.endsWith(".git") || (0, fs_1.existsSync)((0, path_1.join)(gitDrivePath, n, "HEAD")));
67
+ repoCount = entries.length;
68
+ }
69
+ catch { }
70
+ }
71
+ // Format size
72
+ const sizeGB = drive.blocks ? ((parseInt(drive.blocks) * 1024) / (1024 * 1024 * 1024)).toFixed(1) : "?";
73
+ // Status indicator
74
+ const status = hasGitDrive ? "✓ registered" : "○ not registered";
75
+ console.log(` ${mp}`);
76
+ console.log(` Size: ${sizeGB} GB`);
77
+ console.log(` Status: ${status}`);
78
+ console.log(` Repositories: ${repoCount}`);
79
+ console.log();
80
+ }
81
+ console.log(`\n${externalDrives.length} drive${externalDrives.length === 1 ? "" : "s"} detected.`);
82
+ console.log("\nRun 'git-drive link' to link a repo to a drive.");
83
+ }
@@ -0,0 +1,99 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.push = push;
40
+ const git_js_1 = require("../git.js");
41
+ const errors_js_1 = require("../errors.js");
42
+ const prompts_1 = __importDefault(require("prompts"));
43
+ const fs = __importStar(require("fs"));
44
+ const path = __importStar(require("path"));
45
+ const os = __importStar(require("os"));
46
+ async function push(_args) {
47
+ if (!(0, git_js_1.isGitRepo)()) {
48
+ throw new errors_js_1.GitDriveError("Not in a git repository.");
49
+ }
50
+ const existingUrl = (0, git_js_1.getRemoteUrl)("gd");
51
+ if (!existingUrl) {
52
+ throw new errors_js_1.GitDriveError("No git-drive linked for this project. Please run 'git-drive link' first.");
53
+ }
54
+ try {
55
+ const currentBranch = (0, git_js_1.git)("branch --show-current") || "HEAD";
56
+ const { pushMode } = await (0, prompts_1.default)({
57
+ type: "select",
58
+ name: "pushMode",
59
+ message: `Pushing to ${existingUrl}\nSelect what to branch to push:`,
60
+ choices: [
61
+ { title: `Current branch only (${currentBranch})`, value: "current" },
62
+ { title: "All branches & tags", value: "all" }
63
+ ]
64
+ });
65
+ if (!pushMode)
66
+ return;
67
+ if (pushMode === "current") {
68
+ console.log(`\nPushing ${currentBranch}...`);
69
+ (0, git_js_1.git)(`push gd ${currentBranch}`);
70
+ console.log(`✅ Successfully pushed ${currentBranch} to git-drive.`);
71
+ }
72
+ else {
73
+ console.log("\nPushing all branches and tags...");
74
+ (0, git_js_1.git)("push gd --all");
75
+ (0, git_js_1.git)("push gd --tags");
76
+ console.log(`✅ Successfully pushed all branches and tags to git-drive.`);
77
+ }
78
+ // Write context to a central pushlog safely inside the git-drive repo folder
79
+ try {
80
+ if (fs.existsSync(existingUrl)) {
81
+ const payload = {
82
+ date: new Date().toISOString(),
83
+ computer: os.hostname(),
84
+ user: os.userInfo().username,
85
+ localDir: process.cwd(),
86
+ mode: pushMode,
87
+ };
88
+ const logFile = path.join(existingUrl, "git-drive-pushlog.json");
89
+ fs.appendFileSync(logFile, JSON.stringify(payload) + "\n", "utf-8");
90
+ }
91
+ }
92
+ catch {
93
+ // Intentionally swallow telemetry tracking errors
94
+ }
95
+ }
96
+ catch (err) {
97
+ throw new errors_js_1.GitDriveError(`Failed to push to drive. Make sure the drive is connected.\n${err.message}`);
98
+ }
99
+ }
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.restore = restore;
4
+ const fs_1 = require("fs");
5
+ const path_1 = require("path");
6
+ const config_js_1 = require("../config.js");
7
+ const git_js_1 = require("../git.js");
8
+ const errors_js_1 = require("../errors.js");
9
+ function restore(args) {
10
+ const projectName = args[0];
11
+ const targetDir = args[1] || projectName;
12
+ if (!projectName) {
13
+ throw new errors_js_1.GitDriveError("Usage: git drive restore <project-name> [target-dir]");
14
+ }
15
+ const config = (0, config_js_1.requireConfig)();
16
+ (0, config_js_1.assertDriveMounted)(config.drivePath);
17
+ const storePath = (0, config_js_1.getDriveStorePath)(config.drivePath);
18
+ const bareRepoPath = (0, path_1.join)(storePath, `${projectName}.git`);
19
+ if (!(0, fs_1.existsSync)(bareRepoPath)) {
20
+ throw new errors_js_1.GitDriveError(`Project '${projectName}' not found on drive.`);
21
+ }
22
+ const targetPath = (0, path_1.resolve)(targetDir);
23
+ if ((0, fs_1.existsSync)(targetPath)) {
24
+ throw new errors_js_1.GitDriveError(`Directory already exists: ${targetPath}`);
25
+ }
26
+ (0, git_js_1.git)(`clone ${bareRepoPath} ${targetPath}`);
27
+ // Rename origin to drive so the remote stays consistent
28
+ (0, git_js_1.git)("remote rename origin drive", targetPath);
29
+ console.log(`Restored ${projectName} into ${targetPath}`);
30
+ }
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.status = status;
4
+ const fs_1 = require("fs");
5
+ const path_1 = require("path");
6
+ const os_1 = require("os");
7
+ const node_disk_info_1 = require("node-disk-info");
8
+ const git_js_1 = require("../git.js");
9
+ function loadLinks() {
10
+ const linksFile = (0, path_1.join)((0, os_1.homedir)(), ".config", "git-drive", "links.json");
11
+ if (!(0, fs_1.existsSync)(linksFile))
12
+ return {};
13
+ try {
14
+ return JSON.parse((0, fs_1.readFileSync)(linksFile, "utf-8"));
15
+ }
16
+ catch {
17
+ return {};
18
+ }
19
+ }
20
+ function getGitDrivePath(mountpoint) {
21
+ return (0, path_1.join)(mountpoint, ".git-drive");
22
+ }
23
+ async function status(_args) {
24
+ console.log("Git Drive Status\n");
25
+ // Get all connected drives
26
+ let drives = [];
27
+ try {
28
+ drives = await (0, node_disk_info_1.getDiskInfo)();
29
+ }
30
+ catch (err) {
31
+ console.error("Error detecting drives:", err);
32
+ return;
33
+ }
34
+ // Filter to external/removable drives
35
+ const externalDrives = drives.filter((d) => {
36
+ const mp = d.mounted;
37
+ if (!mp)
38
+ return false;
39
+ if (mp === "/" || mp === "100%")
40
+ return false;
41
+ if (process.platform === "darwin") {
42
+ return mp.startsWith("/Volumes/") && !mp.startsWith("/Volumes/Recovery");
43
+ }
44
+ if (mp.startsWith("/sys") || mp.startsWith("/proc") || mp.startsWith("/run") || mp.startsWith("/snap") || mp.startsWith("/boot"))
45
+ return false;
46
+ if (d.filesystem === "tmpfs" || d.filesystem === "devtmpfs" || d.filesystem === "udev" || d.filesystem === "overlay")
47
+ return false;
48
+ return true;
49
+ });
50
+ // Load links
51
+ const links = loadLinks();
52
+ const linkEntries = Object.entries(links);
53
+ // Show connected drives with git-drive
54
+ console.log("=== Connected Drives ===\n");
55
+ if (externalDrives.length === 0) {
56
+ console.log("No external drives connected.\n");
57
+ }
58
+ else {
59
+ for (const drive of externalDrives) {
60
+ const mp = drive.mounted;
61
+ const gitDrivePath = getGitDrivePath(mp);
62
+ const hasGitDrive = (0, fs_1.existsSync)(gitDrivePath);
63
+ if (hasGitDrive) {
64
+ const entries = (0, fs_1.readdirSync)(gitDrivePath).filter(n => n.endsWith(".git") || (0, fs_1.existsSync)((0, path_1.join)(gitDrivePath, n, "HEAD")));
65
+ console.log(`✓ ${mp}`);
66
+ console.log(` ${entries.length} repo${entries.length === 1 ? "" : "s"} backed up`);
67
+ }
68
+ else {
69
+ console.log(`○ ${mp} (not initialized)`);
70
+ }
71
+ }
72
+ console.log();
73
+ }
74
+ // Show registered drives (from links)
75
+ console.log("=== Registered Repositories ===\n");
76
+ if (linkEntries.length === 0) {
77
+ console.log("No repositories linked to drives yet.");
78
+ console.log("Run 'git-drive link' to link a repository.\n");
79
+ }
80
+ else {
81
+ for (const [localPath, link] of linkEntries) {
82
+ const stillConnected = (0, fs_1.existsSync)(link.mountpoint);
83
+ const localExists = (0, fs_1.existsSync)(localPath);
84
+ console.log(`${localPath}`);
85
+ console.log(` → ${link.mountpoint} (${link.repoName})`);
86
+ console.log(` Drive: ${stillConnected ? "connected" : "NOT CONNECTED"}`);
87
+ console.log(` Local: ${localExists ? "exists" : "NOT FOUND"}`);
88
+ console.log();
89
+ }
90
+ }
91
+ // Show current repo status if in a git repo
92
+ if ((0, git_js_1.isGitRepo)()) {
93
+ console.log("=== Current Repository ===\n");
94
+ const name = (0, git_js_1.getProjectName)();
95
+ const remoteUrl = (0, git_js_1.getRemoteUrl)("gd");
96
+ console.log(`Repository: ${name}`);
97
+ if (remoteUrl) {
98
+ console.log(`Remote 'gd': ${remoteUrl}`);
99
+ // Check if this repo is linked
100
+ const cwd = process.cwd();
101
+ const link = links[cwd];
102
+ if (link) {
103
+ console.log(`Linked to: ${link.mountpoint}`);
104
+ }
105
+ }
106
+ else {
107
+ console.log(`No 'gd' remote configured.`);
108
+ console.log("Run 'git-drive link' to set up backup.");
109
+ }
110
+ console.log();
111
+ }
112
+ // Server status hint
113
+ console.log("=== Server ===\n");
114
+ console.log("Web UI: http://localhost:4483");
115
+ console.log("Run 'git-drive server' to start the web interface.\n");
116
+ }
package/dist/config.js ADDED
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loadConfig = loadConfig;
4
+ exports.saveConfig = saveConfig;
5
+ exports.requireConfig = requireConfig;
6
+ exports.assertDriveMounted = assertDriveMounted;
7
+ exports.getDriveStorePath = getDriveStorePath;
8
+ exports.loadLinks = loadLinks;
9
+ exports.saveLink = saveLink;
10
+ const os_1 = require("os");
11
+ const path_1 = require("path");
12
+ const fs_1 = require("fs");
13
+ const errors_js_1 = require("./errors.js");
14
+ const CONFIG_DIR = (0, path_1.join)((0, os_1.homedir)(), ".config", "git-drive");
15
+ const CONFIG_FILE = (0, path_1.join)(CONFIG_DIR, "config.json");
16
+ function loadConfig() {
17
+ if (!(0, fs_1.existsSync)(CONFIG_FILE))
18
+ return null;
19
+ const raw = (0, fs_1.readFileSync)(CONFIG_FILE, "utf-8");
20
+ return JSON.parse(raw);
21
+ }
22
+ function saveConfig(config) {
23
+ (0, fs_1.mkdirSync)(CONFIG_DIR, { recursive: true });
24
+ (0, fs_1.writeFileSync)(CONFIG_FILE, JSON.stringify(config, null, 2) + "\n");
25
+ }
26
+ function requireConfig() {
27
+ const config = loadConfig();
28
+ if (!config) {
29
+ throw new errors_js_1.GitDriveError("No drive configured. Run: git drive init <path>");
30
+ }
31
+ return config;
32
+ }
33
+ function assertDriveMounted(drivePath) {
34
+ if (!(0, fs_1.existsSync)(drivePath)) {
35
+ throw new errors_js_1.GitDriveError(`Drive not found at ${drivePath}. Is it connected?`);
36
+ }
37
+ }
38
+ function getDriveStorePath(drivePath) {
39
+ return (0, path_1.join)(drivePath, "git-drive");
40
+ }
41
+ const LINKS_FILE = (0, path_1.join)(CONFIG_DIR, "links.json");
42
+ function loadLinks() {
43
+ if (!(0, fs_1.existsSync)(LINKS_FILE))
44
+ return {};
45
+ try {
46
+ const raw = (0, fs_1.readFileSync)(LINKS_FILE, "utf-8");
47
+ return JSON.parse(raw);
48
+ }
49
+ catch {
50
+ return {};
51
+ }
52
+ }
53
+ function saveLink(localPath, mountpoint, repoName) {
54
+ (0, fs_1.mkdirSync)(CONFIG_DIR, { recursive: true });
55
+ const links = loadLinks();
56
+ links[localPath] = {
57
+ mountpoint,
58
+ repoName,
59
+ linkedAt: new Date().toISOString(),
60
+ };
61
+ (0, fs_1.writeFileSync)(LINKS_FILE, JSON.stringify(links, null, 2) + "\n");
62
+ }
package/dist/errors.js ADDED
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GitDriveError = void 0;
4
+ exports.handleError = handleError;
5
+ class GitDriveError extends Error {
6
+ constructor(message) {
7
+ super(message);
8
+ this.name = "GitDriveError";
9
+ }
10
+ }
11
+ exports.GitDriveError = GitDriveError;
12
+ function handleError(err) {
13
+ if (err instanceof GitDriveError) {
14
+ console.error(`error: ${err.message}`);
15
+ }
16
+ else if (err instanceof Error) {
17
+ const msg = err.message;
18
+ // execSync errors include stderr in the message
19
+ const stderrMatch = msg.match(/stderr:\s*([\s\S]*)/);
20
+ if (stderrMatch) {
21
+ console.error(`error: ${stderrMatch[1].trim()}`);
22
+ }
23
+ else {
24
+ console.error(`error: ${msg}`);
25
+ }
26
+ }
27
+ else {
28
+ console.error("An unexpected error occurred.");
29
+ }
30
+ }
package/dist/git.js ADDED
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.git = git;
4
+ exports.listDrives = listDrives;
5
+ exports.getRepoRoot = getRepoRoot;
6
+ exports.getProjectName = getProjectName;
7
+ exports.getRemoteUrl = getRemoteUrl;
8
+ exports.isGitRepo = isGitRepo;
9
+ const child_process_1 = require("child_process");
10
+ const path_1 = require("path");
11
+ const node_disk_info_1 = require("node-disk-info");
12
+ function git(args, cwd) {
13
+ return (0, child_process_1.execSync)(`git ${args}`, {
14
+ cwd,
15
+ encoding: "utf-8",
16
+ stdio: ["pipe", "pipe", "pipe"],
17
+ }).trim();
18
+ }
19
+ async function listDrives() {
20
+ const drives = await (0, node_disk_info_1.getDiskInfo)();
21
+ return drives.filter((d) => {
22
+ const mp = d.mounted;
23
+ if (!mp)
24
+ return false;
25
+ if (mp === "/" || mp === "100%")
26
+ return false;
27
+ if (process.platform === "darwin") {
28
+ return mp.startsWith("/Volumes/") && !mp.startsWith("/Volumes/Recovery");
29
+ }
30
+ if (mp.startsWith("/sys") || mp.startsWith("/proc") || mp.startsWith("/run") || mp.startsWith("/snap") || mp.startsWith("/boot"))
31
+ return false;
32
+ if (d.filesystem === "tmpfs" || d.filesystem === "devtmpfs" || d.filesystem === "udev" || d.filesystem === "overlay")
33
+ return false;
34
+ return true;
35
+ });
36
+ }
37
+ function getRepoRoot() {
38
+ return git("rev-parse --show-toplevel");
39
+ }
40
+ function getProjectName() {
41
+ const root = getRepoRoot();
42
+ return (0, path_1.basename)(root);
43
+ }
44
+ function getRemoteUrl(remoteName) {
45
+ try {
46
+ return git(`remote get-url ${remoteName}`);
47
+ }
48
+ catch {
49
+ return null;
50
+ }
51
+ }
52
+ function isGitRepo() {
53
+ try {
54
+ git("rev-parse --is-inside-work-tree");
55
+ return true;
56
+ }
57
+ catch {
58
+ return false;
59
+ }
60
+ }