@markjaquith/agency 3.1.1 → 3.2.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 +6 -4
- package/package.json +1 -1
- package/src/cli-parser.test.ts +5 -3
- package/src/cli-parser.ts +3 -4
- package/src/cli.test.ts +9 -1
- package/src/commands/work.test.ts +43 -0
- package/src/commands/work.ts +5 -4
package/README.md
CHANGED
|
@@ -1028,7 +1028,7 @@ until restored.
|
|
|
1028
1028
|
|
|
1029
1029
|
```text
|
|
1030
1030
|
agency work [<directory> | --epic <epic-id>] [--agent <name>] [--auto] [--print-command]
|
|
1031
|
-
agency work prepare [target] [--evidence <json-or-path>] [--dry-run] [--json]
|
|
1031
|
+
agency work prepare [target] [--evidence <json-or-path>] [--force] [--dry-run] [--json]
|
|
1032
1032
|
agency worktree <list|inspect|prepare|remove|rebuild|repair>
|
|
1033
1033
|
agency push [--json]
|
|
1034
1034
|
agency pr create <task-id> [phase-id] [--draft] [--title <title>] [--head <branch>] [--base <branch>] [--label <label>] [--force] [--json]
|
|
@@ -1062,9 +1062,11 @@ work and reading context. It does not prescribe how callers present or execute
|
|
|
1062
1062
|
prepared work.
|
|
1063
1063
|
The evidence argument may be an evidence object, task-creation JSON, or a path to
|
|
1064
1064
|
either. Use `--dry-run` to report planned fetch, branch, and worktree changes
|
|
1065
|
-
without applying them.
|
|
1066
|
-
|
|
1067
|
-
|
|
1065
|
+
without applying them. Use `--force` to prepare work blocked by readiness, such
|
|
1066
|
+
as a follow-on phase whose dependency is still active; preparation still does
|
|
1067
|
+
not launch an agent or change lifecycle status. Validation reuse never skips
|
|
1068
|
+
readiness, active-claim, repository, ownership, reference-drift, dirty-workspace,
|
|
1069
|
+
or worktree safety checks.
|
|
1068
1070
|
|
|
1069
1071
|
The authoritative implementation locations for this contract are
|
|
1070
1072
|
`src/commands/task.ts` (creation output),
|
package/package.json
CHANGED
package/src/cli-parser.test.ts
CHANGED
|
@@ -397,9 +397,11 @@ describe("strict CLI parsing", () => {
|
|
|
397
397
|
commandName: "work",
|
|
398
398
|
values: { force: true },
|
|
399
399
|
})
|
|
400
|
-
expect(
|
|
401
|
-
|
|
402
|
-
|
|
400
|
+
expect(parseCli(["work", "prepare", "example", "--force"])).toMatchObject({
|
|
401
|
+
commandName: "work",
|
|
402
|
+
args: ["prepare", "example"],
|
|
403
|
+
values: { force: true },
|
|
404
|
+
})
|
|
403
405
|
})
|
|
404
406
|
|
|
405
407
|
test("preserves every argument after pr without parsing it", () => {
|
package/src/cli-parser.ts
CHANGED
|
@@ -917,7 +917,7 @@ const commands = {
|
|
|
917
917
|
},
|
|
918
918
|
work: {
|
|
919
919
|
usage:
|
|
920
|
-
"agency work [<directory-or-task-id> | --epic <epic-id>] [--agent <name>] [--auto] | agency work prepare [target] [--dry-run] [--json]",
|
|
920
|
+
"agency work [<directory-or-task-id> | --epic <epic-id>] [--agent <name>] [--auto] | agency work prepare [target] [--force] [--dry-run] [--json]",
|
|
921
921
|
options: {
|
|
922
922
|
...commonOptions,
|
|
923
923
|
...entitySelectorOptions,
|
|
@@ -933,7 +933,7 @@ const commands = {
|
|
|
933
933
|
},
|
|
934
934
|
command: {
|
|
935
935
|
usage:
|
|
936
|
-
"agency work [<directory-or-task-id> | --epic <epic-id>] [--agent <name>] [--auto] | agency work prepare [target] [--dry-run] [--json]",
|
|
936
|
+
"agency work [<directory-or-task-id> | --epic <epic-id>] [--agent <name>] [--auto] | agency work prepare [target] [--force] [--dry-run] [--json]",
|
|
937
937
|
minArgs: 0,
|
|
938
938
|
maxArgs: 2,
|
|
939
939
|
options: [
|
|
@@ -1691,8 +1691,7 @@ export function parseCli(args: readonly string[]): ParsedCli {
|
|
|
1691
1691
|
parsed.values.claude ||
|
|
1692
1692
|
parsed.values.agent ||
|
|
1693
1693
|
parsed.values.auto ||
|
|
1694
|
-
parsed.values["print-command"]
|
|
1695
|
-
parsed.values.force))
|
|
1694
|
+
parsed.values["print-command"]))
|
|
1696
1695
|
) {
|
|
1697
1696
|
throw usageError(
|
|
1698
1697
|
preparing
|
package/src/cli.test.ts
CHANGED
|
@@ -1310,7 +1310,12 @@ status: open
|
|
|
1310
1310
|
...process.env,
|
|
1311
1311
|
...contract.environment,
|
|
1312
1312
|
XDG_CONFIG_HOME: isolatedConfigHome,
|
|
1313
|
+
OPENCODE_DISABLE_AUTOUPDATE: "1",
|
|
1313
1314
|
OPENCODE_DISABLE_EXTERNAL_SKILLS: "1",
|
|
1315
|
+
OPENCODE_DISABLE_MODELS_FETCH: "1",
|
|
1316
|
+
OPENCODE_CONFIG_CONTENT: JSON.stringify({
|
|
1317
|
+
model: "opencode/big-pickle",
|
|
1318
|
+
}),
|
|
1314
1319
|
}
|
|
1315
1320
|
const probe = Bun.spawnSync(["opencode", "debug", "agent", "build"], {
|
|
1316
1321
|
cwd: contract.cwd,
|
|
@@ -1409,7 +1414,9 @@ status: open
|
|
|
1409
1414
|
...process.env,
|
|
1410
1415
|
PATH: `${agencyBin}:${process.env.PATH ?? ""}`,
|
|
1411
1416
|
XDG_CONFIG_HOME: isolatedConfigHome,
|
|
1417
|
+
OPENCODE_DISABLE_AUTOUPDATE: "1",
|
|
1412
1418
|
OPENCODE_DISABLE_EXTERNAL_SKILLS: "1",
|
|
1419
|
+
OPENCODE_DISABLE_MODELS_FETCH: "1",
|
|
1413
1420
|
}
|
|
1414
1421
|
delete directEnvironment.OPENCODE_CONFIG
|
|
1415
1422
|
delete directEnvironment.OPENCODE_CONFIG_CONTENT
|
|
@@ -1480,6 +1487,7 @@ status: open
|
|
|
1480
1487
|
env: {
|
|
1481
1488
|
...directEnvironment,
|
|
1482
1489
|
OPENCODE_CONFIG_CONTENT: JSON.stringify({
|
|
1490
|
+
model: "opencode/big-pickle",
|
|
1483
1491
|
permission: { external_directory: { "*": "deny" } },
|
|
1484
1492
|
}),
|
|
1485
1493
|
},
|
|
@@ -1578,7 +1586,7 @@ status: open
|
|
|
1578
1586
|
graph.nodes.find((node: any) => node.id === "task:pipeline").status,
|
|
1579
1587
|
).toBe("working")
|
|
1580
1588
|
},
|
|
1581
|
-
|
|
1589
|
+
360_000,
|
|
1582
1590
|
)
|
|
1583
1591
|
|
|
1584
1592
|
test("envelopes help and version output in machine mode", async () => {
|
|
@@ -569,6 +569,49 @@ describe("work command", () => {
|
|
|
569
569
|
).rejects.toThrow("Recalled repository conflicts")
|
|
570
570
|
})
|
|
571
571
|
|
|
572
|
+
test("force prepares a phase blocked by an active dependency without launching or changing status", async () => {
|
|
573
|
+
const blocked = createHarness({
|
|
574
|
+
workspace: multiPhaseWorkspace,
|
|
575
|
+
multiPhaseTasks: ["example"],
|
|
576
|
+
guardError: new Error("Phase dependency is working"),
|
|
577
|
+
})
|
|
578
|
+
await expect(
|
|
579
|
+
blocked.runPrepare({
|
|
580
|
+
cwd: "/workbase",
|
|
581
|
+
taskId: "example",
|
|
582
|
+
phaseId: "implementation",
|
|
583
|
+
}),
|
|
584
|
+
).rejects.toThrow("Phase dependency is working")
|
|
585
|
+
expect(blocked.events).toEqual(["guard"])
|
|
586
|
+
|
|
587
|
+
const forced = createHarness({
|
|
588
|
+
workspace: multiPhaseWorkspace,
|
|
589
|
+
multiPhaseTasks: ["example"],
|
|
590
|
+
guardError: new Error("Phase dependency is working"),
|
|
591
|
+
})
|
|
592
|
+
await forced.runPrepare({
|
|
593
|
+
cwd: "/workbase",
|
|
594
|
+
taskId: "example",
|
|
595
|
+
phaseId: "implementation",
|
|
596
|
+
force: true,
|
|
597
|
+
silent: true,
|
|
598
|
+
})
|
|
599
|
+
|
|
600
|
+
expect(forced.guards).toEqual([
|
|
601
|
+
{
|
|
602
|
+
target: "execution-unit:phase/example/implementation",
|
|
603
|
+
override: true,
|
|
604
|
+
},
|
|
605
|
+
])
|
|
606
|
+
expect(forced.events).toEqual(["guard", "materialize"])
|
|
607
|
+
expect(forced.materializeOptions[0]).toMatchObject({
|
|
608
|
+
force: true,
|
|
609
|
+
validationAlreadyPerformed: true,
|
|
610
|
+
})
|
|
611
|
+
expect(forced.launches).toEqual([])
|
|
612
|
+
expect(forced.statusUpdates).toEqual([])
|
|
613
|
+
})
|
|
614
|
+
|
|
572
615
|
test("launches an epic agent from an epic directory", async () => {
|
|
573
616
|
const harness = createHarness()
|
|
574
617
|
|
package/src/commands/work.ts
CHANGED
|
@@ -577,7 +577,7 @@ export const workPrepare = (options: WorkOptions = {}) =>
|
|
|
577
577
|
|
|
578
578
|
export const help = `
|
|
579
579
|
Usage: agency work [<directory-or-task-id> | --epic <epic-id>] [--agent <name>] [--auto]
|
|
580
|
-
agency work prepare [target] [--evidence <json-or-path>] [--dry-run] [--json]
|
|
580
|
+
agency work prepare [target] [--evidence <json-or-path>] [--force] [--dry-run] [--json]
|
|
581
581
|
|
|
582
582
|
Launch an agent for an epic, task, or phase. With no directory, select one
|
|
583
583
|
interactively. A positional argument resolves as a directory first, then as a task
|
|
@@ -592,7 +592,8 @@ changes without fetching, creating branches, or creating worktrees.
|
|
|
592
592
|
It emits revision-bound validation evidence and an idempotent external-orchestrator
|
|
593
593
|
contract. Evidence is reused only while the target, workbase, configuration, and
|
|
594
594
|
repository mapping remain unchanged. Dynamic readiness and workspace safety checks
|
|
595
|
-
always run.
|
|
595
|
+
always run. With prepare, --force overrides readiness without launching or changing
|
|
596
|
+
lifecycle status.
|
|
596
597
|
|
|
597
598
|
Options:
|
|
598
599
|
--epic <id> Work on an epic
|
|
@@ -605,8 +606,8 @@ Options:
|
|
|
605
606
|
--print-command Print cwd, argv, and non-secret environment without launch
|
|
606
607
|
--opencode Require the OpenCode preset
|
|
607
608
|
--claude Require the Claude Code preset
|
|
608
|
-
--force Override readiness;
|
|
609
|
-
|
|
609
|
+
--force Override readiness; launched terminal work is reopened
|
|
610
|
+
--evidence <value> Validation evidence JSON or a path to JSON (prepare only)
|
|
610
611
|
--no-input Never open an interactive selector
|
|
611
612
|
|
|
612
613
|
Without interactive input, provide an explicit workbase or cwd and an entity
|