gitlo 1.0.1 → 1.0.2

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/README.md CHANGED
@@ -34,7 +34,7 @@ GitHub accounts can be deleted, suspended, or compromised. This tool creates a l
34
34
 
35
35
  ## šŸ“¦ Installation
36
36
 
37
- ### Quick Install (npm - Recommended)
37
+ ### Quick Install (npm)
38
38
 
39
39
  ```bash
40
40
  npm install -g gitlo
@@ -61,15 +61,19 @@ yarn global add gitlo
61
61
  # Clone and build
62
62
  git clone https://github.com/dropocol/gitlo.git
63
63
  cd gitlo
64
- pnpm install
65
- pnpm run build
64
+ npm install
65
+ npm run build
66
66
 
67
67
  # Link globally
68
- pnpm link --global
68
+ npm link --global
69
69
  ```
70
70
 
71
71
  ## Getting a GitHub Token
72
72
 
73
+ gitlo supports two types of GitHub personal access tokens:
74
+
75
+ ### Option 1: Classic Token (Recommended)
76
+
73
77
  1. Go to [https://github.com/settings/tokens](https://github.com/settings/tokens)
74
78
  2. Click "Generate new token (classic)"
75
79
  3. Select these scopes:
@@ -77,6 +81,19 @@ pnpm link --global
77
81
  - `read:user` - Read user profile data
78
82
  4. Generate and copy the token
79
83
 
84
+ ### Option 2: Fine-Grained Token
85
+
86
+ 1. Go to [https://github.com/settings/tokens](https://github.com/settings/tokens)
87
+ 2. Click "Generate new token" → "Fine-grained token"
88
+ 3. Configure permissions:
89
+ - **Repository permissions**:
90
+ - Contents: **Read and write** (required for cloning)
91
+ - Metadata: **Read-only** (required for repository access)
92
+ - **Account permissions**:
93
+ - User profile: **Read-only** (optional, for user info)
94
+ 4. Select the repositories to access (or "All repositories")
95
+ 5. Generate and copy the token
96
+
80
97
  ## šŸš€ Quick Start
81
98
 
82
99
  ### 1. Get a GitHub Token
@@ -229,7 +246,7 @@ gitlo config remove output-dir
229
246
  Schedule automatic backups with cron.
230
247
 
231
248
  ```bash
232
- # Weekly on Sunday at 2 AM (default)
249
+ # Weekly on Sunday at 2 AM (default, updates existing repos)
233
250
  gitlo schedule setup
234
251
 
235
252
  # Daily at 3 AM
@@ -241,8 +258,8 @@ gitlo schedule setup --frequency weekly --day 1
241
258
  # Monthly on the 1st at 2 AM
242
259
  gitlo schedule setup --frequency monthly
243
260
 
244
- # Hourly (only updates existing repos)
245
- gitlo schedule setup --frequency hourly --update
261
+ # Full backup (clone all repos, don't just update)
262
+ gitlo schedule setup --full
246
263
  ```
247
264
 
248
265
  #### `gitlo schedule list`
@@ -332,19 +349,19 @@ If you want to contribute or modify the code:
332
349
 
333
350
  ```bash
334
351
  # Install all dependencies (including dev)
335
- pnpm install
352
+ npm install
336
353
 
337
354
  # Build TypeScript to JavaScript
338
- pnpm run build
355
+ npm run build
339
356
 
340
357
  # Run in development mode
341
- pnpm run dev
358
+ npm run dev
342
359
 
343
360
  # Clean build artifacts
344
- pnpm run clean
361
+ npm run clean
345
362
 
346
363
  # Test local changes globally
347
- pnpm link --global
364
+ npm link --global
348
365
  ```
349
366
 
350
367
  ### Publishing
@@ -353,9 +370,6 @@ When you're ready to publish to npm:
353
370
 
354
371
  ```bash
355
372
  # The prepublishOnly script automatically builds before publishing
356
- pnpm publish
357
-
358
- # Or publish to npm
359
373
  npm publish
360
374
  ```
361
375
 
@@ -387,6 +401,7 @@ your-backup-directory/
387
401
 
388
402
  ```bash
389
403
  # Setup weekly backups (default: Sundays at 2 AM)
404
+ # By default, updates existing repos (faster)
390
405
  gitlo schedule setup
391
406
 
392
407
  # Setup daily backups at 3 AM
@@ -395,8 +410,8 @@ gitlo schedule setup --frequency daily --time 03:00
395
410
  # Setup weekly on Mondays at 2 AM
396
411
  gitlo schedule setup --frequency weekly --day 1 --time 02:00
397
412
 
398
- # Only update existing repos (faster)
399
- gitlo schedule setup --update
413
+ # Full backup (clone all repos including new ones)
414
+ gitlo schedule setup --full
400
415
 
401
416
  # View scheduled jobs
402
417
  gitlo schedule list
@@ -410,9 +425,11 @@ gitlo schedule remove
410
425
  - `-f, --frequency <freq>` - hourly, daily, weekly, monthly (default: weekly)
411
426
  - `-t, --time <time>` - Time in HH:MM format (default: 02:00)
412
427
  - `-d, --day <day>` - Day of week 0-6 for weekly (0=Sunday, default: 0)
413
- - `-u, --update` - Only update existing repos, don't clone new ones
428
+ - `--full` - Clone all repos instead of just updating existing (default: update)
414
429
  - `-l, --log <path>` - Log file path (default: ~/.gitlo/backup.log)
415
430
 
431
+ **Note:** By default, scheduled backups update existing repositories for faster execution. Use `--full` to clone all repositories including new ones.
432
+
416
433
  ### Manual Cron Setup (Advanced)
417
434
 
418
435
  If you prefer manual setup:
@@ -434,7 +451,7 @@ npm install -g gitlo && gitlo config set token YOUR_TOKEN && gitlo
434
451
  ### One-liner for Development Setup
435
452
 
436
453
  ```bash
437
- cd ~ && git clone https://github.com/dropocol/gitlo.git && cd gitlo && pnpm install && pnpm run build && pnpm link --global && echo "Setup complete. Run: gitlo config set token YOUR_TOKEN"
454
+ cd ~ && git clone https://github.com/dropocol/gitlo.git && cd gitlo && npm install && npm run build && npm link --global && echo "Setup complete. Run: gitlo config set token YOUR_TOKEN"
438
455
  ```
439
456
 
440
457
  ## Security Notes
package/dist/backup.js CHANGED
@@ -52,10 +52,29 @@ async function cloneOrUpdateRepo(repo, repoPath, options, progress, index, total
52
52
  if (options.updateExisting) {
53
53
  repoSpinner.text = `${progress} Updating ${repo.name}...`;
54
54
  const git = (0, simple_git_1.default)(repoPath);
55
- await git.pull('origin', 'main').catch(async () => {
56
- // Try master if main fails
57
- await git.pull('origin', 'master');
58
- });
55
+ // For private repos with HTTPS, temporarily use authenticated URL
56
+ const originalUrlResult = await git.remote(['get-url', 'origin']);
57
+ const originalUrl = typeof originalUrlResult === 'string'
58
+ ? originalUrlResult.trim().replace(/[\n\r\t]/g, '')
59
+ : '';
60
+ let needsRestore = false;
61
+ if (options.token && options.method === 'https' && originalUrl) {
62
+ const authenticatedUrl = repo.cloneUrl.replace('https://', `https://${options.token}@`);
63
+ await git.remote(['set-url', 'origin', authenticatedUrl.trim()]);
64
+ needsRestore = true;
65
+ }
66
+ try {
67
+ await git.pull('origin', 'main').catch(async () => {
68
+ // Try master if main fails
69
+ await git.pull('origin', 'master');
70
+ });
71
+ }
72
+ finally {
73
+ // Restore original URL without token
74
+ if (needsRestore && originalUrl) {
75
+ await git.remote(['set-url', 'origin', originalUrl]);
76
+ }
77
+ }
59
78
  repoSpinner.succeed(`${progress} ${chalk_1.default.green('āœ“')} Updated ${chalk_1.default.white(repo.name)}`);
60
79
  return { status: 'updated' };
61
80
  }
@@ -66,9 +85,19 @@ async function cloneOrUpdateRepo(repo, repoPath, options, progress, index, total
66
85
  }
67
86
  else {
68
87
  repoSpinner.text = `${progress} Cloning ${repo.name}...`;
69
- const cloneUrl = options.method === 'ssh' ? repo.sshUrl : repo.cloneUrl;
88
+ let cloneUrl = options.method === 'ssh' ? repo.sshUrl : repo.cloneUrl;
89
+ // Inject token into HTTPS URL for private repos
90
+ if (options.token && options.method === 'https') {
91
+ cloneUrl = cloneUrl.replace('https://', `https://${options.token}@`);
92
+ }
70
93
  const parentDir = path.dirname(repoPath);
71
94
  await (0, simple_git_1.default)(parentDir).clone(cloneUrl, repoPath);
95
+ // Remove token from git config after clone for security
96
+ if (options.token && options.method === 'https') {
97
+ const git = (0, simple_git_1.default)(repoPath);
98
+ const cleanUrl = cloneUrl.replace(/https:\/\/[^@]+@/, 'https://').trim();
99
+ await git.remote(['set-url', 'origin', cleanUrl]);
100
+ }
72
101
  repoSpinner.succeed(`${progress} ${chalk_1.default.green('āœ“')} Cloned ${chalk_1.default.white(repo.name)}`);
73
102
  return { status: 'cloned' };
74
103
  }
package/dist/cli.js CHANGED
@@ -285,7 +285,7 @@ function createScheduleCommands(program) {
285
285
  .option('-f, --frequency <freq>', 'Backup frequency: hourly, daily, weekly, monthly', 'weekly')
286
286
  .option('-t, --time <time>', 'Time for daily/weekly/monthly (HH:MM format)', '02:00')
287
287
  .option('-d, --day <day>', 'Day of week for weekly (0-6, 0=Sunday)', '0')
288
- .option('-u, --update', 'Only update existing repos (faster)', false)
288
+ .option('--full', 'Clone all repos instead of updating existing (default: update existing)', false)
289
289
  .option('-l, --log <path>', 'Log file path', '~/.gitlo/backup.log')
290
290
  .action((cmdOptions) => {
291
291
  const { addCronJob, getCronExpression, formatSchedule } = require('./cron.js');
@@ -293,12 +293,12 @@ function createScheduleCommands(program) {
293
293
  frequency: cmdOptions.frequency,
294
294
  time: cmdOptions.time,
295
295
  dayOfWeek: parseInt(cmdOptions.day),
296
- updateOnly: cmdOptions.update,
296
+ updateOnly: !cmdOptions.full,
297
297
  };
298
298
  const logFile = cmdOptions.log.replace(/^~/, require('os').homedir());
299
299
  console.log(chalk_1.default.bold.blue('\nšŸ“… Schedule Automatic Backups\n'));
300
300
  console.log(chalk_1.default.gray(`Frequency: ${formatSchedule(schedule)}`));
301
- console.log(chalk_1.default.gray(`Update only: ${cmdOptions.update ? 'Yes' : 'No (full backup)'}`));
301
+ console.log(chalk_1.default.gray(`Update only: ${!cmdOptions.full ? 'Yes (default)' : 'No (full backup)'}`));
302
302
  console.log(chalk_1.default.gray(`Log file: ${logFile}\n`));
303
303
  if (addCronJob(schedule, logFile)) {
304
304
  console.log(chalk_1.default.green('āœ“ Automatic backup scheduled successfully!'));
package/dist/cron.js CHANGED
@@ -48,7 +48,6 @@ const fs = __importStar(require("fs"));
48
48
  const path = __importStar(require("path"));
49
49
  const os = __importStar(require("os"));
50
50
  const chalk_1 = __importDefault(require("chalk"));
51
- const config_manager_js_1 = require("./config-manager.js");
52
51
  const CRON_COMMENT = '# gitlo-auto-backup';
53
52
  function getCronExpression(schedule) {
54
53
  switch (schedule.frequency) {
@@ -71,9 +70,13 @@ function getCronExpression(schedule) {
71
70
  }
72
71
  }
73
72
  function getCronCommand(updateOnly = false) {
74
- const config = (0, config_manager_js_1.readConfig)();
75
- const gitloPath = (0, child_process_1.execSync)('which gitlo', { encoding: 'utf-8' }).trim() || 'gitlo';
76
- let command = `${gitloPath}`;
73
+ // Use full path to node and the built JS file for cron compatibility
74
+ // Cron has limited PATH, so we can't rely on wrapper scripts
75
+ const nodePath = (0, child_process_1.execSync)('which node', { encoding: 'utf-8' }).trim();
76
+ // Get the path to dist/index.js from the current file location
77
+ // After compilation, this file is at dist/cron.js, so we need index.js in the same dir
78
+ const scriptPath = path.join(path.dirname(__filename), 'index.js');
79
+ let command = `${nodePath} ${scriptPath}`;
77
80
  // Add update flag if specified
78
81
  if (updateOnly) {
79
82
  command += ' --update';
package/dist/index.js CHANGED
@@ -3,11 +3,13 @@
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  const commander_1 = require("commander");
5
5
  const cli_js_1 = require("./cli.js");
6
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
7
+ const packageJson = require('../package.json');
6
8
  const program = new commander_1.Command();
7
9
  program
8
10
  .name('gitlo')
9
11
  .description('CLI tool to backup all your GitHub repositories locally')
10
- .version('1.0.0');
12
+ .version(packageJson.version);
11
13
  // Config subcommands
12
14
  (0, cli_js_1.createConfigCommands)(program);
13
15
  // Schedule subcommands
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitlo",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "CLI tool to backup all your GitHub repositories locally",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -16,7 +16,9 @@
16
16
  "start": "node dist/index.js",
17
17
  "dev": "ts-node src/index.ts",
18
18
  "clean": "rm -rf dist node_modules",
19
- "prepublishOnly": "pnpm run build"
19
+ "prepublishOnly": "pnpm run build",
20
+ "link": "pnpm run build && pnpm link --global",
21
+ "unlink": "pnpm unlink --global && rm -f $(which gitlo 2>/dev/null || echo /dev/null)"
20
22
  },
21
23
  "keywords": [
22
24
  "github",
@@ -34,7 +36,7 @@
34
36
  "bugs": {
35
37
  "url": "https://github.com/dropocol/gitlo/issues"
36
38
  },
37
- "packageManager": "pnpm@9.10.0",
39
+ "packageManager": "pnpm@10.33.0",
38
40
  "engines": {
39
41
  "node": ">=18.0.0"
40
42
  },