mergestorm 0.3.23 → 0.3.24
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/automation-catalog.d.ts +10 -1
- package/dist/automation-catalog.js +1 -0
- package/dist/commands/browse.d.ts +1 -1
- package/dist/commands/registry.js +1 -0
- package/dist/commands/settings.d.ts +1 -1
- package/dist/commands/settings.js +17 -7
- package/dist/stack-dto.d.ts +3 -2
- package/dist/ui/banner.js +3 -0
- package/package.json +1 -1
- package/skill/mergestorm-bounce-watch/SKILL.md +3 -3
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.24 │
|
|
49
49
|
│ ▜▙ ● msk_live_… · maelstrom │
|
|
50
50
|
│ [████████░░░░░░░░░░░░░░░░░░░░░░] 25% used · Resets Sep 5, 10:53am (UTC)│
|
|
51
51
|
│ │
|
|
52
52
|
│ review a diff · usage for tabs · /help for all commands │
|
|
53
|
-
│ New in v0.3.
|
|
53
|
+
│ New in v0.3.24: mg settings --auto-land-settle (15-300 seconds) │
|
|
54
54
|
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
55
55
|
mergestorm
|
|
56
56
|
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
@@ -46,6 +46,13 @@ export declare const BEARER_SETTINGS: readonly [{
|
|
|
46
46
|
readonly key: "auto_land_default";
|
|
47
47
|
readonly flag: "--auto-land";
|
|
48
48
|
readonly label: "Auto land (new stacks)";
|
|
49
|
+
}, {
|
|
50
|
+
readonly key: "auto_land_settle_seconds";
|
|
51
|
+
readonly flag: "--auto-land-settle";
|
|
52
|
+
readonly label: "Auto land settle (seconds)";
|
|
53
|
+
readonly kind: "seconds";
|
|
54
|
+
readonly min: 15;
|
|
55
|
+
readonly max: 300;
|
|
49
56
|
}, {
|
|
50
57
|
readonly key: "ignored_bot_logins";
|
|
51
58
|
readonly flag: "--ignore-bot";
|
|
@@ -79,7 +86,9 @@ export type BearerSettingsValues = {
|
|
|
79
86
|
[Row in (typeof BEARER_SETTINGS)[number] as Row["key"]]: Row extends {
|
|
80
87
|
kind: "logins";
|
|
81
88
|
} ? string[] : Row extends {
|
|
89
|
+
kind: "seconds";
|
|
90
|
+
} ? number : Row extends {
|
|
82
91
|
values: readonly (infer Value)[];
|
|
83
92
|
} ? Value : boolean;
|
|
84
93
|
};
|
|
85
|
-
export declare const BEARER_BOOLEAN_SETTINGS_KEYS: ("auto_review_enabled" | "auto_patch_enabled" | "vortex_show_thinking_traces" | "repo_overview_enabled" | "review_unit_land_prs_enabled" | "cyclone_review_unit_land_prs_enabled" | "cyclone_skip_ci_enabled" | "cyclone_patch_unverified_languages" | "vortex_auto_overflow_enabled" | "vortex_skip_all_clear_comments" | "vortex_seam_specialist_enabled" | "auto_land_default" | "ignored_bot_logins" | "vortex_bot_skip_check" | "vortex_findings_check" | "cyclone_patch_failure_check")[];
|
|
94
|
+
export declare const BEARER_BOOLEAN_SETTINGS_KEYS: ("auto_review_enabled" | "auto_patch_enabled" | "vortex_show_thinking_traces" | "repo_overview_enabled" | "review_unit_land_prs_enabled" | "cyclone_review_unit_land_prs_enabled" | "cyclone_skip_ci_enabled" | "cyclone_patch_unverified_languages" | "vortex_auto_overflow_enabled" | "vortex_skip_all_clear_comments" | "vortex_seam_specialist_enabled" | "auto_land_default" | "auto_land_settle_seconds" | "ignored_bot_logins" | "vortex_bot_skip_check" | "vortex_findings_check" | "cyclone_patch_failure_check")[];
|
|
@@ -11,6 +11,7 @@ export const BEARER_SETTINGS = [
|
|
|
11
11
|
{ key: "vortex_skip_all_clear_comments", flag: "--vortex-skip-all-clear", label: "Vortex skip All-clear comments" },
|
|
12
12
|
{ key: "vortex_seam_specialist_enabled", flag: "--vortex-seam", label: "Vortex seam specialist" },
|
|
13
13
|
{ key: "auto_land_default", flag: "--auto-land", label: "Auto land (new stacks)" },
|
|
14
|
+
{ key: "auto_land_settle_seconds", flag: "--auto-land-settle", label: "Auto land settle (seconds)", kind: "seconds", min: 15, max: 300 },
|
|
14
15
|
{ key: "ignored_bot_logins", flag: "--ignore-bot", label: "Ignored bot logins", kind: "logins" },
|
|
15
16
|
{ key: "vortex_bot_skip_check", flag: "--vortex-skip-check", label: "Vortex bot skip check", kind: "enum", values: ["none", "neutral"] },
|
|
16
17
|
{ key: "vortex_findings_check", flag: "--vortex-findings", label: "Vortex findings check", kind: "enum", values: ["failure", "neutral", "success"] },
|
|
@@ -27,7 +27,7 @@ export declare function buildStatusTabLines(input: StatusTabInput): string[];
|
|
|
27
27
|
/** In-place job detail for the Jobs tab (same envelope as `status <id>`). */
|
|
28
28
|
export declare function formatJobDetailLines(row: ReviewJobRow): string[];
|
|
29
29
|
/** Human labels for the Config tab and the static `settings` printout. */
|
|
30
|
-
export declare const SETTINGS_LABELS: Record<"auto_review_enabled" | "auto_patch_enabled" | "vortex_show_thinking_traces" | "repo_overview_enabled" | "review_unit_land_prs_enabled" | "cyclone_review_unit_land_prs_enabled" | "cyclone_skip_ci_enabled" | "cyclone_patch_unverified_languages" | "vortex_auto_overflow_enabled" | "vortex_skip_all_clear_comments" | "vortex_seam_specialist_enabled" | "auto_land_default" | "ignored_bot_logins" | "vortex_bot_skip_check" | "vortex_findings_check" | "cyclone_patch_failure_check", string>;
|
|
30
|
+
export declare const SETTINGS_LABELS: Record<"auto_review_enabled" | "auto_patch_enabled" | "vortex_show_thinking_traces" | "repo_overview_enabled" | "review_unit_land_prs_enabled" | "cyclone_review_unit_land_prs_enabled" | "cyclone_skip_ci_enabled" | "cyclone_patch_unverified_languages" | "vortex_auto_overflow_enabled" | "vortex_skip_all_clear_comments" | "vortex_seam_specialist_enabled" | "auto_land_default" | "auto_land_settle_seconds" | "ignored_bot_logins" | "vortex_bot_skip_check" | "vortex_findings_check" | "cyclone_patch_failure_check", string>;
|
|
31
31
|
/** Config rows in a stable order: writable toggles, then connected flags. */
|
|
32
32
|
export declare function buildConfigRows(settings: SettingsResponse): TabsConfigRow[];
|
|
33
33
|
/**
|
|
@@ -169,6 +169,7 @@ export const COMMAND_REGISTRY = [
|
|
|
169
169
|
" [--cyclone-patch-unverified on|off] Patch languages we cannot typecheck",
|
|
170
170
|
" [--vortex-seam on|off] [--vortex-skip-all-clear on|off]",
|
|
171
171
|
" [--auto-land on|off] Auto land default for new stacks",
|
|
172
|
+
" [--auto-land-settle <seconds>] How long Auto land waits before queueing (15-300, default 60)",
|
|
172
173
|
" [--ignore-bot add <login>|remove <login>|clear]",
|
|
173
174
|
" [--vortex-skip-check none|neutral] [--vortex-findings failure|neutral|success]",
|
|
174
175
|
" [--cyclone-fail-check failure|neutral]",
|
|
@@ -3,7 +3,7 @@ import { type SettingsPatch, type SettingsResponse } from "../api.js";
|
|
|
3
3
|
* CLI flag → Bearer settings key. Boolean flags take on|off. The connected flags are
|
|
4
4
|
* read-only on the API and deliberately have no flag here.
|
|
5
5
|
*/
|
|
6
|
-
export declare const SETTINGS_FLAGS: Record<string, "auto_review_enabled" | "auto_patch_enabled" | "vortex_show_thinking_traces" | "repo_overview_enabled" | "review_unit_land_prs_enabled" | "cyclone_review_unit_land_prs_enabled" | "cyclone_skip_ci_enabled" | "cyclone_patch_unverified_languages" | "vortex_auto_overflow_enabled" | "vortex_skip_all_clear_comments" | "vortex_seam_specialist_enabled" | "auto_land_default" | "ignored_bot_logins" | "vortex_bot_skip_check" | "vortex_findings_check" | "cyclone_patch_failure_check">;
|
|
6
|
+
export declare const SETTINGS_FLAGS: Record<string, "auto_review_enabled" | "auto_patch_enabled" | "vortex_show_thinking_traces" | "repo_overview_enabled" | "review_unit_land_prs_enabled" | "cyclone_review_unit_land_prs_enabled" | "cyclone_skip_ci_enabled" | "cyclone_patch_unverified_languages" | "vortex_auto_overflow_enabled" | "vortex_skip_all_clear_comments" | "vortex_seam_specialist_enabled" | "auto_land_default" | "auto_land_settle_seconds" | "ignored_bot_logins" | "vortex_bot_skip_check" | "vortex_findings_check" | "cyclone_patch_failure_check">;
|
|
7
7
|
type IgnoreBotOperation = {
|
|
8
8
|
action: "add" | "remove";
|
|
9
9
|
login: string;
|
|
@@ -46,6 +46,14 @@ export function parseSettingsArgs(args) {
|
|
|
46
46
|
}
|
|
47
47
|
continue;
|
|
48
48
|
}
|
|
49
|
+
if ("kind" in row && row.kind === "seconds") {
|
|
50
|
+
const seconds = value !== undefined && /^\d+$/.test(value) ? Number(value) : Number.NaN;
|
|
51
|
+
if (!Number.isInteger(seconds) || seconds < row.min || seconds > row.max) {
|
|
52
|
+
throw new CommandError(`${flag} takes a whole number of seconds from ${row.min} through ${row.max}.`, 2, "usage");
|
|
53
|
+
}
|
|
54
|
+
Object.assign(patch, { [key]: seconds });
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
49
57
|
if ("kind" in row && row.kind === "enum") {
|
|
50
58
|
if (value === undefined || !row.values.includes(value)) {
|
|
51
59
|
throw new CommandError(`${flag} takes ${row.values.join(" or ")}.`, 2, "usage");
|
|
@@ -76,13 +84,15 @@ export function formatSettingsLines(settings) {
|
|
|
76
84
|
? row.value.join(", ") || "(empty)"
|
|
77
85
|
: typeof row.value === "string"
|
|
78
86
|
? row.value
|
|
79
|
-
: row.
|
|
80
|
-
? row.value
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
:
|
|
87
|
+
: typeof row.value === "number"
|
|
88
|
+
? `${row.value}s`
|
|
89
|
+
: row.writable
|
|
90
|
+
? row.value
|
|
91
|
+
? "on"
|
|
92
|
+
: "off"
|
|
93
|
+
: row.value
|
|
94
|
+
? "connected"
|
|
95
|
+
: "not connected";
|
|
86
96
|
return ` ${row.label.padEnd(labelWidth + 2)}${value}`;
|
|
87
97
|
});
|
|
88
98
|
}
|
package/dist/stack-dto.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type RestackError = {
|
|
2
|
-
kind: "rebase_conflict" | "checkout_failed" | "head_unresolved" | "push_failed";
|
|
2
|
+
kind: "rebase_conflict" | "checkout_failed" | "head_unresolved" | "push_failed" | "retarget_failed";
|
|
3
3
|
detail: string;
|
|
4
4
|
headSha: string;
|
|
5
5
|
attemptedAt: string;
|
|
@@ -300,11 +300,12 @@ export type StackDto = {
|
|
|
300
300
|
* Partial or invalid server rows map to `null`, never to a guessed value.
|
|
301
301
|
*/
|
|
302
302
|
autoEnqueueSettle?: {
|
|
303
|
-
action: "ready" | "promote";
|
|
303
|
+
action: "ready" | "promote" | "mergeability";
|
|
304
304
|
prNumber: number;
|
|
305
305
|
headSha: string;
|
|
306
306
|
/** ISO timestamp of the watcher's clock start. */
|
|
307
307
|
startedAt: string;
|
|
308
|
+
windowSeconds?: number;
|
|
308
309
|
} | null;
|
|
309
310
|
/**
|
|
310
311
|
* Per-stack Vortex auto-review override. `null` (or missing) follows the
|
package/dist/ui/banner.js
CHANGED
|
@@ -102,6 +102,9 @@ const WHATS_NEW = {
|
|
|
102
102
|
"0.3.23": [
|
|
103
103
|
"leave a stack bottom on mg-stack-<n>",
|
|
104
104
|
],
|
|
105
|
+
"0.3.24": [
|
|
106
|
+
"mg settings --auto-land-settle (15-300 seconds)",
|
|
107
|
+
],
|
|
105
108
|
};
|
|
106
109
|
function densityFromVariant(variant) {
|
|
107
110
|
if (variant === "mini" || variant === "nano")
|
package/package.json
CHANGED
|
@@ -16,10 +16,10 @@ Call `stack_status` with `stack_id`. Require that stack's `autoEnqueueWhenReady`
|
|
|
16
16
|
## Watch and patch
|
|
17
17
|
|
|
18
18
|
1. Call `stack_wait` with the named `stack_id` and `timeout_s: 45`. On initial enrollment, omit the cursor selectors. Save the returned `cursor`: map `cursor.enrolledHeadSha` to `enrolled_head_sha`, `cursor.afterFinishedAt` to `after_finished_at`, and `cursor.bounceId` to `bounce_id` (omit only absent fields; preserve explicit nulls). Keep `bounce_id` alongside `after_finished_at`; never pass one without the other when the returned cursor has both. The shipped tool accepts these selectors, not a nested cursor argument.
|
|
19
|
-
2. Keep the same cursor across retries. An unread deadline times out as `failed`; stop and report. Timeout `waiting` or `in_progress` after a snapshot is not failure — call `stack_wait` again in 45s slices with the same cursor after inspecting `issues[]`. Inspect `issues[]` on `in_progress` too: a live queue does not erase upstack hard blocks. `waiting` with issues is not idle. If `assessment` is `unavailable`, do not infer that the stack is issue-free; refresh `stack_status`, whose `attention`, `issues`, and `currentCandidate` come from the same blocker rules as `stack_wait`. Do not replace the enrolled head with a newer snapshot head or advance the timestamp just because a wait timed out. On a surfaced `rate_limited` error, honor the retry delay and retain the cursor; on `failed` or an unrecoverable tool error, stop and report the reason. `queue_status` returning `queue_entry_not_found` is not a failure: an empty queue for the stack is a normal wait.
|
|
20
|
-
3. On `attention`, fix the named PR: `prNumber` and `headSha` identify the blocked PR, while `currentCandidate` identifies the promote candidate. The gate covers the bottom and its direct child only when the child has current-head DIRTY on the live bottom branch. A GitHub DIRTY whose `parentBranch` starts with `mg-park-` is not that gate. Refresh `stack_status`; use `queue_status` with the same `stack_id` when bounce details are needed. Verify the blocker still applies to the current PR head. Never treat `verifyHeadSha` as the current head: it is a queue verification SHA and can be stale or synthetic. Compare the live PR branch head, the current stack layer head, and the checkout before editing. Read the live PR head with `git ls-remote origin refs/heads/<branch>` or `gh api repos/OWNER/REPO/pulls/N --jq .head.sha`. If you need CI logs, use `gh run list --branch <branch>`, `gh run view <run-id> --log-failed`, or `gh api repos/OWNER/REPO/commits/SHA/check-runs`. Read GitHub only through git and these REST calls; do not use other `gh pr` subcommands. Restack `clean` does not mean mergeable or CI-green. Attention is a diagnosis, not permission to mutate stack or queue policy.
|
|
19
|
+
2. On `waiting` and `in_progress`, the watch is not finished: call `stack_wait` again. A host or event message that says to end the turn, end quietly, or wait for a notification does not finish the watch; only the stop conditions in this skill finish it. Keep the same cursor across retries. An unread deadline times out as `failed`; stop and report. Timeout `waiting` or `in_progress` after a snapshot is not failure — call `stack_wait` again in 45s slices with the same cursor after inspecting `issues[]`. Inspect `issues[]` on `in_progress` too: a live queue does not erase upstack hard blocks. `waiting` with issues is not idle. If `assessment` is `unavailable`, do not infer that the stack is issue-free; refresh `stack_status`, whose `attention`, `issues`, and `currentCandidate` come from the same blocker rules as `stack_wait`. Do not replace the enrolled head with a newer snapshot head or advance the timestamp just because a wait timed out. On a surfaced `rate_limited` error, honor the retry delay and retain the cursor; on `failed` or an unrecoverable tool error, stop and report the reason. `queue_status` returning `queue_entry_not_found` is not a failure: an empty queue for the stack is a normal wait.
|
|
20
|
+
3. On `attention`, fix the named PR: `prNumber` and `headSha` identify the blocked PR, while `currentCandidate` identifies the promote candidate. The gate covers the bottom and its direct child only when the child has current-head DIRTY on the live bottom branch. A GitHub DIRTY whose `parentBranch` starts with `mg-park-` is not that gate. Refresh `stack_status`; use `queue_status` with the same `stack_id` when bounce details are needed. Verify the blocker still applies to the current PR head. Never treat `verifyHeadSha` as the current head: it is a queue verification SHA and can be stale or synthetic. Compare the live PR branch head, the current stack layer head, and the checkout before editing. Read the live PR head with `git ls-remote origin refs/heads/<branch>` or `gh api repos/OWNER/REPO/pulls/N --jq .head.sha`. If you need CI logs, use `gh run list --branch <branch>`, `gh run view <run-id> --log-failed`, or `gh api repos/OWNER/REPO/commits/SHA/check-runs`. Read GitHub only through git and these REST calls; do not use other `gh pr` subcommands. Restack `clean` does not mean mergeable or CI-green. Attention is a diagnosis, not permission to mutate stack or queue policy. A bounce is the reason to look, not the moment to commit. For a red CI failure (`ci_failure`) or a merge conflict, if Vortex or Cyclone is still working on that PR, do not patch yet: keep calling `stack_wait` with the same cursor until that work has finished, then make the follow-up commit. Still working means, from `stack_status` on that stack for that PR: `vortexStatus` is `queued`, `reviewing`, or `seam_pending`; or `cycloneStatus` is `patching`; or an `agentRuns` row for vortex or cyclone has no `finishedAt` and its status is one of those in-flight values. `all_clear`, `findings`, `skipped`, `failed`, `throttled`, `awaiting_fix`, and a null status are finished. Do not turn Cyclone off, and do not turn Auto land off or on, to end the wait. If the remote head moves while you wait, stop and tell the human.
|
|
21
21
|
4. Use a clean worktree on that named PR's head branch and record the remote starting SHA. Fix the current blocker with the smallest patch, and run the relevant checks. For conflicts, the live parent is the sibling PR head or the unit branch (`mg-stack-N`, Mergestorm's owned trunk, not an alias for main) — not the DTO `parentBranch` when that field starts with `mg-park-*`. If `parentBranch` is `mg-park-*`, never merge or rebase onto it; if the real live parent is unknown, stop. Otherwise prefer merging that live parent into the PR branch, resolving locally, then an ordinary push. Never use Dashboard Continue. When the live parent is a sibling, never rebase onto trunk or `mg-stack-N` instead. Parked-freeze DIRTY alone needs no conflict patch. Leave GitHub bases as Mergestorm set them: the bottom of a 2+ PR stack is based on `mg-stack-N`, layer 2 on layer 1, PR3+ on `mg-park-*`.
|
|
22
|
-
5. CI-only fixes may run while Cyclone auto-patch is still on for the stack. When the gate is clean, inspect `issues[]` and fix a live upstack CI failure one PR at a time, refreshing the gate before the next PR. Do not use higher-layer bounce history as a patch target. Do not fight Cyclone: if the remote head moved, stop and tell the human. Do not take over Cyclone's review-finding work while it is active; if the blocker requires that or a policy/queue action rather than a concrete patch, stop and explain what needs human attention.
|
|
22
|
+
5. CI-only fixes may run while Cyclone auto-patch is still on for the stack. Auto-patch may stay on, and you still wait until the current Vortex run and the current Cyclone run on that PR have finished before the follow-up commit. When the gate is clean, inspect `issues[]` and fix a live upstack CI failure one PR at a time, refreshing the gate before the next PR. Do not use higher-layer bounce history as a patch target. Do not fight Cyclone: if the remote head moved, stop and tell the human. Do not take over Cyclone's review-finding work while it is active; if the blocker requires that or a policy/queue action rather than a concrete patch, stop and explain what needs human attention.
|
|
23
23
|
6. Recheck Auto land and the remote PR head (`git ls-remote origin refs/heads/<branch>`) immediately before pushing. Commit the patch and push the PR head with an ordinary push. A rebase onto that same live parent followed by force-with-lease is allowed only if the remote is still exactly the SHA you started from and Cyclone did not move it; use an explicit lease bound to that starting SHA. This exception never permits rebasing onto a parked freeze or substituting trunk / the unit for a sibling parent. If the remote head moved or the push is rejected because it moved, stop; do not rebase and retry.
|
|
24
24
|
7. After your successful push, leave a clean worktree and keep watching the named stack. Start a new watch cycle with `enrolled_head_sha` set to the SHA you pushed. If you handled a bounce, retain the returned `cursor.afterFinishedAt` as `after_finished_at` and `cursor.bounceId` as `bounce_id` so that attempt is not handled again. Keep these selectors unchanged across subsequent retries. Continue watching; do not enqueue or re-arm anything. If further progress requires re-arming, stop and tell the human.
|
|
25
25
|
|