@neriros/ralphy 2.23.1 → 2.23.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -21
- package/dist/cli/index.js +95 -23
- package/dist/mcp/index.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -240,14 +240,15 @@ Done issues whose PR `gh pr view --json mergeable` reports as `CONFLICTING` get
|
|
|
240
240
|
|
|
241
241
|
### PR + CI integration
|
|
242
242
|
|
|
243
|
-
| Flag / config
|
|
244
|
-
|
|
|
245
|
-
| `createPrOnSuccess` / `--create-pr`
|
|
246
|
-
| `
|
|
247
|
-
| `
|
|
248
|
-
| `
|
|
249
|
-
| `
|
|
250
|
-
| `
|
|
243
|
+
| Flag / config | Behavior |
|
|
244
|
+
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
245
|
+
| `createPrOnSuccess` / `--create-pr` | After a clean exit, push the worker's branch and `gh pr create`. Title: `<ID>: <title>`. Idempotent — surfaces the existing URL if the PR is already open. Requires `--worktree` and `gh` authenticated. `prBaseBranch` defaults to `main`; override per-issue by labelling the Linear issue with `ralph:branch:<branch-name>`. |
|
|
246
|
+
| `stackPrsOnDependencies` / `--stack-prs` | When the Linear issue is blocked by another issue (`blocked_by` relation) that has exactly one open GitHub PR, open this PR against that blocker's head branch instead of `prBaseBranch`. Resolves the blocker's PR via Linear's auto-attachment + `gh pr view --json state,headRefName`. Falls back to `prBaseBranch` when zero / multiple blockers (or PRs) match. A `ralph:branch:<name>` label still wins. |
|
|
247
|
+
| `getAutoMerge` indicator | Opt an issue in for GitHub auto-merge (any-of label/status filter, same shape as `getReview`). When matched, Ralph runs `gh pr merge <url> --auto --<strategy>` right after opening the PR so GitHub merges as soon as required checks pass. Strategy comes from `autoMergeStrategy` (`squash` \| `merge` \| `rebase`, default `squash`). Failures are logged but non-fatal — the CI/conflict watch loop continues. |
|
|
248
|
+
| `fixCiOnFailure` / `--fix-ci` | After the PR opens, poll `gh pr checks`. On failure, pull failed logs via `gh run view --log-failed`, append them to `## Steering`, re-spawn the worker, and push the new commits — repeat until green or `maxCiFixAttempts` (default `5`) is hit. While this loop runs, `setDone` is **not** applied; if CI is never green the worker is treated as failed. |
|
|
249
|
+
| `ciPollIntervalSeconds` | Seconds between CI status polls (default `30`). |
|
|
250
|
+
| `ignoreCiChecks` | Array of check names to ignore when computing pass/fail. |
|
|
251
|
+
| `codeReviewTrigger` / `--code-review` | See [Code-review iteration](#code-review-iteration). |
|
|
251
252
|
|
|
252
253
|
### Worktrees, setup, teardown
|
|
253
254
|
|
|
@@ -302,19 +303,20 @@ Failed workers are not marked processed, so they retry on the next poll. SIGINT
|
|
|
302
303
|
|
|
303
304
|
**Agent-mode flags**
|
|
304
305
|
|
|
305
|
-
| Option | Behavior
|
|
306
|
-
| ------------------------- |
|
|
307
|
-
| `--linear-team <key>` | Linear team key (e.g. `ENG`)
|
|
308
|
-
| `--linear-assignee <id>` | Assignee filter (user id, email, or `me`)
|
|
309
|
-
| `--poll-interval <s>` | Seconds between Linear polls (default `60`)
|
|
310
|
-
| `--concurrency <n>` | Max concurrent task loops (default `1`)
|
|
311
|
-
| `--max-tickets <n>` | Stop picking up new issues after N have been started this run (`0` = unlimited)
|
|
312
|
-
| `--worktree` | Run each task in its own git worktree
|
|
313
|
-
| `--indicator <k>:<t>:<v>` | Override one `linear.indicators` entry (repeatable, e.g. `setDone:status:Done`)
|
|
314
|
-
| `--create-pr` | Push worker branch + open a GitHub PR on success (needs `--worktree`)
|
|
315
|
-
| `--fix-ci` | After PR opens, re-run task on CI failures until green (needs `--create-pr`)
|
|
316
|
-
| `--
|
|
317
|
-
| `--
|
|
306
|
+
| Option | Behavior |
|
|
307
|
+
| ------------------------- | -------------------------------------------------------------------------------------------- |
|
|
308
|
+
| `--linear-team <key>` | Linear team key (e.g. `ENG`) |
|
|
309
|
+
| `--linear-assignee <id>` | Assignee filter (user id, email, or `me`) |
|
|
310
|
+
| `--poll-interval <s>` | Seconds between Linear polls (default `60`) |
|
|
311
|
+
| `--concurrency <n>` | Max concurrent task loops (default `1`) |
|
|
312
|
+
| `--max-tickets <n>` | Stop picking up new issues after N have been started this run (`0` = unlimited) |
|
|
313
|
+
| `--worktree` | Run each task in its own git worktree |
|
|
314
|
+
| `--indicator <k>:<t>:<v>` | Override one `linear.indicators` entry (repeatable, e.g. `setDone:status:Done`) |
|
|
315
|
+
| `--create-pr` | Push worker branch + open a GitHub PR on success (needs `--worktree`) |
|
|
316
|
+
| `--fix-ci` | After PR opens, re-run task on CI failures until green (needs `--create-pr`) |
|
|
317
|
+
| `--stack-prs` | Open the PR against a blocker issue's open-PR head branch when present (needs `--create-pr`) |
|
|
318
|
+
| `--code-review` | Watch open tracked PRs for unresolved review comments and prepend a code-review task |
|
|
319
|
+
| `--json-output` | Emit JSONL to stdout instead of rendering the Ink dashboard (CI / scripting) |
|
|
318
320
|
|
|
319
321
|
**List-mode flags**
|
|
320
322
|
|
package/dist/cli/index.js
CHANGED
|
@@ -9553,7 +9553,7 @@ Learn more about this warning here: https://reactjs.org/link/legacy-context`, so
|
|
|
9553
9553
|
|
|
9554
9554
|
` + ("" + errorBoundaryMessage);
|
|
9555
9555
|
console["error"](combinedMessage);
|
|
9556
|
-
}
|
|
9556
|
+
}
|
|
9557
9557
|
} catch (e) {
|
|
9558
9558
|
setTimeout(function() {
|
|
9559
9559
|
throw e;
|
|
@@ -18037,7 +18037,7 @@ var require_backend = __commonJS((exports, module) => {
|
|
|
18037
18037
|
987: (module2, __unused_webpack_exports, __webpack_require__2) => {
|
|
18038
18038
|
if (true) {
|
|
18039
18039
|
module2.exports = __webpack_require__2(786);
|
|
18040
|
-
}
|
|
18040
|
+
}
|
|
18041
18041
|
},
|
|
18042
18042
|
126: (__unused_webpack_module, exports2, __webpack_require__2) => {
|
|
18043
18043
|
var process3 = __webpack_require__2(169);
|
|
@@ -18487,7 +18487,7 @@ var require_backend = __commonJS((exports, module) => {
|
|
|
18487
18487
|
189: (module2, __unused_webpack_exports, __webpack_require__2) => {
|
|
18488
18488
|
if (true) {
|
|
18489
18489
|
module2.exports = __webpack_require__2(126);
|
|
18490
|
-
}
|
|
18490
|
+
}
|
|
18491
18491
|
},
|
|
18492
18492
|
206: function(module2, exports2, __webpack_require__2) {
|
|
18493
18493
|
var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;
|
|
@@ -18502,7 +18502,7 @@ var require_backend = __commonJS((exports, module) => {
|
|
|
18502
18502
|
(function(root, factory) {
|
|
18503
18503
|
if (true) {
|
|
18504
18504
|
__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__2(430)], __WEBPACK_AMD_DEFINE_FACTORY__ = factory, __WEBPACK_AMD_DEFINE_RESULT__ = typeof __WEBPACK_AMD_DEFINE_FACTORY__ === "function" ? __WEBPACK_AMD_DEFINE_FACTORY__.apply(exports2, __WEBPACK_AMD_DEFINE_ARRAY__) : __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module2.exports = __WEBPACK_AMD_DEFINE_RESULT__);
|
|
18505
|
-
}
|
|
18505
|
+
}
|
|
18506
18506
|
})(this, function ErrorStackParser(StackFrame) {
|
|
18507
18507
|
var FIREFOX_SAFARI_STACK_REGEXP = /(^|@)\S+:\d+/;
|
|
18508
18508
|
var CHROME_IE_STACK_REGEXP = /^\s*at .*(\S+:\d+|\(native\))/m;
|
|
@@ -19198,7 +19198,7 @@ var require_backend = __commonJS((exports, module) => {
|
|
|
19198
19198
|
(function(root, factory) {
|
|
19199
19199
|
if (true) {
|
|
19200
19200
|
__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = factory, __WEBPACK_AMD_DEFINE_RESULT__ = typeof __WEBPACK_AMD_DEFINE_FACTORY__ === "function" ? __WEBPACK_AMD_DEFINE_FACTORY__.apply(exports2, __WEBPACK_AMD_DEFINE_ARRAY__) : __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module2.exports = __WEBPACK_AMD_DEFINE_RESULT__);
|
|
19201
|
-
}
|
|
19201
|
+
}
|
|
19202
19202
|
})(this, function() {
|
|
19203
19203
|
function _isNumber(n) {
|
|
19204
19204
|
return !isNaN(parseFloat(n)) && isFinite(n);
|
|
@@ -24572,7 +24572,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
|
|
|
24572
24572
|
var suffix = "";
|
|
24573
24573
|
if (true) {
|
|
24574
24574
|
suffix = " (<anonymous>)";
|
|
24575
|
-
}
|
|
24575
|
+
}
|
|
24576
24576
|
return `
|
|
24577
24577
|
` + prefix + name + suffix;
|
|
24578
24578
|
}
|
|
@@ -27301,7 +27301,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
|
|
|
27301
27301
|
hasChanges = true;
|
|
27302
27302
|
updateMostRecentlyInspectedElementIfNecessary(devtoolsInstance.id);
|
|
27303
27303
|
}
|
|
27304
|
-
}
|
|
27304
|
+
}
|
|
27305
27305
|
}
|
|
27306
27306
|
} catch (err) {
|
|
27307
27307
|
_iterator2.e(err);
|
|
@@ -29080,7 +29080,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
|
|
|
29080
29080
|
if (contentFiber === null) {
|
|
29081
29081
|
throw new Error("There should always be an Offscreen Fiber child in a hydrated Suspense boundary.");
|
|
29082
29082
|
}
|
|
29083
|
-
}
|
|
29083
|
+
}
|
|
29084
29084
|
var _isTimedOut = fiber.memoizedState !== null;
|
|
29085
29085
|
if (!_isTimedOut) {
|
|
29086
29086
|
newSuspenseNode.rects = measureInstance(newInstance);
|
|
@@ -29114,7 +29114,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
|
|
|
29114
29114
|
if (_contentFiber === null) {
|
|
29115
29115
|
throw new Error("There should always be an Offscreen Fiber child in a hydrated Suspense boundary.");
|
|
29116
29116
|
}
|
|
29117
|
-
}
|
|
29117
|
+
}
|
|
29118
29118
|
var suspenseState = fiber.memoizedState;
|
|
29119
29119
|
var _isTimedOut3 = suspenseState !== null;
|
|
29120
29120
|
if (!_isTimedOut3) {
|
|
@@ -29214,7 +29214,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
|
|
|
29214
29214
|
trackThrownPromisesFromRetryCache(newSuspenseNode, fiber.stateNode);
|
|
29215
29215
|
mountSuspenseChildrenRecursively(_contentFiber2, traceNearestHostComponentUpdate, stashedSuspenseParent, stashedSuspensePrevious, stashedSuspenseRemaining);
|
|
29216
29216
|
shouldPopSuspenseNode = false;
|
|
29217
|
-
}
|
|
29217
|
+
}
|
|
29218
29218
|
} else {
|
|
29219
29219
|
if (fiber.child !== null) {
|
|
29220
29220
|
mountChildrenRecursively(fiber.child, traceNearestHostComponentUpdate);
|
|
@@ -29800,7 +29800,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
|
|
|
29800
29800
|
shouldPopSuspenseNode = false;
|
|
29801
29801
|
} else if (previousHydrated && !nextHydrated) {
|
|
29802
29802
|
throw new Error("Encountered a dehydrated Suspense boundary that was previously hydrated.");
|
|
29803
|
-
}
|
|
29803
|
+
}
|
|
29804
29804
|
} else {
|
|
29805
29805
|
if (nextFiber.child !== prevFiber.child) {
|
|
29806
29806
|
updateFlags |= updateChildrenRecursively(nextFiber.child, prevFiber.child, traceNearestHostComponentUpdate);
|
|
@@ -29846,8 +29846,8 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
|
|
|
29846
29846
|
recordResetChildren(fiberInstance);
|
|
29847
29847
|
}
|
|
29848
29848
|
updateFlags &= ~ShouldResetChildren;
|
|
29849
|
-
}
|
|
29850
|
-
}
|
|
29849
|
+
}
|
|
29850
|
+
}
|
|
29851
29851
|
if ((updateFlags & ShouldResetSuspenseChildren) !== NoUpdate) {
|
|
29852
29852
|
if (fiberInstance !== null && fiberInstance.kind === FIBER_INSTANCE) {
|
|
29853
29853
|
var _suspenseNode3 = fiberInstance.suspenseNode;
|
|
@@ -29855,7 +29855,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
|
|
|
29855
29855
|
recordResetSuspenseChildren(_suspenseNode3);
|
|
29856
29856
|
updateFlags &= ~ShouldResetSuspenseChildren;
|
|
29857
29857
|
}
|
|
29858
|
-
}
|
|
29858
|
+
}
|
|
29859
29859
|
}
|
|
29860
29860
|
if ((updateFlags & ShouldResetParentSuspenseChildren) !== NoUpdate) {
|
|
29861
29861
|
if (fiberInstance !== null && fiberInstance.kind === FIBER_INSTANCE) {
|
|
@@ -29864,7 +29864,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
|
|
|
29864
29864
|
updateFlags &= ~ShouldResetParentSuspenseChildren;
|
|
29865
29865
|
updateFlags |= ShouldResetSuspenseChildren;
|
|
29866
29866
|
}
|
|
29867
|
-
}
|
|
29867
|
+
}
|
|
29868
29868
|
}
|
|
29869
29869
|
return updateFlags;
|
|
29870
29870
|
} finally {
|
|
@@ -32928,7 +32928,7 @@ The error thrown in the component is:
|
|
|
32928
32928
|
rendererInterface = renderer_attach(hook, id, renderer, global2, shouldStartProfilingNow, profilingSettings);
|
|
32929
32929
|
} else if (renderer.ComponentTree) {
|
|
32930
32930
|
rendererInterface = legacy_renderer_attach(hook, id, renderer, global2);
|
|
32931
|
-
}
|
|
32931
|
+
}
|
|
32932
32932
|
}
|
|
32933
32933
|
return rendererInterface;
|
|
32934
32934
|
}
|
|
@@ -35029,8 +35029,8 @@ import { readFileSync as readFileSync2 } from "fs";
|
|
|
35029
35029
|
import { resolve } from "path";
|
|
35030
35030
|
function getVersion() {
|
|
35031
35031
|
try {
|
|
35032
|
-
if ("2.23.
|
|
35033
|
-
return "2.23.
|
|
35032
|
+
if ("2.23.2")
|
|
35033
|
+
return "2.23.2";
|
|
35034
35034
|
} catch {}
|
|
35035
35035
|
const dirsToTry = [];
|
|
35036
35036
|
try {
|
|
@@ -35124,6 +35124,7 @@ async function parseArgs(argv) {
|
|
|
35124
35124
|
indicators: {},
|
|
35125
35125
|
createPr: false,
|
|
35126
35126
|
fixCi: false,
|
|
35127
|
+
stackPrs: false,
|
|
35127
35128
|
codeReview: false,
|
|
35128
35129
|
maxTickets: 0,
|
|
35129
35130
|
projectRoot: undefined,
|
|
@@ -35319,6 +35320,9 @@ async function parseArgs(argv) {
|
|
|
35319
35320
|
case "--fix-ci":
|
|
35320
35321
|
result2.fixCi = true;
|
|
35321
35322
|
break;
|
|
35323
|
+
case "--stack-prs":
|
|
35324
|
+
result2.stackPrs = true;
|
|
35325
|
+
break;
|
|
35322
35326
|
case "--code-review":
|
|
35323
35327
|
result2.codeReview = true;
|
|
35324
35328
|
break;
|
|
@@ -35423,6 +35427,7 @@ var init_cli = __esm(() => {
|
|
|
35423
35427
|
" (attachment upserts a single 'Ralphy' entry; value = subtitle)",
|
|
35424
35428
|
" --create-pr Push the worker branch and open a GitHub PR on success (needs --worktree)",
|
|
35425
35429
|
" --fix-ci After opening the PR, re-run on CI failures until green (needs --create-pr)",
|
|
35430
|
+
" --stack-prs Base the PR on a blocker issue's open-PR head branch when present (needs --create-pr)",
|
|
35426
35431
|
" --code-review Watch open tracked PRs for unresolved review comments and prepend a code-review task",
|
|
35427
35432
|
" --max-tickets <n> Stop picking up new issues after N have been started (0 = unlimited)",
|
|
35428
35433
|
" --json-output Emit JSONL to stdout instead of the Ink dashboard (for scripting/CI)",
|
|
@@ -59526,6 +59531,12 @@ var MarkerSchema, GetIndicatorSchema, SetIndicatorSchema, IndicatorsSchema, Ralp
|
|
|
59526
59531
|
// Linear issue with "ralph:branch:<branch-name>".
|
|
59527
59532
|
"prBaseBranch": "main",
|
|
59528
59533
|
|
|
59534
|
+
// When true, if the Linear issue is blocked by another issue whose
|
|
59535
|
+
// single open GitHub PR can be resolved (via Linear's auto-attachment),
|
|
59536
|
+
// open this PR against that blocker's head branch instead of prBaseBranch.
|
|
59537
|
+
// A "ralph:branch:<name>" label on the issue still wins over this.
|
|
59538
|
+
"stackPrsOnDependencies": false,
|
|
59539
|
+
|
|
59529
59540
|
// Merge strategy used when GitHub auto-merge is enabled (see getAutoMerge
|
|
59530
59541
|
// indicator below). One of "squash", "merge", "rebase".
|
|
59531
59542
|
"autoMergeStrategy": "squash",
|
|
@@ -59679,6 +59690,7 @@ var init_config = __esm(() => {
|
|
|
59679
59690
|
appendPrompt: exports_external.string().optional(),
|
|
59680
59691
|
createPrOnSuccess: exports_external.boolean().default(false),
|
|
59681
59692
|
prBaseBranch: exports_external.string().default("main"),
|
|
59693
|
+
stackPrsOnDependencies: exports_external.boolean().default(false),
|
|
59682
59694
|
autoMergeStrategy: exports_external.enum(["squash", "merge", "rebase"]).default("squash"),
|
|
59683
59695
|
fixCiOnFailure: exports_external.boolean().default(false),
|
|
59684
59696
|
maxCiFixAttempts: exports_external.number().int().positive().default(5),
|
|
@@ -61155,15 +61167,33 @@ async function runPrPhase(input, deps) {
|
|
|
61155
61167
|
wantAutoMerge,
|
|
61156
61168
|
cfg
|
|
61157
61169
|
} = input;
|
|
61158
|
-
const {
|
|
61170
|
+
const {
|
|
61171
|
+
cmd,
|
|
61172
|
+
log: log2,
|
|
61173
|
+
emit,
|
|
61174
|
+
respawnWorker,
|
|
61175
|
+
registerPr,
|
|
61176
|
+
checkPrConflict,
|
|
61177
|
+
resolveDependencyBaseBranch
|
|
61178
|
+
} = deps;
|
|
61159
61179
|
if (!branch || !issue) {
|
|
61160
61180
|
log2(`! createPr requested but no worktree branch is tracked for ${changeName} (use --worktree)`, "yellow");
|
|
61161
61181
|
return PR_FAILED_EXIT;
|
|
61162
61182
|
}
|
|
61163
61183
|
const labelBase = baseBranchFromLabels(issue.labels);
|
|
61164
|
-
|
|
61184
|
+
let base2 = labelBase ?? cfg.prBaseBranch;
|
|
61165
61185
|
if (labelBase && labelBase !== cfg.prBaseBranch) {
|
|
61166
61186
|
log2(` base branch override from label: ${labelBase}`, "gray");
|
|
61187
|
+
} else if (cfg.stackPrsOnDependencies && resolveDependencyBaseBranch) {
|
|
61188
|
+
try {
|
|
61189
|
+
const dependencyBase = await resolveDependencyBaseBranch(issue);
|
|
61190
|
+
if (dependencyBase && dependencyBase !== base2) {
|
|
61191
|
+
log2(` base branch override from blocker PR: ${dependencyBase}`, "gray");
|
|
61192
|
+
base2 = dependencyBase;
|
|
61193
|
+
}
|
|
61194
|
+
} catch (err) {
|
|
61195
|
+
log2(`! could not resolve dependency base branch for ${issue.identifier}: ${err.message}`, "yellow");
|
|
61196
|
+
}
|
|
61167
61197
|
}
|
|
61168
61198
|
const ctx = {
|
|
61169
61199
|
changeName,
|
|
@@ -61291,7 +61321,8 @@ async function runPostTask(input, deps) {
|
|
|
61291
61321
|
emit,
|
|
61292
61322
|
respawnWorker,
|
|
61293
61323
|
...deps.registerPr !== undefined ? { registerPr: deps.registerPr } : {},
|
|
61294
|
-
...deps.checkPrConflict !== undefined ? { checkPrConflict: deps.checkPrConflict } : {}
|
|
61324
|
+
...deps.checkPrConflict !== undefined ? { checkPrConflict: deps.checkPrConflict } : {},
|
|
61325
|
+
...deps.resolveDependencyBaseBranch !== undefined ? { resolveDependencyBaseBranch: deps.resolveDependencyBaseBranch } : {}
|
|
61295
61326
|
});
|
|
61296
61327
|
}
|
|
61297
61328
|
emit(effectiveCode === 0 ? "done" : "gave-up", effectiveCode !== 0 ? `exit ${effectiveCode}` : undefined);
|
|
@@ -61839,7 +61870,8 @@ PR: ${prUrl}` : ""
|
|
|
61839
61870
|
maxCiFixAttempts: cfg.maxCiFixAttempts,
|
|
61840
61871
|
ciPollIntervalSeconds: cfg.ciPollIntervalSeconds,
|
|
61841
61872
|
cleanupWorktreeOnSuccess: cfg.cleanupWorktreeOnSuccess,
|
|
61842
|
-
ignoreCiChecks: cfg.ignoreCiChecks
|
|
61873
|
+
ignoreCiChecks: cfg.ignoreCiChecks,
|
|
61874
|
+
stackPrsOnDependencies: args.stackPrs || cfg.stackPrsOnDependencies
|
|
61843
61875
|
},
|
|
61844
61876
|
respawnWorker: respawn
|
|
61845
61877
|
}, {
|
|
@@ -61868,7 +61900,8 @@ PR: ${prUrl}` : ""
|
|
|
61868
61900
|
await new Promise((r) => setTimeout(r, 2000));
|
|
61869
61901
|
}
|
|
61870
61902
|
return false;
|
|
61871
|
-
}
|
|
61903
|
+
},
|
|
61904
|
+
resolveDependencyBaseBranch: (issue) => resolveDependencyBaseBranch(issue, tracedCmd, cwd2)
|
|
61872
61905
|
});
|
|
61873
61906
|
cwdByChange.delete(changeName);
|
|
61874
61907
|
statesDirByChange.delete(changeName);
|
|
@@ -61956,6 +61989,45 @@ PR: ${prUrl}` : ""
|
|
|
61956
61989
|
markPrUnavailable(changeName);
|
|
61957
61990
|
return null;
|
|
61958
61991
|
}
|
|
61992
|
+
async function resolveDependencyBaseBranch(issue, runner, runnerCwd) {
|
|
61993
|
+
const blockerIds = issue.blockedByIds;
|
|
61994
|
+
if (blockerIds.length === 0)
|
|
61995
|
+
return null;
|
|
61996
|
+
const candidates = [];
|
|
61997
|
+
for (const blockerId of blockerIds) {
|
|
61998
|
+
let attachments;
|
|
61999
|
+
try {
|
|
62000
|
+
attachments = await fetchIssueAttachments(apiKey, blockerId);
|
|
62001
|
+
} catch (err) {
|
|
62002
|
+
onLog(`! could not fetch attachments for blocker ${blockerId} of ${issue.identifier}: ${err.message}`, "yellow");
|
|
62003
|
+
continue;
|
|
62004
|
+
}
|
|
62005
|
+
const prUrls = attachments.map((a) => a.url).filter((url) => /^https:\/\/github\.com\/[^/]+\/[^/]+\/pull\/\d+/.test(url));
|
|
62006
|
+
const openHeads = [];
|
|
62007
|
+
for (const url of prUrls) {
|
|
62008
|
+
try {
|
|
62009
|
+
const res = await runner.run(["gh", "pr", "view", url, "--json", "state,headRefName", "--jq", "."], runnerCwd);
|
|
62010
|
+
const parsed = JSON.parse(res.stdout.trim());
|
|
62011
|
+
if (parsed.state === "OPEN" && parsed.headRefName) {
|
|
62012
|
+
openHeads.push(parsed.headRefName);
|
|
62013
|
+
}
|
|
62014
|
+
} catch (err) {
|
|
62015
|
+
onLog(`! gh pr view failed for ${url} (blocker of ${issue.identifier}): ${err.message}`, "yellow");
|
|
62016
|
+
}
|
|
62017
|
+
}
|
|
62018
|
+
if (openHeads.length === 1) {
|
|
62019
|
+
candidates.push(openHeads[0]);
|
|
62020
|
+
} else if (openHeads.length > 1) {
|
|
62021
|
+
onLog(` ${issue.identifier}: blocker ${blockerId} has ${openHeads.length} open PRs \u2014 skipping dependency base resolution`, "gray");
|
|
62022
|
+
}
|
|
62023
|
+
}
|
|
62024
|
+
if (candidates.length === 1)
|
|
62025
|
+
return candidates[0];
|
|
62026
|
+
if (candidates.length > 1) {
|
|
62027
|
+
onLog(` ${issue.identifier}: ${candidates.length} blockers have open PRs \u2014 falling back to default base`, "gray");
|
|
62028
|
+
}
|
|
62029
|
+
return null;
|
|
62030
|
+
}
|
|
61959
62031
|
async function discoverPrUrlFromLinear(issue) {
|
|
61960
62032
|
try {
|
|
61961
62033
|
const attachments = await fetchIssueAttachments(apiKey, issue.id);
|
package/dist/mcp/index.js
CHANGED
|
@@ -14104,7 +14104,7 @@ function finalize(ctx, schema) {
|
|
|
14104
14104
|
result.$schema = "http://json-schema.org/draft-07/schema#";
|
|
14105
14105
|
} else if (ctx.target === "draft-04") {
|
|
14106
14106
|
result.$schema = "http://json-schema.org/draft-04/schema#";
|
|
14107
|
-
} else if (ctx.target === "openapi-3.0") {}
|
|
14107
|
+
} else if (ctx.target === "openapi-3.0") {}
|
|
14108
14108
|
if (ctx.external?.uri) {
|
|
14109
14109
|
const id = ctx.external.registry.get(schema)?.id;
|
|
14110
14110
|
if (!id)
|
|
@@ -14352,7 +14352,7 @@ var literalProcessor = (schema, ctx, json, _params) => {
|
|
|
14352
14352
|
if (val === undefined) {
|
|
14353
14353
|
if (ctx.unrepresentable === "throw") {
|
|
14354
14354
|
throw new Error("Literal `undefined` cannot be represented in JSON Schema");
|
|
14355
|
-
}
|
|
14355
|
+
}
|
|
14356
14356
|
} else if (typeof val === "bigint") {
|
|
14357
14357
|
if (ctx.unrepresentable === "throw") {
|
|
14358
14358
|
throw new Error("BigInt literals cannot be represented in JSON Schema");
|