@markjaquith/agency 2.71.6 → 2.71.7
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.7",
|
|
4
4
|
"description": "Manage agentic work across repositories with durable workbases",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agents",
|
|
@@ -68,6 +68,7 @@
|
|
|
68
68
|
"benchmark:workbase": "bun scripts/benchmark-workbase.ts",
|
|
69
69
|
"benchmark:doctor": "bun scripts/benchmark-doctor.ts",
|
|
70
70
|
"benchmark:context": "bun scripts/benchmark-context.ts",
|
|
71
|
+
"benchmark:finish": "bun scripts/benchmark-finish.ts",
|
|
71
72
|
"benchmark:sync": "bun scripts/benchmark-sync.ts",
|
|
72
73
|
"benchmark:task": "bun scripts/benchmark-task.ts",
|
|
73
74
|
"test": "find src \\( -name '*.test.ts' -o -name '*.test.tsx' \\) -print0 | xargs -0 -n 1 -P 4 bun test",
|
|
@@ -234,6 +234,38 @@ describe("claim service", () => {
|
|
|
234
234
|
)
|
|
235
235
|
})
|
|
236
236
|
|
|
237
|
+
test("inspects a task without parsing unrelated task documents", async () => {
|
|
238
|
+
await mkdir(join(root, "tasks/broken"), { recursive: true })
|
|
239
|
+
await Bun.write(join(root, "tasks/broken/TASK.md"), "not frontmatter\n")
|
|
240
|
+
|
|
241
|
+
const inspected = await inspect()
|
|
242
|
+
expect(inspected.target.path).toBe(join(root, "tasks/single/TASK.md"))
|
|
243
|
+
expect(inspected.data).toMatchObject({ branch: "task/single" })
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
test("inspects a phase without parsing unrelated phase documents", async () => {
|
|
247
|
+
await mkdir(join(root, "tasks/phased/phases/target"), { recursive: true })
|
|
248
|
+
await mkdir(join(root, "tasks/phased/phases/broken"), { recursive: true })
|
|
249
|
+
await Bun.write(
|
|
250
|
+
join(root, "tasks/phased/TASK.md"),
|
|
251
|
+
"---\nticketUrl: null\nphases:\n - id: target\n - id: broken\nstatus: working\n---\n",
|
|
252
|
+
)
|
|
253
|
+
await Bun.write(
|
|
254
|
+
join(root, "tasks/phased/phases/target/PHASE.md"),
|
|
255
|
+
"---\nrepo: agency\nbranch: phase/target\nbase: main\npr: null\nstatus: open\n---\n",
|
|
256
|
+
)
|
|
257
|
+
await Bun.write(
|
|
258
|
+
join(root, "tasks/phased/phases/broken/PHASE.md"),
|
|
259
|
+
"not frontmatter\n",
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
const inspected = await inspect("phased", "target")
|
|
263
|
+
expect(inspected.target.path).toBe(
|
|
264
|
+
join(root, "tasks/phased/phases/target/PHASE.md"),
|
|
265
|
+
)
|
|
266
|
+
expect(inspected.data).toMatchObject({ branch: "phase/target" })
|
|
267
|
+
})
|
|
268
|
+
|
|
237
269
|
test("serializes concurrent claims and allows expired ownership replacement", async () => {
|
|
238
270
|
const initial = await inspect()
|
|
239
271
|
const attempts = await Promise.allSettled([
|
|
@@ -10,10 +10,7 @@ import {
|
|
|
10
10
|
writeFile,
|
|
11
11
|
} from "node:fs/promises"
|
|
12
12
|
import { basename, dirname, join, relative } from "node:path"
|
|
13
|
-
import { PhaseService } from "./PhaseService"
|
|
14
|
-
import { TaskService } from "./TaskService"
|
|
15
13
|
import { WorkbaseService } from "./WorkbaseService"
|
|
16
|
-
import { FileSystemService } from "./FileSystemService"
|
|
17
14
|
import {
|
|
18
15
|
documentRevision,
|
|
19
16
|
isDocumentRevision,
|
|
@@ -66,6 +63,47 @@ interface ClaimTarget {
|
|
|
66
63
|
readonly label: string
|
|
67
64
|
}
|
|
68
65
|
|
|
66
|
+
const resolveTarget = async (
|
|
67
|
+
root: string,
|
|
68
|
+
taskId: string,
|
|
69
|
+
phaseId?: string,
|
|
70
|
+
): Promise<ClaimTarget> => {
|
|
71
|
+
const taskPath = join(root, "tasks", taskId, "TASK.md")
|
|
72
|
+
const path = phaseId
|
|
73
|
+
? join(root, "tasks", taskId, "phases", phaseId, "PHASE.md")
|
|
74
|
+
: taskPath
|
|
75
|
+
try {
|
|
76
|
+
await stat(taskPath)
|
|
77
|
+
} catch {
|
|
78
|
+
throw new ClaimError({ message: `Task '${taskId}' does not exist` })
|
|
79
|
+
}
|
|
80
|
+
if (phaseId) {
|
|
81
|
+
try {
|
|
82
|
+
await stat(path)
|
|
83
|
+
} catch {
|
|
84
|
+
throw new ClaimError({
|
|
85
|
+
message: `Phase '${phaseId}' does not exist on task '${taskId}'`,
|
|
86
|
+
})
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return phaseId
|
|
90
|
+
? {
|
|
91
|
+
kind: "phase",
|
|
92
|
+
root,
|
|
93
|
+
taskId,
|
|
94
|
+
phaseId,
|
|
95
|
+
path,
|
|
96
|
+
label: `phase '${taskId}/${phaseId}'`,
|
|
97
|
+
}
|
|
98
|
+
: {
|
|
99
|
+
kind: "task",
|
|
100
|
+
root,
|
|
101
|
+
taskId,
|
|
102
|
+
path,
|
|
103
|
+
label: `task '${taskId}'`,
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
69
107
|
interface ClaimInput {
|
|
70
108
|
readonly taskId: string
|
|
71
109
|
readonly phaseId?: string
|
|
@@ -276,43 +314,24 @@ export class ClaimService extends Effect.Service<ClaimService>()(
|
|
|
276
314
|
startPath: string = process.cwd(),
|
|
277
315
|
) =>
|
|
278
316
|
Effect.gen(function* () {
|
|
279
|
-
const fs = yield* FileSystemService
|
|
280
317
|
const workbase = yield* WorkbaseService
|
|
281
|
-
const tasks = yield* TaskService
|
|
282
|
-
const phases = yield* PhaseService
|
|
283
318
|
const root = yield* workbase.discover(startPath)
|
|
284
|
-
const
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
const
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
root,
|
|
292
|
-
taskId: task.id,
|
|
293
|
-
phaseId,
|
|
294
|
-
path: phase!.path,
|
|
295
|
-
label: `phase '${task.id}/${phaseId}'`,
|
|
296
|
-
}
|
|
297
|
-
: {
|
|
298
|
-
kind: "task",
|
|
299
|
-
root,
|
|
300
|
-
taskId: task.id,
|
|
301
|
-
path: task.path,
|
|
302
|
-
label: `task '${task.id}'`,
|
|
303
|
-
}
|
|
304
|
-
if (!phaseId && "phases" in task.data) {
|
|
319
|
+
const target = yield* operation(() =>
|
|
320
|
+
resolveTarget(root, taskId, phaseId),
|
|
321
|
+
)
|
|
322
|
+
const content = yield* operation(() => readFile(target.path, "utf8"))
|
|
323
|
+
const parsed = parseFrontmatterSync(content, target.path)
|
|
324
|
+
const data = decodeExecution(target, parsed.data)
|
|
325
|
+
if (!phaseId && "phases" in data) {
|
|
305
326
|
return yield* new ClaimError({
|
|
306
327
|
target: target.label,
|
|
307
|
-
message: `Task '${
|
|
328
|
+
message: `Task '${taskId}' has multiple phases; claim a phase instead`,
|
|
308
329
|
})
|
|
309
330
|
}
|
|
310
|
-
const content = yield* fs.readFile(target.path)
|
|
311
|
-
const parsed = parseFrontmatterSync(content, target.path)
|
|
312
331
|
return {
|
|
313
332
|
target,
|
|
314
333
|
revision: documentRevision(content),
|
|
315
|
-
data
|
|
334
|
+
data,
|
|
316
335
|
}
|
|
317
336
|
}),
|
|
318
337
|
|