mergestorm 0.3.50 → 0.3.52
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 +2 -2
- package/dist/api.js +2 -2
- package/dist/commands/browse.js +1 -1
- package/dist/commands/login.js +3 -0
- package/dist/commands/whoami.js +1 -1
- package/dist/stack-blockers.js +30 -6
- package/dist/stack-dto.d.ts +2 -0
- package/dist/ui/banner.js +6 -0
- package/package.json +1 -1
- package/skill/mergestorm-pr-loop/SKILL.md +1 -1
package/README.md
CHANGED
|
@@ -45,12 +45,12 @@ 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.52 │
|
|
49
49
|
│ ▀▀▀▀▀▀▀▀▀ ● msk_live_… · maelstrom │
|
|
50
50
|
│ ▀▀▀▀▀▀ [████████░░░░░░░░░░░░░░░░░░░░░░] 25% used │
|
|
51
51
|
│ ▝▀▀▀▀▀ local reviews + stacked PRs · mergestorm.ai │
|
|
52
52
|
│ ▝▀▀▘ review a diff · usage for tabs · /help for all commands │
|
|
53
|
-
│ ▀ New:
|
|
53
|
+
│ ▀ New in v0.3.52: Sign-in errors name the agent login │
|
|
54
54
|
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
55
55
|
mergestorm
|
|
56
56
|
╭──────────────────────────────────────────────────────────────────────────────╮
|
package/dist/api.js
CHANGED
|
@@ -81,7 +81,7 @@ function rethrowFetchAbort(err, timeoutMs) {
|
|
|
81
81
|
export async function apiFetch(cfg, route, init = {}) {
|
|
82
82
|
const key = resolveApiKey(cfg);
|
|
83
83
|
if (!key) {
|
|
84
|
-
throw new CommandError("No API key. Run `mergestorm login` or set MERGESTORM_API_KEY.", 1, "missing_api_key");
|
|
84
|
+
throw new CommandError("No API key. Run `mergestorm login` (agents: `mergestorm login --start`, then `--finish`) or set MERGESTORM_API_KEY.", 1, "missing_api_key");
|
|
85
85
|
}
|
|
86
86
|
const { json, timeoutMs = DEFAULT_API_TIMEOUT_MS, signal: userSignal, ...rest } = init;
|
|
87
87
|
const headers = {
|
|
@@ -114,7 +114,7 @@ export async function apiFetch(cfg, route, init = {}) {
|
|
|
114
114
|
// keep text
|
|
115
115
|
}
|
|
116
116
|
if (res.status === 401) {
|
|
117
|
-
throw new CommandError("API key invalid or revoked. Run `mergestorm login
|
|
117
|
+
throw new CommandError("API key invalid or revoked. Run `mergestorm login` (agents: `mergestorm login --start`, then `--finish`).", 1, "auth_invalid");
|
|
118
118
|
}
|
|
119
119
|
const retryAfterSeconds = parseRetryAfterSeconds({
|
|
120
120
|
header: res.headers.get("retry-after"),
|
package/dist/commands/browse.js
CHANGED
|
@@ -183,7 +183,7 @@ export async function openTabsBrowser(initial) {
|
|
|
183
183
|
const cfg = await loadConfig();
|
|
184
184
|
const key = resolveApiKey(cfg);
|
|
185
185
|
if (!key) {
|
|
186
|
-
throw new CommandError("Not logged in. Run `mergestorm login
|
|
186
|
+
throw new CommandError("Not logged in. Run `mergestorm login` (agents: `mergestorm login --start`, then `--finish`).");
|
|
187
187
|
}
|
|
188
188
|
let me = null;
|
|
189
189
|
let keyInvalid = false;
|
package/dist/commands/login.js
CHANGED
|
@@ -220,6 +220,9 @@ export async function cmdLogin(args) {
|
|
|
220
220
|
console.log(` ${ansi.brightGreen(pending.openUrl)}`);
|
|
221
221
|
console.log(`\n Code: ${ansi.bold(pending.userCode)}\n`);
|
|
222
222
|
openBrowser(pending.openUrl);
|
|
223
|
+
if (!process.stdout.isTTY) {
|
|
224
|
+
console.log("No terminal here. If this command may be cut off before the approval, use `mergestorm login --start`, then `mergestorm login --finish`.");
|
|
225
|
+
}
|
|
223
226
|
console.log("Waiting for approval…");
|
|
224
227
|
await pollDeviceLogin(pending, "mergestorm login", "Run `mergestorm login` again.");
|
|
225
228
|
}
|
package/dist/commands/whoami.js
CHANGED
|
@@ -9,7 +9,7 @@ export async function cmdWhoami(args, opts = {}) {
|
|
|
9
9
|
const cfg = await loadConfig();
|
|
10
10
|
const key = resolveApiKey(cfg);
|
|
11
11
|
if (!key) {
|
|
12
|
-
throw new CommandError("Not logged in. Run `mergestorm login
|
|
12
|
+
throw new CommandError("Not logged in. Run `mergestorm login` (agents: `mergestorm login --start`, then `--finish`).");
|
|
13
13
|
}
|
|
14
14
|
if (!asJson && canBrowse()) {
|
|
15
15
|
await openTabsBrowser("status");
|
package/dist/stack-blockers.js
CHANGED
|
@@ -63,11 +63,14 @@ function coreReviewDoneAtHead(layer) {
|
|
|
63
63
|
return review?.status === "done" && sameHead(review.head_sha, layer.headSha);
|
|
64
64
|
}
|
|
65
65
|
export const VORTEX_FINDINGS_NEED_PERSON = "Vortex findings need a person";
|
|
66
|
-
function
|
|
66
|
+
function vortexFindingsRestAtHead(layer) {
|
|
67
67
|
const review = layer.vortexReview;
|
|
68
68
|
if (review && !(review.status === "done" && sameHead(review.head_sha, layer.headSha)))
|
|
69
69
|
return false;
|
|
70
|
-
return layer.vortexStatus === "findings"
|
|
70
|
+
return layer.vortexStatus === "findings" || layer.vortexStatus === "throttled";
|
|
71
|
+
}
|
|
72
|
+
function vortexChangesRequestedAtHead(layer) {
|
|
73
|
+
return vortexFindingsRestAtHead(layer) && layer.reviewStatus === "changes_requested";
|
|
71
74
|
}
|
|
72
75
|
function cycloneHandoffAtHead(stack, layer) {
|
|
73
76
|
if (sameHead(layer.cycloneHandoff?.headSha, layer.headSha))
|
|
@@ -75,6 +78,7 @@ function cycloneHandoffAtHead(stack, layer) {
|
|
|
75
78
|
return stack.cyclonePatchOff ?? (stack.autoPatchOverride === false ? "auto_patch_off" : null);
|
|
76
79
|
}
|
|
77
80
|
const CYCLONE_HANDOFF_WORDS = {
|
|
81
|
+
failed: "Cyclone's patch failed, so it pushed nothing",
|
|
78
82
|
auto_patch_off: "auto-patch is off for this stack",
|
|
79
83
|
stack_auto_patch_off: "auto-patch is off for this stack",
|
|
80
84
|
account_auto_patch_off: "auto-patch is off for the account and this stack does not turn it on",
|
|
@@ -105,9 +109,14 @@ const CYCLONE_HANDOFF_WORDS = {
|
|
|
105
109
|
stack_auto_fix_ci_off: "auto-fix CI is off for this stack",
|
|
106
110
|
account_auto_fix_ci_off: "auto-fix CI is off for the account and this stack does not turn it on",
|
|
107
111
|
};
|
|
108
|
-
function cycloneHandoffWords(reason) {
|
|
112
|
+
function cycloneHandoffWords(reason, detail) {
|
|
113
|
+
if (reason === "failed" && detail?.trim())
|
|
114
|
+
return `Cyclone wrote a fix and held it, so it pushed nothing: ${detail.trim()}`;
|
|
109
115
|
return CYCLONE_HANDOFF_WORDS[reason] ?? reason.replaceAll("_", " ");
|
|
110
116
|
}
|
|
117
|
+
function cycloneHandoffDetailAtHead(layer) {
|
|
118
|
+
return sameHead(layer.cycloneHandoff?.headSha, layer.headSha) ? layer.cycloneHandoff.detail ?? null : null;
|
|
119
|
+
}
|
|
111
120
|
function isLandPrLayer(stack, layer) {
|
|
112
121
|
return layer.prNumber === stack.unit?.landPrNumber || (!!stack.unit?.branch && layer.branch === stack.unit.branch);
|
|
113
122
|
}
|
|
@@ -149,9 +158,24 @@ function ciHandoffNote(stack, layer) {
|
|
|
149
158
|
}
|
|
150
159
|
return null;
|
|
151
160
|
}
|
|
161
|
+
const CYCLONE_HELD_FINDINGS_REASONS = [
|
|
162
|
+
"failed",
|
|
163
|
+
"left_for_human",
|
|
164
|
+
"infra_failure",
|
|
165
|
+
"pr_state_unavailable",
|
|
166
|
+
"vortex_patch_cap",
|
|
167
|
+
"patch_job_lost",
|
|
168
|
+
];
|
|
169
|
+
function vortexImportantFindingsHeldAtHead(layer) {
|
|
170
|
+
return vortexFindingsRestAtHead(layer) && layer.reviewStatus === "reviewed" &&
|
|
171
|
+
sameHead(layer.cycloneHandoff?.headSha, layer.headSha) &&
|
|
172
|
+
CYCLONE_HELD_FINDINGS_REASONS.includes(layer.cycloneHandoff.reason);
|
|
173
|
+
}
|
|
152
174
|
function vortexFindingsLeftForPerson(stack, layer) {
|
|
153
|
-
|
|
154
|
-
|
|
175
|
+
if (layerAgentsBusy(layer).cyclone)
|
|
176
|
+
return false;
|
|
177
|
+
return vortexImportantFindingsHeldAtHead(layer) ||
|
|
178
|
+
(vortexChangesRequestedAtHead(layer) && cycloneHandoffAtHead(stack, layer) !== null);
|
|
155
179
|
}
|
|
156
180
|
function quotaSkippedReview(layer) {
|
|
157
181
|
const review = layer.vortexReview;
|
|
@@ -776,7 +800,7 @@ export function stackRepair(stack, attention, layer, bounce, queueWait = null) {
|
|
|
776
800
|
branch: layer.branch,
|
|
777
801
|
handoff,
|
|
778
802
|
findings,
|
|
779
|
-
steps: `Vortex requested changes on ${layer.branch} at ${layer.headSha ?? "its live head"} and Cyclone left them for a person${handoff ? ` (${cycloneHandoffWords(handoff)})` : ""}, so nothing will patch them and Auto land waits. Read the newest Vortex review and its inline comments (${findings}), verify each finding against ${layer.branch} at its live remote head, fix the real ones with the smallest patch, run the tests, confirm the remote head is still ${layer.headSha ?? "the head you started from"}, then an ordinary git push (no force). If a finding is wrong, tell the human; mg dismiss ${stack.owner}/${stack.repo}#${layer.prNumber} --head <sha> --review <id> dismisses that review. Do not retarget the PR base.`,
|
|
803
|
+
steps: `Vortex ${vortexImportantFindingsHeldAtHead(layer) ? "left Important findings" : "requested changes"} on ${layer.branch} at ${layer.headSha ?? "its live head"} and Cyclone left them for a person${handoff ? ` (${cycloneHandoffWords(handoff, cycloneHandoffDetailAtHead(layer))})` : ""}, so nothing will patch them and Auto land waits. Read the newest Vortex review and its inline comments (${findings}), verify each finding against ${layer.branch} at its live remote head, fix the real ones with the smallest patch, run the tests, confirm the remote head is still ${layer.headSha ?? "the head you started from"}, then an ordinary git push (no force). If a finding is wrong, tell the human; mg dismiss ${stack.owner}/${stack.repo}#${layer.prNumber} --head <sha> --review <id> dismisses that review. Do not retarget the PR base.`,
|
|
780
804
|
};
|
|
781
805
|
}
|
|
782
806
|
if (reason === "ci_failed" || attention.bounceKind === "ci_failure") {
|
package/dist/stack-dto.d.ts
CHANGED
|
@@ -69,6 +69,7 @@ export type StackCycloneHandoff = {
|
|
|
69
69
|
headSha: string;
|
|
70
70
|
reason: string;
|
|
71
71
|
at: string | null;
|
|
72
|
+
detail?: string | null;
|
|
72
73
|
};
|
|
73
74
|
export type StackAgentName = "vortex" | "cyclone";
|
|
74
75
|
/**
|
|
@@ -108,6 +109,7 @@ export type StackAgentRun = {
|
|
|
108
109
|
reviewed: number;
|
|
109
110
|
total: number;
|
|
110
111
|
} | null;
|
|
112
|
+
detail?: string | null;
|
|
111
113
|
};
|
|
112
114
|
export type StackAgentsBusy = {
|
|
113
115
|
vortex: boolean;
|
package/dist/ui/banner.js
CHANGED
|
@@ -188,6 +188,12 @@ const WHATS_NEW = {
|
|
|
188
188
|
"0.3.50": [
|
|
189
189
|
"Agent sign-in: login --start, --finish",
|
|
190
190
|
],
|
|
191
|
+
"0.3.51": [
|
|
192
|
+
"Watch names findings held on a throttled head",
|
|
193
|
+
],
|
|
194
|
+
"0.3.52": [
|
|
195
|
+
"Sign-in errors name the agent login",
|
|
196
|
+
],
|
|
191
197
|
};
|
|
192
198
|
function densityFromVariant(variant) {
|
|
193
199
|
if (variant === "mini" || variant === "nano")
|
package/package.json
CHANGED
|
@@ -22,7 +22,7 @@ mg skill install --claude --cursor --agents
|
|
|
22
22
|
1. There is an already-open GitHub PR on a Vortex-monitored repo. No PR, wrong skill.
|
|
23
23
|
2. Auto-patch (Cyclone) must be off for this PR so you are the only patcher. Do not take anyone's word for it: the settings API and the PR's stack are the source of truth, and step 1 of the loop verifies them before anything else runs. Cyclone is off for the PR when its adopted stack has `autoPatchOverride` `false`, or when that override is unset and the account `auto_patch_enabled` is `false`.
|
|
24
24
|
3. The Bearer key and the Cyclone GitHub App install must be the same Mergestorm account. `stack_list` / `stack_status` expose `keyUserId`, `cycloneInstallUserId`, and `cycloneOwnerMatch`. Cyclone apply always uses the install account, not the key. If those identities differ, your `settings_get` mute reading is about the wrong person.
|
|
25
|
-
4. `whoami` works on the `mergestorm` MCP server (or `mg whoami --json` exits 0). Otherwise stop and ask for install
|
|
25
|
+
4. `whoami` works on the `mergestorm` MCP server (or `mg whoami --json` exits 0). Otherwise stop and ask for install, or sign in yourself: run `mg login --start`, send the person the link it prints, and after they approve it run `mg login --finish`.
|
|
26
26
|
|
|
27
27
|
## Loop (in order)
|
|
28
28
|
|