mergestorm 0.3.64 → 0.3.66
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 +28 -9
- package/dist/api.d.ts +63 -11
- package/dist/api.js +195 -6
- package/dist/automation-catalog.d.ts +5 -1
- package/dist/automation-catalog.js +1 -0
- package/dist/cli.js +21 -19
- package/dist/client/index.d.ts +3 -2
- package/dist/client/index.js +3 -2
- package/dist/commands/account.d.ts +3 -0
- package/dist/commands/account.js +75 -0
- package/dist/commands/browse.d.ts +1 -9
- package/dist/commands/browse.js +10 -8
- package/dist/commands/dismiss.d.ts +0 -2
- package/dist/commands/dismiss.js +2 -2
- package/dist/commands/help.js +3 -2
- package/dist/commands/issue.d.ts +24 -6
- package/dist/commands/issue.js +153 -31
- package/dist/commands/login.d.ts +2 -1
- package/dist/commands/login.js +50 -14
- package/dist/commands/logout.js +6 -7
- package/dist/commands/memory.d.ts +2 -3
- package/dist/commands/memory.js +8 -6
- package/dist/commands/registry.d.ts +1 -0
- package/dist/commands/registry.js +35 -11
- package/dist/commands/review-client.d.ts +0 -3
- package/dist/commands/review-client.js +3 -3
- package/dist/commands/review.d.ts +1 -1
- package/dist/commands/review.js +1 -1
- package/dist/commands/settings.d.ts +3 -5
- package/dist/commands/settings.js +4 -3
- package/dist/commands/stack.d.ts +19 -5
- package/dist/commands/stack.js +78 -4
- package/dist/commands/whoami.js +14 -10
- package/dist/config.d.ts +55 -2
- package/dist/config.js +264 -13
- package/dist/errors.d.ts +1 -1
- package/dist/gh.d.ts +0 -4
- package/dist/gh.js +4 -4
- package/dist/git.d.ts +1 -1
- package/dist/git.js +2 -2
- package/dist/memory-api.d.ts +1 -0
- package/dist/memory-api.js +2 -2
- package/dist/node-version.d.ts +0 -2
- package/dist/node-version.js +1 -1
- package/dist/pr-body.d.ts +4 -0
- package/dist/pr-body.js +15 -0
- package/dist/repo-identity.d.ts +2 -1
- package/dist/repo-identity.js +8 -4
- package/dist/server-publish.d.ts +1 -24
- package/dist/server-publish.js +9 -9
- package/dist/stack-blockers.d.ts +12 -38
- package/dist/stack-blockers.js +55 -33
- package/dist/stack-dto.d.ts +3 -0
- package/dist/stack-dto.js +15 -2
- package/dist/stack-meta.d.ts +2 -2
- package/dist/stack-meta.js +1 -1
- package/dist/stack-watch-loop.d.ts +2 -13
- package/dist/stack-watch-loop.js +12 -12
- package/dist/submit-pr-base.d.ts +0 -1
- package/dist/submit-pr-base.js +1 -1
- package/dist/ui/ansi.d.ts +0 -10
- package/dist/ui/ansi.js +2 -2
- package/dist/ui/banner.d.ts +3 -1
- package/dist/ui/banner.js +10 -3
- package/dist/ui/box.d.ts +0 -2
- package/dist/ui/box.js +1 -1
- package/dist/ui/prompt.d.ts +0 -11
- package/dist/ui/prompt.js +7 -7
- package/dist/ui/tabs.d.ts +2 -2
- package/dist/ui/tabs.js +1 -1
- package/dist/ui/width.d.ts +0 -9
- package/dist/ui/width.js +3 -3
- package/dist/web-api.d.ts +17 -0
- package/dist/web-api.js +30 -0
- package/package.json +1 -1
- package/skill/SKILL.md +4 -0
- package/skill/mergestorm-bounce-watch/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.66 │
|
|
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 in v0.3.
|
|
53
|
+
│ ▀ New in v0.3.66: `issue wait`; submit needs an approved issue │
|
|
54
54
|
╰──────────────────────────────────────────────────────────────────────────────╯
|
|
55
55
|
mergestorm
|
|
56
56
|
╭──────────────────────────────────────────────────────────────────────────────╮
|
|
@@ -75,11 +75,14 @@ One-shot subcommands work the same inside the shell and from argv (scripts/CI):
|
|
|
75
75
|
```
|
|
76
76
|
mergestorm Interactive shell (TTY only)
|
|
77
77
|
mergestorm shell Explicit shell entry
|
|
78
|
-
mergestorm login Sign in via browser
|
|
78
|
+
mergestorm login Sign in via browser and add the account (up to 3 saved)
|
|
79
79
|
mergestorm login --start Print a sign-in URL and code, then exit (agents)
|
|
80
80
|
mergestorm login --finish Store the API key once the code from --start is approved
|
|
81
81
|
mergestorm login --key Paste an existing API key instead (headless/CI)
|
|
82
|
-
mergestorm logout
|
|
82
|
+
mergestorm logout Log out of the active account (or --account <name>) and revoke its key
|
|
83
|
+
mergestorm account list [--json] Saved accounts (up to 3), the active one marked
|
|
84
|
+
mergestorm account use <name> Make <name> the active account
|
|
85
|
+
mergestorm account remove <name> Log out of <name> and revoke its key
|
|
83
86
|
mergestorm review [base] [head] Review git diff base...head (default: origin/HEAD or main or master)
|
|
84
87
|
mergestorm status <job_id> Fetch a review job (envelope; --json --wait --timeout)
|
|
85
88
|
mergestorm status Tabbed Status / Usage / Jobs browser (TTY)
|
|
@@ -87,10 +90,11 @@ mergestorm credits [--json] Usage panel (bar + last 5 jobs); tabbed browser
|
|
|
87
90
|
mergestorm jobs [n] [--json] Recent review jobs (default 10, max 50)
|
|
88
91
|
mergestorm branches [n] Recently reviewed branches (arrow-pick on TTY)
|
|
89
92
|
mergestorm chain [slug] Branch review-chain timeline (default: current branch)
|
|
90
|
-
mergestorm whoami [--json]
|
|
93
|
+
mergestorm whoami [--json] Active account, key prefix, plan, API base, config path
|
|
91
94
|
mergestorm skill install --claude|--cursor|--agents Copy the Mergestorm skills into this repo
|
|
92
95
|
mergestorm thread <slug> Jobs in a review thread
|
|
93
|
-
mergestorm issue create --title <t> Open a GitHub issue through Mergestorm, no `gh` (`--body`, `--body-file`, `--label`, `--repo`)
|
|
96
|
+
mergestorm issue create --title <t> Open a GitHub issue through Mergestorm, no `gh` (`--body`, `--body-file`, `--label`, `--repo`, `--wait`)
|
|
97
|
+
mergestorm issue wait <n> Wait for the Vortex issue review; exits 0 once approved, 4 with points to answer
|
|
94
98
|
mergestorm stack create [name] New local stack layer (optional `--onto` / `--trunk` / `--extend`)
|
|
95
99
|
mergestorm stack submit Push layers, open PRs (`gh`), register via adopt (optional `--extend`, `--server-side`)
|
|
96
100
|
mergestorm stack publish Publish the current branch through Mergestorm with no GitHub credentials (`--base <branch> --extend` to stack, `--status` to read it)
|
|
@@ -167,25 +171,39 @@ mg stack publish --status # absent | pushed | opened | registered
|
|
|
167
171
|
```
|
|
168
172
|
|
|
169
173
|
- **Issues too.** `mg issue create` opens the issue a PR needs through the same Surge App, with existing labels only. Running it again with the same title returns the issue it already opened. Put `Fixes #<n>` in the commit message; `stack submit` carries it into the PR body.
|
|
174
|
+
- **Issue reviews first.** On a repository with Vortex issue reviews on, Vortex reviews each new issue before any PR. `mg issue wait <n>` (or `mg issue create --wait`) waits for that review: it exits 0 once the issue is approved, or exits 4 with the numbered points to answer. Answer them in a comment on the issue and wait again; Vortex re-reviews on each reply, up to four rounds, after which a person approves with an issue comment whose first line is `mergestorm-issue: approve`. `stack submit` refuses to open a PR whose tip commit links an issue that is not approved yet, or links no issue at all while issue reviews are on.
|
|
170
175
|
- **Exact contents.** Every commit travels with its Git tree SHA and the whole content of each changed file, so binaries, deletions, renames, executable bits and symlinks arrive unchanged. Mergestorm moves the branch only when GitHub builds the same tree, and `mg` checks the returned tree against your local branch.
|
|
171
176
|
- **Never overwrites surprises.** `mg` looks at the branch on GitHub first. If its files match one of your local commits, only the commits after that one are appended. If they match none (someone else pushed, or you rebased), `mg` stops with `head_changed`; `--replace-head <sha>` replaces exactly that head and nothing else. Mergestorm refuses `main`, `master`, the default branch, protected branches and its own `mg-stack-*`, `mg-park-*` and `mq-batch-*` branches.
|
|
172
177
|
- **Safe to run again.** After a timeout or an error, run the same command again. It finds the branch, pull request and stack it already made and finishes the missing step; it does not create duplicates.
|
|
173
178
|
- **Read-only home directory.** `mg` keeps the saved login and the local stack state of `stack create` / `stack submit` under `~/.mergestorm`. Where the home directory cannot be written, set `MERGESTORM_HOME` to a writable directory (outside the repository) and every command uses that instead. `MERGESTORM_API_KEY` supplies the key without `mg login`.
|
|
179
|
+
- **Several accounts.** `mg login` keeps up to three accounts signed in; `mg account use <name>` picks the active one, and `--account <name>` or `MERGESTORM_ACCOUNT` runs one command as another.
|
|
174
180
|
- **Limits.** 20 commits, 500 changed paths, 2 MiB a file and 8 MiB in total per publication. Submodules and merge commits are refused with the path or the reason. `stack submit --server-side` publishes the first two layers of a stack; a third layer needs a park freeze, which this mode does not create, so add it once the first two are registered.
|
|
175
181
|
|
|
176
182
|
If local authoring state is stale or malformed, use `mg stack reset --force`; this clears only pre-submit CLI state and never deletes branches, PRs, or registered stacks.
|
|
177
183
|
|
|
178
184
|
### `login`
|
|
179
185
|
|
|
180
|
-
Runs a browser device-authorization flow: prints a short code, opens `https://mergestorm.ai/cli/auth`, and — once you approve — mints and
|
|
186
|
+
Runs a browser device-authorization flow: prints a short code, opens `https://mergestorm.ai/cli/auth`, and — once you approve — mints an API key and saves it as an account in `~/.mergestorm/config.json` (mode `600`), or in `$MERGESTORM_HOME/config.json` when `MERGESTORM_HOME` is set. No key copy/paste needed. The account is named by its GitHub login (or its email when there is no GitHub login), as `mg whoami` reports it, and becomes the active account.
|
|
187
|
+
|
|
188
|
+
Up to three accounts can stay logged in at once. `mg login` again adds another account, or replaces the key of an account that is already saved. A fourth login is refused with the three names; remove one first. A login saved by an older `mg` migrates on first read into an account named by its key prefix (`msk_live_abcd`), and takes its real name the next time a command such as `mg whoami` reaches the API. The file also keeps the active account's key at its top level, so an older `mg` or `mergestorm-mcp` on the same machine keeps signing in as the active account.
|
|
181
189
|
|
|
182
190
|
For headless or CI environments, use `mergestorm login --key` to paste an existing `msk_live_…` key (create one on the dashboard [Settings → API](https://mergestorm.ai/settings#api)). On a TTY the paste is hidden (not echoed); the CLI verifies the key with the API before saving.
|
|
183
191
|
|
|
184
192
|
For an agent, which cannot sit in a prompt while a person signs in, use two steps. `mergestorm login --start` prints the URL and the short code and exits. Give both to the account owner, who opens [mergestorm.ai/cli/auth](https://mergestorm.ai/cli/auth) on any device, signs in, and approves the code. Then `mergestorm login --finish` stores the API key. The code lasts 10 minutes, and `--finish` can be run again if it is interrupted before the approval.
|
|
185
193
|
|
|
194
|
+
### `account`
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
mg account list # saved accounts, the active one marked ● (--json for machines)
|
|
198
|
+
mg account use work # make "work" the active account for every later command
|
|
199
|
+
mg account remove work # log "work" out: revoke its API key and drop it
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Every command runs as the active account. To run one command as another saved account without switching, pass `--account <name>` anywhere on the command line (`mg --account work stack submit`, `mg whoami --account work`), or set `MERGESTORM_ACCOUNT=<name>`; the flag wins over the variable, and both win over the active account. An unknown name stops the command and lists the saved accounts. `MERGESTORM_API_KEY` still overrides every saved account. The `mergestorm-mcp` server reads the same store, so `MERGESTORM_ACCOUNT` in its environment picks the account it serves.
|
|
203
|
+
|
|
186
204
|
### `logout`
|
|
187
205
|
|
|
188
|
-
|
|
206
|
+
Logs out of the active account (or the one named with `--account`): revokes that API key on the server when it can, then drops the account from the store. The next saved account, if any, becomes active. `mg account remove <name>` does the same for a named account.
|
|
189
207
|
|
|
190
208
|
### `review [base] [head]`
|
|
191
209
|
|
|
@@ -234,7 +252,8 @@ Require a logged-in key and API support for `GET /api/v1/me` and `GET /api/v1/re
|
|
|
234
252
|
|
|
235
253
|
| Variable | Purpose | Default |
|
|
236
254
|
|----------|---------|---------|
|
|
237
|
-
| `MERGESTORM_API_KEY` | API key (overrides
|
|
255
|
+
| `MERGESTORM_API_KEY` | API key (overrides every saved account) | — |
|
|
256
|
+
| `MERGESTORM_ACCOUNT` | Saved account to run as; `--account <name>` on a command wins over it | the active account |
|
|
238
257
|
| `MERGESTORM_API_URL` | API base URL | `https://api.mergestorm.ai` |
|
|
239
258
|
| `MERGESTORM_HOME` | Directory for the saved login and local stack state, for machines whose home directory is read-only | `~/.mergestorm` |
|
|
240
259
|
| `NO_COLOR` | Disable ANSI colors | — |
|
package/dist/api.d.ts
CHANGED
|
@@ -30,14 +30,20 @@ export declare function devicePost(base: string, route: string, json: unknown, o
|
|
|
30
30
|
status: number;
|
|
31
31
|
body: any;
|
|
32
32
|
}>;
|
|
33
|
-
|
|
33
|
+
type SurgeUsage = {
|
|
34
34
|
includedMinutes: number;
|
|
35
35
|
usedMinutes: number;
|
|
36
36
|
walletMinutes: number;
|
|
37
37
|
windowStart: string;
|
|
38
38
|
pricePerMinuteUsd: number;
|
|
39
39
|
};
|
|
40
|
+
export type AccountIdentity = {
|
|
41
|
+
github_login: string | null;
|
|
42
|
+
email: string | null;
|
|
43
|
+
};
|
|
44
|
+
export declare function accountLabel(account: AccountIdentity | null | undefined): string | null;
|
|
40
45
|
export type MeResponse = {
|
|
46
|
+
account?: AccountIdentity;
|
|
41
47
|
key: {
|
|
42
48
|
prefix: string;
|
|
43
49
|
name: string;
|
|
@@ -182,10 +188,10 @@ export type SettingsResponse = import("./automation-catalog.js").BearerSettingsV
|
|
|
182
188
|
github_connected: boolean;
|
|
183
189
|
stacks_ready?: boolean;
|
|
184
190
|
};
|
|
185
|
-
export declare const REPO_SETTINGS_SWITCH_KEYS: readonly ["auto_patch_enabled", "auto_review_enabled", "auto_land_default", "merge_queue_batch_enabled", "merge_queue_overdrive"];
|
|
186
|
-
export declare const REPO_SETTINGS_KEYS: readonly ["auto_patch_enabled", "auto_review_enabled", "auto_land_default", "merge_queue_batch_enabled", "merge_queue_overdrive", "merge_queue_batch_size", "merge_queue_lands_alone_paths"];
|
|
191
|
+
export declare const REPO_SETTINGS_SWITCH_KEYS: readonly ["auto_patch_enabled", "auto_review_enabled", "auto_land_default", "merge_queue_batch_enabled", "merge_queue_overdrive", "issue_review_enabled"];
|
|
192
|
+
export declare const REPO_SETTINGS_KEYS: readonly ["auto_patch_enabled", "auto_review_enabled", "auto_land_default", "merge_queue_batch_enabled", "merge_queue_overdrive", "issue_review_enabled", "merge_queue_batch_size", "merge_queue_lands_alone_paths"];
|
|
187
193
|
export type RepoSettingsKey = (typeof REPO_SETTINGS_KEYS)[number];
|
|
188
|
-
|
|
194
|
+
type RepoSettingsValues = Record<(typeof REPO_SETTINGS_SWITCH_KEYS)[number], boolean | null> & {
|
|
189
195
|
merge_queue_batch_size: number | null;
|
|
190
196
|
merge_queue_lands_alone_paths: string[] | null;
|
|
191
197
|
};
|
|
@@ -219,6 +225,9 @@ export declare function patchSettings(patch: SettingsPatch, cfg?: Config, opts?:
|
|
|
219
225
|
export declare function getMe(cfg?: Config, opts?: {
|
|
220
226
|
timeoutMs?: number;
|
|
221
227
|
}): Promise<MeResponse | null>;
|
|
228
|
+
export declare function revokeOwnKey(cfg: Config, opts?: {
|
|
229
|
+
timeoutMs?: number;
|
|
230
|
+
}): Promise<boolean>;
|
|
222
231
|
export declare function listJobs(limit?: number, cfg?: Config, opts?: {
|
|
223
232
|
timeoutMs?: number;
|
|
224
233
|
}): Promise<JobListItem[]>;
|
|
@@ -257,16 +266,11 @@ export type StackPolicyPatch = {
|
|
|
257
266
|
export declare function stackPolicyBody(policy: StackPolicyPatch | undefined): StackPolicyPatch;
|
|
258
267
|
/** Adopt an open PR chain (Bearer POST /api/v1/stacks/adopt). */
|
|
259
268
|
export declare function adoptStack(owner: string, repo: string, prNumber: number, cfg?: Config, policy?: StackPolicyPatch): Promise<unknown>;
|
|
260
|
-
export declare const SURGE_REFUSAL_FALLBACK = "Mergestorm Surge is not installed or not ready on this repository. Install it from Agents.";
|
|
261
|
-
export declare function surgeRefusal(body: unknown): CommandError | null;
|
|
262
|
-
export declare const GITHUB_UNREADABLE_MESSAGE = "GitHub could not be read just now; try again.";
|
|
263
269
|
/** Mint or reuse the PR3+ park freeze (Bearer POST /api/v1/stacks/:id/ensure-upper-park). */
|
|
264
270
|
export declare function ensureUpperPark(stackId: string, cfg?: Config): Promise<{
|
|
265
271
|
freezeBranch: string;
|
|
266
272
|
created: boolean;
|
|
267
273
|
}>;
|
|
268
|
-
export declare const SURGE_INSTALL_URL = "https://github.com/apps/mergestorm-surge/installations/new";
|
|
269
|
-
export declare function surgeNotInstalledMessage(owner: string, repo: string, installUrl?: string): string;
|
|
270
274
|
export declare class LandedQueueReadError extends CommandError {
|
|
271
275
|
readonly status: number;
|
|
272
276
|
readonly retryAfterSeconds?: number | undefined;
|
|
@@ -336,7 +340,7 @@ export type StackPublicationRequest = {
|
|
|
336
340
|
};
|
|
337
341
|
autoLand?: boolean;
|
|
338
342
|
};
|
|
339
|
-
|
|
343
|
+
type StackPublicationStack = {
|
|
340
344
|
id: string;
|
|
341
345
|
autoPatchOverride: boolean | null;
|
|
342
346
|
autoLand: boolean;
|
|
@@ -383,7 +387,6 @@ export type StackPublication = {
|
|
|
383
387
|
};
|
|
384
388
|
stack: StackPublicationStack;
|
|
385
389
|
};
|
|
386
|
-
export declare const STACK_PUBLICATION_TIMEOUT_MS = 180000;
|
|
387
390
|
export declare function getStackPublication(cfg: Config, input: {
|
|
388
391
|
owner: string;
|
|
389
392
|
repo: string;
|
|
@@ -401,6 +404,55 @@ export declare function openStackIssue(input: {
|
|
|
401
404
|
url: string;
|
|
402
405
|
created: boolean;
|
|
403
406
|
}>;
|
|
407
|
+
export declare const ISSUE_REVIEW_STATES: readonly ["approved", "needs_answers", "pending", "unreviewed", "capped", "off"];
|
|
408
|
+
export type IssueReviewState = (typeof ISSUE_REVIEW_STATES)[number];
|
|
409
|
+
export type IssueReviewPoint = {
|
|
410
|
+
kind: string;
|
|
411
|
+
text: string;
|
|
412
|
+
};
|
|
413
|
+
export type IssueReviewStatus = {
|
|
414
|
+
owner: string;
|
|
415
|
+
repo: string;
|
|
416
|
+
number: number;
|
|
417
|
+
enabled: boolean;
|
|
418
|
+
state: IssueReviewState;
|
|
419
|
+
approvedBy: "vortex" | "human" | null;
|
|
420
|
+
round: number | null;
|
|
421
|
+
maxRounds: number;
|
|
422
|
+
verdict: "ready" | "ready_with_notes" | "needs_answers" | null;
|
|
423
|
+
summary: string | null;
|
|
424
|
+
points: IssueReviewPoint[];
|
|
425
|
+
commentUrl: string | null;
|
|
426
|
+
next: string;
|
|
427
|
+
};
|
|
428
|
+
export type IssueReviewTarget = {
|
|
429
|
+
owner: string;
|
|
430
|
+
repo: string;
|
|
431
|
+
number: number;
|
|
432
|
+
};
|
|
433
|
+
export declare const ISSUE_REVIEW_POLL_INTERVAL_MS = 10000;
|
|
434
|
+
export declare const ISSUE_REVIEW_DEFAULT_TIMEOUT_MS = 900000;
|
|
435
|
+
export declare function parseIssueReviewStatus(body: unknown, target: IssueReviewTarget): IssueReviewStatus | null;
|
|
436
|
+
export declare function getIssueReview(cfg: Config, target: IssueReviewTarget, opts?: {
|
|
437
|
+
timeoutMs?: number;
|
|
438
|
+
signal?: AbortSignal;
|
|
439
|
+
}): Promise<IssueReviewStatus | null>;
|
|
440
|
+
export declare class IssueReviewTimeoutError extends CommandError {
|
|
441
|
+
readonly lastStatus: IssueReviewStatus;
|
|
442
|
+
constructor(lastStatus: IssueReviewStatus);
|
|
443
|
+
}
|
|
444
|
+
export type PollIssueReviewOptions = {
|
|
445
|
+
timeoutMs?: number;
|
|
446
|
+
intervalMs?: number;
|
|
447
|
+
now?: () => number;
|
|
448
|
+
sleep?: (ms: number, signal?: AbortSignal) => Promise<void>;
|
|
449
|
+
signal?: AbortSignal;
|
|
450
|
+
onTick?: (status: IssueReviewStatus | null) => void;
|
|
451
|
+
};
|
|
452
|
+
export declare function pollIssueReview(cfg: Config, target: IssueReviewTarget, opts?: PollIssueReviewOptions): Promise<IssueReviewStatus | null>;
|
|
453
|
+
export declare function issueReviewLines(status: IssueReviewStatus): string[];
|
|
454
|
+
export declare function issueNotApprovedError(issues: IssueReviewStatus[], message?: string | null): CommandError;
|
|
455
|
+
export declare function issueNotApprovedRefusal(status: number, body: unknown, owner: string, repo: string): CommandError | null;
|
|
404
456
|
/**
|
|
405
457
|
* Patch any subset of one owned stack's automation policy
|
|
406
458
|
* (Bearer PATCH /api/v1/stacks/:id). `null` clears an override.
|
package/dist/api.js
CHANGED
|
@@ -157,6 +157,13 @@ export async function devicePost(base, route, json, opts = {}) {
|
|
|
157
157
|
}
|
|
158
158
|
return { status: res.status, body: parsed };
|
|
159
159
|
}
|
|
160
|
+
export function accountLabel(account) {
|
|
161
|
+
const login = account?.github_login?.trim();
|
|
162
|
+
if (login)
|
|
163
|
+
return login;
|
|
164
|
+
const email = account?.email?.trim();
|
|
165
|
+
return email || null;
|
|
166
|
+
}
|
|
160
167
|
export function isPositiveInteger(value) {
|
|
161
168
|
return typeof value === "number" && Number.isInteger(value) && value >= 1;
|
|
162
169
|
}
|
|
@@ -180,6 +187,7 @@ export const REPO_SETTINGS_SWITCH_KEYS = [
|
|
|
180
187
|
"auto_land_default",
|
|
181
188
|
"merge_queue_batch_enabled",
|
|
182
189
|
"merge_queue_overdrive",
|
|
190
|
+
"issue_review_enabled",
|
|
183
191
|
];
|
|
184
192
|
export const REPO_SETTINGS_KEYS = [...REPO_SETTINGS_SWITCH_KEYS, "merge_queue_batch_size", "merge_queue_lands_alone_paths"];
|
|
185
193
|
function repoSettingsFailure(status, body, retryAfterSeconds, action) {
|
|
@@ -293,6 +301,20 @@ export async function getMe(cfg, opts) {
|
|
|
293
301
|
return null;
|
|
294
302
|
}
|
|
295
303
|
}
|
|
304
|
+
export async function revokeOwnKey(cfg, opts) {
|
|
305
|
+
try {
|
|
306
|
+
const { status } = await apiFetch(cfg, "/api/v1/me/key", {
|
|
307
|
+
method: "DELETE",
|
|
308
|
+
timeoutMs: opts?.timeoutMs,
|
|
309
|
+
});
|
|
310
|
+
return status === 200;
|
|
311
|
+
}
|
|
312
|
+
catch (err) {
|
|
313
|
+
if (err instanceof CommandError)
|
|
314
|
+
return err.code === "auth_invalid";
|
|
315
|
+
return false;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
296
318
|
export async function listJobs(limit = 10, cfg, opts) {
|
|
297
319
|
const resolved = cfg ?? (await loadConfig());
|
|
298
320
|
const capped = Math.min(Math.max(limit, 1), 50);
|
|
@@ -432,6 +454,9 @@ export async function adoptStack(owner, repo, prNumber, cfg, policy) {
|
|
|
432
454
|
if (status === 429) {
|
|
433
455
|
throw new CommandError(rateLimitedMessage(retryAfterSeconds), REVIEW_EXIT.rate_limited, "rate_limited", { retryAfterSeconds });
|
|
434
456
|
}
|
|
457
|
+
const issueRefusal = issueNotApprovedRefusal(status, body, owner, repo);
|
|
458
|
+
if (issueRefusal)
|
|
459
|
+
throw issueRefusal;
|
|
435
460
|
if (status !== 200) {
|
|
436
461
|
const error = body && typeof body === "object" && "error" in body && typeof body.error === "string"
|
|
437
462
|
? body.error
|
|
@@ -469,13 +494,14 @@ const INFRASTRUCTURE_REFUSAL_CODES = [
|
|
|
469
494
|
"cyclone_not_connected",
|
|
470
495
|
"cyclone_not_installed",
|
|
471
496
|
"cyclone_permission_missing",
|
|
497
|
+
"surge_other_account",
|
|
472
498
|
];
|
|
473
499
|
function refusalReason(body) {
|
|
474
500
|
const reason = (body && typeof body === "object" ? body.reason : undefined);
|
|
475
501
|
return typeof reason === "string" && plainServerText(reason).trim() ? plainServerText(reason).trim() : undefined;
|
|
476
502
|
}
|
|
477
|
-
|
|
478
|
-
|
|
503
|
+
const SURGE_REFUSAL_FALLBACK = "Mergestorm Surge is not installed or not ready on this repository. Install it from Agents.";
|
|
504
|
+
function surgeRefusal(body) {
|
|
479
505
|
if (!body || typeof body !== "object")
|
|
480
506
|
return null;
|
|
481
507
|
const refusal = body;
|
|
@@ -489,7 +515,7 @@ export function surgeRefusal(body) {
|
|
|
489
515
|
const installUrl = githubAppInstallUrl(refusal.installUrl) ?? "";
|
|
490
516
|
return new CommandError(installUrl && !message.includes(installUrl) ? `${message} (${installUrl})` : message, 1, error, { reason });
|
|
491
517
|
}
|
|
492
|
-
|
|
518
|
+
const GITHUB_UNREADABLE_MESSAGE = "GitHub could not be read just now; try again.";
|
|
493
519
|
function serverMessage(message) {
|
|
494
520
|
if (typeof message !== "string")
|
|
495
521
|
return null;
|
|
@@ -518,8 +544,8 @@ export async function ensureUpperPark(stackId, cfg) {
|
|
|
518
544
|
created: body.created === true,
|
|
519
545
|
};
|
|
520
546
|
}
|
|
521
|
-
|
|
522
|
-
|
|
547
|
+
const SURGE_INSTALL_URL = "https://github.com/apps/mergestorm-surge/installations/new";
|
|
548
|
+
function surgeNotInstalledMessage(owner, repo, installUrl = SURGE_INSTALL_URL) {
|
|
523
549
|
return (`Opening PRs needs either the GitHub CLI (gh auth login) or Mergestorm Surge installed on ` +
|
|
524
550
|
`${owner}/${repo} (${installUrl}).`);
|
|
525
551
|
}
|
|
@@ -533,6 +559,9 @@ function stackPullFailure(status, body, owner, repo, failLabel) {
|
|
|
533
559
|
const surge = surgeRefusal(body);
|
|
534
560
|
if (surge)
|
|
535
561
|
return surge;
|
|
562
|
+
const issueRefusal = issueNotApprovedRefusal(status, body, owner, repo);
|
|
563
|
+
if (issueRefusal)
|
|
564
|
+
return issueRefusal;
|
|
536
565
|
const text = `${String(rejection.error ?? "")} ${String(rejection.message ?? "")}`;
|
|
537
566
|
if (rejection.error === "cyclone_not_installed" ||
|
|
538
567
|
/not installed|installation[^\n]*not found/i.test(text)) {
|
|
@@ -599,7 +628,7 @@ export async function openStackPull(cfg, input) {
|
|
|
599
628
|
created: row.created === true,
|
|
600
629
|
};
|
|
601
630
|
}
|
|
602
|
-
|
|
631
|
+
const STACK_PUBLICATION_TIMEOUT_MS = 180_000;
|
|
603
632
|
const PUBLICATION_ERROR_CODES = [
|
|
604
633
|
"head_changed",
|
|
605
634
|
"base_changed",
|
|
@@ -661,6 +690,166 @@ export async function openStackIssue(input, cfg) {
|
|
|
661
690
|
}
|
|
662
691
|
return { number: row.number, url: typeof row.url === "string" ? row.url : "", created: row.created === true };
|
|
663
692
|
}
|
|
693
|
+
export const ISSUE_REVIEW_STATES = ["approved", "needs_answers", "pending", "unreviewed", "capped", "off"];
|
|
694
|
+
export const ISSUE_REVIEW_POLL_INTERVAL_MS = 10_000;
|
|
695
|
+
export const ISSUE_REVIEW_DEFAULT_TIMEOUT_MS = 900_000;
|
|
696
|
+
const ISSUE_REVIEW_MAX_POINTS = 8;
|
|
697
|
+
const ISSUE_REVIEW_DEFAULT_MAX_ROUNDS = 4;
|
|
698
|
+
function issueReviewText(value) {
|
|
699
|
+
if (typeof value !== "string")
|
|
700
|
+
return null;
|
|
701
|
+
const plain = plainServerText(value).trim();
|
|
702
|
+
return plain ? plain : null;
|
|
703
|
+
}
|
|
704
|
+
export function parseIssueReviewStatus(body, target) {
|
|
705
|
+
if (!body || typeof body !== "object")
|
|
706
|
+
return null;
|
|
707
|
+
const row = body;
|
|
708
|
+
const state = ISSUE_REVIEW_STATES.find((known) => known === row.state);
|
|
709
|
+
if (!state)
|
|
710
|
+
return null;
|
|
711
|
+
const points = Array.isArray(row.points)
|
|
712
|
+
? row.points
|
|
713
|
+
.flatMap((point) => {
|
|
714
|
+
const text = issueReviewText(point?.text);
|
|
715
|
+
if (!text)
|
|
716
|
+
return [];
|
|
717
|
+
return [{ kind: issueReviewText(point.kind) ?? "note", text }];
|
|
718
|
+
})
|
|
719
|
+
.slice(0, ISSUE_REVIEW_MAX_POINTS)
|
|
720
|
+
: [];
|
|
721
|
+
const verdict = row.verdict === "ready" || row.verdict === "ready_with_notes" || row.verdict === "needs_answers" ? row.verdict : null;
|
|
722
|
+
return {
|
|
723
|
+
owner: typeof row.owner === "string" && row.owner ? row.owner : target.owner,
|
|
724
|
+
repo: typeof row.repo === "string" && row.repo ? row.repo : target.repo,
|
|
725
|
+
number: isPositiveInteger(row.number) ? row.number : target.number,
|
|
726
|
+
enabled: row.enabled === true,
|
|
727
|
+
state,
|
|
728
|
+
approvedBy: row.approvedBy === "vortex" || row.approvedBy === "human" ? row.approvedBy : null,
|
|
729
|
+
round: isPositiveInteger(row.round) ? row.round : null,
|
|
730
|
+
maxRounds: isPositiveInteger(row.maxRounds) ? row.maxRounds : ISSUE_REVIEW_DEFAULT_MAX_ROUNDS,
|
|
731
|
+
verdict,
|
|
732
|
+
summary: issueReviewText(row.summary),
|
|
733
|
+
points,
|
|
734
|
+
commentUrl: issueReviewText(row.commentUrl),
|
|
735
|
+
next: issueReviewText(row.next) ?? "",
|
|
736
|
+
};
|
|
737
|
+
}
|
|
738
|
+
export async function getIssueReview(cfg, target, opts = {}) {
|
|
739
|
+
const query = new URLSearchParams({ owner: target.owner, repo: target.repo }).toString();
|
|
740
|
+
const { status, body, retryAfterSeconds } = await apiFetch(cfg, `/api/v1/stacks/issues/${encodeURIComponent(String(target.number))}/review?${query}`, opts);
|
|
741
|
+
if (status === 404)
|
|
742
|
+
return null;
|
|
743
|
+
if (status === 429) {
|
|
744
|
+
throw new CommandError(rateLimitedMessage(retryAfterSeconds), REVIEW_EXIT.rate_limited, "rate_limited", retryAfterSeconds !== undefined ? { retryAfterSeconds } : undefined);
|
|
745
|
+
}
|
|
746
|
+
const parsed = status === 200 ? parseIssueReviewStatus(body, target) : null;
|
|
747
|
+
if (!parsed) {
|
|
748
|
+
const message = serverMessage(body?.message);
|
|
749
|
+
throw new CommandError(message ?? `Failed to read the issue review of ${target.owner}/${target.repo}#${target.number} (HTTP ${status})`, 1, status >= 500 ? "issue_review_unavailable" : undefined);
|
|
750
|
+
}
|
|
751
|
+
return parsed;
|
|
752
|
+
}
|
|
753
|
+
export class IssueReviewTimeoutError extends CommandError {
|
|
754
|
+
lastStatus;
|
|
755
|
+
constructor(lastStatus) {
|
|
756
|
+
super(`Timed out waiting for the Vortex review of ${lastStatus.owner}/${lastStatus.repo}#${lastStatus.number}. Run \`mergestorm issue wait ${lastStatus.number}\` again.`, REVIEW_EXIT.timeout, "review_timeout");
|
|
757
|
+
this.name = "IssueReviewTimeoutError";
|
|
758
|
+
this.lastStatus = lastStatus;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
function abortableSleep(ms, signal) {
|
|
762
|
+
return new Promise((resolve, reject) => {
|
|
763
|
+
const abortError = () => Object.assign(new Error("Aborted"), { name: "AbortError" });
|
|
764
|
+
if (signal?.aborted) {
|
|
765
|
+
reject(abortError());
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
768
|
+
const onAbort = () => {
|
|
769
|
+
clearTimeout(timer);
|
|
770
|
+
reject(abortError());
|
|
771
|
+
};
|
|
772
|
+
const timer = setTimeout(() => {
|
|
773
|
+
signal?.removeEventListener("abort", onAbort);
|
|
774
|
+
resolve();
|
|
775
|
+
}, ms);
|
|
776
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
777
|
+
});
|
|
778
|
+
}
|
|
779
|
+
function isTransientIssueReviewError(err) {
|
|
780
|
+
if (!(err instanceof Error) || err.name === "AbortError")
|
|
781
|
+
return false;
|
|
782
|
+
if (err instanceof CommandError) {
|
|
783
|
+
return err.code === "api_timeout" || err.code === "issue_review_unavailable" || err.code === "rate_limited";
|
|
784
|
+
}
|
|
785
|
+
return /fetch failed|ECONNRESET|ETIMEDOUT|ENOTFOUND|EAI_AGAIN|socket hang up|network/i.test(err.message);
|
|
786
|
+
}
|
|
787
|
+
export async function pollIssueReview(cfg, target, opts = {}) {
|
|
788
|
+
const timeoutMs = opts.timeoutMs ?? ISSUE_REVIEW_DEFAULT_TIMEOUT_MS;
|
|
789
|
+
const intervalMs = opts.intervalMs ?? ISSUE_REVIEW_POLL_INTERVAL_MS;
|
|
790
|
+
const now = opts.now ?? Date.now;
|
|
791
|
+
const wait = opts.sleep ?? abortableSleep;
|
|
792
|
+
const deadline = now() + timeoutMs;
|
|
793
|
+
let last = null;
|
|
794
|
+
let failure = null;
|
|
795
|
+
for (;;) {
|
|
796
|
+
try {
|
|
797
|
+
const status = await getIssueReview(cfg, target, { signal: opts.signal });
|
|
798
|
+
if (!status || status.state !== "pending")
|
|
799
|
+
return status;
|
|
800
|
+
last = status;
|
|
801
|
+
opts.onTick?.(status);
|
|
802
|
+
}
|
|
803
|
+
catch (err) {
|
|
804
|
+
if (!isTransientIssueReviewError(err) || now() >= deadline)
|
|
805
|
+
throw err;
|
|
806
|
+
failure = err;
|
|
807
|
+
opts.onTick?.(null);
|
|
808
|
+
}
|
|
809
|
+
const remaining = deadline - now();
|
|
810
|
+
if (remaining <= 0) {
|
|
811
|
+
if (last)
|
|
812
|
+
throw new IssueReviewTimeoutError(last);
|
|
813
|
+
throw failure;
|
|
814
|
+
}
|
|
815
|
+
await wait(Math.min(intervalMs, remaining), opts.signal);
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
export function issueReviewLines(status) {
|
|
819
|
+
const round = status.round ? ` (round ${status.round} of ${status.maxRounds})` : "";
|
|
820
|
+
const lines = [`${status.owner}/${status.repo}#${status.number}: ${status.state}${round}`];
|
|
821
|
+
if (status.summary)
|
|
822
|
+
lines.push(` ${status.summary}`);
|
|
823
|
+
status.points.forEach((point, i) => lines.push(` ${i + 1}. [${point.kind}] ${point.text}`));
|
|
824
|
+
if (status.commentUrl)
|
|
825
|
+
lines.push(` Review: ${status.commentUrl}`);
|
|
826
|
+
if (status.next)
|
|
827
|
+
lines.push(` Next: ${status.next}`);
|
|
828
|
+
return lines;
|
|
829
|
+
}
|
|
830
|
+
export function issueNotApprovedError(issues, message) {
|
|
831
|
+
const lines = [message?.trim() || "Vortex has not approved the linked issue yet; refusing to open the pull request."];
|
|
832
|
+
for (const issue of issues) {
|
|
833
|
+
lines.push(...issueReviewLines(issue));
|
|
834
|
+
lines.push(` Reply in a comment on #${issue.number}, then run \`mergestorm issue wait ${issue.number}\`.`);
|
|
835
|
+
}
|
|
836
|
+
return new CommandError(lines.join("\n"), REVIEW_EXIT.failed, "issue_not_approved");
|
|
837
|
+
}
|
|
838
|
+
export function issueNotApprovedRefusal(status, body, owner, repo) {
|
|
839
|
+
if (status !== 409 || !body || typeof body !== "object")
|
|
840
|
+
return null;
|
|
841
|
+
const refusal = body;
|
|
842
|
+
if (refusal.error !== "issue_not_approved")
|
|
843
|
+
return null;
|
|
844
|
+
const issues = Array.isArray(refusal.issues)
|
|
845
|
+
? refusal.issues.flatMap((issue) => {
|
|
846
|
+
const n = issue?.number;
|
|
847
|
+
const parsed = parseIssueReviewStatus(issue, { owner, repo, number: isPositiveInteger(n) ? n : 0 });
|
|
848
|
+
return parsed ? [parsed] : [];
|
|
849
|
+
})
|
|
850
|
+
: [];
|
|
851
|
+
return issueNotApprovedError(issues, serverMessage(refusal.message));
|
|
852
|
+
}
|
|
664
853
|
async function stackMutation(stackId, pathSuffix, method, json, failLabel, cfg) {
|
|
665
854
|
const resolved = cfg ?? (await loadConfig());
|
|
666
855
|
const { status, body } = await apiFetch(resolved, `/api/v1/stacks/${encodeURIComponent(stackId)}${pathSuffix}`, method === "PATCH"
|
|
@@ -42,6 +42,10 @@ export declare const BEARER_SETTINGS: readonly [{
|
|
|
42
42
|
readonly key: "vortex_seam_specialist_enabled";
|
|
43
43
|
readonly flag: "--vortex-seam";
|
|
44
44
|
readonly label: "Vortex seam specialist";
|
|
45
|
+
}, {
|
|
46
|
+
readonly key: "issue_review_enabled";
|
|
47
|
+
readonly flag: "--issue-review";
|
|
48
|
+
readonly label: "Vortex issue reviews";
|
|
45
49
|
}, {
|
|
46
50
|
readonly key: "auto_land_default";
|
|
47
51
|
readonly flag: "--auto-land";
|
|
@@ -112,4 +116,4 @@ export type BearerSettingsValues = {
|
|
|
112
116
|
values: readonly (infer Value)[];
|
|
113
117
|
} ? Value : boolean;
|
|
114
118
|
};
|
|
115
|
-
export declare const BEARER_BOOLEAN_SETTINGS_KEYS: ("auto_review_enabled" | "auto_patch_enabled" | "auto_resolve_conflicts_enabled" | "auto_fix_ci_enabled" | "vortex_show_thinking_traces" | "repo_overview_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" | "merge_queue_batch_enabled" | "merge_queue_batch_size" | "merge_queue_lands_alone_paths" | "merge_queue_overdrive" | "ignored_bot_logins" | "vortex_bot_skip_check" | "vortex_findings_check" | "cyclone_patch_failure_check")[];
|
|
119
|
+
export declare const BEARER_BOOLEAN_SETTINGS_KEYS: ("auto_review_enabled" | "auto_patch_enabled" | "auto_resolve_conflicts_enabled" | "auto_fix_ci_enabled" | "vortex_show_thinking_traces" | "repo_overview_enabled" | "cyclone_skip_ci_enabled" | "cyclone_patch_unverified_languages" | "vortex_auto_overflow_enabled" | "vortex_skip_all_clear_comments" | "vortex_seam_specialist_enabled" | "issue_review_enabled" | "auto_land_default" | "auto_land_settle_seconds" | "merge_queue_batch_enabled" | "merge_queue_batch_size" | "merge_queue_lands_alone_paths" | "merge_queue_overdrive" | "ignored_bot_logins" | "vortex_bot_skip_check" | "vortex_findings_check" | "cyclone_patch_failure_check")[];
|
|
@@ -10,6 +10,7 @@ export const BEARER_SETTINGS = [
|
|
|
10
10
|
{ key: "vortex_auto_overflow_enabled", flag: "--vortex-auto-overflow", label: "Vortex auto overflow" },
|
|
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
|
+
{ key: "issue_review_enabled", flag: "--issue-review", label: "Vortex issue reviews" },
|
|
13
14
|
{ key: "auto_land_default", flag: "--auto-land", label: "Auto land (new stacks)" },
|
|
14
15
|
{ key: "auto_land_settle_seconds", flag: "--auto-land-settle", label: "Auto land settle (seconds)", kind: "seconds", min: 15, max: 300 },
|
|
15
16
|
{ key: "merge_queue_batch_enabled", flag: "--merge-queue-batch", label: "Merge queue batching" },
|
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { stdin as input, stdout as output } from "node:process";
|
|
3
|
+
import { splitAccountFlag, withAccount } from "./config.js";
|
|
3
4
|
import { CommandError } from "./errors.js";
|
|
4
5
|
import { dispatchCommand, formatUsageBody, } from "./commands/registry.js";
|
|
5
6
|
import { isSupportedNode, unsupportedNodeMessage, } from "./node-version.js";
|
|
@@ -17,37 +18,38 @@ function usage() {
|
|
|
17
18
|
${formatUsageBody()}
|
|
18
19
|
`);
|
|
19
20
|
}
|
|
20
|
-
async function runCommand(cmd, args) {
|
|
21
|
+
async function runCommand(cmd, args, account) {
|
|
21
22
|
if (cmd === "help" || cmd === "?") {
|
|
22
23
|
usage();
|
|
23
24
|
return;
|
|
24
25
|
}
|
|
25
|
-
const ok = await dispatchCommand(cmd, args, { mode: "oneshot" });
|
|
26
|
+
const ok = await dispatchCommand(cmd, args, { mode: "oneshot", account });
|
|
26
27
|
if (!ok) {
|
|
27
28
|
usage();
|
|
28
29
|
throw new CommandError(`unknown command: ${cmd}`);
|
|
29
30
|
}
|
|
30
31
|
}
|
|
31
32
|
async function main() {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
try {
|
|
34
|
+
const { account, args: argv } = splitAccountFlag(process.argv.slice(2));
|
|
35
|
+
const [cmd, ...args] = argv;
|
|
36
|
+
if (!cmd) {
|
|
37
|
+
if (input.isTTY && output.isTTY) {
|
|
38
|
+
await withAccount(account, () => runShell());
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
usage();
|
|
36
42
|
return;
|
|
37
43
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
try {
|
|
50
|
-
await runCommand(cmd, args);
|
|
44
|
+
if (cmd === "-h" || cmd === "--help" || cmd === "help" || cmd === "?") {
|
|
45
|
+
usage();
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
if (cmd === "-v" || cmd === "--version" || cmd === "version") {
|
|
49
|
+
console.log(cliVersion());
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
await runCommand(cmd, args, account);
|
|
51
53
|
}
|
|
52
54
|
catch (err) {
|
|
53
55
|
if (err instanceof CommandError) {
|
package/dist/client/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { DEFAULT_API,
|
|
1
|
+
export { ACCOUNT_LIMIT, DEFAULT_API, accountNameFromMe, apiBase, configPath, keyDisplay, listAccounts, loadConfig, mergestormHome, removeAccount, resolveApiKey, saveAccount, settleAccountName, splitAccountFlag, useAccount, withAccount, type AccountSummary, type Config, type StoredAccount, } from "../config.js";
|
|
2
2
|
export { BEARER_SETTINGS, BEARER_BOOLEAN_SETTINGS_KEYS, BEARER_SETTINGS_FLAGS, BEARER_SETTINGS_KEYS, BEARER_SETTINGS_LABELS, type BearerSettingsKey, } from "../automation-catalog.js";
|
|
3
|
-
export { API_TIMEOUT_PREFIX, DEFAULT_API_TIMEOUT_MS, SETTINGS_WRITABLE_KEYS, adoptStack, apiFetch, cancelMergeQueueEntry, devicePost, dismissPrFindings, dismissThreadsLine, enqueueStack, ensureUpperPark, getEnrichedStack, getMe, getPrVortexReview, getReview, getSettings, listRepoSettings, patchRepoSettings, REPO_SETTINGS_KEYS, getStackPublication, landNextStack, listJobs, listMergeQueueEntries, listStacks, listThreads, openStackIssue, parseRetryAfterSeconds, patchSettings, restackStack, setStackPolicy, stackPolicyBody, submitStackPublication, type ApiFetchInit, type ApiFetchResult, type JobListItem, type MeResponse, type MergeQueueBounceDetail, type MergeQueueBounceKind, type MergeQueueEnqueuedBy, type MergeQueueEnqueuedVia, type MergeQueueEntryDto, type MergeQueueEntryState, type PrDismissedFinding, type PrFindingDismissInput, type PrFindingDismissOutcome, type PrFindingDismissResult, type PrReviewFinding, type PrReviewFindings, type PrVortexReview, type SettingsPatch, type RepoSettings, type RepoSettingsKey, type RepoSettingsPatch, type SettingsResponse, type StackDto, type StackPolicyPatch, type StackPublication, type StackPublicationRequest, type StackPublicationStatus, type ThreadDetail, type ThreadListItem, } from "../api.js";
|
|
3
|
+
export { API_TIMEOUT_PREFIX, DEFAULT_API_TIMEOUT_MS, SETTINGS_WRITABLE_KEYS, adoptStack, accountLabel, apiFetch, cancelMergeQueueEntry, devicePost, dismissPrFindings, dismissThreadsLine, enqueueStack, ensureUpperPark, getEnrichedStack, getIssueReview, ISSUE_REVIEW_DEFAULT_TIMEOUT_MS, ISSUE_REVIEW_POLL_INTERVAL_MS, ISSUE_REVIEW_STATES, IssueReviewTimeoutError, issueNotApprovedError, issueNotApprovedRefusal, issueReviewLines, parseIssueReviewStatus, pollIssueReview, type IssueReviewPoint, type IssueReviewState, type IssueReviewStatus, type IssueReviewTarget, type PollIssueReviewOptions, getMe, getPrVortexReview, revokeOwnKey, getReview, getSettings, listRepoSettings, patchRepoSettings, REPO_SETTINGS_KEYS, getStackPublication, landNextStack, listJobs, listMergeQueueEntries, listStacks, listThreads, openStackIssue, parseRetryAfterSeconds, patchSettings, restackStack, setStackPolicy, stackPolicyBody, submitStackPublication, type ApiFetchInit, type ApiFetchResult, type JobListItem, type AccountIdentity, type MeResponse, type MergeQueueBounceDetail, type MergeQueueBounceKind, type MergeQueueEnqueuedBy, type MergeQueueEnqueuedVia, type MergeQueueEntryDto, type MergeQueueEntryState, type PrDismissedFinding, type PrFindingDismissInput, type PrFindingDismissOutcome, type PrFindingDismissResult, type PrReviewFinding, type PrReviewFindings, type PrVortexReview, type SettingsPatch, type RepoSettings, type RepoSettingsKey, type RepoSettingsPatch, type SettingsResponse, type StackDto, type StackPolicyPatch, type StackPublication, type StackPublicationRequest, type StackPublicationStatus, type ThreadDetail, type ThreadListItem, } from "../api.js";
|
|
4
4
|
export { CommandError, DetachedError, RATE_LIMITED_HINT, REVIEW_EXIT, isCommandErrorCode, rateLimitedMessage, type CommandErrorCode, type CommandErrorExtras, } from "../errors.js";
|
|
5
5
|
export { REVIEW_POLL_BACKOFF_MS, REVIEW_POLL_DEFAULT_TIMEOUT_MS, REVIEW_POLL_INTERVAL_MS, REVIEW_POLL_MAX_INTERVAL_MS, REVIEW_POLL_MAX_TRANSIENT_RETRIES, REVIEW_POLL_STRETCH_AFTER_MS, REVIEW_POLL_STRETCH_SPAN_MS, REVIEW_THREAD_SLUG_RE, PrReviewPollTimeoutError, ReviewPollTimeoutError, noPrReviewYetMessage, collectReviewInput, formatReviewSubmitError, isTransientReviewPollError, isTransientReviewPollStatus, loadReviewContext, pollPrVortexReview, pollReview, stretchedPollIntervalMs, submitReview, transientRetryWaitMs, type PollReviewOptions, type PollPrVortexReviewOptions, type ReviewInput, type SubmitReviewOptions, } from "../commands/review-client.js";
|
|
6
6
|
export { REVIEW_JOB_ENVELOPE_SCHEMA, toReviewJobEnvelope, type ReviewEnvelopeFallbacks, type ReviewJobEnvelope, type ReviewJobRow, } from "../ui/job-envelope.js";
|
|
@@ -12,3 +12,4 @@ export { BREEZE_BRANCH_PREFIX, stackBlockers, stackBlockersSummary, sameHead, la
|
|
|
12
12
|
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";
|
|
13
13
|
export { READ_ONLY_GIT, publishBranchServerSide, publishWorkingBranch, workingBranchPublication, type GitRead, type ServerPublishDeps, type ServerPublishInput, type ServerPublishResult, type WorkingBranchInput, } from "../server-publish.js";
|
|
14
14
|
export { MEMORY_KINDS, MEMORY_MODES, MEMORY_SCOPES, MEMORY_SEARCH_LIMIT_MAX, deleteMemory, getMemoryMode, listMemories, memoryChatId, saveMemory, searchMemories, setMemoryMode, updateMemory, type MemoryItem, type MemoryKind, type MemoryList, type MemoryMode, type MemoryScope, type MemorySearch, } from "../memory-api.js";
|
|
15
|
+
export { WEB_SEARCH_KINDS, WEB_SEARCH_PAGE_MAX, WEB_SEARCH_RECENCIES, readWebPage, searchWeb, type WebSearchInput, type WebText, } from "../web-api.js";
|
package/dist/client/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { DEFAULT_API,
|
|
1
|
+
export { ACCOUNT_LIMIT, DEFAULT_API, accountNameFromMe, apiBase, configPath, keyDisplay, listAccounts, loadConfig, mergestormHome, removeAccount, resolveApiKey, saveAccount, settleAccountName, splitAccountFlag, useAccount, withAccount, } from "../config.js";
|
|
2
2
|
export { BEARER_SETTINGS, BEARER_BOOLEAN_SETTINGS_KEYS, BEARER_SETTINGS_FLAGS, BEARER_SETTINGS_KEYS, BEARER_SETTINGS_LABELS, } from "../automation-catalog.js";
|
|
3
|
-
export { API_TIMEOUT_PREFIX, DEFAULT_API_TIMEOUT_MS, SETTINGS_WRITABLE_KEYS, adoptStack, apiFetch, cancelMergeQueueEntry, devicePost, dismissPrFindings, dismissThreadsLine, enqueueStack, ensureUpperPark, getEnrichedStack, getMe, getPrVortexReview, getReview, getSettings, listRepoSettings, patchRepoSettings, REPO_SETTINGS_KEYS, getStackPublication, landNextStack, listJobs, listMergeQueueEntries, listStacks, listThreads, openStackIssue, parseRetryAfterSeconds, patchSettings, restackStack, setStackPolicy, stackPolicyBody, submitStackPublication, } from "../api.js";
|
|
3
|
+
export { API_TIMEOUT_PREFIX, DEFAULT_API_TIMEOUT_MS, SETTINGS_WRITABLE_KEYS, adoptStack, accountLabel, apiFetch, cancelMergeQueueEntry, devicePost, dismissPrFindings, dismissThreadsLine, enqueueStack, ensureUpperPark, getEnrichedStack, getIssueReview, ISSUE_REVIEW_DEFAULT_TIMEOUT_MS, ISSUE_REVIEW_POLL_INTERVAL_MS, ISSUE_REVIEW_STATES, IssueReviewTimeoutError, issueNotApprovedError, issueNotApprovedRefusal, issueReviewLines, parseIssueReviewStatus, pollIssueReview, getMe, getPrVortexReview, revokeOwnKey, getReview, getSettings, listRepoSettings, patchRepoSettings, REPO_SETTINGS_KEYS, getStackPublication, landNextStack, listJobs, listMergeQueueEntries, listStacks, listThreads, openStackIssue, parseRetryAfterSeconds, patchSettings, restackStack, setStackPolicy, stackPolicyBody, submitStackPublication, } from "../api.js";
|
|
4
4
|
export { CommandError, DetachedError, RATE_LIMITED_HINT, REVIEW_EXIT, isCommandErrorCode, rateLimitedMessage, } from "../errors.js";
|
|
5
5
|
export { REVIEW_POLL_BACKOFF_MS, REVIEW_POLL_DEFAULT_TIMEOUT_MS, REVIEW_POLL_INTERVAL_MS, REVIEW_POLL_MAX_INTERVAL_MS, REVIEW_POLL_MAX_TRANSIENT_RETRIES, REVIEW_POLL_STRETCH_AFTER_MS, REVIEW_POLL_STRETCH_SPAN_MS, REVIEW_THREAD_SLUG_RE, PrReviewPollTimeoutError, ReviewPollTimeoutError, noPrReviewYetMessage, collectReviewInput, formatReviewSubmitError, isTransientReviewPollError, isTransientReviewPollStatus, loadReviewContext, pollPrVortexReview, pollReview, stretchedPollIntervalMs, submitReview, transientRetryWaitMs, } from "../commands/review-client.js";
|
|
6
6
|
export { REVIEW_JOB_ENVELOPE_SCHEMA, toReviewJobEnvelope, } from "../ui/job-envelope.js";
|
|
@@ -12,3 +12,4 @@ export { BREEZE_BRANCH_PREFIX, stackBlockers, stackBlockersSummary, sameHead, la
|
|
|
12
12
|
export { STACK_WATCH_NOT_DONE_SENTENCE, STACK_WATCH_NOTIFY_PATTERN, stackWatchBackgroundCommand, stackTerminalReason, stackWatchNextArgs, stackWatchObligation, } from "../stack-watch-obligation.js";
|
|
13
13
|
export { READ_ONLY_GIT, publishBranchServerSide, publishWorkingBranch, workingBranchPublication, } from "../server-publish.js";
|
|
14
14
|
export { MEMORY_KINDS, MEMORY_MODES, MEMORY_SCOPES, MEMORY_SEARCH_LIMIT_MAX, deleteMemory, getMemoryMode, listMemories, memoryChatId, saveMemory, searchMemories, setMemoryMode, updateMemory, } from "../memory-api.js";
|
|
15
|
+
export { WEB_SEARCH_KINDS, WEB_SEARCH_PAGE_MAX, WEB_SEARCH_RECENCIES, readWebPage, searchWeb, } from "../web-api.js";
|