git-drive 0.1.0

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 (56) hide show
  1. package/.github/workflows/ci.yml +77 -0
  2. package/.planning/codebase/ARCHITECTURE.md +151 -0
  3. package/.planning/codebase/CONCERNS.md +191 -0
  4. package/.planning/codebase/CONVENTIONS.md +169 -0
  5. package/.planning/codebase/INTEGRATIONS.md +94 -0
  6. package/.planning/codebase/STACK.md +77 -0
  7. package/.planning/codebase/STRUCTURE.md +157 -0
  8. package/.planning/codebase/TESTING.md +156 -0
  9. package/Dockerfile.cli +30 -0
  10. package/Dockerfile.server +32 -0
  11. package/README.md +95 -0
  12. package/docker-compose.yml +48 -0
  13. package/package.json +25 -0
  14. package/packages/cli/Dockerfile +26 -0
  15. package/packages/cli/package.json +57 -0
  16. package/packages/cli/src/commands/archive.ts +39 -0
  17. package/packages/cli/src/commands/init.ts +34 -0
  18. package/packages/cli/src/commands/link.ts +115 -0
  19. package/packages/cli/src/commands/list.ts +94 -0
  20. package/packages/cli/src/commands/push.ts +64 -0
  21. package/packages/cli/src/commands/restore.ts +36 -0
  22. package/packages/cli/src/commands/status.ts +127 -0
  23. package/packages/cli/src/config.ts +73 -0
  24. package/packages/cli/src/errors.ts +23 -0
  25. package/packages/cli/src/git.ts +55 -0
  26. package/packages/cli/src/index.ts +97 -0
  27. package/packages/cli/src/server.ts +514 -0
  28. package/packages/cli/tsconfig.json +13 -0
  29. package/packages/cli/ui/assets/index-Cc2q1t5k.js +17 -0
  30. package/packages/cli/ui/assets/index-DrL7ojPA.css +1 -0
  31. package/packages/cli/ui/index.html +14 -0
  32. package/packages/cli/ui/vite.svg +1 -0
  33. package/packages/git-drive-docker/package.json +15 -0
  34. package/packages/server/package.json +44 -0
  35. package/packages/server/src/index.ts +569 -0
  36. package/packages/server/tsconfig.json +9 -0
  37. package/packages/ui/README.md +73 -0
  38. package/packages/ui/eslint.config.js +23 -0
  39. package/packages/ui/index.html +13 -0
  40. package/packages/ui/package.json +42 -0
  41. package/packages/ui/postcss.config.js +6 -0
  42. package/packages/ui/public/vite.svg +1 -0
  43. package/packages/ui/src/App.css +23 -0
  44. package/packages/ui/src/App.tsx +726 -0
  45. package/packages/ui/src/assets/react.svg +8 -0
  46. package/packages/ui/src/assets/vite.svg +3 -0
  47. package/packages/ui/src/index.css +37 -0
  48. package/packages/ui/src/main.tsx +14 -0
  49. package/packages/ui/tailwind.config.js +11 -0
  50. package/packages/ui/tsconfig.app.json +28 -0
  51. package/packages/ui/tsconfig.json +26 -0
  52. package/packages/ui/tsconfig.node.json +12 -0
  53. package/packages/ui/vite.config.ts +7 -0
  54. package/pnpm-workspace.yaml +4 -0
  55. package/rewrite_app.js +731 -0
  56. package/tsconfig.json +14 -0
@@ -0,0 +1,77 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main, master]
6
+ pull_request:
7
+ branches: [main, master]
8
+
9
+ jobs:
10
+ build:
11
+ runs-on: ubuntu-latest
12
+
13
+ steps:
14
+ - name: Checkout repository
15
+ uses: actions/checkout@v4
16
+
17
+ - name: Setup Node.js
18
+ uses: actions/setup-node@v4
19
+ with:
20
+ node-version: '20'
21
+
22
+ - name: Install pnpm
23
+ uses: pnpm/action-setup@v2
24
+ with:
25
+ version: 9
26
+
27
+ - name: Get pnpm store directory
28
+ shell: bash
29
+ run: |
30
+ echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_OUTPUT
31
+ id: pnpm-cache
32
+
33
+ - name: Setup pnpm cache
34
+ uses: actions/cache@v4
35
+ with:
36
+ path: ${{ steps.pnpm-cache.outputs.STORE_PATH }}
37
+ key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
38
+ restore-keys: |
39
+ ${{ runner.os }}-pnpm-store-
40
+
41
+ - name: Install dependencies
42
+ run: pnpm install --frozen-lockfile
43
+
44
+ - name: Build
45
+ run: pnpm build
46
+
47
+ publish-cli:
48
+ needs: build
49
+ runs-on: ubuntu-latest
50
+ if: github.event_name == 'push' && github.ref == 'refs/heads/main'
51
+
52
+ steps:
53
+ - name: Checkout repository
54
+ uses: actions/checkout@v4
55
+
56
+ - name: Setup Node.js
57
+ uses: actions/setup-node@v4
58
+ with:
59
+ node-version: '20'
60
+ registry-url: 'https://registry.npmjs.org'
61
+
62
+ - name: Install pnpm
63
+ uses: pnpm/action-setup@v2
64
+ with:
65
+ version: 9
66
+
67
+ - name: Install dependencies
68
+ run: pnpm install --frozen-lockfile
69
+
70
+ - name: Build CLI
71
+ run: pnpm build:cli
72
+
73
+ - name: Publish to npm
74
+ working-directory: packages/cli
75
+ run: npm publish --access public
76
+ env:
77
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -0,0 +1,151 @@
1
+ # Architecture
2
+
3
+ **Analysis Date:** 2026-01-22
4
+
5
+ ## Pattern Overview
6
+
7
+ **Overall:** Command-line application with modular command pattern and layered abstractions
8
+
9
+ **Key Characteristics:**
10
+ - CLI entry point dispatching to isolated command handlers
11
+ - Separation of concerns: command logic, git operations, configuration management, error handling
12
+ - Synchronous execution using Node.js child_process for git operations
13
+ - Configuration-driven behavior with persistent state in user home directory
14
+ - Minimal external dependencies (Node.js stdlib only)
15
+
16
+ ## Layers
17
+
18
+ **CLI Layer (Command Dispatch):**
19
+ - Purpose: Parse command arguments, route to appropriate command handler, manage process lifecycle
20
+ - Location: `src/index.ts`
21
+ - Contains: Main entry point, command registry, usage documentation, error handling wrapper
22
+ - Depends on: All command modules, error handling
23
+ - Used by: Node.js process execution
24
+
25
+ **Command Layer:**
26
+ - Purpose: Implement high-level workflows for each feature (init, push, archive, restore, list, status)
27
+ - Location: `src/commands/*.ts` (init.ts, push.ts, archive.ts, restore.ts, list.ts, status.ts)
28
+ - Contains: Command-specific business logic, parameter validation, orchestration of lower layers
29
+ - Depends on: Config layer, Git layer, Error types
30
+ - Used by: CLI dispatch layer
31
+
32
+ **Configuration Layer:**
33
+ - Purpose: Load, save, and validate application configuration (drive path); assert drive connectivity
34
+ - Location: `src/config.ts`
35
+ - Contains: Config file I/O, config validation, drive path helpers
36
+ - Depends on: Node.js fs, path, os modules; Error types
37
+ - Used by: Most command handlers; config validation before operations
38
+
39
+ **Git Abstraction Layer:**
40
+ - Purpose: Encapsulate git command execution and repository queries with consistent error handling
41
+ - Location: `src/git.ts`
42
+ - Contains: git() execution wrapper, repo root queries, project name resolution, remote URL inspection
43
+ - Depends on: Node.js child_process, path modules
44
+ - Used by: All command handlers that interact with git
45
+
46
+ **Error Handling Layer:**
47
+ - Purpose: Define custom error types and provide unified error output formatting
48
+ - Location: `src/errors.ts`
49
+ - Contains: GitDriveError exception class, handleError() formatting function
50
+ - Depends on: None
51
+ - Used by: All layers for consistent error propagation and output
52
+
53
+ ## Data Flow
54
+
55
+ **Push Workflow:**
56
+
57
+ 1. CLI receives `git drive push` command
58
+ 2. Index.ts routes to push() handler in `src/commands/push.ts`
59
+ 3. push() validates git repository status (isGitRepo)
60
+ 4. Loads configuration from ~/.config/git-drive/config.json
61
+ 5. Asserts drive is mounted at configured drivePath
62
+ 6. Queries project name from git repository root
63
+ 7. Creates or updates bare git repository at {drive}/git-drive/{project-name}.git
64
+ 8. Adds "drive" remote to local repository pointing to bare repo
65
+ 9. Pushes all branches and tags to drive remote
66
+ 10. Outputs success message
67
+
68
+ **Archive Workflow:**
69
+
70
+ 1. CLI receives `git drive archive [--force]` command
71
+ 2. archive() in `src/commands/archive.ts` validates git repository
72
+ 3. Checks for uncommitted changes (unless --force flag provided)
73
+ 4. Calls push() internally to backup all content
74
+ 5. Changes working directory to parent
75
+ 6. Removes entire local repository directory
76
+ 7. Outputs archive confirmation with restore instructions
77
+
78
+ **Restore Workflow:**
79
+
80
+ 1. CLI receives `git drive restore <project-name> [target-dir]`
81
+ 2. restore() in `src/commands/restore.ts` validates configuration
82
+ 3. Asserts drive is mounted
83
+ 4. Checks that bare repository exists on drive at {drive}/git-drive/{project-name}.git
84
+ 5. Clones bare repository to target directory
85
+ 6. Renames "origin" remote to "drive" for consistency with push workflow
86
+ 7. Outputs success message with restored path
87
+
88
+ **Status Query Workflow:**
89
+
90
+ 1. CLI receives `git drive status`
91
+ 2. status() in `src/commands/status.ts` loads configuration (non-fatal if missing)
92
+ 3. Checks drive connectivity by filesystem existence check
93
+ 4. If connected: lists all projects in {drive}/git-drive/ by enumerating .git directories
94
+ 5. If in a git repository: reports project name and drive remote status
95
+ 6. Outputs multi-line status report
96
+
97
+ **State Management:**
98
+
99
+ - Configuration state: Persistent JSON file at ~/.config/git-drive/config.json (drivePath property only)
100
+ - Repository state: Stored in git bare repositories on external drive; local repositories maintain standard git state
101
+ - No in-memory state caching; all reads are fresh from filesystem/git
102
+
103
+ ## Key Abstractions
104
+
105
+ **Git Command Wrapper (git()):**
106
+ - Purpose: Provide safe, consistent git command execution with error propagation
107
+ - Examples: `src/git.ts` functions like git(), getRepoRoot(), getProjectName(), getRemoteUrl()
108
+ - Pattern: execSync with explicit error handling; stdio piping to capture output; optional cwd parameter for working directory context
109
+
110
+ **GitDriveError Exception:**
111
+ - Purpose: Distinguish application-level errors (user/config issues) from system errors
112
+ - Examples: "No drive configured", "Working tree has uncommitted changes", "Path not found"
113
+ - Pattern: Custom Error subclass with name property; caught and formatted in main error handler
114
+
115
+ **Configuration Contract:**
116
+ - Purpose: Validate drive path existence and accessibility before operations
117
+ - Examples: requireConfig() (throws if missing), assertDriveMounted() (checks filesystem)
118
+ - Pattern: Fail-fast validation at command start; errors reported immediately to user
119
+
120
+ **Command Handler Signature:**
121
+ - Purpose: Provide consistent interface for CLI dispatch
122
+ - Pattern: (args: string[]) => void; throws GitDriveError on validation failures; logs results to console
123
+
124
+ ## Entry Points
125
+
126
+ **CLI Entry Point (Node.js executable):**
127
+ - Location: `src/index.ts` (shebang: #!/usr/bin/env node)
128
+ - Triggers: Installation via npm/git-drive binary; direct node execution
129
+ - Responsibilities: Command parsing, handler dispatch, error handling, process exit code management
130
+
131
+ **Command Handlers (6 total):**
132
+ - init: Initialize drive path; called once per setup
133
+ - push: Back up current repository; called before archive or periodically
134
+ - archive: Backup and remove local copy; called when archiving projects
135
+ - restore: Retrieve archived project; called to bring archived projects back online
136
+ - list: Display all archived projects; informational query
137
+ - status: Display current drive and repository state; diagnostic command
138
+
139
+ ## Error Handling
140
+
141
+ **Strategy:** Fail-fast with clear user messaging; distinguish application errors from system errors
142
+
143
+ **Patterns:**
144
+ - GitDriveError for expected failures (missing config, wrong path, uncommitted changes)
145
+ - Error type checking in main handler: if GitDriveError show message directly, else parse stderr from execSync
146
+ - Process exits with code 1 on any error; code 0 on success
147
+ - All error messages prefixed with "error: " for consistency
148
+
149
+ ---
150
+
151
+ *Architecture analysis: 2026-01-22*
@@ -0,0 +1,191 @@
1
+ # Codebase Concerns
2
+
3
+ **Analysis Date:** 2026-01-22
4
+
5
+ ## Tech Debt
6
+
7
+ **Command Injection Vulnerability via execSync:**
8
+ - Issue: Git arguments are passed directly to `execSync` without sanitization. Paths containing special characters could allow injection.
9
+ - Files: `src/git.ts` (lines 5-9), `src/commands/push.ts` (lines 21, 28, 31, 35-36), `src/commands/archive.ts` (line 16), `src/commands/restore.ts` (line 30, 33)
10
+ - Impact: Malicious project names or file paths could execute arbitrary shell commands
11
+ - Fix approach: Use array form of `execSync` or use `spawn` instead of shell interpolation. Alternatively, escape shell arguments using a library like `shell-escape`.
12
+
13
+ **Unguarded Process State Mutation in archive:**
14
+ - Issue: `process.chdir("..")` modifies global process state without cleanup or error handling. If removal fails, the process stays in parent directory.
15
+ - Files: `src/commands/archive.ts` (lines 34-35)
16
+ - Impact: If `rmSync` throws after `process.chdir`, the error handler exits from wrong directory, potentially confusing users. Subsequent operations in same process would operate from wrong directory.
17
+ - Fix approach: Wrap in try-finally to restore original cwd. Consider using relative paths or path.join instead of process.chdir.
18
+
19
+ **Error Information Leakage in Git Operations:**
20
+ - Issue: Git command failures expose full stderr output which might contain sensitive repository or system information.
21
+ - Files: `src/errors.ts` (lines 14-16), `src/git.ts` (lines 4-9)
22
+ - Impact: Sensitive paths, auth tokens, or system details could leak to stdout/stderr
23
+ - Fix approach: Sanitize git error messages, only show relevant error lines, hide sensitive paths.
24
+
25
+ ## Known Bugs
26
+
27
+ **Race Condition in Push Remote Handling:**
28
+ - Symptoms: If two processes call `push` simultaneously, both might check for existing remote URL and create duplicate remotes
29
+ - Files: `src/commands/push.ts` (lines 26-31)
30
+ - Trigger: Run `git drive push` from two separate terminal windows on same repo simultaneously
31
+ - Workaround: None. User must manually clean up remotes with `git remote rm drive`
32
+
33
+ **Archive Command Fails Silently on Partial Deletion:**
34
+ - Symptoms: If `rmSync` fails due to file locks (on Windows) or permissions, the output still says "Archived" but local copy remains
35
+ - Files: `src/commands/archive.ts` (lines 34-37)
36
+ - Trigger: On Windows with antivirus scanning files, or with open file handles
37
+ - Workaround: Manually delete directory after error, or use `--force` flag which ignores uncommitted changes but won't prevent rmSync errors
38
+
39
+ **Restore Creates Clone with Wrong Remote:**
40
+ - Symptoms: Cloning a bare repo creates `origin` remote, then it's renamed to `drive`, but if clone fails midway and user retries, state is inconsistent
41
+ - Files: `src/commands/restore.ts` (lines 30, 33)
42
+ - Trigger: Clone fails (network error, disk full) and user retries
43
+ - Workaround: Manually delete target directory and retry
44
+
45
+ ## Security Considerations
46
+
47
+ **Config File Permissions Not Set:**
48
+ - Risk: `~/.config/git-drive/config.json` is created world-readable if default umask is permissive. Contains drive path which could be sensitive.
49
+ - Files: `src/config.ts` (lines 20-21)
50
+ - Current mitigation: None
51
+ - Recommendations: Call `chmod 600` on config file after creation. Use `mode` option in `mkdirSync` to set 0o700 permissions.
52
+
53
+ **No Validation of Path Traversal in Restore:**
54
+ - Risk: User can specify `../../../etc/passwd` as target-dir. While Git clone itself prevents escaping, relative paths could be confusing.
55
+ - Files: `src/commands/restore.ts` (lines 9, 25)
56
+ - Current mitigation: Uses `resolve()` to canonicalize paths
57
+ - Recommendations: Validate target path is within expected directory or is absolute
58
+
59
+ **Insufficient Argument Validation:**
60
+ - Risk: Commands don't validate argument length or type, leading to confusing errors
61
+ - Files: `src/commands/restore.ts` (line 8), `src/index.ts` (line 32)
62
+ - Current mitigation: Basic checks in some commands
63
+ - Recommendations: Add argument count/type validation before processing
64
+
65
+ ## Performance Bottlenecks
66
+
67
+ **List Command Iterates All Entries Twice:**
68
+ - Problem: `readdirSync()` called, then filtered, then iterated with `statSync()` for each. No caching or batching.
69
+ - Files: `src/commands/list.ts` (lines 17-33)
70
+ - Cause: Synchronous I/O in loop, no parallelization
71
+ - Improvement path: Use `Dirent.isFile()` option in readdir to avoid extra stat calls. Not a bottleneck for typical drive sizes (<1000 projects) but poor pattern.
72
+
73
+ **Git Operations Not Buffered:**
74
+ - Problem: Each git command is a separate `execSync` call. `push --all` and `push --tags` execute separately instead of combined.
75
+ - Files: `src/commands/push.ts` (lines 35-36)
76
+ - Cause: Two separate git invocations where one could be chained
77
+ - Improvement path: Combine into single command: `git("push drive --all --tags")`
78
+
79
+ ## Fragile Areas
80
+
81
+ **Archive Command - Destructive Without Confirmation:**
82
+ - Files: `src/commands/archive.ts`
83
+ - Why fragile: Deletes entire local directory with only a weak check for uncommitted changes. `--force` flag disables even that.
84
+ - Safe modification: Add confirmation prompt before deletion (even with --force). Consider adding `--dry-run` to preview what would be deleted. Add atomic transaction guarantee: push succeeds before any deletion.
85
+ - Test coverage: No tests present. This is the most dangerous command.
86
+
87
+ **Git Remote Initialization Logic:**
88
+ - Files: `src/commands/push.ts` (lines 19-32)
89
+ - Why fragile: Multiple state branches (remote doesn't exist, exists with same URL, exists with different URL). Easy to miss edge case.
90
+ - Safe modification: Add tests for all three branches. Consider replacing with `git remote set-url --add` if it exists, then prune duplicates.
91
+ - Test coverage: No tests present.
92
+
93
+ **Config Persistence:**
94
+ - Files: `src/config.ts` (lines 13-21)
95
+ - Why fragile: No atomic writes, no backup of old config. If process crashes during JSON write, config corrupts.
96
+ - Safe modification: Write to temp file first, then rename. Add version field to config format.
97
+ - Test coverage: No tests present.
98
+
99
+ **Drive Mount Assumption:**
100
+ - Files: `src/config.ts` (line 33), multiple commands
101
+ - Why fragile: Assumes if path exists, drive is mounted. On filesystems with autounmount, path could exist but be stale mount point.
102
+ - Safe modification: Check if path is actually accessible (try to read), not just exists
103
+ - Test coverage: No tests present.
104
+
105
+ ## Scaling Limits
106
+
107
+ **Bare Repository Storage:**
108
+ - Current capacity: Works fine for ~1000s of projects on typical external drive
109
+ - Limit: No size limits enforced. Bare repos can grow large; no compression or GC recommended to users
110
+ - Scaling path: Document repository GC recommendations. Add `git drive gc` command to run `git gc --aggressive` on all bare repos.
111
+
112
+ **Synchronous I/O Operations:**
113
+ - Current capacity: All operations block. On drive with 1000+ projects, list/status commands visibly slow
114
+ - Limit: ~100ms per large operation on typical USB drive, scales linearly with project count
115
+ - Scaling path: Switch to async operations for I/O-heavy commands. Parallelize directory operations.
116
+
117
+ ## Dependencies at Risk
118
+
119
+ **No Production Dependencies:**
120
+ - Risk: Codebase has only dev dependencies (TypeScript, @types/node). Good security posture but limits future extensibility.
121
+ - Impact: Any new feature requiring external library (e.g., progress bars, colors) requires new dep
122
+ - Migration plan: Carefully evaluate any production dependency for security and maintenance status
123
+
124
+ **execSync from child_process:**
125
+ - Risk: Node's `execSync` doesn't have a maxBuffer safeguard - large git command output (massive commit messages, etc.) could hang or crash process
126
+ - Impact: User loses ability to abort hanging process gracefully
127
+ - Migration plan: Switch to spawn() with streaming output, or add timeout parameter to execSync
128
+
129
+ ## Missing Critical Features
130
+
131
+ **No Progress Indication:**
132
+ - Problem: Large git push operations give no feedback. User doesn't know if hung or still running.
133
+ - Blocks: Difficult to debug stalled operations
134
+
135
+ **No Test Suite:**
136
+ - Problem: Zero test coverage. No unit, integration, or e2e tests.
137
+ - Blocks: Refactoring, verification of security fixes, confidence in changes
138
+
139
+ **No Dry Run Mode:**
140
+ - Problem: Destructive operations (archive, push to wrong remote) have no preview
141
+ - Blocks: Users cannot safely test commands
142
+
143
+ **No Concurrency Control:**
144
+ - Problem: Multiple processes can push/archive simultaneously, causing corruption
145
+ - Blocks: Safe concurrent usage
146
+
147
+ **No Recovery from Partial Operations:**
148
+ - Problem: If push succeeds but archive deletion fails, no way to resume or rollback
149
+ - Blocks: Reliable archive operations
150
+
151
+ ## Test Coverage Gaps
152
+
153
+ **Archive Command - No Tests:**
154
+ - What's not tested: Successful archive flow, archive with uncommitted changes detection, archive with --force flag, rmSync error scenarios, edge case where push succeeds but rm fails
155
+ - Files: `src/commands/archive.ts`
156
+ - Risk: Most destructive operation has zero test coverage. Easy to introduce regressions.
157
+ - Priority: High
158
+
159
+ **Push Command - No Tests:**
160
+ - What's not tested: Creating bare repo, adding new remote, updating existing remote, concurrent pushes, large repository push
161
+ - Files: `src/commands/push.ts`
162
+ - Risk: Core functionality untested. Remote state bugs undetected.
163
+ - Priority: High
164
+
165
+ **Restore Command - No Tests:**
166
+ - What's not tested: Successful restore, nonexistent project error, directory exists error, clone failure scenarios
167
+ - Files: `src/commands/restore.ts`
168
+ - Risk: Data recovery untested. Silent failures possible.
169
+ - Priority: High
170
+
171
+ **Config System - No Tests:**
172
+ - What's not tested: Config loading/saving, corrupted JSON recovery, missing config, permission errors, drive mount detection
173
+ - Files: `src/config.ts`
174
+ - Risk: Configuration system untested. State corruption undetected.
175
+ - Priority: High
176
+
177
+ **Error Handling - No Tests:**
178
+ - What's not tested: GitDriveError formatting, execSync error parsing, unknown error handling, edge case error messages
179
+ - Files: `src/errors.ts`
180
+ - Risk: Error messages could be unhelpful or expose sensitive info, untested.
181
+ - Priority: Medium
182
+
183
+ **Index/CLI - No Tests:**
184
+ - What's not tested: Command routing, unknown command handling, help text, missing command handler errors
185
+ - Files: `src/index.ts`
186
+ - Risk: CLI argument parsing untested. Invalid input handling unverified.
187
+ - Priority: Medium
188
+
189
+ ---
190
+
191
+ *Concerns audit: 2026-01-22*
@@ -0,0 +1,169 @@
1
+ # Coding Conventions
2
+
3
+ **Analysis Date:** 2026-01-22
4
+
5
+ ## Naming Patterns
6
+
7
+ **Files:**
8
+ - Kebab-case for command files: `init.ts`, `push.ts`, `archive.ts`, `restore.ts`, `list.ts`, `status.ts`
9
+ - Lowercase for utility modules: `config.ts`, `errors.ts`, `git.ts`, `index.ts`
10
+ - Commands are organized in `src/commands/` directory
11
+ - Extension: `.ts` for all TypeScript files
12
+
13
+ **Functions:**
14
+ - camelCase for all function names: `init()`, `push()`, `archive()`, `restore()`, `list()`, `status()`
15
+ - Command functions export with pattern: `export function <commandName>(args: string[]): void`
16
+ - Utility functions use camelCase: `loadConfig()`, `saveConfig()`, `getRepoRoot()`, `getProjectName()`, `assertDriveMounted()`
17
+ - Prefix conventions: `is*` for boolean checks (`isGitRepo()`)
18
+ - Prefix conventions: `get*` for retrieval functions (`getRepoRoot()`, `getProjectName()`, `getRemoteUrl()`)
19
+ - Prefix conventions: `require*` for mandatory getters with error throwing (`requireConfig()`)
20
+ - Prefix conventions: `assert*` for validation functions that throw on failure (`assertDriveMounted()`)
21
+
22
+ **Variables:**
23
+ - camelCase for all variables and parameters: `rawPath`, `drivePath`, `repoRoot`, `projectName`, `storePath`, `bareRepoPath`
24
+ - Constants: UPPER_SNAKE_CASE for configuration paths: `CONFIG_DIR`, `CONFIG_FILE`
25
+ - Private/internal prefixes: None used; all module-level constants are uppercase
26
+
27
+ **Types:**
28
+ - PascalCase for interfaces: `Config`
29
+ - Record types for object lookups: `Record<string, (args: string[]) => void>` for command handlers
30
+ - Error classes: PascalCase: `GitDriveError`
31
+
32
+ ## Code Style
33
+
34
+ **Formatting:**
35
+ - Target: ES2022
36
+ - Module system: Node16 with `.js` extensions in imports
37
+ - Strict TypeScript enabled with `strict: true`
38
+ - 2-space indentation (inferred from package and compiled output)
39
+ - Semicolons used consistently at statement ends
40
+
41
+ **Linting:**
42
+ - No formal linting configuration detected (.eslintrc not present)
43
+ - No Prettier configuration detected (.prettierrc not present)
44
+ - TypeScript compiler with strict mode enforces type safety
45
+
46
+ **Type Safety:**
47
+ - All function parameters explicitly typed: `args: string[]`, `cwd?: string`, `remoteName: string`
48
+ - Return types explicitly declared: `void`, `string`, `Config`, `boolean`, `Config | null`
49
+ - Optional parameters marked: `cwd?: string`, `targetDir = args[1] || projectName`
50
+ - Union types used for nullable returns: `string | null`
51
+
52
+ ## Import Organization
53
+
54
+ **Order:**
55
+ 1. Node.js built-in modules (`fs`, `path`, `os`, `child_process`)
56
+ 2. Relative imports from project modules (`./config.js`, `./errors.js`, `./commands/...`)
57
+ 3. No third-party dependencies imported
58
+
59
+ **Path Aliases:**
60
+ - No path aliases configured; all imports use relative paths
61
+ - Imports include `.js` extension: `import { handleError } from "./errors.js"`
62
+ - Example: `import { init } from "./commands/init.js"`
63
+
64
+ **Export Pattern:**
65
+ - Named exports used consistently: `export function`, `export class`, `export interface`
66
+ - No default exports
67
+ - Single responsibility per file maintained
68
+
69
+ ## Error Handling
70
+
71
+ **Patterns:**
72
+ - Custom error class `GitDriveError` extends native `Error` with consistent naming
73
+ - Error instantiation: `throw new GitDriveError("message")`
74
+ - Error handling at top level in `src/index.ts` try-catch block
75
+ - Type-safe error checking: `if (err instanceof GitDriveError)`, `if (err instanceof Error)`
76
+ - Fallback for unknown errors: `else { console.error("An unexpected error occurred.") }`
77
+ - stderr extraction from `execSync` errors: regex match on error message
78
+ - Examples from `src/errors.ts`:
79
+ ```typescript
80
+ export function handleError(err: unknown): void {
81
+ if (err instanceof GitDriveError) {
82
+ console.error(`error: ${err.message}`);
83
+ } else if (err instanceof Error) {
84
+ const msg = err.message;
85
+ const stderrMatch = msg.match(/stderr:\s*([\s\S]*)/);
86
+ if (stderrMatch) {
87
+ console.error(`error: ${stderrMatch[1].trim()}`);
88
+ } else {
89
+ console.error(`error: ${msg}`);
90
+ }
91
+ } else {
92
+ console.error("An unexpected error occurred.");
93
+ }
94
+ }
95
+ ```
96
+
97
+ ## Logging
98
+
99
+ **Framework:** console (built-in)
100
+
101
+ **Patterns:**
102
+ - `console.log()` for normal output: user messages, status updates
103
+ - `console.error()` for error output: error handling
104
+ - Consistent prefix: `error: ` for error messages
105
+ - Informational output with context: `console.log(\`Drive: ${config.drivePath} (connected)\`)`
106
+ - String interpolation used for variables: `` `Drive configured: ${storePath}` ``
107
+ - Status updates: `console.log(\`Pushed ${projectName} to drive.\`)`
108
+ - Diagnostic output: `console.log(\`Created bare repo: ${bareRepoPath}\`)`
109
+
110
+ ## Comments
111
+
112
+ **When to Comment:**
113
+ - Used for explaining non-obvious logic or git operations
114
+ - Precedes multi-step operations to clarify intent
115
+ - Examples from codebase:
116
+ - `// Create bare repo if it doesn't exist`
117
+ - `// Add or update remote`
118
+ - `// Push all branches and tags`
119
+ - `// Check for uncommitted changes`
120
+ - `// Push first`
121
+ - `// Remove local copy`
122
+ - `// execSync errors include stderr in the message`
123
+ - `// Rename origin to drive so the remote stays consistent`
124
+
125
+ **JSDoc/TSDoc:**
126
+ - Not used; minimal documentation approach
127
+ - Function purposes clear from names and context
128
+
129
+ ## Function Design
130
+
131
+ **Size:**
132
+ - Typically 5-40 lines per function
133
+ - Largest file is `src/index.ts` at 51 lines (entry point with usage function)
134
+ - Command implementations: 30-40 lines each
135
+ - Utility functions: 2-10 lines each
136
+
137
+ **Parameters:**
138
+ - Prefer explicit parameters over implicit state: `function git(args: string, cwd?: string)`
139
+ - Command functions always accept `args: string[]` array from CLI arguments
140
+ - Optional parameters use defaults: `const targetDir = args[1] || projectName`
141
+
142
+ **Return Values:**
143
+ - Command handlers return `void` and communicate via console.log/error
144
+ - Utility functions return specific types: `string`, `boolean`, `Config`
145
+ - Nullable returns use union types: `string | null`
146
+ - No implicit undefined returns used
147
+
148
+ ## Module Design
149
+
150
+ **Exports:**
151
+ - Single export per command file: one `export function <command>`
152
+ - Multiple exports in utility modules: `export function loadConfig()`, `export function saveConfig()`, etc.
153
+ - Interface exports for type sharing: `export interface Config`
154
+ - Error class export: `export class GitDriveError`
155
+
156
+ **Barrel Files:**
157
+ - Not used; imports reference specific files directly
158
+ - Example: `import { init } from "./commands/init.js"` not `import { init } from "./commands/"`
159
+
160
+ **Module Responsibilities:**
161
+ - `src/config.ts`: Configuration file I/O and drive path utilities
162
+ - `src/git.ts`: Git command execution and git repo inspection
163
+ - `src/errors.ts`: Error class definition and centralized error handling
164
+ - `src/commands/*.ts`: Individual command implementations
165
+ - `src/index.ts`: CLI entry point and command router
166
+
167
+ ---
168
+
169
+ *Convention analysis: 2026-01-22*
@@ -0,0 +1,94 @@
1
+ # External Integrations
2
+
3
+ **Analysis Date:** 2026-01-22
4
+
5
+ ## APIs & External Services
6
+
7
+ **None Detected**
8
+
9
+ No third-party APIs or external services are used in this codebase.
10
+
11
+ ## Data Storage
12
+
13
+ **Databases:**
14
+ - Not used - No database integration
15
+
16
+ **File Storage:**
17
+ - Local filesystem only
18
+ - Configuration: `~/.config/git-drive/config.json` (user home directory)
19
+ - Git repositories: External USB drive or mounted filesystem
20
+ - Client: Built-in Node.js `fs` module (promises-based)
21
+
22
+ **Caching:**
23
+ - Not used
24
+
25
+ ## Authentication & Identity
26
+
27
+ **Auth Provider:**
28
+ - Custom - No authentication provider integrated
29
+ - Approach: File-based configuration with implicit trust of drive mount
30
+
31
+ ## Monitoring & Observability
32
+
33
+ **Error Tracking:**
34
+ - Not used
35
+
36
+ **Logs:**
37
+ - Console output only
38
+ - Error handling: `console.error()` for errors, `console.log()` for standard output
39
+ - No persistent logging
40
+
41
+ ## CI/CD & Deployment
42
+
43
+ **Hosting:**
44
+ - npm registry only (published as package)
45
+ - Local development installation
46
+
47
+ **CI Pipeline:**
48
+ - Not configured - No CI configuration detected
49
+
50
+ ## Environment Configuration
51
+
52
+ **Required Configuration:**
53
+ - External drive path (configured once via `git drive init <path>`)
54
+ - No environment variables used
55
+ - No `.env` files required
56
+
57
+ **Configuration Storage:**
58
+ - User configuration: `~/.config/git-drive/config.json`
59
+ - Format: JSON
60
+ - Structure:
61
+ ```json
62
+ {
63
+ "drivePath": "/Volumes/ExternalDrive"
64
+ }
65
+ ```
66
+
67
+ ## System Integration
68
+
69
+ **Git Integration:**
70
+ - Uses `git` command-line tool (via `execSync`)
71
+ - Communicates with Git CLI for repository operations:
72
+ - `git rev-parse` - Get repository root
73
+ - `git init --bare` - Create bare repositories
74
+ - `git remote` - Manage git remotes
75
+ - `git push` - Push commits to bare repository
76
+ - `git clone` - Clone from bare repository
77
+
78
+ **File System Integration:**
79
+ - Direct file system access for:
80
+ - Drive detection and mounting verification
81
+ - Repository storage organization
82
+ - Project metadata (modification times)
83
+
84
+ ## Webhooks & Callbacks
85
+
86
+ **Incoming:**
87
+ - None
88
+
89
+ **Outgoing:**
90
+ - None
91
+
92
+ ---
93
+
94
+ *Integration audit: 2026-01-22*