ganbatte-os 0.2.5 → 0.2.7
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/.gos/scripts/hooks/claude-session-track.js +143 -0
- package/.gos/scripts/hooks/claude-stop-summary.js +151 -0
- package/README.md +42 -105
- package/package.json +1 -1
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require("node:fs");
|
|
4
|
+
const path = require("node:path");
|
|
5
|
+
|
|
6
|
+
const ROOT = path.resolve(__dirname, "../../..");
|
|
7
|
+
const STATE_DIR = path.join(ROOT, ".claude", ".hook-state");
|
|
8
|
+
|
|
9
|
+
function readStdin() {
|
|
10
|
+
try {
|
|
11
|
+
return fs.readFileSync(0, "utf8");
|
|
12
|
+
} catch {
|
|
13
|
+
return "";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function parsePayload() {
|
|
18
|
+
const raw = readStdin().trim();
|
|
19
|
+
if (!raw) return {};
|
|
20
|
+
try {
|
|
21
|
+
return JSON.parse(raw);
|
|
22
|
+
} catch {
|
|
23
|
+
return {};
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function getSessionId(payload) {
|
|
28
|
+
return (
|
|
29
|
+
payload.session_id ||
|
|
30
|
+
payload.sessionId ||
|
|
31
|
+
payload.conversation_id ||
|
|
32
|
+
payload.conversationId ||
|
|
33
|
+
"default"
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function ensureDir(dirPath) {
|
|
38
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function statePathFor(sessionId) {
|
|
42
|
+
return path.join(STATE_DIR, `${sessionId}.json`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function readState(statePath, sessionId) {
|
|
46
|
+
if (!fs.existsSync(statePath)) {
|
|
47
|
+
return {
|
|
48
|
+
sessionId,
|
|
49
|
+
touchedFiles: [],
|
|
50
|
+
commands: [],
|
|
51
|
+
significantAction: false,
|
|
52
|
+
updatedAt: new Date().toISOString(),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
try {
|
|
57
|
+
return JSON.parse(fs.readFileSync(statePath, "utf8"));
|
|
58
|
+
} catch {
|
|
59
|
+
return {
|
|
60
|
+
sessionId,
|
|
61
|
+
touchedFiles: [],
|
|
62
|
+
commands: [],
|
|
63
|
+
significantAction: false,
|
|
64
|
+
updatedAt: new Date().toISOString(),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function uniquePush(list, value) {
|
|
70
|
+
if (!value || list.includes(value)) return;
|
|
71
|
+
list.push(value);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function normalizePath(candidate) {
|
|
75
|
+
if (typeof candidate !== "string" || !candidate.trim()) return null;
|
|
76
|
+
const trimmed = candidate.trim();
|
|
77
|
+
const absolute = path.isAbsolute(trimmed) ? trimmed : path.join(ROOT, trimmed);
|
|
78
|
+
const normalized = path.normalize(absolute);
|
|
79
|
+
if (!normalized.startsWith(ROOT)) return null;
|
|
80
|
+
return path.relative(ROOT, normalized).replace(/\\/g, "/");
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function collectPaths(payload) {
|
|
84
|
+
const args = payload.args || payload.arguments || {};
|
|
85
|
+
const candidates = [
|
|
86
|
+
args.file_path,
|
|
87
|
+
args.path,
|
|
88
|
+
args.target_file,
|
|
89
|
+
args.new_file_path,
|
|
90
|
+
payload.file_path,
|
|
91
|
+
payload.path,
|
|
92
|
+
];
|
|
93
|
+
|
|
94
|
+
const result = [];
|
|
95
|
+
for (const candidate of candidates) {
|
|
96
|
+
const normalized = normalizePath(candidate);
|
|
97
|
+
if (normalized) uniquePush(result, normalized);
|
|
98
|
+
}
|
|
99
|
+
return result;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function extractCommand(payload) {
|
|
103
|
+
const args = payload.args || payload.arguments || {};
|
|
104
|
+
return (
|
|
105
|
+
args.command ||
|
|
106
|
+
args.cmd ||
|
|
107
|
+
payload.command ||
|
|
108
|
+
payload.cmd ||
|
|
109
|
+
""
|
|
110
|
+
).trim();
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function main() {
|
|
114
|
+
const payload = parsePayload();
|
|
115
|
+
const sessionId = getSessionId(payload);
|
|
116
|
+
const statePath = statePathFor(sessionId);
|
|
117
|
+
|
|
118
|
+
ensureDir(STATE_DIR);
|
|
119
|
+
const state = readState(statePath, sessionId);
|
|
120
|
+
|
|
121
|
+
for (const filePath of collectPaths(payload)) {
|
|
122
|
+
uniquePush(state.touchedFiles, filePath);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const toolName = String(payload.tool || payload.tool_name || payload.matcher || "");
|
|
126
|
+
if (/Bash/i.test(toolName)) {
|
|
127
|
+
const command = extractCommand(payload);
|
|
128
|
+
if (command) uniquePush(state.commands, command);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (state.touchedFiles.length > 0 || state.commands.length > 0) {
|
|
132
|
+
state.significantAction = true;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
state.updatedAt = new Date().toISOString();
|
|
136
|
+
fs.writeFileSync(statePath, JSON.stringify(state, null, 2));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
try {
|
|
140
|
+
main();
|
|
141
|
+
} catch {
|
|
142
|
+
// observation hook: never block
|
|
143
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require("node:fs");
|
|
4
|
+
const path = require("node:path");
|
|
5
|
+
const { execFileSync } = require("node:child_process");
|
|
6
|
+
|
|
7
|
+
const ROOT = path.resolve(__dirname, "../../..");
|
|
8
|
+
const STATE_DIR = path.join(ROOT, ".claude", ".hook-state");
|
|
9
|
+
|
|
10
|
+
function readStdin() {
|
|
11
|
+
try {
|
|
12
|
+
return fs.readFileSync(0, "utf8");
|
|
13
|
+
} catch {
|
|
14
|
+
return "";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function parsePayload() {
|
|
19
|
+
const raw = readStdin().trim();
|
|
20
|
+
if (!raw) return {};
|
|
21
|
+
try {
|
|
22
|
+
return JSON.parse(raw);
|
|
23
|
+
} catch {
|
|
24
|
+
return {};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function getSessionId(payload) {
|
|
29
|
+
return (
|
|
30
|
+
payload.session_id ||
|
|
31
|
+
payload.sessionId ||
|
|
32
|
+
payload.conversation_id ||
|
|
33
|
+
payload.conversationId ||
|
|
34
|
+
"default"
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function readState(sessionId) {
|
|
39
|
+
const statePath = path.join(STATE_DIR, `${sessionId}.json`);
|
|
40
|
+
if (!fs.existsSync(statePath)) {
|
|
41
|
+
return { statePath, state: null };
|
|
42
|
+
}
|
|
43
|
+
try {
|
|
44
|
+
return {
|
|
45
|
+
statePath,
|
|
46
|
+
state: JSON.parse(fs.readFileSync(statePath, "utf8")),
|
|
47
|
+
};
|
|
48
|
+
} catch {
|
|
49
|
+
return { statePath, state: null };
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function safeUnlink(filePath) {
|
|
54
|
+
try {
|
|
55
|
+
fs.unlinkSync(filePath);
|
|
56
|
+
} catch {
|
|
57
|
+
// ignore cleanup issues
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function runNpm(args, options = {}) {
|
|
62
|
+
const npmCmd = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
63
|
+
return execFileSync(npmCmd, args, {
|
|
64
|
+
cwd: ROOT,
|
|
65
|
+
encoding: "utf8",
|
|
66
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
67
|
+
timeout: options.timeout || 120000,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function getGitStatusMap(paths) {
|
|
72
|
+
const map = new Map();
|
|
73
|
+
if (!Array.isArray(paths) || paths.length === 0) return map;
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
const output = execFileSync("git", ["status", "--porcelain", "--", ...paths], {
|
|
77
|
+
cwd: ROOT,
|
|
78
|
+
encoding: "utf8",
|
|
79
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
80
|
+
timeout: 15000,
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
for (const line of output.split(/\r?\n/)) {
|
|
84
|
+
if (!line.trim()) continue;
|
|
85
|
+
const status = line.slice(0, 2);
|
|
86
|
+
const filePath = line.slice(3).trim().replace(/\\/g, "/");
|
|
87
|
+
map.set(filePath, status);
|
|
88
|
+
}
|
|
89
|
+
} catch {
|
|
90
|
+
// ignore git issues
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return map;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function anyPathMatches(paths, matcher) {
|
|
97
|
+
return paths.some((filePath) => matcher.test(filePath));
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function anyCreatedOrRemoved(statusMap, matcher) {
|
|
101
|
+
for (const [filePath, status] of statusMap.entries()) {
|
|
102
|
+
if (!matcher.test(filePath)) continue;
|
|
103
|
+
if (status.includes("A") || status.includes("D") || status.includes("R") || status === "??") {
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function main() {
|
|
111
|
+
const payload = parsePayload();
|
|
112
|
+
const sessionId = getSessionId(payload);
|
|
113
|
+
const { statePath, state } = readState(sessionId);
|
|
114
|
+
|
|
115
|
+
if (!state || !state.significantAction) {
|
|
116
|
+
safeUnlink(statePath);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const touchedFiles = Array.isArray(state.touchedFiles) ? state.touchedFiles : [];
|
|
121
|
+
const statusMap = getGitStatusMap(touchedFiles);
|
|
122
|
+
const summary = [];
|
|
123
|
+
const syncMatcher = /^(\.gos|\.claude|data|README\.md|CLAUDE\.md|AGENTS\.md|GEMINI\.md)/;
|
|
124
|
+
|
|
125
|
+
if (anyPathMatches(touchedFiles, syncMatcher)) {
|
|
126
|
+
try {
|
|
127
|
+
runNpm(["run", "sync:ides"], { timeout: 180000 });
|
|
128
|
+
summary.push("sync:ides OK");
|
|
129
|
+
|
|
130
|
+
if (anyCreatedOrRemoved(statusMap, /^(\.gos|\.claude)\//)) {
|
|
131
|
+
runNpm(["run", "doctor"], { timeout: 180000 });
|
|
132
|
+
summary.push("doctor OK");
|
|
133
|
+
}
|
|
134
|
+
} catch (error) {
|
|
135
|
+
const message = error.stderr || error.stdout || error.message || "falha no sync";
|
|
136
|
+
summary.push(`sync:ides falhou (${String(message).split(/\r?\n/)[0]})`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
safeUnlink(statePath);
|
|
141
|
+
|
|
142
|
+
if (summary.length > 0) {
|
|
143
|
+
process.stdout.write(`${summary.join("; ")}\n`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
try {
|
|
148
|
+
main();
|
|
149
|
+
} catch {
|
|
150
|
+
// observation hook: never block
|
|
151
|
+
}
|
package/README.md
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
# ganbatte-os
|
|
2
|
-
# ganbatte-os
|
|
3
2
|
|
|
4
3
|
Framework operacional para design-to-code, squads de entrega e sprint sync com ClickUp.
|
|
5
4
|
|
|
@@ -9,134 +8,72 @@ Framework operacional para design-to-code, squads de entrega e sprint sync com C
|
|
|
9
8
|
[](https://www.npmjs.com/package/ganbatte-os)
|
|
10
9
|

|
|
11
10
|
|
|
12
|
-
O ganbatte-os organiza agentes de IA, skills e squads num workspace pronto para uso. Ele
|
|
11
|
+
O **ganbatte-os** organiza agentes de IA, skills e squads num workspace pronto para uso. Ele orquestra o ciclo completo de desenvolvimento conectando Figma, ClickUp e as principais IDEs de IA (Claude Code, Gemini, Cursor, etc). Baseado nos padrões do framework `.a8z-OS`.
|
|
13
12
|
|
|
14
13
|
## Quick Start
|
|
15
14
|
|
|
16
15
|
### 1. Instalação (Recomendado)
|
|
17
|
-
Para
|
|
16
|
+
Para transformar qualquer diretório em um workspace ganbatte-os:
|
|
18
17
|
|
|
19
18
|
```bash
|
|
20
19
|
mkdir meu-projeto && cd meu-projeto
|
|
21
20
|
npx ganbatte-os install
|
|
22
21
|
```
|
|
23
22
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
git clone https://github.com/adrianomorais-ganbatte/ganbatte-os.git .
|
|
28
|
-
node scripts/cli/ganbatte-os-cli.js init
|
|
29
|
-
```
|
|
23
|
+
> [!TIP]
|
|
24
|
+
> Durante o desenvolvimento ou para usar a versão mais recente, você pode instalar diretamente do GitHub:
|
|
25
|
+
> `npx adrianomorais-ganbatte/g-os#main install`
|
|
30
26
|
|
|
31
|
-
### 2.
|
|
32
|
-
|
|
27
|
+
### 2. Pós-Instalação
|
|
28
|
+
Após rodar o install, o framework criará uma estrutura limpa na sua raiz:
|
|
29
|
+
- `.gos/` — O núcleo do framework (Agentes, Skills, Scripts).
|
|
30
|
+
- `AGENTS.md`, `CLAUDE.md`, `GEMINI.md` — Instruções para as IDEs.
|
|
31
|
+
- `packages/` — Onde você deve colocar o código do seu aplicativo.
|
|
33
32
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
- `npm run ganbatte-os:version` — Mostrar versão instalada
|
|
33
|
+
### 3. Comandos do Workspace
|
|
34
|
+
A partir da raiz do seu projeto, você pode gerenciar o framework:
|
|
37
35
|
|
|
38
|
-
|
|
36
|
+
- `npm run gos:doctor` — Valida se o framework está íntegro e as IDEs configuradas.
|
|
37
|
+
- `npm run gos:update` — Sincroniza seu workspace com as últimas melhorias da Ganbatte.
|
|
38
|
+
- `npm run sync:ides` — Regenera os adapters para Claude, Gemini, Cursor e outras.
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
- **Squads de Entrega**: Agentes pré-configurados para SM, PO, Dev e QA.
|
|
42
|
-
- **Integração ClickUp**: Sincronização automática de tarefas e status.
|
|
43
|
-
- **Suporte Multi-IDE**: Configurações otimizadas para Claude Code, Gemini, Cursor e outras.
|
|
40
|
+
## Estrutura do Workspace
|
|
44
41
|
|
|
45
|
-
|
|
42
|
+
O `ganbatte-os` utiliza uma estrutura **encapsulada** para manter seu projeto limpo e organizado:
|
|
46
43
|
|
|
47
44
|
```text
|
|
48
|
-
├──
|
|
49
|
-
├──
|
|
50
|
-
├──
|
|
51
|
-
├── scripts/ # CLI e
|
|
52
|
-
|
|
53
|
-
|
|
45
|
+
├── .gos/ # Core do Framework (Somente leitura para usuários)
|
|
46
|
+
│ ├── agents/ # Perfis e instruções dos agentes IA
|
|
47
|
+
│ ├── skills/ # Catálogo de ferramentas (ex: design-to-code)
|
|
48
|
+
│ ├── scripts/ # Engine do CLI e integração de IDEs
|
|
49
|
+
│ └── prompts/ # Prompts canônicos para os agentes
|
|
50
|
+
├── .gos-local/ # Dados locais (logs, queues, worktrees) - ignorado no git
|
|
51
|
+
├── packages/ # Seu código-fonte e projetos vivem aqui
|
|
52
|
+
├── AGENTS.md # Entrypoint de agentes para o framework
|
|
53
|
+
├── CLAUDE.md # Instruções específicas para Claude Code
|
|
54
|
+
└── GEMINI.md # Instruções específicas para Google Gemini
|
|
54
55
|
```
|
|
55
56
|
|
|
56
|
-
##
|
|
57
|
-
|
|
58
|
-
Este é um projeto interno da **Ganbatte**. Para sugestões ou bugs, abra uma issue no repositório.
|
|
59
|
-
|
|
60
|
-
---
|
|
61
|
-
© 2026 Ganbatte. Todos os direitos reservados.
|
|
62
|
-
|
|
63
|
-
## Agentes
|
|
64
|
-
|
|
65
|
-
| Nome | Foco |
|
|
66
|
-
|------|------|
|
|
67
|
-
| ux-design-expert | Design de interfaces e UX |
|
|
68
|
-
| architect | Arquitetura de software |
|
|
69
|
-
| dev | Desenvolvimento full-stack |
|
|
70
|
-
| sm | Scrum Master e facilitacao |
|
|
71
|
-
| po | Product Owner e priorizacao |
|
|
72
|
-
| devops | Infraestrutura e CI/CD |
|
|
73
|
-
| squad-creator | Montagem de squads |
|
|
57
|
+
## Funcionalidades Principais
|
|
74
58
|
|
|
75
|
-
|
|
59
|
+
- **Design-to-Code**: Pipeline automatizado para converter frames do Figma em componentes React/Next.js de alta fidelidade.
|
|
60
|
+
- **Squads de Entrega**: Agentes especializados (SM, PO, Dev, QA) que trabalham de forma coordenada.
|
|
61
|
+
- **Sincronização ClickUp**: Conecta seu workspace diretamente ao ClickUp para automação de status e tarefas.
|
|
62
|
+
- **Multi-IDE Multi-Tenant**: Configurações automáticas para as melhores ferramentas de IA do mercado.
|
|
76
63
|
|
|
77
|
-
|
|
78
|
-
|------|------|
|
|
79
|
-
| design-to-code | Figma para codigo React |
|
|
80
|
-
| figma-implement-design | Implementacao de designs Figma |
|
|
81
|
-
| figma-make-analyzer | Analise de output do Figma Make |
|
|
82
|
-
| make-code-triage | Triagem de codigo gerado |
|
|
83
|
-
| make-version-diff | Diff entre versoes de componentes |
|
|
84
|
-
| component-dedup | Deduplicacao de componentes |
|
|
85
|
-
| frontend-dev | Desenvolvimento frontend |
|
|
86
|
-
| react-best-practices | Boas praticas React/Next.js |
|
|
87
|
-
| react-doctor | Diagnostico de problemas React |
|
|
88
|
-
| sprint-planner | Planejamento de sprints |
|
|
89
|
-
| clickup | Integracao ClickUp API |
|
|
90
|
-
| plan-to-tasks | Conversao de planos em tasks |
|
|
91
|
-
| agent-teams | Orquestracao multi-agente |
|
|
92
|
-
|
|
93
|
-
## Squads
|
|
64
|
+
## Agentes Disponíveis
|
|
94
65
|
|
|
95
66
|
| Nome | Foco |
|
|
96
67
|
|------|------|
|
|
97
|
-
| design-
|
|
98
|
-
|
|
|
99
|
-
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
Claude Code, Codex (VS Code), Gemini, OpenCode, Antigravity, Cursor, KiloCode
|
|
104
|
-
|
|
105
|
-
Cada IDE recebe adapters finos que apontam para os arquivos canonicos em `agents/` e `skills/`.
|
|
106
|
-
|
|
107
|
-
## Estrutura
|
|
68
|
+
| **ux-design-expert** | Design de interfaces, tokens e design systems. |
|
|
69
|
+
| **architect** | Definição de stack, padrões técnicos e revisões de código. |
|
|
70
|
+
| **dev** | Implementação de features, hooks e refinamentos visuais. |
|
|
71
|
+
| **sm / po** | Gestão de sprint, priorização de backlog e sync com stakeholders. |
|
|
72
|
+
| **squad-creator** | Orquestração de times multi-agentes para tarefas complexas. |
|
|
108
73
|
|
|
109
|
-
|
|
110
|
-
g-os/
|
|
111
|
-
agents/profiles/ Perfis de agentes IA
|
|
112
|
-
skills/ Skills plugaveis (cada uma com SKILL.md)
|
|
113
|
-
squads/ Definicoes de squads e workflows
|
|
114
|
-
scripts/
|
|
115
|
-
cli/ CLI gos-cli.js
|
|
116
|
-
tools/ Ferramentas (clickup.js, etc)
|
|
117
|
-
integrations/ Sync e validacao de IDEs
|
|
118
|
-
manifests/ Manifestos de runtime e instalacao
|
|
119
|
-
packages/ Seus projetos aqui
|
|
120
|
-
docs/ Documentacao
|
|
121
|
-
integrations/ Command maps por IDE
|
|
122
|
-
templates/ Templates reutilizaveis
|
|
123
|
-
prompts/ Prompts canonicos
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
## Scripts
|
|
74
|
+
## Licença
|
|
127
75
|
|
|
128
|
-
|
|
129
|
-
|--------|-----------|
|
|
130
|
-
| `npx g-os install` | Instalação via NPX no diretório atual |
|
|
131
|
-
| `npm run gos:init` | Setup pos-clone |
|
|
132
|
-
| `npm run gos:update` | Atualizar do upstream |
|
|
133
|
-
| `npm run gos:doctor` | Validar integridade |
|
|
134
|
-
| `npm run gos:version` | Ver versao e checar updates |
|
|
135
|
-
| `npm run clickup` | CLI ClickUp API |
|
|
136
|
-
| `npm run sync:ides` | Sincronizar IDE adapters |
|
|
137
|
-
| `npm run check:ides` | Validar IDE adapters |
|
|
138
|
-
| `npm run doctor` | Validacao completa |
|
|
76
|
+
Este é um projeto interno da **Ganbatte**. Distribuído sob licença [MIT](LICENSE).
|
|
139
77
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
[MIT](LICENSE)
|
|
78
|
+
---
|
|
79
|
+
© 2026 Ganbatte. Todos os direitos reservados.
|