@markjaquith/agency 2.24.0 → 2.25.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/cli.ts +10 -0
- package/package.json +1 -1
- package/src/cli-parser.test.ts +9 -0
- package/src/commands/archive.test.ts +22 -0
- package/src/commands/archive.ts +3 -1
- package/src/services/ArchiveService.test.ts +59 -0
- package/src/services/ArchiveService.ts +282 -113
- package/src/services/LifecycleTransaction.test.ts +107 -0
- package/src/services/LifecycleTransaction.ts +302 -0
- package/src/services/PhaseService.ts +156 -48
- package/src/services/TaskPhaseService.test.ts +47 -1
- package/src/services/TaskService.ts +28 -4
- package/src/services/WorktreeLock.ts +60 -0
- package/src/services/WorktreeService.test.ts +174 -1
- package/src/services/WorktreeService.ts +972 -523
package/cli.ts
CHANGED
|
@@ -683,6 +683,7 @@ try {
|
|
|
683
683
|
}
|
|
684
684
|
if (error instanceof Error) {
|
|
685
685
|
let message = error.message
|
|
686
|
+
let details: any = error
|
|
686
687
|
|
|
687
688
|
// Handle Effect FiberFailure errors that wrap tagged errors
|
|
688
689
|
// When the message is generic "An error has occurred", try to extract the actual error
|
|
@@ -695,6 +696,7 @@ try {
|
|
|
695
696
|
const cause = (error as any)[causeSymbol]
|
|
696
697
|
if (cause && cause._tag === "Fail" && cause.failure) {
|
|
697
698
|
const failure = cause.failure
|
|
699
|
+
details = failure
|
|
698
700
|
// Try common error message patterns
|
|
699
701
|
message =
|
|
700
702
|
failure.message ||
|
|
@@ -705,6 +707,14 @@ try {
|
|
|
705
707
|
}
|
|
706
708
|
}
|
|
707
709
|
}
|
|
710
|
+
for (const [field, label] of [
|
|
711
|
+
["completed", "Completed"],
|
|
712
|
+
["rolledBack", "Rolled back"],
|
|
713
|
+
["manualRecovery", "Manual recovery"],
|
|
714
|
+
] as const) {
|
|
715
|
+
if (Array.isArray(details[field]) && details[field].length > 0)
|
|
716
|
+
message += `\n${label}: ${details[field].join("; ")}`
|
|
717
|
+
}
|
|
708
718
|
|
|
709
719
|
console.error(`ⓘ ${message}`)
|
|
710
720
|
} else {
|
package/package.json
CHANGED
package/src/cli-parser.test.ts
CHANGED
|
@@ -292,6 +292,15 @@ describe("strict CLI parsing", () => {
|
|
|
292
292
|
)
|
|
293
293
|
})
|
|
294
294
|
|
|
295
|
+
test("accepts archive dry-run", () => {
|
|
296
|
+
expect(parseCli(["archive", "task", "example", "--dry-run"])).toMatchObject(
|
|
297
|
+
{
|
|
298
|
+
commandName: "archive",
|
|
299
|
+
values: { "dry-run": true },
|
|
300
|
+
},
|
|
301
|
+
)
|
|
302
|
+
})
|
|
303
|
+
|
|
295
304
|
test("validates revision-guarded claim operations", () => {
|
|
296
305
|
const revision = "0".repeat(64)
|
|
297
306
|
expect(
|
|
@@ -63,6 +63,28 @@ describe("archive command", () => {
|
|
|
63
63
|
})
|
|
64
64
|
})
|
|
65
65
|
|
|
66
|
+
test("preflights an archive without moving the task", async () => {
|
|
67
|
+
const logs = await captureLogs(() =>
|
|
68
|
+
runTestEffect(
|
|
69
|
+
archive({
|
|
70
|
+
type: "task",
|
|
71
|
+
args: ["example"],
|
|
72
|
+
cwd: root,
|
|
73
|
+
dryRun: true,
|
|
74
|
+
json: true,
|
|
75
|
+
}),
|
|
76
|
+
),
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
expect(JSON.parse(logs[0]!).dryRun).toBe(true)
|
|
80
|
+
expect(await Bun.file(join(root, "tasks/example/TASK.md")).exists()).toBe(
|
|
81
|
+
true,
|
|
82
|
+
)
|
|
83
|
+
expect(await Bun.file(join(root, "archive/tasks/example")).exists()).toBe(
|
|
84
|
+
false,
|
|
85
|
+
)
|
|
86
|
+
})
|
|
87
|
+
|
|
66
88
|
test("requires a supported work item type", async () => {
|
|
67
89
|
await expect(
|
|
68
90
|
runTestEffect(archive({ args: [], cwd: root, silent: true })),
|
package/src/commands/archive.ts
CHANGED
|
@@ -112,7 +112,9 @@ export const archive = (options: ArchiveOptions) =>
|
|
|
112
112
|
log(
|
|
113
113
|
options.json
|
|
114
114
|
? JSON.stringify(result, null, 2)
|
|
115
|
-
:
|
|
115
|
+
: result.dryRun
|
|
116
|
+
? `Would archive ${result.kind} '${result.id}' to ${result.path}`
|
|
117
|
+
: `Archived ${result.kind} '${result.id}' to ${result.path}`,
|
|
116
118
|
)
|
|
117
119
|
})
|
|
118
120
|
|
|
@@ -850,4 +850,63 @@ describe("ArchiveService", () => {
|
|
|
850
850
|
),
|
|
851
851
|
).rejects.toThrow("is archived; restore it")
|
|
852
852
|
})
|
|
853
|
+
|
|
854
|
+
test("preflights every phase worktree before removing any of them", async () => {
|
|
855
|
+
await runTestEffect(
|
|
856
|
+
TaskService.pipe(
|
|
857
|
+
Effect.flatMap((service) =>
|
|
858
|
+
service.create(
|
|
859
|
+
{
|
|
860
|
+
id: "multi-dirty",
|
|
861
|
+
ticketUrl: "https://example.com/task",
|
|
862
|
+
multiPhase: true,
|
|
863
|
+
},
|
|
864
|
+
root,
|
|
865
|
+
),
|
|
866
|
+
),
|
|
867
|
+
),
|
|
868
|
+
)
|
|
869
|
+
for (const id of ["clean", "dirty"]) {
|
|
870
|
+
await runTestEffect(
|
|
871
|
+
PhaseService.pipe(
|
|
872
|
+
Effect.flatMap((service) =>
|
|
873
|
+
service.create(
|
|
874
|
+
{
|
|
875
|
+
taskId: "multi-dirty",
|
|
876
|
+
id,
|
|
877
|
+
repo: "agency",
|
|
878
|
+
branch: `task/${id}`,
|
|
879
|
+
base: "main",
|
|
880
|
+
},
|
|
881
|
+
root,
|
|
882
|
+
),
|
|
883
|
+
),
|
|
884
|
+
),
|
|
885
|
+
)
|
|
886
|
+
await runTestEffect(
|
|
887
|
+
WorktreeService.pipe(
|
|
888
|
+
Effect.flatMap((service) =>
|
|
889
|
+
service.materialize("multi-dirty", id, root),
|
|
890
|
+
),
|
|
891
|
+
),
|
|
892
|
+
)
|
|
893
|
+
}
|
|
894
|
+
await Bun.write(
|
|
895
|
+
join(root, "tasks/multi-dirty/phases/dirty/code/agency/dirty.txt"),
|
|
896
|
+
"keep me\n",
|
|
897
|
+
)
|
|
898
|
+
|
|
899
|
+
await expect(
|
|
900
|
+
runTestEffect(
|
|
901
|
+
ArchiveService.pipe(
|
|
902
|
+
Effect.flatMap((service) => service.archiveTask("multi-dirty", root)),
|
|
903
|
+
),
|
|
904
|
+
),
|
|
905
|
+
).rejects.toThrow("uncommitted changes")
|
|
906
|
+
expect(
|
|
907
|
+
await Bun.file(
|
|
908
|
+
join(root, "tasks/multi-dirty/phases/clean/code/agency/README.md"),
|
|
909
|
+
).exists(),
|
|
910
|
+
).toBe(true)
|
|
911
|
+
})
|
|
853
912
|
})
|