@slamb2k/mad-skills 2.0.24 → 2.0.26
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/.claude-plugin/plugin.json +1 -1
- package/package.json +1 -1
- package/skills/build/SKILL.md +28 -13
- package/skills/build/references/stage-prompts.md +6 -4
- package/skills/build/tests/evals.json +8 -0
- package/skills/manifest.json +6 -6
- package/skills/prime/SKILL.md +3 -3
- package/skills/ship/SKILL.md +123 -29
- package/skills/ship/references/stage-prompts.md +190 -32
- package/skills/speccy/SKILL.md +28 -19
- package/skills/speccy/references/spec-template.md +113 -0
package/package.json
CHANGED
package/skills/build/SKILL.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: build
|
|
3
3
|
description: Context-isolated feature development pipeline. Takes a detailed design/plan as argument and executes the full feature-dev lifecycle (explore, question, architect, implement, review, ship) inside subagents so the primary conversation stays compact. Use when you have a well-defined plan and want autonomous execution with minimal context window consumption.
|
|
4
|
-
argument-hint: <
|
|
5
|
-
allowed-tools: Bash, Read, Write, Edit, Glob, Grep, Agent, AskUserQuestion
|
|
4
|
+
argument-hint: <plan text or spec file path> [--skip-questions] [--skip-review] [--no-ship] [--parallel-impl]
|
|
5
|
+
allowed-tools: Bash, Read, Write, Edit, Glob, Grep, Agent, AskUserQuestion, TaskCreate, TaskUpdate, TaskGet, TaskList
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Build - Context-Isolated Feature Development
|
|
@@ -103,16 +103,14 @@ For each row, in order:
|
|
|
103
103
|
|
|
104
104
|
1. Capture **PLAN** (the user's argument) and **FLAGS**
|
|
105
105
|
2. **Load project context** — invoke `/prime` to load domain-specific context
|
|
106
|
-
(CLAUDE.md,
|
|
107
|
-
manually scanning CLAUDE.md and
|
|
106
|
+
(CLAUDE.md, specs, memory). If /prime is unavailable, fall back to
|
|
107
|
+
manually scanning CLAUDE.md and specs/ directory.
|
|
108
108
|
3. Detect project type using `references/project-detection.md` to populate
|
|
109
109
|
**PROJECT_CONFIG** (language, test_runner, test_setup)
|
|
110
|
-
3. Check for outstanding
|
|
110
|
+
3. Check for outstanding items from previous work:
|
|
111
|
+
- Query persistent tasks via `TaskList` for incomplete items
|
|
111
112
|
- Search CLAUDE.md for a "Known Issues" or "Open Questions" section
|
|
112
|
-
- Search
|
|
113
|
-
- Search memory (if available) for recent items of type "task" or
|
|
114
|
-
"open_question" that are unresolved
|
|
115
|
-
- Check for `DEBRIEF_ITEMS` in any recent build logs
|
|
113
|
+
- Search memory (if available) for recent unresolved items
|
|
116
114
|
4. If outstanding items found, present via AskUserQuestion:
|
|
117
115
|
```
|
|
118
116
|
"Found {count} outstanding items from previous work:"
|
|
@@ -125,7 +123,23 @@ For each row, in order:
|
|
|
125
123
|
Items marked "incorporate" get appended to the PLAN as additional
|
|
126
124
|
requirements for Stage 1 to explore.
|
|
127
125
|
- **"No, proceed with the build"** → continue normally
|
|
128
|
-
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Plan Resolution
|
|
129
|
+
|
|
130
|
+
Before Stage 1, resolve the PLAN argument into content:
|
|
131
|
+
|
|
132
|
+
1. **File detection** — If the argument contains `/` or ends with
|
|
133
|
+
`.md`, `.yaml`, `.json`, or `.txt`, treat it as a file path:
|
|
134
|
+
- Try reading the path as-is
|
|
135
|
+
- If not found, try `specs/{arg}`
|
|
136
|
+
- If found, use file content as PLAN
|
|
137
|
+
- If not found at any location, treat the original argument as free-form text
|
|
138
|
+
2. **Free-form text** — If not a file path (or file not found), use the argument
|
|
139
|
+
verbatim as PLAN
|
|
140
|
+
3. **Display** — In the Input box, show the resolved source:
|
|
141
|
+
- File: `Plan: {file path} ({line count} lines)`
|
|
142
|
+
- Text: `Plan: inline ({word count} words)`
|
|
129
143
|
|
|
130
144
|
---
|
|
131
145
|
|
|
@@ -303,8 +317,9 @@ Invoke the `/ship` skill:
|
|
|
303
317
|
Options:
|
|
304
318
|
- **"Fix now"** → create a task list of resolution activities for
|
|
305
319
|
each item; present for user confirmation, then work through them
|
|
306
|
-
- **"Create tasks for future sessions"** →
|
|
307
|
-
|
|
320
|
+
- **"Create tasks for future sessions"** → use `TaskCreate` for each
|
|
321
|
+
item as a persistent task, with category as prefix and suggested
|
|
322
|
+
action as description
|
|
308
323
|
- **"Note and continue"** → acknowledge items without formal tracking;
|
|
309
324
|
log to memory (if exists) or as source file comments. No further action.
|
|
310
325
|
- **"Let me choose per item"** → present each individually with full
|
|
@@ -337,7 +352,7 @@ Invoke the `/ship` skill:
|
|
|
337
352
|
│ Findings addressed: {count fixed} / {count found}
|
|
338
353
|
│
|
|
339
354
|
│ 📊 Debrief: {count resolved} / {count surfaced}
|
|
340
|
-
│ {list of created
|
|
355
|
+
│ {list of created tasks}
|
|
341
356
|
│
|
|
342
357
|
│ 🔗 Links
|
|
343
358
|
│ PR: {pr_url}
|
|
@@ -385,9 +385,10 @@ Options:
|
|
|
385
385
|
for user confirmation, then work through them.
|
|
386
386
|
|
|
387
387
|
- "Create tasks for future sessions"
|
|
388
|
-
→ For each item, create a persistent task
|
|
389
|
-
|
|
390
|
-
|
|
388
|
+
→ For each item, use TaskCreate to create a persistent task with:
|
|
389
|
+
title: "[{category}] {summary}"
|
|
390
|
+
description: "{description}\n\nEvidence: {evidence}\nSuggested action: {suggested_action}"
|
|
391
|
+
Format: one task per item for granular tracking.
|
|
391
392
|
|
|
392
393
|
- "Note and continue"
|
|
393
394
|
→ Acknowledge items without formal tracking. Log to memory (if memory
|
|
@@ -398,8 +399,9 @@ Options:
|
|
|
398
399
|
→ Present each item individually via AskUserQuestion. Show the full
|
|
399
400
|
`description`, `evidence`, and `impact` fields so the user has
|
|
400
401
|
enough context to decide. Options per item:
|
|
401
|
-
"Fix now" / "
|
|
402
|
+
"Fix now" / "Create task" / "Explain more" / "Note and continue"
|
|
402
403
|
- "Fix now": launch a general-purpose subagent to resolve
|
|
404
|
+
- "Create task": use TaskCreate to persist for future sessions
|
|
403
405
|
- "Explain more": read the relevant source files/reports cited in
|
|
404
406
|
`evidence`, summarise the context, then re-present the same item
|
|
405
407
|
with the expanded explanation
|
|
@@ -17,6 +17,14 @@
|
|
|
17
17
|
{ "type": "semantic", "value": "Describes a multi-stage development lifecycle that includes exploration, architecture design, implementation, code review, and shipping, with stages running in isolated subagents" }
|
|
18
18
|
]
|
|
19
19
|
},
|
|
20
|
+
{
|
|
21
|
+
"name": "file-path-detection",
|
|
22
|
+
"prompt": "Build specs/user-auth.md",
|
|
23
|
+
"assertions": [
|
|
24
|
+
{ "type": "contains", "value": "██" },
|
|
25
|
+
{ "type": "semantic", "value": "Detects that the argument is a file path (contains / or ends with .md) and attempts to read it as a spec file rather than treating it as literal plan text. Shows the resolved file path in the Input display." }
|
|
26
|
+
]
|
|
27
|
+
},
|
|
20
28
|
{
|
|
21
29
|
"name": "flag-handling",
|
|
22
30
|
"prompt": "Build --skip-questions --no-ship: Refactor the auth module to use middleware pattern",
|
package/skills/manifest.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"generated": "2026-03-
|
|
2
|
+
"generated": "2026-03-12T03:25:58.495Z",
|
|
3
3
|
"count": 10,
|
|
4
4
|
"skills": [
|
|
5
5
|
{
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"name": "build",
|
|
17
17
|
"directory": "build",
|
|
18
18
|
"description": "Context-isolated feature development pipeline. Takes a detailed design/plan as argument and executes the full feature-dev lifecycle (explore, question, architect, implement, review, ship) inside subagents so the primary conversation stays compact. Use when you have a well-defined plan and want autonomous execution with minimal context window consumption.",
|
|
19
|
-
"lines":
|
|
19
|
+
"lines": 378,
|
|
20
20
|
"hasScripts": false,
|
|
21
21
|
"hasReferences": true,
|
|
22
22
|
"hasAssets": false,
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
{
|
|
56
56
|
"name": "prime",
|
|
57
57
|
"directory": "prime",
|
|
58
|
-
"description": "\"Load project context before implementing features or making architectural decisions. Invoke proactively at the start of significant work on any project. Scans CLAUDE.md, README,
|
|
58
|
+
"description": "\"Load project context before implementing features or making architectural decisions. Invoke proactively at the start of significant work on any project. Scans CLAUDE.md, README, specs/, docs/, and source structure to build a context summary. Supports optional domain hints to focus on specific areas of the codebase. Use when you need project conventions, architecture understanding, or domain context before coding.\"",
|
|
59
59
|
"lines": 148,
|
|
60
60
|
"hasScripts": false,
|
|
61
61
|
"hasReferences": true,
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
"name": "ship",
|
|
77
77
|
"directory": "ship",
|
|
78
78
|
"description": "\"Ship changes through the full PR lifecycle. Use after completing feature work to commit, push, create PR, wait for checks, and merge. Handles the entire workflow: syncs with main, creates feature branch if needed, groups commits logically with semantic messages, creates detailed PR, monitors CI, fixes issues, squash merges, and cleans up. Invoke when work is ready to ship.\"",
|
|
79
|
-
"lines":
|
|
79
|
+
"lines": 356,
|
|
80
80
|
"hasScripts": false,
|
|
81
81
|
"hasReferences": true,
|
|
82
82
|
"hasAssets": false,
|
|
@@ -85,8 +85,8 @@
|
|
|
85
85
|
{
|
|
86
86
|
"name": "speccy",
|
|
87
87
|
"directory": "speccy",
|
|
88
|
-
"description": "Deep-dive interview skill for creating comprehensive specifications. Reviews existing code and docs, then interviews the user through multiple rounds of targeted questions covering technical implementation, UI/UX, concerns, and tradeoffs. Produces a structured spec
|
|
89
|
-
"lines":
|
|
88
|
+
"description": "Deep-dive interview skill for creating comprehensive specifications. Reviews existing code and docs, then interviews the user through multiple rounds of targeted questions covering technical implementation, UI/UX, concerns, and tradeoffs. Produces a structured spec in specs/. Use when starting a new feature, system, or major change that needs a spec.",
|
|
89
|
+
"lines": 241,
|
|
90
90
|
"hasScripts": false,
|
|
91
91
|
"hasReferences": true,
|
|
92
92
|
"hasAssets": false,
|
package/skills/prime/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: prime
|
|
3
|
-
description: "Load project context before implementing features or making architectural decisions. Invoke proactively at the start of significant work on any project. Scans CLAUDE.md, README,
|
|
3
|
+
description: "Load project context before implementing features or making architectural decisions. Invoke proactively at the start of significant work on any project. Scans CLAUDE.md, README, specs/, docs/, and source structure to build a context summary. Supports optional domain hints to focus on specific areas of the codebase. Use when you need project conventions, architecture understanding, or domain context before coding."
|
|
4
4
|
argument-hint: "[domain hints: comma-separated directory or topic names to focus on]"
|
|
5
5
|
allowed-tools: Read, Glob, Grep, LS, Agent
|
|
6
6
|
---
|
|
@@ -66,7 +66,7 @@ subagent — the primary thread only sees a structured PRIME_REPORT.
|
|
|
66
66
|
|
|
67
67
|
Extract domain hints from the request (comma-separated). These are directory
|
|
68
68
|
names or topic keywords to focus the context scan on. If no domain specified,
|
|
69
|
-
load core context only (CLAUDE.md, README,
|
|
69
|
+
load core context only (CLAUDE.md, README, specs/).
|
|
70
70
|
|
|
71
71
|
## Step 2: Load Context via Subagent
|
|
72
72
|
|
|
@@ -92,7 +92,7 @@ Limit PRIME_REPORT to 30 lines maximum.
|
|
|
92
92
|
|
|
93
93
|
1. CLAUDE.md — Project conventions, architecture, instructions
|
|
94
94
|
2. README.md — Project overview, setup, usage
|
|
95
|
-
3.
|
|
95
|
+
3. specs/ — Project specifications and roadmap (scan directory if present)
|
|
96
96
|
4. docs/ — Documentation directory (scan if present)
|
|
97
97
|
|
|
98
98
|
If a file is missing, record as NOT FOUND and continue.
|
package/skills/ship/SKILL.md
CHANGED
|
@@ -72,51 +72,140 @@ Parse optional flags from the request:
|
|
|
72
72
|
|
|
73
73
|
---
|
|
74
74
|
|
|
75
|
+
## Platform Detection
|
|
76
|
+
|
|
77
|
+
Detect the hosting platform **before** pre-flight so dependency checks are
|
|
78
|
+
platform-specific:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
REMOTE_URL=$(git remote get-url origin 2>/dev/null)
|
|
82
|
+
if echo "$REMOTE_URL" | grep -qiE 'dev\.azure\.com|visualstudio\.com'; then
|
|
83
|
+
PLATFORM="azdo"
|
|
84
|
+
elif echo "$REMOTE_URL" | grep -qi 'github\.com'; then
|
|
85
|
+
PLATFORM="github"
|
|
86
|
+
else
|
|
87
|
+
PLATFORM="github" # default fallback
|
|
88
|
+
fi
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Pass `{PLATFORM}` into all stage prompts. Each stage uses the appropriate
|
|
92
|
+
CLI tool: `gh` for GitHub, `az repos`/`az pipelines` for Azure DevOps.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
75
96
|
## Pre-flight
|
|
76
97
|
|
|
77
|
-
Before starting, check all dependencies in this table
|
|
98
|
+
Before starting, check all dependencies in this table. The table contains
|
|
99
|
+
**all** dependencies — some are platform-conditional (see notes after table).
|
|
78
100
|
|
|
79
101
|
| Dependency | Type | Check | Required | Resolution | Detail |
|
|
80
102
|
|-----------|------|-------|----------|------------|--------|
|
|
81
103
|
| git | cli | `git --version` | yes | stop | Install from https://git-scm.com |
|
|
82
104
|
| gh | cli | `gh --version` | yes | url | https://cli.github.com |
|
|
83
|
-
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
105
|
+
| az devops | cli | `az devops -h 2>/dev/null` | no | fallback | Falls back to REST API with PAT; see AzDO tooling below |
|
|
106
|
+
| ship-analyzer | agent | `~/.claude/agents/ship-analyzer.md` or `~/.claude/plugins/marketplaces/slamb2k/agents/ship-analyzer.md` | no | fallback | Uses general-purpose agent |
|
|
107
|
+
|
|
108
|
+
**Platform-conditional rules:**
|
|
109
|
+
- **`gh`**: Only required when `PLATFORM == github`. Skip for AzDO repos.
|
|
110
|
+
- **`az devops`**: Only checked when `PLATFORM == azdo`. Skip for GitHub repos.
|
|
111
|
+
|
|
112
|
+
For each applicable row, in order:
|
|
113
|
+
1. Skip rows that don't apply to the detected `{PLATFORM}`
|
|
114
|
+
2. Run the Check command (for cli/npm) or test file existence (for agent/skill)
|
|
115
|
+
3. If found: continue silently
|
|
116
|
+
4. If missing: apply Resolution strategy
|
|
89
117
|
- **stop**: notify user with Detail, halt execution
|
|
90
118
|
- **url**: notify user with Detail (install link), halt execution
|
|
91
119
|
- **install**: notify user, run the command in Detail, continue if successful
|
|
92
120
|
- **ask**: notify user, offer to run command in Detail, continue either way (or halt if required)
|
|
93
121
|
- **fallback**: notify user with Detail, continue with degraded behavior
|
|
94
|
-
|
|
122
|
+
5. After all checks: summarize what's available and what's degraded
|
|
95
123
|
|
|
96
|
-
|
|
97
|
-
substituted into all stage prompts as `{REMOTE}` and `{DEFAULT_BRANCH}`.
|
|
98
|
-
|
|
99
|
-
### Platform Detection
|
|
124
|
+
### AzDO Tooling Detection
|
|
100
125
|
|
|
101
|
-
|
|
126
|
+
When `PLATFORM == azdo`, determine which tooling is available. Set `AZDO_MODE`
|
|
127
|
+
for use in all subsequent stages:
|
|
102
128
|
|
|
103
129
|
```bash
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
PLATFORM="azdo"
|
|
107
|
-
elif echo "$REMOTE_URL" | grep -qi 'github\.com'; then
|
|
108
|
-
PLATFORM="github"
|
|
130
|
+
if az devops -h &>/dev/null; then
|
|
131
|
+
AZDO_MODE="cli"
|
|
109
132
|
else
|
|
110
|
-
|
|
133
|
+
AZDO_MODE="rest"
|
|
111
134
|
fi
|
|
112
135
|
```
|
|
113
136
|
|
|
114
|
-
|
|
115
|
-
|
|
137
|
+
- **`cli`**: Use `az repos` / `az pipelines` commands (preferred)
|
|
138
|
+
- **`rest`**: Use Azure DevOps REST API via `curl`. Requires a PAT (personal
|
|
139
|
+
access token) in `AZURE_DEVOPS_EXT_PAT` or `AZDO_PAT` env var. If no PAT
|
|
140
|
+
is found, prompt the user to either install the CLI or set the env var.
|
|
141
|
+
|
|
142
|
+
Report in pre-flight:
|
|
143
|
+
- ✅ `az devops cli` — version found
|
|
144
|
+
- ⚠️ `az devops cli` — not found → using REST API fallback
|
|
145
|
+
- ❌ `az devops cli` — not found, no PAT configured → halt with setup instructions
|
|
146
|
+
|
|
147
|
+
### AzDO Configuration Validation
|
|
148
|
+
|
|
149
|
+
When `PLATFORM == azdo`, extract organization and project from the remote URL
|
|
150
|
+
and validate they are usable. These values are needed by every `az repos` /
|
|
151
|
+
`az pipelines` command and every REST API call.
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
# Extract org and project from remote URL patterns:
|
|
155
|
+
# https://dev.azure.com/{ORG}/{PROJECT}/_git/{REPO}
|
|
156
|
+
# https://{ORG}@dev.azure.com/{ORG}/{PROJECT}/_git/{REPO}
|
|
157
|
+
# {ORG}@vs-ssh.visualstudio.com:v3/{ORG}/{PROJECT}/{REPO}
|
|
158
|
+
|
|
159
|
+
REMOTE_URL=$(git remote get-url origin 2>/dev/null)
|
|
160
|
+
|
|
161
|
+
if echo "$REMOTE_URL" | grep -q 'dev\.azure\.com'; then
|
|
162
|
+
# HTTPS format: https://dev.azure.com/{ORG}/{PROJECT}/_git/{REPO}
|
|
163
|
+
# Also handles: https://{ORG}@dev.azure.com/{ORG}/{PROJECT}/_git/{REPO}
|
|
164
|
+
AZDO_ORG=$(echo "$REMOTE_URL" | sed -n 's|.*dev\.azure\.com/\([^/]*\)/.*|\1|p')
|
|
165
|
+
AZDO_PROJECT=$(echo "$REMOTE_URL" | sed -n 's|.*dev\.azure\.com/[^/]*/\([^/]*\)/.*|\1|p')
|
|
166
|
+
AZDO_ORG_URL="https://dev.azure.com/$AZDO_ORG"
|
|
167
|
+
elif echo "$REMOTE_URL" | grep -q 'vs-ssh\.visualstudio\.com'; then
|
|
168
|
+
# SSH format: {ORG}@vs-ssh.visualstudio.com:v3/{ORG}/{PROJECT}/{REPO}
|
|
169
|
+
AZDO_ORG=$(echo "$REMOTE_URL" | sed -n 's|.*vs-ssh\.visualstudio\.com:v3/\([^/]*\)/.*|\1|p')
|
|
170
|
+
AZDO_PROJECT=$(echo "$REMOTE_URL" | sed -n 's|.*vs-ssh\.visualstudio\.com:v3/[^/]*/\([^/]*\)/.*|\1|p')
|
|
171
|
+
AZDO_ORG_URL="https://dev.azure.com/$AZDO_ORG"
|
|
172
|
+
elif echo "$REMOTE_URL" | grep -q 'visualstudio\.com'; then
|
|
173
|
+
# Legacy HTTPS format: https://{ORG}.visualstudio.com/{PROJECT}/_git/{REPO}
|
|
174
|
+
AZDO_ORG=$(echo "$REMOTE_URL" | sed -n 's|.*//\([^.]*\)\.visualstudio\.com.*|\1|p')
|
|
175
|
+
AZDO_PROJECT=$(echo "$REMOTE_URL" | sed -n 's|.*/\([^/]*\)/_git/.*|\1|p')
|
|
176
|
+
AZDO_ORG_URL="https://dev.azure.com/$AZDO_ORG"
|
|
177
|
+
fi
|
|
116
178
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
179
|
+
if [ -z "$AZDO_ORG" ] || [ -z "$AZDO_PROJECT" ]; then
|
|
180
|
+
echo "❌ Could not extract organization/project from remote URL"
|
|
181
|
+
echo " Remote: $REMOTE_URL"
|
|
182
|
+
echo ""
|
|
183
|
+
echo "Ensure the remote URL follows one of these formats:"
|
|
184
|
+
echo " https://dev.azure.com/{ORG}/{PROJECT}/_git/{REPO}"
|
|
185
|
+
echo " https://{ORG}.visualstudio.com/{PROJECT}/_git/{REPO}"
|
|
186
|
+
echo " {ORG}@vs-ssh.visualstudio.com:v3/{ORG}/{PROJECT}/{REPO}"
|
|
187
|
+
# HALT — cannot proceed without org/project context
|
|
188
|
+
fi
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
When `AZDO_MODE == cli`, also configure the defaults so commands work correctly:
|
|
192
|
+
```bash
|
|
193
|
+
az devops configure --defaults organization="$AZDO_ORG_URL" project="$AZDO_PROJECT"
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
When `AZDO_MODE == rest`, store these for API calls:
|
|
197
|
+
- Base URL: `$AZDO_ORG_URL/$AZDO_PROJECT/_apis`
|
|
198
|
+
- Auth header: `Authorization: Basic $(echo -n ":$PAT" | base64)`
|
|
199
|
+
|
|
200
|
+
Report in pre-flight:
|
|
201
|
+
- ✅ `azdo context` — org: `{AZDO_ORG}`, project: `{AZDO_PROJECT}`
|
|
202
|
+
- ❌ `azdo context` — could not parse from remote URL → halt with instructions
|
|
203
|
+
|
|
204
|
+
Pass `{AZDO_MODE}`, `{AZDO_ORG}`, `{AZDO_PROJECT}`, `{AZDO_ORG_URL}` into
|
|
205
|
+
all stage prompts alongside `{PLATFORM}`.
|
|
206
|
+
|
|
207
|
+
Read `default_branch` and `remote` from Stage 1's SYNC_REPORT. These are
|
|
208
|
+
substituted into all stage prompts as `{REMOTE}` and `{DEFAULT_BRANCH}`.
|
|
120
209
|
|
|
121
210
|
---
|
|
122
211
|
|
|
@@ -155,14 +244,16 @@ Task(
|
|
|
155
244
|
> **Fallback:** If `ship-analyzer` is not available, use `subagent_type: "general-purpose"`.
|
|
156
245
|
|
|
157
246
|
Substitute `{USER_INTENT}`, `{FILES_TO_INCLUDE}`, `{FILES_TO_EXCLUDE}`,
|
|
158
|
-
`{REMOTE}`, `{DEFAULT_BRANCH}`, `{PLATFORM}`
|
|
247
|
+
`{REMOTE}`, `{DEFAULT_BRANCH}`, `{PLATFORM}`, `{AZDO_MODE}`, `{AZDO_ORG}`,
|
|
248
|
+
`{AZDO_PROJECT}`, `{AZDO_ORG_URL}`, `{PAT}` into the prompt.
|
|
159
249
|
|
|
160
250
|
Parse SHIP_REPORT. Abort if failed.
|
|
161
251
|
|
|
162
252
|
**Rollback:** If push succeeds but PR creation fails, report the error and
|
|
163
253
|
suggest the manual PR creation command. Do NOT revert the push.
|
|
164
254
|
- GitHub: `gh pr create --head {branch}`
|
|
165
|
-
- Azure DevOps: `az repos pr create --source-branch {branch} --target-branch {DEFAULT_BRANCH}`
|
|
255
|
+
- Azure DevOps (cli): `az repos pr create --source-branch {branch} --target-branch {DEFAULT_BRANCH} --org {AZDO_ORG_URL} --project {AZDO_PROJECT}`
|
|
256
|
+
- Azure DevOps (rest): Create PR via `{AZDO_ORG_URL}/{AZDO_PROJECT}/_apis/git/repositories/{repo}/pullrequests?api-version=7.0`
|
|
166
257
|
|
|
167
258
|
**If `--pr-only` flag: Stop here and report PR URL to user.**
|
|
168
259
|
|
|
@@ -182,7 +273,8 @@ Task(
|
|
|
182
273
|
)
|
|
183
274
|
```
|
|
184
275
|
|
|
185
|
-
Substitute `{PR_NUMBER}`
|
|
276
|
+
Substitute `{PR_NUMBER}`, `{BRANCH}`, `{PLATFORM}`, `{AZDO_MODE}`,
|
|
277
|
+
`{AZDO_ORG}`, `{AZDO_ORG_URL}`, `{AZDO_PROJECT}`, `{PAT}` into the prompt.
|
|
186
278
|
|
|
187
279
|
While CI runs in the background, briefly inform the user:
|
|
188
280
|
```
|
|
@@ -205,7 +297,8 @@ Task(
|
|
|
205
297
|
)
|
|
206
298
|
```
|
|
207
299
|
|
|
208
|
-
Substitute `{PR_NUMBER}`, `{BRANCH}`, `{FAILING_CHECKS}`
|
|
300
|
+
Substitute `{PR_NUMBER}`, `{BRANCH}`, `{FAILING_CHECKS}`, `{PLATFORM}`,
|
|
301
|
+
`{AZDO_MODE}`, `{AZDO_ORG}`, `{AZDO_ORG_URL}`, `{AZDO_PROJECT}`, `{PAT}` into the prompt.
|
|
209
302
|
|
|
210
303
|
If fixed, return to Stage 3 (run CI watch again).
|
|
211
304
|
If unable to fix after 2 attempts, report to user and stop.
|
|
@@ -225,7 +318,8 @@ Task(
|
|
|
225
318
|
)
|
|
226
319
|
```
|
|
227
320
|
|
|
228
|
-
Substitute `{PR_NUMBER}`, `{REMOTE}`, `{DEFAULT_BRANCH}`,
|
|
321
|
+
Substitute `{PR_NUMBER}`, `{REMOTE}`, `{DEFAULT_BRANCH}`, `{PLATFORM}`,
|
|
322
|
+
`{AZDO_MODE}`, `{AZDO_ORG_URL}`, `{AZDO_PROJECT}`, `{PAT}`, merge/branch flags.
|
|
229
323
|
|
|
230
324
|
Parse LAND_REPORT.
|
|
231
325
|
|
|
@@ -4,6 +4,8 @@ Subagent prompts for each ship stage. The orchestrator reads these and
|
|
|
4
4
|
substitutes template variables before launching each subagent.
|
|
5
5
|
|
|
6
6
|
`{PLATFORM}` is either `github` or `azdo` (detected from remote URL).
|
|
7
|
+
`{AZDO_MODE}` is `cli` or `rest` (only relevant when PLATFORM == azdo).
|
|
8
|
+
`{AZDO_ORG}`, `{AZDO_PROJECT}`, `{AZDO_ORG_URL}` provide AzDO context.
|
|
7
9
|
|
|
8
10
|
---
|
|
9
11
|
|
|
@@ -69,7 +71,7 @@ FILES TO EXCLUDE: {FILES_TO_EXCLUDE}
|
|
|
69
71
|
EOF
|
|
70
72
|
)"
|
|
71
73
|
|
|
72
|
-
**If PLATFORM == azdo:**
|
|
74
|
+
**If PLATFORM == azdo AND AZDO_MODE == cli:**
|
|
73
75
|
az repos pr create \
|
|
74
76
|
--title "<type>: <concise title>" \
|
|
75
77
|
--description "$(cat <<'EOF'
|
|
@@ -85,20 +87,38 @@ FILES TO EXCLUDE: {FILES_TO_EXCLUDE}
|
|
|
85
87
|
)" \
|
|
86
88
|
--source-branch "$BRANCH" \
|
|
87
89
|
--target-branch "{DEFAULT_BRANCH}" \
|
|
90
|
+
--org "{AZDO_ORG_URL}" --project "{AZDO_PROJECT}" \
|
|
88
91
|
--output json
|
|
89
92
|
|
|
93
|
+
**If PLATFORM == azdo AND AZDO_MODE == rest:**
|
|
94
|
+
REPO_NAME=$(basename -s .git "$(git remote get-url origin)")
|
|
95
|
+
AUTH="Authorization: Basic $(echo -n ":{PAT}" | base64)"
|
|
96
|
+
PR_JSON=$(curl -s -X POST \
|
|
97
|
+
-H "$AUTH" \
|
|
98
|
+
-H "Content-Type: application/json" \
|
|
99
|
+
"{AZDO_ORG_URL}/{AZDO_PROJECT}/_apis/git/repositories/$REPO_NAME/pullrequests?api-version=7.0" \
|
|
100
|
+
-d "{\"sourceRefName\": \"refs/heads/$BRANCH\", \"targetRefName\": \"refs/heads/{DEFAULT_BRANCH}\", \"title\": \"<type>: <concise title>\", \"description\": \"## Summary\\n<1-3 sentences>\\n\\n## Changes\\n<bullets>\\n\\n## Testing\\n- [ ] <steps>\"}")
|
|
101
|
+
|
|
90
102
|
6. **Gather info**
|
|
91
103
|
|
|
92
104
|
**If PLATFORM == github:**
|
|
93
105
|
PR_URL=$(gh pr view --json url -q .url)
|
|
94
106
|
PR_NUMBER=$(gh pr view --json number -q .number)
|
|
95
107
|
|
|
96
|
-
**If PLATFORM == azdo:**
|
|
108
|
+
**If PLATFORM == azdo AND AZDO_MODE == cli:**
|
|
97
109
|
# If az repos pr create returned JSON, parse it directly:
|
|
98
110
|
PR_NUMBER=$(echo "$PR_JSON" | jq -r '.pullRequestId')
|
|
99
111
|
# Otherwise list to find it:
|
|
100
|
-
PR_NUMBER=$(az repos pr list --source-branch "$BRANCH" --status active
|
|
101
|
-
|
|
112
|
+
PR_NUMBER=$(az repos pr list --source-branch "$BRANCH" --status active \
|
|
113
|
+
--org "{AZDO_ORG_URL}" --project "{AZDO_PROJECT}" \
|
|
114
|
+
--query '[0].pullRequestId' -o tsv)
|
|
115
|
+
PR_URL="{AZDO_ORG_URL}/{AZDO_PROJECT}/_git/$(basename -s .git "$(git remote get-url origin)")/pullrequest/$PR_NUMBER"
|
|
116
|
+
|
|
117
|
+
**If PLATFORM == azdo AND AZDO_MODE == rest:**
|
|
118
|
+
# Parse from the create response JSON:
|
|
119
|
+
PR_NUMBER=$(echo "$PR_JSON" | jq -r '.pullRequestId')
|
|
120
|
+
REPO_NAME=$(basename -s .git "$(git remote get-url origin)")
|
|
121
|
+
PR_URL="{AZDO_ORG_URL}/{AZDO_PROJECT}/_git/$REPO_NAME/pullrequest/$PR_NUMBER"
|
|
102
122
|
|
|
103
123
|
COMMITS=$(git log {REMOTE}/{DEFAULT_BRANCH}..HEAD --oneline)
|
|
104
124
|
DIFF_STAT=$(git diff {REMOTE}/{DEFAULT_BRANCH} --shortstat)
|
|
@@ -145,14 +165,16 @@ BRANCH: {BRANCH}
|
|
|
145
165
|
2. **Report final status**
|
|
146
166
|
gh pr checks {PR_NUMBER}
|
|
147
167
|
|
|
148
|
-
**If PLATFORM == azdo:**
|
|
168
|
+
**If PLATFORM == azdo AND AZDO_MODE == cli:**
|
|
149
169
|
|
|
150
170
|
1. **Wait for CI to start** (pipelines may take time to trigger after PR creation)
|
|
151
171
|
Poll until at least one run appears (max 2 minutes, check every 15s):
|
|
152
172
|
```
|
|
153
173
|
RUNS_FOUND=false
|
|
154
174
|
for i in $(seq 1 8); do
|
|
155
|
-
RUN_COUNT=$(az pipelines runs list --branch "$BRANCH" --top 5
|
|
175
|
+
RUN_COUNT=$(az pipelines runs list --branch "$BRANCH" --top 5 \
|
|
176
|
+
--org "{AZDO_ORG_URL}" --project "{AZDO_PROJECT}" \
|
|
177
|
+
--query "length(@)" -o tsv 2>/dev/null)
|
|
156
178
|
if [ -n "$RUN_COUNT" ] && [ "$RUN_COUNT" != "0" ]; then
|
|
157
179
|
RUNS_FOUND=true
|
|
158
180
|
break
|
|
@@ -162,27 +184,101 @@ BRANCH: {BRANCH}
|
|
|
162
184
|
```
|
|
163
185
|
If no runs appear after 2 minutes, also check PR policy evaluations:
|
|
164
186
|
```
|
|
165
|
-
az repos pr policy list --id {PR_NUMBER}
|
|
187
|
+
az repos pr policy list --id {PR_NUMBER} \
|
|
188
|
+
--org "{AZDO_ORG_URL}" --project "{AZDO_PROJECT}" \
|
|
189
|
+
--query "[].{name:configuration.type.displayName, status:status}" -o table
|
|
166
190
|
```
|
|
167
191
|
If no policies exist either, report `no_checks`.
|
|
168
192
|
|
|
169
|
-
2. **Wait for runs to complete** (max 30 minutes, check every 30s)
|
|
193
|
+
2. **Wait for runs to complete — with fail-fast** (max 30 minutes, check every 30s)
|
|
170
194
|
```
|
|
171
195
|
for i in $(seq 1 60); do
|
|
172
|
-
|
|
196
|
+
# Check for failures FIRST — stop immediately if any run has failed
|
|
197
|
+
FAILED=$(az pipelines runs list --branch "$BRANCH" --top 5 \
|
|
198
|
+
--org "{AZDO_ORG_URL}" --project "{AZDO_PROJECT}" \
|
|
199
|
+
--query "[?result=='failed'] | length(@)" -o tsv 2>/dev/null)
|
|
200
|
+
if [ -n "$FAILED" ] && [ "$FAILED" != "0" ]; then
|
|
201
|
+
echo "CI failure detected — stopping wait"
|
|
202
|
+
break
|
|
203
|
+
fi
|
|
204
|
+
|
|
205
|
+
# Then check if anything is still running
|
|
206
|
+
IN_PROGRESS=$(az pipelines runs list --branch "$BRANCH" --top 5 \
|
|
207
|
+
--org "{AZDO_ORG_URL}" --project "{AZDO_PROJECT}" \
|
|
208
|
+
--query "[?status=='inProgress'] | length(@)" -o tsv 2>/dev/null)
|
|
173
209
|
if [ "$IN_PROGRESS" = "0" ] || [ -z "$IN_PROGRESS" ]; then break; fi
|
|
174
210
|
sleep 30
|
|
175
211
|
done
|
|
176
212
|
```
|
|
177
213
|
|
|
178
|
-
3. **
|
|
179
|
-
|
|
214
|
+
3. **Determine final status**
|
|
215
|
+
Query both pipeline runs and PR policy evaluations:
|
|
216
|
+
```
|
|
217
|
+
az pipelines runs list --branch "$BRANCH" --top 5 \
|
|
218
|
+
--org "{AZDO_ORG_URL}" --project "{AZDO_PROJECT}" \
|
|
219
|
+
--query "[].{name:definition.name, status:status, result:result}" -o table
|
|
220
|
+
az repos pr policy list --id {PR_NUMBER} \
|
|
221
|
+
--org "{AZDO_ORG_URL}" --project "{AZDO_PROJECT}" \
|
|
222
|
+
--query "[].{name:configuration.type.displayName, status:status}" -o table
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
**Map results to CHECKS_REPORT status:**
|
|
226
|
+
- Any pipeline with `result == "failed"` → `some_failed`
|
|
227
|
+
- Any policy with `status == "rejected"` → `some_failed`
|
|
228
|
+
- All pipelines `result == "succeeded"` AND no rejected policies → `all_passed`
|
|
229
|
+
- Pipelines still `inProgress` after timeout → `pending`
|
|
230
|
+
- No pipelines and no policies found → `no_checks`
|
|
231
|
+
|
|
232
|
+
**IMPORTANT:** Do NOT report `all_passed` if any run has `result == "failed"`.
|
|
233
|
+
Do NOT continue waiting once a failure is detected — report `some_failed`
|
|
234
|
+
immediately with the failing check names.
|
|
235
|
+
|
|
236
|
+
**If PLATFORM == azdo AND AZDO_MODE == rest:**
|
|
237
|
+
|
|
238
|
+
1. **Wait for CI to start** (max 2 minutes, check every 15s)
|
|
239
|
+
```
|
|
240
|
+
REPO_NAME=$(basename -s .git "$(git remote get-url origin)")
|
|
241
|
+
AUTH="Authorization: Basic $(echo -n ":{PAT}" | base64)"
|
|
242
|
+
BUILDS_URL="{AZDO_ORG_URL}/{AZDO_PROJECT}/_apis/build/builds?branchName=refs/heads/$BRANCH&\$top=5&api-version=7.0"
|
|
243
|
+
|
|
244
|
+
RUNS_FOUND=false
|
|
245
|
+
for i in $(seq 1 8); do
|
|
246
|
+
RUN_COUNT=$(curl -s -H "$AUTH" "$BUILDS_URL" | jq '.value | length')
|
|
247
|
+
if [ -n "$RUN_COUNT" ] && [ "$RUN_COUNT" != "0" ]; then
|
|
248
|
+
RUNS_FOUND=true
|
|
249
|
+
break
|
|
250
|
+
fi
|
|
251
|
+
sleep 15
|
|
252
|
+
done
|
|
253
|
+
```
|
|
254
|
+
If no runs appear, check PR policy evaluations via REST:
|
|
255
|
+
```
|
|
256
|
+
EVALS=$(curl -s -H "$AUTH" \
|
|
257
|
+
"{AZDO_ORG_URL}/{AZDO_PROJECT}/_apis/policy/evaluations?artifactId=vstfs:///CodeReview/CodeReviewId/{AZDO_PROJECT}/{PR_NUMBER}&api-version=7.0")
|
|
258
|
+
EVAL_COUNT=$(echo "$EVALS" | jq '.value | length')
|
|
259
|
+
```
|
|
260
|
+
If no evaluations exist either, report `no_checks`.
|
|
261
|
+
|
|
262
|
+
2. **Wait for runs to complete — with fail-fast** (max 30 minutes, check every 30s)
|
|
180
263
|
```
|
|
181
|
-
|
|
182
|
-
|
|
264
|
+
for i in $(seq 1 60); do
|
|
265
|
+
BUILDS_JSON=$(curl -s -H "$AUTH" "$BUILDS_URL")
|
|
266
|
+
|
|
267
|
+
# Check for failures FIRST
|
|
268
|
+
FAILED=$(echo "$BUILDS_JSON" | jq '[.value[] | select(.result=="failed")] | length')
|
|
269
|
+
if [ "$FAILED" != "0" ]; then
|
|
270
|
+
echo "CI failure detected — stopping wait"
|
|
271
|
+
break
|
|
272
|
+
fi
|
|
273
|
+
|
|
274
|
+
# Check if anything still running
|
|
275
|
+
IN_PROGRESS=$(echo "$BUILDS_JSON" | jq '[.value[] | select(.status=="inProgress")] | length')
|
|
276
|
+
if [ "$IN_PROGRESS" = "0" ]; then break; fi
|
|
277
|
+
sleep 30
|
|
278
|
+
done
|
|
183
279
|
```
|
|
184
|
-
|
|
185
|
-
|
|
280
|
+
|
|
281
|
+
3. **Determine final status** — same mapping rules as CLI mode above.
|
|
186
282
|
|
|
187
283
|
## Output Format
|
|
188
284
|
|
|
@@ -216,14 +312,29 @@ FAILING CHECKS: {FAILING_CHECKS}
|
|
|
216
312
|
gh run list --branch {BRANCH} --status failure --json databaseId --jq '.[0].databaseId'
|
|
217
313
|
gh run view <run-id> --log-failed
|
|
218
314
|
|
|
219
|
-
**If PLATFORM == azdo:**
|
|
220
|
-
RUN_ID=$(az pipelines runs list --branch {BRANCH} --top 1
|
|
221
|
-
|
|
315
|
+
**If PLATFORM == azdo AND AZDO_MODE == cli:**
|
|
316
|
+
RUN_ID=$(az pipelines runs list --branch {BRANCH} --top 1 \
|
|
317
|
+
--org "{AZDO_ORG_URL}" --project "{AZDO_PROJECT}" \
|
|
318
|
+
--query "[?result=='failed'].id | [0]" -o tsv)
|
|
319
|
+
az pipelines runs show --id $RUN_ID \
|
|
320
|
+
--org "{AZDO_ORG_URL}" --project "{AZDO_PROJECT}" --output json
|
|
222
321
|
# Get timeline for detailed step failures:
|
|
223
322
|
az devops invoke --area build --resource timeline \
|
|
224
|
-
--route-parameters project
|
|
323
|
+
--route-parameters project="{AZDO_PROJECT}" buildId=$RUN_ID \
|
|
324
|
+
--org "{AZDO_ORG_URL}" \
|
|
225
325
|
--api-version 7.0 --query "records[?result=='failed'].{name:name, log:log.url}" -o table
|
|
226
326
|
|
|
327
|
+
**If PLATFORM == azdo AND AZDO_MODE == rest:**
|
|
328
|
+
AUTH="Authorization: Basic $(echo -n ":{PAT}" | base64)"
|
|
329
|
+
# Get failed build ID
|
|
330
|
+
RUN_ID=$(curl -s -H "$AUTH" \
|
|
331
|
+
"{AZDO_ORG_URL}/{AZDO_PROJECT}/_apis/build/builds?branchName=refs/heads/{BRANCH}&resultFilter=failed&\$top=1&api-version=7.0" \
|
|
332
|
+
| jq -r '.value[0].id')
|
|
333
|
+
# Get timeline for step-level failures
|
|
334
|
+
curl -s -H "$AUTH" \
|
|
335
|
+
"{AZDO_ORG_URL}/{AZDO_PROJECT}/_apis/build/builds/$RUN_ID/timeline?api-version=7.0" \
|
|
336
|
+
| jq '.records[] | select(.result=="failed") | {name, log: .log.url}'
|
|
337
|
+
|
|
227
338
|
2. **Analyze and fix**
|
|
228
339
|
Read the relevant source files, understand the failures, fix the code.
|
|
229
340
|
|
|
@@ -267,33 +378,80 @@ BRANCH_FLAGS: {--delete-branch (default) | omit if --keep-branch}
|
|
|
267
378
|
**If PLATFORM == github:**
|
|
268
379
|
gh pr merge {PR_NUMBER} {MERGE_FLAGS} {BRANCH_FLAGS}
|
|
269
380
|
|
|
270
|
-
**If PLATFORM == azdo:**
|
|
381
|
+
**If PLATFORM == azdo AND AZDO_MODE == cli:**
|
|
271
382
|
# 1. Verify all policies pass before attempting merge
|
|
272
|
-
REJECTED=$(az repos pr policy list --id {PR_NUMBER}
|
|
383
|
+
REJECTED=$(az repos pr policy list --id {PR_NUMBER} \
|
|
384
|
+
--org "{AZDO_ORG_URL}" --project "{AZDO_PROJECT}" \
|
|
385
|
+
--query "[?status=='rejected'] | length(@)" -o tsv 2>/dev/null)
|
|
273
386
|
if [ -n "$REJECTED" ] && [ "$REJECTED" != "0" ]; then
|
|
274
387
|
echo "ERROR: $REJECTED PR policies are rejected — cannot merge"
|
|
275
|
-
az repos pr policy list --id {PR_NUMBER}
|
|
276
|
-
|
|
388
|
+
az repos pr policy list --id {PR_NUMBER} \
|
|
389
|
+
--org "{AZDO_ORG_URL}" --project "{AZDO_PROJECT}" \
|
|
390
|
+
--query "[?status=='rejected'].{name:configuration.type.displayName, status:status}" -o table
|
|
277
391
|
exit 1
|
|
278
392
|
fi
|
|
279
393
|
|
|
280
|
-
# 2.
|
|
281
|
-
|
|
282
|
-
|
|
394
|
+
# 2. Resolve merge strategy from flags
|
|
395
|
+
if echo "{MERGE_FLAGS}" | grep -q "\-\-merge"; then
|
|
396
|
+
SQUASH_FLAG="false"
|
|
397
|
+
else
|
|
398
|
+
SQUASH_FLAG="true"
|
|
399
|
+
fi
|
|
400
|
+
if echo "{BRANCH_FLAGS}" | grep -q "\-\-keep-branch"; then
|
|
401
|
+
DELETE_FLAG="false"
|
|
402
|
+
else
|
|
403
|
+
DELETE_FLAG="true"
|
|
404
|
+
fi
|
|
283
405
|
|
|
406
|
+
# 3. Complete the PR
|
|
284
407
|
az repos pr update --id {PR_NUMBER} --status completed \
|
|
285
|
-
--
|
|
286
|
-
--
|
|
408
|
+
--org "{AZDO_ORG_URL}" --project "{AZDO_PROJECT}" \
|
|
409
|
+
--squash "$SQUASH_FLAG" \
|
|
410
|
+
--delete-source-branch "$DELETE_FLAG"
|
|
411
|
+
MERGE_RC=$?
|
|
287
412
|
|
|
288
|
-
#
|
|
289
|
-
if [
|
|
413
|
+
# 4. If merge fails (e.g. policies still evaluating), wait and retry once
|
|
414
|
+
if [ $MERGE_RC -ne 0 ]; then
|
|
290
415
|
echo "Merge failed, waiting 30s for policies to finalize..."
|
|
291
416
|
sleep 30
|
|
292
417
|
az repos pr update --id {PR_NUMBER} --status completed \
|
|
293
|
-
--
|
|
294
|
-
--
|
|
418
|
+
--org "{AZDO_ORG_URL}" --project "{AZDO_PROJECT}" \
|
|
419
|
+
--squash "$SQUASH_FLAG" \
|
|
420
|
+
--delete-source-branch "$DELETE_FLAG"
|
|
295
421
|
fi
|
|
296
422
|
|
|
423
|
+
**If PLATFORM == azdo AND AZDO_MODE == rest:**
|
|
424
|
+
AUTH="Authorization: Basic $(echo -n ":{PAT}" | base64)"
|
|
425
|
+
REPO_NAME=$(basename -s .git "$(git remote get-url origin)")
|
|
426
|
+
PR_API="{AZDO_ORG_URL}/{AZDO_PROJECT}/_apis/git/repositories/$REPO_NAME/pullrequests/{PR_NUMBER}"
|
|
427
|
+
|
|
428
|
+
# 1. Check for rejected policy evaluations
|
|
429
|
+
EVALS=$(curl -s -H "$AUTH" \
|
|
430
|
+
"{AZDO_ORG_URL}/{AZDO_PROJECT}/_apis/policy/evaluations?artifactId=vstfs:///CodeReview/CodeReviewId/{AZDO_PROJECT}/{PR_NUMBER}&api-version=7.0")
|
|
431
|
+
REJECTED=$(echo "$EVALS" | jq '[.value[] | select(.status=="rejected")] | length')
|
|
432
|
+
if [ "$REJECTED" != "0" ]; then
|
|
433
|
+
echo "ERROR: PR has rejected policy evaluations — cannot merge"
|
|
434
|
+
echo "$EVALS" | jq '.value[] | select(.status=="rejected") | {name: .configuration.type.displayName, status}'
|
|
435
|
+
exit 1
|
|
436
|
+
fi
|
|
437
|
+
|
|
438
|
+
# 2. Resolve merge strategy from flags
|
|
439
|
+
if echo "{MERGE_FLAGS}" | grep -q "\-\-merge"; then
|
|
440
|
+
MERGE_STRATEGY="noFastForward"
|
|
441
|
+
else
|
|
442
|
+
MERGE_STRATEGY="squash"
|
|
443
|
+
fi
|
|
444
|
+
if echo "{BRANCH_FLAGS}" | grep -q "\-\-keep-branch"; then
|
|
445
|
+
DELETE_BRANCH="false"
|
|
446
|
+
else
|
|
447
|
+
DELETE_BRANCH="true"
|
|
448
|
+
fi
|
|
449
|
+
|
|
450
|
+
# 3. Complete the PR
|
|
451
|
+
curl -s -X PATCH -H "$AUTH" -H "Content-Type: application/json" \
|
|
452
|
+
"$PR_API?api-version=7.0" \
|
|
453
|
+
-d "{\"status\": \"completed\", \"completionOptions\": {\"mergeStrategy\": \"$MERGE_STRATEGY\", \"deleteSourceBranch\": $DELETE_BRANCH}}"
|
|
454
|
+
|
|
297
455
|
2. **Sync local repository**
|
|
298
456
|
Invoke `/sync` to checkout {DEFAULT_BRANCH}, pull latest changes, restore
|
|
299
457
|
any stashed work, and clean up merged branches. This replaces manual git
|
package/skills/speccy/SKILL.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: speccy
|
|
3
|
-
description: Deep-dive interview skill for creating comprehensive specifications. Reviews existing code and docs, then interviews the user through multiple rounds of targeted questions covering technical implementation, UI/UX, concerns, and tradeoffs. Produces a structured spec
|
|
3
|
+
description: Deep-dive interview skill for creating comprehensive specifications. Reviews existing code and docs, then interviews the user through multiple rounds of targeted questions covering technical implementation, UI/UX, concerns, and tradeoffs. Produces a structured spec in specs/. Use when starting a new feature, system, or major change that needs a spec.
|
|
4
4
|
argument-hint: Goal, feature, or high-level description to specify
|
|
5
|
-
allowed-tools: Bash, Read, Write, Edit, Glob, Grep, Agent, AskUserQuestion
|
|
5
|
+
allowed-tools: Bash, Read, Write, Edit, Glob, Grep, Agent, AskUserQuestion, Skill
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Speccy - Interview-Driven Specification Builder
|
|
@@ -60,10 +60,11 @@ Status icons: ✅ done · ❌ failed · ⚠️ degraded · ⏳ working · ⏭️
|
|
|
60
60
|
---
|
|
61
61
|
|
|
62
62
|
Interview the user through multiple rounds of targeted questions to build
|
|
63
|
-
a comprehensive specification
|
|
64
|
-
|
|
63
|
+
a comprehensive specification, then write it directly using the spec template
|
|
64
|
+
in `references/spec-template.md`.
|
|
65
65
|
|
|
66
66
|
Interview prompts and question guidelines: `references/interview-guide.md`
|
|
67
|
+
Spec template and writing guidelines: `references/spec-template.md`
|
|
67
68
|
|
|
68
69
|
## Pre-flight
|
|
69
70
|
|
|
@@ -71,15 +72,12 @@ Before starting, check all dependencies in this table:
|
|
|
71
72
|
|
|
72
73
|
| Dependency | Type | Check | Required | Resolution | Detail |
|
|
73
74
|
|-----------|------|-------|----------|------------|--------|
|
|
74
|
-
| create-specification | skill | `~/.claude/skills/create-specification/SKILL.md` or `~/.agents/skills/create-specification/SKILL.md` | yes | ask | This skill is needed to format the final spec. Install with: `npx skills add slamb2k/mad-skills --skill create-specification` |
|
|
75
75
|
| prime | skill | `~/.claude/skills/prime/SKILL.md` or `~/.claude/plugins/marketplaces/slamb2k/skills/prime/SKILL.md` | no | fallback | Context loading; falls back to manual project scan |
|
|
76
76
|
|
|
77
77
|
For each row, in order:
|
|
78
78
|
1. Test file existence (check both paths for symlinked skills)
|
|
79
79
|
2. If found: continue silently
|
|
80
80
|
3. If missing: apply Resolution strategy
|
|
81
|
-
- **ask**: Notify user the skill is missing, offer to install it. If they
|
|
82
|
-
decline, halt execution — the final spec cannot be produced without it.
|
|
83
81
|
4. After all checks: proceed to context gathering
|
|
84
82
|
|
|
85
83
|
---
|
|
@@ -90,12 +88,12 @@ Before asking any questions, build a thorough understanding of the project:
|
|
|
90
88
|
|
|
91
89
|
1. **Capture GOAL** — the user's argument describing what needs to be specified
|
|
92
90
|
2. **Load project context** — invoke `/prime` to load domain-specific context
|
|
93
|
-
(CLAUDE.md,
|
|
91
|
+
(CLAUDE.md, specs, memory). If /prime is unavailable, fall back to
|
|
94
92
|
the manual scan below.
|
|
95
93
|
3. **Scan the project** (skip items already loaded by /prime):
|
|
96
94
|
- Read `CLAUDE.md` if present (project conventions, structure, domain)
|
|
97
|
-
-
|
|
98
|
-
- Scan existing
|
|
95
|
+
- Scan `specs/` directory for existing specifications
|
|
96
|
+
- Scan existing design docs for context
|
|
99
97
|
- Read relevant source code that relates to the GOAL
|
|
100
98
|
- Check memory for prior decisions or open questions related to the GOAL
|
|
101
99
|
3. **Identify knowledge gaps** — what must you learn from the user to write
|
|
@@ -163,19 +161,26 @@ proceeding to spec generation.
|
|
|
163
161
|
|
|
164
162
|
Once the interview is complete and decisions are confirmed:
|
|
165
163
|
|
|
166
|
-
1. **
|
|
164
|
+
1. **Create `specs/` directory** if it doesn't exist:
|
|
167
165
|
```
|
|
168
|
-
|
|
166
|
+
mkdir -p specs
|
|
169
167
|
```
|
|
170
168
|
|
|
171
|
-
2. **
|
|
172
|
-
- The original GOAL
|
|
173
|
-
- All decisions from the interview rounds
|
|
174
|
-
- Any relevant code/architecture context discovered in Stage 1
|
|
175
|
-
- The spec purpose should match the GOAL description
|
|
169
|
+
2. **Read the spec template** from `references/spec-template.md`
|
|
176
170
|
|
|
177
|
-
3.
|
|
178
|
-
|
|
171
|
+
3. **Generate the spec** by filling the template with:
|
|
172
|
+
- The original GOAL as the introduction and purpose
|
|
173
|
+
- All decisions from the interview rounds, mapped to the appropriate sections
|
|
174
|
+
- Code/architecture context discovered in Stage 1
|
|
175
|
+
- Acceptance criteria derived from requirements decisions
|
|
176
|
+
- Test strategy aligned with the project's existing patterns
|
|
177
|
+
|
|
178
|
+
4. **Write the spec file** to `specs/{name}.md` where `{name}` is a
|
|
179
|
+
kebab-case slug derived from the GOAL (e.g., `specs/user-auth.md`,
|
|
180
|
+
`specs/payment-integration.md`). Use the Write tool directly.
|
|
181
|
+
|
|
182
|
+
5. The `specs/` directory is the standard location — `/build` and `/prime`
|
|
183
|
+
both scan it automatically.
|
|
179
184
|
|
|
180
185
|
---
|
|
181
186
|
|
|
@@ -201,6 +206,10 @@ After the spec is created, report to the user:
|
|
|
201
206
|
│ 🔗 Links
|
|
202
207
|
│ Spec: {spec file path}
|
|
203
208
|
│
|
|
209
|
+
│ ⚡ Next steps
|
|
210
|
+
│ 1. Review the spec: {path}
|
|
211
|
+
│ 2. Run `/build {spec path}` to implement (reads the file automatically)
|
|
212
|
+
│
|
|
204
213
|
└─────────────────────────────────────────────────
|
|
205
214
|
```
|
|
206
215
|
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# Specification Template
|
|
2
|
+
|
|
3
|
+
Use this template when generating the final specification document in Stage 3.
|
|
4
|
+
Fill every section with content from the interview decisions and project context.
|
|
5
|
+
Omit sections that are genuinely not applicable, but err on the side of inclusion.
|
|
6
|
+
|
|
7
|
+
## Writing Guidelines
|
|
8
|
+
|
|
9
|
+
- Use precise, explicit, and unambiguous language
|
|
10
|
+
- Clearly distinguish between requirements, constraints, and recommendations
|
|
11
|
+
- Use structured formatting (headings, lists, tables) for easy parsing
|
|
12
|
+
- Avoid idioms, metaphors, or context-dependent references
|
|
13
|
+
- Define all acronyms and domain-specific terms
|
|
14
|
+
- Include examples and edge cases where applicable
|
|
15
|
+
- Ensure the document is self-contained and does not rely on external context
|
|
16
|
+
|
|
17
|
+
## File Naming
|
|
18
|
+
|
|
19
|
+
Save to `specs/{slug}.md` where `{slug}` is a kebab-case name derived from
|
|
20
|
+
the GOAL. Examples: `specs/user-auth.md`, `specs/payment-integration.md`.
|
|
21
|
+
|
|
22
|
+
## Template
|
|
23
|
+
|
|
24
|
+
```md
|
|
25
|
+
---
|
|
26
|
+
title: [Concise Title Describing the Specification's Focus]
|
|
27
|
+
version: 1.0
|
|
28
|
+
date_created: [YYYY-MM-DD]
|
|
29
|
+
last_updated: [YYYY-MM-DD]
|
|
30
|
+
tags: [e.g., infrastructure, process, design, app, schema, tool, data, architecture]
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
# Introduction
|
|
34
|
+
|
|
35
|
+
[A short concise introduction to the specification and the goal it is intended to achieve.]
|
|
36
|
+
|
|
37
|
+
## 1. Purpose & Scope
|
|
38
|
+
|
|
39
|
+
[Clear, concise description of the specification's purpose and scope. State the intended audience and any assumptions.]
|
|
40
|
+
|
|
41
|
+
## 2. Definitions
|
|
42
|
+
|
|
43
|
+
[List and define all acronyms, abbreviations, and domain-specific terms used in this specification.]
|
|
44
|
+
|
|
45
|
+
## 3. Requirements, Constraints & Guidelines
|
|
46
|
+
|
|
47
|
+
[Explicitly list all requirements, constraints, rules, and guidelines. Use bullet points or tables for clarity.]
|
|
48
|
+
|
|
49
|
+
- **REQ-001**: [Functional requirement]
|
|
50
|
+
- **SEC-001**: [Security requirement]
|
|
51
|
+
- **CON-001**: [Constraint]
|
|
52
|
+
- **GUD-001**: [Guideline]
|
|
53
|
+
- **PAT-001**: [Pattern to follow]
|
|
54
|
+
|
|
55
|
+
## 4. Interfaces & Data Contracts
|
|
56
|
+
|
|
57
|
+
[Describe the interfaces, APIs, data contracts, or integration points. Use tables or code blocks for schemas and examples.]
|
|
58
|
+
|
|
59
|
+
## 5. Acceptance Criteria
|
|
60
|
+
|
|
61
|
+
[Define clear, testable acceptance criteria for each requirement using Given-When-Then format where appropriate.]
|
|
62
|
+
|
|
63
|
+
- **AC-001**: Given [context], When [action], Then [expected outcome]
|
|
64
|
+
- **AC-002**: The system shall [specific behavior] when [condition]
|
|
65
|
+
|
|
66
|
+
## 6. Test Automation Strategy
|
|
67
|
+
|
|
68
|
+
[Define the testing approach, frameworks, and automation requirements.]
|
|
69
|
+
|
|
70
|
+
- **Test Levels**: Unit, Integration, End-to-End
|
|
71
|
+
- **Frameworks**: [appropriate for the project's stack]
|
|
72
|
+
- **Test Data Management**: [approach for test data creation and cleanup]
|
|
73
|
+
- **CI/CD Integration**: [automated testing in pipelines]
|
|
74
|
+
- **Coverage Requirements**: [minimum code coverage thresholds]
|
|
75
|
+
- **Performance Testing**: [approach for load and performance testing]
|
|
76
|
+
|
|
77
|
+
## 7. Rationale & Context
|
|
78
|
+
|
|
79
|
+
[Explain the reasoning behind the requirements, constraints, and guidelines. Provide context for design decisions.]
|
|
80
|
+
|
|
81
|
+
## 8. Dependencies & External Integrations
|
|
82
|
+
|
|
83
|
+
[Define external systems, services, and architectural dependencies. Focus on what is needed rather than how it's implemented.]
|
|
84
|
+
|
|
85
|
+
### External Systems
|
|
86
|
+
- **EXT-001**: [External system name] - [Purpose and integration type]
|
|
87
|
+
|
|
88
|
+
### Third-Party Services
|
|
89
|
+
- **SVC-001**: [Service name] - [Required capabilities and SLA requirements]
|
|
90
|
+
|
|
91
|
+
### Infrastructure Dependencies
|
|
92
|
+
- **INF-001**: [Infrastructure component] - [Requirements and constraints]
|
|
93
|
+
|
|
94
|
+
### Data Dependencies
|
|
95
|
+
- **DAT-001**: [External data source] - [Format, frequency, and access requirements]
|
|
96
|
+
|
|
97
|
+
### Technology Platform Dependencies
|
|
98
|
+
- **PLT-001**: [Platform/runtime requirement] - [Version constraints and rationale]
|
|
99
|
+
|
|
100
|
+
**Note**: Focus on architectural and business dependencies, not specific package implementations.
|
|
101
|
+
|
|
102
|
+
## 9. Examples & Edge Cases
|
|
103
|
+
|
|
104
|
+
[Code snippets or data examples demonstrating correct application, including edge cases.]
|
|
105
|
+
|
|
106
|
+
## 10. Validation Criteria
|
|
107
|
+
|
|
108
|
+
[List the criteria or tests that must be satisfied for compliance with this specification.]
|
|
109
|
+
|
|
110
|
+
## 11. Related Specifications / Further Reading
|
|
111
|
+
|
|
112
|
+
[Links to related specs or relevant external documentation.]
|
|
113
|
+
```
|