gitwarren 0.1.10 → 0.1.12
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 +12 -0
- package/lib/gitwarren.cjs +183 -108
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -61,6 +61,18 @@ The MCP server reads the same SQLite file the browser view does, so an agent
|
|
|
61
61
|
can open and comment on reviews whether or not GitWarren is being served. What
|
|
62
62
|
serving adds is that the links an agent hands you have something to open.
|
|
63
63
|
|
|
64
|
+
On a machine where nothing has been installed, the same server starts by name:
|
|
65
|
+
`npx gitwarren mcp`. That is the command a Claude Code plugin or an MCP registry
|
|
66
|
+
entry names, and it is what makes either work before you have decided to keep
|
|
67
|
+
GitWarren. It writes no launcher and asks for no login item; it reads the same
|
|
68
|
+
database, so the reviews are there when you do.
|
|
69
|
+
|
|
70
|
+
`npx gitwarren mcp --serve` also serves the review page, on loopback and for as
|
|
71
|
+
long as the agent keeps the server running, so the links the agent hands out
|
|
72
|
+
open even on a machine with nothing else installed. If GitWarren is already
|
|
73
|
+
running, as the app or as `gitwarren serve`, it serves nothing and the links
|
|
74
|
+
open there instead.
|
|
75
|
+
|
|
64
76
|
## Where your data is
|
|
65
77
|
|
|
66
78
|
One SQLite database in the usual place for your platform —
|
package/lib/gitwarren.cjs
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
const
|
|
3
|
-
const crypto$1 = require("node:crypto");
|
|
2
|
+
const node_module = require("node:module");
|
|
4
3
|
const fs = require("node:fs");
|
|
5
|
-
const node_os = require("node:os");
|
|
6
4
|
const node_path = require("node:path");
|
|
5
|
+
const node_os = require("node:os");
|
|
6
|
+
const Client = require("better-sqlite3");
|
|
7
|
+
const crypto$1 = require("node:crypto");
|
|
7
8
|
const node_child_process = require("node:child_process");
|
|
8
9
|
const node_stream = require("node:stream");
|
|
9
10
|
const require$$0$3 = require("events");
|
|
@@ -23,6 +24,99 @@ const node_util = require("node:util");
|
|
|
23
24
|
const node_url = require("node:url");
|
|
24
25
|
const node_http = require("node:http");
|
|
25
26
|
var _documentCurrentScript = typeof document !== "undefined" ? document.currentScript : null;
|
|
27
|
+
const INSTANCE_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
28
|
+
function isInstanceId(value) {
|
|
29
|
+
return INSTANCE_ID_PATTERN.test(value);
|
|
30
|
+
}
|
|
31
|
+
const APP_DIR_NAME = "GitWarren";
|
|
32
|
+
const DATABASE_FILE_NAME = "gitwarren.db";
|
|
33
|
+
const INSTANCE_FILE_NAME = "instance-id";
|
|
34
|
+
const DATA_DIR_ENV_VAR = "GITWARREN_DATA_DIR";
|
|
35
|
+
function getDataDirectory() {
|
|
36
|
+
const override = process.env[DATA_DIR_ENV_VAR]?.trim();
|
|
37
|
+
if (override) return override;
|
|
38
|
+
switch (process.platform) {
|
|
39
|
+
case "win32":
|
|
40
|
+
return node_path.join(process.env.APPDATA ?? node_path.join(node_os.homedir(), "AppData", "Roaming"), APP_DIR_NAME);
|
|
41
|
+
case "darwin":
|
|
42
|
+
return node_path.join(node_os.homedir(), "Library", "Application Support", APP_DIR_NAME);
|
|
43
|
+
default:
|
|
44
|
+
return node_path.join(process.env.XDG_CONFIG_HOME ?? node_path.join(node_os.homedir(), ".config"), APP_DIR_NAME);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function getDatabasePath() {
|
|
48
|
+
return node_path.join(getDataDirectory(), DATABASE_FILE_NAME);
|
|
49
|
+
}
|
|
50
|
+
function getInstanceIdPath() {
|
|
51
|
+
return node_path.join(getDataDirectory(), INSTANCE_FILE_NAME);
|
|
52
|
+
}
|
|
53
|
+
function ensureDataDirectory() {
|
|
54
|
+
const dir = getDataDirectory();
|
|
55
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
56
|
+
return dir;
|
|
57
|
+
}
|
|
58
|
+
const DAEMON_CACHE_DIR_NAME = "daemon-cache";
|
|
59
|
+
function getDaemonCacheDirectory() {
|
|
60
|
+
return node_path.join(getDataDirectory(), DAEMON_CACHE_DIR_NAME);
|
|
61
|
+
}
|
|
62
|
+
const RUNTIME_FILE_NAME = "daemon-runtime.json";
|
|
63
|
+
const LEGACY_FILE_NAME = "gui-runtime.json";
|
|
64
|
+
function getDaemonRuntimePath() {
|
|
65
|
+
return node_path.join(getDataDirectory(), RUNTIME_FILE_NAME);
|
|
66
|
+
}
|
|
67
|
+
function writeDaemonRuntime(runtime) {
|
|
68
|
+
try {
|
|
69
|
+
ensureDataDirectory();
|
|
70
|
+
const merged = { ...runtime, webRoot: runtime.webRoot ?? exposure };
|
|
71
|
+
published = merged;
|
|
72
|
+
fs.writeFileSync(getDaemonRuntimePath(), JSON.stringify(merged), "utf8");
|
|
73
|
+
fs.rmSync(node_path.join(getDataDirectory(), LEGACY_FILE_NAME), { force: true });
|
|
74
|
+
} catch (error2) {
|
|
75
|
+
console.error("[runtime] could not publish the runtime file", error2);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function clearDaemonRuntime() {
|
|
79
|
+
published = null;
|
|
80
|
+
exposure = null;
|
|
81
|
+
try {
|
|
82
|
+
fs.rmSync(getDaemonRuntimePath(), { force: true });
|
|
83
|
+
} catch (error2) {
|
|
84
|
+
console.error("[runtime] could not remove the runtime file", error2);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
let published = null;
|
|
88
|
+
let exposure = null;
|
|
89
|
+
function writeDaemonExposure(webRoot) {
|
|
90
|
+
exposure = webRoot;
|
|
91
|
+
if (!published) return;
|
|
92
|
+
if ((published.webRoot ?? null) === webRoot) return;
|
|
93
|
+
writeDaemonRuntime({ ...published, webRoot });
|
|
94
|
+
}
|
|
95
|
+
function isAlive(pid) {
|
|
96
|
+
try {
|
|
97
|
+
process.kill(pid, 0);
|
|
98
|
+
return true;
|
|
99
|
+
} catch {
|
|
100
|
+
return false;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function readLiveDaemonRuntime() {
|
|
104
|
+
let parsed;
|
|
105
|
+
try {
|
|
106
|
+
parsed = JSON.parse(fs.readFileSync(getDaemonRuntimePath(), "utf8"));
|
|
107
|
+
} catch {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
if (typeof parsed !== "object" || parsed === null) return null;
|
|
111
|
+
const { instanceId, pid, linkPort, owner, webRoot } = parsed;
|
|
112
|
+
if (typeof instanceId !== "string" || !isInstanceId(instanceId)) return null;
|
|
113
|
+
if (!Number.isInteger(pid) || pid === void 0 || pid <= 0) return null;
|
|
114
|
+
if (owner !== "gui" && owner !== "daemon") return null;
|
|
115
|
+
const port = linkPort === null ? null : Number.isInteger(linkPort) && linkPort !== void 0 && linkPort > 0 && linkPort <= 65535 ? linkPort : void 0;
|
|
116
|
+
if (port === void 0) return null;
|
|
117
|
+
const root = typeof webRoot === "string" ? webRoot : null;
|
|
118
|
+
return isAlive(pid) ? { instanceId, pid, linkPort: port, owner, webRoot: root } : null;
|
|
119
|
+
}
|
|
26
120
|
const entityKind = /* @__PURE__ */ Symbol.for("drizzle:entityKind");
|
|
27
121
|
function is(value, type) {
|
|
28
122
|
if (!value || typeof value !== "object") {
|
|
@@ -4871,37 +4965,6 @@ function migrate(db, config2) {
|
|
|
4871
4965
|
const migrations = readMigrationFiles(config2);
|
|
4872
4966
|
db.dialect.migrate(migrations, db.session, config2);
|
|
4873
4967
|
}
|
|
4874
|
-
const APP_DIR_NAME = "GitWarren";
|
|
4875
|
-
const DATABASE_FILE_NAME = "gitwarren.db";
|
|
4876
|
-
const INSTANCE_FILE_NAME = "instance-id";
|
|
4877
|
-
const DATA_DIR_ENV_VAR = "GITWARREN_DATA_DIR";
|
|
4878
|
-
function getDataDirectory() {
|
|
4879
|
-
const override = process.env[DATA_DIR_ENV_VAR]?.trim();
|
|
4880
|
-
if (override) return override;
|
|
4881
|
-
switch (process.platform) {
|
|
4882
|
-
case "win32":
|
|
4883
|
-
return node_path.join(process.env.APPDATA ?? node_path.join(node_os.homedir(), "AppData", "Roaming"), APP_DIR_NAME);
|
|
4884
|
-
case "darwin":
|
|
4885
|
-
return node_path.join(node_os.homedir(), "Library", "Application Support", APP_DIR_NAME);
|
|
4886
|
-
default:
|
|
4887
|
-
return node_path.join(process.env.XDG_CONFIG_HOME ?? node_path.join(node_os.homedir(), ".config"), APP_DIR_NAME);
|
|
4888
|
-
}
|
|
4889
|
-
}
|
|
4890
|
-
function getDatabasePath() {
|
|
4891
|
-
return node_path.join(getDataDirectory(), DATABASE_FILE_NAME);
|
|
4892
|
-
}
|
|
4893
|
-
function getInstanceIdPath() {
|
|
4894
|
-
return node_path.join(getDataDirectory(), INSTANCE_FILE_NAME);
|
|
4895
|
-
}
|
|
4896
|
-
function ensureDataDirectory() {
|
|
4897
|
-
const dir = getDataDirectory();
|
|
4898
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
4899
|
-
return dir;
|
|
4900
|
-
}
|
|
4901
|
-
const DAEMON_CACHE_DIR_NAME = "daemon-cache";
|
|
4902
|
-
function getDaemonCacheDirectory() {
|
|
4903
|
-
return node_path.join(getDataDirectory(), DAEMON_CACHE_DIR_NAME);
|
|
4904
|
-
}
|
|
4905
4968
|
const MIGRATIONS_DIR_ENV_VAR = "GITWARREN_MIGRATIONS_DIR";
|
|
4906
4969
|
function isMigrationsFolder(candidate) {
|
|
4907
4970
|
return fs.existsSync(node_path.join(candidate, "meta", "_journal.json"));
|
|
@@ -5295,10 +5358,6 @@ const schema = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProper
|
|
|
5295
5358
|
reviewedFiles,
|
|
5296
5359
|
reviews
|
|
5297
5360
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
5298
|
-
const INSTANCE_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
5299
|
-
function isInstanceId(value) {
|
|
5300
|
-
return INSTANCE_ID_PATTERN.test(value);
|
|
5301
|
-
}
|
|
5302
5361
|
let cached$2 = null;
|
|
5303
5362
|
function readExisting() {
|
|
5304
5363
|
try {
|
|
@@ -10242,7 +10301,7 @@ function cmdQuote(value) {
|
|
|
10242
10301
|
if (value.includes('"')) throw new Error(`a Windows path cannot contain a quote: ${value}`);
|
|
10243
10302
|
return `"${value}"`;
|
|
10244
10303
|
}
|
|
10245
|
-
const APP_VERSION = "0.1.
|
|
10304
|
+
const APP_VERSION = "0.1.12";
|
|
10246
10305
|
const REMOTE_ROOT = "$HOME/.gitwarren";
|
|
10247
10306
|
const runOnHost = (route2, options) => {
|
|
10248
10307
|
switch (route2.kind) {
|
|
@@ -10498,64 +10557,6 @@ async function unserveTailnet(port) {
|
|
|
10498
10557
|
await tailscale(["serve", "--http", String(port), "off"], SERVE_TIMEOUT_MS);
|
|
10499
10558
|
return await tailnetServeOrigin(port) !== null;
|
|
10500
10559
|
}
|
|
10501
|
-
const RUNTIME_FILE_NAME = "daemon-runtime.json";
|
|
10502
|
-
const LEGACY_FILE_NAME = "gui-runtime.json";
|
|
10503
|
-
function getDaemonRuntimePath() {
|
|
10504
|
-
return node_path.join(getDataDirectory(), RUNTIME_FILE_NAME);
|
|
10505
|
-
}
|
|
10506
|
-
function writeDaemonRuntime(runtime) {
|
|
10507
|
-
try {
|
|
10508
|
-
ensureDataDirectory();
|
|
10509
|
-
const merged = { ...runtime, webRoot: runtime.webRoot ?? exposure };
|
|
10510
|
-
published = merged;
|
|
10511
|
-
fs.writeFileSync(getDaemonRuntimePath(), JSON.stringify(merged), "utf8");
|
|
10512
|
-
fs.rmSync(node_path.join(getDataDirectory(), LEGACY_FILE_NAME), { force: true });
|
|
10513
|
-
} catch (error2) {
|
|
10514
|
-
console.error("[runtime] could not publish the runtime file", error2);
|
|
10515
|
-
}
|
|
10516
|
-
}
|
|
10517
|
-
function clearDaemonRuntime() {
|
|
10518
|
-
published = null;
|
|
10519
|
-
exposure = null;
|
|
10520
|
-
try {
|
|
10521
|
-
fs.rmSync(getDaemonRuntimePath(), { force: true });
|
|
10522
|
-
} catch (error2) {
|
|
10523
|
-
console.error("[runtime] could not remove the runtime file", error2);
|
|
10524
|
-
}
|
|
10525
|
-
}
|
|
10526
|
-
let published = null;
|
|
10527
|
-
let exposure = null;
|
|
10528
|
-
function writeDaemonExposure(webRoot) {
|
|
10529
|
-
exposure = webRoot;
|
|
10530
|
-
if (!published) return;
|
|
10531
|
-
if ((published.webRoot ?? null) === webRoot) return;
|
|
10532
|
-
writeDaemonRuntime({ ...published, webRoot });
|
|
10533
|
-
}
|
|
10534
|
-
function isAlive(pid) {
|
|
10535
|
-
try {
|
|
10536
|
-
process.kill(pid, 0);
|
|
10537
|
-
return true;
|
|
10538
|
-
} catch {
|
|
10539
|
-
return false;
|
|
10540
|
-
}
|
|
10541
|
-
}
|
|
10542
|
-
function readLiveDaemonRuntime() {
|
|
10543
|
-
let parsed;
|
|
10544
|
-
try {
|
|
10545
|
-
parsed = JSON.parse(fs.readFileSync(getDaemonRuntimePath(), "utf8"));
|
|
10546
|
-
} catch {
|
|
10547
|
-
return null;
|
|
10548
|
-
}
|
|
10549
|
-
if (typeof parsed !== "object" || parsed === null) return null;
|
|
10550
|
-
const { instanceId, pid, linkPort, owner, webRoot } = parsed;
|
|
10551
|
-
if (typeof instanceId !== "string" || !isInstanceId(instanceId)) return null;
|
|
10552
|
-
if (!Number.isInteger(pid) || pid === void 0 || pid <= 0) return null;
|
|
10553
|
-
if (owner !== "gui" && owner !== "daemon") return null;
|
|
10554
|
-
const port = linkPort === null ? null : Number.isInteger(linkPort) && linkPort !== void 0 && linkPort > 0 && linkPort <= 65535 ? linkPort : void 0;
|
|
10555
|
-
if (port === void 0) return null;
|
|
10556
|
-
const root = typeof webRoot === "string" ? webRoot : null;
|
|
10557
|
-
return isAlive(pid) ? { instanceId, pid, linkPort: port, owner, webRoot: root } : null;
|
|
10558
|
-
}
|
|
10559
10560
|
const UNAVAILABLE = {
|
|
10560
10561
|
available: false,
|
|
10561
10562
|
dnsName: null,
|
|
@@ -26868,7 +26869,7 @@ Connection: close\r
|
|
|
26868
26869
|
}
|
|
26869
26870
|
};
|
|
26870
26871
|
}
|
|
26871
|
-
const VERSION$1 = "0.1.
|
|
26872
|
+
const VERSION$1 = "0.1.12";
|
|
26872
26873
|
function isWebBuild(directory) {
|
|
26873
26874
|
return fs.existsSync(node_path.join(directory, "index.html")) && !fs.existsSync(node_path.join(directory, "main.ts"));
|
|
26874
26875
|
}
|
|
@@ -26971,6 +26972,11 @@ function runListen(hooks = {}) {
|
|
|
26971
26972
|
owner: "daemon"
|
|
26972
26973
|
});
|
|
26973
26974
|
const url = `http://${LINK_SERVER_HOST}:${LINK_SERVER_PORT}/?${TOKEN_PARAM}=${token}`;
|
|
26975
|
+
if (hooks.brief) {
|
|
26976
|
+
console.error(`[gitwarren] serving the review page at ${url}`);
|
|
26977
|
+
hooks.onListening?.(url);
|
|
26978
|
+
return;
|
|
26979
|
+
}
|
|
26974
26980
|
console.error(
|
|
26975
26981
|
`[gitwarren] GitWarren is running at
|
|
26976
26982
|
|
|
@@ -27087,17 +27093,21 @@ function findMcpServer(script) {
|
|
|
27087
27093
|
}
|
|
27088
27094
|
return null;
|
|
27089
27095
|
}
|
|
27090
|
-
function
|
|
27096
|
+
function resolveScript() {
|
|
27091
27097
|
const argv1 = process.argv[1];
|
|
27092
|
-
|
|
27093
|
-
|
|
27094
|
-
|
|
27095
|
-
|
|
27096
|
-
|
|
27097
|
-
|
|
27098
|
-
script = null;
|
|
27099
|
-
}
|
|
27098
|
+
if (argv1 === void 0) return null;
|
|
27099
|
+
try {
|
|
27100
|
+
const resolved2 = fs.realpathSync(argv1);
|
|
27101
|
+
return /\.[cm]?ts$/i.test(resolved2) ? null : resolved2;
|
|
27102
|
+
} catch {
|
|
27103
|
+
return null;
|
|
27100
27104
|
}
|
|
27105
|
+
}
|
|
27106
|
+
function locateMcpServer() {
|
|
27107
|
+
return findMcpServer(resolveScript());
|
|
27108
|
+
}
|
|
27109
|
+
function describeSelf() {
|
|
27110
|
+
const script = resolveScript();
|
|
27101
27111
|
return { node: fs.realpathSync(process.execPath), script, mcpServer: findMcpServer(script), env: relaunchEnv() };
|
|
27102
27112
|
}
|
|
27103
27113
|
const BANNER = (what) => [
|
|
@@ -27609,7 +27619,7 @@ function runService(argv) {
|
|
|
27609
27619
|
return true;
|
|
27610
27620
|
}
|
|
27611
27621
|
}
|
|
27612
|
-
const VERSION = "0.1.
|
|
27622
|
+
const VERSION = "0.1.12";
|
|
27613
27623
|
const USAGE = `gitwarren - code review for your own git repositories, in a browser tab
|
|
27614
27624
|
|
|
27615
27625
|
Run it now
|
|
@@ -27626,6 +27636,8 @@ Keep it running
|
|
|
27626
27636
|
Let a coding agent in
|
|
27627
27637
|
gitwarren agent-setup print the one sentence to give an agent so it can
|
|
27628
27638
|
reach this GitWarren over MCP
|
|
27639
|
+
gitwarren mcp [--serve] run the MCP server itself, on stdin/stdout - what
|
|
27640
|
+
\`npx gitwarren mcp\` in an agent's config starts
|
|
27629
27641
|
|
|
27630
27642
|
gitwarren serve --stdio answer GitWarren's protocol on stdin/stdout (this
|
|
27631
27643
|
is what another machine's GitWarren spawns)
|
|
@@ -27652,6 +27664,22 @@ a URL that carries this launch's token. Ctrl-C stops it.
|
|
|
27652
27664
|
Serving also writes ~/.gitwarren/bin/gitwarren-mcp, the command a coding agent
|
|
27653
27665
|
starts the MCP server with - see \`gitwarren agent-setup\`.
|
|
27654
27666
|
`;
|
|
27667
|
+
const MCP_USAGE = `gitwarren mcp [--serve]
|
|
27668
|
+
|
|
27669
|
+
Runs GitWarren's MCP server, speaking MCP over stdin and stdout. This is for an
|
|
27670
|
+
agent to run, not a person: it is the same server ~/.gitwarren/bin/gitwarren-mcp
|
|
27671
|
+
starts, reachable by name so that an agent's config can say \`npx gitwarren mcp\`
|
|
27672
|
+
on a machine where GitWarren was never installed.
|
|
27673
|
+
|
|
27674
|
+
It reads the same SQLite file the app and \`gitwarren serve\` do, so reviews an
|
|
27675
|
+
agent makes this way are there the moment a person opens GitWarren to look.
|
|
27676
|
+
|
|
27677
|
+
--serve also serve the review page on 127.0.0.1 for as long as the agent
|
|
27678
|
+
keeps this running, unless a GitWarren is already running on this
|
|
27679
|
+
machine - then links open there and this serves nothing. This is
|
|
27680
|
+
what a plugin asks for, so the links its agent hands out open on a
|
|
27681
|
+
machine with nothing else installed.
|
|
27682
|
+
`;
|
|
27655
27683
|
function afterListening(url, open2) {
|
|
27656
27684
|
const launchers = ensureLaunchers();
|
|
27657
27685
|
if (launchers.refused) {
|
|
@@ -27667,6 +27695,51 @@ function afterListening(url, open2) {
|
|
|
27667
27695
|
openInBrowser(url, (message) => console.error(`[gitwarren] ${message}. The URL is above.`));
|
|
27668
27696
|
}
|
|
27669
27697
|
}
|
|
27698
|
+
function runMcp(argv) {
|
|
27699
|
+
if (argv.includes("--help") || argv.includes("-h")) {
|
|
27700
|
+
console.log(MCP_USAGE);
|
|
27701
|
+
return true;
|
|
27702
|
+
}
|
|
27703
|
+
if (argv.some((argument) => argument !== "--serve")) {
|
|
27704
|
+
console.error(MCP_USAGE);
|
|
27705
|
+
return false;
|
|
27706
|
+
}
|
|
27707
|
+
const server = locateMcpServer();
|
|
27708
|
+
if (!server) {
|
|
27709
|
+
console.error(
|
|
27710
|
+
"[gitwarren] this install has no MCP server bundle next to it. From a checkout, run `npm run build:mcp` first, or use `npm run mcp:dev`."
|
|
27711
|
+
);
|
|
27712
|
+
return false;
|
|
27713
|
+
}
|
|
27714
|
+
process.removeAllListeners("SIGINT");
|
|
27715
|
+
process.removeAllListeners("SIGTERM");
|
|
27716
|
+
if (argv.includes("--serve")) serveBesideMcp();
|
|
27717
|
+
node_module.createRequire(server)(server);
|
|
27718
|
+
return true;
|
|
27719
|
+
}
|
|
27720
|
+
function serveBesideMcp() {
|
|
27721
|
+
const owner = readLiveDaemonRuntime();
|
|
27722
|
+
if (owner) {
|
|
27723
|
+
console.error(
|
|
27724
|
+
`[gitwarren] GitWarren is already running on this machine as ${owner.owner === "gui" ? "the desktop app" : "a server"}; links will open there.`
|
|
27725
|
+
);
|
|
27726
|
+
return;
|
|
27727
|
+
}
|
|
27728
|
+
if (!runDaemon(["--listen"], { brief: true })) {
|
|
27729
|
+
process.exitCode = void 0;
|
|
27730
|
+
console.error(
|
|
27731
|
+
"[gitwarren] the review page could not be served, so links will not open until a GitWarren is started on this machine. The MCP server is running regardless."
|
|
27732
|
+
);
|
|
27733
|
+
return;
|
|
27734
|
+
}
|
|
27735
|
+
const release = () => shutdownListen();
|
|
27736
|
+
process.on("SIGINT", release);
|
|
27737
|
+
process.on("SIGTERM", release);
|
|
27738
|
+
process.stdin.once("end", () => {
|
|
27739
|
+
shutdownListen();
|
|
27740
|
+
process.exit(0);
|
|
27741
|
+
});
|
|
27742
|
+
}
|
|
27670
27743
|
function runCli(argv) {
|
|
27671
27744
|
const [command, ...rest] = argv;
|
|
27672
27745
|
switch (command) {
|
|
@@ -27684,6 +27757,8 @@ function runCli(argv) {
|
|
|
27684
27757
|
return runService(rest);
|
|
27685
27758
|
case "agent-setup":
|
|
27686
27759
|
return runAgentSetup(rest);
|
|
27760
|
+
case "mcp":
|
|
27761
|
+
return runMcp(rest);
|
|
27687
27762
|
case "--version":
|
|
27688
27763
|
case "-v":
|
|
27689
27764
|
console.log(VERSION);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "gitwarren",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
4
4
|
"description": "Code review for your own machines and your own agents, served on loopback. No Electron, no account.",
|
|
5
5
|
"keywords": ["code-review", "git", "diff", "mcp", "local-first", "ssh", "wsl", "tailscale", "self-hosted"],
|
|
6
6
|
"homepage": "https://github.com/klarluft/gitwarren-app",
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"bugs": "https://github.com/klarluft/gitwarren-app/issues",
|
|
9
9
|
"license": "GPL-3.0-or-later",
|
|
10
10
|
"author": { "name": "Klarluft B.V.", "email": "contact@klarluft.com", "url": "https://klarluft.com" },
|
|
11
|
+
"mcpName": "io.github.klarluft/gitwarren",
|
|
11
12
|
"type": "module",
|
|
12
13
|
"bin": { "gitwarren": "bin/gitwarren.mjs" },
|
|
13
14
|
"files": ["bin", "lib", "drizzle", "web", "README.md"],
|