@avantmedia/af 0.0.1
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.
- package/LICENSE +21 -0
- package/README.md +539 -0
- package/af +2 -0
- package/bun-upgrade.ts +130 -0
- package/commands/bun.ts +55 -0
- package/commands/changes.ts +35 -0
- package/commands/e2e.ts +12 -0
- package/commands/help.ts +236 -0
- package/commands/install-extension.ts +133 -0
- package/commands/jira.ts +577 -0
- package/commands/licenses.ts +32 -0
- package/commands/npm.ts +55 -0
- package/commands/scaffold.ts +105 -0
- package/commands/setup.tsx +156 -0
- package/commands/spec.ts +405 -0
- package/commands/stop-hook.ts +90 -0
- package/commands/todo.ts +208 -0
- package/commands/versions.ts +150 -0
- package/commands/watch.ts +344 -0
- package/commands/worktree.ts +424 -0
- package/components/change-select.tsx +71 -0
- package/components/confirm.tsx +41 -0
- package/components/file-conflict.tsx +52 -0
- package/components/input.tsx +53 -0
- package/components/layout.tsx +70 -0
- package/components/messages.tsx +48 -0
- package/components/progress.tsx +71 -0
- package/components/select.tsx +90 -0
- package/components/status-display.tsx +74 -0
- package/components/table.tsx +79 -0
- package/generated/setup-manifest.ts +67 -0
- package/git-worktree.ts +184 -0
- package/main.ts +12 -0
- package/npm-upgrade.ts +117 -0
- package/package.json +83 -0
- package/resources/copy-prompt-reporter.ts +443 -0
- package/router.ts +220 -0
- package/setup/.claude/commands/commit-work.md +47 -0
- package/setup/.claude/commands/complete-work.md +34 -0
- package/setup/.claude/commands/e2e.md +29 -0
- package/setup/.claude/commands/start-work.md +51 -0
- package/setup/.claude/skills/pm/SKILL.md +294 -0
- package/setup/.claude/skills/pm/templates/api-endpoint.md +69 -0
- package/setup/.claude/skills/pm/templates/bug-fix.md +77 -0
- package/setup/.claude/skills/pm/templates/feature.md +87 -0
- package/setup/.claude/skills/pm/templates/ui-component.md +78 -0
- package/utils/change-select-render.tsx +44 -0
- package/utils/claude.ts +9 -0
- package/utils/config.ts +58 -0
- package/utils/env.ts +53 -0
- package/utils/git.ts +120 -0
- package/utils/ink-render.tsx +50 -0
- package/utils/openspec.ts +54 -0
- package/utils/output.ts +104 -0
- package/utils/proposal.ts +160 -0
- package/utils/resources.ts +64 -0
- package/utils/setup-files.ts +230 -0
package/router.ts
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { handleBunUpgrade } from './commands/bun.ts';
|
|
2
|
+
import { handleChanges } from './commands/changes.ts';
|
|
3
|
+
import { handleE2e } from './commands/e2e.ts';
|
|
4
|
+
import { handleHelp } from './commands/help.ts';
|
|
5
|
+
import { handleInstallExtension } from './commands/install-extension.ts';
|
|
6
|
+
import { handleJira } from './commands/jira.ts';
|
|
7
|
+
import { handleLicenses } from './commands/licenses.ts';
|
|
8
|
+
import { handleNpmUpgrade } from './commands/npm.ts';
|
|
9
|
+
import { handleScaffold } from './commands/scaffold.ts';
|
|
10
|
+
import { handleSetup } from './commands/setup.tsx';
|
|
11
|
+
import {
|
|
12
|
+
handleCommitApply,
|
|
13
|
+
handleCommitSave,
|
|
14
|
+
handleSpecApply,
|
|
15
|
+
handleSpecArchive,
|
|
16
|
+
handleSpecPropose,
|
|
17
|
+
} from './commands/spec.ts';
|
|
18
|
+
import { handleStopHook } from './commands/stop-hook.ts';
|
|
19
|
+
import { handleTodo } from './commands/todo.ts';
|
|
20
|
+
import { handleVersionsPush, handleVersionsReset } from './commands/versions.ts';
|
|
21
|
+
import { handleWatch } from './commands/watch.ts';
|
|
22
|
+
import { handleWorktree } from './commands/worktree.ts';
|
|
23
|
+
import { error } from './utils/output.ts';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Route command-line arguments to the appropriate command handler.
|
|
27
|
+
* Parses the command structure and delegates to command modules.
|
|
28
|
+
*
|
|
29
|
+
* @param args - Command-line arguments (excluding node executable and script path)
|
|
30
|
+
* @returns Exit code (0 for success, 1 for error)
|
|
31
|
+
*/
|
|
32
|
+
export async function route(args: string[]): Promise<number> {
|
|
33
|
+
// Handle no arguments - show help
|
|
34
|
+
if (args.length === 0) {
|
|
35
|
+
return await handleHelp();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const [command, subcommand] = args;
|
|
39
|
+
|
|
40
|
+
// Handle --help and -h flags
|
|
41
|
+
if (command === '--help' || command === '-h') {
|
|
42
|
+
return await handleHelp();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Handle command-specific --help flag
|
|
46
|
+
if (subcommand === '--help' || subcommand === '-h') {
|
|
47
|
+
return await handleHelp(command);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Route npm commands
|
|
51
|
+
if (command === 'npm') {
|
|
52
|
+
if (subcommand === 'upgrade') {
|
|
53
|
+
return await handleNpmUpgrade();
|
|
54
|
+
} else if (!subcommand) {
|
|
55
|
+
error('Error: npm command requires a subcommand');
|
|
56
|
+
console.error("Run 'af help npm' for more information.");
|
|
57
|
+
return 1;
|
|
58
|
+
} else {
|
|
59
|
+
error(`Error: Unknown npm subcommand: ${subcommand}`);
|
|
60
|
+
console.error("Run 'af help npm' for available subcommands.");
|
|
61
|
+
return 1;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Route bun commands
|
|
66
|
+
if (command === 'bun') {
|
|
67
|
+
if (subcommand === 'upgrade') {
|
|
68
|
+
return await handleBunUpgrade();
|
|
69
|
+
} else if (!subcommand) {
|
|
70
|
+
error('Error: bun command requires a subcommand');
|
|
71
|
+
console.error("Run 'af help bun' for more information.");
|
|
72
|
+
return 1;
|
|
73
|
+
} else {
|
|
74
|
+
error(`Error: Unknown bun subcommand: ${subcommand}`);
|
|
75
|
+
console.error("Run 'af help bun' for available subcommands.");
|
|
76
|
+
return 1;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Route spec commands
|
|
81
|
+
if (command === 'spec') {
|
|
82
|
+
if (subcommand === 'apply') {
|
|
83
|
+
const changeId = args[2];
|
|
84
|
+
return await handleSpecApply(changeId);
|
|
85
|
+
} else if (subcommand === 'archive') {
|
|
86
|
+
const specId = args[2];
|
|
87
|
+
return await handleSpecArchive(specId);
|
|
88
|
+
} else if (subcommand === 'propose') {
|
|
89
|
+
const proposalText = args.slice(2).join(' ');
|
|
90
|
+
return await handleSpecPropose(proposalText);
|
|
91
|
+
} else if (!subcommand) {
|
|
92
|
+
error('Error: spec command requires a subcommand');
|
|
93
|
+
console.error("Run 'af help spec' for more information.");
|
|
94
|
+
return 1;
|
|
95
|
+
} else {
|
|
96
|
+
error(`Error: Unknown spec subcommand: ${subcommand}`);
|
|
97
|
+
console.error("Run 'af help spec' for available subcommands.");
|
|
98
|
+
return 1;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Route commit commands
|
|
103
|
+
if (command === 'commit') {
|
|
104
|
+
if (subcommand === 'save') {
|
|
105
|
+
// commit save "<message>" [Key=Value...]
|
|
106
|
+
const message = args[2];
|
|
107
|
+
const trailerArgs = args.slice(3);
|
|
108
|
+
return handleCommitSave(message, trailerArgs);
|
|
109
|
+
} else if (subcommand === 'apply' || !subcommand) {
|
|
110
|
+
// Both 'commit apply' and 'commit' (shorthand) do the same thing
|
|
111
|
+
const changeId = subcommand === 'apply' ? args[2] : args[1];
|
|
112
|
+
return await handleCommitApply(changeId);
|
|
113
|
+
} else {
|
|
114
|
+
error(`Error: Unknown commit subcommand: ${subcommand}`);
|
|
115
|
+
console.error("Run 'af help commit' for available subcommands.");
|
|
116
|
+
return 1;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Route shorthand commands
|
|
121
|
+
if (command === 'apply') {
|
|
122
|
+
const changeId = args[1];
|
|
123
|
+
return await handleSpecApply(changeId);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (command === 'propose') {
|
|
127
|
+
const proposalText = args.slice(1).join(' ');
|
|
128
|
+
return await handleSpecPropose(proposalText);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (command === 'archive') {
|
|
132
|
+
const specId = args[1];
|
|
133
|
+
return await handleSpecArchive(specId);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (command === 'changes') {
|
|
137
|
+
// Pass true if any additional arguments were provided
|
|
138
|
+
const hasArgs = args.length > 1;
|
|
139
|
+
return await handleChanges(hasArgs);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Route e2e command
|
|
143
|
+
if (command === 'e2e') {
|
|
144
|
+
return await handleE2e(args.slice(1));
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Route stop-hook command
|
|
148
|
+
if (command === 'stop-hook') {
|
|
149
|
+
return await handleStopHook();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (command === 'todo') {
|
|
153
|
+
// Pass true if any additional arguments were provided
|
|
154
|
+
const hasArgs = args.length > 1;
|
|
155
|
+
return await handleTodo(hasArgs);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (command === 'watch') {
|
|
159
|
+
// Pass true if any additional arguments were provided
|
|
160
|
+
const hasArgs = args.length > 1;
|
|
161
|
+
return await handleWatch(hasArgs);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Route jira commands
|
|
165
|
+
if (command === 'jira') {
|
|
166
|
+
return await handleJira(args.slice(1));
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Route versions commands
|
|
170
|
+
if (command === 'versions') {
|
|
171
|
+
if (subcommand === 'reset') {
|
|
172
|
+
return await handleVersionsReset();
|
|
173
|
+
} else if (subcommand === 'push') {
|
|
174
|
+
return await handleVersionsPush();
|
|
175
|
+
} else if (!subcommand) {
|
|
176
|
+
error('Error: versions command requires a subcommand');
|
|
177
|
+
console.error("Run 'af help versions' for more information.");
|
|
178
|
+
return 1;
|
|
179
|
+
} else {
|
|
180
|
+
error(`Error: Unknown versions subcommand: ${subcommand}`);
|
|
181
|
+
console.error("Run 'af help versions' for available subcommands.");
|
|
182
|
+
return 1;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Route help command
|
|
187
|
+
if (command === 'help') {
|
|
188
|
+
return await handleHelp(subcommand);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Route licenses command
|
|
192
|
+
if (command === 'licenses') {
|
|
193
|
+
return await handleLicenses();
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Route scaffold command
|
|
197
|
+
if (command === 'scaffold') {
|
|
198
|
+
return handleScaffold(args.slice(1));
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Route setup command
|
|
202
|
+
if (command === 'setup') {
|
|
203
|
+
return await handleSetup(args.slice(1));
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Route install-extension command
|
|
207
|
+
if (command === 'install-extension') {
|
|
208
|
+
return await handleInstallExtension();
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Route worktree command
|
|
212
|
+
if (command === 'worktree') {
|
|
213
|
+
return await handleWorktree(args.slice(1));
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Unknown command
|
|
217
|
+
error(`Error: Unknown command: ${command}`);
|
|
218
|
+
console.error("Run 'af help' to see all available commands.");
|
|
219
|
+
return 1;
|
|
220
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Commit Work
|
|
3
|
+
description: Commit all changes with the OpenSpec proposal title and ID as a trailer.
|
|
4
|
+
category: Workflow
|
|
5
|
+
tags: [git, openspec, workflow]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
**Usage**
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
/commit-work [openspec-id] [title]
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Examples:
|
|
15
|
+
- `/commit-work` — Uses the ID and title from context
|
|
16
|
+
- `/commit-work add-user-auth "Add User Authentication"` — Uses provided arguments
|
|
17
|
+
|
|
18
|
+
**Steps**
|
|
19
|
+
|
|
20
|
+
1. **Determine OpenSpec ID and title:**
|
|
21
|
+
- If arguments are provided, use them
|
|
22
|
+
- If you are currently working on an OpenSpec, use that ID and title
|
|
23
|
+
- Otherwise:
|
|
24
|
+
1. Run `openspec list` to find active changes
|
|
25
|
+
2. If exactly one active change exists, use that ID
|
|
26
|
+
3. If multiple changes exist, ask the user which one to use
|
|
27
|
+
4. If no changes exist, ask the user for the ID and title
|
|
28
|
+
5. Extract the title from the first heading in `openspec/changes/<id>/proposal.md`
|
|
29
|
+
|
|
30
|
+
2. **Archive the OpenSpec change (if not already archived):**
|
|
31
|
+
- Check if `openspec/changes/<id>/` directory exists
|
|
32
|
+
- If it exists, perform the OPSX archive workflow:
|
|
33
|
+
1. Check artifact completion: `openspec status --change "<id>" --json`
|
|
34
|
+
2. Check task completion: read `openspec/changes/<id>/tasks.md`, count `- [ ]` vs `- [x]`
|
|
35
|
+
3. Check for delta specs at `openspec/changes/<id>/specs/` — if they exist, perform agent-driven sync to main specs (same as `/opsx:sync`)
|
|
36
|
+
4. Archive: `mkdir -p openspec/changes/archive && mv openspec/changes/<id> openspec/changes/archive/YYYY-MM-DD-<id>`
|
|
37
|
+
5. Ensure everything meets the project's formatting rules (run `bun run format` if needed)
|
|
38
|
+
- If the directory does not exist (already archived), skip this step
|
|
39
|
+
|
|
40
|
+
3. Run the following command to stage all changes and create a commit:
|
|
41
|
+
```bash
|
|
42
|
+
af commit save "<title>" OpenSpec-Id=<openspec-id>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**Reference**
|
|
46
|
+
|
|
47
|
+
- Run `af help commit` for commit subcommand options
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Complete Work
|
|
3
|
+
description: Archive an OpenSpec change and transition the Jira issue to Done.
|
|
4
|
+
category: Workflow
|
|
5
|
+
tags: [jira, openspec, workflow]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
**Usage**
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
/complete-work <issue-key>
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Example: `/complete-work MUSH-123`
|
|
15
|
+
|
|
16
|
+
**Steps**
|
|
17
|
+
|
|
18
|
+
1. Fetch the issue details using `af jira get <issue-key>` to verify it exists and get the summary.
|
|
19
|
+
2. Find the associated OpenSpec change by searching `openspec/changes/*/proposal.md` files for the issue key using grep or by running `openspec list` and checking which change references this issue.
|
|
20
|
+
3. Archive the OpenSpec change using the OPSX workflow:
|
|
21
|
+
1. Check artifact completion: `openspec status --change "<change-id>" --json`
|
|
22
|
+
- If incomplete artifacts, warn but continue
|
|
23
|
+
2. Check task completion: read `openspec/changes/<change-id>/tasks.md`, count `- [ ]` vs `- [x]`
|
|
24
|
+
- If incomplete tasks, warn but continue
|
|
25
|
+
3. Check for delta specs at `openspec/changes/<change-id>/specs/`
|
|
26
|
+
- If delta specs exist, perform agent-driven sync to main specs (same as `/opsx:sync`)
|
|
27
|
+
4. Archive: `mkdir -p openspec/changes/archive && mv openspec/changes/<change-id> openspec/changes/archive/YYYY-MM-DD-<change-id>`
|
|
28
|
+
4. Run the following command: `./scripts/create-commit.sh "<issue-summary>" "<issue-key>"` where `<issue-summary>` is derived from the Jira issue. This adds the issue key as a commit trailer.
|
|
29
|
+
6. Transition the issue to "Done" using `af jira transition <issue-key> --to "Done"`. If this fails, run `af jira transitions <issue-key>` to find the correct completion status name.
|
|
30
|
+
|
|
31
|
+
**Reference**
|
|
32
|
+
|
|
33
|
+
- See `openspec/AGENTS.md` for OpenSpec conventions (Stage 3: Archiving Changes)
|
|
34
|
+
- Run `af jira --help` for Jira CLI options
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Run E2E tests
|
|
3
|
+
description: Run E2E tests and fix any failures
|
|
4
|
+
category: Testing
|
|
5
|
+
tags: [e2e, playwright]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
**Guardrails**
|
|
9
|
+
|
|
10
|
+
- Run only inside Docker via `af e2e` — never run Playwright directly
|
|
11
|
+
- For specific tests: `af e2e npm run e2e -- --grep "pattern"`
|
|
12
|
+
- For specific files: `af e2e npm run e2e -- tests/Feature.spec.ts`
|
|
13
|
+
|
|
14
|
+
**Steps**
|
|
15
|
+
|
|
16
|
+
1. Run `af e2e` (defaults to `--max-failures=1` for fast feedback)
|
|
17
|
+
2. On failure, read the reporter output — it includes error messages, DOM snapshots, and file paths
|
|
18
|
+
3. For deeper debugging, read `./test-results/*/error-context.md` for full page state
|
|
19
|
+
4. Fix the code or test
|
|
20
|
+
5. If the failure is a visual regression from an intentional change, update baselines:
|
|
21
|
+
`af e2e npm run e2e -- --update-snapshots`
|
|
22
|
+
6. Use `--grep "pattern"` to iterate faster on the specific failing test
|
|
23
|
+
7. Once the targeted test passes, run the full suite without `--grep` to confirm nothing else broke
|
|
24
|
+
|
|
25
|
+
**Reference**
|
|
26
|
+
|
|
27
|
+
- Use the `e2e-testing` skill for test patterns, selectors, and debugging tips
|
|
28
|
+
- HTML report: `./playwright-report/index.html`
|
|
29
|
+
- Trace files: `./test-results/*/trace.zip`
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Start Work
|
|
3
|
+
description: Assign a Jira issue to yourself and convert it into an OpenSpec proposal.
|
|
4
|
+
category: Workflow
|
|
5
|
+
tags: [jira, openspec, workflow]
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
**Usage**
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
/start-work [issue-key]
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Examples:
|
|
15
|
+
- `/start-work` — Takes the topmost issue from the backlog
|
|
16
|
+
- `/start-work MUSH-123` — Uses the specified issue
|
|
17
|
+
|
|
18
|
+
**Steps**
|
|
19
|
+
|
|
20
|
+
0. **If no issue-key is provided**, fetch the topmost issue from the backlog:
|
|
21
|
+
1. Detect project key by running `af jira projects --json`
|
|
22
|
+
- If single project: use it
|
|
23
|
+
- If multiple projects: ask the user to choose
|
|
24
|
+
2. Fetch the topmost backlog issue using:
|
|
25
|
+
```bash
|
|
26
|
+
af jira search "project = <PROJECT> AND status = Backlog ORDER BY priority DESC, created ASC" --limit 1 --json
|
|
27
|
+
```
|
|
28
|
+
3. Display the issue summary and ask the user for confirmation before proceeding
|
|
29
|
+
4. If no backlog issues found: inform the user the backlog is empty and stop
|
|
30
|
+
1. Fetch the issue details using `af jira get <issue-key>`.
|
|
31
|
+
2. Assign the issue to yourself using `af jira assign <issue-key> --to $(af jira get <issue-key> --json | jq -r '.reporter.emailAddress')` — but first check who the current user is by looking at the Jira config or asking.
|
|
32
|
+
3. Transition the issue to "In Progress" using `af jira transition <issue-key> --to "In Progress"`. If this fails, run `af jira transitions <issue-key>` to find the correct status name.
|
|
33
|
+
4. Create an OpenSpec change using the artifact workflow:
|
|
34
|
+
- Derive a `change-id` from the issue key and summary (kebab-case, verb-led)
|
|
35
|
+
- Create the change: `openspec new change "<change-id>"`
|
|
36
|
+
- Get the artifact status: `openspec status --change "<change-id>" --json`
|
|
37
|
+
- Get proposal artifact instructions: `openspec instructions proposal --change "<change-id>" --json`
|
|
38
|
+
- Create the proposal artifact using the template from instructions, enriching it with:
|
|
39
|
+
- Jira issue link: `**Jira**: [ISSUE-KEY](jira-url)`
|
|
40
|
+
- Why section derived from Jira issue description
|
|
41
|
+
- What Changes derived from issue details
|
|
42
|
+
- Show the updated status
|
|
43
|
+
5. **STOP and hand off to OPSX workflow**
|
|
44
|
+
|
|
45
|
+
Suggest: "Proposal created. Run `/opsx:continue` to create the next artifact, or `/opsx:ff` to generate all remaining artifacts."
|
|
46
|
+
|
|
47
|
+
**Reference**
|
|
48
|
+
|
|
49
|
+
- See `openspec/AGENTS.md` for OpenSpec conventions
|
|
50
|
+
- Run `af jira --help` for Jira CLI options
|
|
51
|
+
- See `/opsx:new` and `/opsx:ff` for the full artifact workflow
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pm
|
|
3
|
+
description: Project management workflows for sprint planning, epic breakdowns, progress reporting, and backlog grooming. Uses the jira skill for all Jira operations.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Project Manager Skill
|
|
7
|
+
|
|
8
|
+
High-level project management workflows that use the Jira CLI (`jira` skill) for operations.
|
|
9
|
+
|
|
10
|
+
## When to Use This Skill
|
|
11
|
+
|
|
12
|
+
Use the PM skill when the user wants to:
|
|
13
|
+
- Plan sprints or prioritize backlog items
|
|
14
|
+
- Break down epics or features into tasks
|
|
15
|
+
- Generate progress reports or standup summaries
|
|
16
|
+
- Identify risks (overdue, blocked, stale issues)
|
|
17
|
+
- Get project context for informed planning decisions
|
|
18
|
+
- Groom or refine the backlog
|
|
19
|
+
|
|
20
|
+
For individual issue operations (get, update, transition, comment), use the `jira` skill directly.
|
|
21
|
+
|
|
22
|
+
## Prerequisites
|
|
23
|
+
|
|
24
|
+
The `jira` skill must be configured. See `.claude/skills/jira/SKILL.md` for setup.
|
|
25
|
+
|
|
26
|
+
## Sub-Agent Behavior
|
|
27
|
+
|
|
28
|
+
When acting as a PM sub-agent, follow these guidelines:
|
|
29
|
+
|
|
30
|
+
### 1. Always Load Context First
|
|
31
|
+
|
|
32
|
+
Before planning or making recommendations, gather project state:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# Get open sprint issues
|
|
36
|
+
af jira search "project = PROJ AND sprint in openSprints() ORDER BY priority DESC"
|
|
37
|
+
|
|
38
|
+
# Check for blockers
|
|
39
|
+
af jira search "project = PROJ AND (status = Blocked OR labels = blocked)"
|
|
40
|
+
|
|
41
|
+
# Recent activity (last 48h)
|
|
42
|
+
af jira search "project = PROJ AND updated >= -2d ORDER BY updated DESC"
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 2. Use Templates for Consistency
|
|
46
|
+
|
|
47
|
+
When breaking down work, use templates from `.claude/skills/pm/templates/`:
|
|
48
|
+
- `api-endpoint.md` - REST/GraphQL endpoint implementation
|
|
49
|
+
- `ui-component.md` - React component development
|
|
50
|
+
- `bug-fix.md` - Bug investigation and fix
|
|
51
|
+
- `feature.md` - General feature implementation
|
|
52
|
+
|
|
53
|
+
### 3. Validate Before Executing
|
|
54
|
+
|
|
55
|
+
For bulk operations (creating multiple issues, updating priorities):
|
|
56
|
+
1. Show the user what will be created/modified
|
|
57
|
+
2. Wait for confirmation before executing
|
|
58
|
+
3. Execute one operation at a time, reporting progress
|
|
59
|
+
|
|
60
|
+
### 4. Track Dependencies
|
|
61
|
+
|
|
62
|
+
When creating related tasks, use Jira linking:
|
|
63
|
+
- Parent/subtask relationships via `--parent` flag
|
|
64
|
+
- Note blocking relationships in descriptions
|
|
65
|
+
|
|
66
|
+
### 5. Report on Completion
|
|
67
|
+
|
|
68
|
+
After multi-step workflows, provide a summary:
|
|
69
|
+
- What was created/modified
|
|
70
|
+
- Any issues encountered
|
|
71
|
+
- Next recommended actions
|
|
72
|
+
|
|
73
|
+
## Workflows
|
|
74
|
+
|
|
75
|
+
### Load Project Context
|
|
76
|
+
|
|
77
|
+
Gather comprehensive project state before planning:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# 1. Active sprint overview
|
|
81
|
+
af jira search "project = PROJ AND sprint in openSprints() ORDER BY status ASC, priority DESC" --limit 50
|
|
82
|
+
|
|
83
|
+
# 2. Blocked issues requiring attention
|
|
84
|
+
af jira search "project = PROJ AND (status = Blocked OR labels = blocked) ORDER BY priority DESC"
|
|
85
|
+
|
|
86
|
+
# 3. Upcoming deadlines (next 7 days)
|
|
87
|
+
af jira search "project = PROJ AND duedate >= now() AND duedate <= 7d AND status != Done ORDER BY duedate ASC"
|
|
88
|
+
|
|
89
|
+
# 4. Unassigned high-priority items
|
|
90
|
+
af jira search "project = PROJ AND assignee IS EMPTY AND priority in (Highest, High) ORDER BY created ASC"
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Present findings organized by:
|
|
94
|
+
- Sprint progress (done/in-progress/todo counts)
|
|
95
|
+
- Blockers requiring attention
|
|
96
|
+
- Upcoming deadlines
|
|
97
|
+
- Unassigned work
|
|
98
|
+
|
|
99
|
+
### Sprint Planning
|
|
100
|
+
|
|
101
|
+
Help plan upcoming sprints:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
# 1. Check current sprint velocity (completed in last sprint)
|
|
105
|
+
af jira search "project = PROJ AND sprint in closedSprints() AND status = Done ORDER BY resolutiondate DESC" --limit 30
|
|
106
|
+
|
|
107
|
+
# 2. Get backlog candidates (not in any sprint, prioritized)
|
|
108
|
+
af jira search "project = PROJ AND sprint IS EMPTY AND status = Backlog ORDER BY priority DESC, created ASC" --limit 30
|
|
109
|
+
|
|
110
|
+
# 3. Check team capacity (assigned work)
|
|
111
|
+
af jira search "project = PROJ AND assignee IS NOT EMPTY AND status != Done"
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Planning steps:
|
|
115
|
+
1. Calculate velocity from recent sprints
|
|
116
|
+
2. Present top backlog items with estimates
|
|
117
|
+
3. Suggest sprint composition based on capacity
|
|
118
|
+
4. Create issues or move items to sprint after confirmation
|
|
119
|
+
|
|
120
|
+
### Epic Breakdown
|
|
121
|
+
|
|
122
|
+
Break down an epic into implementable tasks:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# 1. Get epic details
|
|
126
|
+
af jira get PROJ-123
|
|
127
|
+
|
|
128
|
+
# 2. Check for existing subtasks
|
|
129
|
+
af jira search "parent = PROJ-123"
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
Breakdown process:
|
|
133
|
+
1. Read the epic description and acceptance criteria
|
|
134
|
+
2. Select appropriate template from `.claude/skills/pm/templates/`
|
|
135
|
+
3. Generate subtask list with estimates
|
|
136
|
+
4. Present for review
|
|
137
|
+
5. Create subtasks after confirmation:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
af jira create --project PROJ --type Sub-task --summary "Task title" --parent PROJ-123
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Progress Report
|
|
144
|
+
|
|
145
|
+
Generate status reports:
|
|
146
|
+
|
|
147
|
+
**Daily Report:**
|
|
148
|
+
```bash
|
|
149
|
+
# Completed yesterday
|
|
150
|
+
af jira search "project = PROJ AND status changed to Done AFTER -1d"
|
|
151
|
+
|
|
152
|
+
# In progress today
|
|
153
|
+
af jira search "project = PROJ AND status = 'In Progress' ORDER BY assignee"
|
|
154
|
+
|
|
155
|
+
# Blocked
|
|
156
|
+
af jira search "project = PROJ AND (status = Blocked OR labels = blocked)"
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Weekly Report:**
|
|
160
|
+
```bash
|
|
161
|
+
# Completed this week
|
|
162
|
+
af jira search "project = PROJ AND status changed to Done AFTER -7d ORDER BY resolutiondate DESC"
|
|
163
|
+
|
|
164
|
+
# Created this week
|
|
165
|
+
af jira search "project = PROJ AND created >= -7d ORDER BY created DESC"
|
|
166
|
+
|
|
167
|
+
# Scope changes (added to sprint mid-week)
|
|
168
|
+
af jira search "project = PROJ AND sprint in openSprints() AND created >= -7d"
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
**Sprint Report:**
|
|
172
|
+
```bash
|
|
173
|
+
# Sprint completion
|
|
174
|
+
af jira search "project = PROJ AND sprint in openSprints()" --limit 100
|
|
175
|
+
|
|
176
|
+
# Calculate: done / total issues
|
|
177
|
+
# Identify: carried over items, added mid-sprint items
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Standup Summary
|
|
181
|
+
|
|
182
|
+
Generate daily standup content from Jira activity:
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
# Done (status changed to Done in last 24h)
|
|
186
|
+
af jira search "project = PROJ AND status changed to Done AFTER -1d"
|
|
187
|
+
|
|
188
|
+
# In Progress (currently being worked on)
|
|
189
|
+
af jira search "project = PROJ AND status = 'In Progress' AND assignee = currentUser()"
|
|
190
|
+
|
|
191
|
+
# Blockers
|
|
192
|
+
af jira search "project = PROJ AND (status = Blocked OR labels = blocked) AND assignee = currentUser()"
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Format as:
|
|
196
|
+
- **Done**: [list of completed items]
|
|
197
|
+
- **Today**: [list of in-progress items]
|
|
198
|
+
- **Blockers**: [list of blocked items with reasons]
|
|
199
|
+
|
|
200
|
+
### Risk Identification
|
|
201
|
+
|
|
202
|
+
Find issues that need attention:
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
# Overdue (past due date, not done)
|
|
206
|
+
af jira search "project = PROJ AND duedate < now() AND status != Done ORDER BY duedate ASC"
|
|
207
|
+
|
|
208
|
+
# Stale (no updates in 7+ days, not done)
|
|
209
|
+
af jira search "project = PROJ AND status != Done AND updated < -7d ORDER BY updated ASC"
|
|
210
|
+
|
|
211
|
+
# Blocked
|
|
212
|
+
af jira search "project = PROJ AND (status = Blocked OR labels = blocked)"
|
|
213
|
+
|
|
214
|
+
# Scope creep (added to sprint after start)
|
|
215
|
+
af jira search "project = PROJ AND sprint in openSprints() AND created >= startOfSprint()"
|
|
216
|
+
|
|
217
|
+
# Under-resourced (unassigned high priority)
|
|
218
|
+
af jira search "project = PROJ AND assignee IS EMPTY AND priority in (Highest, High) AND status != Done"
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Categorize and present:
|
|
222
|
+
- **Critical**: Overdue items, high-priority blockers
|
|
223
|
+
- **Warning**: Stale items, scope creep indicators
|
|
224
|
+
- **Attention**: Unassigned high-priority work
|
|
225
|
+
|
|
226
|
+
### Backlog Grooming
|
|
227
|
+
|
|
228
|
+
Help prioritize and refine backlog:
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
# Get backlog items
|
|
232
|
+
af jira search "project = PROJ AND sprint IS EMPTY AND status = Backlog ORDER BY created ASC" --limit 50
|
|
233
|
+
|
|
234
|
+
# Check for duplicates or related items
|
|
235
|
+
af jira search "project = PROJ AND summary ~ 'keyword'"
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Grooming activities:
|
|
239
|
+
1. Review items for clarity and completeness
|
|
240
|
+
2. Suggest priority adjustments based on:
|
|
241
|
+
- Age (older items may need re-evaluation)
|
|
242
|
+
- Dependencies (blocking other work)
|
|
243
|
+
- Business value indicators in description
|
|
244
|
+
3. Identify candidates for archiving (very old, low priority)
|
|
245
|
+
4. Flag items needing more detail
|
|
246
|
+
|
|
247
|
+
To update priority after confirmation:
|
|
248
|
+
```bash
|
|
249
|
+
af jira update PROJ-123 --priority High
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Dependency Analysis
|
|
253
|
+
|
|
254
|
+
Map dependencies for an issue:
|
|
255
|
+
|
|
256
|
+
```bash
|
|
257
|
+
# Get issue with links
|
|
258
|
+
af jira get PROJ-123
|
|
259
|
+
|
|
260
|
+
# Find related issues by summary/labels
|
|
261
|
+
af jira search "project = PROJ AND (summary ~ 'related-keyword' OR labels = related-label)"
|
|
262
|
+
|
|
263
|
+
# Find potential blockers (same component, earlier in pipeline)
|
|
264
|
+
af jira search "project = PROJ AND component = 'Component' AND status != Done"
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
Present as:
|
|
268
|
+
- **Blocks**: Issues this blocks
|
|
269
|
+
- **Blocked by**: Issues blocking this
|
|
270
|
+
- **Related**: Similar or dependent work
|
|
271
|
+
|
|
272
|
+
## JQL Quick Reference
|
|
273
|
+
|
|
274
|
+
Common queries for project management:
|
|
275
|
+
|
|
276
|
+
| Purpose | JQL |
|
|
277
|
+
|---------|-----|
|
|
278
|
+
| My open issues | `assignee = currentUser() AND status != Done` |
|
|
279
|
+
| Open sprint | `project = PROJ AND sprint in openSprints()` |
|
|
280
|
+
| Blocked | `project = PROJ AND (status = Blocked OR labels = blocked)` |
|
|
281
|
+
| Overdue | `project = PROJ AND duedate < now() AND status != Done` |
|
|
282
|
+
| Stale (7d) | `project = PROJ AND status != Done AND updated < -7d` |
|
|
283
|
+
| Unassigned | `project = PROJ AND assignee IS EMPTY` |
|
|
284
|
+
| High priority | `project = PROJ AND priority in (Highest, High)` |
|
|
285
|
+
| Created this week | `project = PROJ AND created >= -7d` |
|
|
286
|
+
| Done this week | `project = PROJ AND status changed to Done AFTER -7d` |
|
|
287
|
+
| Backlog | `project = PROJ AND sprint IS EMPTY AND status = Backlog` |
|
|
288
|
+
|
|
289
|
+
## Tips
|
|
290
|
+
|
|
291
|
+
- **Replace PROJ**: Substitute with actual project key in all queries
|
|
292
|
+
- **Adjust time ranges**: `-7d`, `-2d`, etc. can be customized
|
|
293
|
+
- **Use --json for parsing**: When you need to analyze results programmatically
|
|
294
|
+
- **Combine with jira**: This skill provides workflows; jira provides operations
|