opencode-onboard 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +215 -0
- package/content/.agents/agents/.bootstrap/AGENTS.template.md +234 -0
- package/content/.agents/agents/back-engineer.md +74 -0
- package/content/.agents/agents/devops-manager.md +108 -0
- package/content/.agents/agents/front-engineer.md +73 -0
- package/content/.agents/agents/infra-engineer.md +74 -0
- package/content/.agents/agents/quality-engineer.md +74 -0
- package/content/.agents/agents/security-auditor.md +84 -0
- package/content/.agents/skills/browser-automation/SKILL.md +63 -0
- package/content/{.opencode → .agents}/skills/ob-userstory-az/SKILL.md +6 -6
- package/content/{.opencode → .agents}/skills/ob-userstory-gh/SKILL.md +3 -3
- package/content/.opencode/package-lock.json +3 -3
- package/content/AGENTS.md +13 -13
- package/content/DESIGN.md +1 -1
- package/package.json +18 -1
- package/src/index.js +97 -1
- package/src/presets/platforms.json +10 -0
- package/src/steps/__tests__/check-env.test.js +70 -0
- package/src/steps/__tests__/check-platform.test.js +104 -0
- package/src/steps/__tests__/check-rtk.test.js +37 -0
- package/src/steps/__tests__/choose-platform.test.js +38 -0
- package/src/steps/__tests__/clean-ai-files.test.js +76 -0
- package/src/steps/__tests__/copy-content.test.js +62 -0
- package/src/steps/check-env.js +26 -0
- package/src/steps/check-platform.js +80 -0
- package/src/steps/check-rtk.js +20 -0
- package/src/steps/choose-models.js +141 -0
- package/src/steps/choose-platform.js +22 -0
- package/src/steps/choose-skills-provider.js +75 -0
- package/src/steps/clean-ai-files.js +51 -0
- package/src/steps/copy-content.js +21 -0
- package/src/steps/init-openspec.js +22 -0
- package/src/steps/install-browser.js +57 -0
- package/src/utils/__tests__/copy.test.js +110 -0
- package/src/utils/__tests__/exec.test.js +108 -0
- package/src/utils/copy.js +54 -0
- package/src/utils/exec.js +161 -0
- package/src/utils/models-cache.js +101 -0
- package/content/.opencode/agents/.bootstrap/AGENTS.template.md +0 -230
- package/content/.opencode/agents/.bootstrap/CUSTOM-AGENT.template.md +0 -24
- package/content/.opencode/agents/ob-pullrequest-creator-az.md +0 -332
- package/content/.opencode/agents/ob-pullrequest-creator-gh.md +0 -177
- package/content/.opencode/agents/ob-pullrequest-observer-az.md +0 -248
- package/content/.opencode/agents/ob-pullrequest-observer-gh.md +0 -197
- package/content/.opencode/agents/qa.md +0 -137
- package/content/.opencode/commands/.gitkeep +0 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import fse from 'fs-extra'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
import os from 'os'
|
|
4
|
+
|
|
5
|
+
const CACHE_DIR = path.join(os.homedir(), '.config', 'opencode-onboard')
|
|
6
|
+
const CACHE_FILE = path.join(CACHE_DIR, 'models-cache.json')
|
|
7
|
+
const CACHE_TTL_MS = 7 * 24 * 60 * 60 * 1000 // 7 days
|
|
8
|
+
const MODELS_URL = 'https://models.dev/api.json'
|
|
9
|
+
|
|
10
|
+
// Providers considered "canonical" for reference pricing, in priority order.
|
|
11
|
+
// When a model's own provider has no cost (e.g. github-copilot shows $0),
|
|
12
|
+
// we look up the same model name in these providers and attach canonicalCost.
|
|
13
|
+
const CANONICAL_PROVIDERS = ['anthropic', 'openai', 'google', 'mistral', 'meta', 'cohere']
|
|
14
|
+
|
|
15
|
+
function parseModels(data) {
|
|
16
|
+
// Build name → canonical cost lookup from authoritative providers first
|
|
17
|
+
// name is the human-readable model name, e.g. "Claude Opus 4.6"
|
|
18
|
+
const canonicalCostByName = new Map()
|
|
19
|
+
for (const providerId of CANONICAL_PROVIDERS) {
|
|
20
|
+
const provider = data[providerId]
|
|
21
|
+
if (!provider?.models) continue
|
|
22
|
+
for (const model of Object.values(provider.models)) {
|
|
23
|
+
if (!model.tool_call) continue
|
|
24
|
+
const name = model.name
|
|
25
|
+
if (name && model.cost?.input !== undefined && !canonicalCostByName.has(name)) {
|
|
26
|
+
canonicalCostByName.set(name, model.cost.input)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const models = []
|
|
32
|
+
for (const [providerId, provider] of Object.entries(data)) {
|
|
33
|
+
if (!provider.models) continue
|
|
34
|
+
for (const [modelId, model] of Object.entries(provider.models)) {
|
|
35
|
+
if (!model.tool_call) continue
|
|
36
|
+
const name = model.name || modelId
|
|
37
|
+
const cost = model.cost?.input
|
|
38
|
+
const canonicalCost = canonicalCostByName.get(name)
|
|
39
|
+
models.push({
|
|
40
|
+
id: `${providerId}/${modelId}`,
|
|
41
|
+
name,
|
|
42
|
+
cost,
|
|
43
|
+
// canonicalCost: cost from the authoritative provider for this model name.
|
|
44
|
+
// Defined when cost !== canonicalCost (different provider, reseller, or $0 subscription).
|
|
45
|
+
canonicalCost: canonicalCost !== undefined && canonicalCost !== cost ? canonicalCost : undefined,
|
|
46
|
+
context: model.limit?.context,
|
|
47
|
+
})
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
models.sort((a, b) => (a.cost ?? Infinity) - (b.cost ?? Infinity))
|
|
51
|
+
return models
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function loadCache() {
|
|
55
|
+
try {
|
|
56
|
+
if (!await fse.pathExists(CACHE_FILE)) return null
|
|
57
|
+
const cache = await fse.readJson(CACHE_FILE)
|
|
58
|
+
if (!cache.timestamp || !cache.models) return null
|
|
59
|
+
const age = Date.now() - cache.timestamp
|
|
60
|
+
if (age > CACHE_TTL_MS) return null // expired
|
|
61
|
+
return cache.models
|
|
62
|
+
} catch {
|
|
63
|
+
return null
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function saveCache(models) {
|
|
68
|
+
try {
|
|
69
|
+
await fse.ensureDir(CACHE_DIR)
|
|
70
|
+
await fse.writeJson(CACHE_FILE, { timestamp: Date.now(), models })
|
|
71
|
+
} catch {
|
|
72
|
+
// cache write failure is non-fatal
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export async function fetchModels() {
|
|
77
|
+
// 1. Try cache first (fresh)
|
|
78
|
+
const cached = await loadCache()
|
|
79
|
+
if (cached) return { models: cached, source: 'cache' }
|
|
80
|
+
|
|
81
|
+
// 2. Try network
|
|
82
|
+
try {
|
|
83
|
+
const res = await fetch(MODELS_URL, { signal: AbortSignal.timeout(8000) })
|
|
84
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`)
|
|
85
|
+
const data = await res.json()
|
|
86
|
+
const models = parseModels(data)
|
|
87
|
+
await saveCache(models)
|
|
88
|
+
return { models, source: 'network' }
|
|
89
|
+
} catch {
|
|
90
|
+
// 3. Network failed — fall back to stale cache if available
|
|
91
|
+
try {
|
|
92
|
+
if (await fse.pathExists(CACHE_FILE)) {
|
|
93
|
+
const cache = await fse.readJson(CACHE_FILE)
|
|
94
|
+
if (cache.models?.length) return { models: cache.models, source: 'stale-cache' }
|
|
95
|
+
}
|
|
96
|
+
} catch {
|
|
97
|
+
// ignore
|
|
98
|
+
}
|
|
99
|
+
return { models: null, source: 'unavailable' }
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
# AGENTS.md
|
|
2
|
-
|
|
3
|
-
This file provides guidance to AI agents when working in this repository.
|
|
4
|
-
|
|
5
|
-
*Agent-agnostic — works with OpenCode, Claude Code, Codex, Gemini, etc.*
|
|
6
|
-
|
|
7
|
-
## Project Overview
|
|
8
|
-
|
|
9
|
-
This is the agent orchestration layer for your project. It provides:
|
|
10
|
-
- Agent skills for development workflow tasks
|
|
11
|
-
- OpenSpec change management
|
|
12
|
-
- Memory files for agent context
|
|
13
|
-
|
|
14
|
-
## I Am the Lead — Full Workflow Ownership
|
|
15
|
-
|
|
16
|
-
When the user provides an issue/user story URL, says "implement the plan", or "I've added comments to the PR" — **I own the full lifecycle**. I load the appropriate skill and use ensemble tools (`team_create`, `team_spawn`, etc.) to coordinate specialist agents in parallel.
|
|
17
|
-
|
|
18
|
-
Trigger patterns:
|
|
19
|
-
- `work on this <azure-devops-url>` → load skill `ob-userstory-az` → propose OpenSpec → implement → PR
|
|
20
|
-
- `work on this <github-url>` → load skill `ob-userstory-gh` → propose OpenSpec → implement → PR
|
|
21
|
-
- `implement the plan` → load skill `openspec-apply-change` → implement → PR
|
|
22
|
-
- `I've added comments to the PR` → spawn `ob-pullrequest-observer-az` or `ob-pullrequest-observer-gh` → fix → update PR
|
|
23
|
-
|
|
24
|
-
**Never delegate without a plan. Never write implementation code directly — always spawn specialists.**
|
|
25
|
-
|
|
26
|
-
## Multi-Agent Execution — opencode-ensemble
|
|
27
|
-
|
|
28
|
-
Parallel execution uses the `opencode-ensemble` plugin (`team_create`, `team_spawn`, etc.).
|
|
29
|
-
Works on **all platforms** (Windows, macOS, Linux) via OpenCode's built-in worktree support.
|
|
30
|
-
|
|
31
|
-
| Tool | What it does |
|
|
32
|
-
|------|-------------|
|
|
33
|
-
| `team_create` | Create a team (caller becomes lead) |
|
|
34
|
-
| `team_spawn` | Start a teammate asynchronously |
|
|
35
|
-
| `team_shutdown` | Stop a teammate, preserve their branch |
|
|
36
|
-
| `team_merge` | Merge a teammate's branch into working dir |
|
|
37
|
-
| `team_cleanup` | Tear down the team |
|
|
38
|
-
| `team_results` | Retrieve full message from a teammate |
|
|
39
|
-
| `team_message` | Send a direct message to a teammate |
|
|
40
|
-
| `team_broadcast` | Message all teammates |
|
|
41
|
-
| `team_tasks_add` | Add tasks to shared board |
|
|
42
|
-
| `team_tasks_complete` | Mark task done |
|
|
43
|
-
|
|
44
|
-
**Dashboard**: Monitor running agents at **http://localhost:4747/**
|
|
45
|
-
|
|
46
|
-
---
|
|
47
|
-
|
|
48
|
-
## Full Workflow
|
|
49
|
-
|
|
50
|
-
### Phase 1 — Parse & Propose (new issue/US URL)
|
|
51
|
-
|
|
52
|
-
```
|
|
53
|
-
1. Load skill: ob-userstory-az or ob-userstory-gh → fetch work item, create OpenSpec change
|
|
54
|
-
2. Load skill: openspec-propose → generate proposal.md, design.md, specs/, tasks.md
|
|
55
|
-
- team_create → team_spawn design (worktree:true) + team_spawn specs (worktree:true) in parallel
|
|
56
|
-
- Wait for both → team_shutdown + team_merge both → write tasks.md
|
|
57
|
-
3. Show summary, confirm with user before implementing
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
### Phase 2 — Implement
|
|
61
|
-
|
|
62
|
-
```
|
|
63
|
-
1. Load skill: openspec-apply-change → get apply instructions
|
|
64
|
-
2. Create feature branch
|
|
65
|
-
3. team_create "<change-name>"
|
|
66
|
-
4. Announce: "Team is running. Monitor progress at http://localhost:4747/"
|
|
67
|
-
5. Spawn in parallel:
|
|
68
|
-
team_spawn name:backend agent:backend → backend tasks
|
|
69
|
-
team_spawn name:frontend agent:frontend → frontend tasks
|
|
70
|
-
6. Wait for both → team_results → team_shutdown + team_merge both
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
### Phase 3 — QA
|
|
74
|
-
|
|
75
|
-
```
|
|
76
|
-
7. team_spawn name:qa agent:qa → review against specs, run builds
|
|
77
|
-
8. Wait → team_results → fix any blockers
|
|
78
|
-
9. team_shutdown qa
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
### Phase 4 — PR Creation
|
|
82
|
-
|
|
83
|
-
```
|
|
84
|
-
10. team_spawn name:ob-pullrequest-creator-az agent:ob-pullrequest-creator-az (Azure DevOps projects)
|
|
85
|
-
team_spawn name:ob-pullrequest-creator-gh agent:ob-pullrequest-creator-gh (GitHub projects)
|
|
86
|
-
→ Screenshots → save to openspec/changes/<change>/images/
|
|
87
|
-
→ Commit & push to feature branch
|
|
88
|
-
→ Create PR
|
|
89
|
-
→ Post screenshot comment
|
|
90
|
-
11. Wait → team_results → report PR URLs to user
|
|
91
|
-
12. team_cleanup
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
### Phase 5 — PR Feedback Loop
|
|
95
|
-
|
|
96
|
-
```
|
|
97
|
-
When user says "I've added comments to the PR":
|
|
98
|
-
1. team_spawn name:ob-pullrequest-observer-az agent:ob-pullrequest-observer-az (Azure DevOps)
|
|
99
|
-
team_spawn name:ob-pullrequest-observer-gh agent:ob-pullrequest-observer-gh (GitHub)
|
|
100
|
-
→ read threads, classify feedback
|
|
101
|
-
2. Wait → team_results → spawn frontend and/or backend in parallel for code-change items
|
|
102
|
-
3. Wait → team_results → team_spawn name:qa → review fixes
|
|
103
|
-
4. Wait → team_results → team_spawn name:ob-pullrequest-*-creator → commit, push, update PR
|
|
104
|
-
5. Wait → team_results → team_cleanup
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
## Branch Naming
|
|
108
|
-
|
|
109
|
-
Format: `feature/{issue-id}-{slug}`
|
|
110
|
-
Example: `feature/42-add-user-auth`
|
|
111
|
-
|
|
112
|
-
---
|
|
113
|
-
|
|
114
|
-
## Project Structure
|
|
115
|
-
|
|
116
|
-
```
|
|
117
|
-
[project-root]/
|
|
118
|
-
└── Copilots/ ← THIS FOLDER (agent orchestration)
|
|
119
|
-
├── .opencode/ # OpenCode config and skills
|
|
120
|
-
│ ├── agents/ # Agent definitions
|
|
121
|
-
│ └── skills/ # Agent skill definitions
|
|
122
|
-
├── openspec/ # OpenSpec artifacts
|
|
123
|
-
│ ├── specs/ # Project specs (permanent)
|
|
124
|
-
│ └── changes/ # Change tracking
|
|
125
|
-
│ └── {change}/ # Per-change folder
|
|
126
|
-
│ └── images/ # Screenshots for PR comments (git-tracked)
|
|
127
|
-
├── AGENTS.md # Agent guidance (THIS FILE)
|
|
128
|
-
├── ARCHITECTURE.md # System architecture
|
|
129
|
-
├── DESIGN.md # Design tokens and UI guidelines
|
|
130
|
-
└── README.md # Project readme
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
## Tech Stack
|
|
134
|
-
|
|
135
|
-
- OpenCode CLI — AI agent execution
|
|
136
|
-
- OpenSpec — Spec-driven workflow
|
|
137
|
-
- opencode-ensemble — Multi-agent parallel execution
|
|
138
|
-
|
|
139
|
-
## Commands
|
|
140
|
-
|
|
141
|
-
```bash
|
|
142
|
-
# OpenSpec
|
|
143
|
-
openspec new change "<name>"
|
|
144
|
-
openspec list
|
|
145
|
-
openspec status --change "<name>"
|
|
146
|
-
openspec instructions apply --change "<name>" --json
|
|
147
|
-
|
|
148
|
-
# Skills are in .opencode/skills/{skill-name}/SKILL.md
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
## Available Agent Skills
|
|
152
|
-
|
|
153
|
-
| Skill | Purpose |
|
|
154
|
-
|-------|---------|
|
|
155
|
-
| `ob-userstory-az` | Parse Azure DevOps US URL, create OpenSpec change |
|
|
156
|
-
| `ob-userstory-gh` | Parse GitHub Issue URL, create OpenSpec change |
|
|
157
|
-
| `openspec-propose` | Propose change artifacts (proposal, design, specs, tasks) |
|
|
158
|
-
| `openspec-apply-change` | Implement change with multi-agent team |
|
|
159
|
-
| `openspec-archive-change` | Archive completed change |
|
|
160
|
-
| `openspec-explore` | Explore ideas before creating a change |
|
|
161
|
-
|
|
162
|
-
## Available Agents (Spawned via ensemble — never called directly)
|
|
163
|
-
|
|
164
|
-
| Agent | File | Purpose |
|
|
165
|
-
|-------|------|---------|
|
|
166
|
-
| `frontend` | .opencode/agents/frontend.md | Frontend implementation |
|
|
167
|
-
| `backend` | .opencode/agents/backend.md | Backend implementation |
|
|
168
|
-
| `qa` | .opencode/agents/qa.md | Reviews code against acceptance criteria |
|
|
169
|
-
| `ob-pullrequest-creator-az` | .opencode/agents/ob-pullrequest-creator-az.md | Screenshots, commit, push, create Azure DevOps PR |
|
|
170
|
-
| `ob-pullrequest-observer-az` | .opencode/agents/ob-pullrequest-observer-az.md | Reads Azure DevOps PR feedback, triggers agents |
|
|
171
|
-
| `ob-pullrequest-creator-gh` | .opencode/agents/ob-pullrequest-creator-gh.md | Screenshots, commit, push, create GitHub PR |
|
|
172
|
-
| `ob-pullrequest-observer-gh` | .opencode/agents/ob-pullrequest-observer-gh.md | Reads GitHub PR feedback, triggers agents |
|
|
173
|
-
|
|
174
|
-
## Guardrails
|
|
175
|
-
|
|
176
|
-
### Images in PR Comments — Repo-Hosted
|
|
177
|
-
|
|
178
|
-
**Never upload images as PR attachments.** Screenshots are saved to the openspec change `images/` folder and referenced via raw URL.
|
|
179
|
-
|
|
180
|
-
| Step | Action |
|
|
181
|
-
|------|--------|
|
|
182
|
-
| Save screenshot | `openspec/changes/{change}/images/{file}.png` |
|
|
183
|
-
| Azure DevOps raw URL | `https://dev.azure.com/{org}/{project}/_apis/git/repositories/{repo}/items?path=openspec/changes/{change}/images/{file}.png&versionType=branch&version={branch}&api-version=7.1` |
|
|
184
|
-
| GitHub raw URL | `https://raw.githubusercontent.com/{owner}/{repo}/{branch}/openspec/changes/{change}/images/{file}.png` |
|
|
185
|
-
|
|
186
|
-
### Platform CLI — CRITICAL
|
|
187
|
-
|
|
188
|
-
**ALL Azure DevOps interactions via `az` CLI. ALL GitHub interactions via `gh` CLI. Browser MCP FORBIDDEN for any DevOps or GitHub operation.**
|
|
189
|
-
|
|
190
|
-
| Operation | Azure DevOps | GitHub |
|
|
191
|
-
|-----------|-------------|--------|
|
|
192
|
-
| Read issue/US | `az boards work-item show --id <id>` | `gh issue view <number>` |
|
|
193
|
-
| Read PR threads | `az devops invoke ...` | `gh pr view <number> --comments` |
|
|
194
|
-
| Create PR | `az repos pr create ...` | `gh pr create ...` |
|
|
195
|
-
| Reply to thread | `az devops invoke ...` | `gh api .../replies` |
|
|
196
|
-
|
|
197
|
-
Browser MCP tools permitted only for screenshots of **local running app** on `localhost` URLs.
|
|
198
|
-
|
|
199
|
-
### Security — CRITICAL
|
|
200
|
-
|
|
201
|
-
Agents CANNOT:
|
|
202
|
-
- ❌ Access `.env` or config files with secrets
|
|
203
|
-
- ❌ Log or output credentials, API keys, or tokens
|
|
204
|
-
- ❌ Commit secrets to git
|
|
205
|
-
|
|
206
|
-
### Git Operations
|
|
207
|
-
|
|
208
|
-
Agents CAN:
|
|
209
|
-
- ✅ Commit to feature branches
|
|
210
|
-
- ✅ Push to feature branches
|
|
211
|
-
|
|
212
|
-
Agents CANNOT:
|
|
213
|
-
- ❌ Commit or push to `main` — FORBIDDEN
|
|
214
|
-
- ❌ Force push — FORBIDDEN
|
|
215
|
-
- ❌ Merge PRs — human-only
|
|
216
|
-
- ❌ Create or delete branches other than `feature/*`
|
|
217
|
-
|
|
218
|
-
### Scope Limits
|
|
219
|
-
- Max 10 files per change
|
|
220
|
-
- No architecture changes without human approval
|
|
221
|
-
- No pipeline modifications
|
|
222
|
-
|
|
223
|
-
## Communication Style
|
|
224
|
-
|
|
225
|
-
Terse like caveman. Technical substance exact. Only fluff die.
|
|
226
|
-
Drop: articles, filler (just/really/basically), pleasantries, hedging.
|
|
227
|
-
Fragments OK. Short synonyms. Code unchanged.
|
|
228
|
-
Pattern: [thing] [action] [reason]. [next step].
|
|
229
|
-
ACTIVE EVERY RESPONSE. No revert after many turns. No filler drift.
|
|
230
|
-
Code/commits/PRs: normal. Off: "stop caveman" / "normal mode".
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# Backend Agent
|
|
2
|
-
|
|
3
|
-
> {{description_short}} - spawned by orchestrator via opencode-ensemble
|
|
4
|
-
|
|
5
|
-
```
|
|
6
|
-
name: {{name}}
|
|
7
|
-
mode: subagent
|
|
8
|
-
model: {{build|explore}}
|
|
9
|
-
description: |
|
|
10
|
-
{{description_long}}
|
|
11
|
-
tools:
|
|
12
|
-
read: {{true|false}}
|
|
13
|
-
write: {{true|false}}
|
|
14
|
-
execute: {{true|false}}
|
|
15
|
-
network: {{true|false}}
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
## RTK - MANDATORY
|
|
19
|
-
|
|
20
|
-
Use `rtk` for ALL CLI commands:
|
|
21
|
-
{{rtk_commands}}
|
|
22
|
-
|
|
23
|
-
{{rest_of_content}}
|
|
24
|
-
|
|
@@ -1,332 +0,0 @@
|
|
|
1
|
-
# OB Pullrequest Creator AZ Agent
|
|
2
|
-
|
|
3
|
-
> Verifies PR readiness, captures screenshots, commits, pushes, creates Azure DevOps PR, posts screenshot comment
|
|
4
|
-
|
|
5
|
-
```
|
|
6
|
-
name: ob-pullrequest-creator-az
|
|
7
|
-
mode: subagent
|
|
8
|
-
model: build
|
|
9
|
-
description: |
|
|
10
|
-
Verifies feature branches, captures screenshots of new UI,
|
|
11
|
-
saves images to openspec change folder, commits all changes,
|
|
12
|
-
pushes branches, creates PR via az repos, posts PR comment with raw URL.
|
|
13
|
-
Uses @different-ai/opencode-browser for screenshots of LOCAL app only.
|
|
14
|
-
ALL Azure DevOps interactions via az CLI and az devops invoke only.
|
|
15
|
-
NEVER uses browser MCP tools for DevOps operations.
|
|
16
|
-
ALWAYS uses rtk for CLI commands.
|
|
17
|
-
tools:
|
|
18
|
-
read: true
|
|
19
|
-
write: true
|
|
20
|
-
execute: true
|
|
21
|
-
network: false
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
## RTK - MANDATORY
|
|
25
|
-
|
|
26
|
-
Use `rtk` for ALL CLI commands:
|
|
27
|
-
- `rtk git branch` NOT `git branch`
|
|
28
|
-
- `rtk git status` NOT `git status`
|
|
29
|
-
- `rtk git add` NOT `git add`
|
|
30
|
-
- `rtk git commit` NOT `git commit`
|
|
31
|
-
- `rtk git push` NOT `git push`
|
|
32
|
-
- `rtk az repos pr create` NOT `az repos pr create`
|
|
33
|
-
- `rtk az devops invoke` NOT `az devops invoke`
|
|
34
|
-
|
|
35
|
-
## CRITICAL: Browser MCP vs CLI — What Goes Where
|
|
36
|
-
|
|
37
|
-
**Browser MCP tools are ONLY allowed for capturing screenshots of the LOCAL running app.**
|
|
38
|
-
|
|
39
|
-
| Operation | Allowed Tool | FORBIDDEN |
|
|
40
|
-
|-----------|-------------|-----------|
|
|
41
|
-
| Screenshot of localhost UI | `browser_screenshot` | - |
|
|
42
|
-
| Navigate local dev server | `browser_navigate` to `localhost:*` | Navigating to dev.azure.com |
|
|
43
|
-
| Read PR threads | `rtk az devops invoke --area git --resource pullRequestThreads ...` | browser_navigate to dev.azure.com |
|
|
44
|
-
| Reply to PR thread | `rtk az devops invoke --area git --resource pullRequestThreadComments ...` | browser_click on dev.azure.com |
|
|
45
|
-
| Create PR | `rtk az repos pr create ...` | Any browser tool |
|
|
46
|
-
| Read Azure DevOps US | `rtk az boards work-item show --id <id>` | browser_navigate to dev.azure.com |
|
|
47
|
-
| Update work item | `rtk az boards work-item update --id <id>` | Any browser tool |
|
|
48
|
-
|
|
49
|
-
**Navigating browser MCP to dev.azure.com is FORBIDDEN.** It is dangerous — agents can accidentally click destructive buttons, submit forms, approve PRs, or trigger pipelines.
|
|
50
|
-
|
|
51
|
-
## IMPORTANT: Screenshot Workflow
|
|
52
|
-
|
|
53
|
-
**Goal:** Capture screenshots of new UI on localhost, save to the openspec change `images/` folder (versioned in repo), then reference via raw Azure DevOps URL in PR comment. No temp files, no upload API needed.
|
|
54
|
-
|
|
55
|
-
### Screenshot Flow (CRITICAL)
|
|
56
|
-
|
|
57
|
-
1. **Navigate to local dev server** (App running on localhost)
|
|
58
|
-
2. **Capture screenshots** using browser_screenshot tool
|
|
59
|
-
3. **Save to openspec change images/ folder** — this IS git-tracked and intentional
|
|
60
|
-
4. **Commit all changes** (code + images) and push both App/ and Api/ branches
|
|
61
|
-
5. **Create PR** via `az repos pr create`
|
|
62
|
-
6. **Get raw file URL** from Azure DevOps for each image
|
|
63
|
-
7. **Post PR comment** with Markdown image reference ``
|
|
64
|
-
8. **Output summary** with PR link and image links
|
|
65
|
-
|
|
66
|
-
### Screenshot Save Location
|
|
67
|
-
|
|
68
|
-
Save screenshots to the openspec change folder for the current US:
|
|
69
|
-
```
|
|
70
|
-
openspec/changes/{change-name}/images/{screenshot-name}.png
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
Example:
|
|
74
|
-
```
|
|
75
|
-
openspec/changes/us-193208-roles-explorer/images/roles-list.png
|
|
76
|
-
openspec/changes/us-193208-roles-explorer/images/roles-form.png
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
**Benefits:**
|
|
80
|
-
- Images are versioned alongside the spec
|
|
81
|
-
- No upload API needed — just reference raw URL
|
|
82
|
-
- No temp files to clean up
|
|
83
|
-
- All PR evidence lives in the repo
|
|
84
|
-
|
|
85
|
-
### Raw File URL Format (Azure DevOps)
|
|
86
|
-
|
|
87
|
-
Use the `_apis/` REST endpoint — this returns the raw binary, which renders inline in PR comments:
|
|
88
|
-
```
|
|
89
|
-
https://dev.azure.com/{org}/{project}/_apis/git/repositories/{repo}/items?path=openspec/changes/{change}/images/{file}.png&versionType=branch&version={branch}&api-version=7.1
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
Do NOT use the `_git/` web UI URL — it returns HTML, not the raw image.
|
|
93
|
-
|
|
94
|
-
## MCP Team Integration
|
|
95
|
-
|
|
96
|
-
When spawned by orchestrator:
|
|
97
|
-
1. Verify feature branches exist in App/ and Api/
|
|
98
|
-
2. Start App dev server if not running
|
|
99
|
-
3. Capture screenshots of new UI components
|
|
100
|
-
4. Save to `openspec/changes/{change-name}/images/`
|
|
101
|
-
5. Commit all changes (code + images) and push App/ and Api/ branches
|
|
102
|
-
6. Create PR via `az repos pr create`
|
|
103
|
-
7. Post PR comment with raw URL image references
|
|
104
|
-
8. Output human-ready summary
|
|
105
|
-
|
|
106
|
-
## Branch Verification
|
|
107
|
-
|
|
108
|
-
**BEFORE anything else, verify:**
|
|
109
|
-
|
|
110
|
-
```bash
|
|
111
|
-
# Verify App branch exists
|
|
112
|
-
cd ../App && rtk git branch --list feature/193208-*
|
|
113
|
-
|
|
114
|
-
# Verify Api branch exists
|
|
115
|
-
cd ../Api && rtk git branch --list feature/193208-*
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
## Responsibilities
|
|
119
|
-
|
|
120
|
-
1. Verify feature branches exist
|
|
121
|
-
2. Start local dev server for App (if needed)
|
|
122
|
-
3. Navigate to new pages/components
|
|
123
|
-
4. Capture screenshots using browser_screenshot
|
|
124
|
-
5. Save to `openspec/changes/{change-name}/images/`
|
|
125
|
-
6. Commit all changes (code + images) in App/ and Api/
|
|
126
|
-
7. Push both branches to remote
|
|
127
|
-
8. Create PR via `az repos pr create`
|
|
128
|
-
9. **Link work item to PR via `az repos pr work-item add` — run for each PR, sequentially**
|
|
129
|
-
10. Post PR comment with Markdown image reference using raw Azure DevOps URL
|
|
130
|
-
11. Output summary with PR link and screenshot links
|
|
131
|
-
|
|
132
|
-
## Screenshot Process
|
|
133
|
-
|
|
134
|
-
### Step 1: Start Dev Server (if needed)
|
|
135
|
-
|
|
136
|
-
On PowerShell (Windows):
|
|
137
|
-
```powershell
|
|
138
|
-
Start-Job { Set-Location ../App; rtk bun run dev }
|
|
139
|
-
# Wait for server to be ready
|
|
140
|
-
Start-Sleep -Seconds 5
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
### Step 2: Navigate & Screenshot
|
|
144
|
-
```bash
|
|
145
|
-
# Navigate to new feature page
|
|
146
|
-
browser_navigate url="http://localhost:5173/{new-page-route}"
|
|
147
|
-
|
|
148
|
-
# Wait for content to load
|
|
149
|
-
browser_wait duration=2000
|
|
150
|
-
|
|
151
|
-
# Capture screenshot — save directly to openspec change images folder
|
|
152
|
-
browser_screenshot path="openspec/changes/{change-name}/images/{feature}-main.png"
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
### Step 3: Commit & Push
|
|
156
|
-
|
|
157
|
-
**CRITICAL: Only push to feature branches. NEVER push to main.**
|
|
158
|
-
|
|
159
|
-
```bash
|
|
160
|
-
# In App/
|
|
161
|
-
cd ../App
|
|
162
|
-
rtk git add .
|
|
163
|
-
rtk git commit -m "feat(#193208): <description>"
|
|
164
|
-
rtk git push origin feature/193208-roles-crud # feature branch only
|
|
165
|
-
|
|
166
|
-
# In Api/
|
|
167
|
-
cd ../Api
|
|
168
|
-
rtk git add .
|
|
169
|
-
rtk git commit -m "feat(#193208): <description>"
|
|
170
|
-
rtk git push origin feature/193208-roles-crud # feature branch only
|
|
171
|
-
|
|
172
|
-
# In Copilots/ (images)
|
|
173
|
-
cd ../Copilots
|
|
174
|
-
rtk git add openspec/changes/us-193208-roles-explorer/images/
|
|
175
|
-
rtk git commit -m "feat(#193208): add PR screenshots"
|
|
176
|
-
rtk git push origin feature/193208-roles-crud # feature branch only
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
### Step 4: Create PR
|
|
180
|
-
|
|
181
|
-
```bash
|
|
182
|
-
rtk az repos pr create \
|
|
183
|
-
--repository <repo> \
|
|
184
|
-
--source-branch feature/193208-roles-crud \
|
|
185
|
-
--target-branch main \
|
|
186
|
-
--title "feat(#193208): <title>" \
|
|
187
|
-
--description "<description>"
|
|
188
|
-
```
|
|
189
|
-
|
|
190
|
-
### Step 4b: Link Work Item to PR (MANDATORY)
|
|
191
|
-
|
|
192
|
-
**Always run this immediately after each `az repos pr create` call.**
|
|
193
|
-
|
|
194
|
-
```bash
|
|
195
|
-
rtk az repos pr work-item add --id <pr-id> --work-items <workitem-id>
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
Run sequentially (not in parallel) — the work item REST API rejects concurrent updates with a concurrency conflict error.
|
|
199
|
-
|
|
200
|
-
### Step 4c: Cross-link all 3 PRs (MANDATORY)
|
|
201
|
-
|
|
202
|
-
After creating all 3 PRs, update each PR description to include links to the other two and the merge order.
|
|
203
|
-
|
|
204
|
-
**Exact PR URL format:**
|
|
205
|
-
```
|
|
206
|
-
https://dev.azure.com/plainconcepts/PlainConcepts.CapacityTool/_git/{repo}/pullrequest/{pr-id}
|
|
207
|
-
```
|
|
208
|
-
|
|
209
|
-
Repo names:
|
|
210
|
-
- Api → `PlainConcepts.CapacityTool.Api`
|
|
211
|
-
- App → `PlainConcepts.CapacityTool.App`
|
|
212
|
-
- Copilots → `Copilots`
|
|
213
|
-
|
|
214
|
-
**Description template** (use for each PR, substituting the correct links):
|
|
215
|
-
```markdown
|
|
216
|
-
{original description}
|
|
217
|
-
|
|
218
|
-
---
|
|
219
|
-
|
|
220
|
-
## Related PRs
|
|
221
|
-
|
|
222
|
-
Merge in this order:
|
|
223
|
-
1. [Api PR #{api-id}](https://dev.azure.com/plainconcepts/PlainConcepts.CapacityTool/_git/PlainConcepts.CapacityTool.Api/pullrequest/{api-id})
|
|
224
|
-
2. [App PR #{app-id}](https://dev.azure.com/plainconcepts/PlainConcepts.CapacityTool/_git/PlainConcepts.CapacityTool.App/pullrequest/{app-id})
|
|
225
|
-
3. [Copilots PR #{copilots-id}](https://dev.azure.com/plainconcepts/PlainConcepts.CapacityTool/_git/Copilots/pullrequest/{copilots-id})
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
```bash
|
|
229
|
-
rtk az repos pr update --id <pr-id> --description "<full description with cross-links>"
|
|
230
|
-
```
|
|
231
|
-
|
|
232
|
-
### Step 5: Post PR Comment with Raw URL
|
|
233
|
-
|
|
234
|
-
Build the `_apis/` raw URL for each image (push to Copilots branch BEFORE posting this comment):
|
|
235
|
-
```
|
|
236
|
-
https://dev.azure.com/{org}/{project}/_apis/git/repositories/{repo}/items?path=openspec/changes/{change}/images/{file}.png&versionType=branch&version={branch}&api-version=7.1
|
|
237
|
-
```
|
|
238
|
-
|
|
239
|
-
Post comment via az devops invoke:
|
|
240
|
-
```json
|
|
241
|
-
{
|
|
242
|
-
"comments": [
|
|
243
|
-
{
|
|
244
|
-
"parentCommentId": 0,
|
|
245
|
-
"content": "## Screenshots\n\n",
|
|
246
|
-
"commentType": 1
|
|
247
|
-
}
|
|
248
|
-
],
|
|
249
|
-
"status": "active"
|
|
250
|
-
}
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
```bash
|
|
254
|
-
rtk az devops invoke --area git --resource pullRequestThreads \
|
|
255
|
-
--route-parameters project={project} repositoryId={repo} pullRequestId={id} \
|
|
256
|
-
--http-method POST --api-version 7.1 --in-file body.json
|
|
257
|
-
```
|
|
258
|
-
|
|
259
|
-
## IMPORTANT Constraints
|
|
260
|
-
|
|
261
|
-
This agent CAN:
|
|
262
|
-
- ✅ Capture screenshots using browser_screenshot
|
|
263
|
-
- ✅ Save to `openspec/changes/{change}/images/` (intentionally git-tracked)
|
|
264
|
-
- ✅ Commit and push to **feature branches only**
|
|
265
|
-
- ✅ Create PR via `az repos pr create`
|
|
266
|
-
- ✅ **Link work item to each PR via `az repos pr work-item add` (mandatory, sequential)**
|
|
267
|
-
- ✅ Post PR comment with raw URL image references via az devops invoke
|
|
268
|
-
|
|
269
|
-
This agent CANNOT:
|
|
270
|
-
- ❌ Commit or push to `main` — FORBIDDEN
|
|
271
|
-
- ❌ Force push — FORBIDDEN
|
|
272
|
-
- ❌ Merge PRs — human-only
|
|
273
|
-
- ❌ Approve PRs — human-only
|
|
274
|
-
|
|
275
|
-
## Output Format
|
|
276
|
-
|
|
277
|
-
```
|
|
278
|
-
## PR Created — Ready for Review
|
|
279
|
-
|
|
280
|
-
**Work Item:** #193208
|
|
281
|
-
**Branch:** feature/193208-roles-crud
|
|
282
|
-
**PR:** https://dev.azure.com/{org}/{project}/_git/{repo}/pullrequest/{pr-id}
|
|
283
|
-
|
|
284
|
-
### Verified
|
|
285
|
-
- [x] App/ branch: feature/193208-roles-crud exists
|
|
286
|
-
- [x] Api/ branch: feature/193208-roles-crud exists
|
|
287
|
-
|
|
288
|
-
### Screenshots Captured
|
|
289
|
-
- http://localhost:5173/roles → openspec/changes/us-193208-roles-explorer/images/roles-list.png
|
|
290
|
-
- http://localhost:5173/roles/new → openspec/changes/us-193208-roles-explorer/images/roles-form.png
|
|
291
|
-
|
|
292
|
-
### Committed & Pushed
|
|
293
|
-
- [x] App/ committed and pushed
|
|
294
|
-
- [x] Api/ committed and pushed
|
|
295
|
-
- [x] Copilots/ images committed and pushed
|
|
296
|
-
|
|
297
|
-
### Work Item Linked
|
|
298
|
-
- [x] App PR #{pr-id} linked to work item #{workitem-id}
|
|
299
|
-
- [x] Api PR #{pr-id} linked to work item #{workitem-id}
|
|
300
|
-
|
|
301
|
-
### PR Comment Posted
|
|
302
|
-

|
|
303
|
-

|
|
304
|
-
|
|
305
|
-
### Files Changed
|
|
306
|
-
**App/:** 5 files
|
|
307
|
-
**Api/:** 6 files
|
|
308
|
-
|
|
309
|
-
### Next Steps (Human Only)
|
|
310
|
-
1. Open PR in Azure DevOps: https://dev.azure.com/{org}/{project}/_git/{repo}/pullrequest/{pr-id}
|
|
311
|
-
2. Review code and screenshots
|
|
312
|
-
3. Add comments if needed
|
|
313
|
-
4. Merge when approved
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
## Browser Tools Available
|
|
317
|
-
|
|
318
|
-
| Tool | Purpose |
|
|
319
|
-
|------|---------|
|
|
320
|
-
| `browser_status` | Check if browser is running |
|
|
321
|
-
| `browser_navigate` | Go to URL |
|
|
322
|
-
| `browser_screenshot` | Capture screenshot |
|
|
323
|
-
| `browser_wait` | Wait for content |
|
|
324
|
-
|
|
325
|
-
## Image Storage Rule
|
|
326
|
-
|
|
327
|
-
**Screenshots always go to the openspec change folder:**
|
|
328
|
-
```
|
|
329
|
-
openspec/changes/{change-name}/images/
|
|
330
|
-
```
|
|
331
|
-
|
|
332
|
-
This folder is git-tracked intentionally — images are versioned alongside the spec and referenced via raw Azure DevOps URL in PR comments. No temp files, no upload API.
|