@andre.buzeli/git-mcp 16.1.2 → 16.1.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@andre.buzeli/git-mcp",
3
- "version": "16.1.2",
3
+ "version": "16.1.4",
4
4
  "private": false,
5
5
  "description": "MCP server para Git com operações locais e sincronização paralela GitHub/Gitea",
6
6
  "license": "MIT",
@@ -19,14 +19,25 @@
19
19
  "git-mcpv2": "src/index.js"
20
20
  },
21
21
  "scripts": {
22
- "start": "node src/index.js"
22
+ "start": "node src/index.js",
23
+ "test": "vitest run",
24
+ "test:unit": "vitest run tests/unit",
25
+ "test:integration": "vitest run --config tests/integration/vitest.config.js",
26
+ "test:e2e": "vitest run tests/e2e",
27
+ "test:property": "vitest run tests/property",
28
+ "test:watch": "vitest",
29
+ "test:coverage": "vitest run --coverage"
23
30
  },
24
31
  "dependencies": {
25
32
  "@modelcontextprotocol/sdk": "^1.11.0",
26
33
  "@octokit/rest": "^20.0.0",
27
- "ajv": "^8.12.0",
34
+ "ajv": "^8.18.0",
28
35
  "archiver": "^7.0.0",
29
36
  "axios": "^1.7.7",
30
37
  "zod": "^3.23.0"
38
+ },
39
+ "devDependencies": {
40
+ "fast-check": "^4.6.0",
41
+ "vitest": "^4.1.0"
31
42
  }
32
43
  }
package/src/index.js CHANGED
@@ -49,13 +49,64 @@ if (!hasGitHub && !hasGitea) {
49
49
 
50
50
  const transport = new StdioServerTransport();
51
51
  const server = new Server(
52
- { name: "git-mcp", version: "16.0.8" },
53
- { capabilities: {
54
- tools: { listChanged: true },
55
- resources: { subscribe: true, listChanged: true },
56
- prompts: {},
57
- logging: {}
58
- } }
52
+ { name: "git-mcp", version: "16.1.3" },
53
+ {
54
+ capabilities: {
55
+ tools: { listChanged: true },
56
+ resources: { subscribe: true, listChanged: true },
57
+ prompts: {},
58
+ logging: {}
59
+ },
60
+ instructions: `# git-mcp — Instruções para AI Agents
61
+
62
+ ## REGRA #1: projectPath é OBRIGATÓRIO
63
+ Toda tool (exceto git-help) exige "projectPath" com o caminho absoluto do projeto aberto no IDE.
64
+ O servidor NÃO consegue detectar o projeto automaticamente.
65
+ Exemplo: "projectPath": "C:/Users/user/meu-projeto" ou "/home/user/meu-projeto"
66
+
67
+ ## REGRA #2: action é OBRIGATÓRIO
68
+ Toda tool usa o padrão { "projectPath": "...", "action": "nome-da-action", ...params }.
69
+ Consulte o enum de cada tool para saber as actions disponíveis.
70
+
71
+ ## Guia Rápido de Tools
72
+
73
+ | Necessidade | Tool | Action | Params obrigatórios |
74
+ |-------------|------|--------|---------------------|
75
+ | Atualizar projeto completo | git-workflow | update | message |
76
+ | Ver status do repo | git-workflow | status | - |
77
+ | Inicializar repo novo | git-workflow | init | - |
78
+ | Ver diferenças locais | git-diff | show | - |
79
+ | Comparar branches/commits | git-diff | compare | target |
80
+ | Estatísticas de diff | git-diff | stat | - |
81
+ | Criar branch | git-branches | create | branch |
82
+ | Trocar branch | git-branches | checkout | branch |
83
+ | Listar branches | git-branches | list | - |
84
+ | Merge de branch | git-merge | merge | branch |
85
+ | Criar tag | git-tags | create | tag |
86
+ | Clonar repo | git-clone | clone | url |
87
+ | Criar issue | git-issues | create | title |
88
+ | Criar PR | git-pulls | create | head, base |
89
+ | Salvar stash | git-stash | save | - |
90
+ | Restaurar stash | git-stash | pop | - |
91
+ | Reset commits | git-reset | soft/mixed/hard | ref |
92
+ | Configurar git | git-config | get/set | key |
93
+ | Gerenciar .gitignore | git-ignore | add/list | patterns |
94
+ | Ler arquivo do git | git-files | read | filepath |
95
+ | Ver histórico | git-history | log | - |
96
+ | Fetch/Pull remoto | git-sync | fetch/pull | - |
97
+ | Gerenciar remotes | git-remote | list/ensure | - |
98
+ | Criar release | git-remote | release-create | tag |
99
+ | Gerenciar worktrees | git-worktree | add/list/remove | branch (add) |
100
+ | Ajuda sobre tools | git-help | - | query/listTools/showFlows |
101
+
102
+ ## Exemplo Completo (ação mais comum)
103
+ \`\`\`json
104
+ { "projectPath": "/caminho/do/projeto", "action": "update", "message": "feat: descrição das mudanças" }
105
+ \`\`\`
106
+
107
+ ## Dica
108
+ Use git-help action="listTools" para ver todas as tools e actions disponíveis em tempo real.`
109
+ }
59
110
  );
60
111
  server.connect(transport);
61
112
 
@@ -22,17 +22,21 @@ Operações Git essenciais.
22
22
 
23
23
  | Action | Descrição | Parâmetros |
24
24
  |--------|-----------|------------|
25
- | **update** | **⭐ RECOMENDADO - Fluxo completo automatizado** | **message, files=["."], gitignore=["pattern"], force, skipIfClean, organization** |
26
- | status | Ver arquivos modificados/staged | - |
25
+ | **update** | **⭐ RECOMENDADO - Fluxo completo automatizado** | **message (obrigatório), files=["."], gitignore=["pattern"], force, skipIfClean, channel, syncBranches, organization, isPublic, dryRun** |
26
+ | status | Ver arquivos modificados/staged | dryRun |
27
27
  | add | Adicionar ao staging | files=["."] ou ["arquivo.js"] |
28
- | commit | Criar commit | message="descrição" (obrigatório) |
29
- | push | Enviar para GitHub+Gitea | force=true se histórico divergir |
30
- | init | Inicializar repo + criar remotes | createGitignore=true, organization |
31
- | ensure-remotes | Configurar remotes | organization |
32
- | clean | Remover arquivos não rastreados | - |
28
+ | remove | Remover do staging | files=["arquivo.js"] |
29
+ | commit | Criar commit | message="descrição" (obrigatório), dryRun |
30
+ | push | Enviar para GitHub+Gitea | force=true se histórico divergir, organization |
31
+ | init | Inicializar repo + criar remotes | createGitignore=true, isPublic, organization, dryRun |
32
+ | ensure-remotes | Configurar remotes | organization, isPublic, dryRun |
33
+ | clean | Remover arquivos não rastreados | dryRun |
34
+ | init-branch | Criar worktree/branch atalho | branch (obrigatório), channel |
33
35
 
34
36
  **Exemplo update:** \`{ "projectPath": "/path", "action": "update", "message": "feat: nova func", "gitignore": ["*.log"] }\`
35
37
  **Com organização:** \`{ "projectPath": "/path", "action": "init", "organization": "automacao-casa" }\`
38
+ **Com channel:** \`{ "projectPath": "/path", "action": "update", "message": "fix: patch", "channel": "beta" }\`
39
+ **Sync worktrees:** \`{ "projectPath": "/path", "action": "update", "message": "sync", "syncBranches": true }\`
36
40
 
37
41
  ---
38
42
 
@@ -51,38 +55,38 @@ Gerenciar branches.
51
55
 
52
56
  ---
53
57
 
54
- ## git-merge (NOVO)
58
+ ## git-merge
55
59
  Mesclar branches.
56
60
 
57
61
  | Action | Descrição | Parâmetros |
58
62
  |--------|-----------|------------|
59
- | merge | Mesclar branch | sourceBranch="feature/x", targetBranch="main" |
60
- | status | Verificar conflitos | - |
61
- | abort | Abortar merge | - |
63
+ | merge | Mesclar branch na branch atual | branch="feature/x" (obrigatório), message="opcional", squash=true |
64
+ | status | Verificar se há merge em andamento | - |
65
+ | abort | Abortar merge com conflitos | - |
62
66
 
63
- **Opções:** fastForwardOnly=true (só FF), squash=true (um commit)
67
+ **Nota:** Faça checkout para a branch destino antes de executar merge. squash=true combina todos os commits em um.
64
68
 
65
69
  ---
66
70
 
67
- ## git-diff (NOVO)
71
+ ## git-diff
68
72
  Visualizar diferenças.
69
73
 
70
74
  | Action | Descrição | Parâmetros |
71
75
  |--------|-----------|------------|
72
- | show | Ver mudanças locais | filepath="src/file.js" (opcional) |
73
- | compare | Comparar commits | fromRef="HEAD~1", toRef="HEAD" |
74
- | stat | Estatísticas | fromRef="HEAD~1", toRef="HEAD" |
76
+ | show | Ver mudanças locais (working vs HEAD) | staged=true (opcional, para staged vs HEAD) |
77
+ | compare | Comparar branches/commits | target="main" (obrigatório), source="HEAD" (opcional) |
78
+ | stat | Estatísticas resumidas | target="HEAD~1" (opcional), source (opcional) |
75
79
 
76
80
  ---
77
81
 
78
- ## git-clone (NOVO)
82
+ ## git-clone
79
83
  Clonar repositórios.
80
84
 
81
85
  | Action | Descrição | Parâmetros |
82
86
  |--------|-----------|------------|
83
- | clone | Clonar repo | url="https://...", targetPath="./pasta" |
87
+ | clone | Clonar repo | url="https://..." (obrigatório), name="pasta-destino" (opcional) |
84
88
 
85
- **Opções:** branch="main", depth=1 (shallow clone)
89
+ **Opções:** branch="main", depth=1 (shallow clone). projectPath é o diretório PAI onde o repo será clonado.
86
90
 
87
91
  ---
88
92
 
@@ -92,9 +96,9 @@ Versionamento semântico.
92
96
  | Action | Descrição | Parâmetros |
93
97
  |--------|-----------|------------|
94
98
  | list | Listar tags | - |
95
- | create | Criar tag | tag="v1.0.0", message="opcional" |
96
- | delete | Deletar tag | tag="v1.0.0" |
97
- | push | Enviar para remotes | tag="v1.0.0" |
99
+ | create | Criar tag | tag="v1.0.0" (obrigatório), ref="HEAD" (opcional), message="opcional" (cria tag anotada) |
100
+ | delete | Deletar tag local | tag="v1.0.0" (obrigatório) |
101
+ | push | Enviar para remotes | tag="v1.0.0" (obrigatório) |
98
102
 
99
103
  **Versões:** v1.0.0 (inicial), v1.1.0 (feature), v1.0.1 (bugfix), v2.0.0 (breaking)
100
104
 
@@ -106,10 +110,10 @@ Salvar mudanças temporariamente.
106
110
  | Action | Descrição | Parâmetros |
107
111
  |--------|-----------|------------|
108
112
  | list | Ver stashes salvos | - |
109
- | save | Salvar mudanças | message="WIP", includeUntracked=true |
110
- | pop | Restaurar e remover | ref="stash@{0}" |
111
- | apply | Restaurar sem remover | ref="stash@{0}" |
112
- | drop | Remover sem restaurar | ref="stash@{0}" |
113
+ | save | Salvar mudanças | message="WIP" (opcional), includeUntracked=true (opcional) |
114
+ | pop | Restaurar e remover | ref="stash@{0}" (opcional, default: mais recente) |
115
+ | apply | Restaurar sem remover | ref="stash@{0}" (opcional, default: mais recente) |
116
+ | drop | Remover sem restaurar | ref="stash@{0}" (opcional, default: mais recente) |
113
117
  | clear | Remover todos | - |
114
118
 
115
119
  ---
@@ -119,12 +123,13 @@ Desfazer commits. ⚠️ CUIDADO
119
123
 
120
124
  | Action | Descrição | Parâmetros |
121
125
  |--------|-----------|------------|
122
- | soft | Mantém mudanças staged | ref="HEAD~1" |
123
- | mixed | Mantém arquivos, remove staging | ref="HEAD~1" |
124
- | hard | ⚠️ DESCARTA tudo | ref="HEAD~1" |
125
- | hard-clean | ⚠️⚠️ DESCARTA + remove untracked | ref="HEAD" |
126
+ | soft | Mantém mudanças staged | ref="HEAD~1" (obrigatório) |
127
+ | mixed | Mantém arquivos, remove staging | ref="HEAD~1" (obrigatório) |
128
+ | hard | ⚠️ DESCARTA tudo | ref="HEAD~1" (obrigatório) |
129
+ | hard-clean | ⚠️⚠️ DESCARTA + remove untracked | ref="HEAD" (obrigatório) |
126
130
 
127
- **Refs:** HEAD~1 (1 commit), HEAD~2 (2 commits), SHA específico
131
+ **Refs:** HEAD~1 (1 commit atrás), HEAD~2 (2 commits), SHA específico do commit
132
+ **Nota:** hard e hard-clean pedem confirmação antes de executar.
128
133
 
129
134
  ---
130
135
 
@@ -146,6 +151,8 @@ Operações em repos remotos GitHub/Gitea.
146
151
  | fork-list | Listar forks | organization |
147
152
  | star-set | Dar estrela | - |
148
153
  | star-unset | Remover estrela | - |
154
+ | subscription-set | Ativar notificações | - |
155
+ | subscription-unset | Desativar notificações | - |
149
156
  | contents-create | Criar arquivo via API | path="", content="", branch="", organization |
150
157
 
151
158
  **Exemplo com organização:** \`{ "projectPath": "/path", "action": "ensure", "organization": "minha-org" }\`
@@ -171,9 +178,9 @@ Gerenciar issues.
171
178
 
172
179
  | Action | Descrição | Parâmetros |
173
180
  |--------|-----------|------------|
174
- | create | Criar issue | title="Bug: ...", body="Descrição" |
175
- | list | Listar issues | - |
176
- | comment | Comentar | number=1, body="Comentário" |
181
+ | create | Criar issue | title="Bug: ..." (obrigatório), body="Descrição", organization |
182
+ | list | Listar issues | organization |
183
+ | comment | Comentar | number=1 (obrigatório), body="Comentário" (obrigatório), organization |
177
184
 
178
185
  ---
179
186
 
@@ -182,9 +189,9 @@ Gerenciar Pull Requests.
182
189
 
183
190
  | Action | Descrição | Parâmetros |
184
191
  |--------|-----------|------------|
185
- | create | Criar PR | head="feature/x", base="main", title="" |
186
- | list | Listar PRs | - |
187
- | files | Ver arquivos do PR | number=1 |
192
+ | create | Criar PR | head="feature/x" (obrigatório), base="main" (obrigatório), title="", body="", organization |
193
+ | list | Listar PRs | organization |
194
+ | files | Ver arquivos do PR | number=1 (obrigatório), organization |
188
195
 
189
196
  ---
190
197
 
@@ -203,12 +210,13 @@ Configurações Git.
203
210
 
204
211
  | Action | Descrição | Parâmetros |
205
212
  |--------|-----------|------------|
206
- | get | Obter valor | key="user.name" |
207
- | set | Definir valor | key="user.name", value="Nome" |
208
- | unset | Remover | key="user.name" |
213
+ | get | Obter valor | key="user.name" (obrigatório), scope="local" |
214
+ | set | Definir valor | key="user.name" (obrigatório), value="Nome", scope="local" |
215
+ | unset | Remover | key="user.name" (obrigatório), scope="local" |
209
216
  | list | Listar todas | scope="local" |
210
217
 
211
- **Keys:** user.name, user.email, core.autocrlf
218
+ **Keys comuns:** user.name, user.email, core.autocrlf, core.editor
219
+ **Scopes:** local (só este repo), global (todos os repos), system (todo o sistema). Default: local
212
220
 
213
221
  ---
214
222
 
@@ -237,9 +245,39 @@ Gerenciar .gitignore.
237
245
  | Action | Descrição | Parâmetros |
238
246
  |--------|-----------|------------|
239
247
  | list | Ver padrões | - |
240
- | create | Criar .gitignore | patterns=["node_modules/","*.log"] |
241
- | add | Adicionar padrões | patterns=["dist/"] |
242
- | remove | Remover padrões | patterns=["*.log"] |
248
+ | create | Criar .gitignore | patterns=["node_modules/","*.log"] (obrigatório) |
249
+ | add | Adicionar padrões | patterns=["dist/"] (obrigatório) |
250
+ | remove | Remover padrões | patterns=["*.log"] (obrigatório) |
251
+
252
+ ---
253
+
254
+ ## git-worktree
255
+ Gerenciar múltiplos diretórios de trabalho (worktrees).
256
+
257
+ | Action | Descrição | Parâmetros |
258
+ |--------|-----------|------------|
259
+ | list | Listar worktrees ativos | - |
260
+ | add | Criar novo worktree | branch="nome" (obrigatório), path="caminho" (opcional), channel="production/beta/alpha", force |
261
+ | remove | Remover worktree | branch="nome" ou path="caminho" (um obrigatório), force |
262
+ | prune | Limpar worktrees deletados manualmente | - |
263
+ | setup | Configurar estrutura recomendada | - |
264
+ | set-channel | Definir canal de deploy da branch | branch="nome" (obrigatório), channel="production/beta/alpha" (obrigatório) |
265
+
266
+ **Channels:** production (branch normal), beta (push para branch-beta), alpha (push para branch-alpha)
267
+ **Nota:** path em add é relativo ao projectPath. Default: ../branch-name
268
+
269
+ ---
270
+
271
+ ## git-help
272
+ Orientação sobre qual tool usar.
273
+
274
+ | Parâmetro | Descrição |
275
+ |-----------|-----------|
276
+ | query="o que fazer" | Recomenda a tool certa para a intenção |
277
+ | listTools=true | Lista todas as tools com descrição e actions |
278
+ | showFlows=true | Mostra fluxos de trabalho comuns passo a passo |
279
+
280
+ **Nota:** Única tool que não exige projectPath.
243
281
 
244
282
  ---
245
283
 
@@ -67,6 +67,14 @@ EXEMPLO:
67
67
  validateProjectPath(projectPath);
68
68
 
69
69
  if (action === "clone") {
70
+ const validation = git.validateRemoteUrl(url);
71
+ if (!validation.valid) {
72
+ return asToolError("INVALID_URL", validation.error, {
73
+ url,
74
+ suggestion: validation.suggestion
75
+ });
76
+ }
77
+
70
78
  await withRetry(() => git.clone(projectPath, url, {
71
79
  name: args.name,
72
80
  branch: args.branch,
@@ -4,6 +4,20 @@ import { validateProjectPath } from "../utils/repoHelpers.js";
4
4
 
5
5
  const ajv = new Ajv({ allErrors: true });
6
6
 
7
+ const DIFF_MAX_CHARS = 100_000;
8
+
9
+ function applyDiffLimit(diff) {
10
+ if (!diff || diff.length <= DIFF_MAX_CHARS) {
11
+ return { diff: diff || "", truncated: false };
12
+ }
13
+ return {
14
+ diff: diff.substring(0, DIFF_MAX_CHARS),
15
+ truncated: true,
16
+ truncatedAt: DIFF_MAX_CHARS,
17
+ originalSize: diff.length
18
+ };
19
+ }
20
+
7
21
  export function createGitDiffTool(git) {
8
22
  const inputSchema = {
9
23
  type: "object",
@@ -30,6 +44,7 @@ export function createGitDiffTool(git) {
30
44
  },
31
45
  staged: {
32
46
  type: "boolean",
47
+ default: false,
33
48
  description: "Para action='show': comparar staged vs HEAD (em vez de working vs index). Default: false"
34
49
  }
35
50
  },
@@ -63,20 +78,24 @@ EXEMPLOS:
63
78
  validateProjectPath(projectPath);
64
79
 
65
80
  if (action === "show") {
66
- const diff = await git.diff(projectPath, { staged: args.staged });
81
+ const raw = await git.diff(projectPath, { staged: args.staged });
82
+ const { diff, ...truncInfo } = applyDiffLimit(raw);
67
83
  return asToolResult({
68
84
  diff: diff || "Nenhuma diferença encontrada",
69
- staged: !!args.staged
85
+ staged: !!args.staged,
86
+ ...truncInfo
70
87
  });
71
88
  }
72
89
 
73
90
  if (action === "compare") {
74
91
  if (!args.target) return asToolError("MISSING_PARAMETER", "target é obrigatório para compare", { parameter: "target", example: "main" });
75
- const diff = await git.diff(projectPath, { target: args.target, source: args.source });
92
+ const raw = await git.diff(projectPath, { target: args.target, source: args.source });
93
+ const { diff, ...truncInfo } = applyDiffLimit(raw);
76
94
  return asToolResult({
77
95
  diff: diff || "Nenhuma diferença encontrada",
78
96
  target: args.target,
79
- source: args.source || "HEAD"
97
+ source: args.source || "HEAD",
98
+ ...truncInfo
80
99
  });
81
100
  }
82
101
 
@@ -31,7 +31,7 @@ export function createGitHelpTool() {
31
31
  },
32
32
  "git-worktree": {
33
33
  purpose: "Gerenciar worktrees (multibranch)",
34
- actions: ["add", "list", "remove", "setup", "set-channel"],
34
+ actions: ["add", "list", "remove", "prune", "setup", "set-channel"],
35
35
  useWhen: "Trabalhar em múltiplas branches/plataformas simultaneamente no mesmo repo"
36
36
  },
37
37
  "git-branches": {
@@ -76,8 +76,8 @@ export function createGitHelpTool() {
76
76
  },
77
77
  "git-remote": {
78
78
  purpose: "Operações em GitHub/Gitea",
79
- actions: ["list", "ensure", "release-create", "topics-set", "label-create"],
80
- useWhen: "Criar release, configurar repositório remoto"
79
+ actions: ["list", "list-all", "list-orgs", "ensure", "release-create", "topics-set", "label-create", "milestone-create", "fork-create", "fork-list", "star-set", "star-unset", "subscription-set", "subscription-unset", "contents-create", "repo-delete"],
80
+ useWhen: "Criar release, configurar repositório remoto, gerenciar repos remotos"
81
81
  },
82
82
  "git-sync": {
83
83
  purpose: "Sincronizar com remotes",
@@ -108,6 +108,11 @@ export function createGitHelpTool() {
108
108
  purpose: "Gerenciar Pull Requests",
109
109
  actions: ["create", "list", "files"],
110
110
  useWhen: "Propor mudanças para review"
111
+ },
112
+ "git-help": {
113
+ purpose: "Orientação sobre qual tool usar e fluxos de trabalho",
114
+ actions: ["query", "listTools", "showFlows"],
115
+ useWhen: "Não sabe qual tool usar, quer ver lista de tools ou fluxos comuns. Única tool sem projectPath obrigatório."
111
116
  }
112
117
  };
113
118
 
@@ -19,10 +19,12 @@ export function createGitHistoryTool(git) {
19
19
  },
20
20
  ref: {
21
21
  type: "string",
22
+ default: "HEAD",
22
23
  description: "Referência inicial para o log (branch, tag, SHA). Default: HEAD"
23
24
  },
24
25
  maxCount: {
25
26
  type: "number",
27
+ default: 50,
26
28
  description: "Número máximo de commits a retornar. Default: 50"
27
29
  }
28
30
  },
@@ -62,7 +64,8 @@ EXEMPLOS:
62
64
  try {
63
65
  validateProjectPath(projectPath);
64
66
  if (action === "log") {
65
- const items = await withRetry(() => git.log(projectPath, { ref: args.ref || "HEAD", maxCount: args.maxCount || 50 }), 3, "history-log");
67
+ const maxCount = args.maxCount || 50;
68
+ const items = await withRetry(() => git.log(projectPath, { ref: args.ref || "HEAD", maxCount }), 3, "history-log");
66
69
  if (items.length === 0) {
67
70
  return asToolResult({
68
71
  commits: [],
@@ -81,7 +84,8 @@ EXEMPLOS:
81
84
  date: c.date
82
85
  })),
83
86
  count: items.length,
84
- ref: args.ref || "HEAD"
87
+ ref: args.ref || "HEAD",
88
+ hasMore: items.length === maxCount
85
89
  });
86
90
  }
87
91
  return asToolError("VALIDATION_ERROR", `Ação '${action}' não suportada`, { availableActions: ["log"] });
@@ -98,11 +98,13 @@ SQUASH:
98
98
  // Pre-merge check: working tree status
99
99
  const status = await git.status(projectPath);
100
100
  if (!status.isClean) {
101
- // We could warn or fail. Standard git refuses merge if changes would be overwritten.
102
- // Let's just warn in logs or return error if critical?
103
- // Git will fail anyway if conflicts with local changes.
104
- // Let's inform the user.
105
- console.warn("[GitMerge] Working tree not clean. Merge might fail.");
101
+ return asToolError("DIRTY_WORKING_TREE",
102
+ "Working tree com alterações não commitadas. Faça commit ou stash antes de mergear.", {
103
+ modified: status.modified,
104
+ staged: status.staged,
105
+ notAdded: status.not_added,
106
+ suggestion: "Use git-workflow action='update' para commitar as mudanças, ou git-stash para guardá-las temporariamente"
107
+ });
106
108
  }
107
109
 
108
110
  const currentBranch = await git.getCurrentBranch(projectPath);
@@ -167,7 +167,11 @@ ARQUIVOS VIA API:
167
167
  },
168
168
  content: {
169
169
  type: "string",
170
- description: "Conteúdo do arquivo para contents-create"
170
+ description: "Conteúdo do arquivo para contents-create (texto simples, será convertido para base64 automaticamente)"
171
+ },
172
+ message: {
173
+ type: "string",
174
+ description: "Mensagem do commit para contents-create. Default: 'Add {path}'"
171
175
  },
172
176
  branch: {
173
177
  type: "string",
@@ -34,6 +34,7 @@ export function createGitStashTool(git) {
34
34
  },
35
35
  includeUntracked: {
36
36
  type: "boolean",
37
+ default: false,
37
38
  description: "Incluir arquivos não rastreados no stash (action='save'). Default: false"
38
39
  }
39
40
  },