@manthank/mgit 1.0.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.
@@ -0,0 +1,585 @@
1
+ // The heart of mgit: a data-driven catalog of every git action, grouped into
2
+ // friendly categories. Each action carries a beginner explanation, the git args
3
+ // to run (optionally built from prompted inputs), and safety flags.
4
+ //
5
+ // Action shape:
6
+ // id, label, hint (plain-English what/why),
7
+ // inputs: [{name, label, placeholder, optional, default}] (optional)
8
+ // build: (values) => string[] -> git arguments
9
+ // danger: boolean -> ask for confirmation
10
+ // view: 'status' | 'branches' | 'log' | 'config' | 'contrib' (special screens)
11
+ // needsRepo: boolean (default true)
12
+
13
+ const t = (str, values) => str.replace(/\{(\w+)\}/g, (_, k) => values[k] ?? '');
14
+ export const categories = [{
15
+ id: 'start',
16
+ label: 'Get Started',
17
+ emoji: 'πŸš€',
18
+ blurb: 'Set up git and create or clone a repository.',
19
+ actions: [{
20
+ id: 'wizard-identity',
21
+ label: 'Setup wizard β€” name, email & default branch',
22
+ hint: 'Runs once per machine. Tells git who you are so your commits are signed with your name, and sets "main" as the default branch.',
23
+ view: 'setup',
24
+ needsRepo: false
25
+ }, {
26
+ id: 'config-list',
27
+ label: 'View my git config',
28
+ hint: 'Lists every setting git currently uses (name, email, editor, aliases…).',
29
+ view: 'config',
30
+ needsRepo: false
31
+ }, {
32
+ id: 'init',
33
+ label: 'Initialize a repo here (git init)',
34
+ hint: 'Turns the current folder into a git repository so you can start tracking changes.',
35
+ build: () => ['init'],
36
+ needsRepo: false
37
+ }, {
38
+ id: 'clone',
39
+ label: 'Clone an existing repo (git clone)',
40
+ hint: 'Downloads a full copy of a remote repository to your machine.',
41
+ inputs: [{
42
+ name: 'url',
43
+ label: 'Repository URL',
44
+ placeholder: 'https://github.com/user/repo.git'
45
+ }, {
46
+ name: 'folder',
47
+ label: 'Folder name (optional)',
48
+ placeholder: 'leave blank for default',
49
+ optional: true
50
+ }],
51
+ build: v => v.folder ? ['clone', v.url, v.folder] : ['clone', v.url],
52
+ needsRepo: false
53
+ }]
54
+ }, {
55
+ id: 'inspect',
56
+ label: 'See What Changed',
57
+ emoji: 'πŸ”Ž',
58
+ blurb: 'Status, differences and history at a glance.',
59
+ actions: [{
60
+ id: 'status',
61
+ label: 'Status dashboard',
62
+ hint: 'A colour-coded view of modified, new, deleted and staged files.',
63
+ view: 'status'
64
+ }, {
65
+ id: 'diff',
66
+ label: 'Show unstaged changes (git diff)',
67
+ hint: 'Line-by-line changes you have NOT staged yet.',
68
+ build: () => ['--no-pager', 'diff']
69
+ }, {
70
+ id: 'diff-staged',
71
+ label: 'Show staged changes (git diff --staged)',
72
+ hint: 'The changes that WILL go into your next commit.',
73
+ build: () => ['--no-pager', 'diff', '--staged']
74
+ }, {
75
+ id: 'diff-names',
76
+ label: 'List changed file names',
77
+ hint: 'Just the filenames that changed β€” no diff detail.',
78
+ build: () => ['--no-pager', 'diff', '--name-only']
79
+ }, {
80
+ id: 'show',
81
+ label: 'Show a commit (git show)',
82
+ hint: 'Full details and diff of a single commit. Leave blank for the latest.',
83
+ inputs: [{
84
+ name: 'ref',
85
+ label: 'Commit id',
86
+ placeholder: 'blank = HEAD',
87
+ optional: true
88
+ }],
89
+ build: v => v.ref ? ['--no-pager', 'show', v.ref] : ['--no-pager', 'show']
90
+ }, {
91
+ id: 'blame',
92
+ label: 'Blame β€” who changed each line',
93
+ hint: 'Shows the author and commit responsible for every line of a file.',
94
+ inputs: [{
95
+ name: 'file',
96
+ label: 'File path',
97
+ placeholder: 'src/app.js'
98
+ }],
99
+ build: v => ['--no-pager', 'blame', v.file]
100
+ }, {
101
+ id: 'grep',
102
+ label: 'Search code (git grep)',
103
+ hint: 'Fast search for text across all tracked files.',
104
+ inputs: [{
105
+ name: 'q',
106
+ label: 'Search text',
107
+ placeholder: 'functionName'
108
+ }],
109
+ build: v => ['--no-pager', 'grep', '-n', v.q]
110
+ }]
111
+ }, {
112
+ id: 'history',
113
+ label: 'History & Graph',
114
+ emoji: 'πŸ“ˆ',
115
+ blurb: 'Visualize commits and branches as a chart.',
116
+ actions: [{
117
+ id: 'log-graph',
118
+ label: 'Commit graph (visual chart)',
119
+ hint: 'An animated ASCII graph of commits across all branches.',
120
+ view: 'log'
121
+ }, {
122
+ id: 'contrib',
123
+ label: 'Contributions chart (git shortlog)',
124
+ hint: 'A bar chart of commits per author.',
125
+ view: 'contrib'
126
+ }, {
127
+ id: 'log-oneline',
128
+ label: 'Compact history (git log --oneline)',
129
+ hint: 'One line per commit β€” quick to scan.',
130
+ build: () => ['--no-pager', 'log', '--oneline', '-30']
131
+ }, {
132
+ id: 'reflog',
133
+ label: 'Reflog β€” where HEAD has been',
134
+ hint: 'A safety net: every place HEAD pointed, even after resets. Great for recovering "lost" commits.',
135
+ build: () => ['--no-pager', 'reflog', '-30']
136
+ }, {
137
+ id: 'shortlog',
138
+ label: 'Shortlog summary',
139
+ hint: 'Commits grouped by author.',
140
+ build: () => ['--no-pager', 'shortlog', '-sn', '--all']
141
+ }]
142
+ }, {
143
+ id: 'stage',
144
+ label: 'Stage & Commit',
145
+ emoji: 'πŸ“¦',
146
+ blurb: 'Add files to the staging area and record commits.',
147
+ actions: [{
148
+ id: 'add-all',
149
+ label: 'Stage everything (git add .)',
150
+ hint: 'Stages all new and changed files, ready to commit.',
151
+ build: () => ['add', '.']
152
+ }, {
153
+ id: 'add-file',
154
+ label: 'Stage specific file(s)',
155
+ hint: 'Stage only the files you name (space-separated).',
156
+ inputs: [{
157
+ name: 'files',
158
+ label: 'File(s)',
159
+ placeholder: 'file1.txt file2.txt'
160
+ }],
161
+ build: v => ['add', ...v.files.split(/\s+/).filter(Boolean)]
162
+ }, {
163
+ id: 'add-tracked',
164
+ label: 'Stage tracked changes only (git add -u)',
165
+ hint: 'Stages modifications & deletions of already-tracked files, ignoring brand-new files.',
166
+ build: () => ['add', '-u']
167
+ }, {
168
+ id: 'commit',
169
+ label: 'Commit staged changes',
170
+ hint: 'Saves a snapshot of your staged files with a message.',
171
+ inputs: [{
172
+ name: 'msg',
173
+ label: 'Commit message',
174
+ placeholder: 'Add login screen'
175
+ }],
176
+ build: v => ['commit', '-m', v.msg]
177
+ }, {
178
+ id: 'commit-am',
179
+ label: 'Stage tracked + commit (git commit -am)',
180
+ hint: 'Shortcut: stages tracked changes and commits in one step.',
181
+ inputs: [{
182
+ name: 'msg',
183
+ label: 'Commit message',
184
+ placeholder: 'Fixed bug'
185
+ }],
186
+ build: v => ['commit', '-am', v.msg]
187
+ }]
188
+ }, {
189
+ id: 'branch',
190
+ label: 'Branches',
191
+ emoji: '🌿',
192
+ blurb: 'Create, switch, merge and delete branches.',
193
+ actions: [{
194
+ id: 'branch-view',
195
+ label: 'Branch map (visual)',
196
+ hint: 'See all branches, which one you are on, and their latest commit.',
197
+ view: 'branches'
198
+ }, {
199
+ id: 'current-branch',
200
+ label: 'Show current branch',
201
+ hint: 'Prints the branch you are currently on.',
202
+ build: () => ['branch', '--show-current']
203
+ }, {
204
+ id: 'switch-create',
205
+ label: 'Create & switch to a new branch',
206
+ hint: 'Makes a new branch and moves you onto it (git switch -c).',
207
+ inputs: [{
208
+ name: 'name',
209
+ label: 'New branch name',
210
+ placeholder: 'feature/login'
211
+ }],
212
+ build: v => ['switch', '-c', v.name]
213
+ }, {
214
+ id: 'switch',
215
+ label: 'Switch to an existing branch',
216
+ hint: 'Moves you onto another branch (git switch).',
217
+ inputs: [{
218
+ name: 'name',
219
+ label: 'Branch name',
220
+ placeholder: 'main'
221
+ }],
222
+ build: v => ['switch', v.name]
223
+ }, {
224
+ id: 'branch-create',
225
+ label: 'Create branch (no switch)',
226
+ hint: 'Creates a branch but keeps you where you are.',
227
+ inputs: [{
228
+ name: 'name',
229
+ label: 'Branch name',
230
+ placeholder: 'feature'
231
+ }],
232
+ build: v => ['branch', v.name]
233
+ }, {
234
+ id: 'merge',
235
+ label: 'Merge a branch into current',
236
+ hint: 'Brings another branch\'s commits into the branch you are on.',
237
+ inputs: [{
238
+ name: 'name',
239
+ label: 'Branch to merge in',
240
+ placeholder: 'feature'
241
+ }],
242
+ build: v => ['merge', v.name]
243
+ }, {
244
+ id: 'branch-delete',
245
+ label: 'Delete a branch (safe)',
246
+ hint: 'Deletes a branch that is already merged (git branch -d).',
247
+ inputs: [{
248
+ name: 'name',
249
+ label: 'Branch name',
250
+ placeholder: 'feature'
251
+ }],
252
+ build: v => ['branch', '-d', v.name]
253
+ }, {
254
+ id: 'branch-delete-force',
255
+ label: 'Force-delete a branch',
256
+ hint: 'Deletes a branch even if not merged. You may lose commits!',
257
+ inputs: [{
258
+ name: 'name',
259
+ label: 'Branch name',
260
+ placeholder: 'feature'
261
+ }],
262
+ build: v => ['branch', '-D', v.name],
263
+ danger: true
264
+ }]
265
+ }, {
266
+ id: 'remote',
267
+ label: 'Remotes, Push & Pull',
268
+ emoji: 'πŸ›°οΈ',
269
+ blurb: 'Connect to GitHub and sync your work.',
270
+ actions: [{
271
+ id: 'remote-v',
272
+ label: 'View remotes (git remote -v)',
273
+ hint: 'Lists the remote repositories (like GitHub) this repo is linked to.',
274
+ build: () => ['remote', '-v']
275
+ }, {
276
+ id: 'remote-add',
277
+ label: 'Add a remote (origin)',
278
+ hint: 'Links your local repo to a GitHub URL named "origin".',
279
+ inputs: [{
280
+ name: 'url',
281
+ label: 'Remote URL',
282
+ placeholder: 'https://github.com/user/repo.git'
283
+ }],
284
+ build: v => ['remote', 'add', 'origin', v.url]
285
+ }, {
286
+ id: 'remote-seturl',
287
+ label: 'Change remote URL',
288
+ hint: 'Points "origin" at a different URL.',
289
+ inputs: [{
290
+ name: 'url',
291
+ label: 'New URL',
292
+ placeholder: 'https://github.com/user/repo.git'
293
+ }],
294
+ build: v => ['remote', 'set-url', 'origin', v.url]
295
+ }, {
296
+ id: 'remote-remove',
297
+ label: 'Remove remote origin',
298
+ hint: 'Unlinks the "origin" remote.',
299
+ build: () => ['remote', 'remove', 'origin'],
300
+ danger: true
301
+ }, {
302
+ id: 'push-first',
303
+ label: 'First push (git push -u origin <branch>)',
304
+ hint: 'Publishes your branch to GitHub and remembers it for future pushes.',
305
+ inputs: [{
306
+ name: 'branch',
307
+ label: 'Branch',
308
+ placeholder: 'main',
309
+ default: 'main'
310
+ }],
311
+ build: v => ['push', '-u', 'origin', v.branch || 'main']
312
+ }, {
313
+ id: 'push',
314
+ label: 'Push (git push)',
315
+ hint: 'Uploads your commits to the already-linked remote branch.',
316
+ build: () => ['push']
317
+ }, {
318
+ id: 'pull',
319
+ label: 'Pull (git pull)',
320
+ hint: 'Downloads and merges the latest changes from the remote.',
321
+ build: () => ['pull']
322
+ }, {
323
+ id: 'fetch',
324
+ label: 'Fetch (git fetch)',
325
+ hint: 'Downloads remote changes WITHOUT merging β€” safe to inspect first.',
326
+ build: () => ['fetch', '--all']
327
+ }, {
328
+ id: 'push-force',
329
+ label: 'Force push (overwrite remote)',
330
+ hint: 'Overwrites the remote branch with yours. Can destroy others\' work β€” use with care!',
331
+ inputs: [{
332
+ name: 'branch',
333
+ label: 'Branch',
334
+ placeholder: 'main',
335
+ default: 'main'
336
+ }],
337
+ build: v => ['push', 'origin', v.branch || 'main', '--force'],
338
+ danger: true
339
+ }]
340
+ }, {
341
+ id: 'undo',
342
+ label: 'Undo & Recover',
343
+ emoji: 'βͺ',
344
+ blurb: 'Restore files, reset, revert and clean.',
345
+ actions: [{
346
+ id: 'restore-file',
347
+ label: 'Discard changes in a file',
348
+ hint: 'Throws away unstaged edits in a file, restoring the last committed version.',
349
+ inputs: [{
350
+ name: 'file',
351
+ label: 'File path',
352
+ placeholder: 'file.txt'
353
+ }],
354
+ build: v => ['restore', v.file],
355
+ danger: true
356
+ }, {
357
+ id: 'restore-all',
358
+ label: 'Discard ALL unstaged changes',
359
+ hint: 'Reverts every unstaged change back to the last commit.',
360
+ build: () => ['restore', '.'],
361
+ danger: true
362
+ }, {
363
+ id: 'unstage',
364
+ label: 'Unstage a file (git restore --staged)',
365
+ hint: 'Removes a file from the staging area but keeps your edits.',
366
+ inputs: [{
367
+ name: 'file',
368
+ label: 'File path',
369
+ placeholder: 'file.txt'
370
+ }],
371
+ build: v => ['restore', '--staged', v.file]
372
+ }, {
373
+ id: 'reset',
374
+ label: 'Unstage everything (git reset)',
375
+ hint: 'Clears the staging area; your file contents are untouched.',
376
+ build: () => ['reset']
377
+ }, {
378
+ id: 'undo-soft',
379
+ label: 'Undo last commit, keep changes staged (--soft)',
380
+ hint: 'Removes the last commit but keeps its changes staged, ready to re-commit.',
381
+ build: () => ['reset', '--soft', 'HEAD~1'],
382
+ danger: true
383
+ }, {
384
+ id: 'undo-mixed',
385
+ label: 'Undo last commit, keep changes unstaged (--mixed)',
386
+ hint: 'Removes the last commit and unstages its changes, but keeps the file edits.',
387
+ build: () => ['reset', '--mixed', 'HEAD~1'],
388
+ danger: true
389
+ }, {
390
+ id: 'undo-hard',
391
+ label: 'Undo last commit, DELETE changes (--hard)',
392
+ hint: 'Removes the last commit AND discards its changes forever. Cannot be undone easily!',
393
+ build: () => ['reset', '--hard', 'HEAD~1'],
394
+ danger: true
395
+ }, {
396
+ id: 'revert',
397
+ label: 'Revert a commit safely (git revert)',
398
+ hint: 'Creates a NEW commit that undoes an old one β€” history stays intact. Safe for shared branches.',
399
+ inputs: [{
400
+ name: 'ref',
401
+ label: 'Commit id',
402
+ placeholder: 'a1b2c3d'
403
+ }],
404
+ build: v => ['revert', '--no-edit', v.ref]
405
+ }, {
406
+ id: 'clean',
407
+ label: 'Delete untracked files (git clean -fd)',
408
+ hint: 'Permanently removes files git isn\'t tracking (e.g. build junk). No undo!',
409
+ build: () => ['clean', '-fd'],
410
+ danger: true
411
+ }]
412
+ }, {
413
+ id: 'stash',
414
+ label: 'Stash',
415
+ emoji: '🧰',
416
+ blurb: 'Shelve work-in-progress temporarily.',
417
+ actions: [{
418
+ id: 'stash-save',
419
+ label: 'Stash current changes',
420
+ hint: 'Tucks away your uncommitted changes so you have a clean slate.',
421
+ build: () => ['stash', 'push']
422
+ }, {
423
+ id: 'stash-list',
424
+ label: 'List stashes',
425
+ hint: 'Shows everything you have stashed away.',
426
+ build: () => ['stash', 'list']
427
+ }, {
428
+ id: 'stash-pop',
429
+ label: 'Restore latest stash (pop)',
430
+ hint: 'Brings back your most recent stash and removes it from the list.',
431
+ build: () => ['stash', 'pop']
432
+ }, {
433
+ id: 'stash-apply',
434
+ label: 'Apply latest stash (keep it)',
435
+ hint: 'Brings back your stash but keeps a copy in the list.',
436
+ build: () => ['stash', 'apply']
437
+ }, {
438
+ id: 'stash-drop',
439
+ label: 'Drop latest stash',
440
+ hint: 'Deletes the most recent stash.',
441
+ build: () => ['stash', 'drop'],
442
+ danger: true
443
+ }, {
444
+ id: 'stash-clear',
445
+ label: 'Clear all stashes',
446
+ hint: 'Deletes every stash. Cannot be undone.',
447
+ build: () => ['stash', 'clear'],
448
+ danger: true
449
+ }]
450
+ }, {
451
+ id: 'files',
452
+ label: 'Files & Tags',
453
+ emoji: '🏷️',
454
+ blurb: 'Move, remove, ignore files and manage tags.',
455
+ actions: [{
456
+ id: 'rm',
457
+ label: 'Remove a file (git rm)',
458
+ hint: 'Deletes a file and stages the deletion.',
459
+ inputs: [{
460
+ name: 'file',
461
+ label: 'File path',
462
+ placeholder: 'file.txt'
463
+ }],
464
+ build: v => ['rm', v.file],
465
+ danger: true
466
+ }, {
467
+ id: 'rm-dir',
468
+ label: 'Remove a folder (git rm -r)',
469
+ hint: 'Deletes a folder and its contents, staging the deletion.',
470
+ inputs: [{
471
+ name: 'dir',
472
+ label: 'Folder path',
473
+ placeholder: 'oldfolder'
474
+ }],
475
+ build: v => ['rm', '-r', v.dir],
476
+ danger: true
477
+ }, {
478
+ id: 'mv',
479
+ label: 'Rename / move a file (git mv)',
480
+ hint: 'Renames or moves a file while keeping its history.',
481
+ inputs: [{
482
+ name: 'from',
483
+ label: 'From',
484
+ placeholder: 'old.txt'
485
+ }, {
486
+ name: 'to',
487
+ label: 'To',
488
+ placeholder: 'new.txt'
489
+ }],
490
+ build: v => ['mv', v.from, v.to]
491
+ }, {
492
+ id: 'gitignore',
493
+ label: 'Create a starter .gitignore',
494
+ hint: 'Writes a sensible .gitignore (node_modules, dist, .env…) so junk stays out of git.',
495
+ view: 'gitignore'
496
+ }, {
497
+ id: 'ls-files',
498
+ label: 'List tracked files (git ls-files)',
499
+ hint: 'Every file git is currently tracking.',
500
+ build: () => ['ls-files']
501
+ }, {
502
+ id: 'tag-list',
503
+ label: 'List tags',
504
+ hint: 'Shows all version tags (like v1.0).',
505
+ build: () => ['tag']
506
+ }, {
507
+ id: 'tag-create',
508
+ label: 'Create a tag',
509
+ hint: 'Marks a point in history, usually a release version.',
510
+ inputs: [{
511
+ name: 'name',
512
+ label: 'Tag name',
513
+ placeholder: 'v1.0'
514
+ }],
515
+ build: v => ['tag', v.name]
516
+ }, {
517
+ id: 'tag-push',
518
+ label: 'Push a tag to remote',
519
+ hint: 'Uploads a tag to GitHub so it appears in releases.',
520
+ inputs: [{
521
+ name: 'name',
522
+ label: 'Tag name',
523
+ placeholder: 'v1.0'
524
+ }],
525
+ build: v => ['push', 'origin', v.name]
526
+ }]
527
+ }, {
528
+ id: 'advanced',
529
+ label: 'Advanced',
530
+ emoji: 'πŸ§ͺ',
531
+ blurb: 'Cherry-pick, rebase and rewrite history.',
532
+ actions: [{
533
+ id: 'cherry-pick',
534
+ label: 'Cherry-pick a commit',
535
+ hint: 'Copies one commit from another branch onto your current branch.',
536
+ inputs: [{
537
+ name: 'ref',
538
+ label: 'Commit id',
539
+ placeholder: 'a1b2c3d'
540
+ }],
541
+ build: v => ['cherry-pick', v.ref]
542
+ }, {
543
+ id: 'rebase',
544
+ label: 'Rebase onto a branch',
545
+ hint: 'Replays your commits on top of another branch for a cleaner, linear history.',
546
+ inputs: [{
547
+ name: 'branch',
548
+ label: 'Base branch',
549
+ placeholder: 'main'
550
+ }],
551
+ build: v => ['rebase', v.branch],
552
+ danger: true
553
+ }, {
554
+ id: 'rev-parse',
555
+ label: 'Show current commit hash (rev-parse HEAD)',
556
+ hint: 'Prints the full SHA of the commit you are on.',
557
+ build: () => ['rev-parse', 'HEAD']
558
+ }]
559
+ }, {
560
+ id: 'recipes',
561
+ label: 'Guided Recipes',
562
+ emoji: '🍳',
563
+ blurb: 'Step-by-step multi-command workflows.',
564
+ actions: [{
565
+ id: 'recipe-github-first',
566
+ label: 'Publish this folder to GitHub (first time)',
567
+ hint: 'init β†’ add β†’ commit β†’ set branch main β†’ add origin β†’ push. A guided end-to-end flow.',
568
+ view: 'recipe',
569
+ recipe: 'github-first',
570
+ needsRepo: false
571
+ }, {
572
+ id: 'recipe-feature',
573
+ label: 'Start a feature branch workflow',
574
+ hint: 'pull β†’ create branch β†’ (you code) β†’ add β†’ commit β†’ push. The everyday team workflow.',
575
+ view: 'recipe',
576
+ recipe: 'feature'
577
+ }, {
578
+ id: 'recipe-sync-main',
579
+ label: 'Sync my main branch',
580
+ hint: 'switch to main β†’ pull origin main. Keeps your main up to date.',
581
+ view: 'recipe',
582
+ recipe: 'sync-main'
583
+ }]
584
+ }];
585
+ export { t };
package/dist/cli.js ADDED
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env node
2
+ // mgit β€” interactive, animated git/GitHub companion for beginners.
3
+ import React from 'react';
4
+ import { render } from 'ink';
5
+ import App from './app.js';
6
+ import { loadConfig } from './config.js';
7
+ import { jsx as _jsx } from "react/jsx-runtime";
8
+ const args = process.argv.slice(2);
9
+ if (args.includes('--version') || args.includes('-v')) {
10
+ console.log('mgit 1.0.0');
11
+ process.exit(0);
12
+ }
13
+ if (args.includes('--help') || args.includes('-h')) {
14
+ console.log(`
15
+ mgit β€” a friendly, animated terminal UI for learning git & GitHub.
16
+
17
+ Usage:
18
+ mgit Launch the interactive app
19
+ mgit --version Print version
20
+ mgit --help Show this message
21
+
22
+ Inside the app:
23
+ ↑ ↓ / Enter Navigate & select
24
+ Esc Go back / quit
25
+ t Cycle theme
26
+ s Settings & themes
27
+ ? Help
28
+ `);
29
+ process.exit(0);
30
+ }
31
+
32
+ // Ink needs a real interactive terminal for keyboard input.
33
+ if (!process.stdout.isTTY) {
34
+ console.error('mgit needs an interactive terminal (TTY). Run it directly in your terminal.');
35
+ process.exit(1);
36
+ }
37
+ const config = loadConfig();
38
+ const {
39
+ waitUntilExit
40
+ } = render(/*#__PURE__*/_jsx(App, {
41
+ initialConfig: config
42
+ }), {
43
+ exitOnCtrlC: true
44
+ });
45
+ waitUntilExit().then(() => {
46
+ // Clear a little space so the shell prompt returns cleanly.
47
+ process.stdout.write('\n');
48
+ });
@@ -0,0 +1,38 @@
1
+ // Persistent hint bar shown at the bottom of every screen.
2
+ import React from 'react';
3
+ import { Box, Text } from 'ink';
4
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
5
+ export default function Footer({
6
+ theme,
7
+ hints,
8
+ repo
9
+ }) {
10
+ return /*#__PURE__*/_jsxs(Box, {
11
+ marginTop: 1,
12
+ justifyContent: "space-between",
13
+ children: [/*#__PURE__*/_jsx(Box, {
14
+ children: hints.map((h, i) => /*#__PURE__*/_jsxs(Text, {
15
+ color: theme.muted,
16
+ children: [/*#__PURE__*/_jsx(Text, {
17
+ color: theme.accent,
18
+ bold: true,
19
+ children: h.key
20
+ }), /*#__PURE__*/_jsxs(Text, {
21
+ children: [" ", h.label, " "]
22
+ })]
23
+ }, i))
24
+ }), /*#__PURE__*/_jsxs(Text, {
25
+ color: theme.muted,
26
+ children: [repo ? /*#__PURE__*/_jsx(Text, {
27
+ color: theme.success,
28
+ children: "\u25CF repo"
29
+ }) : /*#__PURE__*/_jsx(Text, {
30
+ color: theme.warn,
31
+ children: "\u25CB no repo"
32
+ }), /*#__PURE__*/_jsxs(Text, {
33
+ color: theme.muted,
34
+ children: [" ", theme.emoji, " ", theme.label]
35
+ })]
36
+ })]
37
+ });
38
+ }