@devflow-one/cli 0.1.9 → 0.1.11
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 +4 -3
- package/package.json +1 -1
- package/src/cli.js +9 -5
- package/src/client.js +21 -1
- package/src/commands.js +11 -1
package/README.md
CHANGED
|
@@ -166,9 +166,10 @@ devflow mr create "Title" feat/x --body "desc" --project ABC
|
|
|
166
166
|
# pattern is expanded to the newest matching remote branch), or pick one
|
|
167
167
|
devflow mr create "Title" feat/x --base release/2026.4 --project ABC
|
|
168
168
|
|
|
169
|
-
# PR type: the
|
|
170
|
-
#
|
|
171
|
-
#
|
|
169
|
+
# PR type: supplies the description/title templates and the labels the PR is
|
|
170
|
+
# stamped with. Omitted or unrecognized, it is auto-selected by matching configured
|
|
171
|
+
# type names against the title's conventional prefix, branch prefix, Jira issue type
|
|
172
|
+
# and title keywords, falling back to the first type. Pass its id or label to pick one.
|
|
172
173
|
devflow mr create "Title" feat/x --type Bugfix --project ABC
|
|
173
174
|
devflow mr types --project ABC # configured types: id, label, default flag
|
|
174
175
|
|
package/package.json
CHANGED
package/src/cli.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { parseArgs } from "./args.js";
|
|
6
6
|
import { resolveConfig, ConfigError } from "./config.js";
|
|
7
|
-
import { gatewayRequest, GatewayError } from "./client.js";
|
|
7
|
+
import { gatewayRequest, GatewayError, retryHint } from "./client.js";
|
|
8
8
|
import { resolveCommand, listCommands, UsageError } from "./commands.js";
|
|
9
9
|
import {
|
|
10
10
|
createContextQuery,
|
|
@@ -86,17 +86,21 @@ function printWarnings(result, stderr) {
|
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
/** Print an error, honoring --json, to stderr. */
|
|
90
|
-
function printError(err, json, stderr) {
|
|
89
|
+
/** Print an error (plus an optional retry hint), honoring --json, to stderr. */
|
|
90
|
+
function printError(err, json, stderr, hint) {
|
|
91
91
|
const code = err instanceof GatewayError ? err.code : err.name;
|
|
92
92
|
|
|
93
93
|
if (json) {
|
|
94
|
-
|
|
94
|
+
const error = { code, message: err.message, delivered: err.delivered, hint };
|
|
95
|
+
|
|
96
|
+
stderr(JSON.stringify({ ok: false, error }, null, 2));
|
|
95
97
|
|
|
96
98
|
return;
|
|
97
99
|
}
|
|
98
100
|
|
|
99
101
|
stderr(`error${code ? ` [${code}]` : ""}: ${err.message}`);
|
|
102
|
+
|
|
103
|
+
if (hint) stderr(`hint: ${hint}`);
|
|
100
104
|
}
|
|
101
105
|
|
|
102
106
|
/**
|
|
@@ -231,7 +235,7 @@ export async function run(argv, io = {}) {
|
|
|
231
235
|
return 0;
|
|
232
236
|
} catch (err) {
|
|
233
237
|
if (err instanceof UsageError || err instanceof GatewayError) {
|
|
234
|
-
printError(err, Boolean(flags.json), stderr);
|
|
238
|
+
printError(err, Boolean(flags.json), stderr, retryHint(err, command.retryUnsafe));
|
|
235
239
|
|
|
236
240
|
return 1;
|
|
237
241
|
}
|
package/src/client.js
CHANGED
|
@@ -9,15 +9,34 @@ export class GatewayError extends Error {
|
|
|
9
9
|
* @param {string} [code]
|
|
10
10
|
* @param {unknown} [result] the envelope's `result`, which some failures still
|
|
11
11
|
* carry — `/context` reports its ambiguity candidates there.
|
|
12
|
+
* @param {boolean} [delivered] on a TIMEOUT, whether the profile had already
|
|
13
|
+
* picked the action up (undefined from daemons that predate the flag).
|
|
12
14
|
*/
|
|
13
|
-
constructor(message, code, result) {
|
|
15
|
+
constructor(message, code, result, delivered) {
|
|
14
16
|
super(message);
|
|
15
17
|
this.name = "GatewayError";
|
|
16
18
|
this.code = code;
|
|
17
19
|
this.result = result;
|
|
20
|
+
this.delivered = delivered;
|
|
18
21
|
}
|
|
19
22
|
}
|
|
20
23
|
|
|
24
|
+
export const RETRY_HINT =
|
|
25
|
+
"The action may have completed — verify (e.g. findPrByIssueKey) before retrying.";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The "verify before retrying" hint for a TIMEOUT of a retry-unsafe action
|
|
29
|
+
* that may already have run; undefined when a retry is safe.
|
|
30
|
+
* @param {unknown} err
|
|
31
|
+
* @param {boolean} [retryUnsafe]
|
|
32
|
+
*/
|
|
33
|
+
export function retryHint(err, retryUnsafe) {
|
|
34
|
+
const mayHaveRun =
|
|
35
|
+
err instanceof GatewayError && err.code === "TIMEOUT" && err.delivered !== false;
|
|
36
|
+
|
|
37
|
+
return retryUnsafe && mayHaveRun ? RETRY_HINT : undefined;
|
|
38
|
+
}
|
|
39
|
+
|
|
21
40
|
/**
|
|
22
41
|
* Turn a network-level failure into an actionable message. ECONNREFUSED almost
|
|
23
42
|
* always means the daemon isn't running.
|
|
@@ -83,5 +102,6 @@ export async function gatewayRequest(config, method, path, body) {
|
|
|
83
102
|
error.message ?? `Gateway error (HTTP ${response.status}).`,
|
|
84
103
|
error.code,
|
|
85
104
|
envelope?.result,
|
|
105
|
+
error.delivered,
|
|
86
106
|
);
|
|
87
107
|
}
|
package/src/commands.js
CHANGED
|
@@ -93,6 +93,7 @@ export class UsageError extends Error {
|
|
|
93
93
|
* @property {string} [path] For GET commands.
|
|
94
94
|
* @property {string} [action] Gateway action name for POST commands.
|
|
95
95
|
* @property {boolean} [destructive] Requires --force/--yes (gated by cli.js).
|
|
96
|
+
* @property {boolean} [retryUnsafe] A retry may repeat its side effect; a TIMEOUT warns to verify first.
|
|
96
97
|
* @property {(pos: string[], flags: Record<string, unknown>, context?: object) => unknown[]} [buildArgs]
|
|
97
98
|
* @property {string} usage One-line usage string.
|
|
98
99
|
*/
|
|
@@ -118,6 +119,7 @@ const COMMANDS = {
|
|
|
118
119
|
|
|
119
120
|
"branch create": {
|
|
120
121
|
method: "POST",
|
|
122
|
+
retryUnsafe: true,
|
|
121
123
|
action: "createBranch",
|
|
122
124
|
usage: "branch create <branchName> [--issue KEY] [--project KEY]",
|
|
123
125
|
buildArgs: ([branchName]) => {
|
|
@@ -128,6 +130,7 @@ const COMMANDS = {
|
|
|
128
130
|
},
|
|
129
131
|
"branch delete": {
|
|
130
132
|
method: "POST",
|
|
133
|
+
retryUnsafe: true,
|
|
131
134
|
action: "deleteBranch",
|
|
132
135
|
destructive: true,
|
|
133
136
|
usage: "branch delete <branchName> [--issue KEY] [--project KEY] --force",
|
|
@@ -140,6 +143,7 @@ const COMMANDS = {
|
|
|
140
143
|
|
|
141
144
|
"commit template": {
|
|
142
145
|
method: "POST",
|
|
146
|
+
retryUnsafe: true,
|
|
143
147
|
action: "commitByTemplate",
|
|
144
148
|
usage:
|
|
145
149
|
'commit template <worktreePath> [--values \'{"key":"val"}\'] [--no-push] [--issue KEY] [--project KEY]' +
|
|
@@ -159,12 +163,14 @@ const COMMANDS = {
|
|
|
159
163
|
|
|
160
164
|
"mr create": {
|
|
161
165
|
method: "POST",
|
|
166
|
+
retryUnsafe: true,
|
|
162
167
|
action: "createPullRequest",
|
|
163
168
|
usage:
|
|
164
169
|
"mr create <title> <headBranch> [--body <text>] [--base <branch>] [--type <idOrLabel>]" +
|
|
165
170
|
" [--issue KEY] [--project KEY]" +
|
|
166
171
|
" (--base defaults to the repo's configured base branch, expanding a {year}/{number} pattern;" +
|
|
167
|
-
" --type
|
|
172
|
+
" --type is auto-selected by matching PR type names against the title prefix, branch prefix," +
|
|
173
|
+
" Jira issue type and title keywords, falling back to the first configured type)",
|
|
168
174
|
buildArgs: ([title, headBranch], flags) => {
|
|
169
175
|
if (!title || !headBranch) {
|
|
170
176
|
throw new UsageError("mr create requires <title> and <headBranch>.");
|
|
@@ -198,6 +204,7 @@ const COMMANDS = {
|
|
|
198
204
|
},
|
|
199
205
|
"mr close": {
|
|
200
206
|
method: "POST",
|
|
207
|
+
retryUnsafe: true,
|
|
201
208
|
action: "closePullRequest",
|
|
202
209
|
destructive: true,
|
|
203
210
|
usage: "mr close <prId> [--issue KEY] [--project KEY] --force",
|
|
@@ -205,6 +212,7 @@ const COMMANDS = {
|
|
|
205
212
|
},
|
|
206
213
|
"mr merge": {
|
|
207
214
|
method: "POST",
|
|
215
|
+
retryUnsafe: true,
|
|
208
216
|
action: "mergePullRequest",
|
|
209
217
|
destructive: true,
|
|
210
218
|
usage:
|
|
@@ -308,6 +316,7 @@ const COMMANDS = {
|
|
|
308
316
|
},
|
|
309
317
|
"pipeline retry": {
|
|
310
318
|
method: "POST",
|
|
319
|
+
retryUnsafe: true,
|
|
311
320
|
action: "restartFailedJobs",
|
|
312
321
|
usage: "pipeline retry <pipelineOrRunId> [--all] [--job <jobId>] [--issue KEY] [--project KEY]",
|
|
313
322
|
buildArgs: ([id], flags) => {
|
|
@@ -328,6 +337,7 @@ const COMMANDS = {
|
|
|
328
337
|
|
|
329
338
|
"slack notify": {
|
|
330
339
|
method: "POST",
|
|
340
|
+
retryUnsafe: true,
|
|
331
341
|
action: "notifySlack",
|
|
332
342
|
usage:
|
|
333
343
|
'slack notify <message> [--channel ID] [--values \'{"key":"val"}\'] [--issue KEY] [--project KEY]',
|