@markjaquith/agency 2.74.0 → 3.0.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.
Files changed (57) hide show
  1. package/README.md +23 -121
  2. package/cli-main.ts +0 -26
  3. package/cli.ts +1 -17
  4. package/package.json +1 -2
  5. package/schemas/agency-graph-v1.schema.json +1 -1
  6. package/src/cli-parser.test.ts +0 -19
  7. package/src/cli-parser.ts +0 -23
  8. package/src/cli.test.ts +3 -3
  9. package/src/commands/context.test.ts +0 -67
  10. package/src/commands/init.test.ts +1 -2
  11. package/src/commands/pr.test.ts +2 -87
  12. package/src/commands/pr.ts +2 -79
  13. package/src/commands/push.test.ts +1 -2
  14. package/src/graph-schema.ts +1 -1
  15. package/src/services/ArchiveBulkService.test.ts +1 -142
  16. package/src/services/ArchiveService.test.ts +1 -172
  17. package/src/services/ArchiveService.ts +0 -26
  18. package/src/services/ContextService.ts +3 -47
  19. package/src/services/DoctorService.ts +8 -24
  20. package/src/services/GraphService.test.ts +1 -0
  21. package/src/services/GraphService.ts +2 -5
  22. package/src/services/PhaseService.ts +70 -191
  23. package/src/services/PullRequestService.test.ts +1 -45
  24. package/src/services/PullRequestService.ts +1 -22
  25. package/src/services/PushService.test.ts +29 -295
  26. package/src/services/PushService.ts +10 -239
  27. package/src/services/RepositoryService.test.ts +1 -61
  28. package/src/services/RepositoryService.ts +2 -13
  29. package/src/services/ReviewService.test.ts +1 -84
  30. package/src/services/ReviewService.ts +9 -48
  31. package/src/services/SyncService.test.ts +0 -81
  32. package/src/services/SyncService.ts +12 -39
  33. package/src/services/TaskPhaseService.test.ts +0 -80
  34. package/src/services/TaskService.ts +1 -9
  35. package/src/services/VersionControlService.test.ts +4 -117
  36. package/src/services/VersionControlService.ts +3 -426
  37. package/src/services/WorkbaseService.test.ts +0 -20
  38. package/src/services/WorkbaseService.ts +1 -18
  39. package/src/services/WorktreeService.test.ts +1 -705
  40. package/src/services/WorktreeService.ts +395 -1604
  41. package/src/services/push-validation.ts +0 -7
  42. package/src/test-utils.ts +0 -4
  43. package/src/workbase/AGENTS.md +4 -5
  44. package/src/workbase/checkout-command.test.ts +1 -1
  45. package/src/workbase/checkout-command.ts +1 -1
  46. package/src/workbase/delivery-command.test.ts +4 -35
  47. package/src/workbase/delivery-command.ts +2 -15
  48. package/src/workbase/schemas.test.ts +0 -19
  49. package/src/workbase/schemas.ts +1 -2
  50. package/src/commands/vcs.test.ts +0 -75
  51. package/src/commands/vcs.ts +0 -72
  52. package/src/services/VcsMigrationService.test.ts +0 -348
  53. package/src/services/VcsMigrationService.ts +0 -857
  54. package/src/vcs-status-fast.ts +0 -310
  55. package/src/workbase/version-control.ts +0 -5
  56. package/src/workbase/workspace-command.test.ts +0 -70
  57. package/src/workbase/workspace-command.ts +0 -63
@@ -1,12 +1,8 @@
1
1
  export interface PushCommitMetadata {
2
2
  readonly commitId: string
3
- readonly changeId?: string
4
3
  readonly description: string
5
- readonly empty: boolean
6
4
  readonly authorName: string
7
5
  readonly authorEmail: string
8
- readonly conflict: boolean
9
- readonly parents: readonly string[]
10
6
  }
11
7
 
12
8
  export const parseGitCommits = (
@@ -26,10 +22,7 @@ export const parseGitCommits = (
26
22
  return {
27
23
  commitId,
28
24
  description,
29
- empty: false,
30
25
  authorName,
31
26
  authorEmail,
32
- conflict: false,
33
- parents: [],
34
27
  }
35
28
  })
package/src/test-utils.ts CHANGED
@@ -24,10 +24,8 @@ import { DoctorService } from "./services/DoctorService"
24
24
  import { ReviewService } from "./services/ReviewService"
25
25
  import {
26
26
  GitVersionControlService,
27
- JjVersionControlService,
28
27
  VersionControlService,
29
28
  } from "./services/VersionControlService"
30
- import { VcsMigrationService } from "./services/VcsMigrationService"
31
29
 
32
30
  export const createTempDir = () => mkdtemp(join(tmpdir(), "agency-test-"))
33
31
 
@@ -38,9 +36,7 @@ const TestLayer = Layer.mergeAll(
38
36
  FileSystemService.Default,
39
37
  WorkbaseService.Default,
40
38
  GitVersionControlService.Default,
41
- JjVersionControlService.Default,
42
39
  VersionControlService.Default,
43
- VcsMigrationService.Default,
44
40
  RepositoryService.Default,
45
41
  EpicService.Default,
46
42
  TaskService.Default,
@@ -1,8 +1,8 @@
1
1
  # Agency Workbase
2
2
 
3
3
  This directory is an Agency workbase. Epics, tasks, and phases are durable
4
- Markdown documents; repository aliases and generated Git worktrees or jj
5
- workspaces provide code access according to the workbase's `vcs` setting.
4
+ Markdown documents; repository aliases and generated Git worktrees provide code
5
+ access.
6
6
 
7
7
  ## Command Fast Paths
8
8
 
@@ -184,9 +184,8 @@ repository's formatting, type checks, build, dead-code checks, and focused tests
184
184
  Review and commit the diff according to the repository's instructions.
185
185
 
186
186
  Use `agency push` from an execution task or phase to validate and publish its
187
- declared delivery branch or bookmark without creating a pull request. The
188
- command never authors semantic commit descriptions; resolve its reported change
189
- IDs and remediation commands before retrying.
187
+ declared delivery branch without creating a pull request. The command never authors semantic commit descriptions;
188
+ resolve its reported commits and remediation commands before retrying.
190
189
 
191
190
  `agency work` is the human launch flow: it reconciles managed integration,
192
191
  selects work, checks readiness, prepares checkouts, marks execution work
@@ -11,7 +11,7 @@ const variables = {
11
11
  checkoutKind: "reference" as const,
12
12
  requestedRef: "main",
13
13
  base: "",
14
- vcs: "jj" as const,
14
+ vcs: "git" as const,
15
15
  workbaseRoot: "/work",
16
16
  taskId: "example",
17
17
  phaseId: "",
@@ -5,7 +5,7 @@ export interface CheckoutCommandVariables {
5
5
  readonly checkoutKind: "writable" | "reference"
6
6
  readonly requestedRef: string
7
7
  readonly base: string
8
- readonly vcs: "git" | "jj"
8
+ readonly vcs: "git"
9
9
  readonly workbaseRoot: string
10
10
  readonly taskId: string
11
11
  readonly phaseId: string
@@ -32,45 +32,18 @@ describe("delivery commands", () => {
32
32
  })
33
33
  })
34
34
 
35
- test("adds explicit jj context to the default GitHub create command", () => {
35
+ test("builds the default GitHub create command", () => {
36
36
  const input = {
37
37
  base: "main",
38
- branch: "feat/example",
39
- repository: "example/agency",
40
38
  draft: false,
41
39
  } as const
42
- expect(
43
- resolveGitHubCreateCommand({
44
- ...input,
45
- vcs: "jj",
46
- defaults: { title: "Add example", body: "Details" },
47
- }),
48
- ).toEqual({
49
- argv: [
50
- "gh",
51
- "pr",
52
- "create",
53
- "--title",
54
- "Add example",
55
- "--body",
56
- "Details",
57
- "--base",
58
- "main",
59
- "--head",
60
- "feat/example",
61
- "--repo",
62
- "example/agency",
63
- ],
64
- environment: {},
65
- })
66
- expect(resolveGitHubCreateCommand({ ...input, vcs: "git" })).toEqual({
40
+ expect(resolveGitHubCreateCommand(input)).toEqual({
67
41
  argv: ["gh", "pr", "create", "--fill", "--base", "main"],
68
42
  environment: {},
69
43
  })
70
44
  expect(
71
45
  resolveGitHubCreateCommand({
72
46
  ...input,
73
- vcs: "git",
74
47
  head: "feat/example",
75
48
  }),
76
49
  ).toEqual({
@@ -89,9 +62,8 @@ describe("delivery commands", () => {
89
62
  expect(
90
63
  resolveGitHubCreateCommand({
91
64
  ...input,
92
- vcs: "jj",
93
- defaults: { title: "Generated", body: "Details" },
94
65
  title: "Requested",
66
+ head: "feat/example",
95
67
  labels: ["ai-assisted", "platform"],
96
68
  }),
97
69
  ).toEqual({
@@ -99,16 +71,13 @@ describe("delivery commands", () => {
99
71
  "gh",
100
72
  "pr",
101
73
  "create",
74
+ "--fill",
102
75
  "--title",
103
76
  "Requested",
104
- "--body",
105
- "Details",
106
77
  "--base",
107
78
  "main",
108
79
  "--head",
109
80
  "feat/example",
110
- "--repo",
111
- "example/agency",
112
81
  "--label",
113
82
  "ai-assisted",
114
83
  "--label",
@@ -20,21 +20,13 @@ export const repositoryFromRemote = (remote: string) =>
20
20
 
21
21
  export const resolveGitHubCreateCommand = ({
22
22
  base,
23
- branch,
24
- repository,
25
23
  draft,
26
- vcs,
27
- defaults,
28
24
  title,
29
25
  head,
30
26
  labels = [],
31
27
  }: {
32
28
  readonly base: string
33
- readonly branch: string
34
- readonly repository: string
35
29
  readonly draft: boolean
36
- readonly vcs: "git" | "jj"
37
- readonly defaults?: { readonly title: string; readonly body: string }
38
30
  readonly title?: string
39
31
  readonly head?: string
40
32
  readonly labels?: readonly string[]
@@ -43,15 +35,10 @@ export const resolveGitHubCreateCommand = ({
43
35
  "gh",
44
36
  "pr",
45
37
  "create",
46
- ...(defaults
47
- ? ["--title", title ?? defaults.title, "--body", defaults.body]
48
- : title
49
- ? ["--fill", "--title", title]
50
- : ["--fill"]),
38
+ ...(title ? ["--fill", "--title", title] : ["--fill"]),
51
39
  "--base",
52
40
  base,
53
- ...(vcs === "jj" || head ? ["--head", head ?? branch] : []),
54
- ...(vcs === "jj" ? ["--repo", repository] : []),
41
+ ...(head ? ["--head", head] : []),
55
42
  ...(draft ? ["--draft"] : []),
56
43
  ...labels.flatMap((label) => ["--label", label]),
57
44
  ],
@@ -257,25 +257,6 @@ describe("repository post-checkout configuration", () => {
257
257
  })
258
258
  })
259
259
 
260
- describe("workspace creation configuration", () => {
261
- test("accepts a jj workspace argv command", () => {
262
- const config = Schema.decodeUnknownSync(WorkbaseConfig)({
263
- version: 2,
264
- vcs: "jj",
265
- workspaceCreateCommand: [
266
- "prewarm",
267
- "adopt",
268
- "{repo}",
269
- "{workspace}",
270
- "{name}",
271
- "{revision}",
272
- ],
273
- })
274
-
275
- expect(config.workspaceCreateCommand?.[0]).toBe("prewarm")
276
- })
277
- })
278
-
279
260
  describe("agent configuration", () => {
280
261
  test("accepts named argv commands with resume commands and environment", () => {
281
262
  const config = Schema.decodeUnknownSync(WorkbaseConfig)({
@@ -103,13 +103,12 @@ const DeliveryProvider = Schema.Struct({
103
103
 
104
104
  export const WorkbaseConfig = Schema.Struct({
105
105
  version: Schema.Literal(2),
106
- vcs: Schema.optional(Schema.Literal("git", "jj")),
106
+ vcs: Schema.optional(Schema.Literal("git")),
107
107
  repositories: Schema.optional(
108
108
  Schema.Record({ key: RepositoryAlias, value: RepositoryDeclaration }),
109
109
  ),
110
110
  chooserCommand: Schema.optional(Schema.NonEmptyArray(NonEmptyString)),
111
111
  worktreeCreateCommand: Schema.optional(Schema.NonEmptyArray(NonEmptyString)),
112
- workspaceCreateCommand: Schema.optional(Schema.NonEmptyArray(NonEmptyString)),
113
112
  agents: Schema.optional(
114
113
  Schema.Record({
115
114
  key: EntityId,
@@ -1,75 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, test } from "bun:test"
2
- import {
3
- captureLogs,
4
- cleanupTempDir,
5
- createTempDir,
6
- runTestEffect,
7
- } from "../test-utils"
8
- import { vcs } from "./vcs"
9
-
10
- describe("vcs command", () => {
11
- let root: string
12
-
13
- beforeEach(async () => {
14
- root = await createTempDir()
15
- await Bun.write(
16
- `${root}/agency.json`,
17
- JSON.stringify({ version: 2, vcs: "git" }),
18
- )
19
- })
20
-
21
- afterEach(async () => cleanupTempDir(root))
22
-
23
- test("reports structured backend status", async () => {
24
- const logs = await captureLogs(() =>
25
- runTestEffect(vcs({ subcommand: "status", cwd: root, json: true })),
26
- )
27
- expect(JSON.parse(logs[0]!)).toMatchObject({
28
- root,
29
- configured: "git",
30
- source: "git",
31
- target: "git",
32
- workspaceCount: 0,
33
- blockers: [],
34
- })
35
- })
36
-
37
- test("persists the inferred Git backend for a legacy workbase", async () => {
38
- await Bun.write(`${root}/agency.json`, JSON.stringify({ version: 2 }))
39
- await captureLogs(() =>
40
- runTestEffect(
41
- vcs({
42
- subcommand: "migrate",
43
- target: "git",
44
- cwd: root,
45
- apply: true,
46
- json: true,
47
- }),
48
- ),
49
- )
50
- expect(await Bun.file(`${root}/agency.json`).json()).toEqual({
51
- version: 2,
52
- vcs: "git",
53
- })
54
- })
55
-
56
- test("treats migration to the configured backend as a no-op", async () => {
57
- const logs = await captureLogs(() =>
58
- runTestEffect(
59
- vcs({
60
- subcommand: "migrate",
61
- target: "git",
62
- cwd: root,
63
- apply: true,
64
- json: true,
65
- }),
66
- ),
67
- )
68
- expect(JSON.parse(logs[0]!)).toMatchObject({
69
- source: "git",
70
- target: "git",
71
- mode: "apply",
72
- actions: [],
73
- })
74
- })
75
- })
@@ -1,72 +0,0 @@
1
- import { Effect } from "effect"
2
- import { VcsMigrationService } from "../services/VcsMigrationService"
3
- import type { BaseCommandOptions } from "../utils/command"
4
- import { createLoggers } from "../utils/effect"
5
-
6
- interface VcsOptions extends BaseCommandOptions {
7
- readonly subcommand?: string
8
- readonly target?: string
9
- readonly apply?: boolean
10
- }
11
-
12
- export const vcs = (options: VcsOptions = {}) =>
13
- Effect.gen(function* () {
14
- const migrations = yield* VcsMigrationService
15
- const { log } = createLoggers(options)
16
- const root = options.cwd ?? process.cwd()
17
- if (options.subcommand === "status") {
18
- const status = yield* migrations.status(root)
19
- if (options.json) return log(JSON.stringify(status, null, 2))
20
- log(
21
- `Version control: ${status.source}${status.configured ? "" : " (inferred for legacy workbase)"}`,
22
- )
23
- log(
24
- `Tools: git=${status.available.git ? "available" : "missing"} jj=${status.available.jj ? "available" : "missing"}`,
25
- )
26
- log(
27
- `Repositories: ${status.repositories.length}; managed workspaces: ${status.workspaceCount}; blockers: ${status.blockers.length}`,
28
- )
29
- for (const blocker of status.blockers)
30
- log(`blocker ${blocker.kind} ${blocker.target}: ${blocker.message}`)
31
- return
32
- }
33
- if (options.subcommand === "migrate") {
34
- if (options.target !== "git" && options.target !== "jj") {
35
- return yield* Effect.fail(
36
- new Error("VCS migration target must be 'git' or 'jj'"),
37
- )
38
- }
39
- const result = yield* migrations.migrate(options.target, root, {
40
- apply: options.apply,
41
- })
42
- if (options.json) return log(JSON.stringify(result, null, 2))
43
- log(
44
- result.mode === "apply"
45
- ? `Migrated workbase to ${options.target}`
46
- : `Migration plan: ${result.source} -> ${options.target}`,
47
- )
48
- for (const action of result.actions) log(`- ${action}`)
49
- if (result.mode === "dry-run" && result.actions.length > 0)
50
- log("Run again with --apply to perform the migration.")
51
- return
52
- }
53
- return yield* Effect.fail(
54
- new Error(`Unknown vcs subcommand '${options.subcommand ?? ""}'`),
55
- )
56
- })
57
-
58
- export const help = `
59
- Usage: agency vcs <status|migrate>
60
-
61
- Inspect or migrate the workbase-wide version-control backend.
62
-
63
- Commands:
64
- status Show the configured backend, tools, repositories, and blockers
65
- migrate <git|jj> [--dry-run | --apply]
66
- Preview or apply a clean, transactional backend migration
67
-
68
- Options:
69
- --apply Apply the migration; omission performs a dry run
70
- --dry-run Explicitly preview the migration without applying it
71
- --json Print structured output
72
- `