@markjaquith/agency 2.74.0 → 3.0.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 +23 -121
- package/cli-main.ts +0 -26
- package/cli.ts +1 -17
- package/package.json +1 -2
- package/schemas/agency-graph-v1.schema.json +1 -1
- package/src/cli-parser.test.ts +0 -19
- package/src/cli-parser.ts +0 -23
- package/src/cli.test.ts +3 -3
- package/src/commands/context.test.ts +0 -67
- package/src/commands/init.test.ts +1 -2
- package/src/commands/pr.test.ts +2 -87
- package/src/commands/pr.ts +2 -79
- package/src/commands/push.test.ts +1 -2
- package/src/graph-schema.ts +1 -1
- package/src/services/ArchiveBulkService.test.ts +1 -142
- package/src/services/ArchiveService.test.ts +1 -172
- package/src/services/ArchiveService.ts +0 -26
- package/src/services/ContextService.ts +3 -47
- package/src/services/DoctorService.ts +8 -24
- package/src/services/GraphService.test.ts +1 -0
- package/src/services/GraphService.ts +2 -5
- package/src/services/PhaseService.ts +70 -191
- package/src/services/PullRequestService.test.ts +1 -45
- package/src/services/PullRequestService.ts +1 -22
- package/src/services/PushService.test.ts +29 -295
- package/src/services/PushService.ts +10 -239
- package/src/services/RepositoryService.test.ts +1 -61
- package/src/services/RepositoryService.ts +2 -13
- package/src/services/ReviewService.test.ts +1 -84
- package/src/services/ReviewService.ts +9 -48
- package/src/services/SyncService.test.ts +0 -81
- package/src/services/SyncService.ts +12 -39
- package/src/services/TaskPhaseService.test.ts +0 -80
- package/src/services/TaskService.ts +1 -9
- package/src/services/VersionControlService.test.ts +4 -117
- package/src/services/VersionControlService.ts +3 -426
- package/src/services/WorkbaseService.test.ts +0 -20
- package/src/services/WorkbaseService.ts +1 -18
- package/src/services/WorktreeService.test.ts +1 -705
- package/src/services/WorktreeService.ts +395 -1604
- package/src/services/push-validation.ts +0 -7
- package/src/test-utils.ts +0 -4
- package/src/workbase/AGENTS.md +4 -5
- package/src/workbase/checkout-command.test.ts +1 -1
- package/src/workbase/checkout-command.ts +1 -1
- package/src/workbase/delivery-command.test.ts +4 -35
- package/src/workbase/delivery-command.ts +2 -15
- package/src/workbase/schemas.test.ts +0 -19
- package/src/workbase/schemas.ts +1 -2
- package/src/commands/vcs.test.ts +0 -75
- package/src/commands/vcs.ts +0 -72
- package/src/services/VcsMigrationService.test.ts +0 -348
- package/src/services/VcsMigrationService.ts +0 -857
- package/src/vcs-status-fast.ts +0 -310
- package/src/workbase/version-control.ts +0 -5
- package/src/workbase/workspace-command.test.ts +0 -70
- package/src/workbase/workspace-command.ts +0 -63
package/README.md
CHANGED
|
@@ -9,7 +9,6 @@ read or write.
|
|
|
9
9
|
|
|
10
10
|
- [Bun](https://bun.sh) 1.0 or newer
|
|
11
11
|
- Git
|
|
12
|
-
- [Jujutsu](https://jj-vcs.github.io/jj/) is preferred when available
|
|
13
12
|
- [GitHub CLI](https://cli.github.com/) for `agency pr`
|
|
14
13
|
- OpenCode, Claude Code, or a configured agent for `agency work`
|
|
15
14
|
|
|
@@ -151,15 +150,16 @@ the writable checkout's `.claude/skills`, `.agents/skills`,
|
|
|
151
150
|
`.opencode/{skill,skills}`, and `.pi/skills` directories. `agency context`
|
|
152
151
|
remains the authority for writes; reference checkouts remain read-only.
|
|
153
152
|
|
|
154
|
-
Repository aliases
|
|
155
|
-
|
|
156
|
-
`repos/{alias}`. A declaration contains no local path, symlink target,
|
|
157
|
-
or credential
|
|
153
|
+
Repository aliases and canonical fetch remotes are declared in tracked
|
|
154
|
+
`agency.json`; local Git clones and symlinks remain ignored under
|
|
155
|
+
`repos/{alias}`. A declaration contains no local path, symlink target, worktree,
|
|
156
|
+
or credential. The optional `vcs` field accepts only `"git"`; omitting it also
|
|
157
|
+
selects Git:
|
|
158
158
|
|
|
159
159
|
```json
|
|
160
160
|
{
|
|
161
161
|
"version": 2,
|
|
162
|
-
"vcs": "
|
|
162
|
+
"vcs": "git",
|
|
163
163
|
"repositories": {
|
|
164
164
|
"frontend": {
|
|
165
165
|
"remote": "git@example.com:team/frontend.git"
|
|
@@ -168,39 +168,9 @@ or credential:
|
|
|
168
168
|
}
|
|
169
169
|
```
|
|
170
170
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
non-colocated managed clones and jj workspaces, while Git workbases continue to
|
|
175
|
-
use bare repositories and Git worktrees. Existing colocated jj repositories are
|
|
176
|
-
also supported.
|
|
177
|
-
|
|
178
|
-
Agency uses jj-native commands for repository validity, workspace registration,
|
|
179
|
-
working-copy state, revisions, bookmarks, ancestry, fetch, and push. Raw Git is
|
|
180
|
-
limited to backing-store plumbing such as durable review refs and integrations
|
|
181
|
-
that require Git, including GitHub CLI commit discovery. For those operations,
|
|
182
|
-
Agency obtains the backing repository with `jj git root` and supplies it as
|
|
183
|
-
`GIT_DIR`; it does not use raw Git to infer jj workspace state.
|
|
184
|
-
|
|
185
|
-
Inspect the current backend and migration readiness with:
|
|
186
|
-
|
|
187
|
-
```bash
|
|
188
|
-
agency vcs status
|
|
189
|
-
agency vcs migrate jj # dry-run
|
|
190
|
-
agency vcs migrate jj --apply
|
|
191
|
-
agency vcs migrate git --apply
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
Migration is workbase-wide and transactional. Agency locks every execution
|
|
195
|
-
unit, requires clean registered workspaces, blocks active claims and working or
|
|
196
|
-
delegated units, converts repository metadata, recreates checkout paths with the
|
|
197
|
-
target backend, and updates `agency.json` last. Migration from jj to Git also
|
|
198
|
-
blocks jj-only heads that are not preserved by a bookmark or workspace. Failed
|
|
199
|
-
migrations restore the source repositories and workspaces when rollback is
|
|
200
|
-
possible and report explicit manual recovery paths otherwise.
|
|
201
|
-
Converting a non-colocated jj workbase to Git is currently blocked before any
|
|
202
|
-
mutation because its backing Git object store is inside `.jj`; first convert the
|
|
203
|
-
repositories to colocated jj so the Git store survives metadata removal.
|
|
171
|
+
Agency materializes declared remotes as bare Git repositories and creates
|
|
172
|
+
managed Git worktrees for execution units. Linked aliases remain symlinks to
|
|
173
|
+
existing Git repositories.
|
|
204
174
|
|
|
205
175
|
Existing version 2 workbases without `repositories` remain valid. Run
|
|
206
176
|
`agency repo setup` to preview deterministic adoption of legacy local aliases;
|
|
@@ -274,63 +244,13 @@ Agency also reconciles known tool-owned artifacts such as Worktrunk's
|
|
|
274
244
|
new and existing managed worktrees clean without changing the repository's
|
|
275
245
|
tracked ignore configuration or overwriting user-maintained local excludes.
|
|
276
246
|
|
|
277
|
-
The configured command applies only to the writable checkout
|
|
247
|
+
The configured command applies only to the writable checkout.
|
|
278
248
|
Supplemental read-only repositories remain detached Git worktrees at their
|
|
279
|
-
declared refs so they do not acquire writable branches.
|
|
280
|
-
jj workspaces and ignore this Git-specific customization.
|
|
281
|
-
|
|
282
|
-
### Custom Jj Workspace Command
|
|
283
|
-
|
|
284
|
-
Jj workbases normally create managed workspaces with `jj workspace add`. Set
|
|
285
|
-
`workspaceCreateCommand` to an argv template when another tool should create or
|
|
286
|
-
adopt a prepared workspace directly at Agency's destination:
|
|
287
|
-
|
|
288
|
-
```json
|
|
289
|
-
{
|
|
290
|
-
"version": 2,
|
|
291
|
-
"vcs": "jj",
|
|
292
|
-
"workspaceCreateCommand": [
|
|
293
|
-
"my-prewarm-tool",
|
|
294
|
-
"adopt",
|
|
295
|
-
"--repo",
|
|
296
|
-
"{repo}",
|
|
297
|
-
"--destination",
|
|
298
|
-
"{workspace}",
|
|
299
|
-
"--name",
|
|
300
|
-
"{name}",
|
|
301
|
-
"--revision",
|
|
302
|
-
"{revision}"
|
|
303
|
-
]
|
|
304
|
-
}
|
|
305
|
-
```
|
|
306
|
-
|
|
307
|
-
Available placeholders are:
|
|
308
|
-
|
|
309
|
-
- `{repo}`: absolute repository alias path under `repos/`
|
|
310
|
-
- `{workspace}`: absolute managed workspace path Agency requires
|
|
311
|
-
- `{name}`: unique jj workspace name Agency requires
|
|
312
|
-
- `{revision}`: exact commit the new working copy must be based on
|
|
313
|
-
- `{kind}`: `writable` or `reference`
|
|
314
|
-
- `{requestedRef}`: configured branch, reference, or review commit
|
|
315
|
-
|
|
316
|
-
`{repo}`, `{workspace}`, `{name}`, and `{revision}` are required. Agency invokes
|
|
317
|
-
the command directly without a shell and sets matching `AGENCY_REPO`,
|
|
318
|
-
`AGENCY_WORKSPACE`, `AGENCY_WORKSPACE_NAME`, `AGENCY_REVISION`,
|
|
319
|
-
`AGENCY_CHECKOUT_KIND`, and `AGENCY_REQUESTED_REF` environment variables. The
|
|
320
|
-
command applies to each new jj checkout and must leave `{workspace}` registered
|
|
321
|
-
under `{name}` with its working-copy parent at `{revision}`. This lets a prewarm
|
|
322
|
-
tool move or adopt a prepared workspace without first paying for Agency's normal
|
|
323
|
-
full checkout.
|
|
324
|
-
|
|
325
|
-
Agency validates the registration, name, path, and revision before running any
|
|
326
|
-
`postCheckoutCommand`. A failed command or validation removes a partially
|
|
327
|
-
created workspace when possible and otherwise reports manual recovery. Resume
|
|
328
|
-
restoration continues to use Agency's built-in exact-target recovery path.
|
|
329
|
-
Git workbases ignore this jj-specific customization.
|
|
249
|
+
declared refs so they do not acquire writable branches.
|
|
330
250
|
|
|
331
251
|
### Post-checkout Commands
|
|
332
252
|
|
|
333
|
-
Each repository declaration may provide a
|
|
253
|
+
Each repository declaration may provide a `postCheckoutCommand` argv
|
|
334
254
|
template for repository-specific setup. Agency invokes it directly, without a
|
|
335
255
|
shell, with the new checkout as its working directory:
|
|
336
256
|
|
|
@@ -346,11 +266,10 @@ shell, with the new checkout as its working directory:
|
|
|
346
266
|
}
|
|
347
267
|
```
|
|
348
268
|
|
|
349
|
-
The hook runs for each newly created managed
|
|
350
|
-
reference
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
`workspaceCreateCommand` completes and is validated before this hook runs.
|
|
269
|
+
The hook runs for each newly created managed Git worktree, including writable
|
|
270
|
+
and reference worktrees, after Agency has validated it. It does not run for a
|
|
271
|
+
reused worktree or for inspection-only commands. A custom
|
|
272
|
+
`worktreeCreateCommand` completes and is validated before this hook runs.
|
|
354
273
|
|
|
355
274
|
Available placeholders and matching environment variables are:
|
|
356
275
|
|
|
@@ -362,7 +281,7 @@ Available placeholders and matching environment variables are:
|
|
|
362
281
|
| `{checkoutKind}` | `AGENCY_CHECKOUT_KIND` | `writable` or `reference` |
|
|
363
282
|
| `{requestedRef}` | `AGENCY_REQUESTED_REF` | Requested branch, reference, or review commit |
|
|
364
283
|
| `{base}` | `AGENCY_BASE` | Configured execution base |
|
|
365
|
-
| `{vcs}` | `AGENCY_VCS` | `git`
|
|
284
|
+
| `{vcs}` | `AGENCY_VCS` | `git` |
|
|
366
285
|
| `{workbaseRoot}` | `AGENCY_WORKBASE_ROOT` | Absolute workbase root |
|
|
367
286
|
| `{taskId}` | `AGENCY_TASK_ID` | Task ID |
|
|
368
287
|
| `{phaseId}` | `AGENCY_PHASE_ID` | Phase ID |
|
|
@@ -1162,15 +1081,6 @@ conflicting worktrees. Repair is deliberately conservative: it repairs safe Git
|
|
|
1162
1081
|
registration issues and materializes missing checkouts, but never switches a
|
|
1163
1082
|
branch, resets a commit, or discards uncommitted work.
|
|
1164
1083
|
|
|
1165
|
-
For jj, explicit removal is a suspend operation. Agency records each workspace's
|
|
1166
|
-
exact `@` commit and stable change ID in `.agency-jj-resume.json`, roots that
|
|
1167
|
-
commit with an internal local bookmark, and only then forgets the workspace.
|
|
1168
|
-
The next `work prepare` validates all three identities, restores the workspace by
|
|
1169
|
-
editing the recorded commit, and consumes the resume metadata and bookmarks.
|
|
1170
|
-
Missing, ambiguous, or conflicting resume state stops instead of falling back to
|
|
1171
|
-
the declared delivery bookmark, `@-`, or the base. Unknown checkout cleanliness
|
|
1172
|
-
also stops removal. Git worktree removal and preparation are unchanged.
|
|
1173
|
-
|
|
1174
1084
|
Agency launches every agent beside its epic or task document. Single-phase tasks
|
|
1175
1085
|
and phases first fetch repositories and create or reuse worktrees under `code/`,
|
|
1176
1086
|
then launch the execution agent from the task directory with absolute context
|
|
@@ -1195,18 +1105,11 @@ that the declared base is in the publication history, validates every outgoing
|
|
|
1195
1105
|
commit's description, author, and conflict state, and refuses non-fast-forward
|
|
1196
1106
|
updates.
|
|
1197
1107
|
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
changes remain intentional publication tips. Missing descriptions or authors
|
|
1204
|
-
stop with exact change IDs and remediation commands. Agency creates or safely
|
|
1205
|
-
advances only the declared bookmark and never invents a `push-*` bookmark.
|
|
1206
|
-
If the fetched remote base advanced outside the local stack, Agency prints the
|
|
1207
|
-
exact `jj rebase` command needed to move the stack onto `<base>@<remote>`. Push
|
|
1208
|
-
reports deterministic fetch, inspection, validation, and publication progress
|
|
1209
|
-
on stderr, including while `--json` reserves stdout for one machine result.
|
|
1108
|
+
YAML `branch` must exactly match the checked-out local branch, the worktree must
|
|
1109
|
+
be clean, and `HEAD` is pushed with upstream tracking. Missing commit descriptions
|
|
1110
|
+
or authors stop publication with exact commits and remediation commands. Push
|
|
1111
|
+
reports deterministic fetch, inspection, validation, and publication progress on
|
|
1112
|
+
stderr, including while `--json` reserves stdout for one machine result.
|
|
1210
1113
|
|
|
1211
1114
|
Task-aware `agency pr create <task-id> [phase-id]` uses Agency's delivery flow,
|
|
1212
1115
|
including readiness checks and durable PR recording. It accepts draft, title,
|
|
@@ -1216,8 +1119,7 @@ Other `agency pr`
|
|
|
1216
1119
|
invocations forward every argument to `gh pr`. From an execution task or phase
|
|
1217
1120
|
directory, including descendants, passthrough runs in that execution unit's
|
|
1218
1121
|
authoritative writable checkout. Otherwise it runs in the caller's current
|
|
1219
|
-
directory.
|
|
1220
|
-
item's declared branch to subcommands that would otherwise infer Git context.
|
|
1122
|
+
directory.
|
|
1221
1123
|
|
|
1222
1124
|
### Status and Validation
|
|
1223
1125
|
|
package/cli-main.ts
CHANGED
|
@@ -48,12 +48,9 @@ import { DoctorService } from "./src/services/DoctorService"
|
|
|
48
48
|
import { ReviewService } from "./src/services/ReviewService"
|
|
49
49
|
import {
|
|
50
50
|
GitVersionControlService,
|
|
51
|
-
JjVersionControlService,
|
|
52
51
|
VersionControlService,
|
|
53
52
|
} from "./src/services/VersionControlService"
|
|
54
53
|
import { review, help as reviewHelp } from "./src/commands/review"
|
|
55
|
-
import { vcs, help as vcsHelp } from "./src/commands/vcs"
|
|
56
|
-
import { VcsMigrationService } from "./src/services/VcsMigrationService"
|
|
57
54
|
import { act, help as actHelp } from "./src/commands/act"
|
|
58
55
|
import {
|
|
59
56
|
claimCommand,
|
|
@@ -74,9 +71,7 @@ const CliLayer = Layer.mergeAll(
|
|
|
74
71
|
FileSystemService.Default,
|
|
75
72
|
WorkbaseService.Default,
|
|
76
73
|
GitVersionControlService.Default,
|
|
77
|
-
JjVersionControlService.Default,
|
|
78
74
|
VersionControlService.Default,
|
|
79
|
-
VcsMigrationService.Default,
|
|
80
75
|
RepositoryService.Default,
|
|
81
76
|
EpicService.Default,
|
|
82
77
|
TaskService.Default,
|
|
@@ -623,26 +618,6 @@ const commands: Record<string, Command> = {
|
|
|
623
618
|
)
|
|
624
619
|
},
|
|
625
620
|
},
|
|
626
|
-
vcs: {
|
|
627
|
-
run: async (args: string[], options: Record<string, any>) => {
|
|
628
|
-
if (options.help) {
|
|
629
|
-
console.log(vcsHelp)
|
|
630
|
-
return
|
|
631
|
-
}
|
|
632
|
-
await runCommand(
|
|
633
|
-
vcs({
|
|
634
|
-
subcommand: args[0],
|
|
635
|
-
target: args[1],
|
|
636
|
-
apply: options.apply,
|
|
637
|
-
dryRun: options["dry-run"],
|
|
638
|
-
json: options.json,
|
|
639
|
-
silent: options.silent,
|
|
640
|
-
verbose: options.verbose,
|
|
641
|
-
cwd: options.cwd,
|
|
642
|
-
}),
|
|
643
|
-
)
|
|
644
|
-
},
|
|
645
|
-
},
|
|
646
621
|
next: {
|
|
647
622
|
run: async (_args: string[], options: Record<string, any>) => {
|
|
648
623
|
if (options.help) return console.log(nextHelp)
|
|
@@ -802,7 +777,6 @@ Commands:
|
|
|
802
777
|
task <subcommand> Manage tasks
|
|
803
778
|
work [directory|task] Work on an epic, task, or phase
|
|
804
779
|
worktree <subcommand> Inspect and maintain managed workspaces
|
|
805
|
-
vcs <subcommand> Inspect or migrate the version-control backend
|
|
806
780
|
next List or select ready execution units
|
|
807
781
|
pr create / pr [...] Create an Agency PR or run gh pr with repository focus
|
|
808
782
|
push Validate and publish the current execution unit
|
package/cli.ts
CHANGED
|
@@ -1,19 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
const fastVcsStatus =
|
|
5
|
-
args[0] === "vcs" &&
|
|
6
|
-
args[1] === "status" &&
|
|
7
|
-
(args.length === 2 || (args.length === 3 && args[2] === "--json"))
|
|
8
|
-
|
|
9
|
-
if (fastVcsStatus) {
|
|
10
|
-
try {
|
|
11
|
-
const { runVcsStatusFast } = await import("./src/vcs-status-fast")
|
|
12
|
-
if (!(await runVcsStatusFast(args[2] === "--json")))
|
|
13
|
-
await import("./cli-main")
|
|
14
|
-
} catch {
|
|
15
|
-
await import("./cli-main")
|
|
16
|
-
}
|
|
17
|
-
} else {
|
|
18
|
-
await import("./cli-main")
|
|
19
|
-
}
|
|
3
|
+
await import("./cli-main")
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markjaquith/agency",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Manage agentic work across repositories with durable workbases",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agents",
|
|
@@ -83,7 +83,6 @@
|
|
|
83
83
|
"benchmark:graph": "bun scripts/benchmark-graph.ts",
|
|
84
84
|
"benchmark:push": "bun scripts/benchmark-push.ts",
|
|
85
85
|
"benchmark:archive": "bun scripts/benchmark-archive.ts",
|
|
86
|
-
"benchmark:vcs": "bun scripts/benchmark-vcs.ts",
|
|
87
86
|
"benchmark:sync": "bun scripts/benchmark-sync.ts",
|
|
88
87
|
"benchmark:task": "bun scripts/benchmark-task.ts",
|
|
89
88
|
"benchmark:validate": "bun scripts/benchmark-validate.ts",
|
package/src/cli-parser.test.ts
CHANGED
|
@@ -674,25 +674,6 @@ describe("strict CLI parsing", () => {
|
|
|
674
674
|
)
|
|
675
675
|
})
|
|
676
676
|
|
|
677
|
-
test("parses VCS status and migration commands", () => {
|
|
678
|
-
expect(parseCli(["vcs", "status", "--json"])).toMatchObject({
|
|
679
|
-
commandName: "vcs",
|
|
680
|
-
args: ["status"],
|
|
681
|
-
values: { json: true },
|
|
682
|
-
})
|
|
683
|
-
expect(
|
|
684
|
-
parseCli(["vcs", "migrate", "jj", "--apply", "--json"]),
|
|
685
|
-
).toMatchObject({
|
|
686
|
-
commandName: "vcs",
|
|
687
|
-
args: ["migrate", "jj"],
|
|
688
|
-
values: { apply: true, json: true },
|
|
689
|
-
})
|
|
690
|
-
expectUsageError(["vcs", "migrate"], "agency vcs migrate")
|
|
691
|
-
expect(() =>
|
|
692
|
-
parseCli(["vcs", "migrate", "jj", "--dry-run", "--apply"]),
|
|
693
|
-
).toThrow("cannot be combined")
|
|
694
|
-
})
|
|
695
|
-
|
|
696
677
|
test("parses push without accepting an alternate target", () => {
|
|
697
678
|
expect(parseCli(["push", "--json"])).toMatchObject({
|
|
698
679
|
commandName: "push",
|
package/src/cli-parser.ts
CHANGED
|
@@ -908,29 +908,6 @@ const commands = {
|
|
|
908
908
|
},
|
|
909
909
|
},
|
|
910
910
|
},
|
|
911
|
-
vcs: {
|
|
912
|
-
usage: "agency vcs <status|migrate>",
|
|
913
|
-
options: {
|
|
914
|
-
...outputOptions,
|
|
915
|
-
apply: { type: "boolean" },
|
|
916
|
-
"dry-run": { type: "boolean" },
|
|
917
|
-
},
|
|
918
|
-
subcommands: {
|
|
919
|
-
status: {
|
|
920
|
-
usage: "agency vcs status [--json]",
|
|
921
|
-
minArgs: 0,
|
|
922
|
-
maxArgs: 0,
|
|
923
|
-
options: ["json"],
|
|
924
|
-
},
|
|
925
|
-
migrate: {
|
|
926
|
-
usage: "agency vcs migrate <git|jj> [--dry-run | --apply] [--json]",
|
|
927
|
-
minArgs: 1,
|
|
928
|
-
maxArgs: 1,
|
|
929
|
-
options: ["apply", "dry-run", "json"],
|
|
930
|
-
conflicts: [["apply", "dry-run"]],
|
|
931
|
-
},
|
|
932
|
-
},
|
|
933
|
-
},
|
|
934
911
|
work: {
|
|
935
912
|
usage:
|
|
936
913
|
"agency work [<directory-or-task-id> | --epic <epic-id>] [--agent <name>] [--auto] | agency work prepare [target] [--dry-run] [--json]",
|
package/src/cli.test.ts
CHANGED
|
@@ -1929,9 +1929,9 @@ status: open
|
|
|
1929
1929
|
alias: "agency",
|
|
1930
1930
|
status: "applied",
|
|
1931
1931
|
})
|
|
1932
|
-
expect(
|
|
1933
|
-
|
|
1934
|
-
)
|
|
1932
|
+
expect((await stat(join(restored, "repos/agency/HEAD"))).isFile()).toBe(
|
|
1933
|
+
true,
|
|
1934
|
+
)
|
|
1935
1935
|
|
|
1936
1936
|
const prepared = parseJson(
|
|
1937
1937
|
await runCli(["work", "prepare", "portable", "--json"], restored),
|
|
@@ -219,73 +219,6 @@ Phase prose.
|
|
|
219
219
|
)
|
|
220
220
|
})
|
|
221
221
|
|
|
222
|
-
test("reports the current jj change without inventing a missing bookmark", async () => {
|
|
223
|
-
if (!Bun.which("jj")) return
|
|
224
|
-
await cleanupTempDir(root)
|
|
225
|
-
root = await createTempDir()
|
|
226
|
-
const remote = join(root, "remote.git")
|
|
227
|
-
const seed = join(root, "seed")
|
|
228
|
-
const repository = join(root, "repos/agency")
|
|
229
|
-
const checkout = join(root, "tasks/example/code/agency")
|
|
230
|
-
await mkdir(join(root, "repos"), { recursive: true })
|
|
231
|
-
await write(root, "agency.json", '{"version":2,"vcs":"jj"}\n')
|
|
232
|
-
await run(root, ["git", "init", "--bare", "--initial-branch=main", remote])
|
|
233
|
-
await run(root, ["git", "init", "--initial-branch=main", seed])
|
|
234
|
-
await run(seed, ["git", "config", "user.email", "test@example.com"])
|
|
235
|
-
await run(seed, ["git", "config", "user.name", "Test"])
|
|
236
|
-
await Bun.write(join(seed, "README.md"), "example\n")
|
|
237
|
-
await run(seed, ["git", "add", "README.md"])
|
|
238
|
-
await run(seed, ["git", "commit", "-m", "initial"])
|
|
239
|
-
await run(seed, ["git", "remote", "add", "origin", remote])
|
|
240
|
-
await run(seed, ["git", "push", "origin", "main"])
|
|
241
|
-
await run(root, ["jj", "git", "clone", "--no-colocate", remote, repository])
|
|
242
|
-
await write(
|
|
243
|
-
root,
|
|
244
|
-
"tasks/example/TASK.md",
|
|
245
|
-
`---
|
|
246
|
-
ticketUrl: null
|
|
247
|
-
repo: agency
|
|
248
|
-
branch: task/example
|
|
249
|
-
base: main
|
|
250
|
-
pr: null
|
|
251
|
-
status: working
|
|
252
|
-
---
|
|
253
|
-
|
|
254
|
-
# Example
|
|
255
|
-
`,
|
|
256
|
-
)
|
|
257
|
-
await mkdir(dirname(checkout), { recursive: true })
|
|
258
|
-
await run(repository, [
|
|
259
|
-
"jj",
|
|
260
|
-
"workspace",
|
|
261
|
-
"add",
|
|
262
|
-
"--name",
|
|
263
|
-
"task-example",
|
|
264
|
-
"-r",
|
|
265
|
-
"main",
|
|
266
|
-
checkout,
|
|
267
|
-
])
|
|
268
|
-
await Bun.write(join(checkout, "feature.txt"), "current change\n")
|
|
269
|
-
const current = Bun.spawn(
|
|
270
|
-
["jj", "log", "--no-graph", "-r", "@", "-T", "commit_id"],
|
|
271
|
-
{ cwd: checkout, stdout: "pipe", stderr: "pipe" },
|
|
272
|
-
)
|
|
273
|
-
const currentCommit = (await new Response(current.stdout).text()).trim()
|
|
274
|
-
expect(await current.exited).toBe(0)
|
|
275
|
-
|
|
276
|
-
const result = await readContext(root, "tasks/example", false, true)
|
|
277
|
-
expect(result.workspace.writable).toMatchObject({
|
|
278
|
-
branchCommit: null,
|
|
279
|
-
checkoutCommit: currentCommit,
|
|
280
|
-
checkoutBranch: null,
|
|
281
|
-
detached: true,
|
|
282
|
-
dirty: false,
|
|
283
|
-
})
|
|
284
|
-
expect(result.workspace.warnings).toContain(
|
|
285
|
-
`Unable to resolve branch 'task/example' in ${repository}`,
|
|
286
|
-
)
|
|
287
|
-
})
|
|
288
|
-
|
|
289
222
|
test("defaults to compact while preserving explicit compact compatibility", async () => {
|
|
290
223
|
const result = await readContext(
|
|
291
224
|
root,
|
|
@@ -8,7 +8,6 @@ import {
|
|
|
8
8
|
runTestEffect,
|
|
9
9
|
} from "../test-utils"
|
|
10
10
|
import { init } from "./init"
|
|
11
|
-
import { preferredVersionControl } from "../workbase/version-control"
|
|
12
11
|
|
|
13
12
|
describe("init command", () => {
|
|
14
13
|
let parent: string
|
|
@@ -27,7 +26,7 @@ describe("init command", () => {
|
|
|
27
26
|
|
|
28
27
|
expect(await Bun.file(join(root, "agency.json")).json()).toEqual({
|
|
29
28
|
version: 2,
|
|
30
|
-
vcs:
|
|
29
|
+
vcs: "git",
|
|
31
30
|
})
|
|
32
31
|
for (const directory of ["repos", "epics", "tasks"]) {
|
|
33
32
|
expect((await stat(join(root, directory))).isDirectory()).toBe(true)
|
package/src/commands/pr.test.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { afterEach, beforeEach, describe, expect, test } from "bun:test"
|
|
2
2
|
import { Effect } from "effect"
|
|
3
|
-
import { chmod, mkdir, realpath
|
|
3
|
+
import { chmod, mkdir, realpath } from "node:fs/promises"
|
|
4
4
|
import { dirname, join } from "node:path"
|
|
5
5
|
import { PullRequestService } from "../services/PullRequestService"
|
|
6
6
|
import {
|
|
@@ -31,7 +31,6 @@ describe("pr command", () => {
|
|
|
31
31
|
join(bin, "gh"),
|
|
32
32
|
`#!/bin/sh
|
|
33
33
|
printf '%s\n' "$PWD" "$@" > "$GH_CAPTURE"
|
|
34
|
-
if [ -n "$GIT_DIR" ]; then printf 'GIT_DIR=%s\n' "$GIT_DIR" >> "$GH_CAPTURE"; fi
|
|
35
34
|
exit "\${GH_EXIT:-0}"
|
|
36
35
|
`,
|
|
37
36
|
)
|
|
@@ -51,14 +50,13 @@ exit "\${GH_EXIT:-0}"
|
|
|
51
50
|
const captured = async () =>
|
|
52
51
|
(await Bun.file(capturePath).text()).trim().split("\n")
|
|
53
52
|
|
|
54
|
-
const createExecutionWorkbase = async (
|
|
53
|
+
const createExecutionWorkbase = async () => {
|
|
55
54
|
const root = join(tempRoot, "workbase")
|
|
56
55
|
await write(
|
|
57
56
|
root,
|
|
58
57
|
"agency.json",
|
|
59
58
|
`${JSON.stringify({
|
|
60
59
|
version: 2,
|
|
61
|
-
vcs,
|
|
62
60
|
repositories: {
|
|
63
61
|
agency: { remote: "https://github.com/example/agency.git" },
|
|
64
62
|
},
|
|
@@ -110,41 +108,6 @@ status: open
|
|
|
110
108
|
# Build
|
|
111
109
|
`,
|
|
112
110
|
)
|
|
113
|
-
if (vcs === "jj") {
|
|
114
|
-
const repository = join(root, "repos/agency")
|
|
115
|
-
await rm(join(root, "tasks/single/code/agency"), { recursive: true })
|
|
116
|
-
await rm(join(root, "tasks/multi/phases/build/code/agency"), {
|
|
117
|
-
recursive: true,
|
|
118
|
-
})
|
|
119
|
-
const initialized = Bun.spawn(
|
|
120
|
-
["jj", "git", "init", "--no-colocate", repository],
|
|
121
|
-
{ stdout: "pipe", stderr: "pipe" },
|
|
122
|
-
)
|
|
123
|
-
if ((await initialized.exited) !== 0)
|
|
124
|
-
throw new Error(await new Response(initialized.stderr).text())
|
|
125
|
-
for (const [name, path] of [
|
|
126
|
-
["single", join(root, "tasks/single/code/agency")],
|
|
127
|
-
["build", join(root, "tasks/multi/phases/build/code/agency")],
|
|
128
|
-
] as const) {
|
|
129
|
-
const workspace = Bun.spawn(
|
|
130
|
-
[
|
|
131
|
-
"jj",
|
|
132
|
-
"-R",
|
|
133
|
-
repository,
|
|
134
|
-
"workspace",
|
|
135
|
-
"add",
|
|
136
|
-
"--name",
|
|
137
|
-
name,
|
|
138
|
-
"-r",
|
|
139
|
-
"root()",
|
|
140
|
-
path,
|
|
141
|
-
],
|
|
142
|
-
{ stdout: "pipe", stderr: "pipe" },
|
|
143
|
-
)
|
|
144
|
-
if ((await workspace.exited) !== 0)
|
|
145
|
-
throw new Error(await new Response(workspace.stderr).text())
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
111
|
return root
|
|
149
112
|
}
|
|
150
113
|
|
|
@@ -261,54 +224,6 @@ status: working
|
|
|
261
224
|
])
|
|
262
225
|
})
|
|
263
226
|
|
|
264
|
-
test("injects the execution branch and repository for jj targets", async () => {
|
|
265
|
-
const root = await createExecutionWorkbase("jj")
|
|
266
|
-
const task = join(root, "tasks/single")
|
|
267
|
-
const phase = join(root, "tasks/multi/phases/build")
|
|
268
|
-
|
|
269
|
-
expect(await runTestEffect(pr(["view", "--web"], task))).toBe(0)
|
|
270
|
-
expect(await captured()).toEqual([
|
|
271
|
-
await realpath(join(task, "code/agency")),
|
|
272
|
-
"pr",
|
|
273
|
-
"view",
|
|
274
|
-
"feat/single",
|
|
275
|
-
"--repo",
|
|
276
|
-
"example/agency",
|
|
277
|
-
"--web",
|
|
278
|
-
expect.stringMatching(/^GIT_DIR=.*\.jj/),
|
|
279
|
-
])
|
|
280
|
-
|
|
281
|
-
expect(
|
|
282
|
-
await runTestEffect(pr(["create", "--title", "Example"], phase)),
|
|
283
|
-
).toBe(0)
|
|
284
|
-
expect(await captured()).toEqual([
|
|
285
|
-
await realpath(join(phase, "code/agency")),
|
|
286
|
-
"pr",
|
|
287
|
-
"create",
|
|
288
|
-
"--head",
|
|
289
|
-
"feat/build",
|
|
290
|
-
"--repo",
|
|
291
|
-
"example/agency",
|
|
292
|
-
"--title",
|
|
293
|
-
"Example",
|
|
294
|
-
expect.stringMatching(/^GIT_DIR=.*\.jj/),
|
|
295
|
-
])
|
|
296
|
-
})
|
|
297
|
-
|
|
298
|
-
test("preserves explicit jj PR and repository targets", async () => {
|
|
299
|
-
const root = await createExecutionWorkbase("jj")
|
|
300
|
-
const task = join(root, "tasks/single")
|
|
301
|
-
const args = ["view", "123", "--repo", "other/repository"]
|
|
302
|
-
|
|
303
|
-
expect(await runTestEffect(pr(args, task))).toBe(0)
|
|
304
|
-
expect(await captured()).toEqual([
|
|
305
|
-
await realpath(join(task, "code/agency")),
|
|
306
|
-
"pr",
|
|
307
|
-
...args,
|
|
308
|
-
expect.stringMatching(/^GIT_DIR=.*\.jj/),
|
|
309
|
-
])
|
|
310
|
-
})
|
|
311
|
-
|
|
312
227
|
test("falls back to the invocation directory without execution authority", async () => {
|
|
313
228
|
const root = await createExecutionWorkbase()
|
|
314
229
|
const orchestration = join(root, "tasks/multi")
|