@posthog/agent 2.3.643 → 2.3.655

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.
Files changed (37) hide show
  1. package/dist/adapters/claude/permissions/permission-options.js +700 -0
  2. package/dist/adapters/claude/permissions/permission-options.js.map +1 -1
  3. package/dist/adapters/claude/tools.js +700 -0
  4. package/dist/adapters/claude/tools.js.map +1 -1
  5. package/dist/adapters/codex/local-tools-mcp-server.d.ts +2 -0
  6. package/dist/adapters/codex/local-tools-mcp-server.js +1172 -0
  7. package/dist/adapters/codex/local-tools-mcp-server.js.map +1 -0
  8. package/dist/agent.js +1488 -219
  9. package/dist/agent.js.map +1 -1
  10. package/dist/execution-mode.js +700 -0
  11. package/dist/execution-mode.js.map +1 -1
  12. package/dist/handoff-checkpoint.js.map +1 -1
  13. package/dist/posthog-api.js +1 -1
  14. package/dist/posthog-api.js.map +1 -1
  15. package/dist/server/agent-server.js +1604 -339
  16. package/dist/server/agent-server.js.map +1 -1
  17. package/dist/server/bin.cjs +1520 -258
  18. package/dist/server/bin.cjs.map +1 -1
  19. package/package.json +3 -3
  20. package/src/adapters/claude/claude-agent.ts +32 -2
  21. package/src/adapters/claude/hooks.test.ts +54 -0
  22. package/src/adapters/claude/hooks.ts +86 -0
  23. package/src/adapters/claude/mcp/local-tools.test.ts +50 -0
  24. package/src/adapters/claude/mcp/local-tools.ts +40 -0
  25. package/src/adapters/claude/session/options.ts +14 -9
  26. package/src/adapters/claude/types.ts +1 -0
  27. package/src/adapters/codex/codex-agent.ts +117 -22
  28. package/src/adapters/codex/local-tools-mcp-server.ts +71 -0
  29. package/src/adapters/local-tools/index.ts +22 -0
  30. package/src/adapters/local-tools/registry.test.ts +57 -0
  31. package/src/adapters/local-tools/registry.ts +81 -0
  32. package/src/adapters/local-tools/tools/signed-commit.ts +26 -0
  33. package/src/adapters/session-meta.ts +16 -0
  34. package/src/adapters/signed-commit-shared.ts +82 -0
  35. package/src/server/agent-server.test.ts +2 -4
  36. package/src/server/agent-server.ts +27 -30
  37. package/src/utils/common.ts +14 -0
@@ -0,0 +1,1172 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __commonJS = (cb, mod) => function __require() {
8
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
19
+ // If the importer is in node compatibility mode or this is not an ESM
20
+ // file that has been converted to a CommonJS file using a Babel-
21
+ // compatible transform (i.e. "__esModule" has not been set), then set
22
+ // "default" to the CommonJS "module.exports" for node compatibility.
23
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
24
+ mod
25
+ ));
26
+
27
+ // ../../node_modules/protocols/lib/index.js
28
+ var require_lib = __commonJS({
29
+ "../../node_modules/protocols/lib/index.js"(exports, module) {
30
+ "use strict";
31
+ module.exports = function protocols(input, first) {
32
+ if (first === true) {
33
+ first = 0;
34
+ }
35
+ var prots = "";
36
+ if (typeof input === "string") {
37
+ try {
38
+ prots = new URL(input).protocol;
39
+ } catch (e) {
40
+ }
41
+ } else if (input && input.constructor === URL) {
42
+ prots = input.protocol;
43
+ }
44
+ var splits = prots.split(/\:|\+/).filter(Boolean);
45
+ if (typeof first === "number") {
46
+ return splits[first];
47
+ }
48
+ return splits;
49
+ };
50
+ }
51
+ });
52
+
53
+ // ../../node_modules/parse-path/lib/index.js
54
+ var require_lib2 = __commonJS({
55
+ "../../node_modules/parse-path/lib/index.js"(exports, module) {
56
+ "use strict";
57
+ var protocols = require_lib();
58
+ function parsePath(url) {
59
+ var output = {
60
+ protocols: [],
61
+ protocol: null,
62
+ port: null,
63
+ resource: "",
64
+ host: "",
65
+ user: "",
66
+ password: "",
67
+ pathname: "",
68
+ hash: "",
69
+ search: "",
70
+ href: url,
71
+ query: {},
72
+ parse_failed: false
73
+ };
74
+ try {
75
+ var parsed2 = new URL(url);
76
+ output.protocols = protocols(parsed2);
77
+ output.protocol = output.protocols[0];
78
+ output.port = parsed2.port;
79
+ output.resource = parsed2.hostname;
80
+ output.host = parsed2.host;
81
+ output.user = parsed2.username || "";
82
+ output.password = parsed2.password || "";
83
+ output.pathname = parsed2.pathname;
84
+ output.hash = parsed2.hash.slice(1);
85
+ output.search = parsed2.search.slice(1);
86
+ output.href = parsed2.href;
87
+ output.query = Object.fromEntries(parsed2.searchParams);
88
+ } catch (e) {
89
+ output.protocols = ["file"];
90
+ output.protocol = output.protocols[0];
91
+ output.port = "";
92
+ output.resource = "";
93
+ output.user = "";
94
+ output.pathname = "";
95
+ output.hash = "";
96
+ output.search = "";
97
+ output.href = url;
98
+ output.query = {};
99
+ output.parse_failed = true;
100
+ }
101
+ return output;
102
+ }
103
+ module.exports = parsePath;
104
+ }
105
+ });
106
+
107
+ // ../../node_modules/parse-url/dist/index.js
108
+ var require_dist = __commonJS({
109
+ "../../node_modules/parse-url/dist/index.js"(exports, module) {
110
+ "use strict";
111
+ var require$$1 = require_lib2();
112
+ function _interopDefaultLegacy(e) {
113
+ return e && typeof e === "object" && "default" in e ? e : { "default": e };
114
+ }
115
+ var require$$1__default = /* @__PURE__ */ _interopDefaultLegacy(require$$1);
116
+ function getAugmentedNamespace(n) {
117
+ if (n.__esModule) return n;
118
+ var f = n.default;
119
+ if (typeof f == "function") {
120
+ var a = function a2() {
121
+ if (this instanceof a2) {
122
+ var args = [null];
123
+ args.push.apply(args, arguments);
124
+ var Ctor = Function.bind.apply(f, args);
125
+ return new Ctor();
126
+ }
127
+ return f.apply(this, arguments);
128
+ };
129
+ a.prototype = f.prototype;
130
+ } else a = {};
131
+ Object.defineProperty(a, "__esModule", { value: true });
132
+ Object.keys(n).forEach(function(k) {
133
+ var d = Object.getOwnPropertyDescriptor(n, k);
134
+ Object.defineProperty(a, k, d.get ? d : {
135
+ enumerable: true,
136
+ get: function() {
137
+ return n[k];
138
+ }
139
+ });
140
+ });
141
+ return a;
142
+ }
143
+ var src = {};
144
+ var DATA_URL_DEFAULT_MIME_TYPE = "text/plain";
145
+ var DATA_URL_DEFAULT_CHARSET = "us-ascii";
146
+ var testParameter = (name, filters) => filters.some((filter) => filter instanceof RegExp ? filter.test(name) : filter === name);
147
+ var normalizeDataURL = (urlString, { stripHash }) => {
148
+ const match = /^data:(?<type>[^,]*?),(?<data>[^#]*?)(?:#(?<hash>.*))?$/.exec(urlString);
149
+ if (!match) {
150
+ throw new Error(`Invalid URL: ${urlString}`);
151
+ }
152
+ let { type, data, hash } = match.groups;
153
+ const mediaType = type.split(";");
154
+ hash = stripHash ? "" : hash;
155
+ let isBase64 = false;
156
+ if (mediaType[mediaType.length - 1] === "base64") {
157
+ mediaType.pop();
158
+ isBase64 = true;
159
+ }
160
+ const mimeType = (mediaType.shift() || "").toLowerCase();
161
+ const attributes = mediaType.map((attribute) => {
162
+ let [key, value = ""] = attribute.split("=").map((string) => string.trim());
163
+ if (key === "charset") {
164
+ value = value.toLowerCase();
165
+ if (value === DATA_URL_DEFAULT_CHARSET) {
166
+ return "";
167
+ }
168
+ }
169
+ return `${key}${value ? `=${value}` : ""}`;
170
+ }).filter(Boolean);
171
+ const normalizedMediaType = [
172
+ ...attributes
173
+ ];
174
+ if (isBase64) {
175
+ normalizedMediaType.push("base64");
176
+ }
177
+ if (normalizedMediaType.length > 0 || mimeType && mimeType !== DATA_URL_DEFAULT_MIME_TYPE) {
178
+ normalizedMediaType.unshift(mimeType);
179
+ }
180
+ return `data:${normalizedMediaType.join(";")},${isBase64 ? data.trim() : data}${hash ? `#${hash}` : ""}`;
181
+ };
182
+ function normalizeUrl(urlString, options) {
183
+ options = {
184
+ defaultProtocol: "http:",
185
+ normalizeProtocol: true,
186
+ forceHttp: false,
187
+ forceHttps: false,
188
+ stripAuthentication: true,
189
+ stripHash: false,
190
+ stripTextFragment: true,
191
+ stripWWW: true,
192
+ removeQueryParameters: [/^utm_\w+/i],
193
+ removeTrailingSlash: true,
194
+ removeSingleSlash: true,
195
+ removeDirectoryIndex: false,
196
+ sortQueryParameters: true,
197
+ ...options
198
+ };
199
+ urlString = urlString.trim();
200
+ if (/^data:/i.test(urlString)) {
201
+ return normalizeDataURL(urlString, options);
202
+ }
203
+ if (/^view-source:/i.test(urlString)) {
204
+ throw new Error("`view-source:` is not supported as it is a non-standard protocol");
205
+ }
206
+ const hasRelativeProtocol = urlString.startsWith("//");
207
+ const isRelativeUrl = !hasRelativeProtocol && /^\.*\//.test(urlString);
208
+ if (!isRelativeUrl) {
209
+ urlString = urlString.replace(/^(?!(?:\w+:)?\/\/)|^\/\//, options.defaultProtocol);
210
+ }
211
+ const urlObject = new URL(urlString);
212
+ if (options.forceHttp && options.forceHttps) {
213
+ throw new Error("The `forceHttp` and `forceHttps` options cannot be used together");
214
+ }
215
+ if (options.forceHttp && urlObject.protocol === "https:") {
216
+ urlObject.protocol = "http:";
217
+ }
218
+ if (options.forceHttps && urlObject.protocol === "http:") {
219
+ urlObject.protocol = "https:";
220
+ }
221
+ if (options.stripAuthentication) {
222
+ urlObject.username = "";
223
+ urlObject.password = "";
224
+ }
225
+ if (options.stripHash) {
226
+ urlObject.hash = "";
227
+ } else if (options.stripTextFragment) {
228
+ urlObject.hash = urlObject.hash.replace(/#?:~:text.*?$/i, "");
229
+ }
230
+ if (urlObject.pathname) {
231
+ const protocolRegex = /\b[a-z][a-z\d+\-.]{1,50}:\/\//g;
232
+ let lastIndex = 0;
233
+ let result = "";
234
+ for (; ; ) {
235
+ const match = protocolRegex.exec(urlObject.pathname);
236
+ if (!match) {
237
+ break;
238
+ }
239
+ const protocol = match[0];
240
+ const protocolAtIndex = match.index;
241
+ const intermediate = urlObject.pathname.slice(lastIndex, protocolAtIndex);
242
+ result += intermediate.replace(/\/{2,}/g, "/");
243
+ result += protocol;
244
+ lastIndex = protocolAtIndex + protocol.length;
245
+ }
246
+ const remnant = urlObject.pathname.slice(lastIndex, urlObject.pathname.length);
247
+ result += remnant.replace(/\/{2,}/g, "/");
248
+ urlObject.pathname = result;
249
+ }
250
+ if (urlObject.pathname) {
251
+ try {
252
+ urlObject.pathname = decodeURI(urlObject.pathname);
253
+ } catch {
254
+ }
255
+ }
256
+ if (options.removeDirectoryIndex === true) {
257
+ options.removeDirectoryIndex = [/^index\.[a-z]+$/];
258
+ }
259
+ if (Array.isArray(options.removeDirectoryIndex) && options.removeDirectoryIndex.length > 0) {
260
+ let pathComponents = urlObject.pathname.split("/");
261
+ const lastComponent = pathComponents[pathComponents.length - 1];
262
+ if (testParameter(lastComponent, options.removeDirectoryIndex)) {
263
+ pathComponents = pathComponents.slice(0, -1);
264
+ urlObject.pathname = pathComponents.slice(1).join("/") + "/";
265
+ }
266
+ }
267
+ if (urlObject.hostname) {
268
+ urlObject.hostname = urlObject.hostname.replace(/\.$/, "");
269
+ if (options.stripWWW && /^www\.(?!www\.)[a-z\-\d]{1,63}\.[a-z.\-\d]{2,63}$/.test(urlObject.hostname)) {
270
+ urlObject.hostname = urlObject.hostname.replace(/^www\./, "");
271
+ }
272
+ }
273
+ if (Array.isArray(options.removeQueryParameters)) {
274
+ for (const key of [...urlObject.searchParams.keys()]) {
275
+ if (testParameter(key, options.removeQueryParameters)) {
276
+ urlObject.searchParams.delete(key);
277
+ }
278
+ }
279
+ }
280
+ if (options.removeQueryParameters === true) {
281
+ urlObject.search = "";
282
+ }
283
+ if (options.sortQueryParameters) {
284
+ urlObject.searchParams.sort();
285
+ try {
286
+ urlObject.search = decodeURIComponent(urlObject.search);
287
+ } catch {
288
+ }
289
+ }
290
+ if (options.removeTrailingSlash) {
291
+ urlObject.pathname = urlObject.pathname.replace(/\/$/, "");
292
+ }
293
+ const oldUrlString = urlString;
294
+ urlString = urlObject.toString();
295
+ if (!options.removeSingleSlash && urlObject.pathname === "/" && !oldUrlString.endsWith("/") && urlObject.hash === "") {
296
+ urlString = urlString.replace(/\/$/, "");
297
+ }
298
+ if ((options.removeTrailingSlash || urlObject.pathname === "/") && urlObject.hash === "" && options.removeSingleSlash) {
299
+ urlString = urlString.replace(/\/$/, "");
300
+ }
301
+ if (hasRelativeProtocol && !options.normalizeProtocol) {
302
+ urlString = urlString.replace(/^http:\/\//, "//");
303
+ }
304
+ if (options.stripProtocol) {
305
+ urlString = urlString.replace(/^(?:https?:)?\/\//, "");
306
+ }
307
+ return urlString;
308
+ }
309
+ var normalizeUrl$1 = /* @__PURE__ */ Object.freeze({
310
+ __proto__: null,
311
+ "default": normalizeUrl
312
+ });
313
+ var require$$0 = /* @__PURE__ */ getAugmentedNamespace(normalizeUrl$1);
314
+ Object.defineProperty(src, "__esModule", {
315
+ value: true
316
+ });
317
+ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function(obj) {
318
+ return typeof obj;
319
+ } : function(obj) {
320
+ return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
321
+ };
322
+ var _normalizeUrl = require$$0;
323
+ var _normalizeUrl2 = _interopRequireDefault(_normalizeUrl);
324
+ var _parsePath = require$$1__default["default"];
325
+ var _parsePath2 = _interopRequireDefault(_parsePath);
326
+ function _interopRequireDefault(obj) {
327
+ return obj && obj.__esModule ? obj : { default: obj };
328
+ }
329
+ var parseUrl = function parseUrl2(url) {
330
+ var normalize = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : false;
331
+ var GIT_RE = /^(?:([a-zA-Z_][a-zA-Z0-9_-]{0,31})@|https?:\/\/)([\w\.\-@]+)[\/:](([\~,\.\w,\-,\_,\/,\s]|%[0-9A-Fa-f]{2})+?(?:\.git|\/)?)$/;
332
+ var throwErr = function throwErr2(msg) {
333
+ var err = new Error(msg);
334
+ err.subject_url = url;
335
+ throw err;
336
+ };
337
+ if (typeof url !== "string" || !url.trim()) {
338
+ throwErr("Invalid url.");
339
+ }
340
+ if (url.length > parseUrl2.MAX_INPUT_LENGTH) {
341
+ throwErr("Input exceeds maximum length. If needed, change the value of parseUrl.MAX_INPUT_LENGTH.");
342
+ }
343
+ if (normalize) {
344
+ if ((typeof normalize === "undefined" ? "undefined" : _typeof(normalize)) !== "object") {
345
+ normalize = {
346
+ stripHash: false
347
+ };
348
+ }
349
+ url = (0, _normalizeUrl2.default)(url, normalize);
350
+ }
351
+ var parsed2 = (0, _parsePath2.default)(url);
352
+ if (parsed2.parse_failed) {
353
+ var matched = parsed2.href.match(GIT_RE);
354
+ if (matched) {
355
+ parsed2.protocols = ["ssh"];
356
+ parsed2.protocol = "ssh";
357
+ parsed2.resource = matched[2];
358
+ parsed2.host = matched[2];
359
+ parsed2.user = matched[1];
360
+ parsed2.pathname = "/" + matched[3];
361
+ parsed2.parse_failed = false;
362
+ } else {
363
+ throwErr("URL parsing failed.");
364
+ }
365
+ }
366
+ return parsed2;
367
+ };
368
+ parseUrl.MAX_INPUT_LENGTH = 2048;
369
+ var _default = src.default = parseUrl;
370
+ module.exports = _default;
371
+ }
372
+ });
373
+
374
+ // ../../node_modules/is-ssh/lib/index.js
375
+ var require_lib3 = __commonJS({
376
+ "../../node_modules/is-ssh/lib/index.js"(exports, module) {
377
+ "use strict";
378
+ var protocols = require_lib();
379
+ function isSsh(input) {
380
+ if (Array.isArray(input)) {
381
+ return input.indexOf("ssh") !== -1 || input.indexOf("rsync") !== -1;
382
+ }
383
+ if (typeof input !== "string") {
384
+ return false;
385
+ }
386
+ var prots = protocols(input);
387
+ input = input.substring(input.indexOf("://") + 3);
388
+ if (isSsh(prots)) {
389
+ return true;
390
+ }
391
+ var urlPortPattern = new RegExp(".([a-zA-Z\\d]+):(\\d+)/");
392
+ return !input.match(urlPortPattern) && input.indexOf("@") < input.indexOf(":");
393
+ }
394
+ module.exports = isSsh;
395
+ }
396
+ });
397
+
398
+ // ../../node_modules/git-up/lib/index.js
399
+ var require_lib4 = __commonJS({
400
+ "../../node_modules/git-up/lib/index.js"(exports, module) {
401
+ "use strict";
402
+ var parseUrl = require_dist();
403
+ var isSsh = require_lib3();
404
+ function gitUp(input) {
405
+ let output = parseUrl(input);
406
+ output.token = "";
407
+ if (output.password === "x-oauth-basic") {
408
+ output.token = output.user;
409
+ } else if (output.user === "x-token-auth") {
410
+ output.token = output.password;
411
+ }
412
+ if (isSsh(output.protocols) || output.protocols.length === 0 && isSsh(input)) {
413
+ output.protocol = "ssh";
414
+ } else if (output.protocols.length) {
415
+ output.protocol = output.protocols[0];
416
+ } else {
417
+ output.protocol = "file";
418
+ output.protocols = ["file"];
419
+ }
420
+ output.href = output.href.replace(/\/$/, "");
421
+ return output;
422
+ }
423
+ module.exports = gitUp;
424
+ }
425
+ });
426
+
427
+ // ../../node_modules/git-url-parse/lib/index.js
428
+ var require_lib5 = __commonJS({
429
+ "../../node_modules/git-url-parse/lib/index.js"(exports, module) {
430
+ "use strict";
431
+ var gitUp = require_lib4();
432
+ function gitUrlParse2(url, refs) {
433
+ refs = refs || [];
434
+ if (typeof url !== "string") {
435
+ throw new Error("The url must be a string.");
436
+ }
437
+ if (!refs.every(function(item) {
438
+ return typeof item === "string";
439
+ })) {
440
+ throw new Error("The refs should contain only strings");
441
+ }
442
+ var shorthandRe = /^([a-z\d-]{1,39})\/([-\.\w]{1,100})$/i;
443
+ if (shorthandRe.test(url)) {
444
+ url = "https://github.com/" + url;
445
+ }
446
+ var urlInfo = gitUp(url), sourceParts = urlInfo.resource.split("."), splits = null;
447
+ urlInfo.toString = function(type) {
448
+ return gitUrlParse2.stringify(this, type);
449
+ };
450
+ urlInfo.source = sourceParts.length > 2 ? sourceParts.slice(1 - sourceParts.length).join(".") : urlInfo.source = urlInfo.resource;
451
+ urlInfo.git_suffix = /\.git$/.test(urlInfo.pathname);
452
+ urlInfo.name = decodeURIComponent((urlInfo.pathname || urlInfo.href).replace(/(^\/)|(\/$)/g, "").replace(/\.git$/, ""));
453
+ urlInfo.owner = decodeURIComponent(urlInfo.user);
454
+ switch (urlInfo.source) {
455
+ case "git.cloudforge.com":
456
+ urlInfo.owner = urlInfo.user;
457
+ urlInfo.organization = sourceParts[0];
458
+ urlInfo.source = "cloudforge.com";
459
+ break;
460
+ case "visualstudio.com":
461
+ if (urlInfo.resource === "vs-ssh.visualstudio.com") {
462
+ splits = urlInfo.name.split("/");
463
+ if (splits.length === 4) {
464
+ urlInfo.organization = splits[1];
465
+ urlInfo.owner = splits[2];
466
+ urlInfo.name = splits[3];
467
+ urlInfo.full_name = splits[2] + "/" + splits[3];
468
+ }
469
+ break;
470
+ } else {
471
+ splits = urlInfo.name.split("/");
472
+ if (splits.length === 2) {
473
+ urlInfo.owner = splits[1];
474
+ urlInfo.name = splits[1];
475
+ urlInfo.full_name = "_git/" + urlInfo.name;
476
+ } else if (splits.length === 3) {
477
+ urlInfo.name = splits[2];
478
+ if (splits[0] === "DefaultCollection") {
479
+ urlInfo.owner = splits[2];
480
+ urlInfo.organization = splits[0];
481
+ urlInfo.full_name = urlInfo.organization + "/_git/" + urlInfo.name;
482
+ } else {
483
+ urlInfo.owner = splits[0];
484
+ urlInfo.full_name = urlInfo.owner + "/_git/" + urlInfo.name;
485
+ }
486
+ } else if (splits.length === 4) {
487
+ urlInfo.organization = splits[0];
488
+ urlInfo.owner = splits[1];
489
+ urlInfo.name = splits[3];
490
+ urlInfo.full_name = urlInfo.organization + "/" + urlInfo.owner + "/_git/" + urlInfo.name;
491
+ }
492
+ break;
493
+ }
494
+ // Azure DevOps (formerly Visual Studio Team Services)
495
+ case "dev.azure.com":
496
+ case "azure.com":
497
+ if (urlInfo.resource === "ssh.dev.azure.com") {
498
+ splits = urlInfo.name.split("/");
499
+ if (splits.length === 4) {
500
+ urlInfo.organization = splits[1];
501
+ urlInfo.owner = splits[2];
502
+ urlInfo.name = splits[3];
503
+ }
504
+ break;
505
+ } else {
506
+ splits = urlInfo.name.split("/");
507
+ if (splits.length === 5) {
508
+ urlInfo.organization = splits[0];
509
+ urlInfo.owner = splits[1];
510
+ urlInfo.name = splits[4];
511
+ urlInfo.full_name = "_git/" + urlInfo.name;
512
+ } else if (splits.length === 3) {
513
+ urlInfo.name = splits[2];
514
+ if (splits[0] === "DefaultCollection") {
515
+ urlInfo.owner = splits[2];
516
+ urlInfo.organization = splits[0];
517
+ urlInfo.full_name = urlInfo.organization + "/_git/" + urlInfo.name;
518
+ } else {
519
+ urlInfo.owner = splits[0];
520
+ urlInfo.full_name = urlInfo.owner + "/_git/" + urlInfo.name;
521
+ }
522
+ } else if (splits.length === 4) {
523
+ urlInfo.organization = splits[0];
524
+ urlInfo.owner = splits[1];
525
+ urlInfo.name = splits[3];
526
+ urlInfo.full_name = urlInfo.organization + "/" + urlInfo.owner + "/_git/" + urlInfo.name;
527
+ }
528
+ if (urlInfo.query && urlInfo.query["path"]) {
529
+ urlInfo.filepath = urlInfo.query["path"].replace(/^\/+/g, "");
530
+ }
531
+ if (urlInfo.query && urlInfo.query["version"]) {
532
+ urlInfo.ref = urlInfo.query["version"].replace(/^GB/, "");
533
+ }
534
+ break;
535
+ }
536
+ default:
537
+ splits = urlInfo.name.split("/");
538
+ var nameIndex = splits.length - 1;
539
+ if (splits.length >= 2) {
540
+ var dashIndex = splits.indexOf("-", 2);
541
+ var blobIndex = splits.indexOf("blob", 2);
542
+ var treeIndex = splits.indexOf("tree", 2);
543
+ var commitIndex = splits.indexOf("commit", 2);
544
+ var issuesIndex = splits.indexOf("issues", 2);
545
+ var srcIndex = splits.indexOf("src", 2);
546
+ var rawIndex = splits.indexOf("raw", 2);
547
+ var editIndex = splits.indexOf("edit", 2);
548
+ nameIndex = dashIndex > 0 ? dashIndex - 1 : blobIndex > 0 && treeIndex > 0 ? Math.min(blobIndex - 1, treeIndex - 1) : blobIndex > 0 ? blobIndex - 1 : issuesIndex > 0 ? issuesIndex - 1 : treeIndex > 0 ? treeIndex - 1 : commitIndex > 0 ? commitIndex - 1 : srcIndex > 0 ? srcIndex - 1 : rawIndex > 0 ? rawIndex - 1 : editIndex > 0 ? editIndex - 1 : nameIndex;
549
+ urlInfo.owner = splits.slice(0, nameIndex).join("/");
550
+ urlInfo.name = splits[nameIndex];
551
+ if (commitIndex && issuesIndex < 0) {
552
+ urlInfo.commit = splits[nameIndex + 2];
553
+ }
554
+ }
555
+ urlInfo.ref = "";
556
+ urlInfo.filepathtype = "";
557
+ urlInfo.filepath = "";
558
+ var offsetNameIndex = splits.length > nameIndex && splits[nameIndex + 1] === "-" ? nameIndex + 1 : nameIndex;
559
+ if (splits.length > offsetNameIndex + 2 && ["raw", "src", "blob", "tree", "edit"].indexOf(splits[offsetNameIndex + 1]) >= 0) {
560
+ urlInfo.filepathtype = splits[offsetNameIndex + 1];
561
+ urlInfo.ref = splits[offsetNameIndex + 2];
562
+ if (splits.length > offsetNameIndex + 3) {
563
+ urlInfo.filepath = splits.slice(offsetNameIndex + 3).join("/");
564
+ }
565
+ }
566
+ urlInfo.organization = urlInfo.owner;
567
+ break;
568
+ }
569
+ if (!urlInfo.full_name) {
570
+ urlInfo.full_name = urlInfo.owner;
571
+ if (urlInfo.name) {
572
+ urlInfo.full_name && (urlInfo.full_name += "/");
573
+ urlInfo.full_name += urlInfo.name;
574
+ }
575
+ }
576
+ if (urlInfo.owner.startsWith("scm/")) {
577
+ urlInfo.source = "bitbucket-server";
578
+ urlInfo.owner = urlInfo.owner.replace("scm/", "");
579
+ urlInfo.organization = urlInfo.owner;
580
+ urlInfo.full_name = urlInfo.owner + "/" + urlInfo.name;
581
+ }
582
+ var bitbucket = /(projects|users)\/(.*?)\/repos\/(.*?)((\/.*$)|$)/;
583
+ var matches = bitbucket.exec(urlInfo.pathname);
584
+ if (matches != null) {
585
+ urlInfo.source = "bitbucket-server";
586
+ if (matches[1] === "users") {
587
+ urlInfo.owner = "~" + matches[2];
588
+ } else {
589
+ urlInfo.owner = matches[2];
590
+ }
591
+ urlInfo.organization = urlInfo.owner;
592
+ urlInfo.name = matches[3];
593
+ splits = matches[4].split("/");
594
+ if (splits.length > 1) {
595
+ if (["raw", "browse"].indexOf(splits[1]) >= 0) {
596
+ urlInfo.filepathtype = splits[1];
597
+ if (splits.length > 2) {
598
+ urlInfo.filepath = splits.slice(2).join("/");
599
+ }
600
+ } else if (splits[1] === "commits" && splits.length > 2) {
601
+ urlInfo.commit = splits[2];
602
+ }
603
+ }
604
+ urlInfo.full_name = urlInfo.owner + "/" + urlInfo.name;
605
+ if (urlInfo.query.at) {
606
+ urlInfo.ref = urlInfo.query.at;
607
+ } else {
608
+ urlInfo.ref = "";
609
+ }
610
+ }
611
+ if (refs.length !== 0 && urlInfo.ref) {
612
+ urlInfo.ref = findLongestMatchingSubstring(urlInfo.href, refs) || urlInfo.ref;
613
+ urlInfo.filepath = urlInfo.href.split(urlInfo.ref + "/")[1];
614
+ }
615
+ return urlInfo;
616
+ }
617
+ gitUrlParse2.stringify = function(obj, type) {
618
+ type = type || (obj.protocols && obj.protocols.length ? obj.protocols.join("+") : obj.protocol);
619
+ var port = obj.port ? ":" + obj.port : "";
620
+ var user = obj.user || "git";
621
+ var maybeGitSuffix = obj.git_suffix ? ".git" : "";
622
+ switch (type) {
623
+ case "ssh":
624
+ if (port) return "ssh://" + user + "@" + obj.resource + port + "/" + obj.full_name + maybeGitSuffix;
625
+ else return user + "@" + obj.resource + ":" + obj.full_name + maybeGitSuffix;
626
+ case "git+ssh":
627
+ case "ssh+git":
628
+ case "ftp":
629
+ case "ftps":
630
+ return type + "://" + user + "@" + obj.resource + port + "/" + obj.full_name + maybeGitSuffix;
631
+ case "http":
632
+ case "https":
633
+ var auth = obj.token ? buildToken(obj) : obj.user && (obj.protocols.includes("http") || obj.protocols.includes("https")) ? obj.user + "@" : "";
634
+ return type + "://" + auth + obj.resource + port + "/" + buildPath(obj) + maybeGitSuffix;
635
+ default:
636
+ return obj.href;
637
+ }
638
+ };
639
+ function buildToken(obj) {
640
+ switch (obj.source) {
641
+ case "bitbucket.org":
642
+ return "x-token-auth:" + obj.token + "@";
643
+ default:
644
+ return obj.token + "@";
645
+ }
646
+ }
647
+ function buildPath(obj) {
648
+ switch (obj.source) {
649
+ case "bitbucket-server":
650
+ return "scm/" + obj.full_name;
651
+ default:
652
+ var encoded_full_name = obj.full_name.split("/").map(function(x) {
653
+ return encodeURIComponent(x);
654
+ }).join("/");
655
+ return encoded_full_name;
656
+ }
657
+ }
658
+ function findLongestMatchingSubstring(string, array) {
659
+ var longestMatch = "";
660
+ array.forEach(function(item) {
661
+ if (string.includes(item) && item.length > longestMatch.length) {
662
+ longestMatch = item;
663
+ }
664
+ });
665
+ return longestMatch;
666
+ }
667
+ module.exports = gitUrlParse2;
668
+ }
669
+ });
670
+
671
+ // src/adapters/codex/local-tools-mcp-server.ts
672
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
673
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
674
+
675
+ // ../git/dist/signed-commit.js
676
+ import * as childProcess3 from "child_process";
677
+
678
+ // ../git/dist/concurrency.js
679
+ async function mapWithConcurrency(items, concurrency, mapper, options) {
680
+ if (items.length === 0)
681
+ return [];
682
+ const results = new Array(items.length);
683
+ let index = 0;
684
+ const worker = async () => {
685
+ while (index < items.length) {
686
+ if (options?.signal?.aborted)
687
+ return;
688
+ const i = index++;
689
+ results[i] = await mapper(items[i]);
690
+ }
691
+ };
692
+ await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, () => worker()));
693
+ return results;
694
+ }
695
+
696
+ // ../git/dist/gh.js
697
+ import * as childProcess from "child_process";
698
+ function execGh(args, options = {}) {
699
+ const env = options.env ? { ...process.env, ...options.env } : process.env;
700
+ return new Promise((resolve2) => {
701
+ const child = childProcess.execFile("gh", args, { cwd: options.cwd, env, timeout: options.timeoutMs ?? 0 }, (error, stdout, stderr) => {
702
+ if (!error) {
703
+ resolve2({ stdout, stderr, exitCode: 0 });
704
+ return;
705
+ }
706
+ const err = error;
707
+ const timedOut = err.killed === true && !!options.timeoutMs;
708
+ const exitCode = typeof err.code === "number" ? err.code : err.code === "ENOENT" ? 127 : 1;
709
+ resolve2({
710
+ stdout: stdout ?? err.stdout ?? "",
711
+ stderr: stderr ?? err.stderr ?? "",
712
+ exitCode,
713
+ error: timedOut ? `gh timed out after ${options.timeoutMs}ms` : err.message
714
+ });
715
+ });
716
+ if (options.input !== void 0) {
717
+ child.stdin?.end(options.input);
718
+ }
719
+ });
720
+ }
721
+ var TRANSIENT_GH_PATTERNS = [
722
+ /HTTP 5\d\d/,
723
+ /HTTP 499/,
724
+ /\btimed out\b/i,
725
+ /\bETIMEDOUT\b/,
726
+ /\bECONNRESET\b/,
727
+ /\bECONNREFUSED\b/,
728
+ /\bEAI_AGAIN\b/,
729
+ /connection reset/i
730
+ ];
731
+ function isTransientGhFailure(res) {
732
+ if (res.exitCode === 0) {
733
+ return false;
734
+ }
735
+ const text = `${res.stderr} ${res.error ?? ""} ${res.stdout}`;
736
+ return TRANSIENT_GH_PATTERNS.some((re) => re.test(text));
737
+ }
738
+ var sleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
739
+ async function execGhWithRetry(args, options = {}, retry = {}, exec = execGh) {
740
+ const maxAttempts = retry.maxAttempts ?? 3;
741
+ const backoffMs = retry.backoffMs ?? 500;
742
+ let res = await exec(args, options);
743
+ for (let attempt = 2; attempt <= maxAttempts && isTransientGhFailure(res); attempt++) {
744
+ await sleep(backoffMs * 2 ** (attempt - 2));
745
+ res = await exec(args, options);
746
+ }
747
+ return res;
748
+ }
749
+
750
+ // ../git/dist/trailers.js
751
+ function buildPostHogTrailers(taskId) {
752
+ const trailers = ["Generated-By: PostHog Code"];
753
+ if (taskId)
754
+ trailers.push(`Task-Id: ${taskId}`);
755
+ return trailers;
756
+ }
757
+
758
+ // ../git/dist/utils.js
759
+ var import_git_url_parse = __toESM(require_lib5(), 1);
760
+ import * as childProcess2 from "child_process";
761
+ import * as fs from "fs/promises";
762
+ import * as os from "os";
763
+ import * as path from "path";
764
+ function parseGithubUrl(url) {
765
+ if (!url)
766
+ return null;
767
+ let parsed2;
768
+ try {
769
+ parsed2 = (0, import_git_url_parse.default)(url.trim());
770
+ } catch {
771
+ return null;
772
+ }
773
+ const resource = parsed2.resource.toLowerCase();
774
+ if (resource !== "github.com" && resource !== "ssh.github.com")
775
+ return null;
776
+ const raw = parsed2.pathname.split("/");
777
+ if (raw[0] !== "")
778
+ return null;
779
+ const parts = raw[raw.length - 1] === "" ? raw.slice(1, -1) : raw.slice(1);
780
+ if (parts.length < 2 || parts.some((p) => p === ""))
781
+ return null;
782
+ const [owner, repoRaw, segment, num] = parts;
783
+ const repo = repoRaw.replace(/\.git$/, "");
784
+ if (segment === "issues" || segment === "pull") {
785
+ const number = Number(num);
786
+ if (!Number.isInteger(number) || number <= 0)
787
+ return null;
788
+ return {
789
+ kind: segment === "pull" ? "pr" : "issue",
790
+ owner,
791
+ repo,
792
+ number
793
+ };
794
+ }
795
+ return { kind: "repo", owner, repo };
796
+ }
797
+
798
+ // ../git/dist/signed-commit.js
799
+ var DEFAULT_MAX_PAYLOAD_BYTES = 35 * 1024 * 1024;
800
+ var MAX_GIT_BUFFER = 256 * 1024 * 1024;
801
+ var GH_GRAPHQL_TIMEOUT_MS = 3e4;
802
+ var OversizedFileError = class extends Error {
803
+ path;
804
+ bytes;
805
+ maxBytes;
806
+ constructor(path2, bytes, maxBytes) {
807
+ super(`File '${path2}' (~${Math.round(bytes / 1024 / 1024)}MB once base64-encoded) exceeds the per-commit request limit (~${Math.round(maxBytes / 1024 / 1024)}MB). A single file cannot be split across createCommitOnBranch requests; use Git LFS or a local signing key for this change.`);
808
+ this.path = path2;
809
+ this.bytes = bytes;
810
+ this.maxBytes = maxBytes;
811
+ this.name = "OversizedFileError";
812
+ }
813
+ };
814
+ function runGit(args, cwd) {
815
+ return new Promise((resolve2) => {
816
+ childProcess3.execFile("git", args, { cwd, maxBuffer: MAX_GIT_BUFFER, encoding: "buffer" }, (error, stdout, stderr) => {
817
+ const err = error;
818
+ const exitCode = err && typeof err.code === "number" ? err.code : err ? 1 : 0;
819
+ resolve2({
820
+ stdout: stdout ?? Buffer.alloc(0),
821
+ stderr: (stderr ?? Buffer.alloc(0)).toString("utf8"),
822
+ exitCode
823
+ });
824
+ });
825
+ });
826
+ }
827
+ async function gitText(args, cwd) {
828
+ const r = await runGit(args, cwd);
829
+ if (r.exitCode !== 0) {
830
+ throw new Error(`git ${args.join(" ")} failed: ${r.stderr.trim()}`);
831
+ }
832
+ return r.stdout.toString("utf8").trim();
833
+ }
834
+ async function resolveRepoNameWithOwner(ctx2) {
835
+ const url = await gitText(["remote", "get-url", "origin"], ctx2.cwd);
836
+ const parsed2 = parseGithubUrl(url);
837
+ if (!parsed2) {
838
+ throw new Error(`Could not parse owner/repo from origin remote: ${url}`);
839
+ }
840
+ return `${parsed2.owner}/${parsed2.repo}`;
841
+ }
842
+ async function resolveBaseBranch(ctx2) {
843
+ if (ctx2.baseBranch)
844
+ return ctx2.baseBranch;
845
+ const r = await runGit(["symbolic-ref", "--short", "refs/remotes/origin/HEAD"], ctx2.cwd);
846
+ if (r.exitCode !== 0)
847
+ return null;
848
+ return r.stdout.toString("utf8").trim().replace(/^origin\//, "") || null;
849
+ }
850
+ async function resolveBranchName(ctx2, input) {
851
+ const branch = input.branch ? input.branch.replace(/^refs\/heads\//, "") : await resolveCurrentBranch(ctx2);
852
+ const baseBranch = await resolveBaseBranch(ctx2);
853
+ if (baseBranch && branch === baseBranch) {
854
+ throw new Error(`Refusing to commit directly to base branch '${baseBranch}'. Pass a 'branch' name prefixed with posthog-code/.`);
855
+ }
856
+ return branch;
857
+ }
858
+ async function resolveCurrentBranch(ctx2) {
859
+ const current = await gitText(["rev-parse", "--abbrev-ref", "HEAD"], ctx2.cwd);
860
+ if (!current || current === "HEAD") {
861
+ throw new Error("Detached HEAD \u2014 pass a `branch` to git_signed_commit (e.g. posthog-code/...).");
862
+ }
863
+ return current;
864
+ }
865
+ async function remoteTip(ctx2, branch) {
866
+ const out = await gitText(["ls-remote", "--heads", "origin", branch], ctx2.cwd);
867
+ if (!out)
868
+ return null;
869
+ return out.split(" ")[0]?.trim() || null;
870
+ }
871
+ async function createRef(ctx2, repo, branch, sha) {
872
+ const res = await execGh([
873
+ "api",
874
+ "-X",
875
+ "POST",
876
+ `/repos/${repo}/git/refs`,
877
+ "-f",
878
+ `ref=refs/heads/${branch}`,
879
+ "-f",
880
+ `sha=${sha}`
881
+ ], { cwd: ctx2.cwd, env: ghTokenEnv(ctx2.token) });
882
+ if (res.exitCode !== 0) {
883
+ throw new Error(`Failed to create branch '${branch}': ${res.stderr || res.error}`);
884
+ }
885
+ }
886
+ var GITHUB_TOKEN_ENV_VARS = ["GH_TOKEN", "GITHUB_TOKEN"];
887
+ function readGithubTokenFromEnv(env = process.env) {
888
+ for (const name of GITHUB_TOKEN_ENV_VARS) {
889
+ if (env[name])
890
+ return env[name];
891
+ }
892
+ return void 0;
893
+ }
894
+ function ghTokenEnv(token) {
895
+ return Object.fromEntries(GITHUB_TOKEN_ENV_VARS.map((name) => [name, token]));
896
+ }
897
+ var STAGED_READ_CONCURRENCY = 16;
898
+ async function buildFileChanges(ctx2, baseOid) {
899
+ const diff = await runGit(["diff", "--cached", "-z", "--no-renames", "--name-status", baseOid], ctx2.cwd);
900
+ if (diff.exitCode !== 0) {
901
+ throw new Error(`git diff --cached failed: ${diff.stderr.trim()}`);
902
+ }
903
+ const tokens = diff.stdout.toString("utf8").split("\0").filter(Boolean);
904
+ const addPaths = [];
905
+ const deletions = [];
906
+ for (let i = 0; i + 1 < tokens.length; i += 2) {
907
+ const path2 = tokens[i + 1];
908
+ if (tokens[i].startsWith("D")) {
909
+ deletions.push({ path: path2 });
910
+ } else {
911
+ addPaths.push(path2);
912
+ }
913
+ }
914
+ const additions = await mapWithConcurrency(addPaths, STAGED_READ_CONCURRENCY, async (path2) => {
915
+ const r = await runGit(["show", `:${path2}`], ctx2.cwd);
916
+ if (r.exitCode !== 0) {
917
+ throw new Error(`Failed to read staged file '${path2}': ${r.stderr.trim()}`);
918
+ }
919
+ return { path: path2, contents: r.stdout.toString("base64") };
920
+ });
921
+ return { additions, deletions };
922
+ }
923
+ function additionBytes(a) {
924
+ return a.contents.length + a.path.length + 32;
925
+ }
926
+ function chunkFileChanges(changes, maxBytes) {
927
+ for (const a of changes.additions) {
928
+ const bytes = additionBytes(a);
929
+ if (bytes > maxBytes)
930
+ throw new OversizedFileError(a.path, bytes, maxBytes);
931
+ }
932
+ if (changes.additions.length === 0) {
933
+ return [{ additions: [], deletions: changes.deletions }];
934
+ }
935
+ const chunks = [];
936
+ let cur = { additions: [], deletions: [...changes.deletions] };
937
+ let curBytes = changes.deletions.reduce((n, d) => n + d.path.length + 16, 0);
938
+ for (const a of changes.additions) {
939
+ const bytes = additionBytes(a);
940
+ if (cur.additions.length > 0 && curBytes + bytes > maxBytes) {
941
+ chunks.push(cur);
942
+ cur = { additions: [], deletions: [] };
943
+ curBytes = 0;
944
+ }
945
+ cur.additions.push(a);
946
+ curBytes += bytes;
947
+ }
948
+ chunks.push(cur);
949
+ return chunks;
950
+ }
951
+ var CREATE_COMMIT_MUTATION = `mutation($input: CreateCommitOnBranchInput!) {
952
+ createCommitOnBranch(input: $input) { commit { oid url } }
953
+ }`;
954
+ async function createCommitOnBranch(ctx2, repo, branch, expectedHeadOid, headline, body, changes) {
955
+ const payload = JSON.stringify({
956
+ query: CREATE_COMMIT_MUTATION,
957
+ variables: {
958
+ input: {
959
+ branch: { repositoryNameWithOwner: repo, branchName: branch },
960
+ expectedHeadOid,
961
+ message: { headline, body },
962
+ fileChanges: changes
963
+ }
964
+ }
965
+ });
966
+ const res = await execGhWithRetry(["api", "graphql", "--input", "-"], {
967
+ cwd: ctx2.cwd,
968
+ input: payload,
969
+ env: ghTokenEnv(ctx2.token),
970
+ // Bound each attempt so a stalled connection can't hang the tool forever.
971
+ timeoutMs: GH_GRAPHQL_TIMEOUT_MS
972
+ }, { maxAttempts: 3 });
973
+ if (res.exitCode !== 0) {
974
+ throw new Error(`createCommitOnBranch failed: ${res.stderr || res.error || res.stdout}`);
975
+ }
976
+ let parsed2;
977
+ try {
978
+ parsed2 = JSON.parse(res.stdout);
979
+ } catch {
980
+ throw new Error(`createCommitOnBranch returned non-JSON: ${res.stdout.slice(0, 500)}`);
981
+ }
982
+ if (parsed2.errors) {
983
+ throw new Error(`createCommitOnBranch errors: ${JSON.stringify(parsed2.errors)}`);
984
+ }
985
+ const commit = parsed2.data?.createCommitOnBranch?.commit;
986
+ if (!commit?.oid) {
987
+ throw new Error(`createCommitOnBranch returned no commit: ${res.stdout}`);
988
+ }
989
+ return commit;
990
+ }
991
+ async function syncLocalCheckout(ctx2, branch, newOid) {
992
+ const steps = [
993
+ ["fetch", ["fetch", "--no-tags", "origin", branch]],
994
+ ["update-ref", ["update-ref", `refs/heads/${branch}`, newOid]],
995
+ ["symbolic-ref", ["symbolic-ref", "HEAD", `refs/heads/${branch}`]],
996
+ ["reset", ["reset", "-q"]]
997
+ ];
998
+ for (const [label, args] of steps) {
999
+ const r = await runGit(args, ctx2.cwd);
1000
+ if (r.exitCode !== 0) {
1001
+ process.stderr.write(`[signed-commit] local sync step '${label}' failed after committing ${newOid}: ${r.stderr.trim()}
1002
+ `);
1003
+ }
1004
+ }
1005
+ }
1006
+ async function createSignedCommit(ctx2, input) {
1007
+ const [repo, branch] = await Promise.all([
1008
+ resolveRepoNameWithOwner(ctx2),
1009
+ resolveBranchName(ctx2, input)
1010
+ ]);
1011
+ if (input.paths && input.paths.length > 0) {
1012
+ const r = await runGit(["add", "--", ...input.paths], ctx2.cwd);
1013
+ if (r.exitCode !== 0) {
1014
+ throw new Error(`git add failed: ${r.stderr.trim()}`);
1015
+ }
1016
+ }
1017
+ let tip = await remoteTip(ctx2, branch);
1018
+ if (tip === null) {
1019
+ const baseSha = await gitText(["rev-parse", "HEAD"], ctx2.cwd);
1020
+ await createRef(ctx2, repo, branch, baseSha);
1021
+ tip = baseSha;
1022
+ } else {
1023
+ await runGit(["fetch", "--no-tags", "origin", branch], ctx2.cwd);
1024
+ }
1025
+ const changes = await buildFileChanges(ctx2, tip);
1026
+ if (changes.additions.length === 0 && changes.deletions.length === 0) {
1027
+ throw new Error("No staged changes to commit. Stage files with `git add` first (or pass `paths`).");
1028
+ }
1029
+ const chunks = chunkFileChanges(changes, DEFAULT_MAX_PAYLOAD_BYTES);
1030
+ const body = [input.body, buildPostHogTrailers(ctx2.taskId).join("\n")].filter(Boolean).join("\n\n");
1031
+ const commits = [];
1032
+ let expectedHeadOid = tip;
1033
+ for (let i = 0; i < chunks.length; i++) {
1034
+ const headline = chunks.length > 1 ? `${input.message} \u2014 part ${i + 1}/${chunks.length}` : input.message;
1035
+ const commit = await createCommitOnBranch(ctx2, repo, branch, expectedHeadOid, headline, body, chunks[i]);
1036
+ commits.push({ sha: commit.oid, url: commit.url });
1037
+ expectedHeadOid = commit.oid;
1038
+ }
1039
+ await syncLocalCheckout(ctx2, branch, expectedHeadOid);
1040
+ return { branch, commits };
1041
+ }
1042
+
1043
+ // src/utils/common.ts
1044
+ var IS_ROOT = typeof process !== "undefined" && (process.geteuid?.() ?? process.getuid?.()) === 0;
1045
+ var ALLOW_BYPASS = !IS_ROOT || !!process.env.IS_SANDBOX;
1046
+ function isCloudRun(meta) {
1047
+ return !!process.env.IS_SANDBOX || !!meta?.taskRunId;
1048
+ }
1049
+
1050
+ // src/adapters/signed-commit-shared.ts
1051
+ import { z } from "zod";
1052
+
1053
+ // src/adapters/local-tools/registry.ts
1054
+ var LOCAL_TOOLS_MCP_NAME = "posthog-local";
1055
+ function defineLocalTool(def) {
1056
+ return def;
1057
+ }
1058
+ function qualifiedLocalToolName(toolName) {
1059
+ return `mcp__${LOCAL_TOOLS_MCP_NAME}__${toolName}`;
1060
+ }
1061
+
1062
+ // src/adapters/signed-commit-shared.ts
1063
+ var SIGNED_COMMIT_TOOL_NAME = "git_signed_commit";
1064
+ var SIGNED_COMMIT_QUALIFIED_TOOL_NAME = qualifiedLocalToolName(
1065
+ SIGNED_COMMIT_TOOL_NAME
1066
+ );
1067
+ var SIGNED_COMMIT_TOOL_DESCRIPTION = "Create a GitHub-signed (Verified) commit on the branch. Stage files with `git add` first (or pass `paths`), then call this instead of `git commit`/`git push` \u2014 those are blocked because all commits must be signed. The commit is created via GitHub's API and your local checkout is kept in sync. For a new branch, pass `branch` (prefixed with `posthog-code/`) and the tool creates it on the remote.";
1068
+ var signedCommitToolSchema = {
1069
+ message: z.string().describe("Commit headline (first line)."),
1070
+ body: z.string().optional().describe("Optional extended commit body."),
1071
+ branch: z.string().optional().describe(
1072
+ "Target branch; defaults to the current branch. Use a posthog-code/ prefix for new branches."
1073
+ ),
1074
+ paths: z.array(z.string()).optional().describe(
1075
+ "Files to stage before committing; defaults to already-staged files."
1076
+ )
1077
+ };
1078
+ function formatSignedCommitResult(result) {
1079
+ const list = result.commits.map((c) => `- ${c.sha} ${c.url}`).join("\n");
1080
+ return `Created ${result.commits.length} signed commit(s) on ${result.branch}:
1081
+ ${list}`;
1082
+ }
1083
+ async function runSignedCommitTool(ctx2, args) {
1084
+ try {
1085
+ const result = await createSignedCommit(ctx2, args);
1086
+ return {
1087
+ content: [{ type: "text", text: formatSignedCommitResult(result) }]
1088
+ };
1089
+ } catch (err) {
1090
+ const message = err instanceof Error ? err.message : String(err);
1091
+ return {
1092
+ content: [
1093
+ { type: "text", text: `${SIGNED_COMMIT_TOOL_NAME} failed: ${message}` }
1094
+ ],
1095
+ isError: true
1096
+ };
1097
+ }
1098
+ }
1099
+
1100
+ // src/adapters/local-tools/tools/signed-commit.ts
1101
+ var signedCommitTool = defineLocalTool({
1102
+ name: SIGNED_COMMIT_TOOL_NAME,
1103
+ description: SIGNED_COMMIT_TOOL_DESCRIPTION,
1104
+ schema: signedCommitToolSchema,
1105
+ alwaysLoad: true,
1106
+ isEnabled: (ctx2, meta) => isCloudRun(meta) && !!ctx2.token,
1107
+ handler: (ctx2, args) => runSignedCommitTool(
1108
+ { cwd: ctx2.cwd, token: ctx2.token ?? "", taskId: ctx2.taskId },
1109
+ args
1110
+ )
1111
+ });
1112
+
1113
+ // src/adapters/local-tools/index.ts
1114
+ var LOCAL_TOOLS = [signedCommitTool];
1115
+
1116
+ // src/adapters/codex/local-tools-mcp-server.ts
1117
+ function die(message) {
1118
+ process.stderr.write(`[local-tools-mcp-server] ${message}
1119
+ `);
1120
+ process.exit(1);
1121
+ }
1122
+ var ctxEnv = process.env.POSTHOG_LOCAL_TOOLS_CTX;
1123
+ if (!ctxEnv) {
1124
+ die("POSTHOG_LOCAL_TOOLS_CTX env var is required");
1125
+ }
1126
+ var parsed;
1127
+ try {
1128
+ parsed = JSON.parse(Buffer.from(ctxEnv, "base64").toString("utf-8"));
1129
+ } catch (err) {
1130
+ die(`Failed to parse POSTHOG_LOCAL_TOOLS_CTX as base64-encoded JSON: ${err}`);
1131
+ }
1132
+ if (!parsed.cwd) {
1133
+ die("POSTHOG_LOCAL_TOOLS_CTX must include cwd");
1134
+ }
1135
+ var ctx = {
1136
+ cwd: parsed.cwd,
1137
+ token: parsed.token ?? readGithubTokenFromEnv(),
1138
+ taskId: parsed.taskId
1139
+ };
1140
+ var enabledNames = (process.env.POSTHOG_LOCAL_TOOLS_ENABLED ?? "").split(",").filter(Boolean);
1141
+ var tools = LOCAL_TOOLS.filter((t) => enabledNames.includes(t.name));
1142
+ if (tools.length === 0) {
1143
+ die("POSTHOG_LOCAL_TOOLS_ENABLED listed no known tools");
1144
+ }
1145
+ var server = new McpServer({
1146
+ name: LOCAL_TOOLS_MCP_NAME,
1147
+ version: "1.0.0"
1148
+ });
1149
+ for (const t of tools) {
1150
+ server.tool(
1151
+ t.name,
1152
+ t.description,
1153
+ t.schema,
1154
+ async (args) => t.handler(ctx, args)
1155
+ );
1156
+ }
1157
+ var transport = new StdioServerTransport();
1158
+ await server.connect(transport);
1159
+ /*! Bundled license information:
1160
+
1161
+ git-url-parse/lib/index.js:
1162
+ (*!
1163
+ * buildToken
1164
+ * Builds OAuth token prefix (helper function)
1165
+ *
1166
+ * @name buildToken
1167
+ * @function
1168
+ * @param {GitUrl} obj The parsed Git url object.
1169
+ * @return {String} token prefix
1170
+ *)
1171
+ */
1172
+ //# sourceMappingURL=local-tools-mcp-server.js.map