@posthog/agent 2.3.556 → 2.3.619

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.
@@ -3951,6 +3951,7 @@ var import_sdk5 = require("@agentclientprotocol/sdk");
3951
3951
  var import_node_server = require("@hono/node-server");
3952
3952
 
3953
3953
  // ../git/dist/queries.js
3954
+ var import_node_fs = require("fs");
3954
3955
  var fs3 = __toESM(require("fs/promises"), 1);
3955
3956
  var path2 = __toESM(require("path"), 1);
3956
3957
 
@@ -8502,13 +8503,20 @@ init_git_response_error();
8502
8503
  var simpleGit = gitInstanceFactory;
8503
8504
 
8504
8505
  // ../git/dist/client.js
8506
+ var PERFORMANCE_CONFIG = [
8507
+ "core.untrackedCache=true",
8508
+ "core.fsmonitor=true",
8509
+ "core.preloadIndex=true"
8510
+ ];
8505
8511
  function createGitClient(baseDir, options) {
8506
- const { abortSignal: signal, ...rest } = options ?? {};
8512
+ const { abortSignal: signal, config: callerConfig, ...rest } = options ?? {};
8513
+ const config = callerConfig ? [...PERFORMANCE_CONFIG, ...callerConfig] : PERFORMANCE_CONFIG;
8507
8514
  return simpleGit({
8508
8515
  baseDir,
8509
8516
  maxConcurrentProcesses: 6,
8510
8517
  trimmed: true,
8511
8518
  abort: signal,
8519
+ config,
8512
8520
  ...rest
8513
8521
  });
8514
8522
  }
@@ -8661,14 +8669,18 @@ var GitOperationManagerImpl = class _GitOperationManagerImpl {
8661
8669
  }
8662
8670
  async executeRead(repoPath, operation, options) {
8663
8671
  const state = this.getRepoState(repoPath);
8672
+ const env = {
8673
+ ...getCleanEnv(),
8674
+ GIT_OPTIONAL_LOCKS: "0",
8675
+ ...options?.env
8676
+ };
8664
8677
  if (options?.signal) {
8665
8678
  const scopedGit = createGitClient(repoPath, {
8666
8679
  abortSignal: options.signal
8667
8680
  });
8668
- return operation(scopedGit.env({ ...getCleanEnv(), GIT_OPTIONAL_LOCKS: "0" }));
8681
+ return operation(scopedGit.env(env));
8669
8682
  }
8670
- const git = state.client.env({ ...getCleanEnv(), GIT_OPTIONAL_LOCKS: "0" });
8671
- return operation(git);
8683
+ return operation(state.client.env(env));
8672
8684
  }
8673
8685
  async executeWrite(repoPath, operation, options) {
8674
8686
  const state = this.getRepoState(repoPath);
@@ -8678,15 +8690,16 @@ var GitOperationManagerImpl = class _GitOperationManagerImpl {
8678
8690
  throw new Error(`Git repository is locked: ${repoPath}`);
8679
8691
  }
8680
8692
  }
8693
+ const env = { ...getCleanEnv(), ...options?.env };
8681
8694
  await state.lock.acquireWrite();
8682
8695
  try {
8683
8696
  if (options?.signal) {
8684
8697
  const scopedGit = createGitClient(repoPath, {
8685
8698
  abortSignal: options.signal
8686
8699
  });
8687
- return await operation(scopedGit.env(getCleanEnv()));
8700
+ return await operation(scopedGit.env(env));
8688
8701
  }
8689
- return await operation(state.client.env(getCleanEnv()));
8702
+ return await operation(state.client.env(env));
8690
8703
  } catch (error) {
8691
8704
  if (options?.signal?.aborted) {
8692
8705
  await removeLock(repoPath).catch(() => {
@@ -8713,6 +8726,9 @@ function getGitOperationManager() {
8713
8726
  return instance2;
8714
8727
  }
8715
8728
 
8729
+ // ../git/dist/status-stream.js
8730
+ var import_node_child_process2 = require("child_process");
8731
+
8716
8732
  // ../git/dist/queries.js
8717
8733
  async function getCurrentBranch(baseDir, options) {
8718
8734
  const manager = getGitOperationManager();
@@ -8747,6 +8763,44 @@ async function listWorktrees(baseDir, options) {
8747
8763
  return worktrees;
8748
8764
  }, { signal: options?.abortSignal });
8749
8765
  }
8766
+ async function inspectGitBusyState(git) {
8767
+ const toplevel = (await git.raw(["rev-parse", "--show-toplevel"])).trim();
8768
+ const resolveGitPath = async (gitPath) => {
8769
+ const relative = (await git.raw(["rev-parse", "--git-path", gitPath])).trim();
8770
+ return path2.isAbsolute(relative) ? relative : path2.resolve(toplevel, relative);
8771
+ };
8772
+ const pathExists = async (gitPath) => {
8773
+ const resolved = await resolveGitPath(gitPath);
8774
+ try {
8775
+ await fs3.access(resolved);
8776
+ return true;
8777
+ } catch {
8778
+ return false;
8779
+ }
8780
+ };
8781
+ const dirExists = async (gitPath) => {
8782
+ const resolved = await resolveGitPath(gitPath);
8783
+ try {
8784
+ const stat4 = await fs3.stat(resolved);
8785
+ return stat4.isDirectory();
8786
+ } catch {
8787
+ return false;
8788
+ }
8789
+ };
8790
+ if (await dirExists("rebase-merge") || await dirExists("rebase-apply")) {
8791
+ return { busy: true, operation: "rebase" };
8792
+ }
8793
+ if (await pathExists("MERGE_HEAD")) {
8794
+ return { busy: true, operation: "merge" };
8795
+ }
8796
+ if (await pathExists("CHERRY_PICK_HEAD")) {
8797
+ return { busy: true, operation: "cherry-pick" };
8798
+ }
8799
+ if (await pathExists("REVERT_HEAD")) {
8800
+ return { busy: true, operation: "revert" };
8801
+ }
8802
+ return { busy: false };
8803
+ }
8750
8804
 
8751
8805
  // src/server/agent-server.ts
8752
8806
  var import_hono = require("hono");
@@ -8755,7 +8809,7 @@ var import_zod3 = require("zod");
8755
8809
  // package.json
8756
8810
  var package_default = {
8757
8811
  name: "@posthog/agent",
8758
- version: "2.3.556",
8812
+ version: "2.3.619",
8759
8813
  repository: "https://github.com/PostHog/code",
8760
8814
  description: "TypeScript agent framework wrapping Claude Agent SDK with Git-based task execution for PostHog",
8761
8815
  exports: {
@@ -11311,8 +11365,7 @@ var ParserManager = class {
11311
11365
  }
11312
11366
  this.queryCache.set(cacheKey, query2);
11313
11367
  return query2;
11314
- } catch (err2) {
11315
- warn("Query compilation failed", err2);
11368
+ } catch {
11316
11369
  this.failedQueries.add(cacheKey);
11317
11370
  return null;
11318
11371
  }
@@ -13698,6 +13751,23 @@ function tryParsePartialJson(s) {
13698
13751
  return null;
13699
13752
  }
13700
13753
 
13754
+ // src/adapters/error-classification.ts
13755
+ var UPSTREAM_PROVIDER_ERROR_STATUS_PATTERN = /API Error:\s*(?:429|5\d\d)\b/i;
13756
+ function classifyAgentError(result) {
13757
+ if (!result) return "agent_error";
13758
+ const text2 = result.trim();
13759
+ if (/API Error:\s*terminated\b/i.test(text2)) {
13760
+ return "upstream_stream_terminated";
13761
+ }
13762
+ if (/API Error:\s*Connection error\b/i.test(text2)) {
13763
+ return "upstream_connection_error";
13764
+ }
13765
+ if (UPSTREAM_PROVIDER_ERROR_STATUS_PATTERN.test(text2)) {
13766
+ return "upstream_provider_failure";
13767
+ }
13768
+ return "agent_error";
13769
+ }
13770
+
13701
13771
  // src/adapters/claude/permissions/posthog-exec-gate.ts
13702
13772
  var POSTHOG_EXEC_TOOL_RE = /^mcp__posthog(?:_[^_]+)*__exec$/;
13703
13773
  var POSTHOG_CALL_COMMAND_RE = /^\s*call\s+(?:--json\s+)?([a-zA-Z0-9_-]+)/;
@@ -13894,7 +13964,7 @@ var createPreToolUseHook = (settingsManager, logger) => async (input, _toolUseID
13894
13964
  };
13895
13965
 
13896
13966
  // src/adapters/claude/conversion/tool-use-to-acp.ts
13897
- var import_node_fs = __toESM(require("fs"), 1);
13967
+ var import_node_fs2 = __toESM(require("fs"), 1);
13898
13968
  var import_node_path3 = __toESM(require("path"), 1);
13899
13969
 
13900
13970
  // src/adapters/claude/mcp/tool-metadata.ts
@@ -14128,7 +14198,7 @@ function toolInfoFromToolUse(toolUse, options) {
14128
14198
  oldContent = options.cachedFileContent[writeFilePath];
14129
14199
  } else {
14130
14200
  try {
14131
- oldContent = import_node_fs.default.readFileSync(writeFilePath, "utf-8");
14201
+ oldContent = import_node_fs2.default.readFileSync(writeFilePath, "utf-8");
14132
14202
  } catch {
14133
14203
  }
14134
14204
  }
@@ -14542,7 +14612,7 @@ function resolveFileContent(filePath, oldText, cachedFileContent) {
14542
14612
  }
14543
14613
  }
14544
14614
  try {
14545
- const content = import_node_fs.default.readFileSync(filePath, "utf-8");
14615
+ const content = import_node_fs2.default.readFileSync(filePath, "utf-8");
14546
14616
  if (content.includes(oldText)) {
14547
14617
  return content;
14548
14618
  }
@@ -15014,17 +15084,6 @@ async function handleSystemMessage(message, context) {
15014
15084
  break;
15015
15085
  }
15016
15086
  }
15017
- function classifyAgentError(result) {
15018
- if (!result) return "agent_error";
15019
- const text2 = result.trim();
15020
- if (/API Error:\s*terminated\b/i.test(text2)) {
15021
- return "upstream_stream_terminated";
15022
- }
15023
- if (/API Error:\s*Connection error\b/i.test(text2)) {
15024
- return "upstream_connection_error";
15025
- }
15026
- return "agent_error";
15027
- }
15028
15087
  function handleResultMessage(message) {
15029
15088
  const usage = extractUsageFromResult(message);
15030
15089
  switch (message.subtype) {
@@ -16086,7 +16145,7 @@ function parseMcpServers(params) {
16086
16145
  }
16087
16146
 
16088
16147
  // src/adapters/claude/session/options.ts
16089
- var import_node_child_process2 = require("child_process");
16148
+ var import_node_child_process3 = require("child_process");
16090
16149
  var fs7 = __toESM(require("fs"), 1);
16091
16150
  var os3 = __toESM(require("os"), 1);
16092
16151
  var path9 = __toESM(require("path"), 1);
@@ -16234,7 +16293,7 @@ function getAbortController(userProvidedController) {
16234
16293
  }
16235
16294
  function buildSpawnWrapper(sessionId, onProcessSpawned, onProcessExited, logger) {
16236
16295
  return (spawnOpts) => {
16237
- const child = (0, import_node_child_process2.spawn)(spawnOpts.command, spawnOpts.args, {
16296
+ const child = (0, import_node_child_process3.spawn)(spawnOpts.command, spawnOpts.args, {
16238
16297
  cwd: spawnOpts.cwd,
16239
16298
  env: spawnOpts.env,
16240
16299
  stdio: ["pipe", "pipe", "pipe"]
@@ -17907,7 +17966,7 @@ var ClaudeAcpAgent = class extends BaseAcpAgent {
17907
17966
  };
17908
17967
 
17909
17968
  // src/adapters/codex/codex-agent.ts
17910
- var import_node_fs3 = require("fs");
17969
+ var import_node_fs4 = require("fs");
17911
17970
  var import_node_path5 = require("path");
17912
17971
  var import_sdk3 = require("@agentclientprotocol/sdk");
17913
17972
 
@@ -18192,8 +18251,8 @@ function parseCodexToml(content, cwd) {
18192
18251
  }
18193
18252
 
18194
18253
  // src/adapters/codex/spawn.ts
18195
- var import_node_child_process3 = require("child_process");
18196
- var import_node_fs2 = require("fs");
18254
+ var import_node_child_process4 = require("child_process");
18255
+ var import_node_fs3 = require("fs");
18197
18256
  var import_node_path4 = require("path");
18198
18257
  function buildConfigArgs(options) {
18199
18258
  const args2 = [];
@@ -18225,7 +18284,7 @@ function buildConfigArgs(options) {
18225
18284
  }
18226
18285
  function findCodexBinary(options) {
18227
18286
  const configArgs = buildConfigArgs(options);
18228
- if (options.binaryPath && (0, import_node_fs2.existsSync)(options.binaryPath)) {
18287
+ if (options.binaryPath && (0, import_node_fs3.existsSync)(options.binaryPath)) {
18229
18288
  return { command: options.binaryPath, args: configArgs };
18230
18289
  }
18231
18290
  if (options.binaryPath) {
@@ -18244,7 +18303,7 @@ function spawnCodexProcess(options) {
18244
18303
  env.POSTHOG_GATEWAY_API_KEY = options.apiKey;
18245
18304
  }
18246
18305
  const { command, args: args2 } = findCodexBinary(options);
18247
- if (options.binaryPath && (0, import_node_fs2.existsSync)(options.binaryPath)) {
18306
+ if (options.binaryPath && (0, import_node_fs3.existsSync)(options.binaryPath)) {
18248
18307
  const binDir = (0, import_node_path4.dirname)(options.binaryPath);
18249
18308
  env.PATH = `${binDir}${import_node_path4.delimiter}${env.PATH ?? ""}`;
18250
18309
  }
@@ -18256,7 +18315,7 @@ function spawnCodexProcess(options) {
18256
18315
  hasApiKey: !!options.apiKey,
18257
18316
  binaryPath: options.binaryPath
18258
18317
  });
18259
- const child = (0, import_node_child_process3.spawn)(command, args2, {
18318
+ const child = (0, import_node_child_process4.spawn)(command, args2, {
18260
18319
  cwd: options.cwd,
18261
18320
  env,
18262
18321
  stdio: ["pipe", "pipe", "pipe"],
@@ -18315,6 +18374,17 @@ function prependPrContext(params) {
18315
18374
  prompt: [{ type: "text", text: prContext }, ...params.prompt]
18316
18375
  };
18317
18376
  }
18377
+ function classifyPromptError(error) {
18378
+ const message = error instanceof Error ? error.message : String(error ?? "");
18379
+ const classification = classifyAgentError(message);
18380
+ if (classification === "agent_error") {
18381
+ return error;
18382
+ }
18383
+ return import_sdk3.RequestError.internalError(
18384
+ { classification, result: message },
18385
+ message
18386
+ );
18387
+ }
18318
18388
  var CODEX_NATIVE_MODE = {
18319
18389
  auto: "auto",
18320
18390
  default: "auto",
@@ -18345,7 +18415,7 @@ function resolveStructuredOutputMcpScript() {
18345
18415
  let dir = import_meta2.dirname ?? __dirname;
18346
18416
  for (let i2 = 0; i2 < 5; i2++) {
18347
18417
  const candidate = (0, import_node_path5.resolve)(dir, rel);
18348
- if ((0, import_node_fs3.existsSync)(candidate)) return candidate;
18418
+ if ((0, import_node_fs4.existsSync)(candidate)) return candidate;
18349
18419
  dir = (0, import_node_path5.resolve)(dir, "..");
18350
18420
  }
18351
18421
  throw new Error(
@@ -18644,6 +18714,8 @@ var CodexAcpAgent = class extends BaseAcpAgent {
18644
18714
  let response;
18645
18715
  try {
18646
18716
  response = await this.codexConnection.prompt(prependPrContext(params));
18717
+ } catch (error) {
18718
+ throw classifyPromptError(error);
18647
18719
  } finally {
18648
18720
  this.session.promptRunning = false;
18649
18721
  }
@@ -18979,7 +19051,7 @@ var import_node_os2 = require("os");
18979
19051
  var import_node_path7 = require("path");
18980
19052
 
18981
19053
  // ../git/dist/handoff.js
18982
- var import_node_child_process4 = require("child_process");
19054
+ var import_node_child_process5 = require("child_process");
18983
19055
  var import_promises2 = require("fs/promises");
18984
19056
  var import_node_os = require("os");
18985
19057
  var import_node_path6 = __toESM(require("path"), 1);
@@ -19145,7 +19217,7 @@ var GitSaga = class extends Saga {
19145
19217
  return manager.executeWrite(input.baseDir, async (git) => {
19146
19218
  this._git = git;
19147
19219
  return this.executeGitOperations(input);
19148
- }, { signal: input.signal });
19220
+ }, { signal: input.signal, env: input.env });
19149
19221
  }
19150
19222
  };
19151
19223
 
@@ -19257,42 +19329,7 @@ async function hasUnmergedEntries(git) {
19257
19329
  return output.trim().length > 0;
19258
19330
  }
19259
19331
  async function getGitBusyState(git) {
19260
- const toplevel = (await git.raw(["rev-parse", "--show-toplevel"])).trim();
19261
- const resolveGitPath = async (gitPath) => {
19262
- const relative = (await git.raw(["rev-parse", "--git-path", gitPath])).trim();
19263
- return path13.isAbsolute(relative) ? relative : path13.resolve(toplevel, relative);
19264
- };
19265
- const pathExists = async (gitPath) => {
19266
- const resolved = await resolveGitPath(gitPath);
19267
- try {
19268
- await fs11.access(resolved);
19269
- return true;
19270
- } catch {
19271
- return false;
19272
- }
19273
- };
19274
- const dirExists = async (gitPath) => {
19275
- const resolved = await resolveGitPath(gitPath);
19276
- try {
19277
- const stat4 = await fs11.stat(resolved);
19278
- return stat4.isDirectory();
19279
- } catch {
19280
- return false;
19281
- }
19282
- };
19283
- if (await dirExists("rebase-merge") || await dirExists("rebase-apply")) {
19284
- return { busy: true, operation: "rebase" };
19285
- }
19286
- if (await pathExists("MERGE_HEAD")) {
19287
- return { busy: true, operation: "merge" };
19288
- }
19289
- if (await pathExists("CHERRY_PICK_HEAD")) {
19290
- return { busy: true, operation: "cherry-pick" };
19291
- }
19292
- if (await pathExists("REVERT_HEAD")) {
19293
- return { busy: true, operation: "revert" };
19294
- }
19295
- return { busy: false };
19332
+ return inspectGitBusyState(git);
19296
19333
  }
19297
19334
  var MAX_WORKTREE_FILE_BYTES = 1024 * 1024;
19298
19335
  async function createWorktreeTree(git, baseDir, head) {
@@ -19794,7 +19831,7 @@ var GitHandoffTracker = class {
19794
19831
  }
19795
19832
  async runGitProcessAllowingFailure(args2) {
19796
19833
  return new Promise((resolve7, reject) => {
19797
- const child = (0, import_node_child_process4.spawn)("git", args2, {
19834
+ const child = (0, import_node_child_process5.spawn)("git", args2, {
19798
19835
  cwd: this.repositoryPath,
19799
19836
  stdio: ["ignore", "ignore", "pipe"]
19800
19837
  });
@@ -19818,7 +19855,7 @@ var GitHandoffTracker = class {
19818
19855
  }
19819
19856
  async runGitWithEnv(env, args2) {
19820
19857
  return new Promise((resolve7, reject) => {
19821
- const child = (0, import_node_child_process4.spawn)("git", args2, {
19858
+ const child = (0, import_node_child_process5.spawn)("git", args2, {
19822
19859
  cwd: this.repositoryPath,
19823
19860
  stdio: ["ignore", "pipe", "pipe"],
19824
19861
  env
@@ -19843,7 +19880,7 @@ var GitHandoffTracker = class {
19843
19880
  }
19844
19881
  runGitProcess(args2, input) {
19845
19882
  return new Promise((resolve7, reject) => {
19846
- const child = (0, import_node_child_process4.spawn)("git", args2, {
19883
+ const child = (0, import_node_child_process5.spawn)("git", args2, {
19847
19884
  cwd: this.repositoryPath,
19848
19885
  stdio: "pipe"
19849
19886
  });
@@ -20695,7 +20732,7 @@ ${toolSummary}`);
20695
20732
  }
20696
20733
 
20697
20734
  // src/session-log-writer.ts
20698
- var import_node_fs4 = __toESM(require("fs"), 1);
20735
+ var import_node_fs5 = __toESM(require("fs"), 1);
20699
20736
  var import_promises4 = __toESM(require("fs/promises"), 1);
20700
20737
  var import_node_path8 = __toESM(require("path"), 1);
20701
20738
  var SessionLogWriter = class _SessionLogWriter {
@@ -20739,7 +20776,7 @@ var SessionLogWriter = class _SessionLogWriter {
20739
20776
  context.runId
20740
20777
  );
20741
20778
  try {
20742
- import_node_fs4.default.mkdirSync(sessionDir, { recursive: true });
20779
+ import_node_fs5.default.mkdirSync(sessionDir, { recursive: true });
20743
20780
  } catch (error) {
20744
20781
  this.logger.warn("Failed to create local cache directory", {
20745
20782
  sessionDir,
@@ -20998,7 +21035,7 @@ var SessionLogWriter = class _SessionLogWriter {
20998
21035
  "logs.ndjson"
20999
21036
  );
21000
21037
  try {
21001
- import_node_fs4.default.appendFileSync(logPath, `${JSON.stringify(entry)}
21038
+ import_node_fs5.default.appendFileSync(logPath, `${JSON.stringify(entry)}
21002
21039
  `);
21003
21040
  } catch (error) {
21004
21041
  this.logger.warn("Failed to write to local cache", {
@@ -21033,11 +21070,11 @@ var SessionLogWriter = class _SessionLogWriter {
21033
21070
  };
21034
21071
 
21035
21072
  // src/server/agentsh-runtime.ts
21036
- var import_node_child_process5 = require("child_process");
21073
+ var import_node_child_process6 = require("child_process");
21037
21074
  var import_promises5 = require("fs/promises");
21038
21075
  var import_node_util2 = require("util");
21039
21076
  var AGENTSH_SESSION_ID_FILE = "/tmp/agentsh-session-id";
21040
- var execFileAsync2 = (0, import_node_util2.promisify)(import_node_child_process5.execFile);
21077
+ var execFileAsync2 = (0, import_node_util2.promisify)(import_node_child_process6.execFile);
21041
21078
  function errorMessage(error) {
21042
21079
  return error instanceof Error ? error.message : String(error);
21043
21080
  }
@@ -21257,8 +21294,15 @@ function validateCommandParams(method, params) {
21257
21294
  var agentErrorClassificationSchema = import_zod3.z.enum([
21258
21295
  "upstream_stream_terminated",
21259
21296
  "upstream_connection_error",
21297
+ "upstream_provider_failure",
21260
21298
  "agent_error"
21261
21299
  ]);
21300
+ var UPSTREAM_PROVIDER_FAILURE_MESSAGE = "The upstream AI provider failed to process the request. Please retry the task in a few minutes.";
21301
+ var upstreamProviderFailureClassifications = /* @__PURE__ */ new Set([
21302
+ "upstream_stream_terminated",
21303
+ "upstream_connection_error",
21304
+ "upstream_provider_failure"
21305
+ ]);
21262
21306
  var errorWithClassificationSchema = import_zod3.z.object({
21263
21307
  data: import_zod3.z.object({ classification: agentErrorClassificationSchema })
21264
21308
  });
@@ -22002,7 +22046,9 @@ var AgentServer = class {
22002
22046
  }
22003
22047
  classifyAndSignalFailure(payload, phase, error) {
22004
22048
  const { classification, message } = this.extractErrorClassification(error);
22005
- const errorMessage2 = classification === "upstream_stream_terminated" ? "Upstream LLM stream terminated" : classification === "upstream_connection_error" ? "Upstream LLM connection error" : message || "Agent error";
22049
+ const errorMessage2 = upstreamProviderFailureClassifications.has(
22050
+ classification
22051
+ ) ? UPSTREAM_PROVIDER_FAILURE_MESSAGE : message || "Agent error";
22006
22052
  this.logger.error(`send_${phase}_task_message_failed`, {
22007
22053
  classification,
22008
22054
  message
@@ -22440,9 +22486,14 @@ After completing the requested changes:
22440
22486
  1. Check out the existing PR branch with \`gh pr checkout ${prUrl}\`
22441
22487
  2. Stage and commit all changes with a clear commit message
22442
22488
  3. Push to the existing PR branch
22489
+ 4. For every PR review comment or review thread you addressed, treat the thread as done only after BOTH of these:
22490
+ - 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='...'\`.
22491
+ - 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>"\`.
22492
+ 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.
22443
22493
 
22444
22494
  Important:
22445
22495
  - Do NOT create a new branch or a new pull request.
22496
+ - Do NOT push fixes for review comments without replying to and resolving each related thread.
22446
22497
  ${attributionInstructions}
22447
22498
  `;
22448
22499
  }
@@ -22454,7 +22505,7 @@ When the user asks for code changes:
22454
22505
  When the user explicitly asks to clone or work in a GitHub repository:
22455
22506
  - Clone the repository into /tmp/workspace/repos/<owner>/<repo> using \`gh repo clone <owner>/<repo> /tmp/workspace/repos/<owner>/<repo>\`
22456
22507
  - Work from inside that cloned repository for follow-up code changes
22457
- - 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
22508
+ - 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.
22458
22509
  - Do NOT create branches, commits, push changes, or open pull requests unless the user explicitly asks for that`;
22459
22510
  return `
22460
22511
  # Cloud Task Execution \u2014 No Repository Mode
@@ -22494,7 +22545,11 @@ After completing the requested changes:
22494
22545
  1. Create a new branch prefixed with \`posthog-code/\` (e.g. \`posthog-code/fix-login-redirect\`) based on the work done
22495
22546
  2. Stage and commit all changes with a clear commit message
22496
22547
  3. Push the branch to origin
22497
- 4. Create a draft pull request using \`gh pr create --draft${this.config.baseBranch ? ` --base ${this.config.baseBranch}` : ""}\` with a descriptive title and body. Add the following footer at the end of the PR description:
22548
+ 4. Before opening the PR, prepare the body:
22549
+ - 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.
22550
+ - 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.
22551
+ - 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.
22552
+ 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:
22498
22553
  \`\`\`
22499
22554
  ---
22500
22555
  *Created with [PostHog Code](https://posthog.com/code?ref=pr)*