gitwarren 0.1.7

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 ADDED
@@ -0,0 +1,53 @@
1
+ # gitwarren
2
+
3
+ Local-only code review for your git repositories. Your code, your diffs and
4
+ your comments stay on your machine — there is no server, no account and nothing
5
+ to sign in to.
6
+
7
+ This package is the command line. There is also a desktop app; see
8
+ [gitwarren-app](https://github.com/klarluft/gitwarren-app).
9
+
10
+ ```
11
+ npx gitwarren serve
12
+ ```
13
+
14
+ That serves the review UI on `127.0.0.1:41427` and prints a URL carrying a
15
+ token minted for that launch. Open it, add a repository, pick two refs, and
16
+ review the diff.
17
+
18
+ ## Commands
19
+
20
+ | | |
21
+ | --- | --- |
22
+ | `gitwarren serve` | serve the web view on loopback and print its URL |
23
+ | `gitwarren serve --stdio` | answer GitWarren's protocol on stdin/stdout |
24
+ | `gitwarren open [link]` | open this machine's GitWarren in a browser, carrying the token |
25
+ | `gitwarren service install` | write the agent launcher, and start at login |
26
+ | `gitwarren service uninstall` | remove the login item |
27
+ | `gitwarren service status` | what is registered, and what is running |
28
+
29
+ `gitwarren open` takes a `gitwarren://` deep link or the `http://127.0.0.1`
30
+ URL an agent hands out, and lands on that review rather than the home screen.
31
+
32
+ ## Letting an agent in
33
+
34
+ `gitwarren service install` writes `~/.gitwarren/bin/gitwarren-mcp`, which is a
35
+ GitWarren MCP server your coding agent can start. Point the agent at that one
36
+ path — it is the same on every machine, and GitWarren keeps it pointing at
37
+ whichever install ran last.
38
+
39
+ ## Where your data is
40
+
41
+ One SQLite database in the usual place for your platform —
42
+ `~/Library/Application Support/GitWarren` on macOS, `~/.config/GitWarren` on
43
+ Linux, `%APPDATA%\GitWarren` on Windows. `gitwarren service status` prints the
44
+ path.
45
+
46
+ The web view binds `127.0.0.1` only, checks `Host` and `Origin` on every
47
+ request and on the WebSocket upgrade, and requires a token minted per launch
48
+ which it exchanges for a `SameSite=Strict` cookie. A page on another origin
49
+ cannot reach it.
50
+
51
+ ## Licence
52
+
53
+ GPL-3.0-or-later. Copyright © 2026 Klarluft B.V.
@@ -0,0 +1,35 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * `npx gitwarren` - the third way to get this, and the only one that does not
4
+ * ship a Node.
5
+ *
6
+ * The tarball from spike S3 carries its own interpreter because the machines it
7
+ * targets have none. Somebody typing `npx` has already proved they have one, so
8
+ * this package carries the bundles and lets `better-sqlite3` be an ordinary
9
+ * dependency - which is how a native addon is supposed to reach a user's
10
+ * platform, and is the reason this package is a tenth of the tarball's size and
11
+ * works on Windows without a fourth build target.
12
+ *
13
+ * ## What this file does, and why it is a file rather than a `bin` entry
14
+ *
15
+ * Two environment variables, and then the bundle. `GITWARREN_MIGRATIONS_DIR`
16
+ * and `GITWARREN_WEB_ROOT` are how a build says where its non-JavaScript parts
17
+ * went, and outside Electron there is no `resourcesPath` and no project root to
18
+ * walk up to - so somebody has to name them. In the tarball it is a `sh`
19
+ * preamble; here it is these six lines.
20
+ *
21
+ * They are set rather than defaulted, and `??=` rather than `=`, so that
22
+ * someone debugging a build can still point either one somewhere else without
23
+ * editing an installed package.
24
+ *
25
+ * `createRequire` because the bundle is CommonJS - see `vite.daemon.config.ts`
26
+ * on why - and this file is ESM so that `import.meta.dirname` is available to
27
+ * locate it. The two module systems meet here and nowhere else.
28
+ */
29
+ import { createRequire } from 'node:module'
30
+ import { join } from 'node:path'
31
+
32
+ process.env.GITWARREN_MIGRATIONS_DIR ??= join(import.meta.dirname, '..', 'drizzle')
33
+ process.env.GITWARREN_WEB_ROOT ??= join(import.meta.dirname, '..', 'web')
34
+
35
+ createRequire(import.meta.url)('../lib/gitwarren.cjs')
@@ -0,0 +1,10 @@
1
+ CREATE TABLE `repositories` (
2
+ `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
3
+ `path` text NOT NULL,
4
+ `name` text NOT NULL,
5
+ `created_at` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL,
6
+ `updated_at` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL
7
+ );
8
+ --> statement-breakpoint
9
+ CREATE UNIQUE INDEX `repositories_path_unique` ON `repositories` (`path`);--> statement-breakpoint
10
+ CREATE INDEX `repositories_name_idx` ON `repositories` (`name`);
@@ -0,0 +1,15 @@
1
+ CREATE TABLE `reviews` (
2
+ `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
3
+ `repository_id` integer NOT NULL,
4
+ `title` text NOT NULL,
5
+ `description` text DEFAULT '' NOT NULL,
6
+ `base_ref` text NOT NULL,
7
+ `head_ref` text NOT NULL,
8
+ `status` text DEFAULT 'open' NOT NULL,
9
+ `created_at` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL,
10
+ `updated_at` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL,
11
+ `closed_at` text,
12
+ FOREIGN KEY (`repository_id`) REFERENCES `repositories`(`id`) ON UPDATE no action ON DELETE cascade
13
+ );
14
+ --> statement-breakpoint
15
+ CREATE INDEX `reviews_repository_idx` ON `reviews` (`repository_id`,`status`);
@@ -0,0 +1,31 @@
1
+ CREATE TABLE `comment_threads` (
2
+ `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
3
+ `review_id` integer NOT NULL,
4
+ `file_path` text,
5
+ `side` text,
6
+ `line` integer,
7
+ `anchor_text` text,
8
+ `anchor_sha` text,
9
+ `resolved_at` text,
10
+ `resolved_by` text,
11
+ `created_at` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL,
12
+ `updated_at` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL,
13
+ FOREIGN KEY (`review_id`) REFERENCES `reviews`(`id`) ON UPDATE no action ON DELETE cascade
14
+ );
15
+ --> statement-breakpoint
16
+ CREATE INDEX `comment_threads_review_idx` ON `comment_threads` (`review_id`,`updated_at`);--> statement-breakpoint
17
+ CREATE INDEX `comment_threads_file_idx` ON `comment_threads` (`review_id`,`file_path`);--> statement-breakpoint
18
+ CREATE TABLE `comments` (
19
+ `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
20
+ `thread_id` integer NOT NULL,
21
+ `author_kind` text NOT NULL,
22
+ `author_name` text NOT NULL,
23
+ `author_label` text,
24
+ `author_session` text,
25
+ `body` text NOT NULL,
26
+ `created_at` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL,
27
+ `updated_at` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL,
28
+ FOREIGN KEY (`thread_id`) REFERENCES `comment_threads`(`id`) ON UPDATE no action ON DELETE cascade
29
+ );
30
+ --> statement-breakpoint
31
+ CREATE INDEX `comments_thread_idx` ON `comments` (`thread_id`,`created_at`);
@@ -0,0 +1 @@
1
+ ALTER TABLE `comment_threads` ADD `anchor_snapshot` text;
@@ -0,0 +1,10 @@
1
+ CREATE TABLE `attachments` (
2
+ `sha` text PRIMARY KEY NOT NULL,
3
+ `ext` text NOT NULL,
4
+ `mime_type` text NOT NULL,
5
+ `byte_size` integer NOT NULL,
6
+ `width` integer,
7
+ `height` integer,
8
+ `original_name` text,
9
+ `created_at` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL
10
+ );
@@ -0,0 +1 @@
1
+ ALTER TABLE `comment_threads` ADD `start_line` integer;
@@ -0,0 +1,10 @@
1
+ CREATE TABLE `reviewed_files` (
2
+ `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
3
+ `review_id` integer NOT NULL,
4
+ `file_path` text NOT NULL,
5
+ `content_digest` text NOT NULL,
6
+ `reviewed_at` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL,
7
+ FOREIGN KEY (`review_id`) REFERENCES `reviews`(`id`) ON UPDATE no action ON DELETE cascade
8
+ );
9
+ --> statement-breakpoint
10
+ CREATE UNIQUE INDEX `reviewed_files_path_idx` ON `reviewed_files` (`review_id`,`file_path`);
@@ -0,0 +1,14 @@
1
+ CREATE TABLE `principals` (
2
+ `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
3
+ `kind` text NOT NULL,
4
+ `identifier` text NOT NULL,
5
+ `display_name` text NOT NULL,
6
+ `created_at` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL
7
+ );
8
+ --> statement-breakpoint
9
+ CREATE UNIQUE INDEX `principals_identity_idx` ON `principals` (`kind`,`identifier`);--> statement-breakpoint
10
+ DROP INDEX `repositories_path_unique`;--> statement-breakpoint
11
+ ALTER TABLE `repositories` ADD `host_id` text;--> statement-breakpoint
12
+ CREATE UNIQUE INDEX `repositories_host_path_idx` ON `repositories` (`host_id`,`path`);--> statement-breakpoint
13
+ CREATE UNIQUE INDEX `repositories_local_path_idx` ON `repositories` (`path`) WHERE "repositories"."host_id" is null;--> statement-breakpoint
14
+ ALTER TABLE `comments` ADD `author_id` integer REFERENCES principals(id);
@@ -0,0 +1,13 @@
1
+ CREATE TABLE `hosts` (
2
+ `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
3
+ `instance_id` text,
4
+ `label` text NOT NULL,
5
+ `kind` text DEFAULT 'ssh' NOT NULL,
6
+ `target` text NOT NULL,
7
+ `editor_target` text,
8
+ `last_seen_at` text,
9
+ `created_at` text DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')) NOT NULL
10
+ );
11
+ --> statement-breakpoint
12
+ CREATE UNIQUE INDEX `hosts_kind_target_idx` ON `hosts` (`kind`,`target`);--> statement-breakpoint
13
+ CREATE UNIQUE INDEX `hosts_instance_idx` ON `hosts` (`instance_id`) WHERE "hosts"."instance_id" is not null;
@@ -0,0 +1 @@
1
+ ALTER TABLE `hosts` ADD `daemon_version` text;
@@ -0,0 +1,80 @@
1
+ {
2
+ "version": "6",
3
+ "dialect": "sqlite",
4
+ "id": "637f1fe0-da2c-4b76-ad8d-cde6574e77f4",
5
+ "prevId": "00000000-0000-0000-0000-000000000000",
6
+ "tables": {
7
+ "repositories": {
8
+ "name": "repositories",
9
+ "columns": {
10
+ "id": {
11
+ "name": "id",
12
+ "type": "integer",
13
+ "primaryKey": true,
14
+ "notNull": true,
15
+ "autoincrement": true
16
+ },
17
+ "path": {
18
+ "name": "path",
19
+ "type": "text",
20
+ "primaryKey": false,
21
+ "notNull": true,
22
+ "autoincrement": false
23
+ },
24
+ "name": {
25
+ "name": "name",
26
+ "type": "text",
27
+ "primaryKey": false,
28
+ "notNull": true,
29
+ "autoincrement": false
30
+ },
31
+ "created_at": {
32
+ "name": "created_at",
33
+ "type": "text",
34
+ "primaryKey": false,
35
+ "notNull": true,
36
+ "autoincrement": false,
37
+ "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))"
38
+ },
39
+ "updated_at": {
40
+ "name": "updated_at",
41
+ "type": "text",
42
+ "primaryKey": false,
43
+ "notNull": true,
44
+ "autoincrement": false,
45
+ "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))"
46
+ }
47
+ },
48
+ "indexes": {
49
+ "repositories_path_unique": {
50
+ "name": "repositories_path_unique",
51
+ "columns": [
52
+ "path"
53
+ ],
54
+ "isUnique": true
55
+ },
56
+ "repositories_name_idx": {
57
+ "name": "repositories_name_idx",
58
+ "columns": [
59
+ "name"
60
+ ],
61
+ "isUnique": false
62
+ }
63
+ },
64
+ "foreignKeys": {},
65
+ "compositePrimaryKeys": {},
66
+ "uniqueConstraints": {},
67
+ "checkConstraints": {}
68
+ }
69
+ },
70
+ "views": {},
71
+ "enums": {},
72
+ "_meta": {
73
+ "schemas": {},
74
+ "tables": {},
75
+ "columns": {}
76
+ },
77
+ "internal": {
78
+ "indexes": {}
79
+ }
80
+ }
@@ -0,0 +1,187 @@
1
+ {
2
+ "version": "6",
3
+ "dialect": "sqlite",
4
+ "id": "1eb43a3d-02ac-4196-bf87-f794d9d5e726",
5
+ "prevId": "637f1fe0-da2c-4b76-ad8d-cde6574e77f4",
6
+ "tables": {
7
+ "repositories": {
8
+ "name": "repositories",
9
+ "columns": {
10
+ "id": {
11
+ "name": "id",
12
+ "type": "integer",
13
+ "primaryKey": true,
14
+ "notNull": true,
15
+ "autoincrement": true
16
+ },
17
+ "path": {
18
+ "name": "path",
19
+ "type": "text",
20
+ "primaryKey": false,
21
+ "notNull": true,
22
+ "autoincrement": false
23
+ },
24
+ "name": {
25
+ "name": "name",
26
+ "type": "text",
27
+ "primaryKey": false,
28
+ "notNull": true,
29
+ "autoincrement": false
30
+ },
31
+ "created_at": {
32
+ "name": "created_at",
33
+ "type": "text",
34
+ "primaryKey": false,
35
+ "notNull": true,
36
+ "autoincrement": false,
37
+ "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))"
38
+ },
39
+ "updated_at": {
40
+ "name": "updated_at",
41
+ "type": "text",
42
+ "primaryKey": false,
43
+ "notNull": true,
44
+ "autoincrement": false,
45
+ "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))"
46
+ }
47
+ },
48
+ "indexes": {
49
+ "repositories_path_unique": {
50
+ "name": "repositories_path_unique",
51
+ "columns": [
52
+ "path"
53
+ ],
54
+ "isUnique": true
55
+ },
56
+ "repositories_name_idx": {
57
+ "name": "repositories_name_idx",
58
+ "columns": [
59
+ "name"
60
+ ],
61
+ "isUnique": false
62
+ }
63
+ },
64
+ "foreignKeys": {},
65
+ "compositePrimaryKeys": {},
66
+ "uniqueConstraints": {},
67
+ "checkConstraints": {}
68
+ },
69
+ "reviews": {
70
+ "name": "reviews",
71
+ "columns": {
72
+ "id": {
73
+ "name": "id",
74
+ "type": "integer",
75
+ "primaryKey": true,
76
+ "notNull": true,
77
+ "autoincrement": true
78
+ },
79
+ "repository_id": {
80
+ "name": "repository_id",
81
+ "type": "integer",
82
+ "primaryKey": false,
83
+ "notNull": true,
84
+ "autoincrement": false
85
+ },
86
+ "title": {
87
+ "name": "title",
88
+ "type": "text",
89
+ "primaryKey": false,
90
+ "notNull": true,
91
+ "autoincrement": false
92
+ },
93
+ "description": {
94
+ "name": "description",
95
+ "type": "text",
96
+ "primaryKey": false,
97
+ "notNull": true,
98
+ "autoincrement": false,
99
+ "default": "''"
100
+ },
101
+ "base_ref": {
102
+ "name": "base_ref",
103
+ "type": "text",
104
+ "primaryKey": false,
105
+ "notNull": true,
106
+ "autoincrement": false
107
+ },
108
+ "head_ref": {
109
+ "name": "head_ref",
110
+ "type": "text",
111
+ "primaryKey": false,
112
+ "notNull": true,
113
+ "autoincrement": false
114
+ },
115
+ "status": {
116
+ "name": "status",
117
+ "type": "text",
118
+ "primaryKey": false,
119
+ "notNull": true,
120
+ "autoincrement": false,
121
+ "default": "'open'"
122
+ },
123
+ "created_at": {
124
+ "name": "created_at",
125
+ "type": "text",
126
+ "primaryKey": false,
127
+ "notNull": true,
128
+ "autoincrement": false,
129
+ "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))"
130
+ },
131
+ "updated_at": {
132
+ "name": "updated_at",
133
+ "type": "text",
134
+ "primaryKey": false,
135
+ "notNull": true,
136
+ "autoincrement": false,
137
+ "default": "(strftime('%Y-%m-%dT%H:%M:%fZ', 'now'))"
138
+ },
139
+ "closed_at": {
140
+ "name": "closed_at",
141
+ "type": "text",
142
+ "primaryKey": false,
143
+ "notNull": false,
144
+ "autoincrement": false
145
+ }
146
+ },
147
+ "indexes": {
148
+ "reviews_repository_idx": {
149
+ "name": "reviews_repository_idx",
150
+ "columns": [
151
+ "repository_id",
152
+ "status"
153
+ ],
154
+ "isUnique": false
155
+ }
156
+ },
157
+ "foreignKeys": {
158
+ "reviews_repository_id_repositories_id_fk": {
159
+ "name": "reviews_repository_id_repositories_id_fk",
160
+ "tableFrom": "reviews",
161
+ "tableTo": "repositories",
162
+ "columnsFrom": [
163
+ "repository_id"
164
+ ],
165
+ "columnsTo": [
166
+ "id"
167
+ ],
168
+ "onDelete": "cascade",
169
+ "onUpdate": "no action"
170
+ }
171
+ },
172
+ "compositePrimaryKeys": {},
173
+ "uniqueConstraints": {},
174
+ "checkConstraints": {}
175
+ }
176
+ },
177
+ "views": {},
178
+ "enums": {},
179
+ "_meta": {
180
+ "schemas": {},
181
+ "tables": {},
182
+ "columns": {}
183
+ },
184
+ "internal": {
185
+ "indexes": {}
186
+ }
187
+ }