@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,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
- `