@devflow-one/cli 0.1.5 → 0.1.7
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 +15 -0
- package/package.json +1 -1
- package/src/commands.js +51 -3
- package/src/context.js +8 -2
- package/src/contextResolver.js +10 -2
package/README.md
CHANGED
|
@@ -162,6 +162,21 @@ devflow branch create feat/x
|
|
|
162
162
|
devflow branch create feat/x --project ABC
|
|
163
163
|
devflow mr create "Title" feat/x --body "desc" --project ABC
|
|
164
164
|
|
|
165
|
+
# target branch: the repo's configured base branch by default (a {year}/{number}
|
|
166
|
+
# pattern is expanded to the newest matching remote branch), or pick one
|
|
167
|
+
devflow mr create "Title" feat/x --base release/2026.4 --project ABC
|
|
168
|
+
|
|
169
|
+
# PR type: the project's first configured type by default — it supplies the
|
|
170
|
+
# description/title templates and the labels the PR is stamped with. Pass its id
|
|
171
|
+
# or its label to pick another; an unrecognized value falls back to that default.
|
|
172
|
+
devflow mr create "Title" feat/x --type Bugfix --project ABC
|
|
173
|
+
devflow mr types --project ABC # configured types: id, label, default flag
|
|
174
|
+
|
|
175
|
+
# issue key: parsed from the head branch by default; --issue sets it explicitly
|
|
176
|
+
# ({parentWithChildIssueKeys}/{issueKey}/{issueTitle} template tokens) for a branch without one.
|
|
177
|
+
# {issueTitle} needs the Jira API token set in Settings, else it renders empty.
|
|
178
|
+
devflow mr create "Title" feat/x --issue ABC-123
|
|
179
|
+
|
|
165
180
|
# routed by issue key (project key = prefix before the last '-')
|
|
166
181
|
devflow mr find ABC-123
|
|
167
182
|
devflow pipeline status 42 deadbeef --issue ABC-9
|
package/package.json
CHANGED
package/src/commands.js
CHANGED
|
@@ -53,6 +53,32 @@ function toValues(flag, raw) {
|
|
|
53
53
|
return parsed;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
/** Parse a value-taking flag as a non-blank string, or fail clearly. */
|
|
57
|
+
function toBranch(flag, raw) {
|
|
58
|
+
if (raw === undefined) return undefined;
|
|
59
|
+
|
|
60
|
+
const branch = String(raw).trim();
|
|
61
|
+
|
|
62
|
+
if (raw === true || branch === "") {
|
|
63
|
+
throw new UsageError(`"--${flag}" requires a branch name.`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return branch;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Parse a value-taking flag as a non-blank string, or fail clearly. */
|
|
70
|
+
function toText(flag, raw) {
|
|
71
|
+
if (raw === undefined) return undefined;
|
|
72
|
+
|
|
73
|
+
const text = String(raw).trim();
|
|
74
|
+
|
|
75
|
+
if (raw === true || text === "") {
|
|
76
|
+
throw new UsageError(`"--${flag}" requires a value.`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return text;
|
|
80
|
+
}
|
|
81
|
+
|
|
56
82
|
/** A bad-invocation error (wrong/missing args) — printed with the command usage. */
|
|
57
83
|
export class UsageError extends Error {
|
|
58
84
|
constructor(message) {
|
|
@@ -116,7 +142,8 @@ const COMMANDS = {
|
|
|
116
142
|
method: "POST",
|
|
117
143
|
action: "commitByTemplate",
|
|
118
144
|
usage:
|
|
119
|
-
'commit template <worktreePath> [--values \'{"key":"val"}\'] [--no-push] [--issue KEY] [--project KEY]'
|
|
145
|
+
'commit template <worktreePath> [--values \'{"key":"val"}\'] [--no-push] [--issue KEY] [--project KEY]' +
|
|
146
|
+
" (--values keys must match the {key} tokens of the project's configured commit template)",
|
|
120
147
|
buildArgs: ([worktreePath], flags) => {
|
|
121
148
|
if (!worktreePath) throw new UsageError("commit template requires <worktreePath>.");
|
|
122
149
|
|
|
@@ -130,13 +157,28 @@ const COMMANDS = {
|
|
|
130
157
|
"mr create": {
|
|
131
158
|
method: "POST",
|
|
132
159
|
action: "createPullRequest",
|
|
133
|
-
usage:
|
|
160
|
+
usage:
|
|
161
|
+
"mr create <title> <headBranch> [--body <text>] [--base <branch>] [--type <idOrLabel>]" +
|
|
162
|
+
" [--issue KEY] [--project KEY]" +
|
|
163
|
+
" (--base defaults to the repo's configured base branch, expanding a {year}/{number} pattern;" +
|
|
164
|
+
" --type defaults to the project's first configured PR type)",
|
|
134
165
|
buildArgs: ([title, headBranch], flags) => {
|
|
135
166
|
if (!title || !headBranch) {
|
|
136
167
|
throw new UsageError("mr create requires <title> and <headBranch>.");
|
|
137
168
|
}
|
|
138
169
|
|
|
139
|
-
|
|
170
|
+
const baseBranch = toBranch("base", flags.base);
|
|
171
|
+
const prType = toText("type", flags.type);
|
|
172
|
+
// Only an explicit --issue is forwarded; the gateway otherwise parses the head branch.
|
|
173
|
+
const issueKey = toText("issue", flags.issue);
|
|
174
|
+
|
|
175
|
+
// Trailing undefined is trimmed so the gateway resolves the repo's own
|
|
176
|
+
// configured base branch (and expands a pattern) instead of seeing null.
|
|
177
|
+
const args = [title, flags.body ?? "", headBranch, baseBranch, prType, issueKey];
|
|
178
|
+
|
|
179
|
+
while (args.length > 3 && args[args.length - 1] === undefined) args.pop();
|
|
180
|
+
|
|
181
|
+
return args;
|
|
140
182
|
},
|
|
141
183
|
},
|
|
142
184
|
"mr ready": {
|
|
@@ -225,6 +267,12 @@ const COMMANDS = {
|
|
|
225
267
|
return [key];
|
|
226
268
|
},
|
|
227
269
|
},
|
|
270
|
+
"mr types": {
|
|
271
|
+
method: "POST",
|
|
272
|
+
action: "listPrTypes",
|
|
273
|
+
usage: "mr types [--issue KEY] [--project KEY]",
|
|
274
|
+
buildArgs: () => [],
|
|
275
|
+
},
|
|
228
276
|
"mr fix-prompt": {
|
|
229
277
|
method: "POST",
|
|
230
278
|
action: "getFixCommentsPrompt",
|
package/src/context.js
CHANGED
|
@@ -203,10 +203,16 @@ export function offlineProfileError(context) {
|
|
|
203
203
|
|
|
204
204
|
/**
|
|
205
205
|
* How the resolved profile looks to the daemon. Shown inline on the profile row
|
|
206
|
-
* so `devflow where` answers "would a call work?" without a second lookup.
|
|
206
|
+
* so `devflow where` answers "would a call work?" without a second lookup. A
|
|
207
|
+
* connected profile also names the extension bundle it is running, so a stale
|
|
208
|
+
* `dist/` can be spotted without guessing.
|
|
207
209
|
*/
|
|
208
210
|
function describeLiveness(context) {
|
|
209
|
-
if (context.profileAlive === true)
|
|
211
|
+
if (context.profileAlive === true) {
|
|
212
|
+
return context.buildStamp
|
|
213
|
+
? `connected; extension build ${context.buildStamp}`
|
|
214
|
+
: "connected; extension build unknown (this build predates the stamp)";
|
|
215
|
+
}
|
|
210
216
|
|
|
211
217
|
if (context.profileAlive === false) {
|
|
212
218
|
return "NOT connected; open this Chrome profile before running actions";
|
package/src/contextResolver.js
CHANGED
|
@@ -162,8 +162,9 @@ function fill(resolved, source, origin) {
|
|
|
162
162
|
* @param {(args: string[]) => string | null} [options.runGit]
|
|
163
163
|
* @param {(q: { cwd?: string, remote?: string, branch?: string }) => Promise<object | null>} [options.queryContext]
|
|
164
164
|
* @returns {Promise<{
|
|
165
|
-
* projectKey?: string, issueKey?: string, repo?: string,
|
|
166
|
-
* profileAlive?: boolean | null,
|
|
165
|
+
* projectKey?: string, issueKey?: string, repo?: string, baseBranch?: string,
|
|
166
|
+
* profile?: string, profileAlive?: boolean | null, buildStamp?: string | null,
|
|
167
|
+
* matchedBy: Record<string, string>,
|
|
167
168
|
* candidates?: object[], ambiguous?: boolean, warnings: string[]
|
|
168
169
|
* }>}
|
|
169
170
|
*/
|
|
@@ -259,6 +260,9 @@ export async function resolveContext({
|
|
|
259
260
|
clean(context.repo?.id) ??
|
|
260
261
|
clean(context.repo?.name) ??
|
|
261
262
|
clean(context.repo?.remoteUrl),
|
|
263
|
+
// The selector `repo` flattens the digest to one string; the configured
|
|
264
|
+
// base branch rides alongside it so a caller can target it explicitly.
|
|
265
|
+
baseBranch: clean(context.repo?.baseBranch),
|
|
262
266
|
profile: clean(context.profileId),
|
|
263
267
|
}),
|
|
264
268
|
},
|
|
@@ -269,8 +273,12 @@ export async function resolveContext({
|
|
|
269
273
|
|
|
270
274
|
// Liveness is only meaningful for the profile we actually resolved to; it lets
|
|
271
275
|
// consumers name an offline profile instead of printing a bare NO_PROFILE.
|
|
276
|
+
// The build stamp describes that same profile's running extension bundle, so
|
|
277
|
+
// it is gated identically — reporting one profile's bundle beside another's id
|
|
278
|
+
// is exactly the confusion the stamp exists to end.
|
|
272
279
|
if (!conflict && resolved.profile && resolved.profile === clean(context.profileId)) {
|
|
273
280
|
resolved.profileAlive = context.profileAlive ?? null;
|
|
281
|
+
resolved.buildStamp = context.buildStamp ?? null;
|
|
274
282
|
}
|
|
275
283
|
|
|
276
284
|
// The daemon's issue key describes its matched project too, so it is dropped on
|