pullfrog 0.1.33 → 0.1.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.mjs CHANGED
@@ -96,7 +96,7 @@ var require_arg = __commonJS({
96
96
  Object.setPrototypeOf(this, _ArgError.prototype);
97
97
  }
98
98
  };
99
- function arg5(opts, {
99
+ function arg6(opts, {
100
100
  argv = process.argv.slice(2),
101
101
  permissive = false,
102
102
  stopAtPositional = false
@@ -171,15 +171,15 @@ var require_arg = __commonJS({
171
171
  if (wholeArg.length > 1 && wholeArg[0] === "-") {
172
172
  const separatedArguments = wholeArg[1] === "-" || wholeArg.length === 2 ? [wholeArg] : wholeArg.slice(1).split("").map((a) => `-${a}`);
173
173
  for (let j3 = 0; j3 < separatedArguments.length; j3++) {
174
- const arg6 = separatedArguments[j3];
175
- const [originalArgName, argStr] = arg6[1] === "-" ? arg6.split(/=(.*)/, 2) : [arg6, void 0];
174
+ const arg7 = separatedArguments[j3];
175
+ const [originalArgName, argStr] = arg7[1] === "-" ? arg7.split(/=(.*)/, 2) : [arg7, void 0];
176
176
  let argName = originalArgName;
177
177
  while (argName in aliases) {
178
178
  argName = aliases[argName];
179
179
  }
180
180
  if (!(argName in handlers2)) {
181
181
  if (permissive) {
182
- result._.push(arg6);
182
+ result._.push(arg7);
183
183
  continue;
184
184
  } else {
185
185
  throw new ArgError(
@@ -218,13 +218,13 @@ var require_arg = __commonJS({
218
218
  }
219
219
  return result;
220
220
  }
221
- arg5.flag = (fn2) => {
221
+ arg6.flag = (fn2) => {
222
222
  fn2[flagSymbol] = true;
223
223
  return fn2;
224
224
  };
225
- arg5.COUNT = arg5.flag((v, name, existingCount) => (existingCount || 0) + 1);
226
- arg5.ArgError = ArgError;
227
- module.exports = arg5;
225
+ arg6.COUNT = arg6.flag((v, name, existingCount) => (existingCount || 0) + 1);
226
+ arg6.ArgError = ArgError;
227
+ module.exports = arg6;
228
228
  }
229
229
  });
230
230
 
@@ -19353,11 +19353,11 @@ var require_toolrunner = __commonJS({
19353
19353
  const upperToolPath = this.toolPath.toUpperCase();
19354
19354
  return this._endsWith(upperToolPath, ".CMD") || this._endsWith(upperToolPath, ".BAT");
19355
19355
  }
19356
- _windowsQuoteCmdArg(arg5) {
19356
+ _windowsQuoteCmdArg(arg6) {
19357
19357
  if (!this._isCmdFile()) {
19358
- return this._uvQuoteCmdArg(arg5);
19358
+ return this._uvQuoteCmdArg(arg6);
19359
19359
  }
19360
- if (!arg5) {
19360
+ if (!arg6) {
19361
19361
  return '""';
19362
19362
  }
19363
19363
  const cmdSpecialChars = [
@@ -19385,22 +19385,22 @@ var require_toolrunner = __commonJS({
19385
19385
  '"'
19386
19386
  ];
19387
19387
  let needsQuotes = false;
19388
- for (const char of arg5) {
19388
+ for (const char of arg6) {
19389
19389
  if (cmdSpecialChars.some((x) => x === char)) {
19390
19390
  needsQuotes = true;
19391
19391
  break;
19392
19392
  }
19393
19393
  }
19394
19394
  if (!needsQuotes) {
19395
- return arg5;
19395
+ return arg6;
19396
19396
  }
19397
19397
  let reverse = '"';
19398
19398
  let quoteHit = true;
19399
- for (let i = arg5.length; i > 0; i--) {
19400
- reverse += arg5[i - 1];
19401
- if (quoteHit && arg5[i - 1] === "\\") {
19399
+ for (let i = arg6.length; i > 0; i--) {
19400
+ reverse += arg6[i - 1];
19401
+ if (quoteHit && arg6[i - 1] === "\\") {
19402
19402
  reverse += "\\";
19403
- } else if (arg5[i - 1] === '"') {
19403
+ } else if (arg6[i - 1] === '"') {
19404
19404
  quoteHit = true;
19405
19405
  reverse += '"';
19406
19406
  } else {
@@ -19410,23 +19410,23 @@ var require_toolrunner = __commonJS({
19410
19410
  reverse += '"';
19411
19411
  return reverse.split("").reverse().join("");
19412
19412
  }
19413
- _uvQuoteCmdArg(arg5) {
19414
- if (!arg5) {
19413
+ _uvQuoteCmdArg(arg6) {
19414
+ if (!arg6) {
19415
19415
  return '""';
19416
19416
  }
19417
- if (!arg5.includes(" ") && !arg5.includes(" ") && !arg5.includes('"')) {
19418
- return arg5;
19417
+ if (!arg6.includes(" ") && !arg6.includes(" ") && !arg6.includes('"')) {
19418
+ return arg6;
19419
19419
  }
19420
- if (!arg5.includes('"') && !arg5.includes("\\")) {
19421
- return `"${arg5}"`;
19420
+ if (!arg6.includes('"') && !arg6.includes("\\")) {
19421
+ return `"${arg6}"`;
19422
19422
  }
19423
19423
  let reverse = '"';
19424
19424
  let quoteHit = true;
19425
- for (let i = arg5.length; i > 0; i--) {
19426
- reverse += arg5[i - 1];
19427
- if (quoteHit && arg5[i - 1] === "\\") {
19425
+ for (let i = arg6.length; i > 0; i--) {
19426
+ reverse += arg6[i - 1];
19427
+ if (quoteHit && arg6[i - 1] === "\\") {
19428
19428
  reverse += "\\";
19429
- } else if (arg5[i - 1] === '"') {
19429
+ } else if (arg6[i - 1] === '"') {
19430
19430
  quoteHit = true;
19431
19431
  reverse += "\\";
19432
19432
  } else {
@@ -19480,8 +19480,8 @@ var require_toolrunner = __commonJS({
19480
19480
  return new Promise((resolve3, reject) => __awaiter(this, void 0, void 0, function* () {
19481
19481
  this._debug(`exec tool: ${this.toolPath}`);
19482
19482
  this._debug("arguments:");
19483
- for (const arg5 of this.args) {
19484
- this._debug(` ${arg5}`);
19483
+ for (const arg6 of this.args) {
19484
+ this._debug(` ${arg6}`);
19485
19485
  }
19486
19486
  const optionsNonNull = this._cloneExecOptions(this.options);
19487
19487
  if (!optionsNonNull.silent && optionsNonNull.outStream) {
@@ -19578,12 +19578,12 @@ var require_toolrunner = __commonJS({
19578
19578
  const args2 = [];
19579
19579
  let inQuotes = false;
19580
19580
  let escaped = false;
19581
- let arg5 = "";
19581
+ let arg6 = "";
19582
19582
  function append2(c2) {
19583
19583
  if (escaped && c2 !== '"') {
19584
- arg5 += "\\";
19584
+ arg6 += "\\";
19585
19585
  }
19586
- arg5 += c2;
19586
+ arg6 += c2;
19587
19587
  escaped = false;
19588
19588
  }
19589
19589
  for (let i = 0; i < argString.length; i++) {
@@ -19605,16 +19605,16 @@ var require_toolrunner = __commonJS({
19605
19605
  continue;
19606
19606
  }
19607
19607
  if (c2 === " " && !inQuotes) {
19608
- if (arg5.length > 0) {
19609
- args2.push(arg5);
19610
- arg5 = "";
19608
+ if (arg6.length > 0) {
19609
+ args2.push(arg6);
19610
+ arg6 = "";
19611
19611
  }
19612
19612
  continue;
19613
19613
  }
19614
19614
  append2(c2);
19615
19615
  }
19616
- if (arg5.length > 0) {
19617
- args2.push(arg5.trim());
19616
+ if (arg6.length > 0) {
19617
+ args2.push(arg6.trim());
19618
19618
  }
19619
19619
  return args2;
19620
19620
  }
@@ -28041,20 +28041,20 @@ var require_escape = __commonJS({
28041
28041
  "node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/escape.js"(exports, module) {
28042
28042
  "use strict";
28043
28043
  var metaCharsRegExp = /([()\][%!^"`<>&|;, *?])/g;
28044
- function escapeCommand(arg5) {
28045
- arg5 = arg5.replace(metaCharsRegExp, "^$1");
28046
- return arg5;
28047
- }
28048
- function escapeArgument(arg5, doubleEscapeMetaChars) {
28049
- arg5 = `${arg5}`;
28050
- arg5 = arg5.replace(/(?=(\\+?)?)\1"/g, '$1$1\\"');
28051
- arg5 = arg5.replace(/(?=(\\+?)?)\1$/, "$1$1");
28052
- arg5 = `"${arg5}"`;
28053
- arg5 = arg5.replace(metaCharsRegExp, "^$1");
28044
+ function escapeCommand(arg6) {
28045
+ arg6 = arg6.replace(metaCharsRegExp, "^$1");
28046
+ return arg6;
28047
+ }
28048
+ function escapeArgument(arg6, doubleEscapeMetaChars) {
28049
+ arg6 = `${arg6}`;
28050
+ arg6 = arg6.replace(/(?=(\\+?)?)\1"/g, '$1$1\\"');
28051
+ arg6 = arg6.replace(/(?=(\\+?)?)\1$/, "$1$1");
28052
+ arg6 = `"${arg6}"`;
28053
+ arg6 = arg6.replace(metaCharsRegExp, "^$1");
28054
28054
  if (doubleEscapeMetaChars) {
28055
- arg5 = arg5.replace(metaCharsRegExp, "^$1");
28055
+ arg6 = arg6.replace(metaCharsRegExp, "^$1");
28056
28056
  }
28057
- return arg5;
28057
+ return arg6;
28058
28058
  }
28059
28059
  module.exports.command = escapeCommand;
28060
28060
  module.exports.argument = escapeArgument;
@@ -28142,7 +28142,7 @@ var require_parse3 = __commonJS({
28142
28142
  const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile);
28143
28143
  parsed2.command = path4.normalize(parsed2.command);
28144
28144
  parsed2.command = escape2.command(parsed2.command);
28145
- parsed2.args = parsed2.args.map((arg5) => escape2.argument(arg5, needsDoubleEscapeMetaChars));
28145
+ parsed2.args = parsed2.args.map((arg6) => escape2.argument(arg6, needsDoubleEscapeMetaChars));
28146
28146
  const shellCommand = [parsed2.command].concat(parsed2.args).join(" ");
28147
28147
  parsed2.args = ["/d", "/s", "/c", `"${shellCommand}"`];
28148
28148
  parsed2.command = process.env.comspec || "cmd.exe";
@@ -28430,10 +28430,10 @@ var require_timers2 = __commonJS({
28430
28430
  * before the specified function or code is executed.
28431
28431
  * @param {*} arg
28432
28432
  */
28433
- constructor(callback, delay2, arg5) {
28433
+ constructor(callback, delay2, arg6) {
28434
28434
  this._onTimeout = callback;
28435
28435
  this._idleTimeout = delay2;
28436
- this._timerArg = arg5;
28436
+ this._timerArg = arg6;
28437
28437
  this.refresh();
28438
28438
  }
28439
28439
  /**
@@ -28477,8 +28477,8 @@ var require_timers2 = __commonJS({
28477
28477
  * when the timer expires.
28478
28478
  * @returns {NodeJS.Timeout|FastTimer}
28479
28479
  */
28480
- setTimeout(callback, delay2, arg5) {
28481
- return delay2 <= RESOLUTION_MS ? setTimeout(callback, delay2, arg5) : new FastTimer(callback, delay2, arg5);
28480
+ setTimeout(callback, delay2, arg6) {
28481
+ return delay2 <= RESOLUTION_MS ? setTimeout(callback, delay2, arg6) : new FastTimer(callback, delay2, arg6);
28482
28482
  },
28483
28483
  /**
28484
28484
  * The clearTimeout method cancels an instantiated Timer previously created
@@ -28504,8 +28504,8 @@ var require_timers2 = __commonJS({
28504
28504
  * when the timer expires.
28505
28505
  * @returns {FastTimer}
28506
28506
  */
28507
- setFastTimeout(callback, delay2, arg5) {
28508
- return new FastTimer(callback, delay2, arg5);
28507
+ setFastTimeout(callback, delay2, arg6) {
28508
+ return new FastTimer(callback, delay2, arg6);
28509
28509
  },
28510
28510
  /**
28511
28511
  * The clearTimeout method cancels an instantiated FastTimer previously
@@ -55420,9 +55420,9 @@ var init_types = __esm({
55420
55420
  const { status, ctx } = this._processInputParams(input);
55421
55421
  const effect = this._def.effect || null;
55422
55422
  const checkCtx = {
55423
- addIssue: (arg5) => {
55424
- addIssueToContext(ctx, arg5);
55425
- if (arg5.fatal) {
55423
+ addIssue: (arg6) => {
55424
+ addIssueToContext(ctx, arg6);
55425
+ if (arg6.fatal) {
55426
55426
  status.abort();
55427
55427
  } else {
55428
55428
  status.dirty();
@@ -57613,13 +57613,13 @@ var init_doc = __esm({
57613
57613
  fn2(this);
57614
57614
  this.indent -= 1;
57615
57615
  }
57616
- write(arg5) {
57617
- if (typeof arg5 === "function") {
57618
- arg5(this, { execution: "sync" });
57619
- arg5(this, { execution: "async" });
57616
+ write(arg6) {
57617
+ if (typeof arg6 === "function") {
57618
+ arg6(this, { execution: "sync" });
57619
+ arg6(this, { execution: "async" });
57620
57620
  return;
57621
57621
  }
57622
- const content = arg5;
57622
+ const content = arg6;
57623
57623
  const lines = content.split("\n").filter((x) => x);
57624
57624
  const minIndent = Math.min(...lines.map((x) => x.length - x.trimStart().length));
57625
57625
  const dedented = lines.map((x) => x.slice(minIndent)).map((x) => " ".repeat(this.indent * 2) + x);
@@ -69675,13 +69675,13 @@ var require_code = __commonJS({
69675
69675
  return new _Code(expr);
69676
69676
  }
69677
69677
  exports.str = str;
69678
- function addCodeArg(code, arg5) {
69679
- if (arg5 instanceof _Code)
69680
- code.push(...arg5._items);
69681
- else if (arg5 instanceof Name)
69682
- code.push(arg5);
69678
+ function addCodeArg(code, arg6) {
69679
+ if (arg6 instanceof _Code)
69680
+ code.push(...arg6._items);
69681
+ else if (arg6 instanceof Name)
69682
+ code.push(arg6);
69683
69683
  else
69684
- code.push(interpolate(arg5));
69684
+ code.push(interpolate(arg6));
69685
69685
  }
69686
69686
  exports.addCodeArg = addCodeArg;
69687
69687
  function optimize(expr) {
@@ -81022,8 +81022,8 @@ var require_select = __commonJS({
81022
81022
  return selectors[":is"](sel);
81023
81023
  },
81024
81024
  ":nth-match": function(param, last) {
81025
- var args2 = param.split(/\s*,\s*/), arg5 = args2.shift(), test = compileGroup(args2.join(","));
81026
- return nth(arg5, test, last);
81025
+ var args2 = param.split(/\s*,\s*/), arg6 = args2.shift(), test = compileGroup(args2.join(","));
81026
+ return nth(arg6, test, last);
81027
81027
  },
81028
81028
  ":nth-last-match": function(param) {
81029
81029
  return selectors[":nth-match"](param, true);
@@ -100072,8 +100072,8 @@ var init_file_type = __esm({
100072
100072
  });
100073
100073
 
100074
100074
  // cli.ts
100075
- var import_arg4 = __toESM(require_arg(), 1);
100076
- var import_picocolors4 = __toESM(require_picocolors(), 1);
100075
+ var import_arg5 = __toESM(require_arg(), 1);
100076
+ var import_picocolors5 = __toESM(require_picocolors(), 1);
100077
100077
  import { basename as basename2 } from "node:path";
100078
100078
 
100079
100079
  // commands/auth.ts
@@ -101370,6 +101370,8 @@ async function promptScope(ctx) {
101370
101370
 
101371
101371
  // commands/auth.ts
101372
101372
  var CODEX_AUTH_SECRET = "CODEX_AUTH_JSON";
101373
+ var CLAUDE_OAUTH_SECRET = "CLAUDE_CODE_OAUTH_TOKEN";
101374
+ var CLAUDE_OAUTH_TOKEN_PREFIX = "sk-ant-oat";
101373
101375
  function stripAnsi(s) {
101374
101376
  return s.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, "");
101375
101377
  }
@@ -101404,7 +101406,8 @@ function printAuthUsage(params) {
101404
101406
  params.stream("manage provider credentials for the current repository.");
101405
101407
  params.stream("");
101406
101408
  params.stream("providers:");
101407
- params.stream(" codex mint a Codex (ChatGPT) subscription credential");
101409
+ params.stream(" codex mint a Codex (ChatGPT) subscription credential");
101410
+ params.stream(" claude save a Claude Code subscription OAuth token");
101408
101411
  params.stream("");
101409
101412
  params.stream("options:");
101410
101413
  params.stream(" -h, --help show help");
@@ -101417,6 +101420,14 @@ function printCodexUsage(params) {
101417
101420
  params.stream("options:");
101418
101421
  params.stream(" -h, --help show help");
101419
101422
  }
101423
+ function printClaudeUsage(params) {
101424
+ params.stream(`usage: ${params.prog} auth claude [options]
101425
+ `);
101426
+ params.stream("save a Claude Code subscription OAuth token as CLAUDE_CODE_OAUTH_TOKEN.");
101427
+ params.stream("");
101428
+ params.stream("options:");
101429
+ params.stream(" -h, --help show help");
101430
+ }
101420
101431
  async function runCli(params) {
101421
101432
  const firstArg = params.args[0];
101422
101433
  const helpAtTopLevel = params.showHelp || params.args.length === 0 || params.args.length === 1 && (firstArg === "--help" || firstArg === "-h");
@@ -101430,6 +101441,10 @@ async function runCli(params) {
101430
101441
  await runCodex({ args: rest, prog: params.prog });
101431
101442
  return;
101432
101443
  }
101444
+ if (subcommand === "claude") {
101445
+ await runClaude({ args: rest, prog: params.prog });
101446
+ return;
101447
+ }
101433
101448
  console.error(`unknown auth provider: ${import_picocolors2.default.bold(subcommand)}
101434
101449
  `);
101435
101450
  printAuthUsage({ stream: console.error, prog: params.prog });
@@ -101592,6 +101607,120 @@ async function runCodexAuth() {
101592
101607
  process.exit(1);
101593
101608
  }
101594
101609
  }
101610
+ function parseClaudeArgs(args2) {
101611
+ return (0, import_arg.default)(
101612
+ {
101613
+ "--help": Boolean,
101614
+ "-h": "--help"
101615
+ },
101616
+ { argv: args2 }
101617
+ );
101618
+ }
101619
+ async function runClaude(params) {
101620
+ let parsed2;
101621
+ try {
101622
+ parsed2 = parseClaudeArgs(params.args);
101623
+ } catch (error49) {
101624
+ const message = error49 instanceof Error ? error49.message : String(error49);
101625
+ console.error(`${message}
101626
+ `);
101627
+ printClaudeUsage({ stream: console.error, prog: params.prog });
101628
+ process.exit(1);
101629
+ }
101630
+ if (parsed2["--help"]) {
101631
+ printClaudeUsage({ stream: console.log, prog: params.prog });
101632
+ return;
101633
+ }
101634
+ await runClaudeAuth();
101635
+ }
101636
+ async function runClaudeAuth() {
101637
+ mt(import_picocolors2.default.bgGreen(import_picocolors2.default.black(" pullfrog auth claude ")));
101638
+ const spin = fe();
101639
+ setActiveSpin(spin);
101640
+ try {
101641
+ spin.start("authenticating with github");
101642
+ const token = getGhToken();
101643
+ spin.stop("github authenticated");
101644
+ spin.start("detecting repository");
101645
+ const remote = parseGitRemote();
101646
+ spin.stop(`detected repo ${import_picocolors2.default.cyan(`${remote.owner}/${remote.repo}`)}`);
101647
+ spin.start("checking pullfrog app installation");
101648
+ const status = await fetchStatus({ token, owner: remote.owner, repo: remote.repo });
101649
+ if (!status.installed) {
101650
+ spin.stop(import_picocolors2.default.red("pullfrog app not installed on this repo"));
101651
+ bail(
101652
+ `install pullfrog on ${import_picocolors2.default.bold(`${remote.owner}/${remote.repo}`)} before configuring auth.
101653
+ ${import_picocolors2.default.dim("run:")} ${import_picocolors2.default.cyan(`npx pullfrog init`)}`
101654
+ );
101655
+ }
101656
+ spin.stop(`pullfrog app is installed on ${import_picocolors2.default.cyan(`@${remote.owner}`)}`);
101657
+ if (status.pullfrogSecrets.includes(CLAUDE_OAUTH_SECRET)) {
101658
+ const overwrite = await _t({
101659
+ message: `${import_picocolors2.default.cyan(CLAUDE_OAUTH_SECRET)} is already configured \u2014 overwrite?`,
101660
+ options: [
101661
+ { value: true, label: "overwrite", hint: "replace with a freshly minted token" },
101662
+ { value: false, label: "cancel" }
101663
+ ]
101664
+ });
101665
+ handleCancel(overwrite);
101666
+ if (!overwrite) {
101667
+ pt("canceled.");
101668
+ return;
101669
+ }
101670
+ }
101671
+ const scope2 = status.isOrg ? await promptScope({ owner: remote.owner, repo: remote.repo }) : "account";
101672
+ O2.info(
101673
+ [
101674
+ `mint a long-lived Claude Code OAuth token, then paste it below.`,
101675
+ ``,
101676
+ `${import_picocolors2.default.dim("run:")} ${import_picocolors2.default.cyan("claude setup-token")}`,
101677
+ `it opens your browser, works with Pro/Max subscriptions, and prints a`,
101678
+ `token starting with ${import_picocolors2.default.cyan("sk-ant-oat\u2026")}. copy that token.`
101679
+ ].join("\n")
101680
+ );
101681
+ const oauthToken = await bt({
101682
+ message: `paste your Claude Code OAuth token ${import_picocolors2.default.dim("(Enter to cancel)")}`,
101683
+ mask: "*"
101684
+ });
101685
+ handleCancel(oauthToken);
101686
+ if (!oauthToken) {
101687
+ pt("canceled.");
101688
+ return;
101689
+ }
101690
+ const value2 = oauthToken.trim();
101691
+ if (!value2.startsWith(CLAUDE_OAUTH_TOKEN_PREFIX)) {
101692
+ O2.warn(
101693
+ `that doesn't look like a ${import_picocolors2.default.cyan("claude setup-token")} token (expected ${import_picocolors2.default.cyan(`${CLAUDE_OAUTH_TOKEN_PREFIX}\u2026`)}). saving it anyway.`
101694
+ );
101695
+ }
101696
+ spin.start(`saving ${import_picocolors2.default.cyan(CLAUDE_OAUTH_SECRET)} to Pullfrog`);
101697
+ const result = await setPullfrogSecret({
101698
+ token,
101699
+ owner: remote.owner,
101700
+ repo: remote.repo,
101701
+ name: CLAUDE_OAUTH_SECRET,
101702
+ value: value2,
101703
+ scope: scope2
101704
+ });
101705
+ if (!result.saved) {
101706
+ spin.stop(import_picocolors2.default.red("could not save secret"));
101707
+ O2.warn(
101708
+ `${result.error}
101709
+ ${import_picocolors2.default.dim("set it manually at:")} ${PULLFROG_API_URL}/console/${remote.owner}`
101710
+ );
101711
+ process.exit(1);
101712
+ }
101713
+ spin.stop(`saved ${import_picocolors2.default.cyan(CLAUDE_OAUTH_SECRET)} to Pullfrog (${scope2})`);
101714
+ setActiveSpin(null);
101715
+ gt("done.");
101716
+ } catch (error49) {
101717
+ spin.stop(import_picocolors2.default.red("failed"));
101718
+ setActiveSpin(null);
101719
+ const message = error49 instanceof Error ? error49.message : String(error49);
101720
+ O2.error(message);
101721
+ process.exit(1);
101722
+ }
101723
+ }
101595
101724
 
101596
101725
  // commands/gha.ts
101597
101726
  var core11 = __toESM(require_core(), 1);
@@ -102439,11 +102568,11 @@ function ts() {
102439
102568
  return isDebugEnabled() ? `[${(/* @__PURE__ */ new Date()).toISOString()}] ` : "";
102440
102569
  }
102441
102570
  function formatArgs(args2) {
102442
- return args2.map((arg5) => {
102443
- if (typeof arg5 === "string") return arg5;
102444
- if (arg5 instanceof Error) return `${arg5.message}
102445
- ${arg5.stack}`;
102446
- return JSON.stringify(arg5);
102571
+ return args2.map((arg6) => {
102572
+ if (typeof arg6 === "string") return arg6;
102573
+ if (arg6 instanceof Error) return `${arg6.message}
102574
+ ${arg6.stack}`;
102575
+ return JSON.stringify(arg6);
102447
102576
  }).join(" ");
102448
102577
  }
102449
102578
  function startGroup2(name) {
@@ -102841,7 +102970,7 @@ var import_semver = __toESM(require_semver2(), 1);
102841
102970
  // package.json
102842
102971
  var package_default = {
102843
102972
  name: "pullfrog",
102844
- version: "0.1.33",
102973
+ version: "0.1.34",
102845
102974
  type: "module",
102846
102975
  bin: {
102847
102976
  pullfrog: "dist/cli.mjs",
@@ -104598,7 +104727,7 @@ function tailLines2(text, maxCodeUnits) {
104598
104727
  const firstNewline = tail.indexOf("\n");
104599
104728
  return firstNewline > 0 && firstNewline < tail.length - 1 ? tail.slice(firstNewline + 1) : tail;
104600
104729
  }
104601
- async function runClaude(params) {
104730
+ async function runClaude2(params) {
104602
104731
  const startTime = performance5.now();
104603
104732
  let eventCount = 0;
104604
104733
  const labeler = new SessionLabeler();
@@ -105124,7 +105253,7 @@ var claude = agent({
105124
105253
  log.debug(`\xBB starting Pullfrog (Claude Code): ${cliPath} ${baseArgs.join(" ")}`);
105125
105254
  log.debug(`\xBB working directory: ${repoDir}`);
105126
105255
  const gateServer = __using(_stack, await startGateServer(ctx), true);
105127
- const result = await runClaude({
105256
+ const result = await runClaude2({
105128
105257
  label: "Pullfrog",
105129
105258
  cmd: cliPath,
105130
105259
  cwd: repoDir,
@@ -105940,7 +106069,7 @@ var buildClientParams = (args2, fields) => {
105940
106069
  };
105941
106070
  const map2 = buildKeyMap(fields);
105942
106071
  let config3;
105943
- for (const [index, arg5] of args2.entries()) {
106072
+ for (const [index, arg6] of args2.entries()) {
105944
106073
  if (fields[index]) {
105945
106074
  config3 = fields[index];
105946
106075
  }
@@ -105953,13 +106082,13 @@ var buildClientParams = (args2, fields) => {
105953
106082
  const name = field.map || config3.key;
105954
106083
  if (field.in) {
105955
106084
  ;
105956
- params[field.in][name] = arg5;
106085
+ params[field.in][name] = arg6;
105957
106086
  }
105958
106087
  } else {
105959
- params.body = arg5;
106088
+ params.body = arg6;
105960
106089
  }
105961
106090
  } else {
105962
- for (const [key, value2] of Object.entries(arg5 ?? {})) {
106091
+ for (const [key, value2] of Object.entries(arg6 ?? {})) {
105963
106092
  const field = map2.get(key);
105964
106093
  if (field) {
105965
106094
  if (field.in) {
@@ -111617,12 +111746,12 @@ var CompiledFunction = class extends CastableBase {
111617
111746
  constructor(...args2) {
111618
111747
  super();
111619
111748
  this.argNames = args2;
111620
- for (const arg5 of args2) {
111621
- if (arg5 in this) {
111622
- throw new Error(`Arg name '${arg5}' would overwrite an existing property on FunctionBody`);
111749
+ for (const arg6 of args2) {
111750
+ if (arg6 in this) {
111751
+ throw new Error(`Arg name '${arg6}' would overwrite an existing property on FunctionBody`);
111623
111752
  }
111624
111753
  ;
111625
- this[arg5] = arg5;
111754
+ this[arg6] = arg6;
111626
111755
  }
111627
111756
  }
111628
111757
  indentation = 0;
@@ -111707,12 +111836,12 @@ var NodeCompiler = class extends CompiledFunction {
111707
111836
  this.optimistic = ctx.optimistic === true;
111708
111837
  }
111709
111838
  invoke(node2, opts) {
111710
- const arg5 = opts?.arg ?? this.data;
111839
+ const arg6 = opts?.arg ?? this.data;
111711
111840
  const requiresContext = typeof node2 === "string" ? true : this.requiresContextFor(node2);
111712
111841
  const id = typeof node2 === "string" ? node2 : node2.id;
111713
111842
  if (requiresContext)
111714
- return `${this.referenceToId(id, opts)}(${arg5}, ${this.ctx})`;
111715
- return `${this.referenceToId(id, opts)}(${arg5})`;
111843
+ return `${this.referenceToId(id, opts)}(${arg6}, ${this.ctx})`;
111844
+ return `${this.referenceToId(id, opts)}(${arg6})`;
111716
111845
  }
111717
111846
  referenceToId(id, opts) {
111718
111847
  const invokedKind = opts?.kind ?? this.traversalKind;
@@ -112673,8 +112802,8 @@ var ZodType2 = /* @__PURE__ */ $constructor("ZodType", (inst, def) => {
112673
112802
  inst.nullish = () => optional(nullable(inst));
112674
112803
  inst.nonoptional = (params) => nonoptional(inst, params);
112675
112804
  inst.array = () => array(inst);
112676
- inst.or = (arg5) => union([inst, arg5]);
112677
- inst.and = (arg5) => intersection(inst, arg5);
112805
+ inst.or = (arg6) => union([inst, arg6]);
112806
+ inst.and = (arg6) => intersection(inst, arg6);
112678
112807
  inst.transform = (tx) => pipe(inst, transform(tx));
112679
112808
  inst.default = (def2) => _default2(inst, def2);
112680
112809
  inst.prefault = (def2) => prefault(inst, def2);
@@ -119734,10 +119863,10 @@ var Context = class {
119734
119863
  }
119735
119864
  return Object.fromEntries(this.#var);
119736
119865
  }
119737
- #newResponse(data, arg5, headers) {
119866
+ #newResponse(data, arg6, headers) {
119738
119867
  const responseHeaders = this.#res ? new Headers(this.#res.headers) : this.#preparedHeaders ?? new Headers();
119739
- if (typeof arg5 === "object" && "headers" in arg5) {
119740
- const argHeaders = arg5.headers instanceof Headers ? arg5.headers : new Headers(arg5.headers);
119868
+ if (typeof arg6 === "object" && "headers" in arg6) {
119869
+ const argHeaders = arg6.headers instanceof Headers ? arg6.headers : new Headers(arg6.headers);
119741
119870
  for (const [key, value2] of argHeaders) {
119742
119871
  if (key.toLowerCase() === "set-cookie") {
119743
119872
  responseHeaders.append(key, value2);
@@ -119758,7 +119887,7 @@ var Context = class {
119758
119887
  }
119759
119888
  }
119760
119889
  }
119761
- const status = typeof arg5 === "number" ? arg5 : arg5?.status ?? this.#status;
119890
+ const status = typeof arg6 === "number" ? arg6 : arg6?.status ?? this.#status;
119762
119891
  return createResponseInstance(data, { status, headers: responseHeaders });
119763
119892
  }
119764
119893
  newResponse = (...args2) => this.#newResponse(...args2);
@@ -119783,7 +119912,7 @@ var Context = class {
119783
119912
  * })
119784
119913
  * ```
119785
119914
  */
119786
- body = (data, arg5, headers) => this.#newResponse(data, arg5, headers);
119915
+ body = (data, arg6, headers) => this.#newResponse(data, arg6, headers);
119787
119916
  /**
119788
119917
  * `.text()` can render text as `Content-Type:text/plain`.
119789
119918
  *
@@ -119796,10 +119925,10 @@ var Context = class {
119796
119925
  * })
119797
119926
  * ```
119798
119927
  */
119799
- text = (text, arg5, headers) => {
119800
- return !this.#preparedHeaders && !this.#status && !arg5 && !headers && !this.finalized ? new Response(text) : this.#newResponse(
119928
+ text = (text, arg6, headers) => {
119929
+ return !this.#preparedHeaders && !this.#status && !arg6 && !headers && !this.finalized ? new Response(text) : this.#newResponse(
119801
119930
  text,
119802
- arg5,
119931
+ arg6,
119803
119932
  setDefaultContentType(TEXT_PLAIN, headers)
119804
119933
  );
119805
119934
  };
@@ -119815,15 +119944,15 @@ var Context = class {
119815
119944
  * })
119816
119945
  * ```
119817
119946
  */
119818
- json = (object5, arg5, headers) => {
119947
+ json = (object5, arg6, headers) => {
119819
119948
  return this.#newResponse(
119820
119949
  JSON.stringify(object5),
119821
- arg5,
119950
+ arg6,
119822
119951
  setDefaultContentType("application/json", headers)
119823
119952
  );
119824
119953
  };
119825
- html = (html, arg5, headers) => {
119826
- const res = (html2) => this.#newResponse(html2, arg5, setDefaultContentType("text/html; charset=UTF-8", headers));
119954
+ html = (html, arg6, headers) => {
119955
+ const res = (html2) => this.#newResponse(html2, arg6, setDefaultContentType("text/html; charset=UTF-8", headers));
119827
119956
  return typeof html === "object" ? resolveCallback(html, HtmlEscapedCallbackPhase.Stringify, false, {}).then(res) : res(html);
119828
119957
  };
119829
119958
  /**
@@ -121892,13 +122021,13 @@ var Doc2 = class {
121892
122021
  fn2(this);
121893
122022
  this.indent -= 1;
121894
122023
  }
121895
- write(arg5) {
121896
- if (typeof arg5 === "function") {
121897
- arg5(this, { execution: "sync" });
121898
- arg5(this, { execution: "async" });
122024
+ write(arg6) {
122025
+ if (typeof arg6 === "function") {
122026
+ arg6(this, { execution: "sync" });
122027
+ arg6(this, { execution: "async" });
121899
122028
  return;
121900
122029
  }
121901
- const lines = arg5.split("\n").filter((x) => x);
122030
+ const lines = arg6.split("\n").filter((x) => x);
121902
122031
  const minIndent = Math.min(...lines.map((x) => x.length - x.trimStart().length));
121903
122032
  const dedented = lines.map((x) => x.slice(minIndent)).map((x) => " ".repeat(this.indent * 2) + x);
121904
122033
  for (const line$1 of dedented) this.content.push(line$1);
@@ -123569,8 +123698,8 @@ var ZodType3 = /* @__PURE__ */ $constructor2("ZodType", (inst, def$30) => {
123569
123698
  inst.nullish = () => optional2(nullable2(inst));
123570
123699
  inst.nonoptional = (params) => nonoptional2(inst, params);
123571
123700
  inst.array = () => array2(inst);
123572
- inst.or = (arg5) => union2([inst, arg5]);
123573
- inst.and = (arg5) => intersection2(inst, arg5);
123701
+ inst.or = (arg6) => union2([inst, arg6]);
123702
+ inst.and = (arg6) => intersection2(inst, arg6);
123574
123703
  inst.transform = (tx) => pipe2(inst, transform2(tx));
123575
123704
  inst.default = (def$31) => _default3(inst, def$31);
123576
123705
  inst.prefault = (def$31) => prefault2(inst, def$31);
@@ -125362,14 +125491,14 @@ var require_http_errors = /* @__PURE__ */ __commonJSMin(((exports, module) => {
125362
125491
  var status$1 = 500;
125363
125492
  var props = {};
125364
125493
  for (var i$3 = 0; i$3 < arguments.length; i$3++) {
125365
- var arg5 = arguments[i$3];
125366
- var type2 = typeof arg5;
125367
- if (type2 === "object" && arg5 instanceof Error) {
125368
- err = arg5;
125494
+ var arg6 = arguments[i$3];
125495
+ var type2 = typeof arg6;
125496
+ if (type2 === "object" && arg6 instanceof Error) {
125497
+ err = arg6;
125369
125498
  status$1 = err.status || err.statusCode || status$1;
125370
- } else if (type2 === "number" && i$3 === 0) status$1 = arg5;
125371
- else if (type2 === "string") msg = arg5;
125372
- else if (type2 === "object") props = arg5;
125499
+ } else if (type2 === "number" && i$3 === 0) status$1 = arg6;
125500
+ else if (type2 === "string") msg = arg6;
125501
+ else if (type2 === "object") props = arg6;
125373
125502
  else throw new TypeError("argument #" + (i$3 + 1) + " unsupported type " + type2);
125374
125503
  }
125375
125504
  if (typeof status$1 === "number" && (status$1 < 400 || status$1 >= 600)) deprecate("non-error status code; use only 4xx or 5xx status codes");
@@ -135563,10 +135692,10 @@ var require_code$1 = /* @__PURE__ */ __commonJSMin(((exports) => {
135563
135692
  return new _Code(expr);
135564
135693
  }
135565
135694
  exports.str = str;
135566
- function addCodeArg(code, arg5) {
135567
- if (arg5 instanceof _Code) code.push(...arg5._items);
135568
- else if (arg5 instanceof Name) code.push(arg5);
135569
- else code.push(interpolate(arg5));
135695
+ function addCodeArg(code, arg6) {
135696
+ if (arg6 instanceof _Code) code.push(...arg6._items);
135697
+ else if (arg6 instanceof Name) code.push(arg6);
135698
+ else code.push(interpolate(arg6));
135570
135699
  }
135571
135700
  exports.addCodeArg = addCodeArg;
135572
135701
  function optimize(expr) {
@@ -142500,11 +142629,11 @@ ${error49 instanceof Error ? error49.stack : JSON.stringify(error49)}`
142500
142629
  );
142501
142630
  }
142502
142631
  const args2 = request2.params.arguments;
142503
- for (const arg5 of prompt.arguments ?? []) {
142504
- if (arg5.required && !(args2 && arg5.name in args2)) {
142632
+ for (const arg6 of prompt.arguments ?? []) {
142633
+ if (arg6.required && !(args2 && arg6.name in args2)) {
142505
142634
  throw new McpError(
142506
142635
  ErrorCode.InvalidRequest,
142507
- `Prompt '${request2.params.name}' requires argument '${arg5.name}': ${arg5.description || "No description provided"}`
142636
+ `Prompt '${request2.params.name}' requires argument '${arg6.name}': ${arg6.description || "No description provided"}`
142508
142637
  );
142509
142638
  }
142510
142639
  }
@@ -143722,7 +143851,7 @@ var FastMCP = class extends FastMCPEventEmitter {
143722
143851
  #parseRuntimeConfig(overrides) {
143723
143852
  const args2 = process.argv.slice(2);
143724
143853
  const getArg = (name) => {
143725
- const index = args2.findIndex((arg5) => arg5 === `--${name}`);
143854
+ const index = args2.findIndex((arg6) => arg6 === `--${name}`);
143726
143855
  return index !== -1 && index + 1 < args2.length ? args2[index + 1] : void 0;
143727
143856
  };
143728
143857
  const transportArg = getArg("transport");
@@ -145097,11 +145226,11 @@ var GenericRoot = class extends Callable {
145097
145226
  constructor(paramDefs, bodyDef, $3, arg$, hkt) {
145098
145227
  super((...args2) => {
145099
145228
  const argNodes = flatMorph(this.names, (i, name) => {
145100
- const arg5 = this.arg$.parse(args2[i]);
145101
- if (!arg5.extends(this.constraints[i])) {
145102
- throwParseError(writeUnsatisfiedParameterConstraintMessage(name, this.constraints[i].expression, arg5.expression));
145229
+ const arg6 = this.arg$.parse(args2[i]);
145230
+ if (!arg6.extends(this.constraints[i])) {
145231
+ throwParseError(writeUnsatisfiedParameterConstraintMessage(name, this.constraints[i].expression, arg6.expression));
145103
145232
  }
145104
- return [name, arg5];
145233
+ return [name, arg6];
145105
145234
  });
145106
145235
  if (this.defIsLazy()) {
145107
145236
  const def = this.bodyDef(argNodes);
@@ -145149,7 +145278,7 @@ var GenericRoot = class extends Callable {
145149
145278
  return this.baseInstantiation.internal.references;
145150
145279
  }
145151
145280
  };
145152
- var writeUnsatisfiedParameterConstraintMessage = (name, constraint, arg5) => `${name} must be assignable to ${constraint} (was ${arg5})`;
145281
+ var writeUnsatisfiedParameterConstraintMessage = (name, constraint, arg6) => `${name} must be assignable to ${constraint} (was ${arg6})`;
145153
145282
 
145154
145283
  // node_modules/.pnpm/@ark+schema@0.56.0/node_modules/@ark/schema/out/predicate.js
145155
145284
  var implementation = implementNode({
@@ -149647,7 +149776,7 @@ var _parseGenericArgs = (name, g, s, argNodes) => {
149647
149776
  argNodes.push(argState.root);
149648
149777
  if (argState.finalizer === ">") {
149649
149778
  if (argNodes.length !== g.params.length) {
149650
- return s.error(writeInvalidGenericArgCountMessage(name, g.names, argNodes.map((arg5) => arg5.expression)));
149779
+ return s.error(writeInvalidGenericArgCountMessage(name, g.names, argNodes.map((arg6) => arg6.expression)));
149651
149780
  }
149652
149781
  return argNodes;
149653
149782
  }
@@ -149676,10 +149805,10 @@ var parseGenericInstantiation = (name, g, s) => {
149676
149805
  var unenclosedToNode = (s, token) => maybeParseReference(s, token) ?? maybeParseUnenclosedLiteral(s, token) ?? s.error(token === "" ? s.scanner.lookahead === "#" ? writePrefixedPrivateReferenceMessage(s.shiftedBy(1).scanner.shiftUntilLookahead(terminatingChars)) : writeMissingOperandMessage(s) : writeUnresolvableMessage(token));
149677
149806
  var maybeParseReference = (s, token) => {
149678
149807
  if (s.ctx.args?.[token]) {
149679
- const arg5 = s.ctx.args[token];
149680
- if (typeof arg5 !== "string")
149681
- return arg5;
149682
- return s.ctx.$.node("alias", { reference: arg5 }, { prereduced: true });
149808
+ const arg6 = s.ctx.args[token];
149809
+ if (typeof arg6 !== "string")
149810
+ return arg6;
149811
+ return s.ctx.$.node("alias", { reference: arg6 }, { prereduced: true });
149683
149812
  }
149684
149813
  const resolution = s.ctx.$.maybeResolve(token);
149685
149814
  if (hasArkKind(resolution, "root"))
@@ -158379,13 +158508,13 @@ function GitTool(ctx) {
158379
158508
  if (blocked) {
158380
158509
  throw new Error(blocked);
158381
158510
  }
158382
- for (const arg5 of args2) {
158511
+ for (const arg6 of args2) {
158383
158512
  const isBlocked = NOSHELL_BLOCKED_ARGS.some(
158384
- (flag) => arg5 === flag || arg5.startsWith(flag + "=")
158513
+ (flag) => arg6 === flag || arg6.startsWith(flag + "=")
158385
158514
  );
158386
158515
  if (isBlocked) {
158387
158516
  throw new Error(
158388
- `Blocked: '${arg5}' flag can execute arbitrary code and is not allowed.`
158517
+ `Blocked: '${arg6}' flag can execute arbitrary code and is not allowed.`
158389
158518
  );
158390
158519
  }
158391
158520
  }
@@ -165316,6 +165445,11 @@ async function mintProxyKey(ctx) {
165316
165445
  body?.error ?? "billing service temporarily unavailable \u2014 retry shortly"
165317
165446
  );
165318
165447
  }
165448
+ if (response.status === 404) {
165449
+ throw new TransientError(
165450
+ "Pullfrog couldn't match this repository to its account \u2014 it may have just been renamed or transferred. The link refreshes automatically on the next run; if it keeps failing, reinstall the GitHub App on the repo's current owner."
165451
+ );
165452
+ }
165319
165453
  if (!response.ok) {
165320
165454
  log.warning(`proxy key mint failed (${response.status})`);
165321
165455
  return null;
@@ -165880,28 +166014,7 @@ ${genericBody}`,
165880
166014
  // utils/runLifecycle.ts
165881
166015
  var core10 = __toESM(require_core(), 1);
165882
166016
 
165883
- // utils/checksGate.ts
165884
- var OK_CONCLUSIONS = /* @__PURE__ */ new Set(["success", "neutral", "skipped"]);
165885
- var PULLFROG_CHECKS = /* @__PURE__ */ new Set(["pullfrog", "pullfrog-approval"]);
165886
- function checkRunsGate(params) {
165887
- for (const run4 of params.checkRuns) {
165888
- if (PULLFROG_CHECKS.has(run4.name.toLowerCase())) continue;
165889
- if (run4.status !== "completed")
165890
- return { ok: false, reason: `check "${run4.name}" ${run4.status}` };
165891
- if (!OK_CONCLUSIONS.has(run4.conclusion ?? "")) {
165892
- return { ok: false, reason: `check "${run4.name}" concluded ${run4.conclusion}` };
165893
- }
165894
- }
165895
- return { ok: true, reason: "all checks passed" };
165896
- }
165897
- function hasVerifiedCheck(params) {
165898
- return params.checkRuns.some(
165899
- (r) => !PULLFROG_CHECKS.has(r.name.toLowerCase()) && r.status === "completed"
165900
- );
165901
- }
165902
-
165903
166017
  // utils/autoMerge.ts
165904
- var NON_MERGEABLE_STATES = /* @__PURE__ */ new Set(["dirty", "behind", "blocked"]);
165905
166018
  function hasBlockingHumanReview(reviews) {
165906
166019
  const latestByReviewer = /* @__PURE__ */ new Map();
165907
166020
  for (const review of reviews) {
@@ -165918,6 +166031,20 @@ function hasBlockingHumanReview(reviews) {
165918
166031
  }
165919
166032
  return false;
165920
166033
  }
166034
+ var ENABLE_AUTO_MERGE = (
166035
+ /* GraphQL */
166036
+ `
166037
+ mutation ($pullRequestId: ID!, $headSha: GitObjectID!) {
166038
+ enablePullRequestAutoMerge(input: {
166039
+ pullRequestId: $pullRequestId
166040
+ mergeMethod: SQUASH
166041
+ expectedHeadOid: $headSha
166042
+ }) { clientMutationId }
166043
+ }`
166044
+ );
166045
+ var isAlreadyMergeable = (error49) => error49 instanceof Error && /clean status/i.test(error49.message);
166046
+ var isHeadChanged = (error49) => error49 instanceof Error && /head has changed|expected head/i.test(error49.message);
166047
+ var isAutoMergeDisallowed = (error49) => error49 instanceof Error && /not allowed/i.test(error49.message);
165921
166048
  async function autoMergeAfterApprove(ctx) {
165922
166049
  if (!ctx.autoMergeEnabled) return;
165923
166050
  if (!ctx.prApproveEnabled) return;
@@ -165928,6 +166055,12 @@ async function autoMergeAfterApprove(ctx) {
165928
166055
  const skip = (reason) => log.info(
165929
166056
  `autoMerge: pr=#${pullNumber} approvalSha=${approval.sha?.slice(0, 7)} \u2192 skipped: ${reason}`
165930
166057
  );
166058
+ const comment = (body) => ctx.octokit.rest.issues.createComment({
166059
+ owner: ctx.repo.owner,
166060
+ repo: ctx.repo.name,
166061
+ issue_number: pullNumber,
166062
+ body: addFooter(ctx, body)
166063
+ }).catch((err) => log.debug(`autoMerge comment failed: ${err}`));
165931
166064
  const pr = await ctx.octokit.rest.pulls.get({
165932
166065
  owner: ctx.repo.owner,
165933
166066
  repo: ctx.repo.name,
@@ -165935,6 +166068,7 @@ async function autoMergeAfterApprove(ctx) {
165935
166068
  });
165936
166069
  if (pr.data.state !== "open") return skip("pr not open");
165937
166070
  if (pr.data.draft) return skip("pr is draft");
166071
+ if (pr.data.auto_merge) return skip("auto-merge already enabled");
165938
166072
  const headSha = pr.data.head.sha;
165939
166073
  if (approval.sha !== headSha) return skip(`approval sha != head ${headSha.slice(0, 7)}`);
165940
166074
  const outstanding = await countOutstandingPullfrogThreads(ctx, pullNumber);
@@ -165946,40 +166080,49 @@ async function autoMergeAfterApprove(ctx) {
165946
166080
  per_page: 100
165947
166081
  });
165948
166082
  if (hasBlockingHumanReview(reviews)) return skip("human changes requested");
165949
- if (pr.data.mergeable !== true) return skip(`not mergeable (mergeable=${pr.data.mergeable})`);
165950
- if (pr.data.mergeable_state && NON_MERGEABLE_STATES.has(pr.data.mergeable_state)) {
165951
- return skip(`mergeable_state=${pr.data.mergeable_state}`);
166083
+ try {
166084
+ await op(
166085
+ () => ctx.octokit.graphql(ENABLE_AUTO_MERGE, {
166086
+ pullRequestId: pr.data.node_id,
166087
+ headSha
166088
+ }),
166089
+ {
166090
+ name: "enablePullRequestAutoMerge",
166091
+ retries: [500, 2e3],
166092
+ bail: (error49) => !isTransientOctokitError(error49)
166093
+ }
166094
+ )();
166095
+ log.info(`autoMerge: pr=#${pullNumber} @ ${headSha.slice(0, 7)} \u2192 native auto-merge enabled`);
166096
+ await comment(
166097
+ "> \u2705 Approved \u2014 auto-merge enabled; GitHub will merge once required checks pass."
166098
+ );
166099
+ return;
166100
+ } catch (error49) {
166101
+ if (isHeadChanged(error49)) return skip("head moved during enable");
166102
+ if (isAutoMergeDisallowed(error49)) {
166103
+ await comment(
166104
+ "> \u26A0\uFE0F Approved, but auto-merge is off for this repo. Enable `Allow auto-merge` in Settings > General > Pull Requests."
166105
+ );
166106
+ return;
166107
+ }
166108
+ if (!isAlreadyMergeable(error49)) throw error49;
165952
166109
  }
165953
- const checkRuns = await ctx.octokit.paginate(ctx.octokit.rest.checks.listForRef, {
165954
- owner: ctx.repo.owner,
165955
- repo: ctx.repo.name,
165956
- ref: headSha,
165957
- per_page: 100
165958
- });
165959
- const gate = checkRunsGate({ checkRuns });
165960
- if (!gate.ok) return skip(`ci: ${gate.reason}`);
165961
- if (!hasVerifiedCheck({ checkRuns })) return skip("no completed external check-run to verify");
166110
+ const base = await ctx.octokit.rest.repos.getBranch({ owner: ctx.repo.owner, repo: ctx.repo.name, branch: pr.data.base.ref }).catch(() => null);
166111
+ if (!base?.data.protected) return skip("base branch not protected \u2014 refusing CI-ungated merge");
165962
166112
  const merge4 = await ctx.octokit.rest.pulls.merge({
165963
166113
  owner: ctx.repo.owner,
165964
166114
  repo: ctx.repo.name,
165965
166115
  pull_number: pullNumber,
165966
166116
  sha: headSha,
165967
166117
  merge_method: "squash",
165968
- commit_title: `${pr.data.title} (#${pullNumber})`,
165969
- commit_message: "merged autonomously by Pullfrog after a clean approval."
166118
+ commit_title: `${pr.data.title} (#${pullNumber})`
165970
166119
  });
165971
166120
  log.info(
165972
- `autoMerge: pr=#${pullNumber} approvalSha=${headSha.slice(0, 7)} outstanding=0 \u2192 merged ${merge4.data.sha?.slice(0, 7)}`
166121
+ `autoMerge: pr=#${pullNumber} @ ${headSha.slice(0, 7)} \u2192 merged directly ${merge4.data.sha?.slice(0, 7)}`
166122
+ );
166123
+ await comment(
166124
+ "> \u2705 Merged autonomously after Pullfrog approved this PR and resolved all of its own review threads."
165973
166125
  );
165974
- await ctx.octokit.rest.issues.createComment({
165975
- owner: ctx.repo.owner,
165976
- repo: ctx.repo.name,
165977
- issue_number: pullNumber,
165978
- body: addFooter(
165979
- ctx,
165980
- "> \u2705 Merged autonomously after Pullfrog approved this PR and resolved all of its own review threads."
165981
- )
165982
- }).catch((err) => log.debug(`autoMerge comment failed: ${err}`));
165983
166126
  }
165984
166127
 
165985
166128
  // utils/reviewCleanup.ts
@@ -167764,8 +167907,122 @@ async function run2() {
167764
167907
  }
167765
167908
  }
167766
167909
 
167910
+ // commands/watch.ts
167911
+ var import_arg4 = __toESM(require_arg(), 1);
167912
+ var import_picocolors4 = __toESM(require_picocolors(), 1);
167913
+ var REQUEST_TIMEOUT_MS = 35e3;
167914
+ function parseWatchArgs(args2) {
167915
+ return (0, import_arg4.default)(
167916
+ {
167917
+ "--pr": Number,
167918
+ "--pretty": Boolean,
167919
+ "--since": String,
167920
+ "--help": Boolean,
167921
+ "-h": "--help",
167922
+ "-p": "--pretty"
167923
+ },
167924
+ { argv: args2 }
167925
+ );
167926
+ }
167927
+ function printUsage(prog, stream) {
167928
+ stream(`usage: ${prog} watch [<owner>/<repo>] --pr <number> [options]
167929
+ `);
167930
+ stream("subscribe to a PR's activity and print one JSON line per event.\n");
167931
+ stream("arguments:");
167932
+ stream(" <owner>/<repo> target repo (defaults to the current git remote)");
167933
+ stream("");
167934
+ stream("options:");
167935
+ stream(" --pr <number> pull request number to watch (required)");
167936
+ stream(" --since <cursor> resume from a cursor emitted by a prior event");
167937
+ stream(" -p, --pretty human-readable output instead of JSON lines");
167938
+ stream(" -h, --help show help");
167939
+ }
167940
+ function resolveRepo(positional) {
167941
+ if (!positional) return parseGitRemote();
167942
+ const match3 = positional.match(/^([^/\s]+)\/([^/\s]+)$/);
167943
+ if (!match3) bail(`invalid repo "${positional}" \u2014 expected <owner>/<repo>`);
167944
+ return { owner: match3[1], repo: match3[2] };
167945
+ }
167946
+ async function pollOnce(ctx) {
167947
+ const params = new URLSearchParams({
167948
+ owner: ctx.owner,
167949
+ repo: ctx.repo,
167950
+ pr: String(ctx.pr)
167951
+ });
167952
+ if (ctx.cursor !== void 0) params.set("since", ctx.cursor);
167953
+ const controller = new AbortController();
167954
+ const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
167955
+ try {
167956
+ const response = await fetch(`${PULLFROG_API_URL}/api/cli/pr-events?${params}`, {
167957
+ headers: { authorization: `Bearer ${ctx.token}` },
167958
+ signal: controller.signal
167959
+ });
167960
+ if (response.status === 401 || response.status === 403) {
167961
+ bail("invalid or expired github token \u2014 run `gh auth login`.");
167962
+ }
167963
+ if (response.status === 404) {
167964
+ bail(`repository ${ctx.owner}/${ctx.repo} not found or Pullfrog not installed on it.`);
167965
+ }
167966
+ if (!response.ok) {
167967
+ throw new Error(`pr-events returned ${response.status}`);
167968
+ }
167969
+ return await response.json();
167970
+ } finally {
167971
+ clearTimeout(timeout);
167972
+ }
167973
+ }
167974
+ function formatPretty(event) {
167975
+ const time4 = new Date(event.createdAt).toLocaleTimeString();
167976
+ const action = typeof event.data.action === "string" ? event.data.action : "";
167977
+ const actor = typeof event.data.author === "string" ? event.data.author : typeof event.data.reviewer === "string" ? event.data.reviewer : "";
167978
+ const detail = [action, actor && import_picocolors4.default.dim(`by ${actor}`)].filter(Boolean).join(" ");
167979
+ return `${import_picocolors4.default.dim(time4)} ${import_picocolors4.default.cyan(event.kind)} ${import_picocolors4.default.bold(`#${event.pr}`)} ${detail}`.trimEnd();
167980
+ }
167981
+ async function runCli4(input) {
167982
+ let parsed2;
167983
+ try {
167984
+ parsed2 = parseWatchArgs(input.args);
167985
+ } catch (error49) {
167986
+ console.error(`${error49 instanceof Error ? error49.message : String(error49)}
167987
+ `);
167988
+ printUsage(input.prog, console.error);
167989
+ process.exit(1);
167990
+ }
167991
+ if (input.showHelp || parsed2["--help"]) {
167992
+ printUsage(input.prog, console.log);
167993
+ process.exit(0);
167994
+ }
167995
+ const target = resolveRepo(parsed2._[0]);
167996
+ const pr = parsed2["--pr"];
167997
+ if (pr === void 0 || !Number.isInteger(pr) || pr <= 0) {
167998
+ bail("--pr <number> is required");
167999
+ }
168000
+ const token = getGhToken();
168001
+ const pretty = parsed2["--pretty"] === true;
168002
+ let cursor = parsed2["--since"];
168003
+ const poll = op(pollOnce, {
168004
+ name: "pr-events poll",
168005
+ retries: [1e3, 2e3, 5e3, 1e4, 15e3]
168006
+ });
168007
+ for (; ; ) {
168008
+ try {
168009
+ const result = await poll({ owner: target.owner, repo: target.repo, pr, token, cursor });
168010
+ cursor = result.cursor;
168011
+ for (const event of result.events) {
168012
+ process.stdout.write(pretty ? `${formatPretty(event)}
168013
+ ` : `${JSON.stringify(event)}
168014
+ `);
168015
+ }
168016
+ } catch (error49) {
168017
+ const message = error49 instanceof Error ? error49.message : String(error49);
168018
+ console.error(import_picocolors4.default.dim(`watch: ${message} \u2014 retrying in 30s`));
168019
+ await new Promise((resolve3) => setTimeout(resolve3, 3e4));
168020
+ }
168021
+ }
168022
+ }
168023
+
167767
168024
  // cli.ts
167768
- var VERSION10 = "0.1.33";
168025
+ var VERSION10 = "0.1.34";
167769
168026
  var bin = basename2(process.argv[1] || "");
167770
168027
  var PROG = bin === "pf" || bin === "pullfrog" ? bin : "pullfrog";
167771
168028
  var rawArgs = process.argv.slice(2);
@@ -167775,13 +168032,14 @@ function printMainUsage(stream) {
167775
168032
  stream("commands:");
167776
168033
  stream(" init set up pullfrog on the current repository");
167777
168034
  stream(" auth manage provider credentials for the current repository");
168035
+ stream(" watch stream a PR's activity as one JSON line per event");
167778
168036
  stream("");
167779
168037
  stream("global options:");
167780
168038
  stream(" -h, --help show help");
167781
168039
  stream(" -v, --version show version");
167782
168040
  }
167783
168041
  function parseGlobalArgs(args2) {
167784
- return (0, import_arg4.default)(
168042
+ return (0, import_arg5.default)(
167785
168043
  {
167786
168044
  "--help": Boolean,
167787
168045
  "--version": Boolean,
@@ -167816,7 +168074,7 @@ async function run3() {
167816
168074
  const commandArgs = globalParsed._.slice(1);
167817
168075
  if (!command) {
167818
168076
  if (globalParsed["--help"]) {
167819
- console.log(`${import_picocolors4.default.bold("pullfrog")} v${VERSION10}
168077
+ console.log(`${import_picocolors5.default.bold("pullfrog")} v${VERSION10}
167820
168078
  `);
167821
168079
  printMainUsage(console.log);
167822
168080
  process.exit(0);
@@ -167848,11 +168106,19 @@ async function run3() {
167848
168106
  });
167849
168107
  return;
167850
168108
  }
168109
+ if (command === "watch") {
168110
+ await runCli4({
168111
+ args: commandArgs,
168112
+ prog: PROG,
168113
+ showHelp: globalParsed["--help"] === true
168114
+ });
168115
+ return;
168116
+ }
167851
168117
  if (globalParsed["--help"]) {
167852
168118
  printMainUsage(console.log);
167853
168119
  process.exit(0);
167854
168120
  }
167855
- console.error(`unknown command: ${import_picocolors4.default.bold(command)}
168121
+ console.error(`unknown command: ${import_picocolors5.default.bold(command)}
167856
168122
  `);
167857
168123
  printMainUsage(console.error);
167858
168124
  process.exit(1);
@@ -167861,7 +168127,7 @@ try {
167861
168127
  await run3();
167862
168128
  } catch (error49) {
167863
168129
  const message = error49 instanceof Error ? error49.message : String(error49);
167864
- console.error(import_picocolors4.default.red(message));
168130
+ console.error(import_picocolors5.default.red(message));
167865
168131
  process.exit(1);
167866
168132
  }
167867
168133
  /*! Bundled license information: