ganbatte-os 0.2.1
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/AGENTS.md +46 -0
- package/CLAUDE.md +31 -0
- package/GEMINI.md +17 -0
- package/LICENSE +21 -0
- package/README.md +141 -0
- package/agents/profiles/architect.md +13 -0
- package/agents/profiles/dev.md +13 -0
- package/agents/profiles/devops.md +12 -0
- package/agents/profiles/ganbatte-os-master.md +444 -0
- package/agents/profiles/index.json +14 -0
- package/agents/profiles/po.md +7 -0
- package/agents/profiles/qa.md +456 -0
- package/agents/profiles/sm.md +7 -0
- package/agents/profiles/squad-creator.md +7 -0
- package/agents/profiles/ux-design-expert.md +14 -0
- package/config.json +15 -0
- package/docs/curation.md +60 -0
- package/docs/gos_installation_guide.md +114 -0
- package/docs/ide-compatibility.md +20 -0
- package/docs/plan/plan-git-operations.md +51 -0
- package/docs/plan-distribuicao-publica.md +360 -0
- package/docs/stacks/stack-git-operations.md +154 -0
- package/docs/toolchain-map.md +18 -0
- package/integrations/README.md +42 -0
- package/integrations/antigravity/README.md +29 -0
- package/integrations/antigravity/command-map.json +29 -0
- package/integrations/claude/README.md +35 -0
- package/integrations/claude/agent-map.json +46 -0
- package/integrations/claude/command-map.json +32 -0
- package/integrations/claude/litellm-proxy.md +93 -0
- package/integrations/claude/mcp-specifics.md +121 -0
- package/integrations/codex/README.md +29 -0
- package/integrations/codex/command-map.json +29 -0
- package/integrations/cursor/README.md +8 -0
- package/integrations/cursor/command-map.json +11 -0
- package/integrations/gemini/README.md +13 -0
- package/integrations/gemini/command-map.json +11 -0
- package/integrations/kilo-code/README.md +7 -0
- package/integrations/kilo-code/command-map.json +11 -0
- package/integrations/opencode/README.md +91 -0
- package/integrations/opencode/command-map.json +46 -0
- package/integrations/registry.json +20 -0
- package/manifests/g-os-runtime-manifest.json +39 -0
- package/manifests/gos-install-manifest.json +46 -0
- package/opencode.json +7 -0
- package/package.json +51 -0
- package/playbooks/feature-development-playbook.md +239 -0
- package/playbooks/sprint-planner-playbook.md +127 -0
- package/playbooks/squad-pipeline-runner.md +196 -0
- package/playbooks/ssh-multi-account-setup.md +185 -0
- package/prompts/01-search.md +18 -0
- package/prompts/02-spec.md +19 -0
- package/prompts/03-tasks.md +15 -0
- package/prompts/04-code.md +10 -0
- package/prompts/05-reviews.md +11 -0
- package/rules/plan-mode.md +60 -0
- package/scripts/cli/gos-cli.js +679 -0
- package/scripts/hooks/pre-commit-validate.js +201 -0
- package/scripts/integrations/check-ide-compat.js +44 -0
- package/scripts/integrations/setup-ide-adapters.js +87 -0
- package/scripts/tools/clickup-preprocess.js +218 -0
- package/scripts/tools/clickup.js +1058 -0
- package/skills/agent-teams/SKILL.md +78 -0
- package/skills/agent-teams/presets/team-all.yaml +14 -0
- package/skills/agent-teams/presets/team-fullstack.yaml +17 -0
- package/skills/agent-teams/presets/team-ide-minimal.yaml +9 -0
- package/skills/agent-teams/presets/team-no-ui.yaml +12 -0
- package/skills/agent-teams/presets/team-qa-focused.yaml +83 -0
- package/skills/clickup/SKILL.md +151 -0
- package/skills/component-dedup/SKILL.md +101 -0
- package/skills/design-to-code/SKILL.md +255 -0
- package/skills/figma-implement-design/SKILL.md +227 -0
- package/skills/figma-make-analyzer/SKILL.md +140 -0
- package/skills/frontend-dev/SKILL.md +271 -0
- package/skills/git-ssh-setup/SKILL.md +164 -0
- package/skills/interface-design/SKILL.md +350 -0
- package/skills/interface-design/references/audit.md +76 -0
- package/skills/interface-design/references/craft-examples.md +134 -0
- package/skills/interface-design/references/critique.md +92 -0
- package/skills/interface-design/references/extract.md +92 -0
- package/skills/interface-design/references/principles.md +348 -0
- package/skills/interface-design/references/templates/system-precision.md +73 -0
- package/skills/interface-design/references/templates/system-warmth.md +67 -0
- package/skills/interface-design/references/validation.md +137 -0
- package/skills/make-code-triage/SKILL.md +135 -0
- package/skills/make-version-diff/SKILL.md +87 -0
- package/skills/plan-to-tasks/SKILL.md +136 -0
- package/skills/react-best-practices/AGENTS.md +2975 -0
- package/skills/react-best-practices/SKILL.md +151 -0
- package/skills/react-best-practices/metadata.json +15 -0
- package/skills/react-best-practices/rules/_sections.md +46 -0
- package/skills/react-best-practices/rules/_template.md +28 -0
- package/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/skills/react-best-practices/rules/advanced-init-once.md +42 -0
- package/skills/react-best-practices/rules/advanced-use-latest.md +39 -0
- package/skills/react-best-practices/rules/async-api-routes.md +38 -0
- package/skills/react-best-practices/rules/async-defer-await.md +80 -0
- package/skills/react-best-practices/rules/async-dependencies.md +51 -0
- package/skills/react-best-practices/rules/async-parallel.md +28 -0
- package/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
- package/skills/react-best-practices/rules/bundle-conditional.md +31 -0
- package/skills/react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/skills/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/skills/react-best-practices/rules/bundle-preload.md +50 -0
- package/skills/react-best-practices/rules/client-event-listeners.md +74 -0
- package/skills/react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
- package/skills/react-best-practices/rules/js-batch-dom-css.md +107 -0
- package/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
- package/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
- package/skills/react-best-practices/rules/js-cache-storage.md +70 -0
- package/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
- package/skills/react-best-practices/rules/js-early-exit.md +50 -0
- package/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/skills/react-best-practices/rules/js-index-maps.md +37 -0
- package/skills/react-best-practices/rules/js-length-check-first.md +49 -0
- package/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
- package/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/skills/react-best-practices/rules/rendering-activity.md +26 -0
- package/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/skills/react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/skills/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/skills/react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
- package/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/skills/react-best-practices/rules/rendering-usetransition-loading.md +75 -0
- package/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
- package/skills/react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
- package/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
- package/skills/react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/skills/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/skills/react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
- package/skills/react-best-practices/rules/rerender-memo.md +44 -0
- package/skills/react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
- package/skills/react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
- package/skills/react-best-practices/rules/rerender-transitions.md +40 -0
- package/skills/react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
- package/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/skills/react-best-practices/rules/server-auth-actions.md +96 -0
- package/skills/react-best-practices/rules/server-cache-lru.md +41 -0
- package/skills/react-best-practices/rules/server-cache-react.md +76 -0
- package/skills/react-best-practices/rules/server-dedup-props.md +65 -0
- package/skills/react-best-practices/rules/server-hoist-static-io.md +142 -0
- package/skills/react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/skills/react-best-practices/rules/server-serialization.md +38 -0
- package/skills/react-doctor/SKILL.md +74 -0
- package/skills/registry.json +21 -0
- package/skills/sprint-planner/SKILL.md +434 -0
- package/squads/design-delivery/README.md +10 -0
- package/squads/design-delivery/squad.yaml +30 -0
- package/squads/design-delivery/workflows/wf-design-delivery.yaml +27 -0
- package/squads/design-squad/README.md +31 -0
- package/squads/design-squad/agents/brad-frost.md +185 -0
- package/squads/design-squad/agents/dan-mall.md +178 -0
- package/squads/design-squad/agents/dave-malouf.md +198 -0
- package/squads/design-squad/agents/design-chief.md +109 -0
- package/squads/design-squad/agents/design-system-architect.md +109 -0
- package/squads/design-squad/agents/ui-engineer.md +102 -0
- package/squads/design-squad/agents/ux-designer.md +105 -0
- package/squads/design-squad/agents/visual-generator.md +108 -0
- package/squads/design-squad/checklists/output-quality.md +76 -0
- package/squads/design-squad/config/config.yaml +65 -0
- package/squads/design-squad/data/design-patterns-catalog.yaml +276 -0
- package/squads/design-squad/data/routing-catalog.yaml +95 -0
- package/squads/design-squad/squad.yaml +88 -0
- package/squads/design-squad/tasks/audit-design.md +174 -0
- package/squads/design-squad/tasks/create-component-spec.md +185 -0
- package/squads/design-squad/tasks/create-design-system.md +179 -0
- package/squads/design-squad/tasks/design-ux-flow.md +184 -0
- package/squads/design-squad/tasks/diagnose.md +138 -0
- package/squads/design-squad/tasks/generate-handoff.md +186 -0
- package/squads/design-squad/tasks/review.md +133 -0
- package/squads/design-squad/tasks/setup-design-ops.md +177 -0
- package/squads/design-squad/workflows/wf-design-system-creation.yaml +131 -0
- package/squads/design-squad/workflows/wf-feature-design.yaml +114 -0
- package/squads/git-operations/README.md +30 -0
- package/squads/git-operations/squad.yaml +27 -0
- package/squads/git-operations/workflows/wf-safe-commit.yaml +27 -0
- package/squads/git-operations/workflows/wf-ssh-setup.yaml +27 -0
- package/squads/sprint-planning/agents/sprint-chief.md +47 -0
- package/squads/sprint-planning/agents/sprint-planner-agent.md +43 -0
- package/squads/sprint-planning/agents/sprint-tracker.md +43 -0
- package/squads/sprint-planning/agents/task-importer.md +44 -0
- package/squads/sprint-planning/checklists/sprint-readiness.md +27 -0
- package/squads/sprint-planning/config/config.yaml +65 -0
- package/squads/sprint-planning/data/clickup-field-mapping.yaml +94 -0
- package/squads/sprint-planning/squad.yaml +52 -0
- package/squads/sprint-planning/tasks/close-sprint.md +43 -0
- package/squads/sprint-planning/tasks/create-sprint.md +42 -0
- package/squads/sprint-planning/tasks/import-tasks.md +39 -0
- package/squads/sprint-planning/tasks/sync-status.md +31 -0
- package/squads/sprint-planning/workflows/wf-sprint-creation.yaml +59 -0
- package/squads/sprint-planning/workflows/wf-sprint-sync.yaml +35 -0
- package/templates/adr-tmpl.yaml +76 -0
- package/templates/sprint-clickup.template.md +80 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* pre-commit-validate.js
|
|
5
|
+
*
|
|
6
|
+
* Validacao pre-commit: roda tsc --noEmit e testes antes do commit.
|
|
7
|
+
* Zero-dependency. Usa execFileSync para seguranca (sem shell injection).
|
|
8
|
+
*
|
|
9
|
+
* Uso:
|
|
10
|
+
* node scripts/hooks/pre-commit-validate.js [--json] [--skip-tests] [--skip-tsc]
|
|
11
|
+
*
|
|
12
|
+
* Exit codes:
|
|
13
|
+
* 0 — todos os checks passaram
|
|
14
|
+
* 1 — um ou mais checks falharam
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
const { execFileSync } = require('child_process');
|
|
18
|
+
const { existsSync, readFileSync } = require('fs');
|
|
19
|
+
const { join } = require('path');
|
|
20
|
+
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Flags
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
const args = process.argv.slice(2);
|
|
25
|
+
const jsonOutput = args.includes('--json');
|
|
26
|
+
const skipTests = args.includes('--skip-tests');
|
|
27
|
+
const skipTsc = args.includes('--skip-tsc');
|
|
28
|
+
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// Detectar diretorio do projeto
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// Se chamado de dentro de um workspace, usar cwd.
|
|
33
|
+
// Se chamado via scripts/hooks/, subir ate a raiz do projeto.
|
|
34
|
+
function findProjectRoot() {
|
|
35
|
+
let dir = process.cwd();
|
|
36
|
+
// Procurar package.json subindo no maximo 5 niveis
|
|
37
|
+
for (let i = 0; i < 5; i++) {
|
|
38
|
+
if (existsSync(join(dir, 'package.json'))) return dir;
|
|
39
|
+
const parent = join(dir, '..');
|
|
40
|
+
if (parent === dir) break;
|
|
41
|
+
dir = parent;
|
|
42
|
+
}
|
|
43
|
+
return process.cwd();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const PROJECT_ROOT = findProjectRoot();
|
|
47
|
+
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
// Detectar package manager
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
function detectPackageManager() {
|
|
52
|
+
if (existsSync(join(PROJECT_ROOT, 'pnpm-lock.yaml'))) return 'pnpm';
|
|
53
|
+
if (existsSync(join(PROJECT_ROOT, 'bun.lockb')) || existsSync(join(PROJECT_ROOT, 'bun.lock'))) return 'bun';
|
|
54
|
+
if (existsSync(join(PROJECT_ROOT, 'yarn.lock'))) return 'yarn';
|
|
55
|
+
return 'npm';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ---------------------------------------------------------------------------
|
|
59
|
+
// Ler package.json
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
function readPkg() {
|
|
62
|
+
const pkgPath = join(PROJECT_ROOT, 'package.json');
|
|
63
|
+
if (!existsSync(pkgPath)) return {};
|
|
64
|
+
try {
|
|
65
|
+
return JSON.parse(readFileSync(pkgPath, 'utf8'));
|
|
66
|
+
} catch {
|
|
67
|
+
return {};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
// Rodar comando com execFileSync
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
function runCheck(name, cmd, cmdArgs, opts = {}) {
|
|
75
|
+
const start = Date.now();
|
|
76
|
+
try {
|
|
77
|
+
const output = execFileSync(cmd, cmdArgs, {
|
|
78
|
+
cwd: PROJECT_ROOT,
|
|
79
|
+
encoding: 'utf8',
|
|
80
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
81
|
+
timeout: 300_000, // 5 min max
|
|
82
|
+
...opts
|
|
83
|
+
});
|
|
84
|
+
return {
|
|
85
|
+
name,
|
|
86
|
+
status: 'pass',
|
|
87
|
+
output: output.trim().slice(0, 2000),
|
|
88
|
+
duration: Date.now() - start
|
|
89
|
+
};
|
|
90
|
+
} catch (err) {
|
|
91
|
+
const stderr = err.stderr ? err.stderr.toString().trim() : '';
|
|
92
|
+
const stdout = err.stdout ? err.stdout.toString().trim() : '';
|
|
93
|
+
return {
|
|
94
|
+
name,
|
|
95
|
+
status: 'fail',
|
|
96
|
+
output: (stderr || stdout || err.message).slice(0, 4000),
|
|
97
|
+
duration: Date.now() - start
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
// Detectar script de teste disponivel
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
function detectTestScript(pkg) {
|
|
106
|
+
const scripts = pkg.scripts || {};
|
|
107
|
+
// Prioridade: test:run (vitest --run) > test:e2e > test
|
|
108
|
+
if (scripts['test:run']) return 'test:run';
|
|
109
|
+
if (scripts['test:e2e']) return 'test:e2e';
|
|
110
|
+
if (scripts['test']) {
|
|
111
|
+
// Se o script test e apenas "vitest" (sem --run), adicionar --run
|
|
112
|
+
// para evitar watch mode
|
|
113
|
+
return 'test';
|
|
114
|
+
}
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
// Main
|
|
120
|
+
// ---------------------------------------------------------------------------
|
|
121
|
+
function main() {
|
|
122
|
+
const pm = detectPackageManager();
|
|
123
|
+
const pkg = readPkg();
|
|
124
|
+
const checks = [];
|
|
125
|
+
|
|
126
|
+
// Check 1: TypeScript (tsc --noEmit)
|
|
127
|
+
if (!skipTsc) {
|
|
128
|
+
const hasTsConfig = existsSync(join(PROJECT_ROOT, 'tsconfig.json'));
|
|
129
|
+
if (hasTsConfig) {
|
|
130
|
+
// Tentar usar npx para garantir que tsc esta disponivel
|
|
131
|
+
const check = runCheck('tsc --noEmit', 'npx', ['tsc', '--noEmit']);
|
|
132
|
+
checks.push(check);
|
|
133
|
+
} else {
|
|
134
|
+
checks.push({
|
|
135
|
+
name: 'tsc --noEmit',
|
|
136
|
+
status: 'skip',
|
|
137
|
+
output: 'tsconfig.json nao encontrado',
|
|
138
|
+
duration: 0
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Check 2: Testes
|
|
144
|
+
if (!skipTests) {
|
|
145
|
+
const testScript = detectTestScript(pkg);
|
|
146
|
+
if (testScript) {
|
|
147
|
+
// Construir comando: <pm> run <script> -- --run (para vitest)
|
|
148
|
+
const cmdArgs = ['run', testScript];
|
|
149
|
+
|
|
150
|
+
// Se o script e "test" e usa vitest, adicionar --run para evitar watch
|
|
151
|
+
const scriptCmd = (pkg.scripts || {})[testScript] || '';
|
|
152
|
+
if (scriptCmd.includes('vitest') && !scriptCmd.includes('--run')) {
|
|
153
|
+
cmdArgs.push('--', '--run');
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const check = runCheck(`${pm} run ${testScript}`, pm, cmdArgs);
|
|
157
|
+
checks.push(check);
|
|
158
|
+
} else {
|
|
159
|
+
checks.push({
|
|
160
|
+
name: 'tests',
|
|
161
|
+
status: 'skip',
|
|
162
|
+
output: 'Nenhum script de teste encontrado no package.json',
|
|
163
|
+
duration: 0
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Resultado
|
|
169
|
+
const passed = checks.every(c => c.status === 'pass' || c.status === 'skip');
|
|
170
|
+
const result = {
|
|
171
|
+
passed,
|
|
172
|
+
packageManager: pm,
|
|
173
|
+
projectRoot: PROJECT_ROOT,
|
|
174
|
+
checks,
|
|
175
|
+
timestamp: new Date().toISOString()
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
if (jsonOutput) {
|
|
179
|
+
process.stdout.write(JSON.stringify(result, null, 2) + '\n');
|
|
180
|
+
} else {
|
|
181
|
+
// Output legivel
|
|
182
|
+
const icon = passed ? '\u2705' : '\u274C';
|
|
183
|
+
console.log(`\n${icon} Pre-Commit Validation\n`);
|
|
184
|
+
for (const c of checks) {
|
|
185
|
+
const statusIcon = c.status === 'pass' ? '\u2705' : c.status === 'skip' ? '\u23ED' : '\u274C';
|
|
186
|
+
console.log(` ${statusIcon} ${c.name} (${c.duration}ms)`);
|
|
187
|
+
if (c.status === 'fail') {
|
|
188
|
+
// Mostrar primeiras linhas do output de erro
|
|
189
|
+
const lines = c.output.split('\n').slice(0, 15);
|
|
190
|
+
for (const line of lines) {
|
|
191
|
+
console.log(` ${line}`);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
console.log(`\n${passed ? 'Todos os checks passaram.' : 'Checks falharam. Corrija os erros antes do commit.'}\n`);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
process.exit(passed ? 0 : 1);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
main();
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
|
|
6
|
+
const root = process.cwd();
|
|
7
|
+
const required = [
|
|
8
|
+
'AGENTS.md',
|
|
9
|
+
'CLAUDE.md',
|
|
10
|
+
'GEMINI.md',
|
|
11
|
+
'prompts/01-search.md',
|
|
12
|
+
'prompts/02-spec.md',
|
|
13
|
+
'prompts/03-tasks.md',
|
|
14
|
+
'prompts/04-code.md',
|
|
15
|
+
'prompts/05-reviews.md',
|
|
16
|
+
'integrations/registry.json',
|
|
17
|
+
'integrations/claude/command-map.json',
|
|
18
|
+
'integrations/codex/command-map.json',
|
|
19
|
+
'integrations/opencode/command-map.json',
|
|
20
|
+
'integrations/antigravity/command-map.json',
|
|
21
|
+
'integrations/gemini/command-map.json',
|
|
22
|
+
'integrations/cursor/command-map.json',
|
|
23
|
+
'integrations/kilo-code/command-map.json',
|
|
24
|
+
'.claude/commands/gos/agents/dev.md',
|
|
25
|
+
'.claude/commands/gos/skills/design-to-code.md',
|
|
26
|
+
'.codex/skills/gos-design-to-code.md',
|
|
27
|
+
'.gemini/skills/gos-design-to-code/SKILL.md',
|
|
28
|
+
'.opencode/skills/gos-design-to-code/SKILL.md',
|
|
29
|
+
'.antigravity/instructions.md',
|
|
30
|
+
'.cursor/rules/g-os.mdc',
|
|
31
|
+
'.kilocode/rules/g-os.md'
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
const missing = required.filter((entry) => !fs.existsSync(path.join(root, entry)));
|
|
35
|
+
|
|
36
|
+
if (missing.length > 0) {
|
|
37
|
+
console.error('Missing compatibility artifacts:');
|
|
38
|
+
for (const entry of missing) {
|
|
39
|
+
console.error(`- ${entry}`);
|
|
40
|
+
}
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
console.log('All IDE compatibility artifacts are present.');
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require('node:fs');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
|
|
6
|
+
const root = process.cwd();
|
|
7
|
+
|
|
8
|
+
function ensureDir(dirPath) {
|
|
9
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function writeFile(filePath, content) {
|
|
13
|
+
ensureDir(path.dirname(filePath));
|
|
14
|
+
fs.writeFileSync(filePath, content.replace(/\r?\n/g, '\n') + '\n');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function readJson(filePath) {
|
|
18
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function relativeTarget(fromFile, targetFile) {
|
|
22
|
+
return path.relative(path.dirname(fromFile), targetFile).replace(/\\/g, '/');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function agentWrapper(agentId, target) {
|
|
26
|
+
return `# ${agentId}\n\nFonte canonica: \`${target}\`\n\nLeia e siga o perfil em \`${target}\`.\nEste arquivo existe apenas como adapter fino para a IDE.`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function skillWrapper(slug, target) {
|
|
30
|
+
return `# gos-${slug}\n\nFonte canonica: \`${target}\`\n\nLeia e siga a skill em \`${target}\`.\nEste arquivo existe apenas como adapter fino para a IDE.`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function main() {
|
|
34
|
+
const agents = readJson(path.join(root, 'agents', 'profiles', 'index.json')).profiles;
|
|
35
|
+
const skills = readJson(path.join(root, 'skills', 'registry.json')).skills;
|
|
36
|
+
|
|
37
|
+
for (const agent of agents) {
|
|
38
|
+
const claudeFile = path.join(root, '.claude', 'commands', 'gos', 'agents', `${agent.id}.md`);
|
|
39
|
+
const target = relativeTarget(claudeFile, path.join(root, 'agents', 'profiles', agent.path));
|
|
40
|
+
writeFile(claudeFile, agentWrapper(agent.id, target));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
for (const skill of skills) {
|
|
44
|
+
const skillTargetPath = skill.skillFile || skill.path;
|
|
45
|
+
const claudeSkill = path.join(root, '.claude', 'commands', 'gos', 'skills', `${skill.slug}.md`);
|
|
46
|
+
const codexSkill = path.join(root, '.codex', 'skills', `gos-${skill.slug}.md`);
|
|
47
|
+
const geminiSkill = path.join(root, '.gemini', 'skills', `gos-${skill.slug}`, 'SKILL.md');
|
|
48
|
+
const opencodeSkill = path.join(root, '.opencode', 'skills', `gos-${skill.slug}`, 'SKILL.md');
|
|
49
|
+
|
|
50
|
+
writeFile(claudeSkill, skillWrapper(skill.slug, relativeTarget(claudeSkill, path.join(root, skillTargetPath))));
|
|
51
|
+
writeFile(codexSkill, skillWrapper(skill.slug, relativeTarget(codexSkill, path.join(root, skillTargetPath))));
|
|
52
|
+
writeFile(geminiSkill, skillWrapper(skill.slug, relativeTarget(geminiSkill, path.join(root, skillTargetPath))));
|
|
53
|
+
writeFile(opencodeSkill, skillWrapper(skill.slug, relativeTarget(opencodeSkill, path.join(root, skillTargetPath))));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const antigravityInstructions = [
|
|
57
|
+
'# G-OS Antigravity Instructions',
|
|
58
|
+
'',
|
|
59
|
+
'Leia sempre:',
|
|
60
|
+
'- `AGENTS.md`',
|
|
61
|
+
'- `CLAUDE.md`',
|
|
62
|
+
'- `docs/toolchain-map.md`',
|
|
63
|
+
'',
|
|
64
|
+
'Agentes disponiveis:',
|
|
65
|
+
...agents.map((agent) => `- ${agent.id}`),
|
|
66
|
+
'',
|
|
67
|
+
'Skills curadas:',
|
|
68
|
+
...skills.map((skill) => `- ${skill.slug}`)
|
|
69
|
+
].join('\n');
|
|
70
|
+
|
|
71
|
+
writeFile(path.join(root, '.antigravity', 'instructions.md'), antigravityInstructions);
|
|
72
|
+
writeFile(
|
|
73
|
+
path.join(root, '.antigravity', 'config.json'),
|
|
74
|
+
JSON.stringify(
|
|
75
|
+
{
|
|
76
|
+
project: 'g-os',
|
|
77
|
+
instructions: ['instructions.md', '../AGENTS.md', '../CLAUDE.md']
|
|
78
|
+
},
|
|
79
|
+
null,
|
|
80
|
+
2
|
|
81
|
+
)
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
console.log(`Adapters generated for ${agents.length} agents and ${skills.length} skills.`);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
main();
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
'use strict'
|
|
4
|
+
|
|
5
|
+
const ACCENT_FIXES = {
|
|
6
|
+
'nao': 'não', 'entao': 'então', 'tambem': 'também', 'codigo': 'código',
|
|
7
|
+
'pagina': 'página', 'unico': 'único', 'analise': 'análise', 'modulo': 'módulo',
|
|
8
|
+
'numero': 'número', 'especifico': 'específico', 'diretorio': 'diretório',
|
|
9
|
+
'padrao': 'padrão', 'configuracao': 'configuração', 'validacao': 'validação',
|
|
10
|
+
'implementacao': 'implementação', 'descricao': 'descrição', 'opcao': 'opção',
|
|
11
|
+
'sessao': 'sessão', 'secao': 'seção', 'funcao': 'função', 'acao': 'ação',
|
|
12
|
+
'informacao': 'informação', 'versao': 'versão', 'conexao': 'conexão',
|
|
13
|
+
'excecao': 'exceção', 'condicao': 'condição', 'operacao': 'operação',
|
|
14
|
+
'autenticacao': 'autenticação', 'migracao': 'migração', 'integracao': 'integração',
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const AI_PATTERNS = [
|
|
18
|
+
/\bvale ressaltar\b/gi, /\be importante destacar\b/gi,
|
|
19
|
+
/\bnesse sentido\b/gi, /\bdiante disso\b/gi,
|
|
20
|
+
/\bem suma\b/gi, /\bpor fim\b/gi,
|
|
21
|
+
/\brobusto\b/gi, /\babrangente\b/gi,
|
|
22
|
+
/\binovador\b/gi, /\bestrategico\b/gi,
|
|
23
|
+
/\bholistic[oa]\b/gi, /\balem disso\b/gi,
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
function fixAccents(text) {
|
|
27
|
+
if (typeof text !== 'string' || !text) return text
|
|
28
|
+
let output = text
|
|
29
|
+
for (const [wrong, right] of Object.entries(ACCENT_FIXES)) {
|
|
30
|
+
output = output.replace(new RegExp(`\\b${wrong}\\b`, 'gi'), (match) => {
|
|
31
|
+
if (match === match.toUpperCase()) return right.toUpperCase()
|
|
32
|
+
if (match[0] === match[0].toUpperCase()) return right[0].toUpperCase() + right.slice(1)
|
|
33
|
+
return right
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
return output
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function detectAIPatterns(text) {
|
|
40
|
+
if (!text) return { count: 0, matches: [] }
|
|
41
|
+
const haystack = Array.isArray(text) ? text.join('\n') : String(text)
|
|
42
|
+
const matches = []
|
|
43
|
+
let count = 0
|
|
44
|
+
for (const pattern of AI_PATTERNS) {
|
|
45
|
+
const found = haystack.match(pattern)
|
|
46
|
+
if (found) {
|
|
47
|
+
count += found.length
|
|
48
|
+
matches.push({ pattern: pattern.source, count: found.length })
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return { count, matches }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function buildTaskDescription(task) {
|
|
55
|
+
const sections = []
|
|
56
|
+
|
|
57
|
+
// Descrição principal (texto livre, sem header)
|
|
58
|
+
if (task.description) sections.push(task.description)
|
|
59
|
+
|
|
60
|
+
// Seções estruturadas — headers H3, sem emojis, português com acentos
|
|
61
|
+
if (task.context) sections.push(`### Contexto\n${task.context}`)
|
|
62
|
+
if (task.steps?.length) sections.push(`### Como fazer\n${task.steps.map((s, i) => `${i + 1}. ${s}`).join('\n')}`)
|
|
63
|
+
if (task.businessRules?.length) sections.push(`### Regras de Negócio\n${task.businessRules.map((r) => `\`${r}\``).join(' · ')}`)
|
|
64
|
+
if (task.files?.length) sections.push(`### Arquivos\n${task.files.map((f) => `- \`${f}\``).join('\n')}`)
|
|
65
|
+
if (task.dependencies?.length) sections.push(`### Dependências\n${task.dependencies.map((d) => `- ${d}`).join('\n')}`)
|
|
66
|
+
if (task.acceptanceCriteria?.length) sections.push(`### Critérios de Aceite\n${task.acceptanceCriteria.map((a) => `- [ ] ${a}`).join('\n')}`)
|
|
67
|
+
if (task.ref) sections.push(`### Referência\n${task.ref}`)
|
|
68
|
+
if (task.technicalNotes) sections.push(`### Notas Técnicas\n${task.technicalNotes}`)
|
|
69
|
+
if (task.dod) sections.push(`### Definition of Done\n${task.dod}`)
|
|
70
|
+
|
|
71
|
+
// Primeira seção (descrição) separada das demais por ---
|
|
72
|
+
if (sections.length > 1) {
|
|
73
|
+
return sections[0] + '\n\n---\n\n' + sections.slice(1).join('\n\n')
|
|
74
|
+
}
|
|
75
|
+
return sections.join('\n\n')
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
function scoreCompleteness(task) {
|
|
80
|
+
let score = 0
|
|
81
|
+
const suggestions = []
|
|
82
|
+
|
|
83
|
+
if (task.description && task.description.length > 50) {
|
|
84
|
+
score += 20
|
|
85
|
+
} else if (task.description) {
|
|
86
|
+
score += 5
|
|
87
|
+
suggestions.push(`Descricao muito curta (${task.description.length} chars).`)
|
|
88
|
+
} else {
|
|
89
|
+
suggestions.push('Sem descricao.')
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (task.acceptanceCriteria?.length >= 2 && task.acceptanceCriteria.every((a) => a.length > 20)) {
|
|
93
|
+
score += 25
|
|
94
|
+
} else if (task.acceptanceCriteria?.length) {
|
|
95
|
+
score += 10
|
|
96
|
+
suggestions.push(`ACs insuficientes (${task.acceptanceCriteria.length} item(ns)).`)
|
|
97
|
+
} else {
|
|
98
|
+
suggestions.push('Sem criterios de aceite.')
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (task.steps?.length || task.subtasks?.length) score += 15
|
|
102
|
+
else suggestions.push('Sem steps de implementacao.')
|
|
103
|
+
|
|
104
|
+
if (task.files?.length) score += 10
|
|
105
|
+
else suggestions.push('Sem arquivos listados.')
|
|
106
|
+
|
|
107
|
+
if (task.points && task.points >= 1 && task.points <= 13) score += 10
|
|
108
|
+
else suggestions.push('Sem story points validos.')
|
|
109
|
+
|
|
110
|
+
if (task.dependencies?.length >= 0) score += 5
|
|
111
|
+
|
|
112
|
+
if (task.context || task.businessRules?.length) score += 10
|
|
113
|
+
else suggestions.push('Sem contexto de negocio.')
|
|
114
|
+
|
|
115
|
+
if (task.dod || task.acceptanceCriteria?.some((a) => /\b(dado|quando|entao|given|when|then)\b/i.test(a))) score += 5
|
|
116
|
+
else suggestions.push('Sem Definition of Done explicito.')
|
|
117
|
+
|
|
118
|
+
return { score, suggestions }
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function sanitizeTaskTexts(task) {
|
|
122
|
+
const copy = { ...task }
|
|
123
|
+
let aiPatternCount = 0
|
|
124
|
+
const textFields = ['description', 'context', 'technicalNotes', 'dod', 'title', 'name', 'ref']
|
|
125
|
+
const arrayFields = ['acceptanceCriteria', 'steps', 'businessRules', 'dependencies', 'files']
|
|
126
|
+
|
|
127
|
+
for (const field of textFields) {
|
|
128
|
+
if (typeof copy[field] === 'string') {
|
|
129
|
+
copy[field] = fixAccents(copy[field])
|
|
130
|
+
aiPatternCount += detectAIPatterns(copy[field]).count
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
for (const field of arrayFields) {
|
|
135
|
+
if (Array.isArray(copy[field])) {
|
|
136
|
+
copy[field] = copy[field].map((item) => {
|
|
137
|
+
if (typeof item !== 'string') return item
|
|
138
|
+
const fixed = fixAccents(item)
|
|
139
|
+
aiPatternCount += detectAIPatterns(fixed).count
|
|
140
|
+
return fixed
|
|
141
|
+
})
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const completeness = scoreCompleteness(copy)
|
|
146
|
+
const description = buildTaskDescription(copy)
|
|
147
|
+
return {
|
|
148
|
+
task: {
|
|
149
|
+
...copy,
|
|
150
|
+
completenessScore: completeness.score,
|
|
151
|
+
completenessSuggestions: completeness.suggestions,
|
|
152
|
+
aiPatternCount,
|
|
153
|
+
description,
|
|
154
|
+
},
|
|
155
|
+
aiPatternCount,
|
|
156
|
+
completenessScore: completeness.score,
|
|
157
|
+
completenessSuggestions: completeness.suggestions,
|
|
158
|
+
description,
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function processPayload(payload) {
|
|
163
|
+
if (Array.isArray(payload)) {
|
|
164
|
+
return { tasks: payload.map((task) => sanitizeTaskTexts(task).task) }
|
|
165
|
+
}
|
|
166
|
+
if (payload && Array.isArray(payload.tasks)) {
|
|
167
|
+
return { ...payload, tasks: payload.tasks.map((task) => sanitizeTaskTexts(task).task) }
|
|
168
|
+
}
|
|
169
|
+
if (payload && typeof payload === 'object') {
|
|
170
|
+
return sanitizeTaskTexts(payload).task
|
|
171
|
+
}
|
|
172
|
+
return payload
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function readStdin() {
|
|
176
|
+
return new Promise((resolve, reject) => {
|
|
177
|
+
let data = ''
|
|
178
|
+
process.stdin.setEncoding('utf8')
|
|
179
|
+
process.stdin.on('data', (chunk) => { data += chunk })
|
|
180
|
+
process.stdin.on('end', () => resolve(data))
|
|
181
|
+
process.stdin.on('error', reject)
|
|
182
|
+
})
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
async function main() {
|
|
186
|
+
if (!process.argv.includes('--json')) {
|
|
187
|
+
console.error(JSON.stringify({ error: 'Use --json and provide JSON via stdin' }))
|
|
188
|
+
process.exit(1)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const input = await readStdin()
|
|
192
|
+
let parsed
|
|
193
|
+
try {
|
|
194
|
+
parsed = input.trim() ? JSON.parse(input) : {}
|
|
195
|
+
} catch (error) {
|
|
196
|
+
console.error(JSON.stringify({ error: `Invalid JSON input: ${error.message}` }))
|
|
197
|
+
process.exit(1)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const output = processPayload(parsed)
|
|
201
|
+
process.stdout.write(JSON.stringify(output, null, 2) + '\n')
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (require.main === module) {
|
|
205
|
+
main().catch((error) => {
|
|
206
|
+
console.error(JSON.stringify({ error: error.message }))
|
|
207
|
+
process.exit(1)
|
|
208
|
+
})
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
module.exports = {
|
|
212
|
+
fixAccents,
|
|
213
|
+
detectAIPatterns,
|
|
214
|
+
scoreCompleteness,
|
|
215
|
+
buildTaskDescription,
|
|
216
|
+
sanitizeTaskTexts,
|
|
217
|
+
processPayload,
|
|
218
|
+
}
|