@markjaquith/agency 2.49.0 → 2.51.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 +56 -9
- package/cli.ts +56 -1
- package/package.json +1 -1
- package/schemas/agency-graph-v1.schema.json +142 -38
- package/src/cli-parser.test.ts +81 -0
- package/src/cli-parser.ts +78 -1
- package/src/cli.test.ts +4 -4
- package/src/commands/init.test.ts +2 -0
- package/src/commands/review.ts +38 -0
- package/src/commands/task.ts +27 -5
- package/src/commands/vcs.test.ts +75 -0
- package/src/commands/vcs.ts +72 -0
- package/src/commands/work.test.ts +2 -0
- package/src/commands/work.ts +2 -2
- package/src/commands/worktree.ts +1 -1
- package/src/graph-schema.test.ts +1 -1
- package/src/graph-schema.ts +36 -13
- package/src/protocol.ts +1 -0
- package/src/services/ArchiveService.test.ts +2 -2
- package/src/services/ArchiveService.ts +24 -0
- package/src/services/ClaimService.ts +3 -2
- package/src/services/ContextService.ts +118 -17
- package/src/services/DoctorService.ts +58 -7
- package/src/services/GraphMutationService.ts +5 -0
- package/src/services/GraphService.ts +119 -54
- package/src/services/PhaseService.ts +196 -70
- package/src/services/PullRequestService.test.ts +2 -2
- package/src/services/PullRequestService.ts +37 -33
- package/src/services/ReadinessService.ts +7 -3
- package/src/services/RepositoryService.test.ts +31 -1
- package/src/services/RepositoryService.ts +63 -31
- package/src/services/ReviewService.test.ts +472 -0
- package/src/services/ReviewService.ts +427 -0
- package/src/services/SyncService.test.ts +69 -2
- package/src/services/SyncService.ts +161 -90
- package/src/services/TaskPhaseService.test.ts +80 -0
- package/src/services/TaskService.ts +82 -9
- package/src/services/VcsMigrationService.test.ts +211 -0
- package/src/services/VcsMigrationService.ts +816 -0
- package/src/services/VersionControlService.test.ts +100 -0
- package/src/services/VersionControlService.ts +479 -0
- package/src/services/WorkbaseService.ts +7 -2
- package/src/services/WorktreeService.test.ts +88 -17
- package/src/services/WorktreeService.ts +865 -329
- package/src/test-utils.ts +12 -0
- package/src/work-view.ts +14 -6
- package/src/workbase/AGENTS.md +2 -2
- package/src/workbase/schemas.test.ts +57 -0
- package/src/workbase/schemas.ts +57 -0
- package/src/workbase/version-control.ts +5 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { afterEach, beforeEach, describe, expect, test } from "bun:test"
|
|
2
2
|
import { Effect } from "effect"
|
|
3
|
-
import { mkdir, realpath, rename, rm } from "node:fs/promises"
|
|
3
|
+
import { mkdir, realpath, rename, rm, stat } from "node:fs/promises"
|
|
4
4
|
import { join } from "node:path"
|
|
5
5
|
import {
|
|
6
6
|
captureErrors,
|
|
@@ -23,6 +23,17 @@ const git = async (args: string[], cwd?: string) => {
|
|
|
23
23
|
throw new Error(await new Response(process.stderr).text())
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
const jj = async (args: string[], cwd?: string) => {
|
|
27
|
+
const process = Bun.spawn(["jj", ...args], {
|
|
28
|
+
cwd,
|
|
29
|
+
stdout: "pipe",
|
|
30
|
+
stderr: "pipe",
|
|
31
|
+
})
|
|
32
|
+
await process.exited
|
|
33
|
+
if (process.exitCode !== 0)
|
|
34
|
+
throw new Error(await new Response(process.stderr).text())
|
|
35
|
+
}
|
|
36
|
+
|
|
26
37
|
describe("WorktreeService", () => {
|
|
27
38
|
let root: string
|
|
28
39
|
let source: string
|
|
@@ -81,18 +92,78 @@ describe("WorktreeService", () => {
|
|
|
81
92
|
)
|
|
82
93
|
|
|
83
94
|
expect(
|
|
84
|
-
await Bun.file(join(workspace.writablePath
|
|
95
|
+
await Bun.file(join(workspace.writablePath!, "README.md")).text(),
|
|
85
96
|
).toBe("example\n")
|
|
86
97
|
expect(
|
|
87
98
|
await Bun.file(join(workspace.codePath, "effect/README.md")).text(),
|
|
88
99
|
).toBe("example\n")
|
|
89
100
|
const branch = Bun.spawnSync(
|
|
90
|
-
["git", "-C", workspace.writablePath
|
|
101
|
+
["git", "-C", workspace.writablePath!, "branch", "--show-current"],
|
|
91
102
|
{ stdout: "pipe" },
|
|
92
103
|
)
|
|
93
104
|
expect(new TextDecoder().decode(branch.stdout).trim()).toBe("task/example")
|
|
94
105
|
})
|
|
95
106
|
|
|
107
|
+
test("materializes and removes a jj workspace for a jj workbase", async () => {
|
|
108
|
+
if (!Bun.which("jj")) return
|
|
109
|
+
const repository = join(root, "repos/agency")
|
|
110
|
+
await rm(repository, { recursive: true, force: true })
|
|
111
|
+
await git(["clone", source, repository])
|
|
112
|
+
await jj(["git", "init", "--colocate", repository])
|
|
113
|
+
await Bun.write(
|
|
114
|
+
join(root, "agency.json"),
|
|
115
|
+
JSON.stringify({ version: 2, vcs: "jj" }),
|
|
116
|
+
)
|
|
117
|
+
await runTestEffect(
|
|
118
|
+
TaskService.pipe(
|
|
119
|
+
Effect.flatMap((service) =>
|
|
120
|
+
service.create(
|
|
121
|
+
{
|
|
122
|
+
id: "jj-example",
|
|
123
|
+
ticketUrl: null,
|
|
124
|
+
repo: "agency",
|
|
125
|
+
branch: "task/jj-example",
|
|
126
|
+
base: "main",
|
|
127
|
+
},
|
|
128
|
+
root,
|
|
129
|
+
),
|
|
130
|
+
),
|
|
131
|
+
),
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
const workspace = await runTestEffect(
|
|
135
|
+
WorktreeService.pipe(
|
|
136
|
+
Effect.flatMap((service) =>
|
|
137
|
+
service.materialize("jj-example", undefined, root),
|
|
138
|
+
),
|
|
139
|
+
),
|
|
140
|
+
)
|
|
141
|
+
const jjMetadata = await stat(join(workspace.writablePath!, ".jj"))
|
|
142
|
+
expect(jjMetadata.isFile() || jjMetadata.isDirectory()).toBe(true)
|
|
143
|
+
const inspection = await runTestEffect(
|
|
144
|
+
WorktreeService.pipe(
|
|
145
|
+
Effect.flatMap((service) =>
|
|
146
|
+
service.inspect("jj-example", undefined, root),
|
|
147
|
+
),
|
|
148
|
+
),
|
|
149
|
+
)
|
|
150
|
+
expect(inspection.conflicts).toEqual([])
|
|
151
|
+
expect(inspection.checkouts[0]).toMatchObject({
|
|
152
|
+
exists: true,
|
|
153
|
+
registered: true,
|
|
154
|
+
actualBranch: "task/jj-example",
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
await runTestEffect(
|
|
158
|
+
WorktreeService.pipe(
|
|
159
|
+
Effect.flatMap((service) =>
|
|
160
|
+
service.remove("jj-example", undefined, root),
|
|
161
|
+
),
|
|
162
|
+
),
|
|
163
|
+
)
|
|
164
|
+
expect(await Bun.file(workspace.writablePath!).exists()).toBe(false)
|
|
165
|
+
})
|
|
166
|
+
|
|
96
167
|
test("does not fetch the origin for an existing writable worktree", async () => {
|
|
97
168
|
await runTestEffect(
|
|
98
169
|
TaskService.pipe(
|
|
@@ -272,7 +343,7 @@ describe("WorktreeService", () => {
|
|
|
272
343
|
),
|
|
273
344
|
)
|
|
274
345
|
expect(
|
|
275
|
-
await Bun.file(join(workspace.writablePath
|
|
346
|
+
await Bun.file(join(workspace.writablePath!, "README.md")).text(),
|
|
276
347
|
).toBe("example\n")
|
|
277
348
|
})
|
|
278
349
|
|
|
@@ -599,7 +670,7 @@ pr: null
|
|
|
599
670
|
|
|
600
671
|
expect(
|
|
601
672
|
await Bun.file(
|
|
602
|
-
join(originalWorkspace.writablePath
|
|
673
|
+
join(originalWorkspace.writablePath!, "README.md"),
|
|
603
674
|
).exists(),
|
|
604
675
|
).toBe(false)
|
|
605
676
|
const movedWorkspace = await runTestEffect(
|
|
@@ -613,10 +684,10 @@ pr: null
|
|
|
613
684
|
join(root, "tasks/promoted/phases/implementation/code/agency"),
|
|
614
685
|
)
|
|
615
686
|
expect(
|
|
616
|
-
await Bun.file(join(movedWorkspace.writablePath
|
|
687
|
+
await Bun.file(join(movedWorkspace.writablePath!, "README.md")).text(),
|
|
617
688
|
).toBe("example\n")
|
|
618
689
|
const status = Bun.spawnSync(
|
|
619
|
-
["git", "-C", movedWorkspace.writablePath
|
|
690
|
+
["git", "-C", movedWorkspace.writablePath!, "status", "--porcelain"],
|
|
620
691
|
{ stdout: "pipe", stderr: "pipe" },
|
|
621
692
|
)
|
|
622
693
|
expect(status.exitCode).toBe(0)
|
|
@@ -1072,7 +1143,7 @@ pr: null
|
|
|
1072
1143
|
),
|
|
1073
1144
|
)
|
|
1074
1145
|
await Bun.write(
|
|
1075
|
-
join(workspace.writablePath
|
|
1146
|
+
join(workspace.writablePath!, "uncommitted.txt"),
|
|
1076
1147
|
"keep me\n",
|
|
1077
1148
|
)
|
|
1078
1149
|
|
|
@@ -1084,7 +1155,7 @@ pr: null
|
|
|
1084
1155
|
),
|
|
1085
1156
|
).rejects.toThrow("Failed to remove worktree for 'agency'")
|
|
1086
1157
|
expect(
|
|
1087
|
-
await Bun.file(join(workspace.writablePath
|
|
1158
|
+
await Bun.file(join(workspace.writablePath!, "uncommitted.txt")).text(),
|
|
1088
1159
|
).toBe("keep me\n")
|
|
1089
1160
|
})
|
|
1090
1161
|
|
|
@@ -1131,7 +1202,7 @@ pr: null
|
|
|
1131
1202
|
"--porcelain",
|
|
1132
1203
|
])
|
|
1133
1204
|
expect(new TextDecoder().decode(worktrees.stdout)).not.toContain(
|
|
1134
|
-
workspace.writablePath
|
|
1205
|
+
workspace.writablePath!,
|
|
1135
1206
|
)
|
|
1136
1207
|
expect(
|
|
1137
1208
|
Bun.spawnSync([
|
|
@@ -1325,7 +1396,7 @@ pr: null
|
|
|
1325
1396
|
),
|
|
1326
1397
|
).rejects.toThrow("multiple Agency owners")
|
|
1327
1398
|
expect(
|
|
1328
|
-
await Bun.file(join(workspace.writablePath
|
|
1399
|
+
await Bun.file(join(workspace.writablePath!, "README.md")).exists(),
|
|
1329
1400
|
).toBe(true)
|
|
1330
1401
|
})
|
|
1331
1402
|
|
|
@@ -1371,7 +1442,7 @@ pr: null
|
|
|
1371
1442
|
]),
|
|
1372
1443
|
)
|
|
1373
1444
|
expect(
|
|
1374
|
-
await Bun.file(join(original.writablePath
|
|
1445
|
+
await Bun.file(join(original.writablePath!, "README.md")).exists(),
|
|
1375
1446
|
).toBe(true)
|
|
1376
1447
|
|
|
1377
1448
|
const rebuilt = await runTestEffect(
|
|
@@ -1383,7 +1454,7 @@ pr: null
|
|
|
1383
1454
|
)
|
|
1384
1455
|
expect(rebuilt.inspection.conflicts).toEqual([])
|
|
1385
1456
|
expect(
|
|
1386
|
-
await Bun.file(join(original.writablePath
|
|
1457
|
+
await Bun.file(join(original.writablePath!, "README.md")).exists(),
|
|
1387
1458
|
).toBe(true)
|
|
1388
1459
|
})
|
|
1389
1460
|
|
|
@@ -1435,7 +1506,7 @@ pr: null
|
|
|
1435
1506
|
),
|
|
1436
1507
|
).rejects.toThrow("original worktrees were restored")
|
|
1437
1508
|
expect(
|
|
1438
|
-
await Bun.file(join(workspace.writablePath
|
|
1509
|
+
await Bun.file(join(workspace.writablePath!, "README.md")).exists(),
|
|
1439
1510
|
).toBe(true)
|
|
1440
1511
|
})
|
|
1441
1512
|
|
|
@@ -1473,7 +1544,7 @@ pr: null
|
|
|
1473
1544
|
),
|
|
1474
1545
|
)
|
|
1475
1546
|
expect(plan.actions.join("\n")).toContain("worktree prune --expire now")
|
|
1476
|
-
expect(plan.actions).toContain(`prepare ${workspace.writablePath}`)
|
|
1547
|
+
expect(plan.actions).toContain(`prepare ${workspace.writablePath!}`)
|
|
1477
1548
|
|
|
1478
1549
|
const repaired = await runTestEffect(
|
|
1479
1550
|
WorktreeService.pipe(
|
|
@@ -1484,7 +1555,7 @@ pr: null
|
|
|
1484
1555
|
)
|
|
1485
1556
|
expect(repaired.inspection.conflicts).toEqual([])
|
|
1486
1557
|
expect(
|
|
1487
|
-
await Bun.file(join(workspace.writablePath
|
|
1558
|
+
await Bun.file(join(workspace.writablePath!, "README.md")).exists(),
|
|
1488
1559
|
).toBe(true)
|
|
1489
1560
|
expect(
|
|
1490
1561
|
Bun.spawnSync([
|
|
@@ -1648,7 +1719,7 @@ pr: null
|
|
|
1648
1719
|
),
|
|
1649
1720
|
)
|
|
1650
1721
|
expect(
|
|
1651
|
-
await Bun.file(join(workspace.writablePath
|
|
1722
|
+
await Bun.file(join(workspace.writablePath!, "README.md")).text(),
|
|
1652
1723
|
).toBe("example\n")
|
|
1653
1724
|
})
|
|
1654
1725
|
})
|