@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,172 +0,0 @@
1
- import { describe, it, expect } from "bun:test"
2
- import {
3
- parseTaskItems,
4
- countTasks,
5
- areAllTasksComplete,
6
- extractCompletionPromise,
7
- validateCompletion,
8
- } from "./task-parser"
9
-
10
- describe("task-parser", () => {
11
- describe("parseTaskItems", () => {
12
- it("should parse task items correctly", () => {
13
- const taskContent = `
14
- # Tasks
15
-
16
- - [ ] First task
17
- - [x] Second task
18
- - [ ] Third task
19
- `
20
-
21
- const items = parseTaskItems(taskContent)
22
- expect(items).toHaveLength(3)
23
- expect(items[0]!.isComplete).toBe(false)
24
- expect(items[0]!.text).toBe("First task")
25
- expect(items[1]!.isComplete).toBe(true)
26
- expect(items[1]!.text).toBe("Second task")
27
- expect(items[2]!.isComplete).toBe(false)
28
- expect(items[2]!.text).toBe("Third task")
29
- })
30
-
31
- it("should handle empty task list", () => {
32
- const taskContent = `
33
- # Tasks
34
-
35
- No task items here
36
- `
37
-
38
- const items = parseTaskItems(taskContent)
39
- expect(items).toHaveLength(0)
40
- })
41
-
42
- it("should parse task items with various bullet formats", () => {
43
- const taskContent = `
44
- - [ ] Dash format unchecked
45
- - [x] Dash format checked
46
- * [ ] Asterisk format unchecked
47
- * [X] Asterisk format uppercase
48
- - [ ] Indented unchecked
49
- - [x] Indented checked
50
- `
51
-
52
- const items = parseTaskItems(taskContent)
53
- expect(items).toHaveLength(6)
54
- expect(items[0]!.isComplete).toBe(false)
55
- expect(items[1]!.isComplete).toBe(true)
56
- expect(items[2]!.isComplete).toBe(false)
57
- expect(items[3]!.isComplete).toBe(true)
58
- expect(items[4]!.isComplete).toBe(false)
59
- expect(items[5]!.isComplete).toBe(true)
60
- })
61
-
62
- it("should track line numbers", () => {
63
- const taskContent = `# Header
64
- - [ ] First task
65
- Some text
66
- - [x] Second task`
67
-
68
- const items = parseTaskItems(taskContent)
69
- expect(items).toHaveLength(2)
70
- expect(items[0]!.lineNumber).toBe(2)
71
- expect(items[1]!.lineNumber).toBe(4)
72
- })
73
- })
74
-
75
- describe("countTasks", () => {
76
- it("should count completed and incomplete tasks", () => {
77
- const items = [
78
- { text: "First", isComplete: false, lineNumber: 1 },
79
- { text: "Second", isComplete: true, lineNumber: 2 },
80
- { text: "Third", isComplete: false, lineNumber: 3 },
81
- ]
82
-
83
- const counts = countTasks(items)
84
- expect(counts.completed).toBe(1)
85
- expect(counts.incomplete).toBe(2)
86
- expect(counts.total).toBe(3)
87
- })
88
-
89
- it("should handle empty list", () => {
90
- const counts = countTasks([])
91
- expect(counts.completed).toBe(0)
92
- expect(counts.incomplete).toBe(0)
93
- expect(counts.total).toBe(0)
94
- })
95
- })
96
-
97
- describe("areAllTasksComplete", () => {
98
- it("should return true when all tasks are complete", () => {
99
- const items = [
100
- { text: "First", isComplete: true, lineNumber: 1 },
101
- { text: "Second", isComplete: true, lineNumber: 2 },
102
- ]
103
- expect(areAllTasksComplete(items)).toBe(true)
104
- })
105
-
106
- it("should return false when some tasks are incomplete", () => {
107
- const items = [
108
- { text: "First", isComplete: true, lineNumber: 1 },
109
- { text: "Second", isComplete: false, lineNumber: 2 },
110
- ]
111
- expect(areAllTasksComplete(items)).toBe(false)
112
- })
113
-
114
- it("should return true for empty list", () => {
115
- expect(areAllTasksComplete([])).toBe(true)
116
- })
117
- })
118
-
119
- describe("extractCompletionPromise", () => {
120
- it("should extract completion promise from output", () => {
121
- const output = "Some output\n<promise>COMPLETE</promise>"
122
- expect(extractCompletionPromise(output)).toBe("COMPLETE")
123
- })
124
-
125
- it("should return null when no promise found", () => {
126
- const output = "No promise here"
127
- expect(extractCompletionPromise(output)).toBeNull()
128
- })
129
-
130
- it("should extract any promise content", () => {
131
- const output = "<promise>custom message</promise>"
132
- expect(extractCompletionPromise(output)).toBe("custom message")
133
- })
134
- })
135
-
136
- describe("validateCompletion", () => {
137
- it("should not throw when all tasks complete and claiming completion", () => {
138
- expect(() => {
139
- validateCompletion("COMPLETE", true)
140
- }).not.toThrow()
141
- })
142
-
143
- it("should not throw when not claiming completion", () => {
144
- expect(() => {
145
- validateCompletion(null, false)
146
- }).not.toThrow()
147
- })
148
-
149
- it("should throw when claiming completion but tasks remain", () => {
150
- expect(() => {
151
- validateCompletion("COMPLETE", false)
152
- }).toThrow(
153
- "Agent claimed completion with <promise>COMPLETE</promise> but incomplete tasks remain",
154
- )
155
- })
156
-
157
- it("should be case-insensitive for COMPLETE", () => {
158
- expect(() => {
159
- validateCompletion("complete", false)
160
- }).toThrow()
161
- expect(() => {
162
- validateCompletion("Complete", false)
163
- }).toThrow()
164
- })
165
-
166
- it("should not throw for non-COMPLETE messages", () => {
167
- expect(() => {
168
- validateCompletion("IN_PROGRESS", false)
169
- }).not.toThrow()
170
- })
171
- })
172
- })
@@ -1,93 +0,0 @@
1
- /**
2
- * Utility functions for parsing and analyzing TASK.md files
3
- */
4
-
5
- /**
6
- * Represents a task item parsed from markdown
7
- */
8
- interface TaskItem {
9
- readonly text: string
10
- readonly isComplete: boolean
11
- readonly lineNumber: number
12
- }
13
-
14
- /**
15
- * Parse TASK.md content and extract task items
16
- * Returns all checkbox items (both complete and incomplete)
17
- */
18
- export function parseTaskItems(content: string): TaskItem[] {
19
- const items: TaskItem[] = []
20
- const lines = content.split("\n")
21
-
22
- for (let i = 0; i < lines.length; i++) {
23
- const line = lines[i]
24
- if (!line) continue
25
- // Match both [ ] (incomplete) and [x] or [X] (complete)
26
- const match = line.match(/^[\s]*[-*]\s+\[([ xX])\]\s+(.+)$/)
27
- if (match && match[1] && match[2]) {
28
- const isComplete = match[1].toLowerCase() === "x"
29
- const text = match[2]
30
- items.push({
31
- text,
32
- isComplete,
33
- lineNumber: i + 1, // 1-indexed
34
- })
35
- }
36
- }
37
-
38
- return items
39
- }
40
-
41
- /**
42
- * Count completed and incomplete tasks
43
- */
44
- export function countTasks(items: TaskItem[]): {
45
- completed: number
46
- incomplete: number
47
- total: number
48
- } {
49
- const completed = items.filter((item) => item.isComplete).length
50
- const incomplete = items.filter((item) => !item.isComplete).length
51
- return {
52
- completed,
53
- incomplete,
54
- total: items.length,
55
- }
56
- }
57
-
58
- /**
59
- * Check if all tasks are complete
60
- */
61
- export function areAllTasksComplete(items: TaskItem[]): boolean {
62
- if (items.length === 0) return true
63
- return items.every((item) => item.isComplete)
64
- }
65
-
66
- /**
67
- * Extract the promise completion message from output
68
- * Returns null if no completion message found
69
- */
70
- export function extractCompletionPromise(output: string): string | null {
71
- const match = output.match(/<promise>([^<]+)<\/promise>/)
72
- return match && match[1] ? match[1] : null
73
- }
74
-
75
- /**
76
- * Validate that completion message aligns with task status
77
- * Throws an error if the agent claims completion but tasks remain
78
- */
79
- export function validateCompletion(
80
- completionMessage: string | null,
81
- allTasksComplete: boolean,
82
- ): void {
83
- if (
84
- completionMessage &&
85
- completionMessage.toUpperCase() === "COMPLETE" &&
86
- !allTasksComplete
87
- ) {
88
- throw new Error(
89
- "Agent claimed completion with <promise>COMPLETE</promise> but incomplete tasks remain in TASK.md. " +
90
- "This indicates the agent did not complete all work as required.",
91
- )
92
- }
93
- }
@@ -1,22 +0,0 @@
1
- # Agent Instructions
2
-
3
- ## TASK.md
4
-
5
- The `TASK.md` file describes the task being performed and should be kept updated as work progresses. This file serves as a living record of:
6
-
7
- - What is being built or fixed
8
- - Current progress and status
9
- - Remaining work items
10
- - Any important context or decisions
11
-
12
- All work on this repository should begin by reading and understanding `TASK.md`. Whenever any significant progress is made, `TASK.md` should be updated to reflect the current state of work.
13
-
14
- **Note:** When you receive the prompt "Start the task", `TASK.md` is already in your context. DO NOT re-read it — instead, proceed directly with the work described in the task.
15
-
16
- ## Commit Messages
17
-
18
- When creating commit messages, do not reference changes to `TASK.md`, `AGENTS.md`, or any files tracked in `agency.json` (such as `opencode.json`). These are project management and configuration files that should not be mentioned in commit messages. Focus commit messages on actual code changes, features, fixes, and refactoring.
19
-
20
- **Important:** Even when the only changes in a commit are to tracked files like `TASK.md`, you should still commit those changes. These updates should be co-located with the code changes they describe. Simply omit mentioning the tracked files in the commit message and focus the message on the actual code changes being made.
21
-
22
- If a commit only updates `TASK.md`, use `--no-verify` to skip precommit hooks. Do not use `--no-verify` if the commit includes changes to any other file.
@@ -1,11 +0,0 @@
1
- # Repo Instructions
2
-
3
- Follow these instructions when working in this repository.
4
-
5
- You should have already read @AGENCY.md to understand how agency is use to work on features.
6
-
7
- When you have read this file, move on to reading @TODO.md to understand the specific tasks.
8
-
9
- ## Rules
10
-
11
- {human: fill this in}
@@ -1,3 +0,0 @@
1
- # Claude Code Instructions
2
-
3
- This project uses the agency CLI for managing development tasks and templates.
package/templates/TASK.md DELETED
@@ -1,5 +0,0 @@
1
- {task}
2
-
3
- ## Tasks
4
-
5
- - [ ] Populate this list with tasks
@@ -1,4 +0,0 @@
1
- {
2
- "$schema": "https://opencode.ai/config.json",
3
- "instructions": ["AGENCY.md", "TASK.md"]
4
- }