@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,274 +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 { parseAgencyMetadata } from "../services/AgencyMetadataService"
6
- import highlight, { done } from "../utils/colors"
7
- import { createLoggers, ensureGitRepo } from "../utils/effect"
8
- import { extractCleanBranch, makeSourceBranchName } from "../utils/pr-branch"
9
-
10
- interface CleanOptions extends BaseCommandOptions {
11
- dryRun?: boolean
12
- mergedInto?: string
13
- }
14
-
15
- /**
16
- * Read agency.json metadata from a specific branch without checking it out.
17
- * Uses `git show` to read the file contents directly.
18
- */
19
- const readAgencyMetadata = (gitRoot: string, branch: string) =>
20
- Effect.gen(function* () {
21
- const git = yield* GitService
22
-
23
- // Use git show to read agency.json from the branch without checking out
24
- const content = yield* git.getFileAtRef(gitRoot, branch, "agency.json")
25
-
26
- if (!content) {
27
- return null
28
- }
29
-
30
- return yield* parseAgencyMetadata(content)
31
- }).pipe(Effect.catchAll(() => Effect.succeed(null)))
32
-
33
- /**
34
- * Get all local branches
35
- */
36
- const getAllLocalBranches = (gitRoot: string) =>
37
- Effect.gen(function* () {
38
- const git = yield* GitService
39
- return yield* git.getAllLocalBranches(gitRoot)
40
- }).pipe(Effect.catchAll(() => Effect.succeed([] as readonly string[])))
41
-
42
- /**
43
- * Get all branches that have been fully merged into the specified branch
44
- */
45
- const getBranchesMergedInto = (
46
- gitRoot: string,
47
- targetBranch: string,
48
- options: BaseCommandOptions,
49
- ) =>
50
- Effect.gen(function* () {
51
- const git = yield* GitService
52
- const { verboseLog } = createLoggers(options)
53
-
54
- verboseLog(
55
- `Finding branches merged into ${highlight.branch(targetBranch)}...`,
56
- )
57
-
58
- const mergedBranches = yield* git.getMergedBranches(gitRoot, targetBranch)
59
-
60
- verboseLog(`Found ${mergedBranches.length} merged branches`)
61
- return mergedBranches
62
- }).pipe(Effect.catchAll(() => Effect.succeed([] as readonly string[])))
63
-
64
- /**
65
- * Find source branches for the given branches (emit branches).
66
- * For each branch, check if there's a corresponding source branch by:
67
- * 1. Looking for branches with agency.json that has this branch as emitBranch
68
- * 2. Using the source branch pattern from config
69
- */
70
- const findSourceBranches = (
71
- gitRoot: string,
72
- branches: readonly string[],
73
- sourcePattern: string,
74
- emitPattern: string,
75
- options: BaseCommandOptions,
76
- ) =>
77
- Effect.gen(function* () {
78
- const git = yield* GitService
79
- const { verboseLog } = createLoggers(options)
80
-
81
- const allBranches = yield* getAllLocalBranches(gitRoot)
82
- const sourceBranches: string[] = []
83
-
84
- verboseLog(
85
- `Looking for source branches for ${branches.length} emit branches...`,
86
- )
87
-
88
- // For each branch in our list, check if it's an emit branch and find its source
89
- for (const branch of branches) {
90
- // Strategy 1: Check all branches for agency.json with matching emitBranch
91
- for (const candidateBranch of allBranches) {
92
- if (candidateBranch === branch) continue
93
-
94
- const metadata = yield* readAgencyMetadata(gitRoot, candidateBranch)
95
-
96
- if (metadata?.emitBranch === branch) {
97
- verboseLog(
98
- `Found source branch ${highlight.branch(candidateBranch)} for emit branch ${highlight.branch(branch)}`,
99
- )
100
- if (!sourceBranches.includes(candidateBranch)) {
101
- sourceBranches.push(candidateBranch)
102
- }
103
- }
104
- }
105
-
106
- // Strategy 2: Try using the source pattern
107
- // If emitPattern is "%branch%", the branch name itself is the clean name
108
- const cleanBranch =
109
- emitPattern === "%branch%"
110
- ? branch
111
- : extractCleanBranch(branch, emitPattern)
112
-
113
- if (cleanBranch) {
114
- const possibleSourceBranch = makeSourceBranchName(
115
- cleanBranch,
116
- sourcePattern,
117
- )
118
- const sourceExists = yield* git
119
- .branchExists(gitRoot, possibleSourceBranch)
120
- .pipe(Effect.catchAll(() => Effect.succeed(false)))
121
-
122
- if (sourceExists && !sourceBranches.includes(possibleSourceBranch)) {
123
- verboseLog(
124
- `Found source branch ${highlight.branch(possibleSourceBranch)} via pattern matching`,
125
- )
126
- sourceBranches.push(possibleSourceBranch)
127
- }
128
- }
129
- }
130
-
131
- verboseLog(`Found ${sourceBranches.length} source branches`)
132
- return sourceBranches
133
- })
134
-
135
- export const clean = (options: CleanOptions = {}) =>
136
- Effect.gen(function* () {
137
- const { dryRun = false, mergedInto } = options
138
- const { log, verboseLog } = createLoggers(options)
139
-
140
- const git = yield* GitService
141
- const configService = yield* ConfigService
142
- const gitRoot = yield* ensureGitRepo()
143
-
144
- // Require --merged-into flag
145
- if (!mergedInto) {
146
- return yield* Effect.fail(
147
- new Error(
148
- "The --merged-into flag is required. Specify which branch to check for merged branches (e.g., --merged-into main)",
149
- ),
150
- )
151
- }
152
-
153
- // Verify the target branch exists
154
- const targetExists = yield* git.branchExists(gitRoot, mergedInto)
155
- if (!targetExists) {
156
- return yield* Effect.fail(
157
- new Error(
158
- `Branch ${highlight.branch(mergedInto)} does not exist. Please specify a valid branch.`,
159
- ),
160
- )
161
- }
162
-
163
- // Load config to get source and emit patterns
164
- const config = yield* configService.loadConfig()
165
- const sourcePattern = config.sourceBranchPattern || "agency--%branch%"
166
- const emitPattern = config.emitBranch || "%branch%"
167
-
168
- verboseLog(
169
- `Using source pattern: ${sourcePattern}, emit pattern: ${emitPattern}`,
170
- )
171
-
172
- // Get all branches merged into target
173
- const mergedBranches = yield* getBranchesMergedInto(
174
- gitRoot,
175
- mergedInto,
176
- options,
177
- )
178
- verboseLog(
179
- `Found ${mergedBranches.length} branches merged into ${highlight.branch(mergedInto)}`,
180
- )
181
-
182
- // Find source branches for the merged branches
183
- const sourceBranches = yield* findSourceBranches(
184
- gitRoot,
185
- mergedBranches,
186
- sourcePattern,
187
- emitPattern,
188
- options,
189
- )
190
-
191
- // Combine merged branches and their source branches
192
- const branchesToDelete = [
193
- ...new Set([...mergedBranches, ...sourceBranches]),
194
- ]
195
-
196
- // Filter out the target branch itself (we don't want to delete it)
197
- const filteredBranches = branchesToDelete.filter(
198
- (branch) => branch !== mergedInto,
199
- )
200
-
201
- if (filteredBranches.length === 0) {
202
- log(
203
- `No branches found that are merged into ${highlight.branch(mergedInto)}`,
204
- )
205
- return
206
- }
207
-
208
- // Show what will be deleted
209
- const branchWord = filteredBranches.length === 1 ? "branch" : "branches"
210
- log(
211
- `Found ${filteredBranches.length} ${branchWord} to delete (merged into ${highlight.branch(mergedInto)}):`,
212
- )
213
- for (const branch of filteredBranches) {
214
- log(` ${highlight.branch(branch)}`)
215
- }
216
-
217
- if (dryRun) {
218
- log("")
219
- log("Dry-run mode: no branches were deleted")
220
- return
221
- }
222
-
223
- // Get current branch to avoid deleting it
224
- const currentBranch = yield* git.getCurrentBranch(gitRoot)
225
-
226
- // Delete all branches
227
- log("")
228
- for (const branch of filteredBranches) {
229
- // If we're currently on the branch, switch away first
230
- if (currentBranch === branch) {
231
- verboseLog(
232
- `Currently on ${highlight.branch(branch)}, switching to ${highlight.branch(mergedInto)}`,
233
- )
234
- yield* git.checkoutBranch(gitRoot, mergedInto)
235
- }
236
-
237
- verboseLog(`Deleting ${highlight.branch(branch)}...`)
238
- yield* git.deleteBranch(gitRoot, branch, true)
239
- }
240
-
241
- const deletedBranchWord =
242
- filteredBranches.length === 1 ? "branch" : "branches"
243
- log(done(`Deleted ${filteredBranches.length} ${deletedBranchWord}`))
244
- })
245
-
246
- export const help = `
247
- Usage: agency clean --merged-into <branch> [options]
248
-
249
- Delete all branches that have been fully merged into a specified branch,
250
- along with their corresponding source branches.
251
-
252
- This command is useful for cleaning up branches after they've been merged.
253
- It will:
254
- 1. Find all branches fully merged into the specified branch
255
- 2. Find the corresponding source branches (which won't show as merged due to emit filtering)
256
- 3. Delete both the merged branches and their source branches
257
-
258
- The --merged-into flag is REQUIRED to prevent accidental deletion of branches.
259
-
260
- Options:
261
- --merged-into <branch> Branch to check against (e.g., main, origin/main) [REQUIRED]
262
- --dry-run Show what would be deleted without actually deleting
263
-
264
- Safety:
265
- - By default, this command deletes branches
266
- - Use --dry-run to preview what would be deleted without making changes
267
- - If currently on a branch that will be deleted, switches to the target branch first
268
- - Uses force delete (git branch -D) to ensure branches are deleted
269
-
270
- Examples:
271
- agency clean --merged-into main # Delete branches merged into main
272
- agency clean --merged-into main --dry-run # Preview what would be deleted
273
- agency clean --merged-into origin/main # Delete branches merged into origin/main
274
- `
@@ -1,51 +0,0 @@
1
- import { describe, expect, test } from "bun:test"
2
- import { Effect } from "effect"
3
- import { completions } from "./completions"
4
-
5
- const captureCompletions = async (shell: string) => {
6
- const originalLog = console.log
7
- let output = ""
8
- console.log = (message: string) => {
9
- output += message
10
- }
11
-
12
- try {
13
- await Effect.runPromise(completions(shell))
14
- } finally {
15
- console.log = originalLog
16
- }
17
-
18
- return output
19
- }
20
-
21
- describe("completions command", () => {
22
- test("generates bash completions", async () => {
23
- const output = await captureCompletions("bash")
24
-
25
- expect(output).toContain("_agency_completions()")
26
- expect(output).toContain("complete -F _agency_completions agency")
27
- expect(output).toContain("completions")
28
- expect(output).toContain("bash zsh")
29
- })
30
-
31
- test("generates zsh completions", async () => {
32
- const output = await captureCompletions("zsh")
33
-
34
- expect(output).toContain("#compdef agency")
35
- expect(output).toContain("_agency()")
36
- expect(output).toContain("agency_commands=(")
37
- expect(output).toContain("bash\\:Generate\\ bash\\ completions")
38
- })
39
-
40
- test("prints the requested completion script", async () => {
41
- const output = await captureCompletions("zsh")
42
-
43
- expect(output).toContain("#compdef agency")
44
- })
45
-
46
- test("rejects unsupported shells", async () => {
47
- await expect(Effect.runPromise(completions("fish"))).rejects.toThrow(
48
- "Usage: agency completions <bash|zsh>",
49
- )
50
- })
51
- })
@@ -1,308 +0,0 @@
1
- import { Effect } from "effect"
2
-
3
- const shells = ["bash", "zsh"] as const
4
- type Shell = (typeof shells)[number]
5
-
6
- const commands = [
7
- "init",
8
- "task",
9
- "tasks",
10
- "edit",
11
- "work",
12
- "template",
13
- "emit",
14
- "emitted",
15
- "pr",
16
- "push",
17
- "pull",
18
- "rebase",
19
- "base",
20
- "switch",
21
- "source",
22
- "merge",
23
- "status",
24
- "clean",
25
- "loop",
26
- "completions",
27
- ] as const
28
-
29
- const templateSubcommands = ["use", "save", "list", "view", "delete"] as const
30
- const baseSubcommands = ["get", "set"] as const
31
- const completionSubcommands = shells
32
-
33
- const globalOptions = [
34
- "--help",
35
- "-h",
36
- "--version",
37
- "-v",
38
- "--no-color",
39
- "--silent",
40
- "-s",
41
- "--verbose",
42
- ] as const
43
-
44
- const commandOptions: Record<string, readonly string[]> = {
45
- init: [
46
- "--help",
47
- "-h",
48
- "--template",
49
- "-t",
50
- "--silent",
51
- "-s",
52
- "--verbose",
53
- "-v",
54
- ],
55
- emit: [
56
- "--help",
57
- "-h",
58
- "--emit",
59
- "--branch",
60
- "--silent",
61
- "-s",
62
- "--verbose",
63
- "-v",
64
- ],
65
- push: [
66
- "--help",
67
- "-h",
68
- "--emit",
69
- "--branch",
70
- "--force",
71
- "-f",
72
- "--no-verify",
73
- "--pr",
74
- "--silent",
75
- "-s",
76
- "--verbose",
77
- "-v",
78
- ],
79
- pull: ["--help", "-h", "--remote", "-r", "--silent", "-s", "--verbose", "-v"],
80
- rebase: [
81
- "--help",
82
- "-h",
83
- "--emit",
84
- "--branch",
85
- "--silent",
86
- "-s",
87
- "--verbose",
88
- "-v",
89
- ],
90
- task: [
91
- "--help",
92
- "-h",
93
- "--emit",
94
- "--branch",
95
- "--task",
96
- "--from",
97
- "--from-current",
98
- "--continue",
99
- "--squash",
100
- "--silent",
101
- "-s",
102
- "--verbose",
103
- "-v",
104
- ],
105
- tasks: ["--help", "-h", "--json", "--silent", "-s", "--verbose", "-v"],
106
- base: ["--help", "-h", "--repo", "--silent", "-s", "--verbose", "-v"],
107
- template: [
108
- "--help",
109
- "-h",
110
- "--template",
111
- "-t",
112
- "--silent",
113
- "-s",
114
- "--verbose",
115
- "-v",
116
- ],
117
- work: [
118
- "--help",
119
- "-h",
120
- "--opencode",
121
- "--claude",
122
- "--silent",
123
- "-s",
124
- "--verbose",
125
- "-v",
126
- ],
127
- loop: [
128
- "--help",
129
- "-h",
130
- "--min-loops",
131
- "--max-loops",
132
- "--opencode",
133
- "--claude",
134
- "--silent",
135
- "-s",
136
- "--verbose",
137
- "-v",
138
- ],
139
- status: ["--help", "-h", "--json", "--silent", "-s", "--verbose", "-v"],
140
- clean: [
141
- "--help",
142
- "-h",
143
- "--dry-run",
144
- "--merged-into",
145
- "--silent",
146
- "-s",
147
- "--verbose",
148
- "-v",
149
- ],
150
- completions: ["--help", "-h"],
151
- }
152
-
153
- const words = (values: readonly string[]) => values.join(" ")
154
-
155
- const bashCase = (command: string, subcommands?: readonly string[]) => {
156
- const options = commandOptions[command] ?? [
157
- "--help",
158
- "-h",
159
- "--silent",
160
- "-s",
161
- "--verbose",
162
- "-v",
163
- ]
164
- const completions = subcommands ? [...subcommands, ...options] : options
165
- return `\t\t${command})\n\t\t\tCOMPREPLY=( $(compgen -W "${words(completions)}" -- "$cur") )\n\t\t\treturn 0\n\t\t\t;;`
166
- }
167
-
168
- const zshCommandSpec = (command: string, description: string) =>
169
- ` '${command}:${description}'`
170
-
171
- const generateBashCompletions = () => `# bash completion for agency
172
- _agency_completions() {
173
- local cur prev command
174
- COMPREPLY=()
175
- cur="\${COMP_WORDS[COMP_CWORD]}"
176
- prev="\${COMP_WORDS[COMP_CWORD-1]}"
177
-
178
- if [[ $COMP_CWORD -eq 1 ]]; then
179
- COMPREPLY=( $(compgen -W "${words([...commands, ...globalOptions])}" -- "$cur") )
180
- return 0
181
- fi
182
-
183
- command="\${COMP_WORDS[1]}"
184
- case "$command" in
185
- ${bashCase("template", templateSubcommands)}
186
- ${bashCase("base", baseSubcommands)}
187
- ${bashCase("completions", completionSubcommands)}
188
- ${commands
189
- .filter((command) => !["template", "base", "completions"].includes(command))
190
- .map((command) => bashCase(command))
191
- .join("\n")}
192
- esac
193
-
194
- case "$prev" in
195
- --template|-t|--emit|--branch|--task|--from|--remote|-r|--merged-into)
196
- return 0
197
- ;;
198
- esac
199
- }
200
-
201
- complete -F _agency_completions agency
202
- `
203
-
204
- const generateZshCompletions = () => `#compdef agency
205
- # zsh completion for agency
206
-
207
- _agency() {
208
- local context state line
209
- local -a agency_commands
210
- typeset -A opt_args
211
-
212
- agency_commands=(
213
- ${zshCommandSpec("init", "Initialize agency with template selection")}
214
- ${zshCommandSpec("task", "Initialize template files on a feature branch")}
215
- ${zshCommandSpec("tasks", "List all task branches")}
216
- ${zshCommandSpec("edit", "Open TASK.md in system editor")}
217
- ${zshCommandSpec("work", "Start working on TASK.md with OpenCode")}
218
- ${zshCommandSpec("template", "Template management commands")}
219
- ${zshCommandSpec("emit", "Emit a branch with backpack files reverted")}
220
- ${zshCommandSpec("emitted", "Get the name of the emitted branch")}
221
- ${zshCommandSpec("pr", "Run gh pr with the emitted branch name")}
222
- ${zshCommandSpec("push", "Emit, push to remote, return to source")}
223
- ${zshCommandSpec("pull", "Pull commits from remote emit branch to source")}
224
- ${zshCommandSpec("rebase", "Rebase source branch onto base branch")}
225
- ${zshCommandSpec("base", "Get or set the base branch")}
226
- ${zshCommandSpec("switch", "Toggle between source and emitted branch")}
227
- ${zshCommandSpec("source", "Switch to source branch from emitted branch")}
228
- ${zshCommandSpec("merge", "Merge emitted branch into base branch")}
229
- ${zshCommandSpec("status", "Show agency status for this repository")}
230
- ${zshCommandSpec("clean", "Delete branches merged into a specified branch")}
231
- ${zshCommandSpec("loop", "Run a Ralph Wiggum loop to complete all tasks")}
232
- ${zshCommandSpec("completions", "Generate shell completion scripts")}
233
- )
234
-
235
- _arguments -C \\
236
- '(-h --help)'{-h,--help}'[show help]' \\
237
- '(-v --version)'{-v,--version}'[show version]' \\
238
- '--no-color[disable color output]' \\
239
- '(-s --silent)'{-s,--silent}'[suppress output messages]' \\
240
- '--verbose[show verbose output]' \\
241
- '1:command:->command' \\
242
- '*::arg:->args'
243
-
244
- case $state in
245
- command)
246
- _describe 'agency command' agency_commands
247
- ;;
248
- args)
249
- case $line[1] in
250
- template)
251
- _arguments \\
252
- '(-h --help)'{-h,--help}'[show help]' \\
253
- '(-t --template)'{-t,--template}'[template name]:template:' \\
254
- '(-s --silent)'{-s,--silent}'[suppress output messages]' \\
255
- '--verbose[show verbose output]' \\
256
- '1:subcommand:((use\\:Set\\ template save\\:Save\\ files list\\:List\\ files view\\:View\\ file delete\\:Delete\\ files))' \\
257
- '*:file:_files'
258
- ;;
259
- base)
260
- _arguments \\
261
- '(-h --help)'{-h,--help}'[show help]' \\
262
- '--repo[use repository-local configuration]' \\
263
- '(-s --silent)'{-s,--silent}'[suppress output messages]' \\
264
- '--verbose[show verbose output]' \\
265
- '1:subcommand:((get\\:Get\\ base\\ branch set\\:Set\\ base\\ branch))' \\
266
- '*:branch:'
267
- ;;
268
- completions)
269
- _arguments \\
270
- '(-h --help)'{-h,--help}'[show help]' \\
271
- '1:shell:((bash\\:Generate\\ bash\\ completions zsh\\:Generate\\ zsh\\ completions))'
272
- ;;
273
- *)
274
- _arguments \\
275
- '(-h --help)'{-h,--help}'[show help]' \\
276
- '(-s --silent)'{-s,--silent}'[suppress output messages]' \\
277
- '--verbose[show verbose output]'
278
- ;;
279
- esac
280
- ;;
281
- esac
282
- }
283
-
284
- _agency "$@"
285
- `
286
-
287
- export const completions = (shell: string | undefined) =>
288
- Effect.gen(function* () {
289
- if (!shell || !shells.includes(shell as Shell)) {
290
- return yield* Effect.fail(
291
- new Error("Usage: agency completions <bash|zsh>"),
292
- )
293
- }
294
-
295
- console.log(
296
- shell === "bash" ? generateBashCompletions() : generateZshCompletions(),
297
- )
298
- })
299
-
300
- export const help = `
301
- Usage: agency completions <bash|zsh>
302
-
303
- Generate shell completion scripts.
304
-
305
- Examples:
306
- agency completions zsh > ~/.zsh/completions/_agency
307
- agency completions bash > ~/.local/share/bash-completion/completions/agency
308
- `