gitwrit 0.2.6 → 0.2.8

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
@@ -4,7 +4,7 @@
4
4
 
5
5
  Made for `git`-ters and `writ`-ters.
6
6
 
7
- **gitwrit** watches your Markdown files and quietly commits and pushes them to your Git repository no manual `git add`, no `git commit`, no `git push`. You write. gitwrit handles the rest.
7
+ **gitwrit** watches your Markdown files and quietly commits and pushes them to your Git repository—no manual `git add`, no `git commit`, no `git push`. You write. gitwrit handles the rest.
8
8
 
9
9
  It is built for engineers writing internal specs, researchers building private knowledge bases, AI practitioners documenting models and experiments, and anyone who wants the safety of version control without the overhead of Git discipline. Your files stay in your own repository, on your own terms—not in someone else's cloud.
10
10
 
@@ -99,9 +99,9 @@ Run `gitwrit config` from inside a watched directory to set local overrides. Ove
99
99
 
100
100
  gitwrit supports two branch modes, configurable globally or per directory.
101
101
 
102
- **`current`** — Commits to whatever branch you currently have checked out. Switch branches freely; gitwrit follows you.
102
+ **`current`**—Commits to whatever branch you currently have checked out. Switch branches freely; gitwrit follows you.
103
103
 
104
- **`autogenerated`** — Creates a fresh named branch at the start of each session. Branch names are generated by combining a random adjective, noun, and verb like `crimson-walrus-stumbling` or `teal-fox-bouncing`. 64,000 possible combinations. Good for keeping autosave history separate from your main branch.
104
+ **`autogenerated`**—Creates a fresh named branch at the start of each session. Branch names are generated by combining a random adjective, noun, and verb—like `crimson-walrus-stumbling` or `teal-fox-bouncing`. 64,000 possible combinations. Good for keeping autosave history separate from your main branch.
105
105
 
106
106
  ---
107
107
 
@@ -113,16 +113,51 @@ gitwrit checks for updates automatically after every command. If a newer version
113
113
  · Update available: 0.2.1 → 0.3.0 Run npm install -g gitwrit to update.
114
114
  ```
115
115
 
116
-
117
116
  The check runs in the background, caches for 24 hours, and fails silently if you are offline. It will never interrupt or slow down your workflow.
118
117
 
119
118
  ---
120
119
 
120
+ ## Compatibility
121
+
122
+ | Platform | Status |
123
+ |---|---|
124
+ | macOS | ✅ Fully supported |
125
+ | Linux | ✅ Fully supported |
126
+ | Windows | ❌ Not currently supported |
127
+
128
+ gitwrit is built for macOS and Linux. Windows is not currently supported—the daemon process management and file system watching rely on POSIX signals (`SIGTERM`, `SIGCONT`) that are not available on Windows.
129
+
130
+ If you are a Windows user and would like to contribute Windows support, please open an issue on [GitHub](https://github.com/TBiddy/gitwrit)—it is a welcome contribution.
131
+
132
+ ---
133
+
121
134
  ## Requirements
122
135
 
123
136
  - Node.js ≥ 18
124
137
  - Git
125
- - A configured Git remote (`git remote add origin <url>`) gitwrit requires one before it will initialize a directory
138
+ - A configured Git remote (`git remote add origin <url>`)—gitwrit requires one before it will initialize a directory
139
+
140
+ ---
141
+
142
+ ## Troubleshooting
143
+
144
+ **gitwrit isn't committing my changes**
145
+
146
+ gitwrit watches for file save events. Make sure your editor is actually saving to disk—some terminal editors like Pico and Nano require an explicit save (`Ctrl+X` → `Y`) before changes hit the filesystem. gitwrit cannot commit changes that haven't been written to disk yet.
147
+
148
+ **Push failed notification**
149
+
150
+ If gitwrit notifies you that a push failed, first verify that git can push manually from your terminal:
151
+
152
+ ```sh
153
+ git push
154
+ ```
155
+
156
+ If that works, restart gitwrit with `gitwrit restart`. If it fails, fix your Git authentication first—gitwrit can only push if git itself can push from a non-interactive terminal session. Make sure your SSH key is configured and registered with your Git provider, or that your HTTPS credentials are cached.
157
+
158
+ **Something else feels off**
159
+
160
+ `gitwrit logs` is always your first stop. It shows a timestamped record of every commit, push, and error the daemon has encountered.
126
161
 
127
162
  ---
128
163
 
package/bin/gitwrit.js CHANGED
@@ -1,6 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  import { Command } from 'commander';
4
+ import { createRequire } from 'module';
5
+ import { fileURLToPath } from 'url';
6
+ import { dirname, join } from 'path';
4
7
  import { init } from '../src/commands/init.js';
5
8
  import { start } from '../src/commands/start.js';
6
9
  import { stop } from '../src/commands/stop.js';
@@ -15,12 +18,18 @@ import { checkForUpdate, currentVersion } from '../src/updater.js';
15
18
  import chalk from 'chalk';
16
19
  import { TEAL, PINK } from '../src/ui.js';
17
20
 
21
+ // ── dynamic version from package.json ────────────────────────────────────────
22
+ // never hardcode the version — read it directly from package.json so
23
+ // gitwrit --version always matches the published version automatically.
24
+ const require = createRequire(import.meta.url);
25
+ const PKG = require(join(dirname(fileURLToPath(import.meta.url)), '../package.json'));
26
+
18
27
  const program = new Command();
19
28
 
20
29
  program
21
30
  .name('gitwrit')
22
31
  .description('Private, versioned writing for people who live in the terminal.')
23
- .version('0.2.1')
32
+ .version(PKG.version)
24
33
  .addHelpCommand(false)
25
34
  .helpOption(false);
26
35
 
@@ -76,8 +85,7 @@ if (process.argv.length <= 2) {
76
85
  }
77
86
 
78
87
  // ── run command then check for updates ───────────────────────────────────────
79
- // update check runs after the command completes so it never delays the user.
80
- // shows a single hint line at the bottom if a newer version is available.
88
+ // runs after the command completes never blocks or delays the user.
81
89
  program.parseAsync(process.argv).then(async () => {
82
90
  const latest = await checkForUpdate();
83
91
  if (latest) {
@@ -88,7 +96,7 @@ program.parseAsync(process.argv).then(async () => {
88
96
  chalk.dim(' → ') +
89
97
  chalk.hex(PINK).bold(latest) +
90
98
  chalk.dim(' Run ') +
91
- chalk.white('npm install -g gitwrit') +
99
+ chalk.white('npm install -g gitwrit@latest') +
92
100
  chalk.dim(' to update.')
93
101
  );
94
102
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gitwrit",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "description": "Private, versioned writing for people who live in the terminal.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,9 +1,13 @@
1
1
  import { readFile } from 'fs/promises';
2
- import { print, timeAgo } from '../ui.js';
2
+ import boxen from 'boxen';
3
+ import chalk from 'chalk';
4
+ import { print, timeAgo, TEAL, PINK } from '../ui.js';
3
5
  import { PID_FILE } from '../paths.js';
4
6
  import { readState, STATE } from '../state.js';
5
7
  import { loadGlobalConfig, globalConfigExists } from '../settings.js';
6
8
 
9
+ // ─── helpers ──────────────────────────────────────────────────────────────────
10
+
7
11
  async function getLivePid() {
8
12
  try {
9
13
  const raw = await readFile(PID_FILE, 'utf8');
@@ -23,6 +27,27 @@ function formatUptime(startedAt) {
23
27
  return `${Math.floor(seconds / 3600)}h ${Math.floor((seconds % 3600) / 60)}m`;
24
28
  }
25
29
 
30
+ // left-padded label + white value — used inside the box
31
+ function row(label, value) {
32
+ return chalk.dim(` ${label.padEnd(13)}`) + chalk.white(value);
33
+ }
34
+
35
+ // ─── boxen options ────────────────────────────────────────────────────────────
36
+
37
+ const BOX_OPTS = {
38
+ padding: { top: 0, bottom: 0, left: 1, right: 2 },
39
+ borderStyle: 'round',
40
+ borderColor: TEAL,
41
+ };
42
+
43
+ const BOX_OPTS_PINK = {
44
+ padding: { top: 0, bottom: 0, left: 1, right: 2 },
45
+ borderStyle: 'round',
46
+ borderColor: PINK,
47
+ };
48
+
49
+ // ─── main ─────────────────────────────────────────────────────────────────────
50
+
26
51
  export async function status() {
27
52
  if (!(await globalConfigExists())) {
28
53
  print.gap();
@@ -32,63 +57,82 @@ export async function status() {
32
57
  return;
33
58
  }
34
59
 
35
- const pid = await getLivePid();
36
- const state = await readState();
60
+ const pid = await getLivePid();
61
+ const state = await readState();
37
62
  const config = await loadGlobalConfig();
38
63
 
39
64
  print.gap();
40
65
 
66
+ // ── not running ─────────────────────────────────────────────────────────────
67
+
41
68
  if (!pid) {
42
69
  if (state.status === STATE.PAUSED) {
43
- print.brand('gitwrit is paused.');
44
- print.gap();
45
- print.info(`Resumed from sleep — last active ${timeAgo(state.pausedAt)}.`);
46
- print.gap();
47
- print.hint('Run gitwrit start to resume watching.');
70
+ const lines = [
71
+ '',
72
+ chalk.hex(PINK).bold(' gitwrit is paused.'),
73
+ '',
74
+ chalk.dim(` Last active ${timeAgo(state.pausedAt)}.`),
75
+ chalk.dim(' Run gitwrit start to resume watching.'),
76
+ '',
77
+ ];
78
+ console.log(boxen(lines.join('\n'), BOX_OPTS_PINK));
48
79
  } else {
49
- print.brand('gitwrit is not running.');
50
- print.hint('Run gitwrit start to begin watching.');
80
+ const lines = [
81
+ '',
82
+ chalk.dim(' gitwrit is not running.'),
83
+ '',
84
+ chalk.dim(' Run gitwrit start to begin watching.'),
85
+ '',
86
+ ];
87
+ console.log(boxen(lines.join('\n'), { ...BOX_OPTS, borderColor: 'gray' }));
51
88
  }
52
89
  print.gap();
53
90
  return;
54
91
  }
55
92
 
93
+ // ── running ──────────────────────────────────────────────────────────────────
94
+
56
95
  const resumedAfterSleep = state.resumedAt &&
57
96
  (Date.now() - new Date(state.resumedAt)) < 60000;
58
97
 
98
+ const lines = [''];
99
+
59
100
  if (resumedAfterSleep) {
60
- print.brand('gitwrit is running — resumed after sleep.');
101
+ lines.push(chalk.hex(TEAL).bold(' gitwrit is running') + chalk.dim(' — resumed after sleep.'));
61
102
  } else {
62
- print.brand('gitwrit is running.');
103
+ lines.push(chalk.hex(TEAL).bold(' gitwrit is running.'));
63
104
  }
64
105
 
65
- print.gap();
66
- print.row('Uptime', formatUptime(state.startedAt));
67
- print.row('Watching', config.watch.map(w => w.path).join(', '));
106
+ lines.push('');
107
+ lines.push(row('Uptime', formatUptime(state.startedAt)));
108
+ lines.push(row('Watching', config.watch.map(w => w.path).join(', ')));
68
109
 
69
110
  if (state.sessionBranch) {
70
- print.row('Branch', state.sessionBranch, 'autogenerated');
111
+ lines.push(row('Branch', state.sessionBranch) + chalk.hex(PINK).dim(' (autogenerated)'));
71
112
  } else {
72
- print.row('Branch', 'Current branch');
113
+ lines.push(row('Branch', 'Current branch'));
73
114
  }
74
115
 
75
116
  if (state.sessionCommits > 0) {
76
- print.row('Commits', `${state.sessionCommits} this session`);
117
+ lines.push(row('Commits', `${state.sessionCommits} this session`));
77
118
  }
78
119
 
79
120
  if (state.lastCommittedAt) {
80
121
  const fileLabel = state.lastCommittedFile ? ` (${state.lastCommittedFile})` : '';
81
- print.row('Last commit', `${timeAgo(state.lastCommittedAt)}${fileLabel}`);
122
+ lines.push(row('Last commit', `${timeAgo(state.lastCommittedAt)}${fileLabel}`));
82
123
  }
83
124
 
84
125
  if (state.lastPushedAt) {
85
- print.row('Last push', timeAgo(state.lastPushedAt));
126
+ lines.push(row('Last push', timeAgo(state.lastPushedAt)));
86
127
  }
87
128
 
88
129
  if (resumedAfterSleep && state.catchUpCommits > 0) {
89
- print.gap();
90
- print.good(`${state.catchUpCommits} file${state.catchUpCommits !== 1 ? 's' : ''} committed on wake.`);
130
+ lines.push('');
131
+ lines.push(chalk.hex(TEAL)(` ✔ ${state.catchUpCommits} file${state.catchUpCommits !== 1 ? 's' : ''} committed on wake.`));
91
132
  }
92
133
 
134
+ lines.push('');
135
+
136
+ console.log(boxen(lines.join('\n'), BOX_OPTS));
93
137
  print.gap();
94
- }
138
+ }