@markjaquith/agency 2.48.0 → 2.49.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 -19
- package/cli.ts +9 -0
- package/package.json +1 -1
- package/src/cli-parser.test.ts +58 -0
- package/src/cli-parser.ts +67 -6
- package/src/cli.test.ts +82 -3
- package/src/commands/claim.ts +26 -2
- package/src/commands/init.test.ts +3 -5
- package/src/commands/integration.test.ts +1 -16
- package/src/commands/integration.ts +0 -2
- package/src/commands/phase.ts +23 -2
- package/src/commands/task.ts +22 -2
- package/src/commands/work.test.ts +38 -4
- package/src/commands/work.ts +1 -1
- package/src/services/ClaimService.test.ts +59 -0
- package/src/services/ClaimService.ts +34 -1
- package/src/services/GraphMutationService.ts +16 -0
- package/src/services/IntegrationService.test.ts +32 -75
- package/src/services/IntegrationService.ts +27 -52
- package/src/services/PhaseService.ts +50 -3
- package/src/services/PullRequestService.test.ts +20 -0
- package/src/services/PullRequestService.ts +24 -3
- package/src/services/SyncService.test.ts +66 -0
- package/src/services/SyncService.ts +13 -0
- package/src/services/TaskPhaseService.test.ts +182 -0
- package/src/services/TaskService.ts +47 -3
- package/src/services/WorkbaseService.test.ts +58 -0
- package/src/services/WorkbaseService.ts +20 -0
- package/src/workbase/AGENTS.md +13 -8
- package/src/workbase/completion.ts +28 -0
- package/src/workbase/schemas.ts +9 -0
- package/src/workbase/AGENCY_COMMAND.md +0 -48
- package/src/workbase/opencode-command-file.ts +0 -30
package/README.md
CHANGED
|
@@ -53,7 +53,6 @@ workbase/
|
|
|
53
53
|
.opencode/
|
|
54
54
|
opencode.jsonc # managed @agency subagent, instructions, and reference
|
|
55
55
|
tui.jsonc # managed TUI plugin registration
|
|
56
|
-
command/agency.md # managed /agency workflow command
|
|
57
56
|
plugin/agency-repository-skills.ts # managed workbase access and checkout skills
|
|
58
57
|
tui/agency-debug.ts # managed /agency-debug TUI diagnostic
|
|
59
58
|
agency.json # tracked config and portable repository declarations
|
|
@@ -84,10 +83,11 @@ workbase/
|
|
|
84
83
|
|
|
85
84
|
Agency keeps discovery and other observational commands read-only. Run
|
|
86
85
|
`agency integration status` to inspect `.agency/AGENTS.md` and
|
|
87
|
-
`.opencode/opencode.jsonc`, `.opencode/tui.jsonc`, and their managed
|
|
88
|
-
|
|
86
|
+
`.opencode/opencode.jsonc`, `.opencode/tui.jsonc`, and their managed plugin
|
|
87
|
+
files, then `agency integration sync` to create missing files or refresh
|
|
89
88
|
checksum-safe managed files. Customized files are reported but never
|
|
90
|
-
overwritten.
|
|
89
|
+
overwritten. Sync also removes checksum-valid retired managed artifacts while
|
|
90
|
+
preserving customized files at their former paths. The root
|
|
91
91
|
`AGENTS.md` is user-owned and is not inspected or modified by Agency.
|
|
92
92
|
|
|
93
93
|
The managed `.agency/AGENTS.md` is the complete in-workbase operating contract
|
|
@@ -122,13 +122,6 @@ The plugin grants whole-workbase access dynamically, while the portable
|
|
|
122
122
|
reference advertises that context to agents. Bash and Agency operations must
|
|
123
123
|
still follow the write authority reported by `agency context`.
|
|
124
124
|
|
|
125
|
-
OpenCode also discovers a managed `/agency` command. Use `/agency status` for a
|
|
126
|
-
read-only current-work summary, `/agency start [target]` to begin or resume work
|
|
127
|
-
in the active session, `/agency next` to inspect ready work, `/agency validate`
|
|
128
|
-
to check the workbase, and `/agency finish [target]` for verified closeout. The
|
|
129
|
-
command uses OpenCode positional arguments internally and defaults to the safe
|
|
130
|
-
`status` workflow when no subcommand is supplied.
|
|
131
|
-
|
|
132
125
|
Repository aliases and canonical fetch remotes are declared in tracked
|
|
133
126
|
`agency.json`; local bare clones and symlinks remain ignored under
|
|
134
127
|
`repos/{alias}`. A declaration contains no local path, symlink target, checkout,
|
|
@@ -617,7 +610,8 @@ Inspect tasks:
|
|
|
617
610
|
```text
|
|
618
611
|
agency task list [filters] [--json]
|
|
619
612
|
agency task show <id> [--json]
|
|
620
|
-
agency task status <id> <open|working|dropped>
|
|
613
|
+
agency task status <id> <open|working|done|dropped>
|
|
614
|
+
[--no-pull-request --summary <text> [--evidence-url <url>]] [--json]
|
|
621
615
|
agency task update <id> [metadata options] [--json]
|
|
622
616
|
agency task rename <id> <new-id> [--json]
|
|
623
617
|
agency task move <id> (--epic <epic-id> | --no-epic) [--json]
|
|
@@ -656,7 +650,8 @@ agency phase create <task-id> <phase-id>
|
|
|
656
650
|
|
|
657
651
|
agency phase list <task-id> [filters] [--json]
|
|
658
652
|
agency phase show <task-id> <phase-id> [--json]
|
|
659
|
-
agency phase status <task-id> <phase-id> <open|working|dropped>
|
|
653
|
+
agency phase status <task-id> <phase-id> <open|working|done|dropped>
|
|
654
|
+
[--no-pull-request --summary <text> [--evidence-url <url>]] [--json]
|
|
660
655
|
agency phase update <task-id> <phase-id> [metadata options] [--json]
|
|
661
656
|
agency phase rename <task-id> <phase-id> <new-id> [--json]
|
|
662
657
|
agency phase dependency <add|remove> <task-id> <phase-id> <dependency-id>
|
|
@@ -679,8 +674,12 @@ writing anything.
|
|
|
679
674
|
Single-phase tasks and phases store status in YAML. New execution units start
|
|
680
675
|
`open`, and `agency work` marks the selected execution unit `working` immediately
|
|
681
676
|
before launch. Running `agency work` again can relaunch unclaimed `working` work.
|
|
682
|
-
|
|
683
|
-
|
|
677
|
+
By default, `done` requires an authoritative merged pull request and is applied
|
|
678
|
+
by `agency sync --apply`. Work whose intended outcome genuinely requires no pull
|
|
679
|
+
request may instead use an explicit `--no-pull-request --summary <text>` status
|
|
680
|
+
transition. Agency records the summary, completion time, and optional evidence
|
|
681
|
+
URL durably; reopening removes that evidence. This exceptional path refuses work
|
|
682
|
+
that already has a recorded pull request.
|
|
684
683
|
Use explicit claims only when an external orchestrator needs coordinated
|
|
685
684
|
ownership. The interactive work selector displays status markers before
|
|
686
685
|
execution units. Existing working and delegated work may be released to `open`
|
|
@@ -711,15 +710,19 @@ agency claim <task-id> [phase-id] --claimant <id> --runner <id>
|
|
|
711
710
|
agency release <task-id> [phase-id] --session-id <id>
|
|
712
711
|
--revision <sha256> [--json]
|
|
713
712
|
agency finish <task-id> [phase-id] --session-id <id>
|
|
714
|
-
--revision <sha256> --outcome <done|dropped>
|
|
713
|
+
--revision <sha256> --outcome <done|dropped>
|
|
714
|
+
[--no-pull-request --summary <text> [--evidence-url <url>]] [--json]
|
|
715
715
|
```
|
|
716
716
|
|
|
717
717
|
An active claim sets status to `working`. Release returns it to `open`. Finish
|
|
718
718
|
records the claim outcome and ownership history; a `done` claim outcome leaves
|
|
719
719
|
the execution unit `working` until its pull request is merged, while `dropped`
|
|
720
|
-
remains terminal.
|
|
721
|
-
|
|
722
|
-
|
|
720
|
+
remains terminal. For a genuine non-PR outcome, `--no-pull-request` atomically
|
|
721
|
+
records completion evidence, finishes the claim, and sets the execution unit to
|
|
722
|
+
`done`; `--summary` is required and `--evidence-url` is optional. Conflicts return
|
|
723
|
+
the current revision and complete ownership record in the machine error envelope
|
|
724
|
+
rather than overwriting it. Expired claims may be replaced with a
|
|
725
|
+
revision-guarded claim.
|
|
723
726
|
|
|
724
727
|
`agency work` does not claim execution units. It refuses active explicit claims,
|
|
725
728
|
marks open execution work `working`, and launches the runner. External
|
package/cli.ts
CHANGED
|
@@ -205,6 +205,9 @@ const commands: Record<string, Command> = {
|
|
|
205
205
|
sessionId: options["session-id"],
|
|
206
206
|
revision: options.revision,
|
|
207
207
|
outcome: options.outcome,
|
|
208
|
+
noPullRequest: options["no-pull-request"],
|
|
209
|
+
summary: options.summary,
|
|
210
|
+
evidenceUrl: options["evidence-url"],
|
|
208
211
|
json: options.json,
|
|
209
212
|
silent: options.silent,
|
|
210
213
|
verbose: options.verbose,
|
|
@@ -298,6 +301,9 @@ const commands: Record<string, Command> = {
|
|
|
298
301
|
clearReferences: options["clear-references"],
|
|
299
302
|
prUrl: options["pr-url"],
|
|
300
303
|
clearPr: options["clear-pr"],
|
|
304
|
+
noPullRequest: options["no-pull-request"],
|
|
305
|
+
summary: options.summary,
|
|
306
|
+
evidenceUrl: options["evidence-url"],
|
|
301
307
|
ifRevision: options["if-revision"],
|
|
302
308
|
dependsOn: options["depends-on"],
|
|
303
309
|
firstPhase: options["first-phase"],
|
|
@@ -449,6 +455,9 @@ const commands: Record<string, Command> = {
|
|
|
449
455
|
clearReferences: options["clear-references"],
|
|
450
456
|
prUrl: options["pr-url"],
|
|
451
457
|
clearPr: options["clear-pr"],
|
|
458
|
+
noPullRequest: options["no-pull-request"],
|
|
459
|
+
summary: options.summary,
|
|
460
|
+
evidenceUrl: options["evidence-url"],
|
|
452
461
|
ifRevision: options["if-revision"],
|
|
453
462
|
noEpic: options["no-epic"],
|
|
454
463
|
multiPhase: options["multi-phase"],
|
package/package.json
CHANGED
package/src/cli-parser.test.ts
CHANGED
|
@@ -362,6 +362,64 @@ describe("strict CLI parsing", () => {
|
|
|
362
362
|
"working",
|
|
363
363
|
]),
|
|
364
364
|
).toThrow("must be 'done' or 'dropped'")
|
|
365
|
+
expect(
|
|
366
|
+
parseCli([
|
|
367
|
+
"finish",
|
|
368
|
+
"task",
|
|
369
|
+
"--session-id",
|
|
370
|
+
"job-1",
|
|
371
|
+
"--revision",
|
|
372
|
+
revision,
|
|
373
|
+
"--outcome",
|
|
374
|
+
"done",
|
|
375
|
+
"--no-pull-request",
|
|
376
|
+
"--summary",
|
|
377
|
+
"Investigation completed",
|
|
378
|
+
"--evidence-url",
|
|
379
|
+
"https://example.com/result",
|
|
380
|
+
]),
|
|
381
|
+
).toMatchObject({
|
|
382
|
+
values: {
|
|
383
|
+
"no-pull-request": true,
|
|
384
|
+
summary: "Investigation completed",
|
|
385
|
+
"evidence-url": "https://example.com/result",
|
|
386
|
+
},
|
|
387
|
+
})
|
|
388
|
+
expect(() =>
|
|
389
|
+
parseCli([
|
|
390
|
+
"finish",
|
|
391
|
+
"task",
|
|
392
|
+
"--session-id",
|
|
393
|
+
"job-1",
|
|
394
|
+
"--revision",
|
|
395
|
+
revision,
|
|
396
|
+
"--outcome",
|
|
397
|
+
"done",
|
|
398
|
+
"--no-pull-request",
|
|
399
|
+
]),
|
|
400
|
+
).toThrow("--summary' is required")
|
|
401
|
+
expect(() =>
|
|
402
|
+
parseCli([
|
|
403
|
+
"task",
|
|
404
|
+
"status",
|
|
405
|
+
"example",
|
|
406
|
+
"working",
|
|
407
|
+
"--no-pull-request",
|
|
408
|
+
"--summary",
|
|
409
|
+
"Not done",
|
|
410
|
+
]),
|
|
411
|
+
).toThrow("valid only with a done status")
|
|
412
|
+
expect(() =>
|
|
413
|
+
parseCli([
|
|
414
|
+
"phase",
|
|
415
|
+
"status",
|
|
416
|
+
"task",
|
|
417
|
+
"phase",
|
|
418
|
+
"done",
|
|
419
|
+
"--summary",
|
|
420
|
+
"Missing explicit flag",
|
|
421
|
+
]),
|
|
422
|
+
).toThrow("require '--no-pull-request'")
|
|
365
423
|
})
|
|
366
424
|
|
|
367
425
|
test("accepts valid mutation revisions and rejects malformed hashes", () => {
|
package/src/cli-parser.ts
CHANGED
|
@@ -120,6 +120,12 @@ const ownedClaimOptions = {
|
|
|
120
120
|
revision: { type: "string" },
|
|
121
121
|
} satisfies OptionConfig
|
|
122
122
|
|
|
123
|
+
const nonPrCompletionOptions = {
|
|
124
|
+
"no-pull-request": { type: "boolean" },
|
|
125
|
+
summary: { type: "string" },
|
|
126
|
+
"evidence-url": { type: "string" },
|
|
127
|
+
} satisfies OptionConfig
|
|
128
|
+
|
|
123
129
|
const commands = {
|
|
124
130
|
init: {
|
|
125
131
|
usage: "agency init [path] [--json]",
|
|
@@ -360,6 +366,7 @@ const commands = {
|
|
|
360
366
|
...newWorkOptions,
|
|
361
367
|
...viewOptions,
|
|
362
368
|
...mutationOptions,
|
|
369
|
+
...nonPrCompletionOptions,
|
|
363
370
|
"pr-url": { type: "string" },
|
|
364
371
|
task: { type: "string" },
|
|
365
372
|
},
|
|
@@ -417,10 +424,10 @@ const commands = {
|
|
|
417
424
|
options: ["json", "task"],
|
|
418
425
|
},
|
|
419
426
|
status: {
|
|
420
|
-
usage: "agency task status <id> <status> [--json]",
|
|
427
|
+
usage: "agency task status <id> <status> [options] [--json]",
|
|
421
428
|
minArgs: 2,
|
|
422
429
|
maxArgs: 2,
|
|
423
|
-
options: ["json", "task"],
|
|
430
|
+
options: ["json", "task", "no-pull-request", "summary", "evidence-url"],
|
|
424
431
|
},
|
|
425
432
|
update: {
|
|
426
433
|
usage: "agency task update <id> [options] [--json]",
|
|
@@ -479,6 +486,7 @@ const commands = {
|
|
|
479
486
|
...newWorkOptions,
|
|
480
487
|
...viewOptions,
|
|
481
488
|
...mutationOptions,
|
|
489
|
+
...nonPrCompletionOptions,
|
|
482
490
|
"pr-url": { type: "string" },
|
|
483
491
|
task: { type: "string" },
|
|
484
492
|
phase: { type: "string" },
|
|
@@ -542,10 +550,18 @@ const commands = {
|
|
|
542
550
|
options: ["json", "task", "phase"],
|
|
543
551
|
},
|
|
544
552
|
status: {
|
|
545
|
-
usage:
|
|
553
|
+
usage:
|
|
554
|
+
"agency phase status <task-id> <phase-id> <status> [options] [--json]",
|
|
546
555
|
minArgs: 3,
|
|
547
556
|
maxArgs: 3,
|
|
548
|
-
options: [
|
|
557
|
+
options: [
|
|
558
|
+
"json",
|
|
559
|
+
"task",
|
|
560
|
+
"phase",
|
|
561
|
+
"no-pull-request",
|
|
562
|
+
"summary",
|
|
563
|
+
"evidence-url",
|
|
564
|
+
],
|
|
549
565
|
},
|
|
550
566
|
update: {
|
|
551
567
|
usage: "agency phase update <task-id> <phase-id> [options] [--json]",
|
|
@@ -631,16 +647,27 @@ const commands = {
|
|
|
631
647
|
usage: "agency finish <task-id> [phase-id] [options]",
|
|
632
648
|
options: {
|
|
633
649
|
...ownedClaimOptions,
|
|
650
|
+
...nonPrCompletionOptions,
|
|
634
651
|
outcome: { type: "string" },
|
|
635
652
|
task: { type: "string" },
|
|
636
653
|
phase: { type: "string" },
|
|
637
654
|
},
|
|
638
655
|
command: {
|
|
639
656
|
usage:
|
|
640
|
-
"agency finish <task-id> [phase-id] --session-id <id> --revision <sha256> --outcome <done|dropped> [--json]",
|
|
657
|
+
"agency finish <task-id> [phase-id] --session-id <id> --revision <sha256> --outcome <done|dropped> [options] [--json]",
|
|
641
658
|
minArgs: 1,
|
|
642
659
|
maxArgs: 2,
|
|
643
|
-
options: [
|
|
660
|
+
options: [
|
|
661
|
+
"session-id",
|
|
662
|
+
"revision",
|
|
663
|
+
"outcome",
|
|
664
|
+
"no-pull-request",
|
|
665
|
+
"summary",
|
|
666
|
+
"evidence-url",
|
|
667
|
+
"json",
|
|
668
|
+
"task",
|
|
669
|
+
"phase",
|
|
670
|
+
],
|
|
644
671
|
required: ["session-id", "revision", "outcome"],
|
|
645
672
|
},
|
|
646
673
|
},
|
|
@@ -1409,6 +1436,40 @@ export function parseCli(args: readonly string[]): ParsedCli {
|
|
|
1409
1436
|
spec.usage,
|
|
1410
1437
|
)
|
|
1411
1438
|
}
|
|
1439
|
+
const nonPrCompletion = parsed.values["no-pull-request"] === true
|
|
1440
|
+
const completionSummary = parsed.values.summary
|
|
1441
|
+
const completionEvidenceUrl = parsed.values["evidence-url"]
|
|
1442
|
+
if (
|
|
1443
|
+
(completionSummary !== undefined || completionEvidenceUrl !== undefined) &&
|
|
1444
|
+
!nonPrCompletion
|
|
1445
|
+
) {
|
|
1446
|
+
throw usageError(
|
|
1447
|
+
"Options '--summary' and '--evidence-url' require '--no-pull-request'.",
|
|
1448
|
+
spec.usage,
|
|
1449
|
+
)
|
|
1450
|
+
}
|
|
1451
|
+
if (nonPrCompletion) {
|
|
1452
|
+
if (
|
|
1453
|
+
typeof completionSummary !== "string" ||
|
|
1454
|
+
completionSummary.trim().length === 0
|
|
1455
|
+
) {
|
|
1456
|
+
throw usageError(
|
|
1457
|
+
"Option '--summary' is required with '--no-pull-request'.",
|
|
1458
|
+
spec.usage,
|
|
1459
|
+
)
|
|
1460
|
+
}
|
|
1461
|
+
const completesDone =
|
|
1462
|
+
(commandName === "finish" && parsed.values.outcome === "done") ||
|
|
1463
|
+
(["task", "phase"].includes(commandName) &&
|
|
1464
|
+
subcommand === "status" &&
|
|
1465
|
+
commandPositionals.at(-1) === "done")
|
|
1466
|
+
if (!completesDone) {
|
|
1467
|
+
throw usageError(
|
|
1468
|
+
"Option '--no-pull-request' is valid only with a done status or outcome.",
|
|
1469
|
+
spec.usage,
|
|
1470
|
+
)
|
|
1471
|
+
}
|
|
1472
|
+
}
|
|
1412
1473
|
if (commandName === "work") {
|
|
1413
1474
|
const preparing = commandPositionals[0] === "prepare"
|
|
1414
1475
|
if (
|
package/src/cli.test.ts
CHANGED
|
@@ -248,6 +248,77 @@ describe("CLI", () => {
|
|
|
248
248
|
parseJson(await runCli(["task", "show", "claimed", "--json"], root)).data
|
|
249
249
|
.status,
|
|
250
250
|
).toBe("working")
|
|
251
|
+
|
|
252
|
+
parseJson(
|
|
253
|
+
await runCli(
|
|
254
|
+
["task", "create", "non-pr", "--repo", "agency", "--json"],
|
|
255
|
+
root,
|
|
256
|
+
),
|
|
257
|
+
)
|
|
258
|
+
const nonPrContext = parseJson(
|
|
259
|
+
await runCli(["context", "tasks/non-pr", "--json"], root),
|
|
260
|
+
)
|
|
261
|
+
const nonPrClaim = parseJson(
|
|
262
|
+
await runCli(
|
|
263
|
+
[
|
|
264
|
+
"claim",
|
|
265
|
+
"non-pr",
|
|
266
|
+
"--claimant",
|
|
267
|
+
"orchestrator",
|
|
268
|
+
"--runner",
|
|
269
|
+
"agent",
|
|
270
|
+
"--session-id",
|
|
271
|
+
"job-2",
|
|
272
|
+
"--revision",
|
|
273
|
+
nonPrContext.documents.task.sha256,
|
|
274
|
+
"--json",
|
|
275
|
+
],
|
|
276
|
+
root,
|
|
277
|
+
),
|
|
278
|
+
)
|
|
279
|
+
parseJson(
|
|
280
|
+
await runCli(
|
|
281
|
+
[
|
|
282
|
+
"finish",
|
|
283
|
+
"non-pr",
|
|
284
|
+
"--session-id",
|
|
285
|
+
"job-2",
|
|
286
|
+
"--revision",
|
|
287
|
+
nonPrClaim.revision,
|
|
288
|
+
"--outcome",
|
|
289
|
+
"done",
|
|
290
|
+
"--no-pull-request",
|
|
291
|
+
"--summary",
|
|
292
|
+
"Investigation completed without changes.",
|
|
293
|
+
"--evidence-url",
|
|
294
|
+
"https://example.com/result",
|
|
295
|
+
"--json",
|
|
296
|
+
],
|
|
297
|
+
root,
|
|
298
|
+
),
|
|
299
|
+
)
|
|
300
|
+
expect(
|
|
301
|
+
parseJson(await runCli(["task", "show", "non-pr", "--json"], root)).data,
|
|
302
|
+
).toMatchObject({
|
|
303
|
+
status: "done",
|
|
304
|
+
completion: {
|
|
305
|
+
mode: "non-pr",
|
|
306
|
+
summary: "Investigation completed without changes.",
|
|
307
|
+
evidenceUrl: "https://example.com/result",
|
|
308
|
+
},
|
|
309
|
+
})
|
|
310
|
+
const prUpdate = await runCli(
|
|
311
|
+
[
|
|
312
|
+
"task",
|
|
313
|
+
"update",
|
|
314
|
+
"non-pr",
|
|
315
|
+
"--pr-url",
|
|
316
|
+
"https://github.com/example/agency/pull/1",
|
|
317
|
+
],
|
|
318
|
+
root,
|
|
319
|
+
)
|
|
320
|
+
expect(prUpdate.exitCode).toBe(1)
|
|
321
|
+
expect(prUpdate.stderr).toContain("Reopen non-PR completed work")
|
|
251
322
|
})
|
|
252
323
|
|
|
253
324
|
test("routes graph mutations through structured output", async () => {
|
|
@@ -526,7 +597,6 @@ describe("CLI", () => {
|
|
|
526
597
|
expect(before.files).toMatchObject([
|
|
527
598
|
{ name: "agents", state: "managed" },
|
|
528
599
|
{ name: "opencode", state: "managed" },
|
|
529
|
-
{ name: "opencode-command", state: "managed" },
|
|
530
600
|
{ name: "opencode-plugin", state: "managed" },
|
|
531
601
|
{ name: "opencode-tui", state: "managed" },
|
|
532
602
|
{ name: "opencode-tui-plugin", state: "managed" },
|
|
@@ -538,7 +608,6 @@ describe("CLI", () => {
|
|
|
538
608
|
expect(synced.files).toMatchObject([
|
|
539
609
|
{ name: "agents", state: "managed", changed: false },
|
|
540
610
|
{ name: "opencode", state: "managed", changed: false },
|
|
541
|
-
{ name: "opencode-command", state: "managed", changed: false },
|
|
542
611
|
{ name: "opencode-plugin", state: "managed", changed: false },
|
|
543
612
|
{ name: "opencode-tui", state: "managed", changed: false },
|
|
544
613
|
{ name: "opencode-tui-plugin", state: "managed", changed: false },
|
|
@@ -1022,7 +1091,7 @@ status: open
|
|
|
1022
1091
|
},
|
|
1023
1092
|
{
|
|
1024
1093
|
args: ["--task", "pipeline", "--phase", "build"],
|
|
1025
|
-
cwd: join(workbaseRoot, "tasks/pipeline"),
|
|
1094
|
+
cwd: join(workbaseRoot, "tasks/pipeline/phases/build"),
|
|
1026
1095
|
checkoutPath: join(
|
|
1027
1096
|
workbaseRoot,
|
|
1028
1097
|
"tasks/pipeline/phases/build/code/agency",
|
|
@@ -1060,6 +1129,16 @@ status: open
|
|
|
1060
1129
|
launch.checkoutPath,
|
|
1061
1130
|
)
|
|
1062
1131
|
expect(contract.environment.OPENCODE_CONFIG_CONTENT).toBeUndefined()
|
|
1132
|
+
if (launch === launches[1]) {
|
|
1133
|
+
const context = parseJson(
|
|
1134
|
+
await runCli(["context", ".", "--json"], contract.cwd),
|
|
1135
|
+
)
|
|
1136
|
+
expect(context.target).toMatchObject({
|
|
1137
|
+
kind: "phase",
|
|
1138
|
+
taskId: "pipeline",
|
|
1139
|
+
phaseId: "build",
|
|
1140
|
+
})
|
|
1141
|
+
}
|
|
1063
1142
|
const environment = {
|
|
1064
1143
|
...process.env,
|
|
1065
1144
|
...contract.environment,
|
package/src/commands/claim.ts
CHANGED
|
@@ -13,6 +13,9 @@ interface ClaimCommandOptions extends BaseCommandOptions {
|
|
|
13
13
|
readonly revision?: string
|
|
14
14
|
readonly expiresAt?: string
|
|
15
15
|
readonly outcome?: string
|
|
16
|
+
readonly noPullRequest?: boolean
|
|
17
|
+
readonly summary?: string
|
|
18
|
+
readonly evidenceUrl?: string
|
|
16
19
|
readonly json?: boolean
|
|
17
20
|
}
|
|
18
21
|
|
|
@@ -32,6 +35,16 @@ export const claimCommand = (options: ClaimCommandOptions) =>
|
|
|
32
35
|
new Error("Claimant and runner identities are required"),
|
|
33
36
|
)
|
|
34
37
|
}
|
|
38
|
+
if (options.noPullRequest && !options.summary?.trim()) {
|
|
39
|
+
return yield* Effect.fail(
|
|
40
|
+
new Error("Non-PR completion requires a non-empty summary"),
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
if (options.noPullRequest && options.outcome !== "done") {
|
|
44
|
+
return yield* Effect.fail(
|
|
45
|
+
new Error("Non-PR completion is valid only with a done outcome"),
|
|
46
|
+
)
|
|
47
|
+
}
|
|
35
48
|
if (
|
|
36
49
|
options.operation === "finish" &&
|
|
37
50
|
options.outcome !== "done" &&
|
|
@@ -65,6 +78,16 @@ export const claimCommand = (options: ClaimCommandOptions) =>
|
|
|
65
78
|
{
|
|
66
79
|
...common,
|
|
67
80
|
outcome: options.outcome as "done" | "dropped",
|
|
81
|
+
...(options.noPullRequest
|
|
82
|
+
? {
|
|
83
|
+
nonPrCompletion: {
|
|
84
|
+
summary: options.summary!,
|
|
85
|
+
...(options.evidenceUrl
|
|
86
|
+
? { evidenceUrl: options.evidenceUrl }
|
|
87
|
+
: {}),
|
|
88
|
+
},
|
|
89
|
+
}
|
|
90
|
+
: {}),
|
|
68
91
|
},
|
|
69
92
|
cwd,
|
|
70
93
|
)
|
|
@@ -91,8 +114,9 @@ Release an execution unit owned by the session.
|
|
|
91
114
|
`
|
|
92
115
|
|
|
93
116
|
export const finishHelp = `
|
|
94
|
-
Usage: agency finish <task-id> [phase-id] --session-id <id> --revision <sha256> --outcome <done|dropped>
|
|
117
|
+
Usage: agency finish <task-id> [phase-id] --session-id <id> --revision <sha256> --outcome <done|dropped> [--no-pull-request --summary <text> [--evidence-url <url>]]
|
|
95
118
|
|
|
96
119
|
Finish a claim owned by the session. A done claim outcome leaves unmerged work
|
|
97
|
-
working; agency sync --apply marks the execution unit done after merge.
|
|
120
|
+
working; agency sync --apply marks the execution unit done after merge. Use
|
|
121
|
+
--no-pull-request with a summary for an explicit non-PR completion.
|
|
98
122
|
`
|
|
@@ -68,11 +68,9 @@ describe("init command", () => {
|
|
|
68
68
|
workbase: expect.objectContaining({ path: ".." }),
|
|
69
69
|
})
|
|
70
70
|
expect(config.permission).toBeUndefined()
|
|
71
|
-
|
|
72
|
-
join(root, ".opencode/command/agency.md"),
|
|
73
|
-
).
|
|
74
|
-
expect(command).toContain("Workflow: `$1`")
|
|
75
|
-
expect(command).toContain("Optional target: `$2`")
|
|
71
|
+
expect(
|
|
72
|
+
await Bun.file(join(root, ".opencode/command/agency.md")).exists(),
|
|
73
|
+
).toBe(false)
|
|
76
74
|
const plugin = await Bun.file(
|
|
77
75
|
join(root, ".opencode/plugin/agency-repository-skills.ts"),
|
|
78
76
|
).text()
|
|
@@ -36,11 +36,6 @@ describe("integration command", () => {
|
|
|
36
36
|
diagnostic: expect.stringContaining("cannot load"),
|
|
37
37
|
remediation: expect.stringContaining("integration sync"),
|
|
38
38
|
},
|
|
39
|
-
{
|
|
40
|
-
name: "opencode-command",
|
|
41
|
-
state: "missing",
|
|
42
|
-
remediation: expect.stringContaining("integration sync"),
|
|
43
|
-
},
|
|
44
39
|
{
|
|
45
40
|
name: "opencode-plugin",
|
|
46
41
|
state: "missing",
|
|
@@ -91,11 +86,6 @@ OpenCode config: missing
|
|
|
91
86
|
Agency OpenCode launches cannot load current Agency instructions or whole-workbase access.
|
|
92
87
|
Action: Run 'agency integration sync' to install Agency instructions and whole-workbase OpenCode access.
|
|
93
88
|
|
|
94
|
-
OpenCode /agency command: missing
|
|
95
|
-
Path: .opencode/command/agency.md
|
|
96
|
-
The managed OpenCode /agency command needs synchronization.
|
|
97
|
-
Action: Run 'agency integration sync' to install the managed /agency command.
|
|
98
|
-
|
|
99
89
|
OpenCode workbase plugin: missing
|
|
100
90
|
Path: .opencode/plugin/agency-repository-skills.ts
|
|
101
91
|
The managed OpenCode workbase plugin needs synchronization.
|
|
@@ -120,7 +110,6 @@ OpenCode /agency-debug: missing
|
|
|
120
110
|
expect(JSON.parse(logs[0]!).files).toMatchObject([
|
|
121
111
|
{ name: "agents", state: "managed", changed: true },
|
|
122
112
|
{ name: "opencode", state: "managed", changed: true },
|
|
123
|
-
{ name: "opencode-command", state: "managed", changed: true },
|
|
124
113
|
{ name: "opencode-plugin", state: "managed", changed: true },
|
|
125
114
|
{ name: "opencode-tui", state: "managed", changed: true },
|
|
126
115
|
{ name: "opencode-tui-plugin", state: "managed", changed: true },
|
|
@@ -132,7 +121,7 @@ OpenCode /agency-debug: missing
|
|
|
132
121
|
).toBe(true)
|
|
133
122
|
expect(
|
|
134
123
|
await Bun.file(join(root, ".opencode/command/agency.md")).exists(),
|
|
135
|
-
).toBe(
|
|
124
|
+
).toBe(false)
|
|
136
125
|
expect(
|
|
137
126
|
await Bun.file(
|
|
138
127
|
join(root, ".opencode/plugin/agency-repository-skills.ts"),
|
|
@@ -161,10 +150,6 @@ OpenCode config: synced
|
|
|
161
150
|
Path: .opencode/opencode.jsonc
|
|
162
151
|
Agency's managed OpenCode launch config is ready to load Agency instructions and provide whole-workbase read access.
|
|
163
152
|
|
|
164
|
-
OpenCode /agency command: synced
|
|
165
|
-
Path: .opencode/command/agency.md
|
|
166
|
-
Agency's managed OpenCode /agency command is current.
|
|
167
|
-
|
|
168
153
|
OpenCode workbase plugin: synced
|
|
169
154
|
Path: .opencode/plugin/agency-repository-skills.ts
|
|
170
155
|
Agency's managed OpenCode plugin provides whole-workbase access and exposes writable-checkout skills.
|
|
@@ -15,7 +15,6 @@ interface IntegrationResult {
|
|
|
15
15
|
readonly name:
|
|
16
16
|
| "agents"
|
|
17
17
|
| "opencode"
|
|
18
|
-
| "opencode-command"
|
|
19
18
|
| "opencode-plugin"
|
|
20
19
|
| "opencode-tui"
|
|
21
20
|
| "opencode-tui-plugin"
|
|
@@ -30,7 +29,6 @@ interface IntegrationResult {
|
|
|
30
29
|
const integrationNames = {
|
|
31
30
|
agents: "Agent instructions",
|
|
32
31
|
opencode: "OpenCode config",
|
|
33
|
-
"opencode-command": "OpenCode /agency command",
|
|
34
32
|
"opencode-plugin": "OpenCode workbase plugin",
|
|
35
33
|
"opencode-tui": "OpenCode TUI config",
|
|
36
34
|
"opencode-tui-plugin": "OpenCode /agency-debug",
|
package/src/commands/phase.ts
CHANGED
|
@@ -31,6 +31,9 @@ interface PhaseOptions extends BaseCommandOptions {
|
|
|
31
31
|
readonly pr?: boolean
|
|
32
32
|
readonly work?: boolean
|
|
33
33
|
readonly auto?: boolean
|
|
34
|
+
readonly noPullRequest?: boolean
|
|
35
|
+
readonly summary?: string
|
|
36
|
+
readonly evidenceUrl?: string
|
|
34
37
|
}
|
|
35
38
|
|
|
36
39
|
export const phase = (options: PhaseOptions, work: StartWork = startWork) =>
|
|
@@ -166,7 +169,20 @@ export const phase = (options: PhaseOptions, work: StartWork = startWork) =>
|
|
|
166
169
|
),
|
|
167
170
|
)
|
|
168
171
|
}
|
|
169
|
-
const record = yield* phases.setStatus(
|
|
172
|
+
const record = yield* phases.setStatus(
|
|
173
|
+
taskId,
|
|
174
|
+
phaseId,
|
|
175
|
+
status,
|
|
176
|
+
cwd,
|
|
177
|
+
options.noPullRequest
|
|
178
|
+
? {
|
|
179
|
+
summary: options.summary ?? "",
|
|
180
|
+
...(options.evidenceUrl
|
|
181
|
+
? { evidenceUrl: options.evidenceUrl }
|
|
182
|
+
: {}),
|
|
183
|
+
}
|
|
184
|
+
: undefined,
|
|
185
|
+
)
|
|
170
186
|
const { content: _, ...output } = record
|
|
171
187
|
log(
|
|
172
188
|
options.json
|
|
@@ -275,7 +291,7 @@ Subcommands:
|
|
|
275
291
|
list <task> List task phases
|
|
276
292
|
show <task> <phase> Show a phase
|
|
277
293
|
status <task> <phase> <status>
|
|
278
|
-
Set open, working, or
|
|
294
|
+
Set open, working, dropped, or explicit non-PR done
|
|
279
295
|
update <task> <phase> Update phase metadata
|
|
280
296
|
rename <task> <phase> <new-id>
|
|
281
297
|
Rename a phase and update dependencies
|
|
@@ -285,6 +301,11 @@ Subcommands:
|
|
|
285
301
|
Mutation option:
|
|
286
302
|
--if-revision <hash> Require the target's current revision
|
|
287
303
|
|
|
304
|
+
Non-PR completion options (status done only):
|
|
305
|
+
--no-pull-request Complete without a pull request
|
|
306
|
+
--summary <text> Required durable outcome summary
|
|
307
|
+
--evidence-url <url> Optional supporting record
|
|
308
|
+
|
|
288
309
|
Create options:
|
|
289
310
|
--description <text> Short description of the phase
|
|
290
311
|
--repo <alias> Writable repository
|