@cyanheads/git-mcp-server 2.4.8 → 2.5.1
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 +8 -5
- package/dist/index.js +381 -42
- package/package.json +29 -31
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
<div align="center">
|
|
9
9
|
|
|
10
|
-
[](./CHANGELOG.md) [](https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-06-18/changelog.mdx) [](https://modelcontextprotocol.io/) [](./LICENSE) [](https://github.com/cyanheads/git-mcp-server/issues) [](https://www.typescriptlang.org/) [](https://bun.sh/)
|
|
11
11
|
|
|
12
12
|
</div>
|
|
13
13
|
|
|
@@ -73,7 +73,7 @@ Add the following to your MCP Client configuration file (e.g., `cline_mcp_settin
|
|
|
73
73
|
"env": {
|
|
74
74
|
"MCP_TRANSPORT_TYPE": "stdio",
|
|
75
75
|
"MCP_LOG_LEVEL": "info",
|
|
76
|
-
"
|
|
76
|
+
"GIT_BASE_DIR": "~/Developer/",
|
|
77
77
|
"LOGS_DIR": "~/Developer/logs/git-mcp-server/",
|
|
78
78
|
"GIT_USERNAME": "cyanheads",
|
|
79
79
|
"GIT_EMAIL": "casey@caseyjhand.com",
|
|
@@ -96,7 +96,7 @@ Add the following to your MCP Client configuration file (e.g., `cline_mcp_settin
|
|
|
96
96
|
"env": {
|
|
97
97
|
"MCP_TRANSPORT_TYPE": "stdio",
|
|
98
98
|
"MCP_LOG_LEVEL": "info",
|
|
99
|
-
"
|
|
99
|
+
"GIT_BASE_DIR": "~/Developer/",
|
|
100
100
|
"LOGS_DIR": "~/Developer/logs/git-mcp-server/",
|
|
101
101
|
"GIT_USERNAME": "cyanheads",
|
|
102
102
|
"GIT_EMAIL": "casey@caseyjhand.com",
|
|
@@ -133,8 +133,9 @@ Plus, specialized features for **Git integration**:
|
|
|
133
133
|
- **Optimized Git Execution**: Direct git CLI interaction with cross-runtime support for high-performance process management, streaming I/O, and timeout handling (current CLI provider).
|
|
134
134
|
- **Comprehensive Coverage**: 27 tools covering all essential Git operations from init to push.
|
|
135
135
|
- **Working Directory Management**: Session-specific directory context for multi-repo workflows.
|
|
136
|
+
- **Configurable Git Identity**: Override author/committer information via environment variables with automatic fallback to global git config.
|
|
136
137
|
- **Safety Features**: Explicit confirmations for destructive operations like `git clean` and `git reset --hard`.
|
|
137
|
-
- **Commit Signing**: Optional GPG/SSH signing support for
|
|
138
|
+
- **Commit Signing**: Optional GPG/SSH signing support for all commit-creating operations (commits, merges, rebases, cherry-picks, and tags).
|
|
138
139
|
|
|
139
140
|
### Development Environment Setup
|
|
140
141
|
|
|
@@ -190,7 +191,9 @@ All configuration is centralized and validated at startup in `src/config/index.t
|
|
|
190
191
|
| `STORAGE_PROVIDER_TYPE` | Storage backend: `in-memory`, `filesystem`, `supabase`, `cloudflare-kv`, `r2`. | `in-memory` |
|
|
191
192
|
| `OTEL_ENABLED` | Set to `true` to enable OpenTelemetry. | `false` |
|
|
192
193
|
| `MCP_LOG_LEVEL` | The minimum level for logging (`debug`, `info`, `warn`, `error`). | `info` |
|
|
193
|
-
| `GIT_SIGN_COMMITS` | Set to `"true"` to enable GPG/SSH signing for commits. Requires
|
|
194
|
+
| `GIT_SIGN_COMMITS` | Set to `"true"` to enable GPG/SSH signing for all commits, merges, rebases, cherry-picks, and tags. Requires GPG/SSH configuration. | `false` |
|
|
195
|
+
| `GIT_AUTHOR_NAME` | Git author name. Aliases: `GIT_USERNAME`, `GIT_USER`. Falls back to global git config if not set. | `(none)` |
|
|
196
|
+
| `GIT_AUTHOR_EMAIL` | Git author email. Aliases: `GIT_EMAIL`, `GIT_USER_EMAIL`. Falls back to global git config if not set. | `(none)` |
|
|
194
197
|
| `GIT_BASE_DIR` | Optional absolute path to restrict all git operations to a specific directory tree. Provides security sandboxing for multi-tenant or shared environments. | `(none)` |
|
|
195
198
|
| `GIT_WRAPUP_INSTRUCTIONS_PATH` | Optional path to custom markdown file with Git workflow instructions. | `(none)` |
|
|
196
199
|
| `MCP_AUTH_SECRET_KEY` | **Required for `jwt` auth.** A 32+ character secret key. | `(none)` |
|
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ var __create = Object.create;
|
|
|
4
4
|
var __getProtoOf = Object.getPrototypeOf;
|
|
5
5
|
var __defProp = Object.defineProperty;
|
|
6
6
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
8
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
9
|
var __toESM = (mod2, isNodeMode, target) => {
|
|
9
10
|
target = mod2 != null ? __create(__getProtoOf(mod2)) : {};
|
|
@@ -16,6 +17,20 @@ var __toESM = (mod2, isNodeMode, target) => {
|
|
|
16
17
|
});
|
|
17
18
|
return to;
|
|
18
19
|
};
|
|
20
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
21
|
+
var __toCommonJS = (from) => {
|
|
22
|
+
var entry = __moduleCache.get(from), desc;
|
|
23
|
+
if (entry)
|
|
24
|
+
return entry;
|
|
25
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
26
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
27
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
28
|
+
get: () => from[key],
|
|
29
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
30
|
+
}));
|
|
31
|
+
__moduleCache.set(from, entry);
|
|
32
|
+
return entry;
|
|
33
|
+
};
|
|
19
34
|
var __commonJS = (cb, mod2) => () => (mod2 || cb((mod2 = { exports: {} }).exports, mod2), mod2.exports);
|
|
20
35
|
var __export = (target, all) => {
|
|
21
36
|
for (var name in all)
|
|
@@ -4246,7 +4261,7 @@ var package_default;
|
|
|
4246
4261
|
var init_package = __esm(() => {
|
|
4247
4262
|
package_default = {
|
|
4248
4263
|
name: "@cyanheads/git-mcp-server",
|
|
4249
|
-
version: "2.
|
|
4264
|
+
version: "2.5.1",
|
|
4250
4265
|
mcpName: "io.github.cyanheads/git-mcp-server",
|
|
4251
4266
|
description: "A secure and scalable Git MCP server enabling AI agents to perform comprehensive Git version control operations via STDIO and Streamable HTTP.",
|
|
4252
4267
|
main: "dist/index.js",
|
|
@@ -4312,33 +4327,12 @@ var init_package = __esm(() => {
|
|
|
4312
4327
|
zod: "3.23.8",
|
|
4313
4328
|
typescript: "5.9.3"
|
|
4314
4329
|
},
|
|
4315
|
-
|
|
4330
|
+
devDependencies: {
|
|
4331
|
+
"@cloudflare/workers-types": "^4.20251011.0",
|
|
4332
|
+
"@eslint/js": "^9.37.0",
|
|
4316
4333
|
"@hono/mcp": "^0.1.4",
|
|
4317
4334
|
"@hono/node-server": "^1.19.5",
|
|
4318
4335
|
"@modelcontextprotocol/sdk": "^1.20.0",
|
|
4319
|
-
"@supabase/supabase-js": "^2.75.0",
|
|
4320
|
-
axios: "^1.12.2",
|
|
4321
|
-
"chrono-node": "^2.9.0",
|
|
4322
|
-
dotenv: "^17.2.3",
|
|
4323
|
-
"fast-xml-parser": "^5.3.0",
|
|
4324
|
-
hono: "^4.9.12",
|
|
4325
|
-
ignore: "^7.0.5",
|
|
4326
|
-
jose: "^6.1.0",
|
|
4327
|
-
"js-yaml": "^4.1.0",
|
|
4328
|
-
"node-cron": "^4.2.1",
|
|
4329
|
-
openai: "^6.3.0",
|
|
4330
|
-
papaparse: "^5.5.3",
|
|
4331
|
-
"partial-json": "^0.1.7",
|
|
4332
|
-
"pdf-lib": "^1.17.1",
|
|
4333
|
-
pino: "^10.0.0",
|
|
4334
|
-
"pino-pretty": "^13.1.2",
|
|
4335
|
-
"reflect-metadata": "^0.2.2",
|
|
4336
|
-
repomix: "^1.7.0",
|
|
4337
|
-
"sanitize-html": "^2.17.0",
|
|
4338
|
-
tslib: "^2.8.1",
|
|
4339
|
-
tsyringe: "^4.10.0",
|
|
4340
|
-
validator: "13.15.15",
|
|
4341
|
-
zod: "^3.23.8",
|
|
4342
4336
|
"@opentelemetry/api": "^1.9.0",
|
|
4343
4337
|
"@opentelemetry/auto-instrumentations-node": "^0.65.0",
|
|
4344
4338
|
"@opentelemetry/exporter-metrics-otlp-http": "^0.206.0",
|
|
@@ -4348,11 +4342,8 @@ var init_package = __esm(() => {
|
|
|
4348
4342
|
"@opentelemetry/sdk-metrics": "^2.1.0",
|
|
4349
4343
|
"@opentelemetry/sdk-node": "^0.206.0",
|
|
4350
4344
|
"@opentelemetry/sdk-trace-node": "^2.1.0",
|
|
4351
|
-
"@opentelemetry/semantic-conventions": "^1.37.0"
|
|
4352
|
-
|
|
4353
|
-
devDependencies: {
|
|
4354
|
-
"@cloudflare/workers-types": "^4.20251011.0",
|
|
4355
|
-
"@eslint/js": "^9.37.0",
|
|
4345
|
+
"@opentelemetry/semantic-conventions": "^1.37.0",
|
|
4346
|
+
"@supabase/supabase-js": "^2.75.0",
|
|
4356
4347
|
"@types/bun": "^1.3.0",
|
|
4357
4348
|
"@types/js-yaml": "^4.0.9",
|
|
4358
4349
|
"@types/node": "^24.7.2",
|
|
@@ -4363,21 +4354,43 @@ var init_package = __esm(() => {
|
|
|
4363
4354
|
"@vitest/coverage-v8": "3.2.4",
|
|
4364
4355
|
ajv: "^8.17.1",
|
|
4365
4356
|
"ajv-formats": "^3.0.1",
|
|
4357
|
+
axios: "^1.12.2",
|
|
4366
4358
|
"bun-types": "^1.3.0",
|
|
4359
|
+
"chrono-node": "^2.9.0",
|
|
4367
4360
|
clipboardy: "^5.0.0",
|
|
4368
4361
|
depcheck: "^1.4.7",
|
|
4362
|
+
dotenv: "^17.2.3",
|
|
4369
4363
|
eslint: "^9.37.0",
|
|
4370
4364
|
execa: "^9.6.0",
|
|
4365
|
+
"fast-xml-parser": "^5.3.0",
|
|
4371
4366
|
globals: "^16.4.0",
|
|
4367
|
+
hono: "^4.9.12",
|
|
4372
4368
|
husky: "^9.1.7",
|
|
4369
|
+
ignore: "^7.0.5",
|
|
4370
|
+
jose: "^6.1.0",
|
|
4371
|
+
"js-yaml": "^4.1.0",
|
|
4373
4372
|
msw: "^2.11.5",
|
|
4373
|
+
"node-cron": "^4.2.1",
|
|
4374
|
+
openai: "^6.3.0",
|
|
4375
|
+
papaparse: "^5.5.3",
|
|
4376
|
+
"partial-json": "^0.1.7",
|
|
4377
|
+
"pdf-lib": "^1.17.1",
|
|
4378
|
+
pino: "^10.0.0",
|
|
4379
|
+
"pino-pretty": "^13.1.2",
|
|
4374
4380
|
prettier: "^3.6.2",
|
|
4381
|
+
"reflect-metadata": "^0.2.2",
|
|
4382
|
+
repomix: "^1.7.0",
|
|
4383
|
+
"sanitize-html": "^2.17.0",
|
|
4384
|
+
tslib: "^2.8.1",
|
|
4385
|
+
tsyringe: "^4.10.0",
|
|
4375
4386
|
typedoc: "^0.28.14",
|
|
4376
4387
|
typescript: "^5.9.3",
|
|
4377
4388
|
"typescript-eslint": "8.46.0",
|
|
4389
|
+
validator: "13.15.15",
|
|
4378
4390
|
vite: "7.1.9",
|
|
4379
4391
|
"vite-tsconfig-paths": "^5.1.4",
|
|
4380
|
-
vitest: "^3.2.4"
|
|
4392
|
+
vitest: "^3.2.4",
|
|
4393
|
+
zod: "^3.23.8"
|
|
4381
4394
|
},
|
|
4382
4395
|
keywords: [
|
|
4383
4396
|
"ai-agent",
|
|
@@ -4574,6 +4587,10 @@ var import_dotenv, packageManifest, hasFileSystemAccess, emptyStringAsUndefined
|
|
|
4574
4587
|
git: {
|
|
4575
4588
|
provider: env.GIT_PROVIDER,
|
|
4576
4589
|
signCommits: env.GIT_SIGN_COMMITS,
|
|
4590
|
+
authorName: env.GIT_AUTHOR_NAME || env.GIT_USERNAME || env.GIT_USER || undefined,
|
|
4591
|
+
authorEmail: env.GIT_AUTHOR_EMAIL || env.GIT_EMAIL || env.GIT_USER_EMAIL || undefined,
|
|
4592
|
+
committerName: env.GIT_COMMITTER_NAME || env.GIT_USERNAME || env.GIT_USER || undefined,
|
|
4593
|
+
committerEmail: env.GIT_COMMITTER_EMAIL || env.GIT_EMAIL || env.GIT_USER_EMAIL || undefined,
|
|
4577
4594
|
wrapupInstructionsPath: env.GIT_WRAPUP_INSTRUCTIONS_PATH,
|
|
4578
4595
|
baseDir: env.GIT_BASE_DIR,
|
|
4579
4596
|
maxCommandTimeoutMs: env.GIT_MAX_COMMAND_TIMEOUT_MS,
|
|
@@ -4753,6 +4770,10 @@ var init_config = __esm(() => {
|
|
|
4753
4770
|
git: z.object({
|
|
4754
4771
|
provider: z.preprocess(emptyStringAsUndefined, z.enum(["auto", "cli", "isomorphic"]).default("auto")),
|
|
4755
4772
|
signCommits: z.coerce.boolean().default(false),
|
|
4773
|
+
authorName: z.string().optional(),
|
|
4774
|
+
authorEmail: z.string().email().optional(),
|
|
4775
|
+
committerName: z.string().optional(),
|
|
4776
|
+
committerEmail: z.string().email().optional(),
|
|
4756
4777
|
wrapupInstructionsPath: z.preprocess(expandTildePath, z.string().optional()),
|
|
4757
4778
|
baseDir: z.preprocess((val) => expandTildePath(emptyStringAsUndefined(val)), z.string().refine((path) => !path || path.startsWith("/"), {
|
|
4758
4779
|
message: 'GIT_BASE_DIR must be an absolute path starting with "/" (tilde expansion is supported)'
|
|
@@ -13784,7 +13805,7 @@ var require_propwrap = __commonJS((exports) => {
|
|
|
13784
13805
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13785
13806
|
exports.propwrap = undefined;
|
|
13786
13807
|
var __defProp2 = Object.defineProperty;
|
|
13787
|
-
var
|
|
13808
|
+
var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
|
|
13788
13809
|
var __hasOwnProp2 = Object.prototype.hasOwnProperty;
|
|
13789
13810
|
var __getOwnPropNames2 = Object.getOwnPropertyNames;
|
|
13790
13811
|
var __copyProps = (to, from, except, desc) => {
|
|
@@ -13793,7 +13814,7 @@ var require_propwrap = __commonJS((exports) => {
|
|
|
13793
13814
|
if (!__hasOwnProp2.call(to, key) && key !== except) {
|
|
13794
13815
|
__defProp2(to, key, {
|
|
13795
13816
|
get: () => from[key],
|
|
13796
|
-
enumerable: !(desc =
|
|
13817
|
+
enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable
|
|
13797
13818
|
});
|
|
13798
13819
|
}
|
|
13799
13820
|
}
|
|
@@ -13828,7 +13849,7 @@ var require_propwrap = __commonJS((exports) => {
|
|
|
13828
13849
|
} else {
|
|
13829
13850
|
val = namespaces[i + 1];
|
|
13830
13851
|
}
|
|
13831
|
-
const desc =
|
|
13852
|
+
const desc = __getOwnPropDesc2(namespace, key);
|
|
13832
13853
|
const wrappedNamespace = __defProp2({}, key, {
|
|
13833
13854
|
value: val,
|
|
13834
13855
|
enumerable: !desc || desc.enumerable
|
|
@@ -151663,6 +151684,14 @@ function buildGitCommand(config2) {
|
|
|
151663
151684
|
}
|
|
151664
151685
|
return parts;
|
|
151665
151686
|
}
|
|
151687
|
+
function loadConfig() {
|
|
151688
|
+
try {
|
|
151689
|
+
const configModule = (init_config(), __toCommonJS(exports_config));
|
|
151690
|
+
return configModule.config;
|
|
151691
|
+
} catch {
|
|
151692
|
+
return null;
|
|
151693
|
+
}
|
|
151694
|
+
}
|
|
151666
151695
|
function buildGitEnv(additionalEnv) {
|
|
151667
151696
|
const env = { ...process.env };
|
|
151668
151697
|
Object.assign(env, {
|
|
@@ -151670,6 +151699,21 @@ function buildGitEnv(additionalEnv) {
|
|
|
151670
151699
|
LANG: "en_US.UTF-8",
|
|
151671
151700
|
LC_ALL: "en_US.UTF-8"
|
|
151672
151701
|
});
|
|
151702
|
+
const config2 = loadConfig();
|
|
151703
|
+
if (config2?.git) {
|
|
151704
|
+
if (config2.git.authorName) {
|
|
151705
|
+
env.GIT_AUTHOR_NAME = config2.git.authorName;
|
|
151706
|
+
}
|
|
151707
|
+
if (config2.git.authorEmail) {
|
|
151708
|
+
env.GIT_AUTHOR_EMAIL = config2.git.authorEmail;
|
|
151709
|
+
}
|
|
151710
|
+
if (config2.git.committerName) {
|
|
151711
|
+
env.GIT_COMMITTER_NAME = config2.git.committerName;
|
|
151712
|
+
}
|
|
151713
|
+
if (config2.git.committerEmail) {
|
|
151714
|
+
env.GIT_COMMITTER_EMAIL = config2.git.committerEmail;
|
|
151715
|
+
}
|
|
151716
|
+
}
|
|
151673
151717
|
if (additionalEnv) {
|
|
151674
151718
|
Object.assign(env, additionalEnv);
|
|
151675
151719
|
}
|
|
@@ -151732,6 +151776,20 @@ function validateGitArgs(args) {
|
|
|
151732
151776
|
}
|
|
151733
151777
|
}
|
|
151734
151778
|
|
|
151779
|
+
// src/services/git/providers/cli/utils/config-helper.ts
|
|
151780
|
+
function loadConfig2() {
|
|
151781
|
+
try {
|
|
151782
|
+
const configModule = (init_config(), __toCommonJS(exports_config));
|
|
151783
|
+
return configModule.config;
|
|
151784
|
+
} catch {
|
|
151785
|
+
return null;
|
|
151786
|
+
}
|
|
151787
|
+
}
|
|
151788
|
+
function shouldSignCommits() {
|
|
151789
|
+
const config2 = loadConfig2();
|
|
151790
|
+
return config2?.git?.signCommits ?? false;
|
|
151791
|
+
}
|
|
151792
|
+
|
|
151735
151793
|
// src/services/git/providers/cli/utils/error-mapper.ts
|
|
151736
151794
|
init_errors();
|
|
151737
151795
|
var ERROR_PATTERNS = [
|
|
@@ -151871,13 +151929,24 @@ function detectRuntime2() {
|
|
|
151871
151929
|
}
|
|
151872
151930
|
return "node";
|
|
151873
151931
|
}
|
|
151874
|
-
async function spawnWithBun(args, cwd, env, timeout) {
|
|
151932
|
+
async function spawnWithBun(args, cwd, env, timeout, signal) {
|
|
151875
151933
|
const bunApi = globalThis.Bun;
|
|
151934
|
+
if (signal?.aborted) {
|
|
151935
|
+
throw new Error(`Git command cancelled before execution: git ${args.join(" ")}`);
|
|
151936
|
+
}
|
|
151876
151937
|
const proc = bunApi.spawn(["git", ...args], {
|
|
151877
151938
|
cwd,
|
|
151878
151939
|
env,
|
|
151879
151940
|
stdio: ["ignore", "pipe", "pipe"]
|
|
151880
151941
|
});
|
|
151942
|
+
const abortPromise = new Promise((_, reject) => {
|
|
151943
|
+
if (signal) {
|
|
151944
|
+
signal.addEventListener("abort", () => {
|
|
151945
|
+
proc.kill();
|
|
151946
|
+
reject(new Error(`Git command cancelled: git ${args.join(" ")}`));
|
|
151947
|
+
}, { once: true });
|
|
151948
|
+
}
|
|
151949
|
+
});
|
|
151881
151950
|
const timeoutPromise = new Promise((_, reject) => {
|
|
151882
151951
|
const timeoutId = setTimeout(() => {
|
|
151883
151952
|
proc.kill();
|
|
@@ -151885,7 +151954,11 @@ async function spawnWithBun(args, cwd, env, timeout) {
|
|
|
151885
151954
|
}, timeout);
|
|
151886
151955
|
proc.exited.finally(() => clearTimeout(timeoutId));
|
|
151887
151956
|
});
|
|
151888
|
-
const exitCode = await Promise.race([
|
|
151957
|
+
const exitCode = await Promise.race([
|
|
151958
|
+
proc.exited,
|
|
151959
|
+
timeoutPromise,
|
|
151960
|
+
...signal ? [abortPromise] : []
|
|
151961
|
+
]);
|
|
151889
151962
|
const [stdout, stderr] = await Promise.all([
|
|
151890
151963
|
proc.stdout.text(),
|
|
151891
151964
|
proc.stderr.text()
|
|
@@ -151898,8 +151971,12 @@ Stdout: ${stdout}`;
|
|
|
151898
151971
|
}
|
|
151899
151972
|
return { stdout, stderr };
|
|
151900
151973
|
}
|
|
151901
|
-
async function spawnWithNode(args, cwd, env, timeout) {
|
|
151974
|
+
async function spawnWithNode(args, cwd, env, timeout, signal) {
|
|
151902
151975
|
return new Promise((resolve, reject) => {
|
|
151976
|
+
if (signal?.aborted) {
|
|
151977
|
+
reject(new Error(`Git command cancelled before execution: ${args.join(" ")}`));
|
|
151978
|
+
return;
|
|
151979
|
+
}
|
|
151903
151980
|
const proc = spawn("git", args, {
|
|
151904
151981
|
cwd,
|
|
151905
151982
|
env,
|
|
@@ -151913,16 +151990,29 @@ async function spawnWithNode(args, cwd, env, timeout) {
|
|
|
151913
151990
|
proc.stderr.on("data", (chunk) => {
|
|
151914
151991
|
stderrChunks.push(chunk);
|
|
151915
151992
|
});
|
|
151993
|
+
const abortHandler = () => {
|
|
151994
|
+
proc.kill("SIGTERM");
|
|
151995
|
+
reject(new Error(`Git command cancelled: ${args.join(" ")}`));
|
|
151996
|
+
};
|
|
151997
|
+
if (signal) {
|
|
151998
|
+
signal.addEventListener("abort", abortHandler, { once: true });
|
|
151999
|
+
}
|
|
151916
152000
|
const timeoutHandle = setTimeout(() => {
|
|
151917
152001
|
proc.kill("SIGTERM");
|
|
151918
152002
|
reject(new Error(`Git command timed out after ${timeout / 1000}s: ${args.join(" ")}`));
|
|
151919
152003
|
}, timeout);
|
|
151920
152004
|
proc.on("error", (error) => {
|
|
151921
152005
|
clearTimeout(timeoutHandle);
|
|
152006
|
+
if (signal) {
|
|
152007
|
+
signal.removeEventListener("abort", abortHandler);
|
|
152008
|
+
}
|
|
151922
152009
|
reject(error);
|
|
151923
152010
|
});
|
|
151924
152011
|
proc.on("close", (exitCode) => {
|
|
151925
152012
|
clearTimeout(timeoutHandle);
|
|
152013
|
+
if (signal) {
|
|
152014
|
+
signal.removeEventListener("abort", abortHandler);
|
|
152015
|
+
}
|
|
151926
152016
|
const stdout = Buffer.concat(stdoutChunks).toString("utf-8");
|
|
151927
152017
|
const stderr = Buffer.concat(stderrChunks).toString("utf-8");
|
|
151928
152018
|
if (exitCode !== 0) {
|
|
@@ -151936,12 +152026,12 @@ Stdout: ${stdout}`;
|
|
|
151936
152026
|
});
|
|
151937
152027
|
});
|
|
151938
152028
|
}
|
|
151939
|
-
async function spawnGitCommand(args, cwd, env, timeout = 60000) {
|
|
152029
|
+
async function spawnGitCommand(args, cwd, env, timeout = 60000, signal) {
|
|
151940
152030
|
const runtime2 = detectRuntime2();
|
|
151941
152031
|
if (runtime2 === "bun") {
|
|
151942
|
-
return spawnWithBun(args, cwd, env, timeout);
|
|
152032
|
+
return spawnWithBun(args, cwd, env, timeout, signal);
|
|
151943
152033
|
} else {
|
|
151944
|
-
return spawnWithNode(args, cwd, env, timeout);
|
|
152034
|
+
return spawnWithNode(args, cwd, env, timeout, signal);
|
|
151945
152035
|
}
|
|
151946
152036
|
}
|
|
151947
152037
|
|
|
@@ -152327,7 +152417,8 @@ async function executeCommit(options, context, execGit) {
|
|
|
152327
152417
|
if (options.noVerify) {
|
|
152328
152418
|
args.push("--no-verify");
|
|
152329
152419
|
}
|
|
152330
|
-
|
|
152420
|
+
const shouldSign = options.sign ?? shouldSignCommits();
|
|
152421
|
+
if (shouldSign) {
|
|
152331
152422
|
args.push("--gpg-sign");
|
|
152332
152423
|
}
|
|
152333
152424
|
if (options.author) {
|
|
@@ -152627,6 +152718,10 @@ async function executeMerge(options, context, execGit) {
|
|
|
152627
152718
|
if (options.message) {
|
|
152628
152719
|
args.push("-m", options.message);
|
|
152629
152720
|
}
|
|
152721
|
+
const shouldSign = options.sign ?? shouldSignCommits();
|
|
152722
|
+
if (shouldSign) {
|
|
152723
|
+
args.push("-S");
|
|
152724
|
+
}
|
|
152630
152725
|
const cmd = buildGitCommand({ command: "merge", args });
|
|
152631
152726
|
const result = await execGit(cmd, context.workingDirectory, context.requestContext);
|
|
152632
152727
|
const hasConflicts = result.stdout.includes("CONFLICT") || result.stderr.includes("CONFLICT");
|
|
@@ -152706,6 +152801,10 @@ async function executeRebase(options, context, execGit) {
|
|
|
152706
152801
|
if (options.preserve) {
|
|
152707
152802
|
args.push("--preserve-merges");
|
|
152708
152803
|
}
|
|
152804
|
+
const shouldSign = options.sign ?? shouldSignCommits();
|
|
152805
|
+
if (shouldSign) {
|
|
152806
|
+
args.push("--gpg-sign");
|
|
152807
|
+
}
|
|
152709
152808
|
}
|
|
152710
152809
|
const cmd = buildGitCommand({ command: "rebase", args });
|
|
152711
152810
|
const result = await execGit(cmd, context.workingDirectory, context.requestContext);
|
|
@@ -152741,6 +152840,10 @@ async function executeCherryPick(options, context, execGit) {
|
|
|
152741
152840
|
if (options.noCommit) {
|
|
152742
152841
|
args.push("--no-commit");
|
|
152743
152842
|
}
|
|
152843
|
+
const shouldSign = options.sign ?? shouldSignCommits();
|
|
152844
|
+
if (shouldSign) {
|
|
152845
|
+
args.push("--gpg-sign");
|
|
152846
|
+
}
|
|
152744
152847
|
}
|
|
152745
152848
|
const cmd = buildGitCommand({ command: "cherry-pick", args });
|
|
152746
152849
|
const result = await execGit(cmd, context.workingDirectory, context.requestContext);
|
|
@@ -153041,7 +153144,11 @@ async function executeTag(options, context, execGit) {
|
|
|
153041
153144
|
throw new Error("Tag name is required for create operation");
|
|
153042
153145
|
}
|
|
153043
153146
|
args.push(options.tagName);
|
|
153044
|
-
|
|
153147
|
+
const shouldSign = options.sign ?? shouldSignCommits();
|
|
153148
|
+
if (shouldSign) {
|
|
153149
|
+
const message = options.message || `Tag ${options.tagName}`;
|
|
153150
|
+
args.push("-s", "-m", message);
|
|
153151
|
+
} else if (options.message && options.annotated) {
|
|
153045
153152
|
args.push("-a", "-m", options.message);
|
|
153046
153153
|
}
|
|
153047
153154
|
if (options.commit) {
|
|
@@ -172049,6 +172156,163 @@ var httpErrorHandler = async (err, c) => {
|
|
|
172049
172156
|
return c.json(errorResponse);
|
|
172050
172157
|
};
|
|
172051
172158
|
|
|
172159
|
+
// src/mcp-server/transports/http/sessionManager.ts
|
|
172160
|
+
init_utils();
|
|
172161
|
+
|
|
172162
|
+
class SessionManager {
|
|
172163
|
+
static instance = null;
|
|
172164
|
+
sessions = new Map;
|
|
172165
|
+
cleanupIntervalId = null;
|
|
172166
|
+
staleTimeoutMs;
|
|
172167
|
+
cleanupIntervalMs;
|
|
172168
|
+
constructor(staleTimeoutMs = 30 * 60 * 1000, cleanupIntervalMs = 5 * 60 * 1000) {
|
|
172169
|
+
this.staleTimeoutMs = staleTimeoutMs;
|
|
172170
|
+
this.cleanupIntervalMs = cleanupIntervalMs;
|
|
172171
|
+
this.startCleanupInterval();
|
|
172172
|
+
}
|
|
172173
|
+
static getInstance(staleTimeoutMs, cleanupIntervalMs) {
|
|
172174
|
+
if (!SessionManager.instance) {
|
|
172175
|
+
SessionManager.instance = new SessionManager(staleTimeoutMs, cleanupIntervalMs);
|
|
172176
|
+
}
|
|
172177
|
+
return SessionManager.instance;
|
|
172178
|
+
}
|
|
172179
|
+
static resetInstance() {
|
|
172180
|
+
if (SessionManager.instance) {
|
|
172181
|
+
SessionManager.instance.stopCleanupInterval();
|
|
172182
|
+
SessionManager.instance = null;
|
|
172183
|
+
}
|
|
172184
|
+
}
|
|
172185
|
+
createSession(sessionId, clientId, tenantId) {
|
|
172186
|
+
const now2 = Date.now();
|
|
172187
|
+
const metadata = {
|
|
172188
|
+
sessionId,
|
|
172189
|
+
createdAt: now2,
|
|
172190
|
+
lastActivityAt: now2,
|
|
172191
|
+
...clientId !== undefined && { clientId },
|
|
172192
|
+
...tenantId !== undefined && { tenantId }
|
|
172193
|
+
};
|
|
172194
|
+
this.sessions.set(sessionId, metadata);
|
|
172195
|
+
logger.debug("Created new MCP session", {
|
|
172196
|
+
...requestContextService.createRequestContext({
|
|
172197
|
+
operation: "SessionManager.createSession"
|
|
172198
|
+
}),
|
|
172199
|
+
sessionId,
|
|
172200
|
+
...clientId !== undefined && { clientId },
|
|
172201
|
+
...tenantId !== undefined && { tenantId },
|
|
172202
|
+
totalSessions: this.sessions.size
|
|
172203
|
+
});
|
|
172204
|
+
return sessionId;
|
|
172205
|
+
}
|
|
172206
|
+
isSessionValid(sessionId) {
|
|
172207
|
+
const session = this.sessions.get(sessionId);
|
|
172208
|
+
if (!session) {
|
|
172209
|
+
return false;
|
|
172210
|
+
}
|
|
172211
|
+
const now2 = Date.now();
|
|
172212
|
+
const age = now2 - session.lastActivityAt;
|
|
172213
|
+
if (age > this.staleTimeoutMs) {
|
|
172214
|
+
logger.info("Session expired due to inactivity", {
|
|
172215
|
+
...requestContextService.createRequestContext({
|
|
172216
|
+
operation: "SessionManager.isSessionValid"
|
|
172217
|
+
}),
|
|
172218
|
+
sessionId,
|
|
172219
|
+
ageMs: age,
|
|
172220
|
+
staleTimeoutMs: this.staleTimeoutMs
|
|
172221
|
+
});
|
|
172222
|
+
this.sessions.delete(sessionId);
|
|
172223
|
+
return false;
|
|
172224
|
+
}
|
|
172225
|
+
return true;
|
|
172226
|
+
}
|
|
172227
|
+
touchSession(sessionId) {
|
|
172228
|
+
const session = this.sessions.get(sessionId);
|
|
172229
|
+
if (session) {
|
|
172230
|
+
session.lastActivityAt = Date.now();
|
|
172231
|
+
}
|
|
172232
|
+
}
|
|
172233
|
+
terminateSession(sessionId) {
|
|
172234
|
+
const existed = this.sessions.has(sessionId);
|
|
172235
|
+
this.sessions.delete(sessionId);
|
|
172236
|
+
if (existed) {
|
|
172237
|
+
logger.info("Session explicitly terminated", {
|
|
172238
|
+
...requestContextService.createRequestContext({
|
|
172239
|
+
operation: "SessionManager.terminateSession"
|
|
172240
|
+
}),
|
|
172241
|
+
sessionId,
|
|
172242
|
+
remainingSessions: this.sessions.size
|
|
172243
|
+
});
|
|
172244
|
+
}
|
|
172245
|
+
return existed;
|
|
172246
|
+
}
|
|
172247
|
+
getSessionMetadata(sessionId) {
|
|
172248
|
+
if (!this.isSessionValid(sessionId)) {
|
|
172249
|
+
return null;
|
|
172250
|
+
}
|
|
172251
|
+
return this.sessions.get(sessionId) ?? null;
|
|
172252
|
+
}
|
|
172253
|
+
getActiveSessionCount() {
|
|
172254
|
+
return this.sessions.size;
|
|
172255
|
+
}
|
|
172256
|
+
startCleanupInterval() {
|
|
172257
|
+
if (this.cleanupIntervalId) {
|
|
172258
|
+
return;
|
|
172259
|
+
}
|
|
172260
|
+
this.cleanupIntervalId = setInterval(() => {
|
|
172261
|
+
this.cleanupStaleSessions();
|
|
172262
|
+
}, this.cleanupIntervalMs);
|
|
172263
|
+
logger.info("Session cleanup interval started", {
|
|
172264
|
+
...requestContextService.createRequestContext({
|
|
172265
|
+
operation: "SessionManager.startCleanupInterval"
|
|
172266
|
+
}),
|
|
172267
|
+
cleanupIntervalMs: this.cleanupIntervalMs,
|
|
172268
|
+
staleTimeoutMs: this.staleTimeoutMs
|
|
172269
|
+
});
|
|
172270
|
+
}
|
|
172271
|
+
stopCleanupInterval() {
|
|
172272
|
+
if (this.cleanupIntervalId) {
|
|
172273
|
+
clearInterval(this.cleanupIntervalId);
|
|
172274
|
+
this.cleanupIntervalId = null;
|
|
172275
|
+
logger.info("Session cleanup interval stopped", {
|
|
172276
|
+
...requestContextService.createRequestContext({
|
|
172277
|
+
operation: "SessionManager.stopCleanupInterval"
|
|
172278
|
+
})
|
|
172279
|
+
});
|
|
172280
|
+
}
|
|
172281
|
+
}
|
|
172282
|
+
cleanupStaleSessions() {
|
|
172283
|
+
const now2 = Date.now();
|
|
172284
|
+
const sessionsBefore = this.sessions.size;
|
|
172285
|
+
let removedCount = 0;
|
|
172286
|
+
for (const [sessionId, metadata] of this.sessions.entries()) {
|
|
172287
|
+
const age = now2 - metadata.lastActivityAt;
|
|
172288
|
+
if (age > this.staleTimeoutMs) {
|
|
172289
|
+
this.sessions.delete(sessionId);
|
|
172290
|
+
removedCount++;
|
|
172291
|
+
}
|
|
172292
|
+
}
|
|
172293
|
+
if (removedCount > 0) {
|
|
172294
|
+
logger.notice("Cleaned up stale sessions", {
|
|
172295
|
+
...requestContextService.createRequestContext({
|
|
172296
|
+
operation: "SessionManager.cleanupStaleSessions"
|
|
172297
|
+
}),
|
|
172298
|
+
removedCount,
|
|
172299
|
+
sessionsBefore,
|
|
172300
|
+
sessionsAfter: this.sessions.size
|
|
172301
|
+
});
|
|
172302
|
+
}
|
|
172303
|
+
}
|
|
172304
|
+
clearAllSessions() {
|
|
172305
|
+
const count = this.sessions.size;
|
|
172306
|
+
this.sessions.clear();
|
|
172307
|
+
logger.warning("All sessions cleared", {
|
|
172308
|
+
...requestContextService.createRequestContext({
|
|
172309
|
+
operation: "SessionManager.clearAllSessions"
|
|
172310
|
+
}),
|
|
172311
|
+
clearedCount: count
|
|
172312
|
+
});
|
|
172313
|
+
}
|
|
172314
|
+
}
|
|
172315
|
+
|
|
172052
172316
|
// src/mcp-server/transports/http/httpTransport.ts
|
|
172053
172317
|
init_utils();
|
|
172054
172318
|
|
|
@@ -172065,6 +172329,11 @@ function createHttpApp(mcpServer, parentContext) {
|
|
|
172065
172329
|
...parentContext,
|
|
172066
172330
|
component: "HttpTransportSetup"
|
|
172067
172331
|
};
|
|
172332
|
+
const sessionManager = SessionManager.getInstance(config.mcpStatefulSessionStaleTimeoutMs);
|
|
172333
|
+
logger.info("Session manager initialized", {
|
|
172334
|
+
...transportContext,
|
|
172335
|
+
staleTimeoutMs: config.mcpStatefulSessionStaleTimeoutMs
|
|
172336
|
+
});
|
|
172068
172337
|
const allowedOrigin = Array.isArray(config.mcpAllowedOrigins) && config.mcpAllowedOrigins.length > 0 ? config.mcpAllowedOrigins : "*";
|
|
172069
172338
|
app.use("*", cors({
|
|
172070
172339
|
origin: allowedOrigin,
|
|
@@ -172113,6 +172382,35 @@ function createHttpApp(mcpServer, parentContext) {
|
|
|
172113
172382
|
} else {
|
|
172114
172383
|
logger.info("Authentication is disabled; MCP endpoint is unprotected.", transportContext);
|
|
172115
172384
|
}
|
|
172385
|
+
app.delete(config.mcpHttpEndpointPath, (c) => {
|
|
172386
|
+
const sessionId = c.req.header("mcp-session-id");
|
|
172387
|
+
if (!sessionId) {
|
|
172388
|
+
return c.json({
|
|
172389
|
+
jsonrpc: "2.0",
|
|
172390
|
+
error: {
|
|
172391
|
+
code: -32600,
|
|
172392
|
+
message: "Mcp-Session-Id header required for DELETE"
|
|
172393
|
+
},
|
|
172394
|
+
id: null
|
|
172395
|
+
}, 400);
|
|
172396
|
+
}
|
|
172397
|
+
const terminated = sessionManager.terminateSession(sessionId);
|
|
172398
|
+
if (!terminated) {
|
|
172399
|
+
return c.json({
|
|
172400
|
+
jsonrpc: "2.0",
|
|
172401
|
+
error: {
|
|
172402
|
+
code: -32001,
|
|
172403
|
+
message: "Session not found or already expired"
|
|
172404
|
+
},
|
|
172405
|
+
id: null
|
|
172406
|
+
}, 404);
|
|
172407
|
+
}
|
|
172408
|
+
logger.info("Session terminated via DELETE", {
|
|
172409
|
+
...transportContext,
|
|
172410
|
+
sessionId
|
|
172411
|
+
});
|
|
172412
|
+
return c.body(null, 204);
|
|
172413
|
+
});
|
|
172116
172414
|
app.all(config.mcpHttpEndpointPath, async (c) => {
|
|
172117
172415
|
const protocolVersion = c.req.header("mcp-protocol-version") ?? "2025-03-26";
|
|
172118
172416
|
logger.debug("Handling MCP request.", {
|
|
@@ -172128,12 +172426,50 @@ function createHttpApp(mcpServer, parentContext) {
|
|
|
172128
172426
|
protocolVersion,
|
|
172129
172427
|
supportedVersions
|
|
172130
172428
|
});
|
|
172429
|
+
return c.json({
|
|
172430
|
+
jsonrpc: "2.0",
|
|
172431
|
+
error: {
|
|
172432
|
+
code: -32600,
|
|
172433
|
+
message: `Unsupported MCP protocol version: ${protocolVersion}`,
|
|
172434
|
+
data: {
|
|
172435
|
+
requested: protocolVersion,
|
|
172436
|
+
supported: supportedVersions
|
|
172437
|
+
}
|
|
172438
|
+
},
|
|
172439
|
+
id: null
|
|
172440
|
+
}, 400);
|
|
172131
172441
|
}
|
|
172132
172442
|
const sessionId = c.req.header("mcp-session-id") ?? randomUUID();
|
|
172443
|
+
if (c.req.header("mcp-session-id") && !sessionManager.isSessionValid(sessionId)) {
|
|
172444
|
+
logger.warning("Invalid or expired session ID", {
|
|
172445
|
+
...transportContext,
|
|
172446
|
+
sessionId
|
|
172447
|
+
});
|
|
172448
|
+
return c.json({
|
|
172449
|
+
jsonrpc: "2.0",
|
|
172450
|
+
error: {
|
|
172451
|
+
code: -32001,
|
|
172452
|
+
message: "Session expired or invalid. Please reinitialize."
|
|
172453
|
+
},
|
|
172454
|
+
id: null
|
|
172455
|
+
}, 404);
|
|
172456
|
+
}
|
|
172457
|
+
if (!c.req.header("mcp-session-id")) {
|
|
172458
|
+
logger.debug("New session will be created", {
|
|
172459
|
+
...transportContext,
|
|
172460
|
+
sessionId
|
|
172461
|
+
});
|
|
172462
|
+
} else {
|
|
172463
|
+
sessionManager.touchSession(sessionId);
|
|
172464
|
+
}
|
|
172133
172465
|
const transport = new McpSessionTransport(sessionId);
|
|
172134
172466
|
const handleRpc = async () => {
|
|
172135
172467
|
await mcpServer.connect(transport);
|
|
172136
172468
|
const response = await transport.handleRequest(c);
|
|
172469
|
+
if (response && !c.req.header("mcp-session-id")) {
|
|
172470
|
+
const store = authContext.getStore();
|
|
172471
|
+
sessionManager.createSession(sessionId, store?.authInfo.clientId, store?.authInfo.tenantId);
|
|
172472
|
+
}
|
|
172137
172473
|
if (response) {
|
|
172138
172474
|
return response;
|
|
172139
172475
|
}
|
|
@@ -172229,6 +172565,9 @@ async function stopHttpTransport(server, parentContext) {
|
|
|
172229
172565
|
transportType: "Http"
|
|
172230
172566
|
};
|
|
172231
172567
|
logger.info("Attempting to stop http transport...", operationContext);
|
|
172568
|
+
const sessionManager = SessionManager.getInstance();
|
|
172569
|
+
sessionManager.stopCleanupInterval();
|
|
172570
|
+
logger.info("Session cleanup interval stopped", operationContext);
|
|
172232
172571
|
return new Promise((resolve, reject) => {
|
|
172233
172572
|
server.close((err) => {
|
|
172234
172573
|
if (err) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyanheads/git-mcp-server",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.1",
|
|
4
4
|
"mcpName": "io.github.cyanheads/git-mcp-server",
|
|
5
5
|
"description": "A secure and scalable Git MCP server enabling AI agents to perform comprehensive Git version control operations via STDIO and Streamable HTTP.",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -66,33 +66,12 @@
|
|
|
66
66
|
"zod": "3.23.8",
|
|
67
67
|
"typescript": "5.9.3"
|
|
68
68
|
},
|
|
69
|
-
"
|
|
69
|
+
"devDependencies": {
|
|
70
|
+
"@cloudflare/workers-types": "^4.20251011.0",
|
|
71
|
+
"@eslint/js": "^9.37.0",
|
|
70
72
|
"@hono/mcp": "^0.1.4",
|
|
71
73
|
"@hono/node-server": "^1.19.5",
|
|
72
74
|
"@modelcontextprotocol/sdk": "^1.20.0",
|
|
73
|
-
"@supabase/supabase-js": "^2.75.0",
|
|
74
|
-
"axios": "^1.12.2",
|
|
75
|
-
"chrono-node": "^2.9.0",
|
|
76
|
-
"dotenv": "^17.2.3",
|
|
77
|
-
"fast-xml-parser": "^5.3.0",
|
|
78
|
-
"hono": "^4.9.12",
|
|
79
|
-
"ignore": "^7.0.5",
|
|
80
|
-
"jose": "^6.1.0",
|
|
81
|
-
"js-yaml": "^4.1.0",
|
|
82
|
-
"node-cron": "^4.2.1",
|
|
83
|
-
"openai": "^6.3.0",
|
|
84
|
-
"papaparse": "^5.5.3",
|
|
85
|
-
"partial-json": "^0.1.7",
|
|
86
|
-
"pdf-lib": "^1.17.1",
|
|
87
|
-
"pino": "^10.0.0",
|
|
88
|
-
"pino-pretty": "^13.1.2",
|
|
89
|
-
"reflect-metadata": "^0.2.2",
|
|
90
|
-
"repomix": "^1.7.0",
|
|
91
|
-
"sanitize-html": "^2.17.0",
|
|
92
|
-
"tslib": "^2.8.1",
|
|
93
|
-
"tsyringe": "^4.10.0",
|
|
94
|
-
"validator": "13.15.15",
|
|
95
|
-
"zod": "^3.23.8",
|
|
96
75
|
"@opentelemetry/api": "^1.9.0",
|
|
97
76
|
"@opentelemetry/auto-instrumentations-node": "^0.65.0",
|
|
98
77
|
"@opentelemetry/exporter-metrics-otlp-http": "^0.206.0",
|
|
@@ -102,11 +81,8 @@
|
|
|
102
81
|
"@opentelemetry/sdk-metrics": "^2.1.0",
|
|
103
82
|
"@opentelemetry/sdk-node": "^0.206.0",
|
|
104
83
|
"@opentelemetry/sdk-trace-node": "^2.1.0",
|
|
105
|
-
"@opentelemetry/semantic-conventions": "^1.37.0"
|
|
106
|
-
|
|
107
|
-
"devDependencies": {
|
|
108
|
-
"@cloudflare/workers-types": "^4.20251011.0",
|
|
109
|
-
"@eslint/js": "^9.37.0",
|
|
84
|
+
"@opentelemetry/semantic-conventions": "^1.37.0",
|
|
85
|
+
"@supabase/supabase-js": "^2.75.0",
|
|
110
86
|
"@types/bun": "^1.3.0",
|
|
111
87
|
"@types/js-yaml": "^4.0.9",
|
|
112
88
|
"@types/node": "^24.7.2",
|
|
@@ -117,21 +93,43 @@
|
|
|
117
93
|
"@vitest/coverage-v8": "3.2.4",
|
|
118
94
|
"ajv": "^8.17.1",
|
|
119
95
|
"ajv-formats": "^3.0.1",
|
|
96
|
+
"axios": "^1.12.2",
|
|
120
97
|
"bun-types": "^1.3.0",
|
|
98
|
+
"chrono-node": "^2.9.0",
|
|
121
99
|
"clipboardy": "^5.0.0",
|
|
122
100
|
"depcheck": "^1.4.7",
|
|
101
|
+
"dotenv": "^17.2.3",
|
|
123
102
|
"eslint": "^9.37.0",
|
|
124
103
|
"execa": "^9.6.0",
|
|
104
|
+
"fast-xml-parser": "^5.3.0",
|
|
125
105
|
"globals": "^16.4.0",
|
|
106
|
+
"hono": "^4.9.12",
|
|
126
107
|
"husky": "^9.1.7",
|
|
108
|
+
"ignore": "^7.0.5",
|
|
109
|
+
"jose": "^6.1.0",
|
|
110
|
+
"js-yaml": "^4.1.0",
|
|
127
111
|
"msw": "^2.11.5",
|
|
112
|
+
"node-cron": "^4.2.1",
|
|
113
|
+
"openai": "^6.3.0",
|
|
114
|
+
"papaparse": "^5.5.3",
|
|
115
|
+
"partial-json": "^0.1.7",
|
|
116
|
+
"pdf-lib": "^1.17.1",
|
|
117
|
+
"pino": "^10.0.0",
|
|
118
|
+
"pino-pretty": "^13.1.2",
|
|
128
119
|
"prettier": "^3.6.2",
|
|
120
|
+
"reflect-metadata": "^0.2.2",
|
|
121
|
+
"repomix": "^1.7.0",
|
|
122
|
+
"sanitize-html": "^2.17.0",
|
|
123
|
+
"tslib": "^2.8.1",
|
|
124
|
+
"tsyringe": "^4.10.0",
|
|
129
125
|
"typedoc": "^0.28.14",
|
|
130
126
|
"typescript": "^5.9.3",
|
|
131
127
|
"typescript-eslint": "8.46.0",
|
|
128
|
+
"validator": "13.15.15",
|
|
132
129
|
"vite": "7.1.9",
|
|
133
130
|
"vite-tsconfig-paths": "^5.1.4",
|
|
134
|
-
"vitest": "^3.2.4"
|
|
131
|
+
"vitest": "^3.2.4",
|
|
132
|
+
"zod": "^3.23.8"
|
|
135
133
|
},
|
|
136
134
|
"keywords": [
|
|
137
135
|
"ai-agent",
|