@markjaquith/agency 2.71.0 → 2.71.2
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.2",
|
|
4
4
|
"description": "Manage agentic work across repositories with durable workbases",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agents",
|
|
@@ -65,6 +65,7 @@
|
|
|
65
65
|
"scripts": {
|
|
66
66
|
"postinstall": "bun scripts/install-pi-extension.ts install",
|
|
67
67
|
"preuninstall": "bun scripts/install-pi-extension.ts uninstall",
|
|
68
|
+
"benchmark:workbase": "bun scripts/benchmark-workbase.ts",
|
|
68
69
|
"benchmark:sync": "bun scripts/benchmark-sync.ts",
|
|
69
70
|
"test": "find src \\( -name '*.test.ts' -o -name '*.test.tsx' \\) -print0 | xargs -0 -n 1 -P 4 bun test",
|
|
70
71
|
"test:opencode": "AGENCY_TEST_OPENCODE=1 bun test src/cli.test.ts --test-name-pattern 'provides effective whole-workbase OpenCode access'",
|
|
@@ -394,6 +394,15 @@ describe("work command", () => {
|
|
|
394
394
|
target: "execution-unit:task/example",
|
|
395
395
|
override: true,
|
|
396
396
|
})
|
|
397
|
+
expect(forced.materializeOptions[0]?.validationAlreadyPerformed).toBe(false)
|
|
398
|
+
})
|
|
399
|
+
|
|
400
|
+
test("reuses successful readiness validation during materialization", async () => {
|
|
401
|
+
const harness = createHarness()
|
|
402
|
+
|
|
403
|
+
await harness.run({ taskId: "example", opencode: true })
|
|
404
|
+
|
|
405
|
+
expect(harness.materializeOptions[0]?.validationAlreadyPerformed).toBe(true)
|
|
397
406
|
})
|
|
398
407
|
|
|
399
408
|
test("reopens forced terminal tasks through open before launching as working", async () => {
|
package/src/commands/work.ts
CHANGED
|
@@ -237,6 +237,7 @@ export const work = (
|
|
|
237
237
|
if (!target) return
|
|
238
238
|
}
|
|
239
239
|
yield* readiness.guardWorkTarget(targetNodeId(target), root, options.force)
|
|
240
|
+
const validationAlreadyPerformed = !options.force
|
|
240
241
|
|
|
241
242
|
const continuing =
|
|
242
243
|
target.kind !== "epic" &&
|
|
@@ -257,7 +258,10 @@ export const work = (
|
|
|
257
258
|
const phaseId = target.kind === "phase" ? target.phaseId : undefined
|
|
258
259
|
progress.start("Preparing workspace...")
|
|
259
260
|
const workspace = yield* worktrees
|
|
260
|
-
.materialize(taskId, phaseId, root,
|
|
261
|
+
.materialize(taskId, phaseId, root, {
|
|
262
|
+
...options,
|
|
263
|
+
validationAlreadyPerformed,
|
|
264
|
+
})
|
|
261
265
|
.pipe(
|
|
262
266
|
Effect.tap(() =>
|
|
263
267
|
Effect.sync(() => progress.succeed("Workspace ready")),
|
|
@@ -87,14 +87,7 @@ export class FileSystemService extends Effect.Service<FileSystemService>()(
|
|
|
87
87
|
|
|
88
88
|
readFile: (path: string) =>
|
|
89
89
|
Effect.tryPromise({
|
|
90
|
-
try:
|
|
91
|
-
const file = Bun.file(path)
|
|
92
|
-
const exists = await file.exists()
|
|
93
|
-
if (!exists) {
|
|
94
|
-
throw new Error(`File not found: ${path}`)
|
|
95
|
-
}
|
|
96
|
-
return await file.text()
|
|
97
|
-
},
|
|
90
|
+
try: () => Bun.file(path).text(),
|
|
98
91
|
catch: () => new FileNotFoundError({ path }),
|
|
99
92
|
}),
|
|
100
93
|
|
|
@@ -144,13 +144,15 @@ export class GraphService extends Effect.Service<GraphService>()(
|
|
|
144
144
|
const phases = new Map<string, Document<PhaseData>>()
|
|
145
145
|
|
|
146
146
|
const directories = (path: string) =>
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
147
|
+
fs.readDirectory(path).pipe(
|
|
148
|
+
Effect.map((entries) =>
|
|
149
|
+
entries
|
|
150
|
+
.filter((entry) => entry.isDirectory)
|
|
151
|
+
.map((entry) => entry.name)
|
|
152
|
+
.sort(),
|
|
153
|
+
),
|
|
154
|
+
Effect.catchAll(() => Effect.succeed([])),
|
|
155
|
+
)
|
|
154
156
|
|
|
155
157
|
const readDocument = <S extends Schema.Schema.AnyNoContext>(
|
|
156
158
|
id: string,
|
|
@@ -185,9 +187,11 @@ export class GraphService extends Effect.Service<GraphService>()(
|
|
|
185
187
|
epicIds.map((id) =>
|
|
186
188
|
Effect.gen(function* () {
|
|
187
189
|
const path = join(root, "epics", id, "EPIC.md")
|
|
188
|
-
return
|
|
189
|
-
|
|
190
|
-
|
|
190
|
+
return yield* readDocument(id, path, EpicFrontmatter).pipe(
|
|
191
|
+
Effect.catchTag("FileNotFoundError", () =>
|
|
192
|
+
Effect.succeed(null),
|
|
193
|
+
),
|
|
194
|
+
)
|
|
191
195
|
}),
|
|
192
196
|
),
|
|
193
197
|
{ concurrency: "unbounded" },
|
|
@@ -201,9 +205,15 @@ export class GraphService extends Effect.Service<GraphService>()(
|
|
|
201
205
|
taskIds.map((id) =>
|
|
202
206
|
Effect.gen(function* () {
|
|
203
207
|
const path = join(root, "tasks", id, "TASK.md")
|
|
204
|
-
const task =
|
|
205
|
-
|
|
206
|
-
|
|
208
|
+
const task = yield* readDocument(
|
|
209
|
+
id,
|
|
210
|
+
path,
|
|
211
|
+
TaskFrontmatter,
|
|
212
|
+
).pipe(
|
|
213
|
+
Effect.catchTag("FileNotFoundError", () =>
|
|
214
|
+
Effect.succeed(null),
|
|
215
|
+
),
|
|
216
|
+
)
|
|
207
217
|
const phaseIds = yield* directories(
|
|
208
218
|
join(root, "tasks", id, "phases"),
|
|
209
219
|
)
|
|
@@ -218,13 +228,15 @@ export class GraphService extends Effect.Service<GraphService>()(
|
|
|
218
228
|
phaseId,
|
|
219
229
|
"PHASE.md",
|
|
220
230
|
)
|
|
221
|
-
return
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
231
|
+
return yield* readDocument(
|
|
232
|
+
phaseId,
|
|
233
|
+
phasePath,
|
|
234
|
+
PhaseFrontmatter,
|
|
235
|
+
).pipe(
|
|
236
|
+
Effect.catchTag("FileNotFoundError", () =>
|
|
237
|
+
Effect.succeed(null),
|
|
238
|
+
),
|
|
239
|
+
)
|
|
228
240
|
}),
|
|
229
241
|
),
|
|
230
242
|
{ concurrency: "unbounded" },
|
|
@@ -271,11 +271,11 @@ export class WorkbaseService extends Effect.Service<WorkbaseService>()(
|
|
|
271
271
|
|
|
272
272
|
while (true) {
|
|
273
273
|
const configPath = join(current, "agency.json")
|
|
274
|
-
|
|
275
|
-
|
|
274
|
+
const content = yield* Effect.option(fs.readFile(configPath))
|
|
275
|
+
if (content._tag === "Some") {
|
|
276
276
|
let input: unknown
|
|
277
277
|
try {
|
|
278
|
-
input = JSON.parse(content)
|
|
278
|
+
input = JSON.parse(content.value)
|
|
279
279
|
} catch (cause) {
|
|
280
280
|
return yield* new WorkbaseConfigError({
|
|
281
281
|
path: configPath,
|
|
@@ -668,16 +668,15 @@ export class WorkbaseService extends Effect.Service<WorkbaseService>()(
|
|
|
668
668
|
}
|
|
669
669
|
|
|
670
670
|
const readDirectories = (path: string) =>
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
})
|
|
671
|
+
fs.readDirectory(path).pipe(
|
|
672
|
+
Effect.map((entries) =>
|
|
673
|
+
entries
|
|
674
|
+
.filter((entry) => entry.isDirectory)
|
|
675
|
+
.map((entry) => entry.name)
|
|
676
|
+
.sort(),
|
|
677
|
+
),
|
|
678
|
+
Effect.catchAll(() => Effect.succeed([])),
|
|
679
|
+
)
|
|
681
680
|
|
|
682
681
|
const aliases = new Set(yield* service.repositoryAliases(root))
|
|
683
682
|
|
|
@@ -686,14 +685,13 @@ export class WorkbaseService extends Effect.Service<WorkbaseService>()(
|
|
|
686
685
|
schema: S,
|
|
687
686
|
) =>
|
|
688
687
|
Effect.gen(function* () {
|
|
689
|
-
|
|
688
|
+
const content = yield* Effect.option(fs.readFile(path))
|
|
689
|
+
if (content._tag === "None") {
|
|
690
690
|
issue(path, "Required document is missing")
|
|
691
691
|
return null
|
|
692
692
|
}
|
|
693
|
-
|
|
694
|
-
const content = yield* fs.readFile(path)
|
|
695
693
|
const parsed = yield* Effect.either(
|
|
696
|
-
parseFrontmatter(content, path),
|
|
694
|
+
parseFrontmatter(content.value, path),
|
|
697
695
|
)
|
|
698
696
|
if (Either.isLeft(parsed)) {
|
|
699
697
|
issue(path, parsed.left.message)
|