@markjaquith/agency 3.6.2 → 3.8.0
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 +22 -13
- package/package.json +1 -1
- package/src/act-schema.ts +3 -0
- package/src/cli-parser.ts +13 -3
- package/src/commands/act-actions.ts +799 -29
- package/src/commands/act.ts +10 -21
package/README.md
CHANGED
|
@@ -564,7 +564,11 @@ agency validate
|
|
|
564
564
|
### Interactive Actions
|
|
565
565
|
|
|
566
566
|
`agency` with no subcommand (or `agency act`) opens on **Workstream**, a flat list
|
|
567
|
-
of non-archived tasks and phases
|
|
567
|
+
of non-archived tasks and phases. When run inside an epic, task, phase, or one of
|
|
568
|
+
its checkout descendants, it opens that item's actions first; Escape returns to
|
|
569
|
+
Workstream, where **Tab** reaches global Workbase actions. `agency .` is shorthand
|
|
570
|
+
for `agency act .` and explicitly focuses the item containing the current path.
|
|
571
|
+
Otherwise, select an item to see its available actions.
|
|
568
572
|
Press **Tab** to cycle to **Workbase** for workbase actions. Both tabs have a blank
|
|
569
573
|
row above a chevron-prefixed filter with the placeholder “type to filter”.
|
|
570
574
|
Each tab remembers its filter and selection. The active
|
|
@@ -612,18 +616,21 @@ handoffs restore the terminal before starting the interactive worker, then reope
|
|
|
612
616
|
the TUI when the worker returns. A configured
|
|
613
617
|
external chooser continues to offer goals and **Browse items** through that chooser.
|
|
614
618
|
|
|
615
|
-
| Goal | Choose in `act` | Discovery/action ID
|
|
616
|
-
| ------------------------------------ | ------------------------------------------------------------------------------------------------- |
|
|
617
|
-
|
|
|
618
|
-
| Create
|
|
619
|
-
| Split work | Add a phase / split this task; name the existing work's first phase | `split`
|
|
620
|
-
| Work on a task or phase | Work on this item | `work`
|
|
621
|
-
| Move from investigation to execution | Create implementation follow-up | `handoff`
|
|
622
|
-
| Review someone else's work | Review a PR, or a remote branch/commit | `review`, `review-ref`
|
|
623
|
-
| Close finished work | Close or reopen work → complete without a PR, drop abandoned work, refresh a merged PR, or reopen | `complete`, `drop`, `sync`, `reopen`
|
|
624
|
-
|
|
|
625
|
-
|
|
|
626
|
-
|
|
|
619
|
+
| Goal | Choose in `act` | Discovery/action ID |
|
|
620
|
+
| ------------------------------------ | ------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
621
|
+
| Manage repositories | Add, link, set up, materialize, fetch, verify, rename, update, unlink, or remove aliases | `repo-add`, `repo-link`, `repo-setup`, `repo-materialize`, `repo-fetch`, `repo-verify`, `repo-rename`, `repo-remote`, `repo-unlink`, `repo-remove` |
|
|
622
|
+
| Create work | Create a standard task, multi-phase task, investigation, epic, or a task inside an epic | `task-create`, `multi-phase-create`, `investigation-create`, `epic-create`, `task-create-in-epic` |
|
|
623
|
+
| Split work | Add a phase / split this task; name the existing work's first phase | `split` |
|
|
624
|
+
| Work on a task or phase | Work on this item | `work` |
|
|
625
|
+
| Move from investigation to execution | Create implementation follow-up | `handoff` |
|
|
626
|
+
| Review someone else's work | Review a PR, or a remote branch/commit | `review`, `review-ref` |
|
|
627
|
+
| Close finished work | Close or reopen work → complete without a PR, drop abandoned work, refresh a merged PR, or reopen | `complete`, `drop`, `sync`, `reopen` |
|
|
628
|
+
| Publish or update PR status | Push without a PR, refresh provider state, create a PR, mark a GitHub PR ready, or close it | `push`, `sync`, `pr`, `pr-ready`, `pr-close` |
|
|
629
|
+
| Maintain review work | Fetch and repin a review task to its current source | `review-refresh` |
|
|
630
|
+
| Organize work | Rename an item, move a task into/out of an epic, or add/remove a sibling dependency | `rename`, `move-to-epic`, `remove-from-epic`, `dependency-add`, `dependency-remove` |
|
|
631
|
+
| Archive terminal work | Archive | `archive` |
|
|
632
|
+
| See work status | See current or ready work | `current-work`, `ready-work` |
|
|
633
|
+
| Check or refresh the workbase | Validate, diagnose, reconcile all state, or inspect/update managed integration files | `validate`, `doctor`, `sync-all`, `integration-status`, `integration-sync` |
|
|
627
634
|
|
|
628
635
|
After creating a task, phase, review, or implementation follow-up, choose **Work
|
|
629
636
|
on the new item now** or **Finish**. Only choosing Work prepares checkouts and
|
|
@@ -659,6 +666,8 @@ For agents, `--json` never prompts or executes. Its compact, runtime-validated
|
|
|
659
666
|
result includes workbase actions and repository aliases, current working items,
|
|
660
667
|
and matching targets with readiness, document revisions, available `actions`,
|
|
661
668
|
and `blockedActions` with reasons. `--action` filters discovery to one scenario.
|
|
669
|
+
Every action includes a concise `description`, Nerd Font `icon`, and semantic
|
|
670
|
+
hex `color`, in addition to its label and availability.
|
|
662
671
|
Targets and current working items share the same identity and metadata fields:
|
|
663
672
|
`id`, `kind`, `key`, `status`, `description`, `repo` (the declared main repository,
|
|
664
673
|
when present), `repositories`, `readiness`, and `revision`. Descriptions retain
|
package/package.json
CHANGED
package/src/act-schema.ts
CHANGED
|
@@ -6,6 +6,9 @@ const Argv = Schema.Array(Schema.String)
|
|
|
6
6
|
const Action = Schema.Struct({
|
|
7
7
|
id: Schema.String,
|
|
8
8
|
label: Schema.optional(Schema.String),
|
|
9
|
+
description: Schema.String,
|
|
10
|
+
icon: Schema.String,
|
|
11
|
+
color: Schema.String,
|
|
9
12
|
available: Schema.Boolean,
|
|
10
13
|
blockedReason: Schema.optional(Schema.NullOr(Schema.String)),
|
|
11
14
|
inputs: Schema.optional(
|
package/src/cli-parser.ts
CHANGED
|
@@ -499,7 +499,14 @@ const commands = {
|
|
|
499
499
|
usage: "agency task status <id> <status> [options] [--json]",
|
|
500
500
|
minArgs: 2,
|
|
501
501
|
maxArgs: 2,
|
|
502
|
-
options: [
|
|
502
|
+
options: [
|
|
503
|
+
"json",
|
|
504
|
+
"task",
|
|
505
|
+
"if-revision",
|
|
506
|
+
"no-pull-request",
|
|
507
|
+
"summary",
|
|
508
|
+
"evidence-url",
|
|
509
|
+
],
|
|
503
510
|
},
|
|
504
511
|
update: {
|
|
505
512
|
usage: "agency task update <id> [options] [--json]",
|
|
@@ -630,6 +637,7 @@ const commands = {
|
|
|
630
637
|
"json",
|
|
631
638
|
"task",
|
|
632
639
|
"phase",
|
|
640
|
+
"if-revision",
|
|
633
641
|
"no-pull-request",
|
|
634
642
|
"summary",
|
|
635
643
|
"evidence-url",
|
|
@@ -1355,12 +1363,13 @@ export function parseCli(args: readonly string[]): ParsedCli {
|
|
|
1355
1363
|
return { commandPath: "root", args: [], values: parsed.values }
|
|
1356
1364
|
}
|
|
1357
1365
|
|
|
1358
|
-
const
|
|
1366
|
+
const suppliedCommandName = args[commandIndex]!
|
|
1367
|
+
const commandName = suppliedCommandName === "." ? "act" : suppliedCommandName
|
|
1359
1368
|
const definition: CommandDefinition | undefined =
|
|
1360
1369
|
commands[commandName as keyof typeof commands]
|
|
1361
1370
|
if (!definition) {
|
|
1362
1371
|
throw usageError(
|
|
1363
|
-
`Unknown command '${
|
|
1372
|
+
`Unknown command '${suppliedCommandName}'.`,
|
|
1364
1373
|
"agency <command> [options]",
|
|
1365
1374
|
)
|
|
1366
1375
|
}
|
|
@@ -1405,6 +1414,7 @@ export function parseCli(args: readonly string[]): ParsedCli {
|
|
|
1405
1414
|
}
|
|
1406
1415
|
const commandArgs = [
|
|
1407
1416
|
...args.slice(0, commandIndex),
|
|
1417
|
+
...(suppliedCommandName === "." ? ["."] : []),
|
|
1408
1418
|
...args.slice(commandIndex + 1),
|
|
1409
1419
|
]
|
|
1410
1420
|
const parsed = parse(commandArgs, definition.options, definition.usage)
|
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
import { Effect } from "effect"
|
|
2
|
+
import { join } from "node:path"
|
|
2
3
|
import type { GraphNode } from "../graph-schema"
|
|
3
4
|
import type { BaseCommandOptions } from "../utils/command"
|
|
4
5
|
import type { ActionPrompts } from "./act-prompts"
|
|
5
6
|
import { archive } from "./archive"
|
|
7
|
+
import { doctor } from "./doctor"
|
|
8
|
+
import { epic } from "./epic"
|
|
9
|
+
import { integration } from "./integration"
|
|
6
10
|
import { repo } from "./repo"
|
|
11
|
+
import { review } from "./review"
|
|
7
12
|
import { task } from "./task"
|
|
8
13
|
import { phase } from "./phase"
|
|
14
|
+
import { push } from "./push"
|
|
9
15
|
import { sync } from "./sync"
|
|
10
16
|
import { status } from "./status"
|
|
11
17
|
import { pr, prCreate } from "./pr"
|
|
18
|
+
import { validate } from "./validate"
|
|
12
19
|
import { work as startWork, type StartWork } from "./work"
|
|
20
|
+
import { macchiato } from "../utils/theme"
|
|
13
21
|
|
|
14
22
|
export type ActEntity = Extract<
|
|
15
23
|
GraphNode,
|
|
@@ -18,9 +26,15 @@ export type ActEntity = Extract<
|
|
|
18
26
|
type NativeOperation =
|
|
19
27
|
| ReturnType<typeof task>
|
|
20
28
|
| ReturnType<typeof phase>
|
|
29
|
+
| ReturnType<typeof epic>
|
|
21
30
|
| ReturnType<typeof repo>
|
|
31
|
+
| ReturnType<typeof review>
|
|
32
|
+
| ReturnType<typeof push>
|
|
22
33
|
| ReturnType<typeof sync>
|
|
23
34
|
| ReturnType<typeof status>
|
|
35
|
+
| ReturnType<typeof doctor>
|
|
36
|
+
| ReturnType<typeof integration>
|
|
37
|
+
| ReturnType<typeof validate>
|
|
24
38
|
| ReturnType<typeof prCreate>
|
|
25
39
|
| ReturnType<typeof archive>
|
|
26
40
|
| ReturnType<StartWork>
|
|
@@ -50,11 +64,241 @@ interface Details {
|
|
|
50
64
|
readonly inputs?: readonly Input[]
|
|
51
65
|
}
|
|
52
66
|
export interface ActAction extends Details {
|
|
67
|
+
readonly description: string
|
|
68
|
+
readonly icon: string
|
|
69
|
+
readonly color: string
|
|
53
70
|
readonly preview: Plan
|
|
54
71
|
/** Replayable input collection. All mutations belong in the returned plan.run. */
|
|
55
72
|
readonly prepare: (prompts: ActionPrompts) => Effect.Effect<Plan, Error>
|
|
56
73
|
}
|
|
57
74
|
|
|
75
|
+
const actionPresentation: Record<
|
|
76
|
+
string,
|
|
77
|
+
{
|
|
78
|
+
readonly description: string
|
|
79
|
+
readonly icon: string
|
|
80
|
+
readonly color: string
|
|
81
|
+
}
|
|
82
|
+
> = {
|
|
83
|
+
"repo-add": {
|
|
84
|
+
description: "Clone a remote repository into this workbase.",
|
|
85
|
+
icon: "",
|
|
86
|
+
color: macchiato.green,
|
|
87
|
+
},
|
|
88
|
+
"repo-link": {
|
|
89
|
+
description: "Use an existing local checkout as a repository alias.",
|
|
90
|
+
icon: "",
|
|
91
|
+
color: macchiato.sapphire,
|
|
92
|
+
},
|
|
93
|
+
"repo-setup": {
|
|
94
|
+
description: "Materialize all portable repository declarations.",
|
|
95
|
+
icon: "",
|
|
96
|
+
color: macchiato.blue,
|
|
97
|
+
},
|
|
98
|
+
"repo-materialize": {
|
|
99
|
+
description: "Replace a linked alias with a managed bare clone.",
|
|
100
|
+
icon: "",
|
|
101
|
+
color: macchiato.blue,
|
|
102
|
+
},
|
|
103
|
+
"repo-fetch": {
|
|
104
|
+
description: "Fetch and prune a repository alias.",
|
|
105
|
+
icon: "",
|
|
106
|
+
color: macchiato.sapphire,
|
|
107
|
+
},
|
|
108
|
+
"repo-verify": {
|
|
109
|
+
description: "Check that a repository alias is operational.",
|
|
110
|
+
icon: "",
|
|
111
|
+
color: macchiato.green,
|
|
112
|
+
},
|
|
113
|
+
"repo-rename": {
|
|
114
|
+
description: "Rename an unused repository alias.",
|
|
115
|
+
icon: "",
|
|
116
|
+
color: macchiato.yellow,
|
|
117
|
+
},
|
|
118
|
+
"repo-remote": {
|
|
119
|
+
description: "Update an alias's portable remote declaration.",
|
|
120
|
+
icon: "",
|
|
121
|
+
color: macchiato.sapphire,
|
|
122
|
+
},
|
|
123
|
+
"repo-unlink": {
|
|
124
|
+
description: "Remove only this machine's linked checkout.",
|
|
125
|
+
icon: "",
|
|
126
|
+
color: macchiato.red,
|
|
127
|
+
},
|
|
128
|
+
"repo-remove": {
|
|
129
|
+
description: "Remove an unused alias and its local materialization.",
|
|
130
|
+
icon: "",
|
|
131
|
+
color: macchiato.red,
|
|
132
|
+
},
|
|
133
|
+
"task-create": {
|
|
134
|
+
description: "Create one deliverable execution task.",
|
|
135
|
+
icon: "",
|
|
136
|
+
color: macchiato.green,
|
|
137
|
+
},
|
|
138
|
+
"multi-phase-create": {
|
|
139
|
+
description: "Create a task that will be delivered through phases.",
|
|
140
|
+
icon: "",
|
|
141
|
+
color: macchiato.yellow,
|
|
142
|
+
},
|
|
143
|
+
"investigation-create": {
|
|
144
|
+
description: "Create evidence-gathering work before implementation.",
|
|
145
|
+
icon: "",
|
|
146
|
+
color: macchiato.mauve,
|
|
147
|
+
},
|
|
148
|
+
"epic-create": {
|
|
149
|
+
description: "Create an epic to coordinate related tasks.",
|
|
150
|
+
icon: "",
|
|
151
|
+
color: macchiato.mauve,
|
|
152
|
+
},
|
|
153
|
+
"task-create-in-epic": {
|
|
154
|
+
description: "Create a new execution task inside this epic.",
|
|
155
|
+
icon: "",
|
|
156
|
+
color: macchiato.green,
|
|
157
|
+
},
|
|
158
|
+
review: {
|
|
159
|
+
description: "Create a task pinned to an existing pull request.",
|
|
160
|
+
icon: "",
|
|
161
|
+
color: macchiato.mauve,
|
|
162
|
+
},
|
|
163
|
+
"review-ref": {
|
|
164
|
+
description: "Create a task pinned to a remote branch or commit.",
|
|
165
|
+
icon: "",
|
|
166
|
+
color: macchiato.mauve,
|
|
167
|
+
},
|
|
168
|
+
"current-work": {
|
|
169
|
+
description: "Show tasks and phases currently being worked.",
|
|
170
|
+
icon: "",
|
|
171
|
+
color: macchiato.blue,
|
|
172
|
+
},
|
|
173
|
+
"ready-work": {
|
|
174
|
+
description: "Show execution units that are ready to start.",
|
|
175
|
+
icon: "",
|
|
176
|
+
color: macchiato.green,
|
|
177
|
+
},
|
|
178
|
+
validate: {
|
|
179
|
+
description: "Validate workbase documents and relationships.",
|
|
180
|
+
icon: "",
|
|
181
|
+
color: macchiato.green,
|
|
182
|
+
},
|
|
183
|
+
doctor: {
|
|
184
|
+
description: "Diagnose workbase, repository, and integration health.",
|
|
185
|
+
icon: "",
|
|
186
|
+
color: macchiato.yellow,
|
|
187
|
+
},
|
|
188
|
+
"sync-all": {
|
|
189
|
+
description: "Reconcile all work with repository and provider state.",
|
|
190
|
+
icon: "",
|
|
191
|
+
color: macchiato.sapphire,
|
|
192
|
+
},
|
|
193
|
+
"integration-status": {
|
|
194
|
+
description: "Inspect managed agent integration files.",
|
|
195
|
+
icon: "",
|
|
196
|
+
color: macchiato.blue,
|
|
197
|
+
},
|
|
198
|
+
"integration-sync": {
|
|
199
|
+
description: "Update safe managed agent integration files.",
|
|
200
|
+
icon: "",
|
|
201
|
+
color: macchiato.sapphire,
|
|
202
|
+
},
|
|
203
|
+
work: {
|
|
204
|
+
description: "Prepare this item and start its configured worker.",
|
|
205
|
+
icon: "",
|
|
206
|
+
color: macchiato.green,
|
|
207
|
+
},
|
|
208
|
+
push: {
|
|
209
|
+
description: "Validate and publish this execution branch without a PR.",
|
|
210
|
+
icon: "",
|
|
211
|
+
color: macchiato.sapphire,
|
|
212
|
+
},
|
|
213
|
+
pr: {
|
|
214
|
+
description: "Publish this execution branch and record its pull request.",
|
|
215
|
+
icon: "",
|
|
216
|
+
color: macchiato.mauve,
|
|
217
|
+
},
|
|
218
|
+
"review-refresh": {
|
|
219
|
+
description: "Fetch and repin this review task to its current source.",
|
|
220
|
+
icon: "",
|
|
221
|
+
color: macchiato.sapphire,
|
|
222
|
+
},
|
|
223
|
+
reopen: {
|
|
224
|
+
description: "Return terminal work to open status.",
|
|
225
|
+
icon: "",
|
|
226
|
+
color: macchiato.sapphire,
|
|
227
|
+
},
|
|
228
|
+
drop: {
|
|
229
|
+
description: "Abandon this item without satisfying dependents.",
|
|
230
|
+
icon: "",
|
|
231
|
+
color: macchiato.red,
|
|
232
|
+
},
|
|
233
|
+
archive: {
|
|
234
|
+
description: "Move terminal work into the archive.",
|
|
235
|
+
icon: "",
|
|
236
|
+
color: macchiato.yellow,
|
|
237
|
+
},
|
|
238
|
+
split: {
|
|
239
|
+
description: "Convert or extend this task with another delivery phase.",
|
|
240
|
+
icon: "",
|
|
241
|
+
color: macchiato.yellow,
|
|
242
|
+
},
|
|
243
|
+
handoff: {
|
|
244
|
+
description: "Create distinct implementation work from this investigation.",
|
|
245
|
+
icon: "",
|
|
246
|
+
color: macchiato.mauve,
|
|
247
|
+
},
|
|
248
|
+
complete: {
|
|
249
|
+
description: "Record a genuine non-PR outcome as complete.",
|
|
250
|
+
icon: "",
|
|
251
|
+
color: macchiato.green,
|
|
252
|
+
},
|
|
253
|
+
sync: {
|
|
254
|
+
description: "Reconcile this item with repository and provider state.",
|
|
255
|
+
icon: "",
|
|
256
|
+
color: macchiato.sapphire,
|
|
257
|
+
},
|
|
258
|
+
"pr-ready": {
|
|
259
|
+
description: "Mark this recorded GitHub pull request ready for review.",
|
|
260
|
+
icon: "",
|
|
261
|
+
color: macchiato.green,
|
|
262
|
+
},
|
|
263
|
+
"pr-close": {
|
|
264
|
+
description: "Close this recorded GitHub pull request.",
|
|
265
|
+
icon: "",
|
|
266
|
+
color: macchiato.red,
|
|
267
|
+
},
|
|
268
|
+
rename: {
|
|
269
|
+
description: "Rename this item and update durable references.",
|
|
270
|
+
icon: "",
|
|
271
|
+
color: macchiato.yellow,
|
|
272
|
+
},
|
|
273
|
+
"dependency-add": {
|
|
274
|
+
description: "Require another sibling item to finish first.",
|
|
275
|
+
icon: "",
|
|
276
|
+
color: macchiato.yellow,
|
|
277
|
+
},
|
|
278
|
+
"dependency-remove": {
|
|
279
|
+
description: "Remove a completion dependency from this item.",
|
|
280
|
+
icon: "",
|
|
281
|
+
color: macchiato.red,
|
|
282
|
+
},
|
|
283
|
+
"move-to-epic": {
|
|
284
|
+
description: "Move this task into an existing epic.",
|
|
285
|
+
icon: "",
|
|
286
|
+
color: macchiato.mauve,
|
|
287
|
+
},
|
|
288
|
+
"remove-from-epic": {
|
|
289
|
+
description: "Move this task out of its current epic.",
|
|
290
|
+
icon: "",
|
|
291
|
+
color: macchiato.yellow,
|
|
292
|
+
},
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const present = (details: Details) => {
|
|
296
|
+
const presentation = actionPresentation[details.id]
|
|
297
|
+
if (!presentation)
|
|
298
|
+
throw new Error(`Missing presentation for action '${details.id}'`)
|
|
299
|
+
return { ...details, ...presentation }
|
|
300
|
+
}
|
|
301
|
+
|
|
58
302
|
// A typed argument builder is used for both discovery and execution. Prompts are
|
|
59
303
|
// ordinary TypeScript; discovery does not expose or interpret form instructions.
|
|
60
304
|
const action = <A>(
|
|
@@ -63,12 +307,12 @@ const action = <A>(
|
|
|
63
307
|
read: (p: ActionPrompts) => Effect.Effect<A, Error>,
|
|
64
308
|
build: (args: A) => Plan,
|
|
65
309
|
): ActAction => ({
|
|
66
|
-
...details,
|
|
310
|
+
...present(details),
|
|
67
311
|
preview: build(example),
|
|
68
312
|
prepare: (p) => Effect.map(read(p), build),
|
|
69
313
|
})
|
|
70
314
|
const immediate = (details: Details, plan: Plan): ActAction => ({
|
|
71
|
-
...details,
|
|
315
|
+
...present(details),
|
|
72
316
|
preview: plan,
|
|
73
317
|
prepare: () => Effect.succeed(plan),
|
|
74
318
|
})
|
|
@@ -90,9 +334,15 @@ const taskTarget = (node: ActEntity) =>
|
|
|
90
334
|
export const actionGroups = [
|
|
91
335
|
{
|
|
92
336
|
id: "create",
|
|
93
|
-
label: "Create
|
|
337
|
+
label: "Create work",
|
|
94
338
|
icon: "",
|
|
95
|
-
actions: [
|
|
339
|
+
actions: [
|
|
340
|
+
"task-create",
|
|
341
|
+
"multi-phase-create",
|
|
342
|
+
"investigation-create",
|
|
343
|
+
"epic-create",
|
|
344
|
+
"task-create-in-epic",
|
|
345
|
+
],
|
|
96
346
|
},
|
|
97
347
|
{
|
|
98
348
|
id: "work",
|
|
@@ -120,9 +370,9 @@ export const actionGroups = [
|
|
|
120
370
|
},
|
|
121
371
|
{
|
|
122
372
|
id: "current-work",
|
|
123
|
-
label: "See
|
|
373
|
+
label: "See work status",
|
|
124
374
|
icon: "",
|
|
125
|
-
actions: ["current-work"],
|
|
375
|
+
actions: ["current-work", "ready-work"],
|
|
126
376
|
},
|
|
127
377
|
{
|
|
128
378
|
id: "browse",
|
|
@@ -132,9 +382,9 @@ export const actionGroups = [
|
|
|
132
382
|
},
|
|
133
383
|
{
|
|
134
384
|
id: "pull-request",
|
|
135
|
-
label: "
|
|
385
|
+
label: "Publish or update a pull request",
|
|
136
386
|
icon: "",
|
|
137
|
-
actions: ["sync", "pr", "pr-ready", "pr-close"],
|
|
387
|
+
actions: ["push", "sync", "pr", "pr-ready", "pr-close"],
|
|
138
388
|
},
|
|
139
389
|
{
|
|
140
390
|
id: "close",
|
|
@@ -150,9 +400,44 @@ export const actionGroups = [
|
|
|
150
400
|
},
|
|
151
401
|
{
|
|
152
402
|
id: "repository",
|
|
153
|
-
label: "
|
|
403
|
+
label: "Manage repositories",
|
|
154
404
|
icon: "",
|
|
155
|
-
actions: [
|
|
405
|
+
actions: [
|
|
406
|
+
"repo-add",
|
|
407
|
+
"repo-link",
|
|
408
|
+
"repo-setup",
|
|
409
|
+
"repo-materialize",
|
|
410
|
+
"repo-fetch",
|
|
411
|
+
"repo-verify",
|
|
412
|
+
"repo-rename",
|
|
413
|
+
"repo-remote",
|
|
414
|
+
"repo-unlink",
|
|
415
|
+
"repo-remove",
|
|
416
|
+
],
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
id: "health",
|
|
420
|
+
label: "Check or refresh the workbase",
|
|
421
|
+
icon: "",
|
|
422
|
+
actions: [
|
|
423
|
+
"validate",
|
|
424
|
+
"doctor",
|
|
425
|
+
"sync-all",
|
|
426
|
+
"integration-status",
|
|
427
|
+
"integration-sync",
|
|
428
|
+
],
|
|
429
|
+
},
|
|
430
|
+
{
|
|
431
|
+
id: "organize",
|
|
432
|
+
label: "Rename or change dependencies",
|
|
433
|
+
icon: "",
|
|
434
|
+
actions: [
|
|
435
|
+
"rename",
|
|
436
|
+
"move-to-epic",
|
|
437
|
+
"remove-from-epic",
|
|
438
|
+
"dependency-add",
|
|
439
|
+
"dependency-remove",
|
|
440
|
+
],
|
|
156
441
|
},
|
|
157
442
|
] as const
|
|
158
443
|
|
|
@@ -209,26 +494,38 @@ export const actActions = (
|
|
|
209
494
|
}),
|
|
210
495
|
),
|
|
211
496
|
),
|
|
212
|
-
...([
|
|
497
|
+
...(["standard", "multi-phase", "investigation"] as const).map((kind) =>
|
|
213
498
|
action(
|
|
214
499
|
{
|
|
215
|
-
id:
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
500
|
+
id:
|
|
501
|
+
kind === "standard"
|
|
502
|
+
? "task-create"
|
|
503
|
+
: kind === "multi-phase"
|
|
504
|
+
? "multi-phase-create"
|
|
505
|
+
: "investigation-create",
|
|
506
|
+
label:
|
|
507
|
+
kind === "standard"
|
|
508
|
+
? "Create a standard task"
|
|
509
|
+
: kind === "multi-phase"
|
|
510
|
+
? "Create a multi-phase task"
|
|
511
|
+
: "Create an investigation",
|
|
512
|
+
blockedReason: kind === "multi-phase" ? null : needsRepository,
|
|
220
513
|
inputs: [
|
|
221
514
|
input("description", "Outcome", { multiline: true }),
|
|
222
515
|
input("id", "Task ID"),
|
|
223
|
-
|
|
224
|
-
|
|
516
|
+
...(kind === "multi-phase"
|
|
517
|
+
? []
|
|
518
|
+
: [
|
|
519
|
+
input("repo", "Repository alias"),
|
|
520
|
+
input("base", "Base branch"),
|
|
521
|
+
]),
|
|
225
522
|
],
|
|
226
523
|
},
|
|
227
524
|
{
|
|
228
525
|
id: "<id>",
|
|
229
526
|
description: "<description>",
|
|
230
|
-
repo: "<repo>",
|
|
231
|
-
base: "<base>",
|
|
527
|
+
repo: kind === "multi-phase" ? undefined : "<repo>",
|
|
528
|
+
base: kind === "multi-phase" ? undefined : "<base>",
|
|
232
529
|
},
|
|
233
530
|
(p) =>
|
|
234
531
|
Effect.gen(function* () {
|
|
@@ -236,8 +533,12 @@ export const actActions = (
|
|
|
236
533
|
return {
|
|
237
534
|
description,
|
|
238
535
|
id: yield* p.id("New task ID", description),
|
|
239
|
-
repo:
|
|
240
|
-
|
|
536
|
+
repo:
|
|
537
|
+
kind === "multi-phase" ? undefined : yield* p.repository(),
|
|
538
|
+
base:
|
|
539
|
+
kind === "multi-phase"
|
|
540
|
+
? undefined
|
|
541
|
+
: yield* p.text("Base branch", "main"),
|
|
241
542
|
}
|
|
242
543
|
}),
|
|
243
544
|
(args) => ({
|
|
@@ -246,25 +547,81 @@ export const actActions = (
|
|
|
246
547
|
"task",
|
|
247
548
|
"create",
|
|
248
549
|
args.id,
|
|
249
|
-
"--repo",
|
|
250
|
-
args.
|
|
251
|
-
"--base",
|
|
252
|
-
args.base,
|
|
550
|
+
...(args.repo ? ["--repo", args.repo] : []),
|
|
551
|
+
...(args.base ? ["--base", args.base] : []),
|
|
253
552
|
"--description",
|
|
254
553
|
args.description,
|
|
255
|
-
...(
|
|
554
|
+
...(kind === "multi-phase" ? ["--multi-phase"] : []),
|
|
555
|
+
...(kind === "investigation"
|
|
556
|
+
? ["--purpose", "investigation"]
|
|
557
|
+
: []),
|
|
256
558
|
],
|
|
257
559
|
run: task({
|
|
258
560
|
...options,
|
|
259
561
|
subcommand: "create",
|
|
260
562
|
args: [args.id],
|
|
261
563
|
...args,
|
|
262
|
-
|
|
564
|
+
multiPhase: kind === "multi-phase",
|
|
565
|
+
purpose: kind === "investigation" ? "investigation" : undefined,
|
|
263
566
|
}),
|
|
264
567
|
next: { taskId: args.id },
|
|
265
568
|
}),
|
|
266
569
|
),
|
|
267
570
|
),
|
|
571
|
+
action(
|
|
572
|
+
{
|
|
573
|
+
id: "epic-create",
|
|
574
|
+
label: "Create an epic",
|
|
575
|
+
blockedReason: needsRepository,
|
|
576
|
+
inputs: [
|
|
577
|
+
input("description", "Outcome", { multiline: true }),
|
|
578
|
+
input("id", "Epic ID"),
|
|
579
|
+
input("ticketUrl", "Ticket URL"),
|
|
580
|
+
input("repo", "Repository alias"),
|
|
581
|
+
input("ref", "Repository ref"),
|
|
582
|
+
],
|
|
583
|
+
},
|
|
584
|
+
{
|
|
585
|
+
id: "<id>",
|
|
586
|
+
description: "<description>",
|
|
587
|
+
ticketUrl: "<ticketUrl>",
|
|
588
|
+
repo: "<repo>",
|
|
589
|
+
ref: "<ref>",
|
|
590
|
+
},
|
|
591
|
+
(p) =>
|
|
592
|
+
Effect.gen(function* () {
|
|
593
|
+
const description = yield* p.text("Outcome")
|
|
594
|
+
return {
|
|
595
|
+
description,
|
|
596
|
+
id: yield* p.id("New epic ID", description),
|
|
597
|
+
ticketUrl: yield* p.text("Ticket URL"),
|
|
598
|
+
repo: yield* p.repository(),
|
|
599
|
+
ref: yield* p.text("Repository ref", "main"),
|
|
600
|
+
}
|
|
601
|
+
}),
|
|
602
|
+
(values) => ({
|
|
603
|
+
command: [
|
|
604
|
+
"agency",
|
|
605
|
+
"epic",
|
|
606
|
+
"create",
|
|
607
|
+
values.id,
|
|
608
|
+
"--ticket-url",
|
|
609
|
+
values.ticketUrl,
|
|
610
|
+
"--repo",
|
|
611
|
+
`${values.repo}:${values.ref}`,
|
|
612
|
+
"--description",
|
|
613
|
+
values.description,
|
|
614
|
+
],
|
|
615
|
+
run: epic({
|
|
616
|
+
...options,
|
|
617
|
+
subcommand: "create",
|
|
618
|
+
args: [values.id],
|
|
619
|
+
ticketUrl: values.ticketUrl,
|
|
620
|
+
repos: [`${values.repo}:${values.ref}`],
|
|
621
|
+
description: values.description,
|
|
622
|
+
}),
|
|
623
|
+
}),
|
|
624
|
+
),
|
|
268
625
|
...(["pull-request", "ref"] as const).map((sourceType) =>
|
|
269
626
|
action(
|
|
270
627
|
{
|
|
@@ -337,6 +694,157 @@ export const actActions = (
|
|
|
337
694
|
run: status({ ...options, statuses: ["working"] }),
|
|
338
695
|
},
|
|
339
696
|
),
|
|
697
|
+
immediate(
|
|
698
|
+
{
|
|
699
|
+
id: "ready-work",
|
|
700
|
+
label: "See ready work",
|
|
701
|
+
blockedReason: null,
|
|
702
|
+
},
|
|
703
|
+
{
|
|
704
|
+
command: ["agency", "status", "--ready"],
|
|
705
|
+
run: status({ ...options, ready: true }),
|
|
706
|
+
},
|
|
707
|
+
),
|
|
708
|
+
immediate(
|
|
709
|
+
{
|
|
710
|
+
id: "repo-setup",
|
|
711
|
+
label: "Set up declared repositories",
|
|
712
|
+
blockedReason: null,
|
|
713
|
+
},
|
|
714
|
+
{
|
|
715
|
+
command: ["agency", "repo", "setup", "--apply"],
|
|
716
|
+
run: repo({ ...options, subcommand: "setup", args: [], apply: true }),
|
|
717
|
+
},
|
|
718
|
+
),
|
|
719
|
+
...(["materialize", "fetch", "verify"] as const).map((operation) =>
|
|
720
|
+
action(
|
|
721
|
+
{
|
|
722
|
+
id: `repo-${operation}`,
|
|
723
|
+
label:
|
|
724
|
+
operation === "materialize"
|
|
725
|
+
? "Materialize a repository"
|
|
726
|
+
: operation === "fetch"
|
|
727
|
+
? "Fetch a repository"
|
|
728
|
+
: "Verify a repository",
|
|
729
|
+
blockedReason: needsRepository,
|
|
730
|
+
inputs: [input("repo", "Repository alias")],
|
|
731
|
+
},
|
|
732
|
+
"<repo>",
|
|
733
|
+
(p) => p.repository(),
|
|
734
|
+
(alias) => ({
|
|
735
|
+
command: ["agency", "repo", operation, alias],
|
|
736
|
+
run: repo({ ...options, subcommand: operation, args: [alias] }),
|
|
737
|
+
}),
|
|
738
|
+
),
|
|
739
|
+
),
|
|
740
|
+
action(
|
|
741
|
+
{
|
|
742
|
+
id: "repo-rename",
|
|
743
|
+
label: "Rename a repository alias",
|
|
744
|
+
blockedReason: needsRepository,
|
|
745
|
+
inputs: [
|
|
746
|
+
input("repo", "Repository alias"),
|
|
747
|
+
input("id", "New repository alias"),
|
|
748
|
+
],
|
|
749
|
+
},
|
|
750
|
+
{ repo: "<repo>", id: "<id>" },
|
|
751
|
+
(p) =>
|
|
752
|
+
Effect.gen(function* () {
|
|
753
|
+
return {
|
|
754
|
+
repo: yield* p.repository(),
|
|
755
|
+
id: yield* p.id("New repository alias", "repository"),
|
|
756
|
+
}
|
|
757
|
+
}),
|
|
758
|
+
({ repo: alias, id }) => ({
|
|
759
|
+
command: ["agency", "repo", "rename", alias, id],
|
|
760
|
+
run: repo({
|
|
761
|
+
...options,
|
|
762
|
+
subcommand: "rename",
|
|
763
|
+
args: [alias, id],
|
|
764
|
+
}),
|
|
765
|
+
}),
|
|
766
|
+
),
|
|
767
|
+
action(
|
|
768
|
+
{
|
|
769
|
+
id: "repo-remote",
|
|
770
|
+
label: "Update a repository remote",
|
|
771
|
+
blockedReason: needsRepository,
|
|
772
|
+
inputs: [
|
|
773
|
+
input("repo", "Repository alias"),
|
|
774
|
+
input("remote", "Remote URL"),
|
|
775
|
+
],
|
|
776
|
+
},
|
|
777
|
+
{ repo: "<repo>", remote: "<remote>" },
|
|
778
|
+
(p) =>
|
|
779
|
+
Effect.gen(function* () {
|
|
780
|
+
return {
|
|
781
|
+
repo: yield* p.repository(),
|
|
782
|
+
remote: yield* p.text("Portable remote URL"),
|
|
783
|
+
}
|
|
784
|
+
}),
|
|
785
|
+
({ repo: alias, remote }) => ({
|
|
786
|
+
command: ["agency", "repo", "remote", alias, remote],
|
|
787
|
+
run: repo({
|
|
788
|
+
...options,
|
|
789
|
+
subcommand: "remote",
|
|
790
|
+
args: [alias, remote],
|
|
791
|
+
}),
|
|
792
|
+
}),
|
|
793
|
+
),
|
|
794
|
+
...(["unlink", "remove"] as const).map((operation) =>
|
|
795
|
+
action(
|
|
796
|
+
{
|
|
797
|
+
id: `repo-${operation}`,
|
|
798
|
+
label:
|
|
799
|
+
operation === "unlink"
|
|
800
|
+
? "Unlink a local repository"
|
|
801
|
+
: "Remove a repository alias",
|
|
802
|
+
blockedReason: needsRepository,
|
|
803
|
+
inputs: [input("repo", "Repository alias")],
|
|
804
|
+
},
|
|
805
|
+
"<repo>",
|
|
806
|
+
(p) => p.repository(),
|
|
807
|
+
(alias) => ({
|
|
808
|
+
command: ["agency", "repo", operation, alias],
|
|
809
|
+
run: repo({ ...options, subcommand: operation, args: [alias] }),
|
|
810
|
+
}),
|
|
811
|
+
),
|
|
812
|
+
),
|
|
813
|
+
immediate(
|
|
814
|
+
{ id: "validate", label: "Validate workbase", blockedReason: null },
|
|
815
|
+
{
|
|
816
|
+
command: ["agency", "validate"],
|
|
817
|
+
run: validate(options),
|
|
818
|
+
},
|
|
819
|
+
),
|
|
820
|
+
immediate(
|
|
821
|
+
{ id: "doctor", label: "Diagnose workbase", blockedReason: null },
|
|
822
|
+
{ command: ["agency", "doctor"], run: doctor(options) },
|
|
823
|
+
),
|
|
824
|
+
immediate(
|
|
825
|
+
{
|
|
826
|
+
id: "sync-all",
|
|
827
|
+
label: "Refresh all Agency state",
|
|
828
|
+
blockedReason: null,
|
|
829
|
+
},
|
|
830
|
+
{ command: ["agency", "sync"], run: sync(options) },
|
|
831
|
+
),
|
|
832
|
+
...(["status", "sync"] as const).map((operation) =>
|
|
833
|
+
immediate(
|
|
834
|
+
{
|
|
835
|
+
id: `integration-${operation}`,
|
|
836
|
+
label:
|
|
837
|
+
operation === "status"
|
|
838
|
+
? "Check agent integration"
|
|
839
|
+
: "Update agent integration",
|
|
840
|
+
blockedReason: null,
|
|
841
|
+
},
|
|
842
|
+
{
|
|
843
|
+
command: ["agency", "integration", operation],
|
|
844
|
+
run: integration({ ...options, subcommand: operation }),
|
|
845
|
+
},
|
|
846
|
+
),
|
|
847
|
+
),
|
|
340
848
|
]
|
|
341
849
|
|
|
342
850
|
const target = taskTarget(node)
|
|
@@ -393,6 +901,14 @@ export const actActions = (
|
|
|
393
901
|
return target.phaseId ? phase(update) : task(update)
|
|
394
902
|
}
|
|
395
903
|
const workTarget = node.kind === "epic" ? { epicId: node.key } : target
|
|
904
|
+
const itemDirectory = join(
|
|
905
|
+
options.cwd ?? process.cwd(),
|
|
906
|
+
node.kind === "epic"
|
|
907
|
+
? `epics/${node.key}`
|
|
908
|
+
: target.phaseId
|
|
909
|
+
? `tasks/${target.taskId}/phases/${target.phaseId}`
|
|
910
|
+
: `tasks/${target.taskId}`,
|
|
911
|
+
)
|
|
396
912
|
const canWork =
|
|
397
913
|
node.readiness.ready ||
|
|
398
914
|
Boolean(
|
|
@@ -424,6 +940,22 @@ export const actActions = (
|
|
|
424
940
|
run: Effect.suspend(() => work({ ...options, ...workTarget })),
|
|
425
941
|
},
|
|
426
942
|
),
|
|
943
|
+
immediate(
|
|
944
|
+
details(
|
|
945
|
+
"push",
|
|
946
|
+
"Publish branch without a pull request",
|
|
947
|
+
noExecution ??
|
|
948
|
+
(parent && "review" in parent.data
|
|
949
|
+
? "Review tasks do not publish delivery branches"
|
|
950
|
+
: node.status !== "working"
|
|
951
|
+
? "Item must be working before publication"
|
|
952
|
+
: null),
|
|
953
|
+
),
|
|
954
|
+
{
|
|
955
|
+
command: ["agency", "--cwd", itemDirectory, "push"],
|
|
956
|
+
run: push({ ...options, cwd: itemDirectory }),
|
|
957
|
+
},
|
|
958
|
+
),
|
|
427
959
|
immediate(
|
|
428
960
|
details(
|
|
429
961
|
"pr",
|
|
@@ -450,6 +982,31 @@ export const actActions = (
|
|
|
450
982
|
run: prCreate({ ...options, ...target }),
|
|
451
983
|
},
|
|
452
984
|
),
|
|
985
|
+
immediate(
|
|
986
|
+
details(
|
|
987
|
+
"review-refresh",
|
|
988
|
+
"Refresh review source",
|
|
989
|
+
node.kind === "task" && "review" in node.data
|
|
990
|
+
? null
|
|
991
|
+
: "Select a review task",
|
|
992
|
+
),
|
|
993
|
+
{
|
|
994
|
+
command: [
|
|
995
|
+
"agency",
|
|
996
|
+
"review",
|
|
997
|
+
"refresh",
|
|
998
|
+
target.taskId,
|
|
999
|
+
"--if-revision",
|
|
1000
|
+
node.data.sha256,
|
|
1001
|
+
],
|
|
1002
|
+
run: review({
|
|
1003
|
+
...options,
|
|
1004
|
+
subcommand: "refresh",
|
|
1005
|
+
taskId: target.taskId,
|
|
1006
|
+
ifRevision: node.data.sha256,
|
|
1007
|
+
}),
|
|
1008
|
+
},
|
|
1009
|
+
),
|
|
453
1010
|
...(["reopen", "drop"] as const).map((id) => {
|
|
454
1011
|
const status = id === "reopen" ? "open" : "dropped"
|
|
455
1012
|
return immediate(
|
|
@@ -481,6 +1038,61 @@ export const actActions = (
|
|
|
481
1038
|
run: archive({ ...options, type: node.kind, args }),
|
|
482
1039
|
},
|
|
483
1040
|
),
|
|
1041
|
+
action(
|
|
1042
|
+
{
|
|
1043
|
+
...details(
|
|
1044
|
+
"task-create-in-epic",
|
|
1045
|
+
"Create a task in this epic",
|
|
1046
|
+
node.kind === "epic" ? needsRepository : "Select an epic",
|
|
1047
|
+
),
|
|
1048
|
+
inputs: [
|
|
1049
|
+
input("description", "Outcome", { multiline: true }),
|
|
1050
|
+
input("id", "Task ID"),
|
|
1051
|
+
input("repo", "Repository alias"),
|
|
1052
|
+
input("base", "Base branch"),
|
|
1053
|
+
],
|
|
1054
|
+
},
|
|
1055
|
+
{
|
|
1056
|
+
id: "<id>",
|
|
1057
|
+
description: "<description>",
|
|
1058
|
+
repo: "<repo>",
|
|
1059
|
+
base: "<base>",
|
|
1060
|
+
},
|
|
1061
|
+
(p) =>
|
|
1062
|
+
Effect.gen(function* () {
|
|
1063
|
+
const description = yield* p.text("Outcome")
|
|
1064
|
+
return {
|
|
1065
|
+
description,
|
|
1066
|
+
id: yield* p.id("New task ID", description),
|
|
1067
|
+
repo: yield* p.repository(node.repositories[0]),
|
|
1068
|
+
base: yield* p.text("Base branch", "main"),
|
|
1069
|
+
}
|
|
1070
|
+
}),
|
|
1071
|
+
(values) => ({
|
|
1072
|
+
command: [
|
|
1073
|
+
"agency",
|
|
1074
|
+
"task",
|
|
1075
|
+
"create",
|
|
1076
|
+
values.id,
|
|
1077
|
+
"--epic",
|
|
1078
|
+
node.key,
|
|
1079
|
+
"--repo",
|
|
1080
|
+
values.repo,
|
|
1081
|
+
"--base",
|
|
1082
|
+
values.base,
|
|
1083
|
+
"--description",
|
|
1084
|
+
values.description,
|
|
1085
|
+
],
|
|
1086
|
+
run: task({
|
|
1087
|
+
...options,
|
|
1088
|
+
subcommand: "create",
|
|
1089
|
+
args: [values.id],
|
|
1090
|
+
epic: node.key,
|
|
1091
|
+
...values,
|
|
1092
|
+
}),
|
|
1093
|
+
next: { taskId: values.id },
|
|
1094
|
+
}),
|
|
1095
|
+
),
|
|
484
1096
|
action(
|
|
485
1097
|
{
|
|
486
1098
|
...details(
|
|
@@ -688,14 +1300,172 @@ export const actActions = (
|
|
|
688
1300
|
},
|
|
689
1301
|
),
|
|
690
1302
|
),
|
|
1303
|
+
action(
|
|
1304
|
+
{
|
|
1305
|
+
...details("rename", "Rename item"),
|
|
1306
|
+
inputs: [input("id", "New item ID")],
|
|
1307
|
+
},
|
|
1308
|
+
"<id>",
|
|
1309
|
+
(p) =>
|
|
1310
|
+
p.id(
|
|
1311
|
+
`New ${node.kind} ID`,
|
|
1312
|
+
node.kind === "phase" ? target.phaseId! : node.key,
|
|
1313
|
+
node.kind === "phase" ? `${target.taskId}/` : "",
|
|
1314
|
+
),
|
|
1315
|
+
(id) => {
|
|
1316
|
+
const command = [
|
|
1317
|
+
"agency",
|
|
1318
|
+
node.kind,
|
|
1319
|
+
"rename",
|
|
1320
|
+
...(node.kind === "phase"
|
|
1321
|
+
? [target.taskId, target.phaseId!, id]
|
|
1322
|
+
: [node.key, id]),
|
|
1323
|
+
"--if-revision",
|
|
1324
|
+
node.data.sha256,
|
|
1325
|
+
]
|
|
1326
|
+
const update = {
|
|
1327
|
+
...options,
|
|
1328
|
+
subcommand: "rename",
|
|
1329
|
+
args:
|
|
1330
|
+
node.kind === "phase"
|
|
1331
|
+
? [target.taskId, target.phaseId!, id]
|
|
1332
|
+
: [node.key, id],
|
|
1333
|
+
ifRevision: node.data.sha256,
|
|
1334
|
+
}
|
|
1335
|
+
return {
|
|
1336
|
+
command,
|
|
1337
|
+
run:
|
|
1338
|
+
node.kind === "epic"
|
|
1339
|
+
? epic(update)
|
|
1340
|
+
: node.kind === "phase"
|
|
1341
|
+
? phase(update)
|
|
1342
|
+
: task(update),
|
|
1343
|
+
}
|
|
1344
|
+
},
|
|
1345
|
+
),
|
|
1346
|
+
action(
|
|
1347
|
+
{
|
|
1348
|
+
...details(
|
|
1349
|
+
"move-to-epic",
|
|
1350
|
+
"Move task to an epic",
|
|
1351
|
+
node.kind === "task" ? null : "Select a task",
|
|
1352
|
+
),
|
|
1353
|
+
inputs: [input("epic", "Epic ID")],
|
|
1354
|
+
},
|
|
1355
|
+
"<epic>",
|
|
1356
|
+
(p) => p.text("Destination epic ID"),
|
|
1357
|
+
(epicId) => ({
|
|
1358
|
+
command: [
|
|
1359
|
+
"agency",
|
|
1360
|
+
"task",
|
|
1361
|
+
"move",
|
|
1362
|
+
target.taskId,
|
|
1363
|
+
"--epic",
|
|
1364
|
+
epicId,
|
|
1365
|
+
"--if-revision",
|
|
1366
|
+
node.data.sha256,
|
|
1367
|
+
],
|
|
1368
|
+
run: task({
|
|
1369
|
+
...options,
|
|
1370
|
+
subcommand: "move",
|
|
1371
|
+
args: [target.taskId],
|
|
1372
|
+
epic: epicId,
|
|
1373
|
+
ifRevision: node.data.sha256,
|
|
1374
|
+
}),
|
|
1375
|
+
}),
|
|
1376
|
+
),
|
|
1377
|
+
immediate(
|
|
1378
|
+
details(
|
|
1379
|
+
"remove-from-epic",
|
|
1380
|
+
"Remove task from its epic",
|
|
1381
|
+
node.kind === "task" && node.data.epic
|
|
1382
|
+
? null
|
|
1383
|
+
: "Select a task that belongs to an epic",
|
|
1384
|
+
),
|
|
1385
|
+
{
|
|
1386
|
+
command: [
|
|
1387
|
+
"agency",
|
|
1388
|
+
"task",
|
|
1389
|
+
"move",
|
|
1390
|
+
target.taskId,
|
|
1391
|
+
"--no-epic",
|
|
1392
|
+
"--if-revision",
|
|
1393
|
+
node.data.sha256,
|
|
1394
|
+
],
|
|
1395
|
+
run: task({
|
|
1396
|
+
...options,
|
|
1397
|
+
subcommand: "move",
|
|
1398
|
+
args: [target.taskId],
|
|
1399
|
+
noEpic: true,
|
|
1400
|
+
ifRevision: node.data.sha256,
|
|
1401
|
+
}),
|
|
1402
|
+
},
|
|
1403
|
+
),
|
|
1404
|
+
...(["add", "remove"] as const).map((operation) =>
|
|
1405
|
+
action(
|
|
1406
|
+
{
|
|
1407
|
+
...details(
|
|
1408
|
+
`dependency-${operation}`,
|
|
1409
|
+
operation === "add" ? "Add dependency" : "Remove dependency",
|
|
1410
|
+
node.kind === "phase"
|
|
1411
|
+
? terminal
|
|
1412
|
+
? "Phase is terminal"
|
|
1413
|
+
: null
|
|
1414
|
+
: node.kind === "task" && node.data.epic
|
|
1415
|
+
? terminal
|
|
1416
|
+
? "Task is terminal"
|
|
1417
|
+
: null
|
|
1418
|
+
: "Select a phase or a task in an epic",
|
|
1419
|
+
),
|
|
1420
|
+
inputs: [input("dependency", "Dependency ID")],
|
|
1421
|
+
},
|
|
1422
|
+
"<dependency>",
|
|
1423
|
+
(p) =>
|
|
1424
|
+
p.text(`${operation === "add" ? "Required" : "Current"} sibling ID`),
|
|
1425
|
+
(dependency) => {
|
|
1426
|
+
const command = [
|
|
1427
|
+
"agency",
|
|
1428
|
+
node.kind === "phase" ? "phase" : "task",
|
|
1429
|
+
"dependency",
|
|
1430
|
+
operation,
|
|
1431
|
+
...args,
|
|
1432
|
+
dependency,
|
|
1433
|
+
"--if-revision",
|
|
1434
|
+
node.data.sha256,
|
|
1435
|
+
]
|
|
1436
|
+
const update = {
|
|
1437
|
+
...options,
|
|
1438
|
+
subcommand: "dependency",
|
|
1439
|
+
args: [operation, ...args, dependency],
|
|
1440
|
+
ifRevision: node.data.sha256,
|
|
1441
|
+
}
|
|
1442
|
+
return {
|
|
1443
|
+
command,
|
|
1444
|
+
run: node.kind === "phase" ? phase(update) : task(update),
|
|
1445
|
+
}
|
|
1446
|
+
},
|
|
1447
|
+
),
|
|
1448
|
+
),
|
|
691
1449
|
]
|
|
692
1450
|
}
|
|
693
1451
|
|
|
694
1452
|
export const actionOutput = (action: ActAction, auto?: boolean) => {
|
|
695
|
-
const {
|
|
1453
|
+
const {
|
|
1454
|
+
id,
|
|
1455
|
+
label,
|
|
1456
|
+
description,
|
|
1457
|
+
icon,
|
|
1458
|
+
color,
|
|
1459
|
+
blockedReason,
|
|
1460
|
+
preview,
|
|
1461
|
+
inputs = [],
|
|
1462
|
+
} = action
|
|
696
1463
|
return {
|
|
697
1464
|
id,
|
|
698
1465
|
label,
|
|
1466
|
+
description,
|
|
1467
|
+
icon,
|
|
1468
|
+
color,
|
|
699
1469
|
available: blockedReason === null,
|
|
700
1470
|
blockedReason,
|
|
701
1471
|
...(blockedReason
|
package/src/commands/act.ts
CHANGED
|
@@ -169,29 +169,18 @@ const entitySummary = (node: ActEntity) => ({
|
|
|
169
169
|
readiness: node.readiness,
|
|
170
170
|
revision: node.data.sha256,
|
|
171
171
|
})
|
|
172
|
-
const actionIcons: Record<string, string> = {
|
|
173
|
-
reopen: "",
|
|
174
|
-
drop: "",
|
|
175
|
-
complete: "",
|
|
176
|
-
sync: "",
|
|
177
|
-
"pr-ready": "",
|
|
178
|
-
"pr-close": "",
|
|
179
|
-
}
|
|
180
172
|
const actionChoices = (actions: readonly ActAction[]): Choice<string>[] =>
|
|
181
|
-
actions.map(({ id, label }) => {
|
|
182
|
-
const icon =
|
|
183
|
-
actionIcons[id] ??
|
|
184
|
-
actionGroups.find((group) =>
|
|
185
|
-
group.actions.some((action) => action === id),
|
|
186
|
-
)!.icon
|
|
187
|
-
const color =
|
|
188
|
-
id === "drop" || id === "pr-close" ? macchiato.red : macchiato.overlay1
|
|
173
|
+
actions.map(({ id, label, description, icon, color }) => {
|
|
189
174
|
return {
|
|
190
175
|
key: id,
|
|
191
176
|
value: id,
|
|
192
|
-
label: `${icon} ${label}`,
|
|
193
|
-
plainLabel: label
|
|
194
|
-
segments: [
|
|
177
|
+
label: `${icon} ${label} — ${description}`,
|
|
178
|
+
plainLabel: `${label} — ${description}`,
|
|
179
|
+
segments: [
|
|
180
|
+
{ text: `${icon} `, color },
|
|
181
|
+
{ text: label },
|
|
182
|
+
{ text: ` — ${description}`, color: macchiato.overlay0 },
|
|
183
|
+
],
|
|
195
184
|
}
|
|
196
185
|
})
|
|
197
186
|
|
|
@@ -366,7 +355,7 @@ const actStep = (
|
|
|
366
355
|
? isPath
|
|
367
356
|
? pathEntityKey(root, path)
|
|
368
357
|
: `task:${options.directory}`
|
|
369
|
-
:
|
|
358
|
+
: pathEntityKey(root, path)
|
|
370
359
|
let actionId = options.action
|
|
371
360
|
if (session && options.directory && isPath && !selectedKey && !actionId)
|
|
372
361
|
session.activateTab("workbase")
|
|
@@ -568,7 +557,7 @@ const actStep = (
|
|
|
568
557
|
graph.nodes
|
|
569
558
|
.filter((node) => node.kind === "repository")
|
|
570
559
|
.map((node) => node.key),
|
|
571
|
-
nodes.
|
|
560
|
+
nodes.map((node) => node.key),
|
|
572
561
|
config.chooserCommand,
|
|
573
562
|
),
|
|
574
563
|
)
|