@markjaquith/agency 1.11.1 → 2.1.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 (132) hide show
  1. package/README.md +313 -117
  2. package/cli.ts +124 -420
  3. package/index.ts +1 -1
  4. package/package.json +12 -17
  5. package/skills/agency/SKILL.md +266 -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 +326 -399
  24. package/src/commands/work.ts +153 -153
  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/work-target.test.ts +77 -0
  53. package/src/workbase/work-target.ts +180 -0
  54. package/src/workbase/worktree-command.test.ts +61 -0
  55. package/src/workbase/worktree-command.ts +52 -0
  56. package/src/commands/base.test.ts +0 -198
  57. package/src/commands/base.ts +0 -198
  58. package/src/commands/clean.test.ts +0 -299
  59. package/src/commands/clean.ts +0 -274
  60. package/src/commands/completions.test.ts +0 -51
  61. package/src/commands/completions.ts +0 -308
  62. package/src/commands/emit.integration.test.ts +0 -549
  63. package/src/commands/emit.test.ts +0 -576
  64. package/src/commands/emit.ts +0 -700
  65. package/src/commands/emitted.test.ts +0 -226
  66. package/src/commands/emitted.ts +0 -57
  67. package/src/commands/loop.test.ts +0 -621
  68. package/src/commands/loop.ts +0 -406
  69. package/src/commands/merge.integration.test.ts +0 -195
  70. package/src/commands/merge.test.ts +0 -246
  71. package/src/commands/merge.ts +0 -244
  72. package/src/commands/pull.test.ts +0 -395
  73. package/src/commands/pull.ts +0 -205
  74. package/src/commands/push.test.ts +0 -641
  75. package/src/commands/push.ts +0 -482
  76. package/src/commands/rebase.test.ts +0 -521
  77. package/src/commands/rebase.ts +0 -232
  78. package/src/commands/save.test.ts +0 -247
  79. package/src/commands/save.ts +0 -162
  80. package/src/commands/source.test.ts +0 -195
  81. package/src/commands/source.ts +0 -72
  82. package/src/commands/switch.test.ts +0 -194
  83. package/src/commands/switch.ts +0 -84
  84. package/src/commands/task-branching.test.ts +0 -633
  85. package/src/commands/task-continue.test.ts +0 -311
  86. package/src/commands/task-edit.test.ts +0 -235
  87. package/src/commands/task-main.test.ts +0 -1066
  88. package/src/commands/task-squash.test.ts +0 -266
  89. package/src/commands/tasks.test.ts +0 -391
  90. package/src/commands/tasks.ts +0 -161
  91. package/src/commands/template-delete.test.ts +0 -178
  92. package/src/commands/template-delete.ts +0 -98
  93. package/src/commands/template-list.test.ts +0 -135
  94. package/src/commands/template-list.ts +0 -87
  95. package/src/commands/template-view.test.ts +0 -158
  96. package/src/commands/template-view.ts +0 -86
  97. package/src/commands/template.test.ts +0 -32
  98. package/src/commands/template.ts +0 -96
  99. package/src/commands/use.test.ts +0 -87
  100. package/src/commands/use.ts +0 -97
  101. package/src/constants.ts +0 -10
  102. package/src/errors.ts +0 -17
  103. package/src/schemas.ts +0 -33
  104. package/src/services/AgencyMetadataService.ts +0 -311
  105. package/src/services/ClaudeService.test.ts +0 -184
  106. package/src/services/ClaudeService.ts +0 -91
  107. package/src/services/ConfigService.ts +0 -115
  108. package/src/services/FilterRepoService.ts +0 -164
  109. package/src/services/FormatterService.test.ts +0 -432
  110. package/src/services/FormatterService.ts +0 -219
  111. package/src/services/GitService.ts +0 -1187
  112. package/src/services/MockFilterRepoService.ts +0 -140
  113. package/src/services/OpencodeService.ts +0 -263
  114. package/src/services/PromptService.ts +0 -183
  115. package/src/services/TemplateService.ts +0 -81
  116. package/src/types/native-exec.d.ts +0 -8
  117. package/src/utils/colors.ts +0 -178
  118. package/src/utils/git-path.ts +0 -6
  119. package/src/utils/glob.test.ts +0 -161
  120. package/src/utils/glob.ts +0 -78
  121. package/src/utils/paths.ts +0 -51
  122. package/src/utils/pr-branch.test.ts +0 -376
  123. package/src/utils/pr-branch.ts +0 -508
  124. package/src/utils/spinner.test.ts +0 -45
  125. package/src/utils/spinner.ts +0 -96
  126. package/src/utils/task-parser.test.ts +0 -172
  127. package/src/utils/task-parser.ts +0 -93
  128. package/templates/AGENCY.md +0 -22
  129. package/templates/AGENTS.md +0 -11
  130. package/templates/CLAUDE.md +0 -3
  131. package/templates/TASK.md +0 -5
  132. package/templates/opencode.json +0 -4
@@ -1,246 +0,0 @@
1
- import { test, expect, describe, beforeEach, afterEach } from "bun:test"
2
- import { join } from "path"
3
- import { merge } from "./merge"
4
- import { emit } from "./emit"
5
- import { task } from "./task"
6
- import {
7
- createTempDir,
8
- cleanupTempDir,
9
- initGitRepo,
10
- initAgency,
11
- getGitOutput,
12
- getCurrentBranch,
13
- createCommit,
14
- checkoutBranch,
15
- createBranch,
16
- addAndCommit,
17
- setupRemote,
18
- deleteBranch,
19
- runTestEffect,
20
- } from "../test-utils"
21
-
22
- describe("merge 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
- // Set config dir to temp dir to avoid picking up user's config files
34
- process.env.AGENCY_CONFIG_DIR = await createTempDir()
35
-
36
- // Initialize git repo with main branch (already includes initial commit)
37
- await initGitRepo(tempDir)
38
-
39
- // Set up origin for git-filter-repo
40
- await setupRemote(tempDir, "origin", tempDir)
41
-
42
- // Create a source branch (with agency-- prefix per new default config)
43
- await createBranch(tempDir, "agency--feature")
44
-
45
- // Initialize AGENTS.md on feature branch
46
- await initAgency(tempDir, "test")
47
-
48
- await runTestEffect(task({ silent: true, fromCurrent: true }))
49
-
50
- // Ensure agency.json has baseBranch set (task should auto-detect it, but ensure it's there)
51
- const agencyJsonPath = join(tempDir, "agency.json")
52
- const agencyJson = await Bun.file(agencyJsonPath).json()
53
- if (!agencyJson.baseBranch) {
54
- agencyJson.baseBranch = "origin/main"
55
- await Bun.write(
56
- agencyJsonPath,
57
- JSON.stringify(agencyJson, null, 2) + "\n",
58
- )
59
- }
60
-
61
- await addAndCommit(tempDir, "AGENTS.md agency.json", "Add AGENTS.md")
62
-
63
- // Create another commit on feature branch
64
- await createCommit(tempDir, "Feature work")
65
- })
66
-
67
- afterEach(async () => {
68
- process.chdir(originalCwd)
69
- delete process.env.AGENCY_CONFIG_PATH
70
- if (process.env.AGENCY_CONFIG_DIR) {
71
- await cleanupTempDir(process.env.AGENCY_CONFIG_DIR)
72
- delete process.env.AGENCY_CONFIG_DIR
73
- }
74
- await cleanupTempDir(tempDir)
75
- })
76
-
77
- describe("error handling", () => {
78
- test("throws error when not in a git repository", async () => {
79
- const nonGitDir = await createTempDir()
80
- process.chdir(nonGitDir)
81
-
82
- await expect(runTestEffect(merge({ silent: true }))).rejects.toThrow(
83
- "Not in a git repository",
84
- )
85
-
86
- await cleanupTempDir(nonGitDir)
87
- })
88
-
89
- test("throws error if base branch does not exist locally", async () => {
90
- // Create emit branch (skipFilter for speed since we're testing error handling)
91
- await runTestEffect(emit({ silent: true, skipFilter: true }))
92
-
93
- // Delete main branch (the base)
94
- await checkoutBranch(tempDir, "feature")
95
- await deleteBranch(tempDir, "main", true)
96
-
97
- // Try to merge - should fail
98
- await expect(
99
- runTestEffect(merge({ silent: true, skipFilter: true })),
100
- ).rejects.toThrow("does not exist locally")
101
- })
102
- })
103
-
104
- describe("silent mode", () => {
105
- test("silent flag suppresses output", async () => {
106
- const logs: string[] = []
107
- const originalLog = console.log
108
- console.log = (...args: any[]) => logs.push(args.join(" "))
109
-
110
- await runTestEffect(merge({ silent: true, skipFilter: true }))
111
-
112
- console.log = originalLog
113
-
114
- expect(logs.length).toBe(0)
115
- })
116
- })
117
-
118
- describe("squash merge", () => {
119
- test("performs squash merge when --squash flag is set", async () => {
120
- // We're on feature branch (source)
121
- const currentBranch = await getCurrentBranch(tempDir)
122
- expect(currentBranch).toBe("agency--feature")
123
-
124
- // Run merge with squash flag (skipFilter for speed, we're testing squash behavior)
125
- await runTestEffect(
126
- merge({ silent: true, squash: true, skipFilter: true }),
127
- )
128
-
129
- // Should be on main branch after merge
130
- const afterMergeBranch = await getCurrentBranch(tempDir)
131
- expect(afterMergeBranch).toBe("main")
132
-
133
- // Check that changes are staged but not committed
134
- const status = await getGitOutput(tempDir, ["status", "--porcelain"])
135
-
136
- // Staged changes should be present (indicated by status codes in first column)
137
- expect(status.trim().length).toBeGreaterThan(0)
138
-
139
- // Get the log to verify no merge commit was created
140
- const log = await getGitOutput(tempDir, ["log", "--oneline", "-5"])
141
-
142
- // Should not contain a merge commit message
143
- expect(log).not.toContain("Merge branch")
144
- })
145
-
146
- test("performs regular merge when --squash flag is not set", async () => {
147
- // We're on feature branch (source)
148
- const currentBranch = await getCurrentBranch(tempDir)
149
- expect(currentBranch).toBe("agency--feature")
150
-
151
- // Run merge without squash flag (skipFilter for speed, we're testing merge behavior)
152
- await runTestEffect(
153
- merge({ silent: true, squash: false, skipFilter: true }),
154
- )
155
-
156
- // Should be on main branch after merge
157
- const afterMergeBranch = await getCurrentBranch(tempDir)
158
- expect(afterMergeBranch).toBe("main")
159
-
160
- // With regular merge (not squash), there should be no staged changes
161
- const status = await getGitOutput(tempDir, ["status", "--porcelain"])
162
-
163
- // No staged changes - everything should be committed
164
- expect(status.trim().length).toBe(0)
165
-
166
- // Get the log to verify commits were included
167
- const log = await getGitOutput(tempDir, ["log", "--oneline", "-5"])
168
-
169
- // Should contain the feature work commit (regular merge includes all commits)
170
- expect(log).toContain("Feature work")
171
- })
172
- })
173
-
174
- describe("push flag", () => {
175
- test("pushes base branch to origin when --push flag is set", async () => {
176
- // We're on feature branch (source)
177
- const currentBranch = await getCurrentBranch(tempDir)
178
- expect(currentBranch).toBe("agency--feature")
179
-
180
- // Get the current commit on main before merge
181
- await checkoutBranch(tempDir, "main")
182
- const beforeCommit = (
183
- await getGitOutput(tempDir, ["rev-parse", "HEAD"])
184
- ).trim()
185
-
186
- // Go back to feature branch
187
- await checkoutBranch(tempDir, "agency--feature")
188
-
189
- // Run merge with push flag (skipFilter for speed, we're testing push behavior)
190
- await runTestEffect(merge({ silent: true, push: true, skipFilter: true }))
191
-
192
- // Should be on main branch after merge
193
- const afterMergeBranch = await getCurrentBranch(tempDir)
194
- expect(afterMergeBranch).toBe("main")
195
-
196
- // Get the current commit on main after merge
197
- const afterCommit = (
198
- await getGitOutput(tempDir, ["rev-parse", "HEAD"])
199
- ).trim()
200
-
201
- // The commit should have changed (merge happened)
202
- expect(afterCommit).not.toBe(beforeCommit)
203
-
204
- // Verify that origin/main points to the same commit as local main
205
- const originMainCommit = (
206
- await getGitOutput(tempDir, ["rev-parse", "origin/main"])
207
- ).trim()
208
-
209
- // origin/main should be at the same commit as local main (push succeeded)
210
- expect(originMainCommit).toBe(afterCommit)
211
- })
212
-
213
- test("does not push when --push flag is not set", async () => {
214
- // We're on feature branch (source)
215
- const currentBranch = await getCurrentBranch(tempDir)
216
- expect(currentBranch).toBe("agency--feature")
217
-
218
- // Get the current commit on origin/main before merge
219
- const beforeOriginCommit = (
220
- await getGitOutput(tempDir, ["rev-parse", "origin/main"])
221
- ).trim()
222
-
223
- // Run merge without push flag (skipFilter for speed, we're testing push behavior)
224
- await runTestEffect(merge({ silent: true, skipFilter: true }))
225
-
226
- // Should be on main branch after merge
227
- const afterMergeBranch = await getCurrentBranch(tempDir)
228
- expect(afterMergeBranch).toBe("main")
229
-
230
- // Get the current commit on origin/main after merge
231
- const afterOriginCommit = (
232
- await getGitOutput(tempDir, ["rev-parse", "origin/main"])
233
- ).trim()
234
-
235
- // origin/main should still be at the same commit (no push happened)
236
- expect(afterOriginCommit).toBe(beforeOriginCommit)
237
-
238
- // But local main should have moved forward
239
- const localMainCommit = (
240
- await getGitOutput(tempDir, ["rev-parse", "HEAD"])
241
- ).trim()
242
-
243
- expect(localMainCommit).not.toBe(beforeOriginCommit)
244
- })
245
- })
246
- })
@@ -1,244 +0,0 @@
1
- import { Effect } from "effect"
2
- import type { BaseCommandOptions } from "../utils/command"
3
- import { GitService, GitCommandError } from "../services/GitService"
4
- import { ConfigService } from "../services/ConfigService"
5
- import { resolveBranchPairWithAgencyJson } from "../utils/pr-branch"
6
- import { FileSystemService } from "../services/FileSystemService"
7
- import { emit } from "./emit"
8
- import highlight, { done } from "../utils/colors"
9
- import {
10
- createLoggers,
11
- ensureGitRepo,
12
- ensureBranchExists,
13
- getBaseBranchFromMetadataEffect,
14
- getBaseBranchFromBranch,
15
- getRemoteName,
16
- } from "../utils/effect"
17
-
18
- interface MergeOptions extends BaseCommandOptions {
19
- squash?: boolean
20
- push?: boolean
21
- skipFilter?: boolean
22
- }
23
-
24
- // Helper to merge a branch using git
25
- const mergeBranchEffect = (
26
- gitRoot: string,
27
- branch: string,
28
- squash: boolean = false,
29
- ) =>
30
- Effect.gen(function* () {
31
- const git = yield* GitService
32
-
33
- const result = yield* git.merge(gitRoot, branch, { squash })
34
-
35
- if (result.exitCode !== 0) {
36
- return yield* Effect.fail(
37
- new GitCommandError({
38
- command: `git merge${squash ? " --squash" : ""} ${branch}`,
39
- exitCode: result.exitCode,
40
- stderr: result.stderr,
41
- }),
42
- )
43
- }
44
- })
45
-
46
- export const merge = (options: MergeOptions = {}) =>
47
- Effect.gen(function* () {
48
- const { squash = false, push = false, verbose = false } = options
49
- const { log, verboseLog } = createLoggers(options)
50
-
51
- const git = yield* GitService
52
- const configService = yield* ConfigService
53
-
54
- const gitRoot = yield* ensureGitRepo()
55
-
56
- const config = yield* configService.loadConfig()
57
- const currentBranch = yield* git.getCurrentBranch(gitRoot)
58
-
59
- verboseLog(`Current branch: ${highlight.branch(currentBranch)}`)
60
-
61
- // Use proper branch resolution with agency.json support
62
- const fs = yield* FileSystemService
63
- const branchInfo = yield* resolveBranchPairWithAgencyJson(
64
- gitRoot,
65
- currentBranch,
66
- config.sourceBranchPattern,
67
- config.emitBranch,
68
- )
69
-
70
- let emitBranchToMerge: string
71
- let baseBranchToMergeInto: string
72
-
73
- if (branchInfo.isOnEmitBranch) {
74
- const sourceBranch = branchInfo.sourceBranch
75
- verboseLog(
76
- `Current branch appears to be an emit branch for source: ${highlight.branch(sourceBranch)}`,
77
- )
78
-
79
- yield* ensureBranchExists(
80
- gitRoot,
81
- sourceBranch,
82
- `Current branch ${highlight.branch(currentBranch)} appears to be an emit branch, but source branch ${highlight.branch(sourceBranch)} does not exist.\n` +
83
- `Cannot merge without a valid source branch.`,
84
- )
85
-
86
- // Get the base branch from the source branch's agency.json using git show
87
- // No need to checkout the branch - we can read the file directly
88
- const configuredBase = yield* getBaseBranchFromBranch(
89
- gitRoot,
90
- sourceBranch,
91
- )
92
-
93
- if (!configuredBase) {
94
- return yield* Effect.fail(
95
- new Error(
96
- `No base branch configured for ${highlight.branch(sourceBranch)}.\n` +
97
- `Please switch to ${highlight.branch(sourceBranch)} and run: agency base set <branch>`,
98
- ),
99
- )
100
- }
101
-
102
- verboseLog(`Configured base branch: ${highlight.branch(configuredBase)}`)
103
-
104
- // For git operations (checkout/merge), use local branch name
105
- baseBranchToMergeInto = git.stripRemotePrefix(configuredBase)
106
-
107
- // Verify local base branch exists
108
- yield* ensureBranchExists(
109
- gitRoot,
110
- baseBranchToMergeInto,
111
- `Base branch ${highlight.branch(baseBranchToMergeInto)} does not exist locally.\n` +
112
- `You may need to checkout the branch first or update your base branch configuration.`,
113
- )
114
-
115
- emitBranchToMerge = currentBranch
116
- } else {
117
- // We're on a source branch - need to create/update emit branch first
118
- verboseLog(
119
- `Current branch appears to be a source branch, will create emit branch first`,
120
- )
121
-
122
- // Use the emit branch from branchInfo we already computed
123
- const emitBranch = branchInfo.emitBranch
124
- const emitExists = yield* git.branchExists(gitRoot, emitBranch)
125
-
126
- if (emitExists) {
127
- verboseLog(
128
- `Emit branch ${highlight.branch(emitBranch)} already exists, will recreate it`,
129
- )
130
- }
131
-
132
- // Run 'agency emit' to create/update the emit branch
133
- verboseLog(`Creating emit branch ${highlight.branch(emitBranch)}...`)
134
- yield* emit({ silent: true, verbose, skipFilter: options.skipFilter })
135
-
136
- // emit() leaves us on the source branch, so we can read agency.json directly
137
- const configuredBase = yield* getBaseBranchFromMetadataEffect(gitRoot)
138
- if (!configuredBase) {
139
- return yield* Effect.fail(
140
- new Error(
141
- `No base branch configured for ${highlight.branch(currentBranch)}.\n` +
142
- `Please set one with: agency base set <branch>`,
143
- ),
144
- )
145
- }
146
-
147
- verboseLog(`Configured base branch: ${highlight.branch(configuredBase)}`)
148
-
149
- // For git operations (checkout/merge), use local branch name
150
- baseBranchToMergeInto = git.stripRemotePrefix(configuredBase)
151
-
152
- // Verify local base branch exists
153
- yield* ensureBranchExists(
154
- gitRoot,
155
- baseBranchToMergeInto,
156
- `Base branch ${highlight.branch(baseBranchToMergeInto)} does not exist locally.\n` +
157
- `You may need to checkout the branch first or update your base branch configuration.`,
158
- )
159
-
160
- emitBranchToMerge = emitBranch
161
- }
162
-
163
- // Now switch to the base branch
164
- verboseLog(`Switching to ${highlight.branch(baseBranchToMergeInto)}...`)
165
- yield* git.checkoutBranch(gitRoot, baseBranchToMergeInto)
166
-
167
- // Merge the emit branch
168
- verboseLog(
169
- `Merging ${highlight.branch(emitBranchToMerge)} into ${highlight.branch(baseBranchToMergeInto)}${squash ? " (squash)" : ""}...`,
170
- )
171
- yield* mergeBranchEffect(gitRoot, emitBranchToMerge, squash)
172
-
173
- if (squash) {
174
- log(done(`Squash merged (awaiting commit)`))
175
- } else {
176
- log(done("Merged"))
177
- }
178
-
179
- // Push the base branch if --push flag is set
180
- if (push) {
181
- const remote = yield* getRemoteName(gitRoot)
182
- verboseLog(
183
- `Pushing ${highlight.branch(baseBranchToMergeInto)} to ${highlight.remote(remote)}...`,
184
- )
185
-
186
- const pushResult = yield* git.push(gitRoot, remote, baseBranchToMergeInto)
187
-
188
- if (pushResult.exitCode !== 0) {
189
- return yield* Effect.fail(
190
- new GitCommandError({
191
- command: `git push ${remote} ${baseBranchToMergeInto}`,
192
- exitCode: pushResult.exitCode,
193
- stderr: pushResult.stderr,
194
- }),
195
- )
196
- }
197
-
198
- log(done(`Pushed to ${highlight.remote(remote)}`))
199
- }
200
- })
201
-
202
- export const help = `
203
- Usage: agency merge [options]
204
-
205
- Merge the current emit branch into the configured base branch.
206
-
207
- This command handles two scenarios:
208
- 1. If on an emit branch (e.g., feature--PR): Switches to the base branch and merges the emit branch
209
- 2. If on a source branch (e.g., feature): Runs 'agency emit' first to create/update the emit branch, then merges it
210
-
211
- Behavior:
212
- - Automatically detects whether you're on a source or emit branch
213
- - Retrieves the configured base branch (e.g., 'main') from git config
214
- - Switches to the base branch
215
- - Merges the emit branch into the base branch
216
- - Leaves you on the base branch after merge
217
-
218
- This is useful for local development workflows where you want to test merging
219
- your clean emit branch (without AGENTS.md modifications) into the base branch
220
- before pushing.
221
-
222
- Prerequisites:
223
- - Must be on either a source branch or its corresponding emit branch
224
- - Base branch must exist locally
225
- - For source branches: Must have a corresponding emit branch or be able to create one
226
-
227
- Options:
228
- --squash # Use squash merge instead of regular merge
229
- --push # Push the base branch to origin after merging
230
-
231
- Examples:
232
- agency merge # From source branch: creates emit branch then merges
233
- agency merge --squash # Squash merge (stages changes, requires manual commit)
234
- agency merge --push # Merge and push the base branch to origin
235
-
236
- Notes:
237
- - The command determines the base branch from git config (agency.pr.<branch>.baseBranch)
238
- - If you're on a source branch, 'agency emit' is run automatically
239
- - The emit branch must have both a source branch and base branch configured
240
- - After merge, you remain on the base branch
241
- - Merge conflicts must be resolved manually if they occur
242
- - With --squash, changes are staged but not committed (you must commit manually)
243
- - With --push, the base branch is pushed to origin after a successful merge
244
- `