@markjaquith/agency 1.11.0 → 2.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 (130) hide show
  1. package/README.md +302 -113
  2. package/cli.ts +123 -415
  3. package/index.ts +1 -1
  4. package/package.json +12 -17
  5. package/skills/agency/SKILL.md +258 -0
  6. package/src/cli.test.ts +290 -0
  7. package/src/commands/description.test.ts +103 -0
  8. package/src/commands/epic.test.ts +103 -0
  9. package/src/commands/epic.ts +101 -0
  10. package/src/commands/init.test.ts +42 -290
  11. package/src/commands/init.ts +15 -123
  12. package/src/commands/phase.ts +120 -0
  13. package/src/commands/pr.test.ts +19 -170
  14. package/src/commands/pr.ts +23 -179
  15. package/src/commands/repo.test.ts +80 -0
  16. package/src/commands/repo.ts +83 -0
  17. package/src/commands/status.test.ts +35 -477
  18. package/src/commands/status.ts +24 -213
  19. package/src/commands/task-phase.test.ts +206 -0
  20. package/src/commands/task.ts +83 -1285
  21. package/src/commands/validate.test.ts +91 -0
  22. package/src/commands/validate.ts +50 -0
  23. package/src/commands/work.test.ts +172 -419
  24. package/src/commands/work.ts +47 -166
  25. package/src/services/EpicService.test.ts +71 -0
  26. package/src/services/EpicService.ts +135 -0
  27. package/src/services/FileSystemService.ts +61 -92
  28. package/src/services/PhaseService.ts +323 -0
  29. package/src/services/PullRequestService.test.ts +386 -0
  30. package/src/services/PullRequestService.ts +143 -0
  31. package/src/services/RepositoryService.test.ts +106 -0
  32. package/src/services/RepositoryService.ts +159 -0
  33. package/src/services/TaskPhaseService.test.ts +217 -0
  34. package/src/services/TaskService.ts +192 -0
  35. package/src/services/WorkbaseService.test.ts +446 -0
  36. package/src/services/WorkbaseService.ts +493 -0
  37. package/src/services/WorktreeService.test.ts +599 -0
  38. package/src/services/WorktreeService.ts +357 -0
  39. package/src/test-utils.ts +41 -438
  40. package/src/types.ts +1 -215
  41. package/src/utils/command.ts +1 -5
  42. package/src/utils/effect.test.ts +24 -0
  43. package/src/utils/effect.ts +3 -273
  44. package/src/utils/process.test.ts +0 -15
  45. package/src/utils/process.ts +1 -60
  46. package/src/workbase/frontmatter.test.ts +50 -0
  47. package/src/workbase/frontmatter.ts +77 -0
  48. package/src/workbase/repository-reference.test.ts +25 -0
  49. package/src/workbase/repository-reference.ts +18 -0
  50. package/src/workbase/schemas.test.ts +146 -0
  51. package/src/workbase/schemas.ts +78 -0
  52. package/src/workbase/worktree-command.test.ts +61 -0
  53. package/src/workbase/worktree-command.ts +52 -0
  54. package/src/commands/base.test.ts +0 -198
  55. package/src/commands/base.ts +0 -198
  56. package/src/commands/clean.test.ts +0 -299
  57. package/src/commands/clean.ts +0 -274
  58. package/src/commands/completions.test.ts +0 -51
  59. package/src/commands/completions.ts +0 -308
  60. package/src/commands/emit.integration.test.ts +0 -549
  61. package/src/commands/emit.test.ts +0 -576
  62. package/src/commands/emit.ts +0 -700
  63. package/src/commands/emitted.test.ts +0 -226
  64. package/src/commands/emitted.ts +0 -57
  65. package/src/commands/loop.test.ts +0 -621
  66. package/src/commands/loop.ts +0 -406
  67. package/src/commands/merge.integration.test.ts +0 -195
  68. package/src/commands/merge.test.ts +0 -246
  69. package/src/commands/merge.ts +0 -244
  70. package/src/commands/pull.test.ts +0 -395
  71. package/src/commands/pull.ts +0 -205
  72. package/src/commands/push.test.ts +0 -518
  73. package/src/commands/push.ts +0 -434
  74. package/src/commands/rebase.test.ts +0 -521
  75. package/src/commands/rebase.ts +0 -232
  76. package/src/commands/save.test.ts +0 -247
  77. package/src/commands/save.ts +0 -162
  78. package/src/commands/source.test.ts +0 -195
  79. package/src/commands/source.ts +0 -72
  80. package/src/commands/switch.test.ts +0 -194
  81. package/src/commands/switch.ts +0 -84
  82. package/src/commands/task-branching.test.ts +0 -633
  83. package/src/commands/task-continue.test.ts +0 -311
  84. package/src/commands/task-edit.test.ts +0 -235
  85. package/src/commands/task-main.test.ts +0 -1066
  86. package/src/commands/task-squash.test.ts +0 -266
  87. package/src/commands/tasks.test.ts +0 -391
  88. package/src/commands/tasks.ts +0 -161
  89. package/src/commands/template-delete.test.ts +0 -178
  90. package/src/commands/template-delete.ts +0 -98
  91. package/src/commands/template-list.test.ts +0 -135
  92. package/src/commands/template-list.ts +0 -87
  93. package/src/commands/template-view.test.ts +0 -158
  94. package/src/commands/template-view.ts +0 -86
  95. package/src/commands/template.test.ts +0 -32
  96. package/src/commands/template.ts +0 -96
  97. package/src/commands/use.test.ts +0 -87
  98. package/src/commands/use.ts +0 -97
  99. package/src/constants.ts +0 -10
  100. package/src/errors.ts +0 -17
  101. package/src/schemas.ts +0 -33
  102. package/src/services/AgencyMetadataService.ts +0 -311
  103. package/src/services/ClaudeService.test.ts +0 -184
  104. package/src/services/ClaudeService.ts +0 -91
  105. package/src/services/ConfigService.ts +0 -115
  106. package/src/services/FilterRepoService.ts +0 -164
  107. package/src/services/FormatterService.test.ts +0 -432
  108. package/src/services/FormatterService.ts +0 -219
  109. package/src/services/GitService.ts +0 -1183
  110. package/src/services/MockFilterRepoService.ts +0 -140
  111. package/src/services/OpencodeService.ts +0 -263
  112. package/src/services/PromptService.ts +0 -183
  113. package/src/services/TemplateService.ts +0 -81
  114. package/src/types/native-exec.d.ts +0 -8
  115. package/src/utils/colors.ts +0 -178
  116. package/src/utils/git-path.ts +0 -6
  117. package/src/utils/glob.test.ts +0 -161
  118. package/src/utils/glob.ts +0 -78
  119. package/src/utils/paths.ts +0 -51
  120. package/src/utils/pr-branch.test.ts +0 -376
  121. package/src/utils/pr-branch.ts +0 -508
  122. package/src/utils/spinner.test.ts +0 -45
  123. package/src/utils/spinner.ts +0 -96
  124. package/src/utils/task-parser.test.ts +0 -172
  125. package/src/utils/task-parser.ts +0 -93
  126. package/templates/AGENCY.md +0 -22
  127. package/templates/AGENTS.md +0 -11
  128. package/templates/CLAUDE.md +0 -3
  129. package/templates/TASK.md +0 -5
  130. package/templates/opencode.json +0 -4
@@ -1,195 +0,0 @@
1
- import { test, expect, describe, beforeEach, afterEach } from "bun:test"
2
- import { join } from "path"
3
- import { source } from "./source"
4
- import {
5
- createTempDir,
6
- cleanupTempDir,
7
- initGitRepo,
8
- getCurrentBranch,
9
- createCommit,
10
- runTestEffect,
11
- } from "../test-utils"
12
- import { writeAgencyMetadata } from "../types"
13
-
14
- async function createBranch(cwd: string, branchName: string): Promise<void> {
15
- await Bun.spawn(["git", "checkout", "-b", branchName], {
16
- cwd,
17
- stdout: "pipe",
18
- stderr: "pipe",
19
- }).exited
20
- }
21
-
22
- describe("source command", () => {
23
- let tempDir: string
24
- let originalCwd: string
25
-
26
- beforeEach(async () => {
27
- tempDir = await createTempDir()
28
- originalCwd = process.cwd()
29
- process.chdir(tempDir)
30
-
31
- // Set config path to non-existent file to use defaults
32
- process.env.AGENCY_CONFIG_PATH = join(tempDir, "non-existent-config.json")
33
-
34
- // Initialize git repo
35
- await initGitRepo(tempDir)
36
- await createCommit(tempDir, "Initial commit")
37
-
38
- // Rename to main if needed
39
- const currentBranch = await getCurrentBranch(tempDir)
40
- if (currentBranch === "master") {
41
- await Bun.spawn(["git", "branch", "-m", "main"], {
42
- cwd: tempDir,
43
- stdout: "pipe",
44
- stderr: "pipe",
45
- }).exited
46
- }
47
- })
48
-
49
- afterEach(async () => {
50
- process.chdir(originalCwd)
51
- delete process.env.AGENCY_CONFIG_PATH
52
- await cleanupTempDir(tempDir)
53
- })
54
-
55
- describe("basic functionality", () => {
56
- test("switches from emit branch to source branch", async () => {
57
- // Create source branch with agency.json
58
- await createBranch(tempDir, "agency--feature")
59
- await writeAgencyMetadata(tempDir, {
60
- version: 1,
61
- injectedFiles: [],
62
- template: "test-template",
63
- emitBranch: "feature",
64
- createdAt: new Date().toISOString(),
65
- } as any)
66
- // Stage and commit agency.json
67
- await Bun.spawn(["git", "add", "agency.json"], {
68
- cwd: tempDir,
69
- stdout: "pipe",
70
- stderr: "pipe",
71
- }).exited
72
- await createCommit(tempDir, "Setup")
73
-
74
- // Create emit branch and remove agency.json
75
- await createBranch(tempDir, "feature")
76
- await Bun.spawn(["rm", "agency.json"], {
77
- cwd: tempDir,
78
- stdout: "pipe",
79
- stderr: "pipe",
80
- }).exited
81
-
82
- // Run source command (should switch from feature emit branch to agency--feature source)
83
- await runTestEffect(source({ silent: true }))
84
-
85
- // Should be on agency--feature now
86
- const currentBranch = await getCurrentBranch(tempDir)
87
- expect(currentBranch).toBe("agency--feature")
88
- })
89
-
90
- test("works with custom emit branch pattern", async () => {
91
- // Create custom config with custom patterns
92
- const configPath = join(tempDir, "custom-config.json")
93
- await Bun.write(
94
- configPath,
95
- JSON.stringify({
96
- sourceBranchPattern: "WIP--%branch%",
97
- emitBranch: "PR--%branch%",
98
- }),
99
- )
100
- process.env.AGENCY_CONFIG_PATH = configPath
101
-
102
- // Create source branch with agency.json
103
- await createBranch(tempDir, "WIP--feature")
104
- await writeAgencyMetadata(tempDir, {
105
- version: 1,
106
- injectedFiles: [],
107
- template: "test-template",
108
- emitBranch: "PR--feature",
109
- createdAt: new Date().toISOString(),
110
- } as any)
111
- // Stage and commit
112
- await Bun.spawn(["git", "add", "agency.json"], {
113
- cwd: tempDir,
114
- stdout: "pipe",
115
- stderr: "pipe",
116
- }).exited
117
- await createCommit(tempDir, "Feature work")
118
-
119
- // Create emit branch
120
- await createBranch(tempDir, "PR--feature")
121
- await Bun.spawn(["rm", "agency.json"], {
122
- cwd: tempDir,
123
- stdout: "pipe",
124
- stderr: "pipe",
125
- }).exited
126
-
127
- // Run source command (from PR--feature to WIP--feature)
128
- await runTestEffect(source({ silent: true }))
129
-
130
- // Should be on WIP--feature now
131
- const currentBranch = await getCurrentBranch(tempDir)
132
- expect(currentBranch).toBe("WIP--feature")
133
- })
134
- })
135
-
136
- describe("error handling", () => {
137
- test("throws error when not on an emit branch", async () => {
138
- // We're on main, which is not an emit branch
139
- await expect(runTestEffect(source({ silent: true }))).rejects.toThrow(
140
- "Not on an emit branch",
141
- )
142
- })
143
-
144
- test("throws error when not in a git repository", async () => {
145
- const nonGitDir = await createTempDir()
146
- process.chdir(nonGitDir)
147
-
148
- await expect(runTestEffect(source({ silent: true }))).rejects.toThrow(
149
- "Not in a git repository",
150
- )
151
-
152
- await cleanupTempDir(nonGitDir)
153
- })
154
- })
155
-
156
- describe("silent mode", () => {
157
- test("silent flag suppresses output", async () => {
158
- // Create source branch with agency.json
159
- await createBranch(tempDir, "agency--feature")
160
- await writeAgencyMetadata(tempDir, {
161
- version: 1,
162
- injectedFiles: [],
163
- template: "test-template",
164
- emitBranch: "feature",
165
- createdAt: new Date().toISOString(),
166
- } as any)
167
- await Bun.spawn(["git", "add", "agency.json"], {
168
- cwd: tempDir,
169
- stdout: "pipe",
170
- stderr: "pipe",
171
- }).exited
172
- await createCommit(tempDir, "Setup")
173
-
174
- // Create emit branch
175
- await createBranch(tempDir, "feature")
176
- await Bun.spawn(["rm", "agency.json"], {
177
- cwd: tempDir,
178
- stdout: "pipe",
179
- stderr: "pipe",
180
- }).exited
181
-
182
- // Capture output
183
- const originalLog = console.log
184
- let logCalled = false
185
- console.log = () => {
186
- logCalled = true
187
- }
188
-
189
- await runTestEffect(source({ silent: true }))
190
-
191
- console.log = originalLog
192
- expect(logCalled).toBe(false)
193
- })
194
- })
195
- })
@@ -1,72 +0,0 @@
1
- import { Effect } from "effect"
2
- import type { BaseCommandOptions } from "../utils/command"
3
- import { GitService } from "../services/GitService"
4
- import { ConfigService } from "../services/ConfigService"
5
- import { FileSystemService } from "../services/FileSystemService"
6
- import { resolveBranchPairWithAgencyJson } from "../utils/pr-branch"
7
- import highlight, { done } from "../utils/colors"
8
- import {
9
- createLoggers,
10
- ensureGitRepo,
11
- ensureBranchExists,
12
- } from "../utils/effect"
13
-
14
- interface SourceOptions extends BaseCommandOptions {}
15
-
16
- export const source = (options: SourceOptions = {}) =>
17
- Effect.gen(function* () {
18
- const { log } = createLoggers(options)
19
-
20
- const git = yield* GitService
21
- const configService = yield* ConfigService
22
-
23
- const gitRoot = yield* ensureGitRepo()
24
-
25
- // Load config
26
- const config = yield* configService.loadConfig()
27
-
28
- // Get current branch and resolve the branch pair
29
- const currentBranch = yield* git.getCurrentBranch(gitRoot)
30
- const { sourceBranch, isOnEmitBranch } =
31
- yield* resolveBranchPairWithAgencyJson(
32
- gitRoot,
33
- currentBranch,
34
- config.sourceBranchPattern,
35
- config.emitBranch,
36
- )
37
-
38
- if (!isOnEmitBranch) {
39
- return yield* Effect.fail(
40
- new Error(`Not on an emit branch. Current branch: ${currentBranch}`),
41
- )
42
- }
43
-
44
- // Check if source branch exists
45
- yield* ensureBranchExists(
46
- gitRoot,
47
- sourceBranch,
48
- `Source branch ${highlight.branch(sourceBranch)} does not exist`,
49
- )
50
-
51
- // Checkout source branch
52
- yield* git.checkoutBranch(gitRoot, sourceBranch)
53
-
54
- log(done(`Switched to source branch: ${highlight.branch(sourceBranch)}`))
55
- })
56
-
57
- export const help = `
58
- Usage: agency source [options]
59
-
60
- Switch back to the source branch from an emit branch.
61
-
62
- This command extracts the source branch name from your current emit branch name
63
- using the configured pattern, and switches back to it.
64
-
65
- Example:
66
- agency source # From main--PR, switch to main
67
-
68
- Notes:
69
- - Must be run from an emit branch
70
- - Source branch must exist
71
- - Uses emit branch pattern from ~/.config/agency/agency.json
72
- `
@@ -1,194 +0,0 @@
1
- import { test, expect, describe, beforeEach, afterEach } from "bun:test"
2
- import { join } from "path"
3
- import { switchBranch } from "./switch"
4
- import {
5
- createTempDir,
6
- cleanupTempDir,
7
- initGitRepo,
8
- getGitOutput,
9
- getCurrentBranch,
10
- createCommit,
11
- checkoutBranch,
12
- runTestEffect,
13
- } from "../test-utils"
14
-
15
- async function createBranch(cwd: string, branchName: string): Promise<void> {
16
- await Bun.spawn(["git", "checkout", "-b", branchName], {
17
- cwd,
18
- stdout: "pipe",
19
- stderr: "pipe",
20
- }).exited
21
- }
22
-
23
- describe("switch command", () => {
24
- let tempDir: string
25
- let originalCwd: string
26
-
27
- beforeEach(async () => {
28
- tempDir = await createTempDir()
29
- originalCwd = process.cwd()
30
- process.chdir(tempDir)
31
-
32
- // Set config path to non-existent file to use defaults
33
- process.env.AGENCY_CONFIG_PATH = join(tempDir, "non-existent-config.json")
34
-
35
- // Initialize git repo
36
- await initGitRepo(tempDir)
37
- await createCommit(tempDir, "Initial commit")
38
-
39
- // Rename to main if needed
40
- const currentBranch = await getCurrentBranch(tempDir)
41
- if (currentBranch === "master") {
42
- await Bun.spawn(["git", "branch", "-m", "main"], {
43
- cwd: tempDir,
44
- stdout: "pipe",
45
- stderr: "pipe",
46
- }).exited
47
- }
48
- })
49
-
50
- afterEach(async () => {
51
- process.chdir(originalCwd)
52
- delete process.env.AGENCY_CONFIG_PATH
53
- await cleanupTempDir(tempDir)
54
- })
55
-
56
- describe("basic functionality", () => {
57
- test("switches from emit branch to source branch", async () => {
58
- // Create source and emit branches (source=agency--main, emit=main)
59
- await createBranch(tempDir, "agency--main")
60
- await createCommit(tempDir, "Work on source")
61
- // Emit branch is just "main" (already exists from setup)
62
- await checkoutBranch(tempDir, "main")
63
-
64
- // Run switch command
65
- await runTestEffect(switchBranch({ silent: true }))
66
-
67
- // Should be on source branch now
68
- const currentBranch = await getCurrentBranch(tempDir)
69
- expect(currentBranch).toBe("agency--main")
70
- })
71
-
72
- test("switches from source branch to emit branch", async () => {
73
- // Create source branch (main becomes the emit branch)
74
- await createBranch(tempDir, "agency--main")
75
- await createCommit(tempDir, "Work on source")
76
-
77
- // We're on agency--main (source), switch to main (emit)
78
- // Run switch command
79
- await runTestEffect(switchBranch({ silent: true }))
80
-
81
- // Should be on emit branch now
82
- const currentBranch = await getCurrentBranch(tempDir)
83
- expect(currentBranch).toBe("main")
84
- })
85
-
86
- test("toggles back and forth", async () => {
87
- // Create source and emit branches
88
- await createBranch(tempDir, "agency--main")
89
- await createCommit(tempDir, "Work on source")
90
- await checkoutBranch(tempDir, "main") // Go to emit
91
-
92
- // Switch to source
93
- await runTestEffect(switchBranch({ silent: true }))
94
- expect(await getCurrentBranch(tempDir)).toBe("agency--main")
95
-
96
- // Switch back to emit
97
- await runTestEffect(switchBranch({ silent: true }))
98
- expect(await getCurrentBranch(tempDir)).toBe("main")
99
-
100
- // And back to source
101
- await runTestEffect(switchBranch({ silent: true }))
102
- expect(await getCurrentBranch(tempDir)).toBe("agency--main")
103
- })
104
-
105
- test("works with custom emit branch pattern", async () => {
106
- // Create custom config
107
- const configPath = join(tempDir, "custom-config.json")
108
- await Bun.write(
109
- configPath,
110
- JSON.stringify({
111
- sourceBranchPattern: "agency--%branch%",
112
- emitBranch: "PR--%branch%",
113
- }),
114
- )
115
- process.env.AGENCY_CONFIG_PATH = configPath
116
-
117
- // Create source branch and its emit branch
118
- await createBranch(tempDir, "agency--feature")
119
- await createCommit(tempDir, "Feature work")
120
- await createBranch(tempDir, "PR--feature")
121
-
122
- // Switch to source
123
- await runTestEffect(switchBranch({ silent: true }))
124
- expect(await getCurrentBranch(tempDir)).toBe("agency--feature")
125
-
126
- // Switch back to emit
127
- await runTestEffect(switchBranch({ silent: true }))
128
- expect(await getCurrentBranch(tempDir)).toBe("PR--feature")
129
- })
130
- })
131
-
132
- describe("error handling", () => {
133
- test("throws error when emit branch doesn't exist", async () => {
134
- // Use custom emit pattern so emit branch differs from source
135
- const configPath = join(tempDir, "custom-config.json")
136
- await Bun.write(
137
- configPath,
138
- JSON.stringify({
139
- sourceBranchPattern: "agency--%branch%",
140
- emitBranch: "%branch%--PR",
141
- }),
142
- )
143
- process.env.AGENCY_CONFIG_PATH = configPath
144
-
145
- // Create source branch, but not the emit branch
146
- await createBranch(tempDir, "agency--feature")
147
- // feature--PR doesn't exist
148
-
149
- await expect(
150
- runTestEffect(switchBranch({ silent: true })),
151
- ).rejects.toThrow(/Emit branch .* does not exist/)
152
- })
153
-
154
- test("throws error when emit branch doesn't exist", async () => {
155
- // Create source branch but no emit branch
156
- await createBranch(tempDir, "agency--feature")
157
- // We never created 'feature' (emit), so it doesn't exist
158
-
159
- await expect(
160
- runTestEffect(switchBranch({ silent: true })),
161
- ).rejects.toThrow(/Emit branch .* does not exist/)
162
- })
163
-
164
- test("throws error when not in a git repository", async () => {
165
- const nonGitDir = await createTempDir()
166
- process.chdir(nonGitDir)
167
-
168
- await expect(
169
- runTestEffect(switchBranch({ silent: true })),
170
- ).rejects.toThrow("Not in a git repository")
171
-
172
- await cleanupTempDir(nonGitDir)
173
- })
174
- })
175
-
176
- describe("silent mode", () => {
177
- test("silent flag suppresses output", async () => {
178
- await createBranch(tempDir, "agency--main")
179
- await checkoutBranch(tempDir, "main")
180
-
181
- // Capture output
182
- const originalLog = console.log
183
- let logCalled = false
184
- console.log = () => {
185
- logCalled = true
186
- }
187
-
188
- await runTestEffect(switchBranch({ silent: true }))
189
-
190
- console.log = originalLog
191
- expect(logCalled).toBe(false)
192
- })
193
- })
194
- })
@@ -1,84 +0,0 @@
1
- import { Effect } from "effect"
2
- import type { BaseCommandOptions } from "../utils/command"
3
- import { GitService } from "../services/GitService"
4
- import { ConfigService } from "../services/ConfigService"
5
- import {
6
- resolveBranchPairWithAgencyJson,
7
- type BranchPair,
8
- } from "../utils/pr-branch"
9
- import highlight, { done } from "../utils/colors"
10
- import {
11
- createLoggers,
12
- ensureGitRepo,
13
- ensureBranchExists,
14
- } from "../utils/effect"
15
-
16
- interface SwitchOptions extends BaseCommandOptions {}
17
-
18
- export const switchBranch = (options: SwitchOptions = {}) =>
19
- Effect.gen(function* () {
20
- const { log } = createLoggers(options)
21
-
22
- const git = yield* GitService
23
- const configService = yield* ConfigService
24
-
25
- const gitRoot = yield* ensureGitRepo()
26
-
27
- // Load config
28
- const config = yield* configService.loadConfig()
29
-
30
- // Get current branch and resolve the branch pair
31
- const currentBranch = yield* git.getCurrentBranch(gitRoot)
32
- const branches: BranchPair = yield* resolveBranchPairWithAgencyJson(
33
- gitRoot,
34
- currentBranch,
35
- config.sourceBranchPattern,
36
- config.emitBranch,
37
- )
38
- const { sourceBranch, emitBranch, isOnEmitBranch } = branches
39
-
40
- if (isOnEmitBranch) {
41
- // We're on an emit branch, switch to source
42
- yield* ensureBranchExists(
43
- gitRoot,
44
- sourceBranch,
45
- `Source branch ${highlight.branch(sourceBranch)} does not exist`,
46
- )
47
-
48
- yield* git.checkoutBranch(gitRoot, sourceBranch)
49
- log(done(`Switched to source branch: ${highlight.branch(sourceBranch)}`))
50
- } else {
51
- // We're on a source branch, switch to emit branch
52
- yield* ensureBranchExists(
53
- gitRoot,
54
- emitBranch,
55
- `Emit branch ${highlight.branch(emitBranch)} does not exist. Run 'agency emit' to create it.`,
56
- )
57
-
58
- yield* git.checkoutBranch(gitRoot, emitBranch)
59
- log(done(`Switched to ${highlight.branch(emitBranch)}`))
60
- }
61
- })
62
-
63
- export const help = `
64
- Usage: agency switch [options]
65
-
66
- Toggle between source branch and emit branch.
67
-
68
- Source and Emit Branches:
69
- - Source branches: Your working branches with agency-specific files (e.g., agency--main)
70
- - Emit branches: Clean branches suitable for PRs without agency files (e.g., main)
71
-
72
- This command intelligently switches between your source branch and its
73
- corresponding emit branch:
74
- - If on an emit branch (e.g., main), switches to source (agency--main)
75
- - If on a source branch (e.g., agency--main), switches to emit branch (main)
76
-
77
- Example:
78
- agency switch # Toggle between branches
79
-
80
- Notes:
81
- - Target branch must exist
82
- - Uses source and emit patterns from ~/.config/agency/agency.json
83
- - If emit branch doesn't exist, run 'agency emit' to create it
84
- `