mergestorm 0.3.44 → 0.3.46
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 +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.js +1 -1
- package/dist/stack-blockers.d.ts +2 -0
- package/dist/stack-blockers.js +33 -1
- package/dist/stack-dto.d.ts +5 -1
- package/dist/stack-dto.js +6 -3
- package/dist/ui/banner.js +6 -0
- package/package.json +1 -1
- package/skill/mergestorm-bounce-watch/SKILL.md +1 -1
package/README.md
CHANGED
|
@@ -45,7 +45,7 @@ On a TTY, bare `mergestorm` (or `mergestorm shell`) opens a branded REPL: a comp
|
|
|
45
45
|
|
|
46
46
|
```
|
|
47
47
|
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
48
|
-
│ ▀▀▀▀▀▀▀▀▀▀▘ mergestorm v0.3.
|
|
48
|
+
│ ▀▀▀▀▀▀▀▀▀▀▘ mergestorm v0.3.46 │
|
|
49
49
|
│ ▀▀▀▀▀▀▀▀▀ ● msk_live_… · maelstrom │
|
|
50
50
|
│ ▀▀▀▀▀▀ [████████░░░░░░░░░░░░░░░░░░░░░░] 25% used │
|
|
51
51
|
│ ▝▀▀▀▀▀ local reviews + stacked PRs · mergestorm.ai │
|
package/dist/client/index.d.ts
CHANGED
|
@@ -7,5 +7,5 @@ export { REVIEW_JOB_ENVELOPE_SCHEMA, toReviewJobEnvelope, type ReviewEnvelopeFal
|
|
|
7
7
|
export { discoverTrunk } from "../git-stack.js";
|
|
8
8
|
export { BOUNCE_KIND_LABELS, deriveStackAgentsBusy, mergeQueueBounceLabel, type StackAgentsBusy } from "../stack-dto.js";
|
|
9
9
|
export { STACK_WATCH_SCHEMA, STACK_WATCH_DEFAULT_TIMEOUT_MS, STACK_WATCH_BUSY_RECHECK_S, StackWatchError, StackWatchTimeoutError, pollStackWatch, type PollStackWatchOptions, type StackWatchCursor, type StackWatchEnvelope, } from "../stack-watch.js";
|
|
10
|
-
export { stackBlockers, stackBlockersSummary, sameHead, layerAgents, layerAgentsBusy, conflictLiveParent, stackRepair, agentsCannotClear, autoResolveActive, type StackAgentBusy, type StackBlocker, type StackBusyAgent, type StackHeldBlocker, type StackLandGatePending, type StackLayerAgents, type StackRepairHint, } from "../stack-blockers.js";
|
|
10
|
+
export { stackBlockers, stackBlockersSummary, sameHead, layerAgents, layerAgentsBusy, conflictLiveParent, stackRepair, agentsCannotClear, autoFixCiActive, autoResolveActive, type StackAgentBusy, type StackBlocker, type StackBusyAgent, type StackHeldBlocker, type StackLandGatePending, type StackLayerAgents, type StackRepairHint, } from "../stack-blockers.js";
|
|
11
11
|
export { STACK_WATCH_NOT_DONE_SENTENCE, STACK_WATCH_NOTIFY_PATTERN, stackWatchBackgroundCommand, stackTerminalReason, stackWatchNextArgs, stackWatchObligation, type StackWatchDoneReason, type StackWatchNext, type StackWatchNextArgs, type StackWatchObligation, type StackWatchObligationInput, type StackWatchReason, } from "../stack-watch-obligation.js";
|
package/dist/client/index.js
CHANGED
|
@@ -7,5 +7,5 @@ export { REVIEW_JOB_ENVELOPE_SCHEMA, toReviewJobEnvelope, } from "../ui/job-enve
|
|
|
7
7
|
export { discoverTrunk } from "../git-stack.js";
|
|
8
8
|
export { BOUNCE_KIND_LABELS, deriveStackAgentsBusy, mergeQueueBounceLabel } from "../stack-dto.js";
|
|
9
9
|
export { STACK_WATCH_SCHEMA, STACK_WATCH_DEFAULT_TIMEOUT_MS, STACK_WATCH_BUSY_RECHECK_S, StackWatchError, StackWatchTimeoutError, pollStackWatch, } from "../stack-watch.js";
|
|
10
|
-
export { stackBlockers, stackBlockersSummary, sameHead, layerAgents, layerAgentsBusy, conflictLiveParent, stackRepair, agentsCannotClear, autoResolveActive, } from "../stack-blockers.js";
|
|
10
|
+
export { stackBlockers, stackBlockersSummary, sameHead, layerAgents, layerAgentsBusy, conflictLiveParent, stackRepair, agentsCannotClear, autoFixCiActive, autoResolveActive, } from "../stack-blockers.js";
|
|
11
11
|
export { STACK_WATCH_NOT_DONE_SENTENCE, STACK_WATCH_NOTIFY_PATTERN, stackWatchBackgroundCommand, stackTerminalReason, stackWatchNextArgs, stackWatchObligation, } from "../stack-watch-obligation.js";
|
package/dist/stack-blockers.d.ts
CHANGED
|
@@ -52,6 +52,7 @@ export type StackRepairHint = {
|
|
|
52
52
|
branch: string;
|
|
53
53
|
failingCheck: string | null;
|
|
54
54
|
steps: string;
|
|
55
|
+
note?: string;
|
|
55
56
|
} | {
|
|
56
57
|
kind: "vortex_findings";
|
|
57
58
|
prNumber: number;
|
|
@@ -163,6 +164,7 @@ export declare const SEAM_REREVIEW_NOT_RUNNING = "Seam re-review pending, no rev
|
|
|
163
164
|
export declare const SEAM_VERDICT_STALE = "Seam verdict is for an older head, no review running";
|
|
164
165
|
export declare const VORTEX_FINDINGS_NEED_PERSON = "Vortex findings need a person";
|
|
165
166
|
export declare function autoResolveActive(stack: StackDto, layer: StackLayerDto): boolean;
|
|
167
|
+
export declare function autoFixCiActive(stack: StackDto, layer: StackLayerDto): boolean;
|
|
166
168
|
export declare const VORTEX_AUTO_REVIEW_OFF = "Vortex auto-review is off, so this head was not reviewed";
|
|
167
169
|
export declare const VORTEX_BILLING_SKIPPED = "Vortex skipped this head: it could not confirm billing";
|
|
168
170
|
export declare const VORTEX_REVIEW_INCOMPLETE = "Vortex reviewed only part of this PR";
|
package/dist/stack-blockers.js
CHANGED
|
@@ -91,6 +91,19 @@ const CYCLONE_HANDOFF_WORDS = {
|
|
|
91
91
|
auto_resolve_daily_cap: "Cyclone already resolved conflicts on this PR twice today, its daily cap",
|
|
92
92
|
stack_auto_resolve_off: "auto-resolve conflicts is off for this stack",
|
|
93
93
|
account_auto_resolve_off: "auto-resolve conflicts is off for the account and this stack does not turn it on",
|
|
94
|
+
ci_fix_did_not_hold: "CI still fails on Cyclone's own CI fix",
|
|
95
|
+
auto_fix_ci_daily_cap: "Cyclone already fixed CI on this PR twice today, its daily cap",
|
|
96
|
+
ci_billing_block: "GitHub Actions is blocked by billing, so no code change turns CI green",
|
|
97
|
+
ci_missing_secrets: "the failing job needs secrets its run does not have",
|
|
98
|
+
ci_red_on_base: "the same check also fails on the base branch",
|
|
99
|
+
ci_rerun_exhausted: "Cyclone already had Surge re-run this check once at this head",
|
|
100
|
+
ci_rerun_unavailable: "the failure looked flaky and Surge could not re-run it",
|
|
101
|
+
ci_unverified: "Cyclone could not confirm a fix locally, so it pushed nothing",
|
|
102
|
+
ci_unreadable: "Cyclone could not read the failing checks",
|
|
103
|
+
ci_needs_actions_read: "Cyclone's GitHub App cannot read the Actions logs on this repo",
|
|
104
|
+
ci_unresolved: "Cyclone's CI fix failed",
|
|
105
|
+
stack_auto_fix_ci_off: "auto-fix CI is off for this stack",
|
|
106
|
+
account_auto_fix_ci_off: "auto-fix CI is off for the account and this stack does not turn it on",
|
|
94
107
|
};
|
|
95
108
|
function cycloneHandoffWords(reason) {
|
|
96
109
|
return CYCLONE_HANDOFF_WORDS[reason] ?? reason.replaceAll("_", " ");
|
|
@@ -114,6 +127,22 @@ function conflictHandoffNote(stack, layer) {
|
|
|
114
127
|
}
|
|
115
128
|
return null;
|
|
116
129
|
}
|
|
130
|
+
export function autoFixCiActive(stack, layer) {
|
|
131
|
+
return !stack.cycloneCiOff && !isLandPrLayer(stack, layer) &&
|
|
132
|
+
!sameHead(layer.cycloneCiHandoff?.headSha, layer.headSha);
|
|
133
|
+
}
|
|
134
|
+
function ciHandoffNote(stack, layer) {
|
|
135
|
+
if (isLandPrLayer(stack, layer))
|
|
136
|
+
return null;
|
|
137
|
+
const handoff = layer.cycloneCiHandoff;
|
|
138
|
+
if (handoff && sameHead(handoff.headSha, layer.headSha)) {
|
|
139
|
+
return `Cyclone tried to fix this failing CI at ${layer.headSha ?? handoff.headSha} and left it for a person (${cycloneHandoffWords(handoff.reason)}), so it will not try this head again.`;
|
|
140
|
+
}
|
|
141
|
+
if (stack.cycloneCiOff) {
|
|
142
|
+
return `Cyclone will not fix this failing CI by itself: ${cycloneHandoffWords(stack.cycloneCiOff)}.`;
|
|
143
|
+
}
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
117
146
|
function vortexFindingsLeftForPerson(stack, layer) {
|
|
118
147
|
return vortexChangesRequestedAtHead(layer) && !layerAgentsBusy(layer).cyclone &&
|
|
119
148
|
cycloneHandoffAtHead(stack, layer) !== null;
|
|
@@ -139,7 +168,8 @@ const VORTEX_SKIP_BLOCKERS = {
|
|
|
139
168
|
};
|
|
140
169
|
export function vortexRetryScheduled(layer) {
|
|
141
170
|
const review = layer.vortexReview;
|
|
142
|
-
|
|
171
|
+
const reason = review?.skip_reason?.trim();
|
|
172
|
+
return (reason === "retry_scheduled" || reason === "post_delayed") && sameHead(review?.head_sha, layer.headSha);
|
|
143
173
|
}
|
|
144
174
|
function vortexIdleSkipBlocker(layer) {
|
|
145
175
|
if (layerAgentsBusy(layer).vortex)
|
|
@@ -743,6 +773,7 @@ export function stackRepair(stack, attention, layer, bounce, queueWait = null) {
|
|
|
743
773
|
}
|
|
744
774
|
if (reason === "ci_failed" || attention.bounceKind === "ci_failure") {
|
|
745
775
|
const failingCheck = bounce?.bounceDetail?.failingCheck?.trim() || layer.checks?.failingName?.trim() || null;
|
|
776
|
+
const note = ciHandoffNote(stack, layer);
|
|
746
777
|
return {
|
|
747
778
|
kind: "ci_failure",
|
|
748
779
|
prNumber: layer.prNumber,
|
|
@@ -750,6 +781,7 @@ export function stackRepair(stack, attention, layer, bounce, queueWait = null) {
|
|
|
750
781
|
branch: layer.branch,
|
|
751
782
|
failingCheck,
|
|
752
783
|
steps: `Read the failing ${failingCheck ? `check ${failingCheck}` : "checks"} on ${layer.branch} (gh run list --branch ${layer.branch}, then gh run view <run-id> --log-failed), fix it on ${layer.branch} with the smallest patch, run that check locally, confirm the remote head is still ${layer.headSha ?? "the head you started from"}, then an ordinary git push. Do not retarget the PR base.`,
|
|
784
|
+
...(note ? { note } : {}),
|
|
753
785
|
};
|
|
754
786
|
}
|
|
755
787
|
return null;
|
package/dist/stack-dto.d.ts
CHANGED
|
@@ -116,7 +116,7 @@ export type StackAgentsBusy = {
|
|
|
116
116
|
};
|
|
117
117
|
export declare const STACK_AGENT_QUEUED_STALE_MS: number;
|
|
118
118
|
export declare const AUTO_RESOLVE_ENQUEUE_GRACE_MS: number;
|
|
119
|
-
export declare function deriveStackAgentsBusy(layer: Pick<StackLayerDto, "headSha" | "vortexStatus" | "cycloneStatus" | "agentRuns" | "vortexReview" | "cycloneConflictPendingSince">, opts?: {
|
|
119
|
+
export declare function deriveStackAgentsBusy(layer: Pick<StackLayerDto, "headSha" | "vortexStatus" | "cycloneStatus" | "agentRuns" | "vortexReview" | "cycloneConflictPendingSince" | "cycloneCiPendingSince">, opts?: {
|
|
120
120
|
cycloneClaimed?: boolean;
|
|
121
121
|
nowMs?: number;
|
|
122
122
|
}): StackAgentsBusy;
|
|
@@ -215,6 +215,8 @@ export type StackLayerDto = {
|
|
|
215
215
|
cycloneHandoff?: StackCycloneHandoff | null;
|
|
216
216
|
cycloneConflictHandoff?: StackCycloneHandoff | null;
|
|
217
217
|
cycloneConflictPendingSince?: string | null;
|
|
218
|
+
cycloneCiHandoff?: StackCycloneHandoff | null;
|
|
219
|
+
cycloneCiPendingSince?: string | null;
|
|
218
220
|
conflictDetail: string | null;
|
|
219
221
|
restackError?: RestackError | null;
|
|
220
222
|
lastRestackedSha: string | null;
|
|
@@ -309,6 +311,7 @@ export type StackUnitDto = {
|
|
|
309
311
|
export type CycloneOwnerMatch = "same" | "different" | "none" | "lookup_failed";
|
|
310
312
|
export type CyclonePatchOffReason = "stack_auto_patch_off" | "account_auto_patch_off" | "cyclone_not_connected";
|
|
311
313
|
export type CycloneConflictOffReason = "stack_auto_resolve_off" | "account_auto_resolve_off" | "cyclone_not_connected";
|
|
314
|
+
export type CycloneCiOffReason = "stack_auto_fix_ci_off" | "account_auto_fix_ci_off" | "cyclone_not_connected";
|
|
312
315
|
export type StackDto = {
|
|
313
316
|
id: string;
|
|
314
317
|
owner: string;
|
|
@@ -389,6 +392,7 @@ export type StackDto = {
|
|
|
389
392
|
cycloneOwnerMatch?: CycloneOwnerMatch;
|
|
390
393
|
cyclonePatchOff?: CyclonePatchOffReason;
|
|
391
394
|
cycloneConflictOff?: CycloneConflictOffReason;
|
|
395
|
+
cycloneCiOff?: CycloneCiOffReason;
|
|
392
396
|
infrastructureInstallUserId?: string | null;
|
|
393
397
|
infrastructureOwnerMatch?: CycloneOwnerMatch;
|
|
394
398
|
layers: StackLayerDto[];
|
package/dist/stack-dto.js
CHANGED
|
@@ -48,12 +48,15 @@ export function deriveStackAgentsBusy(layer, opts = {}) {
|
|
|
48
48
|
vortexRuns.some((run) => run.status === "reviewing") ||
|
|
49
49
|
freshQueued ||
|
|
50
50
|
(layer.agentRuns === undefined && review === undefined && layer.vortexStatus === "reviewing");
|
|
51
|
-
const
|
|
52
|
-
|
|
51
|
+
const withinGrace = (since) => {
|
|
52
|
+
const sinceMs = Date.parse(since ?? "");
|
|
53
|
+
return Number.isFinite(sinceMs) && nowMs - sinceMs <= AUTO_RESOLVE_ENQUEUE_GRACE_MS;
|
|
54
|
+
};
|
|
53
55
|
const cyclone = opts.cycloneClaimed === true || layer.cycloneStatus === "patching" ||
|
|
54
56
|
runs.some((run) => run.agent === "cyclone" && run.status === "patching") ||
|
|
55
57
|
runs.some((run) => run.agent === "cyclone" && agentShaMayBeHead(run.sha, headSha) && queuedFresh(run)) ||
|
|
56
|
-
|
|
58
|
+
withinGrace(layer.cycloneConflictPendingSince) ||
|
|
59
|
+
withinGrace(layer.cycloneCiPendingSince);
|
|
57
60
|
return { vortex, cyclone, headSha };
|
|
58
61
|
}
|
|
59
62
|
/** Every bounce kind understood by the shared contract. */
|
package/dist/ui/banner.js
CHANGED
|
@@ -170,6 +170,12 @@ const WHATS_NEW = {
|
|
|
170
170
|
"0.3.44": [
|
|
171
171
|
"Cyclone can auto-resolve stack conflicts",
|
|
172
172
|
],
|
|
173
|
+
"0.3.45": [
|
|
174
|
+
"Cyclone can auto-fix red stack CI",
|
|
175
|
+
],
|
|
176
|
+
"0.3.46": [
|
|
177
|
+
"Watch waits while GitHub delays a review",
|
|
178
|
+
],
|
|
173
179
|
};
|
|
174
180
|
function densityFromVariant(variant) {
|
|
175
181
|
if (variant === "mini" || variant === "nano")
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@ Use only these shipped Mergestorm MCP tools: `stack_wait`, `stack_status`, `queu
|
|
|
9
9
|
|
|
10
10
|
## Who fixes what
|
|
11
11
|
|
|
12
|
-
Cyclone, with auto-patch on, patches only Vortex review findings: Core and seam review findings on any layer, the land PR included. It does not fix merge conflicts, restack conflicts, failing CI, or any other landing blocker by itself. Those are yours, whatever the auto-patch setting. With auto-resolve conflicts on for the stack, Cyclone resolves a layer conflict itself (never the land PR's conflict with main): while `busy[]` shows Cyclone, wait, and fix the conflict only after its handoff, when the watch returns `attention`. Do not turn auto-patch off to fix them; it changes nothing for them.
|
|
12
|
+
Cyclone, with auto-patch on, patches only Vortex review findings: Core and seam review findings on any layer, the land PR included. It does not fix merge conflicts, restack conflicts, failing CI, or any other landing blocker by itself. Those are yours, whatever the auto-patch setting. With auto-resolve conflicts on for the stack, Cyclone resolves a layer conflict itself (never the land PR's conflict with main): while `busy[]` shows Cyclone, wait, and fix the conflict only after its handoff, when the watch returns `attention`. With auto-fix CI on for the stack, Cyclone fixes a settled red check on a layer itself (never the land PR), or asks Surge for one re-run of a flaky one: while `busy[]` shows Cyclone, wait, and fix the failure only after its handoff, when the watch returns `attention`. Do not turn auto-patch off to fix them; it changes nothing for them.
|
|
13
13
|
|
|
14
14
|
## Not done until landed
|
|
15
15
|
|