@sysvv/ai-skill 1.3.0 → 1.4.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/dist/core/mcp.js +156 -38
- package/dist/index.js +4 -9
- package/package.json +3 -2
- package/schemas/mcp.schema.json +12 -16
- package/skills/ado-workflow/SKILL.md +163 -0
- package/skills/azure-devops/SKILL.md +0 -37
package/dist/core/mcp.js
CHANGED
|
@@ -1,60 +1,178 @@
|
|
|
1
1
|
import fs from "fs-extra";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
|
+
import * as TOML from "smol-toml";
|
|
4
5
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
// ── Targets por agent ───────────────────────────────────────────────────
|
|
7
|
+
const AGENT_MCP_TARGETS = {
|
|
8
|
+
// ── Claude ──────────────────────────────────────────────────────────
|
|
9
|
+
// .mcp.json → { mcpServers: { name: { command, args, env } } }
|
|
10
|
+
claude: {
|
|
11
|
+
format: "json",
|
|
12
|
+
file: ".mcp.json",
|
|
13
|
+
serversKey: "mcpServers",
|
|
14
|
+
buildServerConfig: (mcp) => {
|
|
15
|
+
if (mcp.transport === "stdio") {
|
|
16
|
+
const config = { command: mcp.command };
|
|
17
|
+
if (mcp.args?.length)
|
|
18
|
+
config.args = mcp.args;
|
|
19
|
+
if (mcp.env && Object.keys(mcp.env).length)
|
|
20
|
+
config.env = mcp.env;
|
|
21
|
+
return config;
|
|
22
|
+
}
|
|
23
|
+
const config = { url: mcp.url };
|
|
24
|
+
if (mcp.headers && Object.keys(mcp.headers).length)
|
|
25
|
+
config.headers = mcp.headers;
|
|
26
|
+
if (mcp.env && Object.keys(mcp.env).length)
|
|
27
|
+
config.env = mcp.env;
|
|
28
|
+
return config;
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
// ── Gemini ──────────────────────────────────────────────────────────
|
|
32
|
+
// .gemini/settings.json → { mcpServers: { name: { command, args, env, cwd, timeout } } }
|
|
33
|
+
// Gemini usa "httpUrl" para streamable-http
|
|
34
|
+
gemini: {
|
|
35
|
+
format: "json",
|
|
36
|
+
file: ".gemini/settings.json",
|
|
37
|
+
serversKey: "mcpServers",
|
|
38
|
+
buildServerConfig: (mcp) => {
|
|
39
|
+
const config = {};
|
|
40
|
+
if (mcp.transport === "stdio") {
|
|
41
|
+
config.command = mcp.command;
|
|
42
|
+
if (mcp.args?.length)
|
|
43
|
+
config.args = mcp.args;
|
|
44
|
+
if (mcp.cwd)
|
|
45
|
+
config.cwd = mcp.cwd;
|
|
46
|
+
}
|
|
47
|
+
else if (mcp.transport === "sse") {
|
|
48
|
+
config.url = mcp.url;
|
|
49
|
+
if (mcp.headers && Object.keys(mcp.headers).length)
|
|
50
|
+
config.headers = mcp.headers;
|
|
51
|
+
}
|
|
52
|
+
else if (mcp.transport === "streamable-http") {
|
|
53
|
+
config.httpUrl = mcp.url;
|
|
54
|
+
if (mcp.headers && Object.keys(mcp.headers).length)
|
|
55
|
+
config.headers = mcp.headers;
|
|
56
|
+
}
|
|
57
|
+
if (mcp.env && Object.keys(mcp.env).length)
|
|
58
|
+
config.env = mcp.env;
|
|
59
|
+
if (mcp.timeout)
|
|
60
|
+
config.timeout = mcp.timeout;
|
|
61
|
+
return config;
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
// ── Codex ───────────────────────────────────────────────────────────
|
|
65
|
+
// .codex/config.toml → [mcp_servers.<name>]
|
|
66
|
+
// stdio: command, args, env, cwd
|
|
67
|
+
// streamable-http: url, bearer_token_env_var, http_headers
|
|
68
|
+
// extras: startup_timeout_sec, tool_timeout_sec, enabled
|
|
69
|
+
codex: {
|
|
70
|
+
format: "toml",
|
|
71
|
+
file: ".codex/config.toml",
|
|
72
|
+
buildServerEntry: (mcp) => {
|
|
73
|
+
const entry = {};
|
|
74
|
+
if (mcp.transport === "stdio") {
|
|
75
|
+
entry.command = mcp.command;
|
|
76
|
+
if (mcp.args?.length)
|
|
77
|
+
entry.args = mcp.args;
|
|
78
|
+
if (mcp.cwd)
|
|
79
|
+
entry.cwd = mcp.cwd;
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
// sse e streamable-http → Codex usa "url" para ambos
|
|
83
|
+
entry.url = mcp.url;
|
|
84
|
+
if (mcp.headers && Object.keys(mcp.headers).length) {
|
|
85
|
+
entry.http_headers = mcp.headers;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (mcp.env && Object.keys(mcp.env).length)
|
|
89
|
+
entry.env = mcp.env;
|
|
90
|
+
if (mcp.timeout)
|
|
91
|
+
entry.tool_timeout_sec = Math.ceil(mcp.timeout / 1000);
|
|
92
|
+
return entry;
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
// ── Copilot ─────────────────────────────────────────────────────────
|
|
96
|
+
// .vscode/mcp.json → { inputs: [], servers: { name: { command, args, env } } }
|
|
97
|
+
copilot: {
|
|
98
|
+
format: "json",
|
|
99
|
+
file: ".vscode/mcp.json",
|
|
100
|
+
serversKey: "servers",
|
|
101
|
+
buildServerConfig: (mcp) => {
|
|
102
|
+
if (mcp.transport === "stdio") {
|
|
103
|
+
const config = { command: mcp.command };
|
|
104
|
+
if (mcp.args?.length)
|
|
105
|
+
config.args = mcp.args;
|
|
106
|
+
if (mcp.env && Object.keys(mcp.env).length)
|
|
107
|
+
config.env = mcp.env;
|
|
108
|
+
return config;
|
|
109
|
+
}
|
|
110
|
+
const config = { url: mcp.url };
|
|
111
|
+
if (mcp.headers && Object.keys(mcp.headers).length)
|
|
112
|
+
config.headers = mcp.headers;
|
|
113
|
+
if (mcp.env && Object.keys(mcp.env).length)
|
|
114
|
+
config.env = mcp.env;
|
|
115
|
+
return config;
|
|
116
|
+
}
|
|
117
|
+
},
|
|
11
118
|
};
|
|
12
|
-
|
|
13
|
-
function
|
|
14
|
-
|
|
119
|
+
// ── Writers ─────────────────────────────────────────────────────────────
|
|
120
|
+
async function writeJsonTarget(target, targetPath, mcp) {
|
|
121
|
+
let existing = {};
|
|
122
|
+
if (await fs.pathExists(targetPath)) {
|
|
123
|
+
existing = await fs.readJson(targetPath);
|
|
124
|
+
}
|
|
125
|
+
// Copilot: garante que "inputs" exista
|
|
126
|
+
if (target.serversKey === "servers" && !existing.inputs) {
|
|
127
|
+
existing.inputs = [];
|
|
128
|
+
}
|
|
129
|
+
const servers = existing[target.serversKey] ?? {};
|
|
130
|
+
servers[mcp.name] = target.buildServerConfig(mcp);
|
|
131
|
+
existing[target.serversKey] = servers;
|
|
132
|
+
await fs.ensureDir(path.dirname(targetPath));
|
|
133
|
+
await fs.writeJson(targetPath, existing, { spaces: 2 });
|
|
134
|
+
}
|
|
135
|
+
async function writeTomlTarget(target, targetPath, mcp) {
|
|
136
|
+
let existing = {};
|
|
137
|
+
if (await fs.pathExists(targetPath)) {
|
|
138
|
+
const content = await fs.readFile(targetPath, "utf8");
|
|
139
|
+
if (content.trim()) {
|
|
140
|
+
existing = TOML.parse(content);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const mcpServers = existing.mcp_servers ?? {};
|
|
144
|
+
mcpServers[mcp.name] = target.buildServerEntry(mcp);
|
|
145
|
+
existing.mcp_servers = mcpServers;
|
|
146
|
+
await fs.ensureDir(path.dirname(targetPath));
|
|
147
|
+
await fs.writeFile(targetPath, TOML.stringify(existing), "utf8");
|
|
15
148
|
}
|
|
149
|
+
// ── API pública ─────────────────────────────────────────────────────────
|
|
16
150
|
/** Carrega a definição de um MCP pelo nome */
|
|
17
151
|
export async function loadMcp(name) {
|
|
18
|
-
const mcpFile =
|
|
152
|
+
const mcpFile = path.resolve(__dirname, "../../mcps", `${name}.mcp.json`);
|
|
19
153
|
if (!(await fs.pathExists(mcpFile))) {
|
|
20
154
|
throw new Error(`MCP "${name}" não encontrado em mcps/${name}.mcp.json`);
|
|
21
155
|
}
|
|
22
156
|
return fs.readJson(mcpFile);
|
|
23
157
|
}
|
|
24
|
-
/** Extrai apenas os campos de server config (sem metadata) */
|
|
25
|
-
function extractServerConfig(mcp) {
|
|
26
|
-
if (mcp.transport === "stdio") {
|
|
27
|
-
const config = { command: mcp.command };
|
|
28
|
-
if (mcp.args?.length)
|
|
29
|
-
config.args = mcp.args;
|
|
30
|
-
if (mcp.env && Object.keys(mcp.env).length)
|
|
31
|
-
config.env = mcp.env;
|
|
32
|
-
return config;
|
|
33
|
-
}
|
|
34
|
-
// sse | streamable-http
|
|
35
|
-
const config = { url: mcp.url };
|
|
36
|
-
if (mcp.headers && Object.keys(mcp.headers).length)
|
|
37
|
-
config.headers = mcp.headers;
|
|
38
|
-
if (mcp.env && Object.keys(mcp.env).length)
|
|
39
|
-
config.env = mcp.env;
|
|
40
|
-
return config;
|
|
41
|
-
}
|
|
42
158
|
/** Escreve o MCP no arquivo alvo do agent, fazendo merge com configs existentes */
|
|
43
159
|
export async function writeMcp(agent, mcp) {
|
|
44
|
-
const
|
|
45
|
-
if (!
|
|
160
|
+
const target = AGENT_MCP_TARGETS[agent];
|
|
161
|
+
if (!target)
|
|
46
162
|
throw new Error(`Agent "${agent}" não tem target de MCP configurado.`);
|
|
47
|
-
const targetPath = path.resolve(
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
163
|
+
const targetPath = path.resolve(target.file);
|
|
164
|
+
if (target.format === "json") {
|
|
165
|
+
await writeJsonTarget(target, targetPath, mcp);
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
await writeTomlTarget(target, targetPath, mcp);
|
|
51
169
|
}
|
|
52
|
-
const mcpServers = existing.mcpServers ?? {};
|
|
53
|
-
mcpServers[mcp.name] = extractServerConfig(mcp);
|
|
54
|
-
await fs.ensureDir(path.dirname(targetPath));
|
|
55
|
-
await fs.writeJson(targetPath, { ...existing, mcpServers }, { spaces: 2 });
|
|
56
170
|
return targetPath;
|
|
57
171
|
}
|
|
172
|
+
/** Retorna o path do arquivo MCP de um agent */
|
|
173
|
+
export function getMcpTargetPath(agent) {
|
|
174
|
+
return AGENT_MCP_TARGETS[agent]?.file;
|
|
175
|
+
}
|
|
58
176
|
/** Lista todos os MCPs disponíveis */
|
|
59
177
|
export async function listMcps() {
|
|
60
178
|
const mcpsDir = path.resolve(__dirname, "../../mcps");
|
package/dist/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import { fileURLToPath } from "node:url";
|
|
|
7
7
|
import { findSkillFiles } from "./core/registry.js";
|
|
8
8
|
import { parseSkillFile } from "./core/frontmatter.js";
|
|
9
9
|
import { loadSkill } from "./core/skill.js";
|
|
10
|
-
import { loadMcp, writeMcp } from "./core/mcp.js";
|
|
10
|
+
import { loadMcp, writeMcp, getMcpTargetPath } from "./core/mcp.js";
|
|
11
11
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
12
12
|
// ── ANSI ────────────────────────────────────────────────────────────────
|
|
13
13
|
const ANSI = {
|
|
@@ -178,18 +178,13 @@ async function installSkills(agent) {
|
|
|
178
178
|
}
|
|
179
179
|
// ── Clear all skills + MCPs ─────────────────────────────────────────────
|
|
180
180
|
async function clearSkills() {
|
|
181
|
-
const MCP_TARGETS = {
|
|
182
|
-
claude: ".mcp.json",
|
|
183
|
-
codex: ".codex/mcp.json",
|
|
184
|
-
gemini: ".gemini/mcp.json",
|
|
185
|
-
copilot: ".github/copilot/mcp.json",
|
|
186
|
-
};
|
|
187
181
|
const found = [];
|
|
188
182
|
for (const [agent, dir] of Object.entries(AGENT_DIRS)) {
|
|
189
183
|
const skillsFull = path.resolve(dir);
|
|
190
|
-
const
|
|
184
|
+
const mcpTarget = getMcpTargetPath(agent);
|
|
185
|
+
const mcpFull = mcpTarget ? path.resolve(mcpTarget) : "";
|
|
191
186
|
const hasSkills = await fs.pathExists(skillsFull);
|
|
192
|
-
const hasMcp = await fs.pathExists(mcpFull);
|
|
187
|
+
const hasMcp = mcpFull ? await fs.pathExists(mcpFull) : false;
|
|
193
188
|
if (hasSkills || hasMcp) {
|
|
194
189
|
found.push({ agent, skillsDir: skillsFull, mcpFile: mcpFull, hasSkills, hasMcp });
|
|
195
190
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sysvv/ai-skill",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Instale skills de IA direto no seu projeto. Escolha o agent, escolha as skills.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"fs-extra": "^11.3.0",
|
|
32
32
|
"gray-matter": "^4.0.3",
|
|
33
|
-
"inquirer": "^12.5.2"
|
|
33
|
+
"inquirer": "^12.5.2",
|
|
34
|
+
"smol-toml": "^1.6.0"
|
|
34
35
|
},
|
|
35
36
|
"devDependencies": {
|
|
36
37
|
"@types/fs-extra": "^11.0.4",
|
package/schemas/mcp.schema.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://sysvv.dev/schemas/mcp.schema.json",
|
|
4
4
|
"title": "MCP Server Configuration",
|
|
5
|
-
"description": "Schema para configuração de servidores MCP (Model Context Protocol). Suporta os transportes stdio, sse e streamable-http.",
|
|
5
|
+
"description": "Schema para configuração de servidores MCP (Model Context Protocol). Suporta os transportes stdio, sse e streamable-http. Campos opcionais como timeout e cwd são aplicados conforme o suporte de cada agent.",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"properties": {
|
|
8
8
|
"$schema": {
|
|
@@ -32,6 +32,10 @@
|
|
|
32
32
|
"items": { "type": "string" },
|
|
33
33
|
"description": "[stdio] Argumentos passados ao comando."
|
|
34
34
|
},
|
|
35
|
+
"cwd": {
|
|
36
|
+
"type": "string",
|
|
37
|
+
"description": "[stdio] Diretório de trabalho para o processo do servidor."
|
|
38
|
+
},
|
|
35
39
|
"url": {
|
|
36
40
|
"type": "string",
|
|
37
41
|
"format": "uri",
|
|
@@ -46,6 +50,10 @@
|
|
|
46
50
|
"type": "object",
|
|
47
51
|
"additionalProperties": { "type": "string" },
|
|
48
52
|
"description": "Variáveis de ambiente. Use ${VAR} para referências dinâmicas."
|
|
53
|
+
},
|
|
54
|
+
"timeout": {
|
|
55
|
+
"type": "number",
|
|
56
|
+
"description": "Timeout da requisição em milissegundos. Padrão varia por agent."
|
|
49
57
|
}
|
|
50
58
|
},
|
|
51
59
|
"required": ["name", "description", "transport"],
|
|
@@ -56,11 +64,7 @@
|
|
|
56
64
|
"required": ["transport"]
|
|
57
65
|
},
|
|
58
66
|
"then": {
|
|
59
|
-
"required": ["command"]
|
|
60
|
-
"properties": {
|
|
61
|
-
"url": false,
|
|
62
|
-
"headers": false
|
|
63
|
-
}
|
|
67
|
+
"required": ["command"]
|
|
64
68
|
}
|
|
65
69
|
},
|
|
66
70
|
{
|
|
@@ -69,11 +73,7 @@
|
|
|
69
73
|
"required": ["transport"]
|
|
70
74
|
},
|
|
71
75
|
"then": {
|
|
72
|
-
"required": ["url"]
|
|
73
|
-
"properties": {
|
|
74
|
-
"command": false,
|
|
75
|
-
"args": false
|
|
76
|
-
}
|
|
76
|
+
"required": ["url"]
|
|
77
77
|
}
|
|
78
78
|
},
|
|
79
79
|
{
|
|
@@ -82,11 +82,7 @@
|
|
|
82
82
|
"required": ["transport"]
|
|
83
83
|
},
|
|
84
84
|
"then": {
|
|
85
|
-
"required": ["url"]
|
|
86
|
-
"properties": {
|
|
87
|
-
"command": false,
|
|
88
|
-
"args": false
|
|
89
|
-
}
|
|
85
|
+
"required": ["url"]
|
|
90
86
|
}
|
|
91
87
|
}
|
|
92
88
|
]
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ado-workflow
|
|
3
|
+
title: ADO Workflow
|
|
4
|
+
description: gerenciar work items do Azure DevOps integrado com Git local. Sincroniza estados, vincula commits e mantém ADO atualizado.
|
|
5
|
+
version: 1.0.0
|
|
6
|
+
providers:
|
|
7
|
+
- claude
|
|
8
|
+
- codex
|
|
9
|
+
- gemini
|
|
10
|
+
- copilot
|
|
11
|
+
mcps:
|
|
12
|
+
- azure-devops
|
|
13
|
+
variables:
|
|
14
|
+
language: pt-BR
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# ADO Workflow Skill
|
|
18
|
+
|
|
19
|
+
Reusable skill that integrates Azure DevOps work items with local Git operations. Manages work item states, links commits to tasks, and keeps ADO in sync with development progress. Uses MCP tools as primary interface with CLI fallback.
|
|
20
|
+
|
|
21
|
+
## Setup
|
|
22
|
+
|
|
23
|
+
1. Verify MCP server "azure-devops" is available (check `mcp__azure-devops__*` tools)
|
|
24
|
+
2. If MCP is NOT available: fall back to `az` CLI commands for all operations
|
|
25
|
+
3. Verify `git` is installed and repository is initialized
|
|
26
|
+
4. **NEVER** print or display the value of `AZURE_DEVOPS_PAT`
|
|
27
|
+
|
|
28
|
+
## Rules
|
|
29
|
+
|
|
30
|
+
1. ALWAYS reference ADO work item IDs in commit messages (e.g., `feat: implement login #123`)
|
|
31
|
+
2. NEVER update work item state without verifying current state first
|
|
32
|
+
3. NEVER print or display PAT/token values
|
|
33
|
+
4. Make atomic commits — one logical change per commit
|
|
34
|
+
5. Use Conventional Commits format (`feat:`, `fix:`, `docs:`, `refactor:`, `chore:`, etc.)
|
|
35
|
+
6. Keep ADO work item state in sync with actual progress
|
|
36
|
+
7. ALWAYS confirm with the user before changing work item states
|
|
37
|
+
8. Organization, project, area paths, and states are project-specific — do not hardcode them
|
|
38
|
+
9. Work item states may use custom/localized names — always verify before updating
|
|
39
|
+
10. When creating Tasks: do NOT assign, ALWAYS ask Area Path, activity requires user selection
|
|
40
|
+
|
|
41
|
+
## Operations
|
|
42
|
+
|
|
43
|
+
### list
|
|
44
|
+
|
|
45
|
+
List work items assigned to the current user.
|
|
46
|
+
|
|
47
|
+
**MCP:** `mcp__azure-devops__wit_my_work_items` with `project: {project}`, `type: "assignedtome"`, `includeCompleted: false`
|
|
48
|
+
|
|
49
|
+
**Fallback:**
|
|
50
|
+
```bash
|
|
51
|
+
AZURE_DEVOPS_EXT_PAT=$AZURE_DEVOPS_PAT az boards query \
|
|
52
|
+
--wiql "SELECT [System.Id], [System.Title], [System.State], [System.WorkItemType] FROM WorkItems WHERE [System.AssignedTo] = @Me AND [System.State] <> 'Closed'" \
|
|
53
|
+
--project {project} --organization {organization} --output table
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
**Output:** Display ID, Title, State, Assigned To, Work Item Type as formatted table.
|
|
57
|
+
|
|
58
|
+
### show
|
|
59
|
+
|
|
60
|
+
Show full details of a work item by ID.
|
|
61
|
+
|
|
62
|
+
**Params:** `id` (required)
|
|
63
|
+
|
|
64
|
+
**MCP:** `mcp__azure-devops__wit_get_work_item` with `id: {id}`, `project: {project}`, `expand: "relations"`
|
|
65
|
+
|
|
66
|
+
**Fallback:**
|
|
67
|
+
```bash
|
|
68
|
+
AZURE_DEVOPS_EXT_PAT=$AZURE_DEVOPS_PAT az boards work-item show --id {id} --organization {organization} --output json
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
**Output:** Parse and display id, type, title, state, description, acceptance criteria, assignedTo, iterationPath, areaPath, priority, storyPoints, relations.
|
|
72
|
+
|
|
73
|
+
### start
|
|
74
|
+
|
|
75
|
+
Start working on a task — set state to active and begin implementation.
|
|
76
|
+
|
|
77
|
+
**Params:** `id` (required)
|
|
78
|
+
|
|
79
|
+
**Process:**
|
|
80
|
+
1. Fetch work item details using "show" operation
|
|
81
|
+
2. Display title, description, and acceptance criteria to user
|
|
82
|
+
3. Update state to the active state in ADO
|
|
83
|
+
4. Create implementation plan based on requirements
|
|
84
|
+
5. Ask user for confirmation before proceeding
|
|
85
|
+
|
|
86
|
+
**MCP:** `mcp__azure-devops__wit_update_work_item` with `id: {id}`, `updates: [{"path": "/fields/System.State", "value": "{active_state}"}]`
|
|
87
|
+
|
|
88
|
+
**Fallback:**
|
|
89
|
+
```bash
|
|
90
|
+
AZURE_DEVOPS_EXT_PAT=$AZURE_DEVOPS_PAT az boards work-item update --id {id} --state "{active_state}" --organization {organization} --output json
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Output:** Confirm state change. Show implementation plan. Wait for user approval.
|
|
94
|
+
|
|
95
|
+
### complete
|
|
96
|
+
|
|
97
|
+
Complete a task — verify criteria, final commit, set state to closed.
|
|
98
|
+
|
|
99
|
+
**Params:** `id` (required)
|
|
100
|
+
|
|
101
|
+
**Process:**
|
|
102
|
+
1. Fetch work item details — verify acceptance criteria are met
|
|
103
|
+
2. Run final tests if applicable
|
|
104
|
+
3. Make final commit referencing work item ID
|
|
105
|
+
4. Update state to "Closed" in ADO
|
|
106
|
+
5. Add completion comment with commit SHA
|
|
107
|
+
|
|
108
|
+
**MCP:** `mcp__azure-devops__wit_update_work_item` with `id: {id}`, `updates: [{"path": "/fields/System.State", "value": "Closed"}]`
|
|
109
|
+
|
|
110
|
+
**Fallback:**
|
|
111
|
+
```bash
|
|
112
|
+
AZURE_DEVOPS_EXT_PAT=$AZURE_DEVOPS_PAT az boards work-item update --id {id} --state "Closed" --organization {organization} --output json
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**Output:** Confirm completion. Show final commit SHA, updated state, summary.
|
|
116
|
+
|
|
117
|
+
### commit
|
|
118
|
+
|
|
119
|
+
Make an incremental commit linked to a work item.
|
|
120
|
+
|
|
121
|
+
**Params:** `message` (optional), `work-item-id` (optional)
|
|
122
|
+
|
|
123
|
+
**Process:**
|
|
124
|
+
1. Delegate to git-cli skill `/git-commit`
|
|
125
|
+
2. Append work item reference to commit message (e.g., `#123`)
|
|
126
|
+
|
|
127
|
+
**Output:** Commit hash, message, files changed. Tip: use `/git-push` to push.
|
|
128
|
+
|
|
129
|
+
**Notes:** This operation delegates to the git-cli skill for actual Git operations.
|
|
130
|
+
|
|
131
|
+
### create
|
|
132
|
+
|
|
133
|
+
Create a new work item in ADO.
|
|
134
|
+
|
|
135
|
+
**Params:** `type` (required), `title` (required), `description` (optional), `area-path` (optional — ALWAYS ask user), `activity` (optional — present types to user)
|
|
136
|
+
|
|
137
|
+
**MCP:** `mcp__azure-devops__wit_create_work_item` with `project: {project}`, `type: "{type}"`, `title: "{title}"`, `additionalFields: {"System.Description": "{description}", "System.AreaPath": "{area-path}", "Microsoft.VSTS.Common.Activity": "{activity}", "Microsoft.VSTS.Scheduling.OriginalEstimate": 0, "Microsoft.VSTS.Scheduling.RemainingWork": 0, "Microsoft.VSTS.Scheduling.CompletedWork": 0}`
|
|
138
|
+
|
|
139
|
+
**Fallback:**
|
|
140
|
+
```bash
|
|
141
|
+
AZURE_DEVOPS_EXT_PAT=$AZURE_DEVOPS_PAT az boards work-item create \
|
|
142
|
+
--type "{type}" --title "{title}" --project {project} \
|
|
143
|
+
--organization {organization} --area "{area-path}" \
|
|
144
|
+
--fields "Microsoft.VSTS.Common.Activity={activity}" \
|
|
145
|
+
--output json
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
**Output:** Parse response: extract id, title, state, url.
|
|
149
|
+
|
|
150
|
+
**Notes:**
|
|
151
|
+
- Omit additionalFields entries for params not provided
|
|
152
|
+
- Do NOT assign unless explicitly requested
|
|
153
|
+
- ALWAYS ask user for Area Path before executing
|
|
154
|
+
|
|
155
|
+
## Error Handling
|
|
156
|
+
|
|
157
|
+
| Error | Cause | Resolution |
|
|
158
|
+
|-------|-------|------------|
|
|
159
|
+
| MCP server not available | Not configured or not running | Check `.mcp.json`, verify PAT in `.env`, restart AI tool |
|
|
160
|
+
| 401 / 403 | Invalid or expired PAT | Check PAT scopes: Work Items (Read, Write, Manage), Project (Read) |
|
|
161
|
+
| Work item type not found | Process template mismatch | Agile = "User Story", Scrum = "Product Backlog Item" |
|
|
162
|
+
| State transition not allowed | Invalid state change | Verify allowed transitions for the work item type |
|
|
163
|
+
| MCP tool call fails | Various | Fall back to `az` CLI equivalent command |
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: azure-devops
|
|
3
|
-
title: Azure DevOps
|
|
4
|
-
description: gerenciar work items, repos e pipelines no Azure DevOps.
|
|
5
|
-
version: 1.0.0
|
|
6
|
-
providers:
|
|
7
|
-
- claude
|
|
8
|
-
- codex
|
|
9
|
-
- gemini
|
|
10
|
-
mcps:
|
|
11
|
-
- azure-devops
|
|
12
|
-
variables:
|
|
13
|
-
language: pt-BR
|
|
14
|
-
provider_overrides:
|
|
15
|
-
claude:
|
|
16
|
-
style: "retornar bullets curtos e objetivos"
|
|
17
|
-
codex:
|
|
18
|
-
style: "retornar estrutura operacional"
|
|
19
|
-
gemini:
|
|
20
|
-
style: "retornar texto claro e organizado"
|
|
21
|
-
---
|
|
22
|
-
|
|
23
|
-
Você é um assistente especialista em Azure DevOps.
|
|
24
|
-
|
|
25
|
-
Objetivo:
|
|
26
|
-
Ajudar a gerenciar work items, repositórios e pipelines usando a integração com Azure DevOps.
|
|
27
|
-
|
|
28
|
-
Capacidades:
|
|
29
|
-
- Criar e atualizar work items
|
|
30
|
-
- Consultar status de pipelines
|
|
31
|
-
- Listar repositórios e branches
|
|
32
|
-
- Buscar PRs e reviews
|
|
33
|
-
|
|
34
|
-
Idioma: {{language}}
|
|
35
|
-
|
|
36
|
-
Instrução específica do provider:
|
|
37
|
-
{{provider_style}}
|