@markjaquith/agency 2.71.16 → 2.71.17
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markjaquith/agency",
|
|
3
|
-
"version": "2.71.
|
|
3
|
+
"version": "2.71.17",
|
|
4
4
|
"description": "Manage agentic work across repositories with durable workbases",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agents",
|
|
@@ -77,6 +77,7 @@
|
|
|
77
77
|
"benchmark:finish": "bun scripts/benchmark-finish.ts",
|
|
78
78
|
"benchmark:phase": "bun scripts/benchmark-phase.ts",
|
|
79
79
|
"benchmark:push": "bun scripts/benchmark-push.ts",
|
|
80
|
+
"benchmark:archive": "bun scripts/benchmark-archive.ts",
|
|
80
81
|
"benchmark:sync": "bun scripts/benchmark-sync.ts",
|
|
81
82
|
"benchmark:task": "bun scripts/benchmark-task.ts",
|
|
82
83
|
"benchmark:validate": "bun scripts/benchmark-validate.ts",
|
|
@@ -121,6 +121,35 @@ describe("ArchiveService bulk task archive", () => {
|
|
|
121
121
|
)
|
|
122
122
|
})
|
|
123
123
|
|
|
124
|
+
test("reuses loaded records while preflighting task worktrees", async () => {
|
|
125
|
+
for (const id of ["first", "second"]) {
|
|
126
|
+
await createTask(id)
|
|
127
|
+
await dropTask(id)
|
|
128
|
+
}
|
|
129
|
+
let taskReads = 0
|
|
130
|
+
const file = Bun.file(join(root, "tasks/first/TASK.md"))
|
|
131
|
+
const prototype = Object.getPrototypeOf(file) as {
|
|
132
|
+
text: () => Promise<string>
|
|
133
|
+
name: string
|
|
134
|
+
}
|
|
135
|
+
const originalText = prototype.text
|
|
136
|
+
prototype.text = function () {
|
|
137
|
+
if (this.name.endsWith("/TASK.md")) taskReads += 1
|
|
138
|
+
return originalText.call(this)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
try {
|
|
142
|
+
const result = await archiveTasks(true)
|
|
143
|
+
expect(result.tasks.map((task) => task.disposition)).toEqual([
|
|
144
|
+
"planned",
|
|
145
|
+
"planned",
|
|
146
|
+
])
|
|
147
|
+
expect(taskReads).toBe(10)
|
|
148
|
+
} finally {
|
|
149
|
+
prototype.text = originalText
|
|
150
|
+
}
|
|
151
|
+
})
|
|
152
|
+
|
|
124
153
|
test("uses aggregate phase status and archives only when every phase is terminal", async () => {
|
|
125
154
|
await runTestEffect(
|
|
126
155
|
TaskService.pipe(
|
|
@@ -887,7 +887,10 @@ export class ArchiveService extends Effect.Service<ArchiveService>()(
|
|
|
887
887
|
})
|
|
888
888
|
continue
|
|
889
889
|
}
|
|
890
|
+
}
|
|
890
891
|
|
|
892
|
+
for (const context of contexts.values()) {
|
|
893
|
+
if (skipped.has(context.task.id)) continue
|
|
891
894
|
const removed: string[] = []
|
|
892
895
|
let preflightFailure: unknown
|
|
893
896
|
for (const unit of context.executionUnits) {
|
|
@@ -895,6 +898,10 @@ export class ArchiveService extends Effect.Service<ArchiveService>()(
|
|
|
895
898
|
.remove(unit.taskId, executionPhaseId(unit), root, {
|
|
896
899
|
dryRun: true,
|
|
897
900
|
persistResume: false,
|
|
901
|
+
task: context.task,
|
|
902
|
+
phase: unit.phaseId
|
|
903
|
+
? context.phases.find((phase) => phase.id === unit.phaseId)
|
|
904
|
+
: undefined,
|
|
898
905
|
})
|
|
899
906
|
.pipe(Effect.either)
|
|
900
907
|
if (Either.isLeft(result)) {
|
|
@@ -943,13 +950,13 @@ export class ArchiveService extends Effect.Service<ArchiveService>()(
|
|
|
943
950
|
"dirty" in conflict &&
|
|
944
951
|
conflict.dirty === true,
|
|
945
952
|
)
|
|
946
|
-
skipped.set(task.id, {
|
|
953
|
+
skipped.set(context.task.id, {
|
|
947
954
|
code: dirty ? "dirty-worktree" : "checkout-preflight-failed",
|
|
948
955
|
details: [message],
|
|
949
956
|
})
|
|
950
957
|
continue
|
|
951
958
|
}
|
|
952
|
-
removedByTask.set(task.id, [...new Set(removed)].sort())
|
|
959
|
+
removedByTask.set(context.task.id, [...new Set(removed)].sort())
|
|
953
960
|
}
|
|
954
961
|
|
|
955
962
|
const cohort = new Set(
|
|
@@ -1069,6 +1076,14 @@ export class ArchiveService extends Effect.Service<ArchiveService>()(
|
|
|
1069
1076
|
snapshots,
|
|
1070
1077
|
lockHeld: true,
|
|
1071
1078
|
persistResume: false,
|
|
1079
|
+
task: contexts.get(unit.taskId)!.task,
|
|
1080
|
+
phase: unit.phaseId
|
|
1081
|
+
? contexts
|
|
1082
|
+
.get(unit.taskId)!
|
|
1083
|
+
.phases.find(
|
|
1084
|
+
(phase) => phase.id === unit.phaseId,
|
|
1085
|
+
)
|
|
1086
|
+
: undefined,
|
|
1072
1087
|
}),
|
|
1073
1088
|
)
|
|
1074
1089
|
}
|
|
@@ -284,6 +284,8 @@ interface RemoveOptions extends BaseCommandOptions {
|
|
|
284
284
|
readonly lockHeld?: boolean
|
|
285
285
|
readonly allowReferenceDrift?: boolean
|
|
286
286
|
readonly persistResume?: boolean
|
|
287
|
+
readonly task?: TaskRecord
|
|
288
|
+
readonly phase?: PhaseRecord
|
|
287
289
|
}
|
|
288
290
|
|
|
289
291
|
interface LifecycleOptions extends BaseCommandOptions {
|
|
@@ -1575,14 +1577,14 @@ const removeJj = (
|
|
|
1575
1577
|
const phases = yield* PhaseService
|
|
1576
1578
|
const backend = yield* versionControl.forWorkbase(root)
|
|
1577
1579
|
const inspection = yield* inspectExecution(taskId, phaseId, root)
|
|
1578
|
-
const task = yield* tasks.show(taskId, root)
|
|
1580
|
+
const task = options.task ?? (yield* tasks.show(taskId, root))
|
|
1579
1581
|
const execution =
|
|
1580
1582
|
"phases" in task.data && phaseId
|
|
1581
|
-
? (yield* phases.show(taskId, phaseId, root)).data
|
|
1583
|
+
? (options.phase ?? (yield* phases.show(taskId, phaseId, root))).data
|
|
1582
1584
|
: task.data
|
|
1583
1585
|
const phasePath =
|
|
1584
1586
|
"phases" in task.data && phaseId
|
|
1585
|
-
? (yield* phases.show(taskId, phaseId, root)).path
|
|
1587
|
+
? (options.phase ?? (yield* phases.show(taskId, phaseId, root))).path
|
|
1586
1588
|
: null
|
|
1587
1589
|
const resumePath = jjResumePath(task.path, phasePath)
|
|
1588
1590
|
if (yield* fs.exists(resumePath)) {
|
|
@@ -2909,7 +2911,7 @@ export class WorktreeService extends Effect.Service<WorktreeService>()(
|
|
|
2909
2911
|
conflicts: blockingConflicts,
|
|
2910
2912
|
})
|
|
2911
2913
|
}
|
|
2912
|
-
const task = yield* tasks.show(taskId, root)
|
|
2914
|
+
const task = options.task ?? (yield* tasks.show(taskId, root))
|
|
2913
2915
|
|
|
2914
2916
|
let execution:
|
|
2915
2917
|
| {
|
|
@@ -2925,7 +2927,9 @@ export class WorktreeService extends Effect.Service<WorktreeService>()(
|
|
|
2925
2927
|
message: `Task '${taskId}' has multiple phases; phase ID is required`,
|
|
2926
2928
|
})
|
|
2927
2929
|
}
|
|
2928
|
-
const phase =
|
|
2930
|
+
const phase =
|
|
2931
|
+
options.phase ??
|
|
2932
|
+
(yield* phases.show(taskId, phaseId, root))
|
|
2929
2933
|
execution = phase.data
|
|
2930
2934
|
codePath = join(dirname(phase.path), "code")
|
|
2931
2935
|
} else {
|