@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,219 +0,0 @@
1
- import { Effect } from "effect"
2
- import { resolve } from "path"
3
- import { FileSystemService } from "./FileSystemService"
4
-
5
- type PackageJson = {
6
- dependencies?: Record<string, string>
7
- devDependencies?: Record<string, string>
8
- }
9
-
10
- type PackageManager = "bun" | "yarn" | "pnpm" | "npm"
11
-
12
- type Formatter = "prettier" | "oxfmt"
13
-
14
- /**
15
- * Service for detecting and running code formatters on agency-created files.
16
- *
17
- * When agency creates files (markdown, json), pre-commit or pre-push hooks
18
- * in the target project may fail if those files aren't formatted according
19
- * to the project's formatter settings. This service detects the project's
20
- * formatter (prettier or oxfmt) and package manager, then runs the formatter
21
- * on the specified files. Failures are silently ignored.
22
- */
23
- export class FormatterService extends Effect.Service<FormatterService>()(
24
- "FormatterService",
25
- {
26
- sync: () => ({
27
- /**
28
- * Detect which package manager the project uses by checking for lock files.
29
- * Falls back to npm if no lock file is found but package.json exists.
30
- * Returns null if no package.json exists.
31
- */
32
- detectPackageManager: (gitRoot: string) =>
33
- Effect.gen(function* () {
34
- const fs = yield* FileSystemService
35
-
36
- // Check for package.json first - if it doesn't exist, no package manager
37
- const hasPackageJson = yield* fs.exists(
38
- resolve(gitRoot, "package.json"),
39
- )
40
- if (!hasPackageJson) {
41
- return null
42
- }
43
-
44
- // Check lock files in priority order
45
- if (yield* fs.exists(resolve(gitRoot, "bun.lockb")))
46
- return "bun" as PackageManager
47
- if (yield* fs.exists(resolve(gitRoot, "bun.lock")))
48
- return "bun" as PackageManager
49
- if (yield* fs.exists(resolve(gitRoot, "yarn.lock")))
50
- return "yarn" as PackageManager
51
- if (yield* fs.exists(resolve(gitRoot, "pnpm-lock.yaml")))
52
- return "pnpm" as PackageManager
53
- if (yield* fs.exists(resolve(gitRoot, "package-lock.json")))
54
- return "npm" as PackageManager
55
-
56
- // Default to npm if package.json exists but no lock file found
57
- return "npm" as PackageManager
58
- }),
59
-
60
- /**
61
- * Detect which formatter is available in the project's package.json.
62
- * Checks both dependencies and devDependencies for prettier and oxfmt.
63
- * Returns null if neither is found.
64
- */
65
- detectFormatter: (gitRoot: string) =>
66
- Effect.gen(function* () {
67
- const fs = yield* FileSystemService
68
-
69
- const packageJsonPath = resolve(gitRoot, "package.json")
70
- const exists = yield* fs.exists(packageJsonPath)
71
- if (!exists) {
72
- return null
73
- }
74
-
75
- const packageJson = yield* fs.readJSON<PackageJson>(packageJsonPath)
76
-
77
- const allDeps = {
78
- ...packageJson.dependencies,
79
- ...packageJson.devDependencies,
80
- }
81
-
82
- // Check for oxfmt first (newer/faster), then prettier
83
- if ("oxfmt" in allDeps) return "oxfmt" as Formatter
84
- if ("prettier" in allDeps) return "prettier" as Formatter
85
-
86
- return null
87
- }).pipe(Effect.catchAll(() => Effect.succeed(null))),
88
-
89
- /**
90
- * Build the command to run a formatter via the detected package manager.
91
- * Returns the command args array, or null if the formatter/pm combo isn't supported.
92
- */
93
- buildFormatterCommand: (
94
- formatter: Formatter,
95
- packageManager: PackageManager,
96
- files: string[],
97
- ) =>
98
- Effect.sync(() => {
99
- if (files.length === 0) return null
100
-
101
- // Build the runner prefix based on package manager
102
- const runnerPrefix: string[] = (() => {
103
- switch (packageManager) {
104
- case "bun":
105
- return ["bun", "x"]
106
- case "yarn":
107
- return ["yarn", "dlx"]
108
- case "pnpm":
109
- return ["pnpm", "exec"]
110
- case "npm":
111
- return ["npx"]
112
- }
113
- })()
114
-
115
- // Build the formatter command
116
- switch (formatter) {
117
- case "prettier":
118
- return [...runnerPrefix, "prettier", "--write", ...files]
119
- case "oxfmt":
120
- return [...runnerPrefix, "oxfmt", ...files]
121
- default:
122
- return null
123
- }
124
- }),
125
-
126
- /**
127
- * Format the given files using the project's detected formatter.
128
- * Silently returns if no formatter is detected or if the command fails.
129
- * This is the main entry point for formatting agency-created files.
130
- */
131
- formatFiles: (
132
- gitRoot: string,
133
- files: string[],
134
- verboseLog: (msg: string) => void,
135
- ) =>
136
- Effect.gen(function* () {
137
- const fs = yield* FileSystemService
138
-
139
- if (files.length === 0) {
140
- verboseLog("No files to format")
141
- return
142
- }
143
-
144
- // Filter to only .md and .json/.jsonc files (the types agency creates)
145
- const formattableFiles = files.filter(
146
- (f) =>
147
- f.endsWith(".md") || f.endsWith(".json") || f.endsWith(".jsonc"),
148
- )
149
-
150
- if (formattableFiles.length === 0) {
151
- verboseLog("No formattable files (md/json/jsonc) found")
152
- return
153
- }
154
-
155
- // Use yield* on the service methods via self-reference through the service tag
156
- const formatterService = yield* FormatterService
157
-
158
- const formatter = yield* formatterService.detectFormatter(gitRoot)
159
- if (!formatter) {
160
- verboseLog("No formatter (prettier/oxfmt) detected in package.json")
161
- return
162
- }
163
-
164
- const packageManager =
165
- yield* formatterService.detectPackageManager(gitRoot)
166
- if (!packageManager) {
167
- verboseLog("No package manager detected")
168
- return
169
- }
170
-
171
- verboseLog(
172
- `Detected formatter: ${formatter}, package manager: ${packageManager}`,
173
- )
174
-
175
- // Build absolute paths for the files
176
- const absolutePaths = formattableFiles.map((f) => resolve(gitRoot, f))
177
-
178
- const command = yield* formatterService.buildFormatterCommand(
179
- formatter,
180
- packageManager,
181
- absolutePaths,
182
- )
183
- if (!command) {
184
- verboseLog("Could not build formatter command")
185
- return
186
- }
187
-
188
- verboseLog(`Running formatter: ${command.join(" ")}`)
189
-
190
- // Run the formatter, silently ignoring failures
191
- yield* fs
192
- .runCommand(command, {
193
- cwd: gitRoot,
194
- captureOutput: true,
195
- })
196
- .pipe(
197
- Effect.catchAll((err) => {
198
- verboseLog(`Formatter failed (silently ignoring): ${err}`)
199
- return Effect.void
200
- }),
201
- )
202
-
203
- verboseLog(
204
- `Formatted ${formattableFiles.length} file(s) with ${formatter}`,
205
- )
206
- }).pipe(
207
- // Catch any unexpected errors silently
208
- Effect.catchAll((err) => {
209
- verboseLog(`Formatting failed (silently ignoring): ${err}`)
210
- return Effect.void
211
- }),
212
- Effect.catchAllDefect((defect) => {
213
- verboseLog(`Formatting defect (silently ignoring): ${defect}`)
214
- return Effect.void
215
- }),
216
- ),
217
- }),
218
- },
219
- ) {}