@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
@@ -509,7 +509,7 @@ var require_has_flag = __commonJS({
509
509
  var require_supports_color = __commonJS({
510
510
  "../../node_modules/supports-color/index.js"(exports2, module2) {
511
511
  "use strict";
512
- var os8 = require("os");
512
+ var os9 = require("os");
513
513
  var tty = require("tty");
514
514
  var hasFlag = require_has_flag();
515
515
  var { env } = process;
@@ -557,7 +557,7 @@ var require_supports_color = __commonJS({
557
557
  return min;
558
558
  }
559
559
  if (process.platform === "win32") {
560
- const osRelease = os8.release().split(".");
560
+ const osRelease = os9.release().split(".");
561
561
  if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
562
562
  return Number(osRelease[2]) >= 14931 ? 3 : 2;
563
563
  }
@@ -805,10 +805,10 @@ var require_src2 = __commonJS({
805
805
  var fs_1 = require("fs");
806
806
  var debug_1 = __importDefault(require_src());
807
807
  var log = debug_1.default("@kwsites/file-exists");
808
- function check(path17, isFile2, isDirectory) {
809
- log(`checking %s`, path17);
808
+ function check(path18, isFile2, isDirectory) {
809
+ log(`checking %s`, path18);
810
810
  try {
811
- const stat4 = fs_1.statSync(path17);
811
+ const stat4 = fs_1.statSync(path18);
812
812
  if (stat4.isFile() && isFile2) {
813
813
  log(`[OK] path represents a file`);
814
814
  return true;
@@ -828,8 +828,8 @@ var require_src2 = __commonJS({
828
828
  throw e;
829
829
  }
830
830
  }
831
- function exists2(path17, type = exports2.READABLE) {
832
- return check(path17, (type & exports2.FILE) > 0, (type & exports2.FOLDER) > 0);
831
+ function exists2(path18, type = exports2.READABLE) {
832
+ return check(path18, (type & exports2.FILE) > 0, (type & exports2.FOLDER) > 0);
833
833
  }
834
834
  exports2.exists = exists2;
835
835
  exports2.FILE = 1;
@@ -925,11 +925,11 @@ var require_tree_sitter = __commonJS({
925
925
  throw toThrow;
926
926
  };
927
927
  var scriptDirectory = "";
928
- function locateFile(path17) {
928
+ function locateFile(path18) {
929
929
  if (Module["locateFile"]) {
930
- return Module["locateFile"](path17, scriptDirectory);
930
+ return Module["locateFile"](path18, scriptDirectory);
931
931
  }
932
- return scriptDirectory + path17;
932
+ return scriptDirectory + path18;
933
933
  }
934
934
  var readAsync, readBinary;
935
935
  if (ENVIRONMENT_IS_NODE) {
@@ -943,10 +943,10 @@ var require_tree_sitter = __commonJS({
943
943
  };
944
944
  readAsync = (filename, binary2 = true) => {
945
945
  filename = isFileURI(filename) ? new URL(filename) : nodePath.normalize(filename);
946
- return new Promise((resolve7, reject) => {
946
+ return new Promise((resolve8, reject) => {
947
947
  fs.readFile(filename, binary2 ? void 0 : "utf8", (err2, data) => {
948
948
  if (err2) reject(err2);
949
- else resolve7(binary2 ? data.buffer : data);
949
+ else resolve8(binary2 ? data.buffer : data);
950
950
  });
951
951
  });
952
952
  };
@@ -987,13 +987,13 @@ var require_tree_sitter = __commonJS({
987
987
  }
988
988
  readAsync = (url) => {
989
989
  if (isFileURI(url)) {
990
- return new Promise((reject, resolve7) => {
990
+ return new Promise((reject, resolve8) => {
991
991
  var xhr = new XMLHttpRequest();
992
992
  xhr.open("GET", url, true);
993
993
  xhr.responseType = "arraybuffer";
994
994
  xhr.onload = () => {
995
995
  if (xhr.status == 200 || xhr.status == 0 && xhr.response) {
996
- resolve7(xhr.response);
996
+ resolve8(xhr.response);
997
997
  }
998
998
  reject(xhr.status);
999
999
  };
@@ -1953,8 +1953,8 @@ var require_tree_sitter = __commonJS({
1953
1953
  }
1954
1954
  var libFile = locateFile(libName2);
1955
1955
  if (flags2.loadAsync) {
1956
- return new Promise(function(resolve7, reject) {
1957
- asyncLoad(libFile, resolve7, reject);
1956
+ return new Promise(function(resolve8, reject) {
1957
+ asyncLoad(libFile, resolve8, reject);
1958
1958
  });
1959
1959
  }
1960
1960
  if (!readBinary) {
@@ -3450,8 +3450,8 @@ var require_tree_sitter = __commonJS({
3450
3450
  } else {
3451
3451
  const url = input;
3452
3452
  if (typeof process !== "undefined" && process.versions && process.versions.node) {
3453
- const fs14 = require("fs");
3454
- bytes = Promise.resolve(fs14.readFileSync(url));
3453
+ const fs15 = require("fs");
3454
+ bytes = Promise.resolve(fs15.readFileSync(url));
3455
3455
  } else {
3456
3456
  bytes = fetch(url).then((response) => response.arrayBuffer().then((buffer) => {
3457
3457
  if (response.ok) {
@@ -3779,6 +3779,650 @@ ${JSON.stringify(symbolNames, null, 2)}`);
3779
3779
  }
3780
3780
  });
3781
3781
 
3782
+ // ../../node_modules/protocols/lib/index.js
3783
+ var require_lib = __commonJS({
3784
+ "../../node_modules/protocols/lib/index.js"(exports2, module2) {
3785
+ "use strict";
3786
+ module2.exports = function protocols(input, first2) {
3787
+ if (first2 === true) {
3788
+ first2 = 0;
3789
+ }
3790
+ var prots = "";
3791
+ if (typeof input === "string") {
3792
+ try {
3793
+ prots = new URL(input).protocol;
3794
+ } catch (e) {
3795
+ }
3796
+ } else if (input && input.constructor === URL) {
3797
+ prots = input.protocol;
3798
+ }
3799
+ var splits = prots.split(/\:|\+/).filter(Boolean);
3800
+ if (typeof first2 === "number") {
3801
+ return splits[first2];
3802
+ }
3803
+ return splits;
3804
+ };
3805
+ }
3806
+ });
3807
+
3808
+ // ../../node_modules/parse-path/lib/index.js
3809
+ var require_lib2 = __commonJS({
3810
+ "../../node_modules/parse-path/lib/index.js"(exports2, module2) {
3811
+ "use strict";
3812
+ var protocols = require_lib();
3813
+ function parsePath(url) {
3814
+ var output = {
3815
+ protocols: [],
3816
+ protocol: null,
3817
+ port: null,
3818
+ resource: "",
3819
+ host: "",
3820
+ user: "",
3821
+ password: "",
3822
+ pathname: "",
3823
+ hash: "",
3824
+ search: "",
3825
+ href: url,
3826
+ query: {},
3827
+ parse_failed: false
3828
+ };
3829
+ try {
3830
+ var parsed = new URL(url);
3831
+ output.protocols = protocols(parsed);
3832
+ output.protocol = output.protocols[0];
3833
+ output.port = parsed.port;
3834
+ output.resource = parsed.hostname;
3835
+ output.host = parsed.host;
3836
+ output.user = parsed.username || "";
3837
+ output.password = parsed.password || "";
3838
+ output.pathname = parsed.pathname;
3839
+ output.hash = parsed.hash.slice(1);
3840
+ output.search = parsed.search.slice(1);
3841
+ output.href = parsed.href;
3842
+ output.query = Object.fromEntries(parsed.searchParams);
3843
+ } catch (e) {
3844
+ output.protocols = ["file"];
3845
+ output.protocol = output.protocols[0];
3846
+ output.port = "";
3847
+ output.resource = "";
3848
+ output.user = "";
3849
+ output.pathname = "";
3850
+ output.hash = "";
3851
+ output.search = "";
3852
+ output.href = url;
3853
+ output.query = {};
3854
+ output.parse_failed = true;
3855
+ }
3856
+ return output;
3857
+ }
3858
+ module2.exports = parsePath;
3859
+ }
3860
+ });
3861
+
3862
+ // ../../node_modules/parse-url/dist/index.js
3863
+ var require_dist3 = __commonJS({
3864
+ "../../node_modules/parse-url/dist/index.js"(exports2, module2) {
3865
+ "use strict";
3866
+ var require$$1 = require_lib2();
3867
+ function _interopDefaultLegacy(e) {
3868
+ return e && typeof e === "object" && "default" in e ? e : { "default": e };
3869
+ }
3870
+ var require$$1__default = /* @__PURE__ */ _interopDefaultLegacy(require$$1);
3871
+ function getAugmentedNamespace(n) {
3872
+ if (n.__esModule) return n;
3873
+ var f = n.default;
3874
+ if (typeof f == "function") {
3875
+ var a = function a2() {
3876
+ if (this instanceof a2) {
3877
+ var args2 = [null];
3878
+ args2.push.apply(args2, arguments);
3879
+ var Ctor = Function.bind.apply(f, args2);
3880
+ return new Ctor();
3881
+ }
3882
+ return f.apply(this, arguments);
3883
+ };
3884
+ a.prototype = f.prototype;
3885
+ } else a = {};
3886
+ Object.defineProperty(a, "__esModule", { value: true });
3887
+ Object.keys(n).forEach(function(k) {
3888
+ var d = Object.getOwnPropertyDescriptor(n, k);
3889
+ Object.defineProperty(a, k, d.get ? d : {
3890
+ enumerable: true,
3891
+ get: function() {
3892
+ return n[k];
3893
+ }
3894
+ });
3895
+ });
3896
+ return a;
3897
+ }
3898
+ var src = {};
3899
+ var DATA_URL_DEFAULT_MIME_TYPE = "text/plain";
3900
+ var DATA_URL_DEFAULT_CHARSET = "us-ascii";
3901
+ var testParameter = (name2, filters) => filters.some((filter) => filter instanceof RegExp ? filter.test(name2) : filter === name2);
3902
+ var normalizeDataURL = (urlString, { stripHash }) => {
3903
+ const match = /^data:(?<type>[^,]*?),(?<data>[^#]*?)(?:#(?<hash>.*))?$/.exec(urlString);
3904
+ if (!match) {
3905
+ throw new Error(`Invalid URL: ${urlString}`);
3906
+ }
3907
+ let { type, data, hash } = match.groups;
3908
+ const mediaType = type.split(";");
3909
+ hash = stripHash ? "" : hash;
3910
+ let isBase64 = false;
3911
+ if (mediaType[mediaType.length - 1] === "base64") {
3912
+ mediaType.pop();
3913
+ isBase64 = true;
3914
+ }
3915
+ const mimeType = (mediaType.shift() || "").toLowerCase();
3916
+ const attributes = mediaType.map((attribute) => {
3917
+ let [key, value = ""] = attribute.split("=").map((string) => string.trim());
3918
+ if (key === "charset") {
3919
+ value = value.toLowerCase();
3920
+ if (value === DATA_URL_DEFAULT_CHARSET) {
3921
+ return "";
3922
+ }
3923
+ }
3924
+ return `${key}${value ? `=${value}` : ""}`;
3925
+ }).filter(Boolean);
3926
+ const normalizedMediaType = [
3927
+ ...attributes
3928
+ ];
3929
+ if (isBase64) {
3930
+ normalizedMediaType.push("base64");
3931
+ }
3932
+ if (normalizedMediaType.length > 0 || mimeType && mimeType !== DATA_URL_DEFAULT_MIME_TYPE) {
3933
+ normalizedMediaType.unshift(mimeType);
3934
+ }
3935
+ return `data:${normalizedMediaType.join(";")},${isBase64 ? data.trim() : data}${hash ? `#${hash}` : ""}`;
3936
+ };
3937
+ function normalizeUrl(urlString, options) {
3938
+ options = {
3939
+ defaultProtocol: "http:",
3940
+ normalizeProtocol: true,
3941
+ forceHttp: false,
3942
+ forceHttps: false,
3943
+ stripAuthentication: true,
3944
+ stripHash: false,
3945
+ stripTextFragment: true,
3946
+ stripWWW: true,
3947
+ removeQueryParameters: [/^utm_\w+/i],
3948
+ removeTrailingSlash: true,
3949
+ removeSingleSlash: true,
3950
+ removeDirectoryIndex: false,
3951
+ sortQueryParameters: true,
3952
+ ...options
3953
+ };
3954
+ urlString = urlString.trim();
3955
+ if (/^data:/i.test(urlString)) {
3956
+ return normalizeDataURL(urlString, options);
3957
+ }
3958
+ if (/^view-source:/i.test(urlString)) {
3959
+ throw new Error("`view-source:` is not supported as it is a non-standard protocol");
3960
+ }
3961
+ const hasRelativeProtocol = urlString.startsWith("//");
3962
+ const isRelativeUrl = !hasRelativeProtocol && /^\.*\//.test(urlString);
3963
+ if (!isRelativeUrl) {
3964
+ urlString = urlString.replace(/^(?!(?:\w+:)?\/\/)|^\/\//, options.defaultProtocol);
3965
+ }
3966
+ const urlObject = new URL(urlString);
3967
+ if (options.forceHttp && options.forceHttps) {
3968
+ throw new Error("The `forceHttp` and `forceHttps` options cannot be used together");
3969
+ }
3970
+ if (options.forceHttp && urlObject.protocol === "https:") {
3971
+ urlObject.protocol = "http:";
3972
+ }
3973
+ if (options.forceHttps && urlObject.protocol === "http:") {
3974
+ urlObject.protocol = "https:";
3975
+ }
3976
+ if (options.stripAuthentication) {
3977
+ urlObject.username = "";
3978
+ urlObject.password = "";
3979
+ }
3980
+ if (options.stripHash) {
3981
+ urlObject.hash = "";
3982
+ } else if (options.stripTextFragment) {
3983
+ urlObject.hash = urlObject.hash.replace(/#?:~:text.*?$/i, "");
3984
+ }
3985
+ if (urlObject.pathname) {
3986
+ const protocolRegex = /\b[a-z][a-z\d+\-.]{1,50}:\/\//g;
3987
+ let lastIndex = 0;
3988
+ let result = "";
3989
+ for (; ; ) {
3990
+ const match = protocolRegex.exec(urlObject.pathname);
3991
+ if (!match) {
3992
+ break;
3993
+ }
3994
+ const protocol = match[0];
3995
+ const protocolAtIndex = match.index;
3996
+ const intermediate = urlObject.pathname.slice(lastIndex, protocolAtIndex);
3997
+ result += intermediate.replace(/\/{2,}/g, "/");
3998
+ result += protocol;
3999
+ lastIndex = protocolAtIndex + protocol.length;
4000
+ }
4001
+ const remnant = urlObject.pathname.slice(lastIndex, urlObject.pathname.length);
4002
+ result += remnant.replace(/\/{2,}/g, "/");
4003
+ urlObject.pathname = result;
4004
+ }
4005
+ if (urlObject.pathname) {
4006
+ try {
4007
+ urlObject.pathname = decodeURI(urlObject.pathname);
4008
+ } catch {
4009
+ }
4010
+ }
4011
+ if (options.removeDirectoryIndex === true) {
4012
+ options.removeDirectoryIndex = [/^index\.[a-z]+$/];
4013
+ }
4014
+ if (Array.isArray(options.removeDirectoryIndex) && options.removeDirectoryIndex.length > 0) {
4015
+ let pathComponents = urlObject.pathname.split("/");
4016
+ const lastComponent = pathComponents[pathComponents.length - 1];
4017
+ if (testParameter(lastComponent, options.removeDirectoryIndex)) {
4018
+ pathComponents = pathComponents.slice(0, -1);
4019
+ urlObject.pathname = pathComponents.slice(1).join("/") + "/";
4020
+ }
4021
+ }
4022
+ if (urlObject.hostname) {
4023
+ urlObject.hostname = urlObject.hostname.replace(/\.$/, "");
4024
+ if (options.stripWWW && /^www\.(?!www\.)[a-z\-\d]{1,63}\.[a-z.\-\d]{2,63}$/.test(urlObject.hostname)) {
4025
+ urlObject.hostname = urlObject.hostname.replace(/^www\./, "");
4026
+ }
4027
+ }
4028
+ if (Array.isArray(options.removeQueryParameters)) {
4029
+ for (const key of [...urlObject.searchParams.keys()]) {
4030
+ if (testParameter(key, options.removeQueryParameters)) {
4031
+ urlObject.searchParams.delete(key);
4032
+ }
4033
+ }
4034
+ }
4035
+ if (options.removeQueryParameters === true) {
4036
+ urlObject.search = "";
4037
+ }
4038
+ if (options.sortQueryParameters) {
4039
+ urlObject.searchParams.sort();
4040
+ try {
4041
+ urlObject.search = decodeURIComponent(urlObject.search);
4042
+ } catch {
4043
+ }
4044
+ }
4045
+ if (options.removeTrailingSlash) {
4046
+ urlObject.pathname = urlObject.pathname.replace(/\/$/, "");
4047
+ }
4048
+ const oldUrlString = urlString;
4049
+ urlString = urlObject.toString();
4050
+ if (!options.removeSingleSlash && urlObject.pathname === "/" && !oldUrlString.endsWith("/") && urlObject.hash === "") {
4051
+ urlString = urlString.replace(/\/$/, "");
4052
+ }
4053
+ if ((options.removeTrailingSlash || urlObject.pathname === "/") && urlObject.hash === "" && options.removeSingleSlash) {
4054
+ urlString = urlString.replace(/\/$/, "");
4055
+ }
4056
+ if (hasRelativeProtocol && !options.normalizeProtocol) {
4057
+ urlString = urlString.replace(/^http:\/\//, "//");
4058
+ }
4059
+ if (options.stripProtocol) {
4060
+ urlString = urlString.replace(/^(?:https?:)?\/\//, "");
4061
+ }
4062
+ return urlString;
4063
+ }
4064
+ var normalizeUrl$1 = /* @__PURE__ */ Object.freeze({
4065
+ __proto__: null,
4066
+ "default": normalizeUrl
4067
+ });
4068
+ var require$$0 = /* @__PURE__ */ getAugmentedNamespace(normalizeUrl$1);
4069
+ Object.defineProperty(src, "__esModule", {
4070
+ value: true
4071
+ });
4072
+ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function(obj) {
4073
+ return typeof obj;
4074
+ } : function(obj) {
4075
+ return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
4076
+ };
4077
+ var _normalizeUrl = require$$0;
4078
+ var _normalizeUrl2 = _interopRequireDefault(_normalizeUrl);
4079
+ var _parsePath = require$$1__default["default"];
4080
+ var _parsePath2 = _interopRequireDefault(_parsePath);
4081
+ function _interopRequireDefault(obj) {
4082
+ return obj && obj.__esModule ? obj : { default: obj };
4083
+ }
4084
+ var parseUrl = function parseUrl2(url) {
4085
+ var normalize3 = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : false;
4086
+ var GIT_RE = /^(?:([a-zA-Z_][a-zA-Z0-9_-]{0,31})@|https?:\/\/)([\w\.\-@]+)[\/:](([\~,\.\w,\-,\_,\/,\s]|%[0-9A-Fa-f]{2})+?(?:\.git|\/)?)$/;
4087
+ var throwErr = function throwErr2(msg) {
4088
+ var err2 = new Error(msg);
4089
+ err2.subject_url = url;
4090
+ throw err2;
4091
+ };
4092
+ if (typeof url !== "string" || !url.trim()) {
4093
+ throwErr("Invalid url.");
4094
+ }
4095
+ if (url.length > parseUrl2.MAX_INPUT_LENGTH) {
4096
+ throwErr("Input exceeds maximum length. If needed, change the value of parseUrl.MAX_INPUT_LENGTH.");
4097
+ }
4098
+ if (normalize3) {
4099
+ if ((typeof normalize3 === "undefined" ? "undefined" : _typeof(normalize3)) !== "object") {
4100
+ normalize3 = {
4101
+ stripHash: false
4102
+ };
4103
+ }
4104
+ url = (0, _normalizeUrl2.default)(url, normalize3);
4105
+ }
4106
+ var parsed = (0, _parsePath2.default)(url);
4107
+ if (parsed.parse_failed) {
4108
+ var matched = parsed.href.match(GIT_RE);
4109
+ if (matched) {
4110
+ parsed.protocols = ["ssh"];
4111
+ parsed.protocol = "ssh";
4112
+ parsed.resource = matched[2];
4113
+ parsed.host = matched[2];
4114
+ parsed.user = matched[1];
4115
+ parsed.pathname = "/" + matched[3];
4116
+ parsed.parse_failed = false;
4117
+ } else {
4118
+ throwErr("URL parsing failed.");
4119
+ }
4120
+ }
4121
+ return parsed;
4122
+ };
4123
+ parseUrl.MAX_INPUT_LENGTH = 2048;
4124
+ var _default = src.default = parseUrl;
4125
+ module2.exports = _default;
4126
+ }
4127
+ });
4128
+
4129
+ // ../../node_modules/is-ssh/lib/index.js
4130
+ var require_lib3 = __commonJS({
4131
+ "../../node_modules/is-ssh/lib/index.js"(exports2, module2) {
4132
+ "use strict";
4133
+ var protocols = require_lib();
4134
+ function isSsh(input) {
4135
+ if (Array.isArray(input)) {
4136
+ return input.indexOf("ssh") !== -1 || input.indexOf("rsync") !== -1;
4137
+ }
4138
+ if (typeof input !== "string") {
4139
+ return false;
4140
+ }
4141
+ var prots = protocols(input);
4142
+ input = input.substring(input.indexOf("://") + 3);
4143
+ if (isSsh(prots)) {
4144
+ return true;
4145
+ }
4146
+ var urlPortPattern = new RegExp(".([a-zA-Z\\d]+):(\\d+)/");
4147
+ return !input.match(urlPortPattern) && input.indexOf("@") < input.indexOf(":");
4148
+ }
4149
+ module2.exports = isSsh;
4150
+ }
4151
+ });
4152
+
4153
+ // ../../node_modules/git-up/lib/index.js
4154
+ var require_lib4 = __commonJS({
4155
+ "../../node_modules/git-up/lib/index.js"(exports2, module2) {
4156
+ "use strict";
4157
+ var parseUrl = require_dist3();
4158
+ var isSsh = require_lib3();
4159
+ function gitUp(input) {
4160
+ let output = parseUrl(input);
4161
+ output.token = "";
4162
+ if (output.password === "x-oauth-basic") {
4163
+ output.token = output.user;
4164
+ } else if (output.user === "x-token-auth") {
4165
+ output.token = output.password;
4166
+ }
4167
+ if (isSsh(output.protocols) || output.protocols.length === 0 && isSsh(input)) {
4168
+ output.protocol = "ssh";
4169
+ } else if (output.protocols.length) {
4170
+ output.protocol = output.protocols[0];
4171
+ } else {
4172
+ output.protocol = "file";
4173
+ output.protocols = ["file"];
4174
+ }
4175
+ output.href = output.href.replace(/\/$/, "");
4176
+ return output;
4177
+ }
4178
+ module2.exports = gitUp;
4179
+ }
4180
+ });
4181
+
4182
+ // ../../node_modules/git-url-parse/lib/index.js
4183
+ var require_lib5 = __commonJS({
4184
+ "../../node_modules/git-url-parse/lib/index.js"(exports2, module2) {
4185
+ "use strict";
4186
+ var gitUp = require_lib4();
4187
+ function gitUrlParse2(url, refs) {
4188
+ refs = refs || [];
4189
+ if (typeof url !== "string") {
4190
+ throw new Error("The url must be a string.");
4191
+ }
4192
+ if (!refs.every(function(item) {
4193
+ return typeof item === "string";
4194
+ })) {
4195
+ throw new Error("The refs should contain only strings");
4196
+ }
4197
+ var shorthandRe = /^([a-z\d-]{1,39})\/([-\.\w]{1,100})$/i;
4198
+ if (shorthandRe.test(url)) {
4199
+ url = "https://github.com/" + url;
4200
+ }
4201
+ var urlInfo = gitUp(url), sourceParts = urlInfo.resource.split("."), splits = null;
4202
+ urlInfo.toString = function(type) {
4203
+ return gitUrlParse2.stringify(this, type);
4204
+ };
4205
+ urlInfo.source = sourceParts.length > 2 ? sourceParts.slice(1 - sourceParts.length).join(".") : urlInfo.source = urlInfo.resource;
4206
+ urlInfo.git_suffix = /\.git$/.test(urlInfo.pathname);
4207
+ urlInfo.name = decodeURIComponent((urlInfo.pathname || urlInfo.href).replace(/(^\/)|(\/$)/g, "").replace(/\.git$/, ""));
4208
+ urlInfo.owner = decodeURIComponent(urlInfo.user);
4209
+ switch (urlInfo.source) {
4210
+ case "git.cloudforge.com":
4211
+ urlInfo.owner = urlInfo.user;
4212
+ urlInfo.organization = sourceParts[0];
4213
+ urlInfo.source = "cloudforge.com";
4214
+ break;
4215
+ case "visualstudio.com":
4216
+ if (urlInfo.resource === "vs-ssh.visualstudio.com") {
4217
+ splits = urlInfo.name.split("/");
4218
+ if (splits.length === 4) {
4219
+ urlInfo.organization = splits[1];
4220
+ urlInfo.owner = splits[2];
4221
+ urlInfo.name = splits[3];
4222
+ urlInfo.full_name = splits[2] + "/" + splits[3];
4223
+ }
4224
+ break;
4225
+ } else {
4226
+ splits = urlInfo.name.split("/");
4227
+ if (splits.length === 2) {
4228
+ urlInfo.owner = splits[1];
4229
+ urlInfo.name = splits[1];
4230
+ urlInfo.full_name = "_git/" + urlInfo.name;
4231
+ } else if (splits.length === 3) {
4232
+ urlInfo.name = splits[2];
4233
+ if (splits[0] === "DefaultCollection") {
4234
+ urlInfo.owner = splits[2];
4235
+ urlInfo.organization = splits[0];
4236
+ urlInfo.full_name = urlInfo.organization + "/_git/" + urlInfo.name;
4237
+ } else {
4238
+ urlInfo.owner = splits[0];
4239
+ urlInfo.full_name = urlInfo.owner + "/_git/" + urlInfo.name;
4240
+ }
4241
+ } else if (splits.length === 4) {
4242
+ urlInfo.organization = splits[0];
4243
+ urlInfo.owner = splits[1];
4244
+ urlInfo.name = splits[3];
4245
+ urlInfo.full_name = urlInfo.organization + "/" + urlInfo.owner + "/_git/" + urlInfo.name;
4246
+ }
4247
+ break;
4248
+ }
4249
+ // Azure DevOps (formerly Visual Studio Team Services)
4250
+ case "dev.azure.com":
4251
+ case "azure.com":
4252
+ if (urlInfo.resource === "ssh.dev.azure.com") {
4253
+ splits = urlInfo.name.split("/");
4254
+ if (splits.length === 4) {
4255
+ urlInfo.organization = splits[1];
4256
+ urlInfo.owner = splits[2];
4257
+ urlInfo.name = splits[3];
4258
+ }
4259
+ break;
4260
+ } else {
4261
+ splits = urlInfo.name.split("/");
4262
+ if (splits.length === 5) {
4263
+ urlInfo.organization = splits[0];
4264
+ urlInfo.owner = splits[1];
4265
+ urlInfo.name = splits[4];
4266
+ urlInfo.full_name = "_git/" + urlInfo.name;
4267
+ } else if (splits.length === 3) {
4268
+ urlInfo.name = splits[2];
4269
+ if (splits[0] === "DefaultCollection") {
4270
+ urlInfo.owner = splits[2];
4271
+ urlInfo.organization = splits[0];
4272
+ urlInfo.full_name = urlInfo.organization + "/_git/" + urlInfo.name;
4273
+ } else {
4274
+ urlInfo.owner = splits[0];
4275
+ urlInfo.full_name = urlInfo.owner + "/_git/" + urlInfo.name;
4276
+ }
4277
+ } else if (splits.length === 4) {
4278
+ urlInfo.organization = splits[0];
4279
+ urlInfo.owner = splits[1];
4280
+ urlInfo.name = splits[3];
4281
+ urlInfo.full_name = urlInfo.organization + "/" + urlInfo.owner + "/_git/" + urlInfo.name;
4282
+ }
4283
+ if (urlInfo.query && urlInfo.query["path"]) {
4284
+ urlInfo.filepath = urlInfo.query["path"].replace(/^\/+/g, "");
4285
+ }
4286
+ if (urlInfo.query && urlInfo.query["version"]) {
4287
+ urlInfo.ref = urlInfo.query["version"].replace(/^GB/, "");
4288
+ }
4289
+ break;
4290
+ }
4291
+ default:
4292
+ splits = urlInfo.name.split("/");
4293
+ var nameIndex = splits.length - 1;
4294
+ if (splits.length >= 2) {
4295
+ var dashIndex = splits.indexOf("-", 2);
4296
+ var blobIndex = splits.indexOf("blob", 2);
4297
+ var treeIndex = splits.indexOf("tree", 2);
4298
+ var commitIndex = splits.indexOf("commit", 2);
4299
+ var issuesIndex = splits.indexOf("issues", 2);
4300
+ var srcIndex = splits.indexOf("src", 2);
4301
+ var rawIndex = splits.indexOf("raw", 2);
4302
+ var editIndex = splits.indexOf("edit", 2);
4303
+ 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;
4304
+ urlInfo.owner = splits.slice(0, nameIndex).join("/");
4305
+ urlInfo.name = splits[nameIndex];
4306
+ if (commitIndex && issuesIndex < 0) {
4307
+ urlInfo.commit = splits[nameIndex + 2];
4308
+ }
4309
+ }
4310
+ urlInfo.ref = "";
4311
+ urlInfo.filepathtype = "";
4312
+ urlInfo.filepath = "";
4313
+ var offsetNameIndex = splits.length > nameIndex && splits[nameIndex + 1] === "-" ? nameIndex + 1 : nameIndex;
4314
+ if (splits.length > offsetNameIndex + 2 && ["raw", "src", "blob", "tree", "edit"].indexOf(splits[offsetNameIndex + 1]) >= 0) {
4315
+ urlInfo.filepathtype = splits[offsetNameIndex + 1];
4316
+ urlInfo.ref = splits[offsetNameIndex + 2];
4317
+ if (splits.length > offsetNameIndex + 3) {
4318
+ urlInfo.filepath = splits.slice(offsetNameIndex + 3).join("/");
4319
+ }
4320
+ }
4321
+ urlInfo.organization = urlInfo.owner;
4322
+ break;
4323
+ }
4324
+ if (!urlInfo.full_name) {
4325
+ urlInfo.full_name = urlInfo.owner;
4326
+ if (urlInfo.name) {
4327
+ urlInfo.full_name && (urlInfo.full_name += "/");
4328
+ urlInfo.full_name += urlInfo.name;
4329
+ }
4330
+ }
4331
+ if (urlInfo.owner.startsWith("scm/")) {
4332
+ urlInfo.source = "bitbucket-server";
4333
+ urlInfo.owner = urlInfo.owner.replace("scm/", "");
4334
+ urlInfo.organization = urlInfo.owner;
4335
+ urlInfo.full_name = urlInfo.owner + "/" + urlInfo.name;
4336
+ }
4337
+ var bitbucket = /(projects|users)\/(.*?)\/repos\/(.*?)((\/.*$)|$)/;
4338
+ var matches = bitbucket.exec(urlInfo.pathname);
4339
+ if (matches != null) {
4340
+ urlInfo.source = "bitbucket-server";
4341
+ if (matches[1] === "users") {
4342
+ urlInfo.owner = "~" + matches[2];
4343
+ } else {
4344
+ urlInfo.owner = matches[2];
4345
+ }
4346
+ urlInfo.organization = urlInfo.owner;
4347
+ urlInfo.name = matches[3];
4348
+ splits = matches[4].split("/");
4349
+ if (splits.length > 1) {
4350
+ if (["raw", "browse"].indexOf(splits[1]) >= 0) {
4351
+ urlInfo.filepathtype = splits[1];
4352
+ if (splits.length > 2) {
4353
+ urlInfo.filepath = splits.slice(2).join("/");
4354
+ }
4355
+ } else if (splits[1] === "commits" && splits.length > 2) {
4356
+ urlInfo.commit = splits[2];
4357
+ }
4358
+ }
4359
+ urlInfo.full_name = urlInfo.owner + "/" + urlInfo.name;
4360
+ if (urlInfo.query.at) {
4361
+ urlInfo.ref = urlInfo.query.at;
4362
+ } else {
4363
+ urlInfo.ref = "";
4364
+ }
4365
+ }
4366
+ if (refs.length !== 0 && urlInfo.ref) {
4367
+ urlInfo.ref = findLongestMatchingSubstring(urlInfo.href, refs) || urlInfo.ref;
4368
+ urlInfo.filepath = urlInfo.href.split(urlInfo.ref + "/")[1];
4369
+ }
4370
+ return urlInfo;
4371
+ }
4372
+ gitUrlParse2.stringify = function(obj, type) {
4373
+ type = type || (obj.protocols && obj.protocols.length ? obj.protocols.join("+") : obj.protocol);
4374
+ var port = obj.port ? ":" + obj.port : "";
4375
+ var user = obj.user || "git";
4376
+ var maybeGitSuffix = obj.git_suffix ? ".git" : "";
4377
+ switch (type) {
4378
+ case "ssh":
4379
+ if (port) return "ssh://" + user + "@" + obj.resource + port + "/" + obj.full_name + maybeGitSuffix;
4380
+ else return user + "@" + obj.resource + ":" + obj.full_name + maybeGitSuffix;
4381
+ case "git+ssh":
4382
+ case "ssh+git":
4383
+ case "ftp":
4384
+ case "ftps":
4385
+ return type + "://" + user + "@" + obj.resource + port + "/" + obj.full_name + maybeGitSuffix;
4386
+ case "http":
4387
+ case "https":
4388
+ var auth = obj.token ? buildToken(obj) : obj.user && (obj.protocols.includes("http") || obj.protocols.includes("https")) ? obj.user + "@" : "";
4389
+ return type + "://" + auth + obj.resource + port + "/" + buildPath(obj) + maybeGitSuffix;
4390
+ default:
4391
+ return obj.href;
4392
+ }
4393
+ };
4394
+ function buildToken(obj) {
4395
+ switch (obj.source) {
4396
+ case "bitbucket.org":
4397
+ return "x-token-auth:" + obj.token + "@";
4398
+ default:
4399
+ return obj.token + "@";
4400
+ }
4401
+ }
4402
+ function buildPath(obj) {
4403
+ switch (obj.source) {
4404
+ case "bitbucket-server":
4405
+ return "scm/" + obj.full_name;
4406
+ default:
4407
+ var encoded_full_name = obj.full_name.split("/").map(function(x) {
4408
+ return encodeURIComponent(x);
4409
+ }).join("/");
4410
+ return encoded_full_name;
4411
+ }
4412
+ }
4413
+ function findLongestMatchingSubstring(string, array) {
4414
+ var longestMatch = "";
4415
+ array.forEach(function(item) {
4416
+ if (string.includes(item) && item.length > longestMatch.length) {
4417
+ longestMatch = item;
4418
+ }
4419
+ });
4420
+ return longestMatch;
4421
+ }
4422
+ module2.exports = gitUrlParse2;
4423
+ }
4424
+ });
4425
+
3782
4426
  // src/server/bin.ts
3783
4427
  var import_commander = require("commander");
3784
4428
  var import_v42 = require("zod/v4");
@@ -3955,6 +4599,24 @@ var import_node_fs = require("fs");
3955
4599
  var fs3 = __toESM(require("fs/promises"), 1);
3956
4600
  var path2 = __toESM(require("path"), 1);
3957
4601
 
4602
+ // ../git/dist/concurrency.js
4603
+ async function mapWithConcurrency(items, concurrency, mapper, options) {
4604
+ if (items.length === 0)
4605
+ return [];
4606
+ const results = new Array(items.length);
4607
+ let index = 0;
4608
+ const worker = async () => {
4609
+ while (index < items.length) {
4610
+ if (options?.signal?.aborted)
4611
+ return;
4612
+ const i2 = index++;
4613
+ results[i2] = await mapper(items[i2]);
4614
+ }
4615
+ };
4616
+ await Promise.all(Array.from({ length: Math.min(concurrency, items.length) }, () => worker()));
4617
+ return results;
4618
+ }
4619
+
3958
4620
  // ../../node_modules/simple-git/dist/esm/index.js
3959
4621
  var import_node_buffer = require("buffer");
3960
4622
  var import_file_exists = __toESM(require_dist(), 1);
@@ -3992,8 +4654,8 @@ function pathspec(...paths) {
3992
4654
  cache.set(key, paths);
3993
4655
  return key;
3994
4656
  }
3995
- function isPathSpec(path17) {
3996
- return path17 instanceof String && cache.has(path17);
4657
+ function isPathSpec(path18) {
4658
+ return path18 instanceof String && cache.has(path18);
3997
4659
  }
3998
4660
  function toPaths(pathSpec) {
3999
4661
  return cache.get(pathSpec) || [];
@@ -4082,8 +4744,8 @@ function toLinesWithContent(input = "", trimmed2 = true, separator = "\n") {
4082
4744
  function forEachLineWithContent(input, callback) {
4083
4745
  return toLinesWithContent(input, true).map((line) => callback(line));
4084
4746
  }
4085
- function folderExists(path17) {
4086
- return (0, import_file_exists.exists)(path17, import_file_exists.FOLDER);
4747
+ function folderExists(path18) {
4748
+ return (0, import_file_exists.exists)(path18, import_file_exists.FOLDER);
4087
4749
  }
4088
4750
  function append(target, item) {
4089
4751
  if (Array.isArray(target)) {
@@ -4487,8 +5149,8 @@ function checkIsRepoRootTask() {
4487
5149
  commands,
4488
5150
  format: "utf-8",
4489
5151
  onError,
4490
- parser(path17) {
4491
- return /^\.(git)?$/.test(path17.trim());
5152
+ parser(path18) {
5153
+ return /^\.(git)?$/.test(path18.trim());
4492
5154
  }
4493
5155
  };
4494
5156
  }
@@ -4922,11 +5584,11 @@ function parseGrep(grep) {
4922
5584
  const paths = /* @__PURE__ */ new Set();
4923
5585
  const results = {};
4924
5586
  forEachLineWithContent(grep, (input) => {
4925
- const [path17, line, preview] = input.split(NULL);
4926
- paths.add(path17);
4927
- (results[path17] = results[path17] || []).push({
5587
+ const [path18, line, preview] = input.split(NULL);
5588
+ paths.add(path18);
5589
+ (results[path18] = results[path18] || []).push({
4928
5590
  line: asNumber(line),
4929
- path: path17,
5591
+ path: path18,
4930
5592
  preview
4931
5593
  });
4932
5594
  });
@@ -5691,14 +6353,14 @@ var init_hash_object = __esm({
5691
6353
  init_task();
5692
6354
  }
5693
6355
  });
5694
- function parseInit(bare, path17, text2) {
6356
+ function parseInit(bare, path18, text2) {
5695
6357
  const response = String(text2).trim();
5696
6358
  let result;
5697
6359
  if (result = initResponseRegex.exec(response)) {
5698
- return new InitSummary(bare, path17, false, result[1]);
6360
+ return new InitSummary(bare, path18, false, result[1]);
5699
6361
  }
5700
6362
  if (result = reInitResponseRegex.exec(response)) {
5701
- return new InitSummary(bare, path17, true, result[1]);
6363
+ return new InitSummary(bare, path18, true, result[1]);
5702
6364
  }
5703
6365
  let gitDir = "";
5704
6366
  const tokens = response.split(" ");
@@ -5709,7 +6371,7 @@ function parseInit(bare, path17, text2) {
5709
6371
  break;
5710
6372
  }
5711
6373
  }
5712
- return new InitSummary(bare, path17, /^re/i.test(response), gitDir);
6374
+ return new InitSummary(bare, path18, /^re/i.test(response), gitDir);
5713
6375
  }
5714
6376
  var InitSummary;
5715
6377
  var initResponseRegex;
@@ -5718,9 +6380,9 @@ var init_InitSummary = __esm({
5718
6380
  "src/lib/responses/InitSummary.ts"() {
5719
6381
  "use strict";
5720
6382
  InitSummary = class {
5721
- constructor(bare, path17, existing, gitDir) {
6383
+ constructor(bare, path18, existing, gitDir) {
5722
6384
  this.bare = bare;
5723
- this.path = path17;
6385
+ this.path = path18;
5724
6386
  this.existing = existing;
5725
6387
  this.gitDir = gitDir;
5726
6388
  }
@@ -5732,7 +6394,7 @@ var init_InitSummary = __esm({
5732
6394
  function hasBareCommand(command) {
5733
6395
  return command.includes(bareCommand);
5734
6396
  }
5735
- function initTask(bare = false, path17, customArgs) {
6397
+ function initTask(bare = false, path18, customArgs) {
5736
6398
  const commands = ["init", ...customArgs];
5737
6399
  if (bare && !hasBareCommand(commands)) {
5738
6400
  commands.splice(1, 0, bareCommand);
@@ -5741,7 +6403,7 @@ function initTask(bare = false, path17, customArgs) {
5741
6403
  commands,
5742
6404
  format: "utf-8",
5743
6405
  parser(text2) {
5744
- return parseInit(commands.includes("--bare"), path17, text2);
6406
+ return parseInit(commands.includes("--bare"), path18, text2);
5745
6407
  }
5746
6408
  };
5747
6409
  }
@@ -6557,12 +7219,12 @@ var init_FileStatusSummary = __esm({
6557
7219
  "use strict";
6558
7220
  fromPathRegex = /^(.+)\0(.+)$/;
6559
7221
  FileStatusSummary = class {
6560
- constructor(path17, index, working_dir) {
6561
- this.path = path17;
7222
+ constructor(path18, index, working_dir) {
7223
+ this.path = path18;
6562
7224
  this.index = index;
6563
7225
  this.working_dir = working_dir;
6564
7226
  if (index === "R" || working_dir === "R") {
6565
- const detail = fromPathRegex.exec(path17) || [null, path17, path17];
7227
+ const detail = fromPathRegex.exec(path18) || [null, path18, path18];
6566
7228
  this.from = detail[2] || "";
6567
7229
  this.path = detail[1] || "";
6568
7230
  }
@@ -6593,14 +7255,14 @@ function splitLine(result, lineStr) {
6593
7255
  default:
6594
7256
  return;
6595
7257
  }
6596
- function data(index, workingDir, path17) {
7258
+ function data(index, workingDir, path18) {
6597
7259
  const raw = `${index}${workingDir}`;
6598
7260
  const handler = parsers6.get(raw);
6599
7261
  if (handler) {
6600
- handler(result, path17);
7262
+ handler(result, path18);
6601
7263
  }
6602
7264
  if (raw !== "##" && raw !== "!!") {
6603
- result.files.push(new FileStatusSummary(path17, index, workingDir));
7265
+ result.files.push(new FileStatusSummary(path18, index, workingDir));
6604
7266
  }
6605
7267
  }
6606
7268
  }
@@ -6913,9 +7575,9 @@ var init_simple_git_api = __esm({
6913
7575
  next
6914
7576
  );
6915
7577
  }
6916
- hashObject(path17, write) {
7578
+ hashObject(path18, write) {
6917
7579
  return this._runTask(
6918
- hashObjectTask(path17, write === true),
7580
+ hashObjectTask(path18, write === true),
6919
7581
  trailingFunctionArgument(arguments)
6920
7582
  );
6921
7583
  }
@@ -7268,8 +7930,8 @@ var init_branch = __esm({
7268
7930
  }
7269
7931
  });
7270
7932
  function toPath(input) {
7271
- const path17 = input.trim().replace(/^["']|["']$/g, "");
7272
- return path17 && (0, import_node_path.normalize)(path17);
7933
+ const path18 = input.trim().replace(/^["']|["']$/g, "");
7934
+ return path18 && (0, import_node_path.normalize)(path18);
7273
7935
  }
7274
7936
  var parseCheckIgnore;
7275
7937
  var init_CheckIgnore = __esm({
@@ -7583,8 +8245,8 @@ __export(sub_module_exports, {
7583
8245
  subModuleTask: () => subModuleTask,
7584
8246
  updateSubModuleTask: () => updateSubModuleTask
7585
8247
  });
7586
- function addSubModuleTask(repo, path17) {
7587
- return subModuleTask(["add", repo, path17]);
8248
+ function addSubModuleTask(repo, path18) {
8249
+ return subModuleTask(["add", repo, path18]);
7588
8250
  }
7589
8251
  function initSubModuleTask(customArgs) {
7590
8252
  return subModuleTask(["init", ...customArgs]);
@@ -7914,8 +8576,8 @@ var require_git = __commonJS2({
7914
8576
  }
7915
8577
  return this._runTask(straightThroughStringTask2(command, this._trimmed), next);
7916
8578
  };
7917
- Git2.prototype.submoduleAdd = function(repo, path17, then) {
7918
- return this._runTask(addSubModuleTask2(repo, path17), trailingFunctionArgument2(arguments));
8579
+ Git2.prototype.submoduleAdd = function(repo, path18, then) {
8580
+ return this._runTask(addSubModuleTask2(repo, path18), trailingFunctionArgument2(arguments));
7919
8581
  };
7920
8582
  Git2.prototype.submoduleUpdate = function(args2, then) {
7921
8583
  return this._runTask(
@@ -8576,10 +9238,10 @@ var AsyncReaderWriterLock = class {
8576
9238
  this.readers++;
8577
9239
  return;
8578
9240
  }
8579
- return new Promise((resolve7) => {
9241
+ return new Promise((resolve8) => {
8580
9242
  this.readQueue.push(() => {
8581
9243
  this.readers++;
8582
- resolve7();
9244
+ resolve8();
8583
9245
  });
8584
9246
  });
8585
9247
  }
@@ -8593,11 +9255,11 @@ var AsyncReaderWriterLock = class {
8593
9255
  return;
8594
9256
  }
8595
9257
  this.writerWaiting = true;
8596
- return new Promise((resolve7) => {
9258
+ return new Promise((resolve8) => {
8597
9259
  this.writeQueue.push(() => {
8598
9260
  this.writerWaiting = this.writeQueue.length > 0;
8599
9261
  this.writer = true;
8600
- resolve7();
9262
+ resolve8();
8601
9263
  });
8602
9264
  });
8603
9265
  }
@@ -8804,12 +9466,12 @@ async function inspectGitBusyState(git) {
8804
9466
 
8805
9467
  // src/server/agent-server.ts
8806
9468
  var import_hono = require("hono");
8807
- var import_zod3 = require("zod");
9469
+ var import_zod4 = require("zod");
8808
9470
 
8809
9471
  // package.json
8810
9472
  var package_default = {
8811
9473
  name: "@posthog/agent",
8812
- version: "2.3.643",
9474
+ version: "2.3.655",
8813
9475
  repository: "https://github.com/PostHog/code",
8814
9476
  description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
8815
9477
  exports: {
@@ -9081,17 +9743,17 @@ var Pushable = class {
9081
9743
  resolvers = [];
9082
9744
  done = false;
9083
9745
  push(item) {
9084
- const resolve7 = this.resolvers.shift();
9085
- if (resolve7) {
9086
- resolve7({ value: item, done: false });
9746
+ const resolve8 = this.resolvers.shift();
9747
+ if (resolve8) {
9748
+ resolve8({ value: item, done: false });
9087
9749
  } else {
9088
9750
  this.queue.push(item);
9089
9751
  }
9090
9752
  }
9091
9753
  end() {
9092
9754
  this.done = true;
9093
- for (const resolve7 of this.resolvers) {
9094
- resolve7({ value: void 0, done: true });
9755
+ for (const resolve8 of this.resolvers) {
9756
+ resolve8({ value: void 0, done: true });
9095
9757
  }
9096
9758
  this.resolvers = [];
9097
9759
  }
@@ -9108,8 +9770,8 @@ var Pushable = class {
9108
9770
  done: true
9109
9771
  });
9110
9772
  }
9111
- return new Promise((resolve7) => {
9112
- this.resolvers.push(resolve7);
9773
+ return new Promise((resolve8) => {
9774
+ this.resolvers.push(resolve8);
9113
9775
  });
9114
9776
  }
9115
9777
  };
@@ -9223,20 +9885,20 @@ function nodeReadableToWebReadable(nodeStream) {
9223
9885
  function nodeWritableToWebWritable(nodeStream) {
9224
9886
  return new import_web.WritableStream({
9225
9887
  write(chunk) {
9226
- return new Promise((resolve7, reject) => {
9888
+ return new Promise((resolve8, reject) => {
9227
9889
  const ok = nodeStream.write(Buffer.from(chunk), (err2) => {
9228
9890
  if (err2) reject(err2);
9229
9891
  });
9230
9892
  if (ok) {
9231
- resolve7();
9893
+ resolve8();
9232
9894
  } else {
9233
- nodeStream.once("drain", resolve7);
9895
+ nodeStream.once("drain", resolve8);
9234
9896
  }
9235
9897
  });
9236
9898
  },
9237
9899
  close() {
9238
- return new Promise((resolve7) => {
9239
- nodeStream.end(resolve7);
9900
+ return new Promise((resolve8) => {
9901
+ nodeStream.end(resolve8);
9240
9902
  });
9241
9903
  },
9242
9904
  abort(reason) {
@@ -9249,11 +9911,11 @@ function nodeWritableToWebWritable(nodeStream) {
9249
9911
 
9250
9912
  // src/adapters/claude/claude-agent.ts
9251
9913
  var import_node_crypto = require("crypto");
9252
- var fs9 = __toESM(require("fs"), 1);
9253
- var os5 = __toESM(require("os"), 1);
9254
- var path11 = __toESM(require("path"), 1);
9914
+ var fs10 = __toESM(require("fs"), 1);
9915
+ var os6 = __toESM(require("os"), 1);
9916
+ var path12 = __toESM(require("path"), 1);
9255
9917
  var import_sdk2 = require("@agentclientprotocol/sdk");
9256
- var import_claude_agent_sdk = require("@anthropic-ai/claude-agent-sdk");
9918
+ var import_claude_agent_sdk2 = require("@anthropic-ai/claude-agent-sdk");
9257
9919
  var import_uuid = require("uuid");
9258
9920
 
9259
9921
  // src/enrichment/file-enricher.ts
@@ -13389,10 +14051,360 @@ async function buildWrapperContext(deps, content, langId, absPath) {
13389
14051
  return { wrappersByLocalName, namespaceWrappers };
13390
14052
  }
13391
14053
 
14054
+ // ../git/dist/signed-commit.js
14055
+ var childProcess3 = __toESM(require("child_process"), 1);
14056
+
14057
+ // ../git/dist/gh.js
14058
+ var childProcess = __toESM(require("child_process"), 1);
14059
+ function execGh(args2, options = {}) {
14060
+ const env = options.env ? { ...process.env, ...options.env } : process.env;
14061
+ return new Promise((resolve8) => {
14062
+ const child = childProcess.execFile("gh", args2, { cwd: options.cwd, env, timeout: options.timeoutMs ?? 0 }, (error, stdout, stderr) => {
14063
+ if (!error) {
14064
+ resolve8({ stdout, stderr, exitCode: 0 });
14065
+ return;
14066
+ }
14067
+ const err2 = error;
14068
+ const timedOut = err2.killed === true && !!options.timeoutMs;
14069
+ const exitCode = typeof err2.code === "number" ? err2.code : err2.code === "ENOENT" ? 127 : 1;
14070
+ resolve8({
14071
+ stdout: stdout ?? err2.stdout ?? "",
14072
+ stderr: stderr ?? err2.stderr ?? "",
14073
+ exitCode,
14074
+ error: timedOut ? `gh timed out after ${options.timeoutMs}ms` : err2.message
14075
+ });
14076
+ });
14077
+ if (options.input !== void 0) {
14078
+ child.stdin?.end(options.input);
14079
+ }
14080
+ });
14081
+ }
14082
+ var TRANSIENT_GH_PATTERNS = [
14083
+ /HTTP 5\d\d/,
14084
+ /HTTP 499/,
14085
+ /\btimed out\b/i,
14086
+ /\bETIMEDOUT\b/,
14087
+ /\bECONNRESET\b/,
14088
+ /\bECONNREFUSED\b/,
14089
+ /\bEAI_AGAIN\b/,
14090
+ /connection reset/i
14091
+ ];
14092
+ function isTransientGhFailure(res) {
14093
+ if (res.exitCode === 0) {
14094
+ return false;
14095
+ }
14096
+ const text2 = `${res.stderr} ${res.error ?? ""} ${res.stdout}`;
14097
+ return TRANSIENT_GH_PATTERNS.some((re) => re.test(text2));
14098
+ }
14099
+ var sleep = (ms) => new Promise((resolve8) => setTimeout(resolve8, ms));
14100
+ async function execGhWithRetry(args2, options = {}, retry = {}, exec = execGh) {
14101
+ const maxAttempts = retry.maxAttempts ?? 3;
14102
+ const backoffMs = retry.backoffMs ?? 500;
14103
+ let res = await exec(args2, options);
14104
+ for (let attempt = 2; attempt <= maxAttempts && isTransientGhFailure(res); attempt++) {
14105
+ await sleep(backoffMs * 2 ** (attempt - 2));
14106
+ res = await exec(args2, options);
14107
+ }
14108
+ return res;
14109
+ }
14110
+
14111
+ // ../git/dist/trailers.js
14112
+ function buildPostHogTrailers(taskId) {
14113
+ const trailers = ["Generated-By: PostHog Code"];
14114
+ if (taskId)
14115
+ trailers.push(`Task-Id: ${taskId}`);
14116
+ return trailers;
14117
+ }
14118
+
14119
+ // ../git/dist/utils.js
14120
+ var childProcess2 = __toESM(require("child_process"), 1);
14121
+ var fs5 = __toESM(require("fs/promises"), 1);
14122
+ var os = __toESM(require("os"), 1);
14123
+ var path5 = __toESM(require("path"), 1);
14124
+ var import_git_url_parse = __toESM(require_lib5(), 1);
14125
+ function parseGithubUrl(url) {
14126
+ if (!url)
14127
+ return null;
14128
+ let parsed;
14129
+ try {
14130
+ parsed = (0, import_git_url_parse.default)(url.trim());
14131
+ } catch {
14132
+ return null;
14133
+ }
14134
+ const resource = parsed.resource.toLowerCase();
14135
+ if (resource !== "github.com" && resource !== "ssh.github.com")
14136
+ return null;
14137
+ const raw = parsed.pathname.split("/");
14138
+ if (raw[0] !== "")
14139
+ return null;
14140
+ const parts2 = raw[raw.length - 1] === "" ? raw.slice(1, -1) : raw.slice(1);
14141
+ if (parts2.length < 2 || parts2.some((p) => p === ""))
14142
+ return null;
14143
+ const [owner, repoRaw, segment, num] = parts2;
14144
+ const repo = repoRaw.replace(/\.git$/, "");
14145
+ if (segment === "issues" || segment === "pull") {
14146
+ const number = Number(num);
14147
+ if (!Number.isInteger(number) || number <= 0)
14148
+ return null;
14149
+ return {
14150
+ kind: segment === "pull" ? "pr" : "issue",
14151
+ owner,
14152
+ repo,
14153
+ number
14154
+ };
14155
+ }
14156
+ return { kind: "repo", owner, repo };
14157
+ }
14158
+
14159
+ // ../git/dist/signed-commit.js
14160
+ var DEFAULT_MAX_PAYLOAD_BYTES = 35 * 1024 * 1024;
14161
+ var MAX_GIT_BUFFER = 256 * 1024 * 1024;
14162
+ var GH_GRAPHQL_TIMEOUT_MS = 3e4;
14163
+ var OversizedFileError = class extends Error {
14164
+ path;
14165
+ bytes;
14166
+ maxBytes;
14167
+ constructor(path18, bytes, maxBytes) {
14168
+ super(`File '${path18}' (~${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.`);
14169
+ this.path = path18;
14170
+ this.bytes = bytes;
14171
+ this.maxBytes = maxBytes;
14172
+ this.name = "OversizedFileError";
14173
+ }
14174
+ };
14175
+ function runGit(args2, cwd) {
14176
+ return new Promise((resolve8) => {
14177
+ childProcess3.execFile("git", args2, { cwd, maxBuffer: MAX_GIT_BUFFER, encoding: "buffer" }, (error, stdout, stderr) => {
14178
+ const err2 = error;
14179
+ const exitCode = err2 && typeof err2.code === "number" ? err2.code : err2 ? 1 : 0;
14180
+ resolve8({
14181
+ stdout: stdout ?? Buffer.alloc(0),
14182
+ stderr: (stderr ?? Buffer.alloc(0)).toString("utf8"),
14183
+ exitCode
14184
+ });
14185
+ });
14186
+ });
14187
+ }
14188
+ async function gitText(args2, cwd) {
14189
+ const r = await runGit(args2, cwd);
14190
+ if (r.exitCode !== 0) {
14191
+ throw new Error(`git ${args2.join(" ")} failed: ${r.stderr.trim()}`);
14192
+ }
14193
+ return r.stdout.toString("utf8").trim();
14194
+ }
14195
+ async function resolveRepoNameWithOwner(ctx) {
14196
+ const url = await gitText(["remote", "get-url", "origin"], ctx.cwd);
14197
+ const parsed = parseGithubUrl(url);
14198
+ if (!parsed) {
14199
+ throw new Error(`Could not parse owner/repo from origin remote: ${url}`);
14200
+ }
14201
+ return `${parsed.owner}/${parsed.repo}`;
14202
+ }
14203
+ async function resolveBaseBranch(ctx) {
14204
+ if (ctx.baseBranch)
14205
+ return ctx.baseBranch;
14206
+ const r = await runGit(["symbolic-ref", "--short", "refs/remotes/origin/HEAD"], ctx.cwd);
14207
+ if (r.exitCode !== 0)
14208
+ return null;
14209
+ return r.stdout.toString("utf8").trim().replace(/^origin\//, "") || null;
14210
+ }
14211
+ async function resolveBranchName(ctx, input) {
14212
+ const branch = input.branch ? input.branch.replace(/^refs\/heads\//, "") : await resolveCurrentBranch(ctx);
14213
+ const baseBranch = await resolveBaseBranch(ctx);
14214
+ if (baseBranch && branch === baseBranch) {
14215
+ throw new Error(`Refusing to commit directly to base branch '${baseBranch}'. Pass a 'branch' name prefixed with posthog-code/.`);
14216
+ }
14217
+ return branch;
14218
+ }
14219
+ async function resolveCurrentBranch(ctx) {
14220
+ const current2 = await gitText(["rev-parse", "--abbrev-ref", "HEAD"], ctx.cwd);
14221
+ if (!current2 || current2 === "HEAD") {
14222
+ throw new Error("Detached HEAD \u2014 pass a `branch` to git_signed_commit (e.g. posthog-code/...).");
14223
+ }
14224
+ return current2;
14225
+ }
14226
+ async function remoteTip(ctx, branch) {
14227
+ const out2 = await gitText(["ls-remote", "--heads", "origin", branch], ctx.cwd);
14228
+ if (!out2)
14229
+ return null;
14230
+ return out2.split(" ")[0]?.trim() || null;
14231
+ }
14232
+ async function createRef(ctx, repo, branch, sha) {
14233
+ const res = await execGh([
14234
+ "api",
14235
+ "-X",
14236
+ "POST",
14237
+ `/repos/${repo}/git/refs`,
14238
+ "-f",
14239
+ `ref=refs/heads/${branch}`,
14240
+ "-f",
14241
+ `sha=${sha}`
14242
+ ], { cwd: ctx.cwd, env: ghTokenEnv(ctx.token) });
14243
+ if (res.exitCode !== 0) {
14244
+ throw new Error(`Failed to create branch '${branch}': ${res.stderr || res.error}`);
14245
+ }
14246
+ }
14247
+ var GITHUB_TOKEN_ENV_VARS = ["GH_TOKEN", "GITHUB_TOKEN"];
14248
+ function readGithubTokenFromEnv(env = process.env) {
14249
+ for (const name2 of GITHUB_TOKEN_ENV_VARS) {
14250
+ if (env[name2])
14251
+ return env[name2];
14252
+ }
14253
+ return void 0;
14254
+ }
14255
+ function ghTokenEnv(token) {
14256
+ return Object.fromEntries(GITHUB_TOKEN_ENV_VARS.map((name2) => [name2, token]));
14257
+ }
14258
+ var STAGED_READ_CONCURRENCY = 16;
14259
+ async function buildFileChanges(ctx, baseOid) {
14260
+ const diff = await runGit(["diff", "--cached", "-z", "--no-renames", "--name-status", baseOid], ctx.cwd);
14261
+ if (diff.exitCode !== 0) {
14262
+ throw new Error(`git diff --cached failed: ${diff.stderr.trim()}`);
14263
+ }
14264
+ const tokens = diff.stdout.toString("utf8").split("\0").filter(Boolean);
14265
+ const addPaths = [];
14266
+ const deletions = [];
14267
+ for (let i2 = 0; i2 + 1 < tokens.length; i2 += 2) {
14268
+ const path18 = tokens[i2 + 1];
14269
+ if (tokens[i2].startsWith("D")) {
14270
+ deletions.push({ path: path18 });
14271
+ } else {
14272
+ addPaths.push(path18);
14273
+ }
14274
+ }
14275
+ const additions = await mapWithConcurrency(addPaths, STAGED_READ_CONCURRENCY, async (path18) => {
14276
+ const r = await runGit(["show", `:${path18}`], ctx.cwd);
14277
+ if (r.exitCode !== 0) {
14278
+ throw new Error(`Failed to read staged file '${path18}': ${r.stderr.trim()}`);
14279
+ }
14280
+ return { path: path18, contents: r.stdout.toString("base64") };
14281
+ });
14282
+ return { additions, deletions };
14283
+ }
14284
+ function additionBytes(a) {
14285
+ return a.contents.length + a.path.length + 32;
14286
+ }
14287
+ function chunkFileChanges(changes, maxBytes) {
14288
+ for (const a of changes.additions) {
14289
+ const bytes = additionBytes(a);
14290
+ if (bytes > maxBytes)
14291
+ throw new OversizedFileError(a.path, bytes, maxBytes);
14292
+ }
14293
+ if (changes.additions.length === 0) {
14294
+ return [{ additions: [], deletions: changes.deletions }];
14295
+ }
14296
+ const chunks = [];
14297
+ let cur = { additions: [], deletions: [...changes.deletions] };
14298
+ let curBytes = changes.deletions.reduce((n, d) => n + d.path.length + 16, 0);
14299
+ for (const a of changes.additions) {
14300
+ const bytes = additionBytes(a);
14301
+ if (cur.additions.length > 0 && curBytes + bytes > maxBytes) {
14302
+ chunks.push(cur);
14303
+ cur = { additions: [], deletions: [] };
14304
+ curBytes = 0;
14305
+ }
14306
+ cur.additions.push(a);
14307
+ curBytes += bytes;
14308
+ }
14309
+ chunks.push(cur);
14310
+ return chunks;
14311
+ }
14312
+ var CREATE_COMMIT_MUTATION = `mutation($input: CreateCommitOnBranchInput!) {
14313
+ createCommitOnBranch(input: $input) { commit { oid url } }
14314
+ }`;
14315
+ async function createCommitOnBranch(ctx, repo, branch, expectedHeadOid, headline, body2, changes) {
14316
+ const payload = JSON.stringify({
14317
+ query: CREATE_COMMIT_MUTATION,
14318
+ variables: {
14319
+ input: {
14320
+ branch: { repositoryNameWithOwner: repo, branchName: branch },
14321
+ expectedHeadOid,
14322
+ message: { headline, body: body2 },
14323
+ fileChanges: changes
14324
+ }
14325
+ }
14326
+ });
14327
+ const res = await execGhWithRetry(["api", "graphql", "--input", "-"], {
14328
+ cwd: ctx.cwd,
14329
+ input: payload,
14330
+ env: ghTokenEnv(ctx.token),
14331
+ // Bound each attempt so a stalled connection can't hang the tool forever.
14332
+ timeoutMs: GH_GRAPHQL_TIMEOUT_MS
14333
+ }, { maxAttempts: 3 });
14334
+ if (res.exitCode !== 0) {
14335
+ throw new Error(`createCommitOnBranch failed: ${res.stderr || res.error || res.stdout}`);
14336
+ }
14337
+ let parsed;
14338
+ try {
14339
+ parsed = JSON.parse(res.stdout);
14340
+ } catch {
14341
+ throw new Error(`createCommitOnBranch returned non-JSON: ${res.stdout.slice(0, 500)}`);
14342
+ }
14343
+ if (parsed.errors) {
14344
+ throw new Error(`createCommitOnBranch errors: ${JSON.stringify(parsed.errors)}`);
14345
+ }
14346
+ const commit = parsed.data?.createCommitOnBranch?.commit;
14347
+ if (!commit?.oid) {
14348
+ throw new Error(`createCommitOnBranch returned no commit: ${res.stdout}`);
14349
+ }
14350
+ return commit;
14351
+ }
14352
+ async function syncLocalCheckout(ctx, branch, newOid) {
14353
+ const steps = [
14354
+ ["fetch", ["fetch", "--no-tags", "origin", branch]],
14355
+ ["update-ref", ["update-ref", `refs/heads/${branch}`, newOid]],
14356
+ ["symbolic-ref", ["symbolic-ref", "HEAD", `refs/heads/${branch}`]],
14357
+ ["reset", ["reset", "-q"]]
14358
+ ];
14359
+ for (const [label, args2] of steps) {
14360
+ const r = await runGit(args2, ctx.cwd);
14361
+ if (r.exitCode !== 0) {
14362
+ process.stderr.write(`[signed-commit] local sync step '${label}' failed after committing ${newOid}: ${r.stderr.trim()}
14363
+ `);
14364
+ }
14365
+ }
14366
+ }
14367
+ async function createSignedCommit(ctx, input) {
14368
+ const [repo, branch] = await Promise.all([
14369
+ resolveRepoNameWithOwner(ctx),
14370
+ resolveBranchName(ctx, input)
14371
+ ]);
14372
+ if (input.paths && input.paths.length > 0) {
14373
+ const r = await runGit(["add", "--", ...input.paths], ctx.cwd);
14374
+ if (r.exitCode !== 0) {
14375
+ throw new Error(`git add failed: ${r.stderr.trim()}`);
14376
+ }
14377
+ }
14378
+ let tip = await remoteTip(ctx, branch);
14379
+ if (tip === null) {
14380
+ const baseSha = await gitText(["rev-parse", "HEAD"], ctx.cwd);
14381
+ await createRef(ctx, repo, branch, baseSha);
14382
+ tip = baseSha;
14383
+ } else {
14384
+ await runGit(["fetch", "--no-tags", "origin", branch], ctx.cwd);
14385
+ }
14386
+ const changes = await buildFileChanges(ctx, tip);
14387
+ if (changes.additions.length === 0 && changes.deletions.length === 0) {
14388
+ throw new Error("No staged changes to commit. Stage files with `git add` first (or pass `paths`).");
14389
+ }
14390
+ const chunks = chunkFileChanges(changes, DEFAULT_MAX_PAYLOAD_BYTES);
14391
+ const body2 = [input.body, buildPostHogTrailers(ctx.taskId).join("\n")].filter(Boolean).join("\n\n");
14392
+ const commits = [];
14393
+ let expectedHeadOid = tip;
14394
+ for (let i2 = 0; i2 < chunks.length; i2++) {
14395
+ const headline = chunks.length > 1 ? `${input.message} \u2014 part ${i2 + 1}/${chunks.length}` : input.message;
14396
+ const commit = await createCommitOnBranch(ctx, repo, branch, expectedHeadOid, headline, body2, chunks[i2]);
14397
+ commits.push({ sha: commit.oid, url: commit.url });
14398
+ expectedHeadOid = commit.oid;
14399
+ }
14400
+ await syncLocalCheckout(ctx, branch, expectedHeadOid);
14401
+ return { branch, commits };
14402
+ }
14403
+
13392
14404
  // src/utils/common.ts
13393
14405
  async function withTimeout(operation, timeoutMs) {
13394
14406
  const timeoutPromise = new Promise(
13395
- (resolve7) => setTimeout(() => resolve7({ result: "timeout" }), timeoutMs)
14407
+ (resolve8) => setTimeout(() => resolve8({ result: "timeout" }), timeoutMs)
13396
14408
  );
13397
14409
  const operationPromise = operation.then((value) => ({
13398
14410
  result: "success",
@@ -13402,6 +14414,12 @@ async function withTimeout(operation, timeoutMs) {
13402
14414
  }
13403
14415
  var IS_ROOT = typeof process !== "undefined" && (process.geteuid?.() ?? process.getuid?.()) === 0;
13404
14416
  var ALLOW_BYPASS = !IS_ROOT || !!process.env.IS_SANDBOX;
14417
+ function isCloudRun(meta) {
14418
+ return !!process.env.IS_SANDBOX || !!meta?.taskRunId;
14419
+ }
14420
+ function resolveGithubToken() {
14421
+ return readGithubTokenFromEnv();
14422
+ }
13405
14423
  function unreachable(value, logger) {
13406
14424
  let valueAsString;
13407
14425
  try {
@@ -13559,8 +14577,82 @@ var BaseAcpAgent = class {
13559
14577
  }
13560
14578
  };
13561
14579
 
14580
+ // src/adapters/signed-commit-shared.ts
14581
+ var import_zod = require("zod");
14582
+
14583
+ // src/adapters/local-tools/registry.ts
14584
+ var LOCAL_TOOLS_MCP_NAME = "posthog-local";
14585
+ function defineLocalTool(def) {
14586
+ return def;
14587
+ }
14588
+ function qualifiedLocalToolName(toolName) {
14589
+ return `mcp__${LOCAL_TOOLS_MCP_NAME}__${toolName}`;
14590
+ }
14591
+
14592
+ // src/adapters/signed-commit-shared.ts
14593
+ var SIGNED_COMMIT_TOOL_NAME = "git_signed_commit";
14594
+ var SIGNED_COMMIT_QUALIFIED_TOOL_NAME = qualifiedLocalToolName(
14595
+ SIGNED_COMMIT_TOOL_NAME
14596
+ );
14597
+ 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.";
14598
+ var signedCommitToolSchema = {
14599
+ message: import_zod.z.string().describe("Commit headline (first line)."),
14600
+ body: import_zod.z.string().optional().describe("Optional extended commit body."),
14601
+ branch: import_zod.z.string().optional().describe(
14602
+ "Target branch; defaults to the current branch. Use a posthog-code/ prefix for new branches."
14603
+ ),
14604
+ paths: import_zod.z.array(import_zod.z.string()).optional().describe(
14605
+ "Files to stage before committing; defaults to already-staged files."
14606
+ )
14607
+ };
14608
+ function formatSignedCommitResult(result) {
14609
+ const list = result.commits.map((c) => `- ${c.sha} ${c.url}`).join("\n");
14610
+ return `Created ${result.commits.length} signed commit(s) on ${result.branch}:
14611
+ ${list}`;
14612
+ }
14613
+ async function runSignedCommitTool(ctx, args2) {
14614
+ try {
14615
+ const result = await createSignedCommit(ctx, args2);
14616
+ return {
14617
+ content: [{ type: "text", text: formatSignedCommitResult(result) }]
14618
+ };
14619
+ } catch (err2) {
14620
+ const message = err2 instanceof Error ? err2.message : String(err2);
14621
+ return {
14622
+ content: [
14623
+ { type: "text", text: `${SIGNED_COMMIT_TOOL_NAME} failed: ${message}` }
14624
+ ],
14625
+ isError: true
14626
+ };
14627
+ }
14628
+ }
14629
+
14630
+ // src/adapters/local-tools/tools/signed-commit.ts
14631
+ var signedCommitTool = defineLocalTool({
14632
+ name: SIGNED_COMMIT_TOOL_NAME,
14633
+ description: SIGNED_COMMIT_TOOL_DESCRIPTION,
14634
+ schema: signedCommitToolSchema,
14635
+ alwaysLoad: true,
14636
+ isEnabled: (ctx, meta) => isCloudRun(meta) && !!ctx.token,
14637
+ handler: (ctx, args2) => runSignedCommitTool(
14638
+ { cwd: ctx.cwd, token: ctx.token ?? "", taskId: ctx.taskId },
14639
+ args2
14640
+ )
14641
+ });
14642
+
14643
+ // src/adapters/local-tools/index.ts
14644
+ var LOCAL_TOOLS = [signedCommitTool];
14645
+ function enabledLocalTools(ctx, meta) {
14646
+ return LOCAL_TOOLS.filter((t) => t.isEnabled(ctx, meta));
14647
+ }
14648
+
14649
+ // src/adapters/session-meta.ts
14650
+ function resolveTaskId(meta) {
14651
+ return meta?.taskId ?? meta?.persistence?.taskId;
14652
+ }
14653
+
13562
14654
  // src/adapters/claude/conversion/acp-to-sdk.ts
13563
- var path5 = __toESM(require("path"), 1);
14655
+ var path6 = __toESM(require("path"), 1);
13564
14656
  var import_node_url = require("url");
13565
14657
  var PDF_EXTENSIONS = /* @__PURE__ */ new Set(["pdf"]);
13566
14658
  var COMMON_IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
@@ -13590,7 +14682,7 @@ function sdkText(value) {
13590
14682
  function formatUriAsLink(uri) {
13591
14683
  try {
13592
14684
  if (uri.startsWith("zed://")) {
13593
- const name2 = path5.basename(uri) || uri;
14685
+ const name2 = path6.basename(uri) || uri;
13594
14686
  return `[@${name2}](${uri})`;
13595
14687
  }
13596
14688
  return uri;
@@ -13599,7 +14691,7 @@ function formatUriAsLink(uri) {
13599
14691
  }
13600
14692
  }
13601
14693
  function readToolGuidanceForPath(filePath) {
13602
- const ext = path5.extname(filePath).slice(1).toLowerCase();
14694
+ const ext = path6.extname(filePath).slice(1).toLowerCase();
13603
14695
  if (PDF_EXTENSIONS.has(ext)) {
13604
14696
  return 'Optional `pages` string (e.g. "1-5") per Read call instead of loading the entire PDF.';
13605
14697
  }
@@ -13611,7 +14703,7 @@ function readToolGuidanceForPath(filePath) {
13611
14703
  function workspacePromptFromFileUri(uri) {
13612
14704
  try {
13613
14705
  const filePath = (0, import_node_url.fileURLToPath)(uri);
13614
- const name2 = path5.basename(filePath) || filePath;
14706
+ const name2 = path6.basename(filePath) || filePath;
13615
14707
  return [
13616
14708
  "Attached workspace file \u2014 use Read with required `file_path`:",
13617
14709
  `- file_path: ${filePath}`,
@@ -13737,8 +14829,8 @@ var ToolContentBuilder = class {
13737
14829
  this.items.push({ type: "content", content: image(data, mimeType, uri) });
13738
14830
  return this;
13739
14831
  }
13740
- diff(path17, oldText, newText) {
13741
- this.items.push({ type: "diff", path: path17, oldText, newText });
14832
+ diff(path18, oldText, newText) {
14833
+ this.items.push({ type: "diff", path: path18, oldText, newText });
13742
14834
  return this;
13743
14835
  }
13744
14836
  build() {
@@ -13957,6 +15049,60 @@ var createSubagentRewriteHook = (logger, registeredAgents) => async (input, _too
13957
15049
  }
13958
15050
  };
13959
15051
  };
15052
+ var GIT_VALUE_FLAGS = /* @__PURE__ */ new Set([
15053
+ "-C",
15054
+ "-c",
15055
+ "--git-dir",
15056
+ "--work-tree",
15057
+ "--namespace",
15058
+ "--exec-path"
15059
+ ]);
15060
+ function gitSubcommand(segment) {
15061
+ const tokens = segment.trim().split(/\s+/).filter(Boolean);
15062
+ if (tokens.length === 0) return null;
15063
+ const head = tokens[0].split("/").pop();
15064
+ if (head !== "git") return null;
15065
+ let skipNext = false;
15066
+ for (const tok of tokens.slice(1)) {
15067
+ if (skipNext) {
15068
+ skipNext = false;
15069
+ continue;
15070
+ }
15071
+ if (GIT_VALUE_FLAGS.has(tok)) {
15072
+ skipNext = true;
15073
+ continue;
15074
+ }
15075
+ if (tok.startsWith("-")) continue;
15076
+ return tok;
15077
+ }
15078
+ return null;
15079
+ }
15080
+ function blocksUnsignedGit(command) {
15081
+ if (!command.includes("git")) return false;
15082
+ return command.split(/&&|\|\||[;\n|]/).some((segment) => {
15083
+ const sub = gitSubcommand(segment);
15084
+ return sub === "commit" || sub === "push";
15085
+ });
15086
+ }
15087
+ var createSignedCommitGuardHook = (logger) => async (input, _toolUseID) => {
15088
+ if (input.hook_event_name !== "PreToolUse") return { continue: true };
15089
+ if (input.tool_name !== "Bash") return { continue: true };
15090
+ const command = input.tool_input?.command;
15091
+ if (!command || !blocksUnsignedGit(command)) {
15092
+ return { continue: true };
15093
+ }
15094
+ logger.info(
15095
+ `[SignedCommitGuard] Blocking unsigned git command: ${command}`
15096
+ );
15097
+ return {
15098
+ continue: true,
15099
+ hookSpecificOutput: {
15100
+ hookEventName: "PreToolUse",
15101
+ permissionDecision: "deny",
15102
+ permissionDecisionReason: `Commits must be signed: \`git commit\` and \`git push\` are disabled here. Stage changes with \`git add\`, then call the \`git_signed_commit\` tool (${SIGNED_COMMIT_QUALIFIED_TOOL_NAME}) with a \`message\` to create a signed commit on the branch.`
15103
+ }
15104
+ };
15105
+ };
13960
15106
  var createPreToolUseHook = (settingsManager, logger) => async (input, _toolUseID) => {
13961
15107
  if (input.hook_event_name !== "PreToolUse") {
13962
15108
  return { continue: true };
@@ -14021,7 +15167,7 @@ function buildToolKey(serverName, toolName) {
14021
15167
  return `mcp__${serverName}__${toolName}`;
14022
15168
  }
14023
15169
  function delay2(ms) {
14024
- return new Promise((resolve7) => setTimeout(resolve7, ms));
15170
+ return new Promise((resolve8) => setTimeout(resolve8, ms));
14025
15171
  }
14026
15172
  async function fetchMcpToolMetadata(q, logger = new Logger({ debug: false, prefix: "[McpToolMetadata]" })) {
14027
15173
  let retries = 0;
@@ -14041,14 +15187,14 @@ async function fetchMcpToolMetadata(q, logger = new Logger({ debug: false, prefi
14041
15187
  continue;
14042
15188
  }
14043
15189
  let readOnlyCount = 0;
14044
- for (const tool of server.tools) {
14045
- const toolKey = buildToolKey(server.name, tool.name);
14046
- const readOnly = tool.annotations?.readOnly === true;
15190
+ for (const tool2 of server.tools) {
15191
+ const toolKey = buildToolKey(server.name, tool2.name);
15192
+ const readOnly = tool2.annotations?.readOnly === true;
14047
15193
  const existing = mcpToolMetadataCache.get(toolKey);
14048
15194
  mcpToolMetadataCache.set(toolKey, {
14049
15195
  readOnly,
14050
- name: tool.name,
14051
- description: tool.description,
15196
+ name: tool2.name,
15197
+ description: tool2.description,
14052
15198
  approvalState: existing?.approvalState
14053
15199
  });
14054
15200
  if (readOnly) readOnlyCount++;
@@ -15311,20 +16457,42 @@ async function handleUserAssistantMessage(message, context) {
15311
16457
  return {};
15312
16458
  }
15313
16459
 
16460
+ // src/adapters/claude/mcp/local-tools.ts
16461
+ var import_claude_agent_sdk = require("@anthropic-ai/claude-agent-sdk");
16462
+ function createLocalToolsMcpServer(ctx, meta) {
16463
+ const tools = enabledLocalTools(ctx, meta);
16464
+ if (tools.length === 0) {
16465
+ return void 0;
16466
+ }
16467
+ return (0, import_claude_agent_sdk.createSdkMcpServer)({
16468
+ name: LOCAL_TOOLS_MCP_NAME,
16469
+ version: "1.0.0",
16470
+ tools: tools.map(
16471
+ (t) => (0, import_claude_agent_sdk.tool)(
16472
+ t.name,
16473
+ t.description,
16474
+ t.schema,
16475
+ async (args2) => t.handler(ctx, args2),
16476
+ { alwaysLoad: t.alwaysLoad ?? false }
16477
+ )
16478
+ )
16479
+ });
16480
+ }
16481
+
15314
16482
  // src/adapters/claude/plan/utils.ts
15315
- var os = __toESM(require("os"), 1);
15316
- var path7 = __toESM(require("path"), 1);
16483
+ var os2 = __toESM(require("os"), 1);
16484
+ var path8 = __toESM(require("path"), 1);
15317
16485
  function getClaudeConfigDir() {
15318
- return process.env.CLAUDE_CONFIG_DIR || path7.join(os.homedir(), ".claude");
16486
+ return process.env.CLAUDE_CONFIG_DIR || path8.join(os2.homedir(), ".claude");
15319
16487
  }
15320
16488
  function getClaudePlansDir() {
15321
- return path7.join(getClaudeConfigDir(), "plans");
16489
+ return path8.join(getClaudeConfigDir(), "plans");
15322
16490
  }
15323
16491
  function isClaudePlanFilePath(filePath) {
15324
16492
  if (!filePath) return false;
15325
- const resolved = path7.resolve(filePath);
15326
- const plansDir = path7.resolve(getClaudePlansDir());
15327
- return resolved === plansDir || resolved.startsWith(plansDir + path7.sep);
16493
+ const resolved = path8.resolve(filePath);
16494
+ const plansDir = path8.resolve(getClaudePlansDir());
16495
+ return resolved === plansDir || resolved.startsWith(plansDir + path8.sep);
15328
16496
  }
15329
16497
  function isPlanReady(plan) {
15330
16498
  if (!plan) return false;
@@ -15355,21 +16523,21 @@ function getLatestAssistantText(notifications) {
15355
16523
  }
15356
16524
 
15357
16525
  // src/adapters/claude/questions/utils.ts
15358
- var import_zod = require("zod");
16526
+ var import_zod2 = require("zod");
15359
16527
  var OPTION_PREFIX = "option_";
15360
- var QuestionOptionSchema = import_zod.z.object({
15361
- label: import_zod.z.string(),
15362
- description: import_zod.z.string().optional()
16528
+ var QuestionOptionSchema = import_zod2.z.object({
16529
+ label: import_zod2.z.string(),
16530
+ description: import_zod2.z.string().optional()
15363
16531
  });
15364
- var QuestionItemSchema = import_zod.z.object({
15365
- question: import_zod.z.string(),
15366
- header: import_zod.z.string().optional(),
15367
- options: import_zod.z.array(QuestionOptionSchema),
15368
- multiSelect: import_zod.z.boolean().optional(),
15369
- completed: import_zod.z.boolean().optional()
16532
+ var QuestionItemSchema = import_zod2.z.object({
16533
+ question: import_zod2.z.string(),
16534
+ header: import_zod2.z.string().optional(),
16535
+ options: import_zod2.z.array(QuestionOptionSchema),
16536
+ multiSelect: import_zod2.z.boolean().optional(),
16537
+ completed: import_zod2.z.boolean().optional()
15370
16538
  });
15371
- var QuestionMetaSchema = import_zod.z.object({
15372
- questions: import_zod.z.array(QuestionItemSchema)
16539
+ var QuestionMetaSchema = import_zod2.z.object({
16540
+ questions: import_zod2.z.array(QuestionItemSchema)
15373
16541
  });
15374
16542
  function normalizeAskUserQuestionInput(input) {
15375
16543
  if (input.questions && input.questions.length > 0) {
@@ -16141,14 +17309,14 @@ function getAvailableSlashCommands(commands) {
16141
17309
  }
16142
17310
 
16143
17311
  // src/adapters/claude/session/mcp-config.ts
16144
- var fs6 = __toESM(require("fs"), 1);
16145
- var os2 = __toESM(require("os"), 1);
16146
- var path8 = __toESM(require("path"), 1);
16147
- function loadUserClaudeJsonMcpServers(cwd, logger, homeDir = os2.homedir()) {
16148
- const claudeJsonPath = path8.join(homeDir, ".claude.json");
17312
+ var fs7 = __toESM(require("fs"), 1);
17313
+ var os3 = __toESM(require("os"), 1);
17314
+ var path9 = __toESM(require("path"), 1);
17315
+ function loadUserClaudeJsonMcpServers(cwd, logger, homeDir = os3.homedir()) {
17316
+ const claudeJsonPath = path9.join(homeDir, ".claude.json");
16149
17317
  let raw;
16150
17318
  try {
16151
- raw = fs6.readFileSync(claudeJsonPath, "utf8");
17319
+ raw = fs7.readFileSync(claudeJsonPath, "utf8");
16152
17320
  } catch {
16153
17321
  return {};
16154
17322
  }
@@ -16192,9 +17360,9 @@ function parseMcpServers(params) {
16192
17360
 
16193
17361
  // src/adapters/claude/session/options.ts
16194
17362
  var import_node_child_process3 = require("child_process");
16195
- var fs7 = __toESM(require("fs"), 1);
16196
- var os3 = __toESM(require("os"), 1);
16197
- var path9 = __toESM(require("path"), 1);
17363
+ var fs8 = __toESM(require("fs"), 1);
17364
+ var os4 = __toESM(require("os"), 1);
17365
+ var path10 = __toESM(require("path"), 1);
16198
17366
 
16199
17367
  // src/adapters/claude/session/instructions.ts
16200
17368
  var BRANCH_NAMING = `
@@ -16269,28 +17437,27 @@ ${bedrockFallbackHeader}` : bedrockFallbackHeader;
16269
17437
  ANTHROPIC_CUSTOM_HEADERS: customHeaders
16270
17438
  };
16271
17439
  }
16272
- function buildHooks(userHooks, onModeChange, settingsManager, logger, enrichmentDeps, enrichedReadCache, registeredAgents) {
17440
+ function buildHooks(userHooks, onModeChange, settingsManager, logger, enrichmentDeps, enrichedReadCache, registeredAgents, cloudMode) {
16273
17441
  const postToolUseHooks = [createPostToolUseHook({ onModeChange })];
16274
17442
  if (enrichmentDeps && enrichedReadCache) {
16275
17443
  postToolUseHooks.push(
16276
17444
  createReadEnrichmentHook(enrichmentDeps, enrichedReadCache)
16277
17445
  );
16278
17446
  }
17447
+ const preToolUseHooks = [
17448
+ createPreToolUseHook(settingsManager, logger),
17449
+ createSubagentRewriteHook(logger, registeredAgents)
17450
+ ];
17451
+ if (cloudMode) {
17452
+ preToolUseHooks.push(createSignedCommitGuardHook(logger));
17453
+ }
16279
17454
  return {
16280
17455
  ...userHooks,
16281
17456
  PostToolUse: [
16282
17457
  ...userHooks?.PostToolUse || [],
16283
17458
  { hooks: postToolUseHooks }
16284
17459
  ],
16285
- PreToolUse: [
16286
- ...userHooks?.PreToolUse || [],
16287
- {
16288
- hooks: [
16289
- createPreToolUseHook(settingsManager, logger),
16290
- createSubagentRewriteHook(logger, registeredAgents)
16291
- ]
16292
- }
16293
- ]
17460
+ PreToolUse: [...userHooks?.PreToolUse || [], { hooks: preToolUseHooks }]
16294
17461
  };
16295
17462
  }
16296
17463
  var PH_EXPLORE_AGENT = {
@@ -16402,12 +17569,12 @@ function buildSpawnWrapper(sessionId, onProcessSpawned, onProcessExited, logger)
16402
17569
  };
16403
17570
  }
16404
17571
  function ensureLocalSettings(cwd) {
16405
- const claudeDir = path9.join(cwd, ".claude");
16406
- const localSettingsPath = path9.join(claudeDir, "settings.local.json");
17572
+ const claudeDir = path10.join(cwd, ".claude");
17573
+ const localSettingsPath = path10.join(claudeDir, "settings.local.json");
16407
17574
  try {
16408
- if (!fs7.existsSync(localSettingsPath)) {
16409
- fs7.mkdirSync(claudeDir, { recursive: true });
16410
- fs7.writeFileSync(localSettingsPath, "{}\n", { flag: "wx" });
17575
+ if (!fs8.existsSync(localSettingsPath)) {
17576
+ fs8.mkdirSync(claudeDir, { recursive: true });
17577
+ fs8.writeFileSync(localSettingsPath, "{}\n", { flag: "wx" });
16411
17578
  }
16412
17579
  } catch {
16413
17580
  }
@@ -16448,7 +17615,8 @@ function buildSessionOptions(params) {
16448
17615
  params.logger,
16449
17616
  params.enrichmentDeps,
16450
17617
  params.enrichedReadCache,
16451
- registeredAgentNames
17618
+ registeredAgentNames,
17619
+ params.cloudMode ?? false
16452
17620
  ),
16453
17621
  outputFormat: params.outputFormat,
16454
17622
  abortController: getAbortController(
@@ -16483,18 +17651,18 @@ function buildSessionOptions(params) {
16483
17651
  return options;
16484
17652
  }
16485
17653
  function clearStatsigCache() {
16486
- const statsigPath = path9.join(
16487
- process.env.CLAUDE_CONFIG_DIR || path9.join(os3.homedir(), ".claude"),
17654
+ const statsigPath = path10.join(
17655
+ process.env.CLAUDE_CONFIG_DIR || path10.join(os4.homedir(), ".claude"),
16488
17656
  "statsig"
16489
17657
  );
16490
- fs7.rm(statsigPath, { recursive: true, force: true }, () => {
17658
+ fs8.rm(statsigPath, { recursive: true, force: true }, () => {
16491
17659
  });
16492
17660
  }
16493
17661
 
16494
17662
  // src/adapters/claude/session/settings.ts
16495
- var fs8 = __toESM(require("fs"), 1);
16496
- var os4 = __toESM(require("os"), 1);
16497
- var path10 = __toESM(require("path"), 1);
17663
+ var fs9 = __toESM(require("fs"), 1);
17664
+ var os5 = __toESM(require("os"), 1);
17665
+ var path11 = __toESM(require("path"), 1);
16498
17666
  var import_minimatch = require("minimatch");
16499
17667
 
16500
17668
  // src/utils/async-mutex.ts
@@ -16506,8 +17674,8 @@ var AsyncMutex = class {
16506
17674
  this.locked = true;
16507
17675
  return;
16508
17676
  }
16509
- return new Promise((resolve7) => {
16510
- this.queue.push(resolve7);
17677
+ return new Promise((resolve8) => {
17678
+ this.queue.push(resolve8);
16511
17679
  });
16512
17680
  }
16513
17681
  release() {
@@ -16575,13 +17743,13 @@ function parseRule(rule) {
16575
17743
  function normalizePath(filePath, cwd) {
16576
17744
  let resolved = filePath;
16577
17745
  if (resolved.startsWith("~/")) {
16578
- resolved = path10.join(os4.homedir(), resolved.slice(2));
17746
+ resolved = path11.join(os5.homedir(), resolved.slice(2));
16579
17747
  } else if (resolved.startsWith("./")) {
16580
- resolved = path10.join(cwd, resolved.slice(2));
16581
- } else if (!path10.isAbsolute(resolved)) {
16582
- resolved = path10.join(cwd, resolved);
17748
+ resolved = path11.join(cwd, resolved.slice(2));
17749
+ } else if (!path11.isAbsolute(resolved)) {
17750
+ resolved = path11.join(cwd, resolved);
16583
17751
  }
16584
- return path10.normalize(resolved).replace(/\\/g, "/");
17752
+ return path11.normalize(resolved).replace(/\\/g, "/");
16585
17753
  }
16586
17754
  function matchesGlob(pattern, filePath, cwd) {
16587
17755
  const normalizedPattern = normalizePath(pattern, cwd);
@@ -16628,11 +17796,11 @@ function formatRule(rule) {
16628
17796
  }
16629
17797
  async function writeFileAtomic(filePath, data) {
16630
17798
  const tmpPath = `${filePath}.${process.pid}.${Date.now()}.tmp`;
16631
- await fs8.promises.writeFile(tmpPath, data);
17799
+ await fs9.promises.writeFile(tmpPath, data);
16632
17800
  try {
16633
- await fs8.promises.rename(tmpPath, filePath);
17801
+ await fs9.promises.rename(tmpPath, filePath);
16634
17802
  } catch (error) {
16635
- await fs8.promises.rm(tmpPath, { force: true });
17803
+ await fs9.promises.rm(tmpPath, { force: true });
16636
17804
  throw error;
16637
17805
  }
16638
17806
  }
@@ -16641,7 +17809,7 @@ async function loadSettingsFile(filePath) {
16641
17809
  return {};
16642
17810
  }
16643
17811
  try {
16644
- const content = await fs8.promises.readFile(filePath, "utf-8");
17812
+ const content = await fs9.promises.readFile(filePath, "utf-8");
16645
17813
  return JSON.parse(content);
16646
17814
  } catch (error) {
16647
17815
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -16656,7 +17824,7 @@ async function loadSettingsFile(filePath) {
16656
17824
  }
16657
17825
  async function readSettingsFileForUpdate(filePath) {
16658
17826
  try {
16659
- const content = await fs8.promises.readFile(filePath, "utf-8");
17827
+ const content = await fs9.promises.readFile(filePath, "utf-8");
16660
17828
  return JSON.parse(content);
16661
17829
  } catch (error) {
16662
17830
  if (error instanceof Error && "code" in error && error.code === "ENOENT") {
@@ -16702,11 +17870,11 @@ var SettingsManager = class {
16702
17870
  return this.initPromise;
16703
17871
  }
16704
17872
  getUserSettingsPath() {
16705
- const configDir = process.env.CLAUDE_CONFIG_DIR || path10.join(os4.homedir(), ".claude");
16706
- return path10.join(configDir, "settings.json");
17873
+ const configDir = process.env.CLAUDE_CONFIG_DIR || path11.join(os5.homedir(), ".claude");
17874
+ return path11.join(configDir, "settings.json");
16707
17875
  }
16708
17876
  getProjectSettingsPath() {
16709
- return path10.join(this.cwd, ".claude", "settings.json");
17877
+ return path11.join(this.cwd, ".claude", "settings.json");
16710
17878
  }
16711
17879
  /**
16712
17880
  * Local settings are anchored to the primary worktree so every worktree of
@@ -16714,7 +17882,7 @@ var SettingsManager = class {
16714
17882
  * avoids re-prompting for the same permission in every worktree.
16715
17883
  */
16716
17884
  getLocalSettingsPath() {
16717
- return path10.join(this.repoRoot, ".claude", "settings.local.json");
17885
+ return path11.join(this.repoRoot, ".claude", "settings.local.json");
16718
17886
  }
16719
17887
  async loadAllSettings() {
16720
17888
  this.repoRoot = await resolveMainRepoPath(this.cwd);
@@ -16772,8 +17940,8 @@ var SettingsManager = class {
16772
17940
  merged.model = settings.model;
16773
17941
  }
16774
17942
  if (settings.posthogApprovedExecTools) {
16775
- for (const tool of settings.posthogApprovedExecTools) {
16776
- posthogApprovedExecTools.add(tool);
17943
+ for (const tool2 of settings.posthogApprovedExecTools) {
17944
+ posthogApprovedExecTools.add(tool2);
16777
17945
  }
16778
17946
  }
16779
17947
  }
@@ -16841,7 +18009,7 @@ var SettingsManager = class {
16841
18009
  }
16842
18010
  permissions.allow = Array.from(current2);
16843
18011
  const next = { ...existing, permissions };
16844
- await fs8.promises.mkdir(path10.dirname(filePath), { recursive: true });
18012
+ await fs9.promises.mkdir(path11.dirname(filePath), { recursive: true });
16845
18013
  await writeFileAtomic(filePath, `${JSON.stringify(next, null, 2)}
16846
18014
  `);
16847
18015
  this.localSettings = next;
@@ -16874,7 +18042,7 @@ var SettingsManager = class {
16874
18042
  ...existing,
16875
18043
  posthogApprovedExecTools: Array.from(current2)
16876
18044
  };
16877
- await fs8.promises.mkdir(path10.dirname(filePath), { recursive: true });
18045
+ await fs9.promises.mkdir(path11.dirname(filePath), { recursive: true });
16878
18046
  await writeFileAtomic(filePath, `${JSON.stringify(next, null, 2)}
16879
18047
  `);
16880
18048
  this.localSettings = next;
@@ -16980,7 +18148,7 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
16980
18148
  };
16981
18149
  }
16982
18150
  async newSession(params) {
16983
- if (fs9.existsSync(path11.resolve(os5.homedir(), ".claude.json.backup")) && !fs9.existsSync(path11.resolve(os5.homedir(), ".claude.json"))) {
18151
+ if (fs10.existsSync(path12.resolve(os6.homedir(), ".claude.json.backup")) && !fs10.existsSync(path12.resolve(os6.homedir(), ".claude.json"))) {
16984
18152
  throw import_sdk2.RequestError.authRequired();
16985
18153
  }
16986
18154
  const response = await this.createSession(params, {
@@ -17034,7 +18202,7 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
17034
18202
  };
17035
18203
  }
17036
18204
  async listSessions(params) {
17037
- const sdkSessions = await (0, import_claude_agent_sdk.listSessions)({ dir: params.cwd ?? void 0 });
18205
+ const sdkSessions = await (0, import_claude_agent_sdk2.listSessions)({ dir: params.cwd ?? void 0 });
17038
18206
  const sessions = [];
17039
18207
  for (const session of sdkSessions) {
17040
18208
  if (!session.cwd) continue;
@@ -17078,8 +18246,8 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
17078
18246
  if (this.session.promptRunning) {
17079
18247
  this.session.input.push(userMessage);
17080
18248
  const order = this.session.nextPendingOrder++;
17081
- const cancelled = await new Promise((resolve7) => {
17082
- this.session.pendingMessages.set(promptUuid, { resolve: resolve7, order });
18249
+ const cancelled = await new Promise((resolve8) => {
18250
+ this.session.pendingMessages.set(promptUuid, { resolve: resolve8, order });
17083
18251
  });
17084
18252
  if (cancelled) {
17085
18253
  return { stopReason: "cancelled" };
@@ -17467,7 +18635,7 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
17467
18635
  abortController: newAbortController
17468
18636
  };
17469
18637
  const newInput = new Pushable();
17470
- const newQuery = (0, import_claude_agent_sdk.query)({ prompt: newInput, options: newOptions });
18638
+ const newQuery = (0, import_claude_agent_sdk2.query)({ prompt: newInput, options: newOptions });
17471
18639
  prev.query = newQuery;
17472
18640
  prev.input = newInput;
17473
18641
  prev.queryOptions = newOptions;
@@ -17601,7 +18769,8 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
17601
18769
  const { resume, forkSession } = creationOpts;
17602
18770
  const isResume = !!resume;
17603
18771
  const meta = params._meta;
17604
- const taskId = meta?.persistence?.taskId;
18772
+ const taskId = resolveTaskId(meta);
18773
+ const cloudRun = isCloudRun(meta);
17605
18774
  const effort = meta?.claudeCode?.options?.effort;
17606
18775
  let sessionId;
17607
18776
  if (forkSession) {
@@ -17616,6 +18785,17 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
17616
18785
  await settingsManager.initialize();
17617
18786
  const earlyModelId = settingsManager.getSettings().model || meta?.model || "";
17618
18787
  const mcpServers = supportsMcpInjection(earlyModelId) ? parseMcpServers(params) : {};
18788
+ const localToolsServer = createLocalToolsMcpServer(
18789
+ { cwd, token: resolveGithubToken(), taskId },
18790
+ meta
18791
+ );
18792
+ if (localToolsServer) {
18793
+ mcpServers[LOCAL_TOOLS_MCP_NAME] = localToolsServer;
18794
+ } else if (cloudRun) {
18795
+ this.logger.warn(
18796
+ "Cloud run registered no local tools \u2014 missing GH_TOKEN/GITHUB_TOKEN? signed commits unavailable"
18797
+ );
18798
+ }
17619
18799
  const systemPrompt = buildSystemPrompt(meta?.systemPrompt);
17620
18800
  if (meta?.mcpToolApprovals) {
17621
18801
  setMcpToolApprovalStates(meta.mcpToolApprovals);
@@ -17651,10 +18831,11 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
17651
18831
  onProcessExited: this.options?.onProcessExited,
17652
18832
  effort,
17653
18833
  enrichmentDeps: this.enrichment?.deps,
17654
- enrichedReadCache: this.enrichedReadCache
18834
+ enrichedReadCache: this.enrichedReadCache,
18835
+ cloudMode: cloudRun
17655
18836
  });
17656
18837
  const abortController = options.abortController;
17657
- const q = (0, import_claude_agent_sdk.query)({ prompt: input, options });
18838
+ const q = (0, import_claude_agent_sdk2.query)({ prompt: input, options });
17658
18839
  const session = {
17659
18840
  query: q,
17660
18841
  queryOptions: options,
@@ -17942,7 +19123,7 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
17942
19123
  }
17943
19124
  async replaySessionHistory(sessionId) {
17944
19125
  try {
17945
- const messages = await (0, import_claude_agent_sdk.getSessionMessages)(sessionId, {
19126
+ const messages = await (0, import_claude_agent_sdk2.getSessionMessages)(sessionId, {
17946
19127
  dir: this.session.cwd
17947
19128
  });
17948
19129
  const replayContext = {
@@ -17983,7 +19164,7 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
17983
19164
  */
17984
19165
  deferBackgroundFetches(q) {
17985
19166
  Promise.all([
17986
- new Promise((resolve7) => setTimeout(resolve7, 10)).then(
19167
+ new Promise((resolve8) => setTimeout(resolve8, 10)).then(
17987
19168
  () => this.sendAvailableCommandsUpdate()
17988
19169
  ),
17989
19170
  fetchMcpToolMetadata(q, this.logger).then(() => {
@@ -18223,9 +19404,9 @@ function resetUsage(state) {
18223
19404
  }
18224
19405
 
18225
19406
  // src/adapters/codex/settings.ts
18226
- var fs10 = __toESM(require("fs"), 1);
18227
- var os6 = __toESM(require("os"), 1);
18228
- var path12 = __toESM(require("path"), 1);
19407
+ var fs11 = __toESM(require("fs"), 1);
19408
+ var os7 = __toESM(require("os"), 1);
19409
+ var path13 = __toESM(require("path"), 1);
18229
19410
  var CodexSettingsManager = class {
18230
19411
  cwd;
18231
19412
  settings = { mcpServerNames: [] };
@@ -18236,12 +19417,12 @@ var CodexSettingsManager = class {
18236
19417
  async initialize() {
18237
19418
  }
18238
19419
  getConfigPath() {
18239
- return path12.join(os6.homedir(), ".codex", "config.toml");
19420
+ return path13.join(os7.homedir(), ".codex", "config.toml");
18240
19421
  }
18241
19422
  loadSettings() {
18242
19423
  const configPath = this.getConfigPath();
18243
19424
  try {
18244
- const content = fs10.readFileSync(configPath, "utf-8");
19425
+ const content = fs11.readFileSync(configPath, "utf-8");
18245
19426
  this.settings = parseCodexToml(content, this.cwd);
18246
19427
  } catch {
18247
19428
  this.settings = { mcpServerNames: [] };
@@ -18456,8 +19637,7 @@ function getCurrentPermissionMode(currentModeId, fallbackMode) {
18456
19637
  var STRUCTURED_OUTPUT_INSTRUCTIONS = `
18457
19638
 
18458
19639
  When you have completed the task, call the \`${STRUCTURED_OUTPUT_TOOL_NAME}\` tool with the final structured result. The tool's input schema matches the required output format for this task. Do not describe the result in a plain message \u2014 submitting it via the tool is required for the task to be considered complete.`;
18459
- function resolveStructuredOutputMcpScript() {
18460
- const rel = "adapters/codex/structured-output-mcp-server.js";
19640
+ function resolveBundledMcpScript(rel) {
18461
19641
  let dir = import_meta2.dirname ?? __dirname;
18462
19642
  for (let i2 = 0; i2 < 5; i2++) {
18463
19643
  const candidate = (0, import_node_path5.resolve)(dir, rel);
@@ -18469,7 +19649,9 @@ function resolveStructuredOutputMcpScript() {
18469
19649
  );
18470
19650
  }
18471
19651
  function buildStructuredOutputMcpServer(jsonSchema) {
18472
- const scriptPath = resolveStructuredOutputMcpScript();
19652
+ const scriptPath = resolveBundledMcpScript(
19653
+ "adapters/codex/structured-output-mcp-server.js"
19654
+ );
18473
19655
  const schemaBase64 = Buffer.from(JSON.stringify(jsonSchema)).toString(
18474
19656
  "base64"
18475
19657
  );
@@ -18480,6 +19662,30 @@ function buildStructuredOutputMcpServer(jsonSchema) {
18480
19662
  env: [{ name: "POSTHOG_OUTPUT_SCHEMA", value: schemaBase64 }]
18481
19663
  };
18482
19664
  }
19665
+ function buildLocalToolsMcpServer(ctx, enabledNames) {
19666
+ const scriptPath = resolveBundledMcpScript(
19667
+ "adapters/codex/local-tools-mcp-server.js"
19668
+ );
19669
+ const ctxBase64 = Buffer.from(JSON.stringify(ctx)).toString("base64");
19670
+ const env = [
19671
+ { name: "POSTHOG_LOCAL_TOOLS_CTX", value: ctxBase64 },
19672
+ { name: "POSTHOG_LOCAL_TOOLS_ENABLED", value: enabledNames.join(",") }
19673
+ ];
19674
+ if (ctx.token) {
19675
+ env.push(
19676
+ ...Object.entries(ghTokenEnv(ctx.token)).map(([name2, value]) => ({
19677
+ name: name2,
19678
+ value
19679
+ }))
19680
+ );
19681
+ }
19682
+ return {
19683
+ name: LOCAL_TOOLS_MCP_NAME,
19684
+ command: process.execPath,
19685
+ args: [scriptPath],
19686
+ env
19687
+ };
19688
+ }
18483
19689
  var CodexAcpAgent = class extends BaseAcpAgent {
18484
19690
  adapterName = "codex";
18485
19691
  codexProcess;
@@ -18567,14 +19773,17 @@ var CodexAcpAgent = class extends BaseAcpAgent {
18567
19773
  async newSession(params) {
18568
19774
  const meta = params._meta;
18569
19775
  const requestedPermissionMode = toCodexPermissionMode(meta?.permissionMode);
18570
- const injectedParams = this.applyStructuredOutput(params, meta);
19776
+ const injectedParams = this.applyLocalTools(
19777
+ this.applyStructuredOutput(params, meta),
19778
+ meta
19779
+ );
18571
19780
  const response = await this.codexConnection.newSession(injectedParams);
18572
19781
  response.configOptions = normalizeCodexConfigOptions(
18573
19782
  response.configOptions
18574
19783
  );
18575
19784
  this.sessionState = createSessionState(response.sessionId, params.cwd, {
18576
19785
  taskRunId: meta?.taskRunId,
18577
- taskId: meta?.taskId ?? meta?.persistence?.taskId,
19786
+ taskId: resolveTaskId(meta),
18578
19787
  modeId: response.modes?.currentModeId ?? "auto",
18579
19788
  modelId: response.models?.currentModelId,
18580
19789
  permissionMode: requestedPermissionMode
@@ -18601,7 +19810,10 @@ var CodexAcpAgent = class extends BaseAcpAgent {
18601
19810
  }
18602
19811
  async loadSession(params) {
18603
19812
  const meta = params._meta;
18604
- const injectedParams = this.applyStructuredOutput(params, meta);
19813
+ const injectedParams = this.applyLocalTools(
19814
+ this.applyStructuredOutput(params, meta),
19815
+ meta
19816
+ );
18605
19817
  const response = await this.codexConnection.loadSession(injectedParams);
18606
19818
  response.configOptions = normalizeCodexConfigOptions(
18607
19819
  response.configOptions
@@ -18612,7 +19824,7 @@ var CodexAcpAgent = class extends BaseAcpAgent {
18612
19824
  );
18613
19825
  this.sessionState = createSessionState(params.sessionId, params.cwd, {
18614
19826
  taskRunId: meta?.taskRunId,
18615
- taskId: meta?.taskId ?? meta?.persistence?.taskId,
19827
+ taskId: resolveTaskId(meta),
18616
19828
  modeId: response.modes?.currentModeId ?? "auto",
18617
19829
  permissionMode: currentPermissionMode
18618
19830
  });
@@ -18629,13 +19841,16 @@ var CodexAcpAgent = class extends BaseAcpAgent {
18629
19841
  }
18630
19842
  async unstable_resumeSession(params) {
18631
19843
  const meta = params._meta;
18632
- const injectedParams = this.applyStructuredOutput(
18633
- {
18634
- sessionId: params.sessionId,
18635
- cwd: params.cwd,
18636
- mcpServers: params.mcpServers ?? [],
18637
- _meta: params._meta
18638
- },
19844
+ const injectedParams = this.applyLocalTools(
19845
+ this.applyStructuredOutput(
19846
+ {
19847
+ sessionId: params.sessionId,
19848
+ cwd: params.cwd,
19849
+ mcpServers: params.mcpServers ?? [],
19850
+ _meta: params._meta
19851
+ },
19852
+ meta
19853
+ ),
18639
19854
  meta
18640
19855
  );
18641
19856
  const loadResponse = await this.codexConnection.loadSession(injectedParams);
@@ -18648,7 +19863,7 @@ var CodexAcpAgent = class extends BaseAcpAgent {
18648
19863
  );
18649
19864
  this.sessionState = createSessionState(params.sessionId, params.cwd, {
18650
19865
  taskRunId: meta?.taskRunId,
18651
- taskId: meta?.taskId ?? meta?.persistence?.taskId,
19866
+ taskId: resolveTaskId(meta),
18652
19867
  modeId: loadResponse.modes?.currentModeId ?? "auto",
18653
19868
  permissionMode: currentPermissionMode
18654
19869
  });
@@ -18669,12 +19884,15 @@ var CodexAcpAgent = class extends BaseAcpAgent {
18669
19884
  }
18670
19885
  async unstable_forkSession(params) {
18671
19886
  const meta = params._meta;
18672
- const injectedParams = this.applyStructuredOutput(
18673
- {
18674
- cwd: params.cwd,
18675
- mcpServers: params.mcpServers ?? [],
18676
- _meta: params._meta
18677
- },
19887
+ const injectedParams = this.applyLocalTools(
19888
+ this.applyStructuredOutput(
19889
+ {
19890
+ cwd: params.cwd,
19891
+ mcpServers: params.mcpServers ?? [],
19892
+ _meta: params._meta
19893
+ },
19894
+ meta
19895
+ ),
18678
19896
  meta
18679
19897
  );
18680
19898
  const newResponse = await this.codexConnection.newSession(injectedParams);
@@ -18684,7 +19902,7 @@ var CodexAcpAgent = class extends BaseAcpAgent {
18684
19902
  const requestedPermissionMode = toCodexPermissionMode(meta?.permissionMode);
18685
19903
  this.sessionState = createSessionState(newResponse.sessionId, params.cwd, {
18686
19904
  taskRunId: meta?.taskRunId,
18687
- taskId: meta?.taskId ?? meta?.persistence?.taskId,
19905
+ taskId: resolveTaskId(meta),
18688
19906
  modeId: newResponse.modes?.currentModeId ?? "auto",
18689
19907
  permissionMode: requestedPermissionMode
18690
19908
  });
@@ -18721,6 +19939,41 @@ var CodexAcpAgent = class extends BaseAcpAgent {
18721
19939
  }
18722
19940
  };
18723
19941
  }
19942
+ /**
19943
+ * Injects the stdio general local-tools MCP server. Tools self-gate via the
19944
+ * registry (e.g. signed-commit is cloud-only and needs a GH token), so the
19945
+ * server is only injected when at least one tool's gate passes. Their
19946
+ * instructions already live in the shared cloud system prompt, so only the
19947
+ * server needs injecting here.
19948
+ */
19949
+ applyLocalTools(request, meta) {
19950
+ const cwd = request.cwd;
19951
+ if (!cwd) {
19952
+ return request;
19953
+ }
19954
+ const ctx = {
19955
+ cwd,
19956
+ token: resolveGithubToken(),
19957
+ taskId: resolveTaskId(meta)
19958
+ };
19959
+ const tools = enabledLocalTools(ctx, meta);
19960
+ if (tools.length === 0) {
19961
+ if (isCloudRun(meta)) {
19962
+ this.logger.warn(
19963
+ "Cloud run registered no local tools \u2014 missing GH_TOKEN/GITHUB_TOKEN? signed commits unavailable"
19964
+ );
19965
+ }
19966
+ return request;
19967
+ }
19968
+ const mcpServer = buildLocalToolsMcpServer(
19969
+ ctx,
19970
+ tools.map((t) => t.name)
19971
+ );
19972
+ return {
19973
+ ...request,
19974
+ mcpServers: [...request.mcpServers ?? [], mcpServer]
19975
+ };
19976
+ }
18724
19977
  async applyInitialPermissionMode(sessionId, permissionMode, currentModeId) {
18725
19978
  if (!permissionMode) {
18726
19979
  return;
@@ -19104,8 +20357,8 @@ var import_node_path6 = __toESM(require("path"), 1);
19104
20357
 
19105
20358
  // ../git/dist/sagas/checkpoint.js
19106
20359
  var import_node_crypto2 = require("crypto");
19107
- var fs11 = __toESM(require("fs/promises"), 1);
19108
- var path13 = __toESM(require("path"), 1);
20360
+ var fs12 = __toESM(require("fs/promises"), 1);
20361
+ var path14 = __toESM(require("path"), 1);
19109
20362
 
19110
20363
  // ../shared/dist/index.js
19111
20364
  var CLOUD_PROMPT_PREFIX = "__twig_cloud_prompt_v1__:";
@@ -19391,7 +20644,7 @@ async function createWorktreeTree(git, baseDir, head) {
19391
20644
  const treeHash = await tempGit.raw(["write-tree"]);
19392
20645
  return treeHash.trim();
19393
20646
  } finally {
19394
- await fs11.rm(tempIndexPath, { force: true }).catch(() => {
20647
+ await fs12.rm(tempIndexPath, { force: true }).catch(() => {
19395
20648
  });
19396
20649
  }
19397
20650
  }
@@ -19489,7 +20742,7 @@ async function createMetaTree(git, baseDir, indexTree, worktreeTree) {
19489
20742
  const metaTree = await tempGit.raw(["write-tree"]);
19490
20743
  return metaTree.trim();
19491
20744
  } finally {
19492
- await fs11.rm(tempIndexPath, { force: true }).catch(() => {
20745
+ await fs12.rm(tempIndexPath, { force: true }).catch(() => {
19493
20746
  });
19494
20747
  }
19495
20748
  }
@@ -19506,12 +20759,12 @@ function formatCheckpointMessage(meta) {
19506
20759
  async function getGitCommonDir(git, baseDir) {
19507
20760
  const raw = await git.raw(["rev-parse", "--git-common-dir"]);
19508
20761
  const dir = raw.trim() || ".git";
19509
- return path13.isAbsolute(dir) ? dir : path13.resolve(baseDir, dir);
20762
+ return path14.isAbsolute(dir) ? dir : path14.resolve(baseDir, dir);
19510
20763
  }
19511
20764
  async function createTempIndexGit(git, baseDir, label) {
19512
- const tmpDir = path13.join(await getGitCommonDir(git, baseDir), "posthog-code-tmp");
19513
- await fs11.mkdir(tmpDir, { recursive: true });
19514
- const tempIndexPath = path13.join(tmpDir, `${label}-${Date.now()}-${(0, import_node_crypto2.randomUUID)()}`);
20765
+ const tmpDir = path14.join(await getGitCommonDir(git, baseDir), "posthog-code-tmp");
20766
+ await fs12.mkdir(tmpDir, { recursive: true });
20767
+ const tempIndexPath = path14.join(tmpDir, `${label}-${Date.now()}-${(0, import_node_crypto2.randomUUID)()}`);
19515
20768
  const tempGit = createGitClient(baseDir).env({
19516
20769
  ...process.env,
19517
20770
  GIT_INDEX_FILE: tempIndexPath
@@ -19876,7 +21129,7 @@ var GitHandoffTracker = class {
19876
21129
  await this.runGitProcess(args2, input);
19877
21130
  }
19878
21131
  async runGitProcessAllowingFailure(args2) {
19879
- return new Promise((resolve7, reject) => {
21132
+ return new Promise((resolve8, reject) => {
19880
21133
  const child = (0, import_node_child_process5.spawn)("git", args2, {
19881
21134
  cwd: this.repositoryPath,
19882
21135
  stdio: ["ignore", "ignore", "pipe"]
@@ -19895,12 +21148,12 @@ var GitHandoffTracker = class {
19895
21148
  reject(new Error(stderr || `git ${args2.join(" ")} failed with code ${code}`));
19896
21149
  return;
19897
21150
  }
19898
- resolve7(code);
21151
+ resolve8(code);
19899
21152
  });
19900
21153
  });
19901
21154
  }
19902
21155
  async runGitWithEnv(env, args2) {
19903
- return new Promise((resolve7, reject) => {
21156
+ return new Promise((resolve8, reject) => {
19904
21157
  const child = (0, import_node_child_process5.spawn)("git", args2, {
19905
21158
  cwd: this.repositoryPath,
19906
21159
  stdio: ["ignore", "pipe", "pipe"],
@@ -19917,7 +21170,7 @@ var GitHandoffTracker = class {
19917
21170
  child.on("error", reject);
19918
21171
  child.on("close", (code) => {
19919
21172
  if (code === 0) {
19920
- resolve7(stdout);
21173
+ resolve8(stdout);
19921
21174
  return;
19922
21175
  }
19923
21176
  reject(new Error(stderr || `git ${args2.join(" ")} failed with code ${code}`));
@@ -19925,7 +21178,7 @@ var GitHandoffTracker = class {
19925
21178
  });
19926
21179
  }
19927
21180
  runGitProcess(args2, input) {
19928
- return new Promise((resolve7, reject) => {
21181
+ return new Promise((resolve8, reject) => {
19929
21182
  const child = (0, import_node_child_process5.spawn)("git", args2, {
19930
21183
  cwd: this.repositoryPath,
19931
21184
  stdio: "pipe"
@@ -19941,7 +21194,7 @@ var GitHandoffTracker = class {
19941
21194
  child.on("error", reject);
19942
21195
  child.on("close", (code) => {
19943
21196
  if (code === 0) {
19944
- resolve7({ stdout, stderr });
21197
+ resolve8({ stdout, stderr });
19945
21198
  return;
19946
21199
  }
19947
21200
  reject(new Error(stderr || `git ${args2.join(" ")} failed with code ${code}`));
@@ -20469,9 +21722,9 @@ function extractCreatedPrUrl(input) {
20469
21722
 
20470
21723
  // src/adapters/claude/session/jsonl-hydration.ts
20471
21724
  var import_node_crypto3 = require("crypto");
20472
- var fs12 = __toESM(require("fs/promises"), 1);
20473
- var os7 = __toESM(require("os"), 1);
20474
- var path15 = __toESM(require("path"), 1);
21725
+ var fs13 = __toESM(require("fs/promises"), 1);
21726
+ var os8 = __toESM(require("os"), 1);
21727
+ var path16 = __toESM(require("path"), 1);
20475
21728
  var CHARS_PER_TOKEN = 4;
20476
21729
  var DEFAULT_MAX_TOKENS = 15e4;
20477
21730
  function estimateTurnTokens(turn) {
@@ -21137,7 +22390,7 @@ async function getAgentshVersion() {
21137
22390
  }
21138
22391
  async function resolveAgentshRuntimeInfo({
21139
22392
  sessionIdPath = AGENTSH_SESSION_ID_FILE,
21140
- readSessionId = async (path17) => (0, import_promises5.readFile)(path17, "utf8"),
22393
+ readSessionId = async (path18) => (0, import_promises5.readFile)(path18, "utf8"),
21141
22394
  getVersion = getAgentshVersion
21142
22395
  } = {}) {
21143
22396
  let sessionId;
@@ -21191,20 +22444,20 @@ function normalizeCloudPromptContent(content) {
21191
22444
 
21192
22445
  // src/server/jwt.ts
21193
22446
  var import_jsonwebtoken = __toESM(require("jsonwebtoken"), 1);
21194
- var import_zod2 = require("zod");
22447
+ var import_zod3 = require("zod");
21195
22448
  var SANDBOX_CONNECTION_AUDIENCE = "posthog:sandbox_connection";
21196
- var userDataSchema = import_zod2.z.object({
21197
- run_id: import_zod2.z.string(),
21198
- task_id: import_zod2.z.string(),
21199
- team_id: import_zod2.z.number(),
21200
- user_id: import_zod2.z.number(),
21201
- distinct_id: import_zod2.z.string(),
21202
- mode: import_zod2.z.enum(["interactive", "background"]).optional().default("interactive")
22449
+ var userDataSchema = import_zod3.z.object({
22450
+ run_id: import_zod3.z.string(),
22451
+ task_id: import_zod3.z.string(),
22452
+ team_id: import_zod3.z.number(),
22453
+ user_id: import_zod3.z.number(),
22454
+ distinct_id: import_zod3.z.string(),
22455
+ mode: import_zod3.z.enum(["interactive", "background"]).optional().default("interactive")
21203
22456
  });
21204
22457
  var jwtPayloadSchema = userDataSchema.extend({
21205
- exp: import_zod2.z.number(),
21206
- iat: import_zod2.z.number().optional(),
21207
- aud: import_zod2.z.string().optional()
22458
+ exp: import_zod3.z.number(),
22459
+ iat: import_zod3.z.number().optional(),
22460
+ aud: import_zod3.z.string().optional()
21208
22461
  });
21209
22462
  var JwtValidationError = class extends Error {
21210
22463
  constructor(message, code) {
@@ -21337,7 +22590,7 @@ function validateCommandParams(method, params) {
21337
22590
  }
21338
22591
 
21339
22592
  // src/server/agent-server.ts
21340
- var agentErrorClassificationSchema = import_zod3.z.enum([
22593
+ var agentErrorClassificationSchema = import_zod4.z.enum([
21341
22594
  "upstream_stream_terminated",
21342
22595
  "upstream_connection_error",
21343
22596
  "upstream_provider_failure",
@@ -21349,8 +22602,8 @@ var upstreamProviderFailureClassifications = /* @__PURE__ */ new Set([
21349
22602
  "upstream_connection_error",
21350
22603
  "upstream_provider_failure"
21351
22604
  ]);
21352
- var errorWithClassificationSchema = import_zod3.z.object({
21353
- data: import_zod3.z.object({ classification: agentErrorClassificationSchema })
22605
+ var errorWithClassificationSchema = import_zod4.z.object({
22606
+ data: import_zod4.z.object({ classification: agentErrorClassificationSchema })
21354
22607
  });
21355
22608
  var SSE_KEEPALIVE_INTERVAL_MS = 25e3;
21356
22609
  var NdJsonTap = class {
@@ -21671,7 +22924,7 @@ var AgentServer = class {
21671
22924
  return app;
21672
22925
  }
21673
22926
  async start() {
21674
- await new Promise((resolve7) => {
22927
+ await new Promise((resolve8) => {
21675
22928
  this.server = (0, import_node_server.serve)(
21676
22929
  {
21677
22930
  fetch: this.app.fetch,
@@ -21681,7 +22934,7 @@ var AgentServer = class {
21681
22934
  this.logger.debug(
21682
22935
  `HTTP server listening on port ${this.config.port}`
21683
22936
  );
21684
- resolve7();
22937
+ resolve8();
21685
22938
  }
21686
22939
  );
21687
22940
  });
@@ -22007,6 +23260,7 @@ var AgentServer = class {
22007
23260
  _meta: {
22008
23261
  sessionId: payload.run_id,
22009
23262
  taskRunId: payload.run_id,
23263
+ taskId: payload.task_id,
22010
23264
  systemPrompt: sessionSystemPrompt,
22011
23265
  ...this.config.model && { model: this.config.model },
22012
23266
  allowedDomains: this.config.allowedDomains,
@@ -22490,24 +23744,21 @@ You MUST NOT create a new branch, close the existing PR, or create a new PR.`;
22490
23744
  buildCloudSystemPrompt(prUrl) {
22491
23745
  const taskId = this.config.taskId;
22492
23746
  const shouldAutoCreatePr = this.shouldAutoPublishCloudChanges();
22493
- const attributionInstructions = `
22494
- ## Attribution
22495
- Do NOT use Claude Code's default attribution (no "Co-Authored-By" trailers, no "Generated with [Claude Code]" lines).
23747
+ const signedCommitInstructions = `
23748
+ ## Committing (signed commits required)
23749
+ Commits MUST be signed. \`git commit\` and \`git push\` are blocked in this environment.
23750
+ To commit: stage your changes with \`git add\`, then call the \`git_signed_commit\` tool (full
23751
+ name \`${SIGNED_COMMIT_QUALIFIED_TOOL_NAME}\`) with a \`message\` (and optional \`body\`/\`paths\`).
23752
+ It creates a GitHub-signed ("Verified") commit on the branch and keeps your local checkout in
23753
+ sync. To start a new branch, pass \`branch\` (prefixed with \`posthog-code/\`) \u2014 the tool creates
23754
+ it on the remote for you.
22496
23755
 
22497
- If you create a commit, add the following trailers to the commit message (after a blank line at the end):
23756
+ ## Attribution
23757
+ Do NOT add "Co-Authored-By" trailers or "Generated with [Claude Code]" lines to your
23758
+ commit messages. The \`git_signed_commit\` tool automatically appends the only trailers
23759
+ we want:
22498
23760
  Generated-By: PostHog Code
22499
- Task-Id: ${taskId}
22500
-
22501
- Example:
22502
- \`\`\`
22503
- git commit -m "$(cat <<'EOF'
22504
- fix: resolve login redirect loop
22505
-
22506
- Generated-By: PostHog Code
22507
- Task-Id: ${taskId}
22508
- EOF
22509
- )"
22510
- \`\`\``;
23761
+ Task-Id: ${taskId}`;
22511
23762
  if (prUrl) {
22512
23763
  if (!shouldAutoCreatePr) {
22513
23764
  return `
@@ -22520,7 +23771,7 @@ Do the requested work, but stop with local changes ready for review.
22520
23771
  Important:
22521
23772
  - Do NOT create new commits, push to the branch, or update the pull request unless the user explicitly asks.
22522
23773
  - Do NOT create a new branch or a new pull request.
22523
- ${attributionInstructions}
23774
+ ${signedCommitInstructions}
22524
23775
  `;
22525
23776
  }
22526
23777
  return `
@@ -22530,9 +23781,8 @@ This task already has an open pull request: ${prUrl}
22530
23781
 
22531
23782
  After completing the requested changes:
22532
23783
  1. Check out the existing PR branch with \`gh pr checkout ${prUrl}\`
22533
- 2. Stage and commit all changes with a clear commit message
22534
- 3. Push to the existing PR branch
22535
- 4. For every PR review comment or review thread you addressed, treat the thread as done only after BOTH of these:
23784
+ 2. Stage your changes with \`git add\`, then call the \`git_signed_commit\` tool with a clear \`message\` (do NOT use \`git commit\`/\`git push\` \u2014 they are blocked). This commits to the existing PR branch.
23785
+ 3. For every PR review comment or review thread you addressed, treat the thread as done only after BOTH of these:
22536
23786
  - Reply on the thread with a short note describing what changed (reference the commit SHA when useful) using \`gh api -X POST /repos/{owner}/{repo}/pulls/{n}/comments/{id}/replies -f body='...'\`.
22537
23787
  - Resolve the thread via the \`resolveReviewThread\` GraphQL mutation: \`gh api graphql -f query='mutation($id:ID!){resolveReviewThread(input:{threadId:$id}){thread{isResolved}}}' -f id="<thread-node-id>"\`.
22538
23788
  List unresolved threads first with \`gh api graphql -f query='{repository(owner:"<owner>",name:"<repo>"){pullRequest(number:<n>){reviewThreads(first:100){nodes{id isResolved comments(first:1){nodes{body}}}}}}}'\` so you can resolve each one you fixed.
@@ -22540,7 +23790,7 @@ After completing the requested changes:
22540
23790
  Important:
22541
23791
  - Do NOT create a new branch or a new pull request.
22542
23792
  - Do NOT push fixes for review comments without replying to and resolving each related thread.
22543
- ${attributionInstructions}
23793
+ ${signedCommitInstructions}
22544
23794
  `;
22545
23795
  }
22546
23796
  if (!this.config.repositoryPath) {
@@ -22551,7 +23801,7 @@ When the user asks for code changes:
22551
23801
  When the user explicitly asks to clone or work in a GitHub repository:
22552
23802
  - Clone the repository into /tmp/workspace/repos/<owner>/<repo> using \`gh repo clone <owner>/<repo> /tmp/workspace/repos/<owner>/<repo>\`
22553
23803
  - Work from inside that cloned repository for follow-up code changes
22554
- - If the user explicitly asks you to open or update a pull request, create a branch, commit the requested changes, push it, and open a draft pull request from inside the clone. Before opening the PR, check the cloned repo for a PR template at \`.github/pull_request_template.md\` (or variants; fall back to the org's \`.github\` repo via \`gh api\`) and use it as the body structure, and search for matching open issues with \`gh issue list --search\` to include \`Closes #<n>\` / \`Refs #<n>\` links.
23804
+ - If the user explicitly asks you to open or update a pull request, create a branch, stage your changes with \`git add\` and commit them with the \`git_signed_commit\` tool (do NOT use \`git commit\`/\`git push\` \u2014 they are blocked), and open a draft pull request from inside the clone. Before opening the PR, check the cloned repo for a PR template at \`.github/pull_request_template.md\` (or variants; fall back to the org's \`.github\` repo via \`gh api\`) and use it as the body structure, and search for matching open issues with \`gh issue list --search\` to include \`Closes #<n>\` / \`Refs #<n>\` links.
22555
23805
  - Do NOT create branches, commits, push changes, or open pull requests unless the user explicitly asks for that`;
22556
23806
  return `
22557
23807
  # Cloud Task Execution \u2014 No Repository Mode
@@ -22570,7 +23820,7 @@ ${publishInstructions}
22570
23820
 
22571
23821
  Important:
22572
23822
  - Prefer using MCP tools to answer questions with real data over giving generic advice.
22573
- ${attributionInstructions}
23823
+ ${signedCommitInstructions}
22574
23824
  `;
22575
23825
  }
22576
23826
  if (!shouldAutoCreatePr) {
@@ -22581,21 +23831,20 @@ Do the requested work, but stop with local changes ready for review.
22581
23831
 
22582
23832
  Important:
22583
23833
  - Do NOT create a branch, commit, push, or open a pull request unless the user explicitly asks.
22584
- ${attributionInstructions}
23834
+ ${signedCommitInstructions}
22585
23835
  `;
22586
23836
  }
22587
23837
  return `
22588
23838
  # Cloud Task Execution
22589
23839
 
22590
23840
  After completing the requested changes:
22591
- 1. Create a new branch prefixed with \`posthog-code/\` (e.g. \`posthog-code/fix-login-redirect\`) based on the work done
22592
- 2. Stage and commit all changes with a clear commit message
22593
- 3. Push the branch to origin
22594
- 4. Before opening the PR, prepare the body:
23841
+ 1. Pick a new branch name prefixed with \`posthog-code/\` (e.g. \`posthog-code/fix-login-redirect\`)
23842
+ 2. Stage your changes with \`git add\`, then call the \`git_signed_commit\` tool with \`branch\` set to that name and a clear \`message\` (do NOT use \`git commit\`/\`git push\` \u2014 they are blocked). The tool creates the branch on the remote and a signed commit on it.
23843
+ 3. Before opening the PR, prepare the body:
22595
23844
  - Check the repo for a PR template at \`.github/pull_request_template.md\` (also try \`.github/PULL_REQUEST_TEMPLATE.md\`, \`docs/pull_request_template.md\`, and root variants). If one exists, use its exact section headings as the PR body \u2014 do NOT fall back to a generic Summary/Test plan format.
22596
23845
  - If no repo-level template exists, check the org's \`.github\` repo via \`gh api /repos/<owner>/.github/contents/.github/pull_request_template.md\` (and other common paths) and use that as a fallback.
22597
23846
  - Search for matching open issues with \`gh issue list --state open --search '<keywords>'\` (derive keywords from the branch name, commits, and changed files; \`gh issue view <n>\` to confirm relevance). For every issue this PR would resolve, include a \`Closes #<n>\` line in the body so GitHub auto-links and auto-closes it on merge. For issues that are related but not fully resolved, use \`Refs #<n>\` instead.
22598
- 5. Create a draft pull request using \`gh pr create --draft${this.config.baseBranch ? ` --base ${this.config.baseBranch}` : ""}\` with a descriptive title and the body prepared above. Add the following footer at the end of the PR description:
23847
+ 4. Create a draft pull request using \`gh pr create --draft${this.config.baseBranch ? ` --base ${this.config.baseBranch}` : ""}\` with a descriptive title and the body prepared above. Add the following footer at the end of the PR description:
22599
23848
  \`\`\`
22600
23849
  ---
22601
23850
  *Created with [PostHog Code](https://posthog.com/code?ref=pr)*
@@ -22603,7 +23852,7 @@ After completing the requested changes:
22603
23852
 
22604
23853
  Important:
22605
23854
  - Always create the PR as a draft. Do not ask for confirmation.
22606
- ${attributionInstructions}
23855
+ ${signedCommitInstructions}
22607
23856
  `;
22608
23857
  }
22609
23858
  async getCurrentGitBranch() {
@@ -23059,8 +24308,8 @@ ${attributionInstructions}
23059
24308
  options: params.options,
23060
24309
  toolCall: params.toolCall
23061
24310
  });
23062
- return new Promise((resolve7) => {
23063
- this.pendingPermissions.set(requestId, { resolve: resolve7 });
24311
+ return new Promise((resolve8) => {
24312
+ this.pendingPermissions.set(requestId, { resolve: resolve8 });
23064
24313
  });
23065
24314
  }
23066
24315
  resolvePermission(requestId, optionId, customInput, answers) {
@@ -23193,4 +24442,17 @@ ${errors}`);
23193
24442
  await server.start();
23194
24443
  });
23195
24444
  program.parse();
24445
+ /*! Bundled license information:
24446
+
24447
+ git-url-parse/lib/index.js:
24448
+ (*!
24449
+ * buildToken
24450
+ * Builds OAuth token prefix (helper function)
24451
+ *
24452
+ * @name buildToken
24453
+ * @function
24454
+ * @param {GitUrl} obj The parsed Git url object.
24455
+ * @return {String} token prefix
24456
+ *)
24457
+ */
23196
24458
  //# sourceMappingURL=bin.cjs.map