ganbatte-os 0.2.16 → 0.2.18
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.
|
@@ -10,12 +10,12 @@
|
|
|
10
10
|
],
|
|
11
11
|
"supportedIdes": {
|
|
12
12
|
"claude-code": { "workspaceDir": ".claude", "adapter": "integrations/claude", "status": "active" },
|
|
13
|
-
"antigravity": { "workspaceDir": ".antigravity", "adapter": "integrations/antigravity", "status": "active" },
|
|
13
|
+
"antigravity": { "workspaceDir": ".antigravity", "skillsDir": ".antigravity/skills", "adapter": "integrations/antigravity", "status": "active" },
|
|
14
14
|
"gemini-cli": { "workspaceDir": ".gemini", "contextFile": "GEMINI.md", "status": "active" },
|
|
15
15
|
"cursor": { "workspaceDir": ".cursor", "ruleFile": ".cursor/rules/g-os.mdc", "status": "active" },
|
|
16
|
-
"codex": { "workspaceDir": ".codex", "adapter": "integrations/codex", "status": "active" },
|
|
16
|
+
"codex": { "workspaceDir": ".codex", "skillsDir": ".agents/skills", "adapter": "integrations/codex", "status": "active" },
|
|
17
17
|
"opencode": { "workspaceDir": ".opencode", "adapter": "integrations/opencode", "status": "active" },
|
|
18
18
|
"kilo-code": { "workspaceDir": ".kilocode", "ruleFile": ".kilocode/rules/g-os.md", "status": "active" },
|
|
19
|
-
"qwen-code": { "workspaceDir": ".qwen", "adapter": "integrations/qwen", "status": "active" }
|
|
19
|
+
"qwen-code": { "workspaceDir": ".qwen", "skillsDir": ".qwen/skills", "commandsDir": ".qwen/commands/gos", "agentsDir": ".qwen/agents", "adapter": "integrations/qwen", "status": "active" }
|
|
20
20
|
}
|
|
21
21
|
}
|
|
@@ -26,8 +26,60 @@ function agentWrapper(agentId, target) {
|
|
|
26
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
27
|
}
|
|
28
28
|
|
|
29
|
-
function skillWrapper(slug, target) {
|
|
30
|
-
|
|
29
|
+
function skillWrapper(slug, target, description) {
|
|
30
|
+
const body = `# 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
|
+
if (!description) return body;
|
|
32
|
+
const desc = String(description).replace(/"/g, '\\"').replace(/\n/g, ' ').slice(0, 200);
|
|
33
|
+
return `---\nname: "gos-${slug}"\ndescription: "${desc}"\n---\n\n${body}`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function qwenCommandWrapper(name, description, target) {
|
|
37
|
+
const desc = (description || name).replace(/"/g, '\\"').replace(/\n/g, ' ').slice(0, 200);
|
|
38
|
+
return `---\ndescription: "${desc}"\n---\n\n# ${name} (Qwen Command Adapter)\n\n> Adapter para Qwen Code. Fonte canonica: \`${target}\`.\n\nCANONICAL-SOURCE: ${target}\n\n## Adapter Contract\n\n1. Leia o arquivo canonico em **CANONICAL-SOURCE** por completo.\n2. Execute as instrucoes desse arquivo como fonte primaria.\n3. Argumentos do usuario: {{args}}`;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function claudeCommandWrapper(name, description, target, argumentHint) {
|
|
42
|
+
const desc = (description || name).replace(/"/g, '\\"').replace(/\n/g, ' ').slice(0, 200);
|
|
43
|
+
const hint = argumentHint ? `\nargument-hint: "${argumentHint.replace(/"/g, '\\"')}"` : '\nargument-hint: "[argumentos opcionais]"';
|
|
44
|
+
return `---\ndescription: "${desc}"${hint}\n---\n\n# ${name} (Claude Adapter)\n\n> Adapter fino para Claude. Fonte canonica: \`${target}\`.\n\nCANONICAL-SOURCE: ${target}\n\n## Adapter Contract\n\n1. Leia o arquivo canonico indicado em **CANONICAL-SOURCE** por completo.\n2. Execute as instrucoes desse arquivo como fonte primaria.\n3. Argumentos do usuario: $ARGUMENTS`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function extractAgentDescription(filePath) {
|
|
48
|
+
if (!fs.existsSync(filePath)) return '';
|
|
49
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
50
|
+
const topBlock = content.split(/\n\s+persona:/)[0];
|
|
51
|
+
for (const field of ['role', 'title', 'description']) {
|
|
52
|
+
const re = new RegExp(`^\\s{2,4}${field}:\\s*(.+)`, 'm');
|
|
53
|
+
const match = topBlock.match(re);
|
|
54
|
+
if (match) return match[1].trim().replace(/^['"]|['"]$/g, '');
|
|
55
|
+
}
|
|
56
|
+
const useForMatch = content.match(/Use para:\s*\n+\s*-\s*(.+)/);
|
|
57
|
+
if (useForMatch) return `Agent para ${useForMatch[1].trim()}`;
|
|
58
|
+
return '';
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function parseFrontmatter(filePath) {
|
|
62
|
+
if (!fs.existsSync(filePath)) return {};
|
|
63
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
64
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
65
|
+
if (!match) return {};
|
|
66
|
+
const fm = {};
|
|
67
|
+
const lines = match[1].split('\n');
|
|
68
|
+
for (let i = 0; i < lines.length; i++) {
|
|
69
|
+
const kv = lines[i].match(/^(\w[\w-]*):\s*(.*)/);
|
|
70
|
+
if (!kv) continue;
|
|
71
|
+
let val = kv[2].trim();
|
|
72
|
+
if (val.startsWith('"') && val.endsWith('"')) val = val.slice(1, -1);
|
|
73
|
+
if (val === '>' || val === '|' || val === '>-' || val === '|-') {
|
|
74
|
+
const parts = [];
|
|
75
|
+
while (i + 1 < lines.length && /^\s+\S/.test(lines[i + 1])) {
|
|
76
|
+
parts.push(lines[++i].trim());
|
|
77
|
+
}
|
|
78
|
+
val = parts.join(' ');
|
|
79
|
+
}
|
|
80
|
+
fm[kv[1]] = val;
|
|
81
|
+
}
|
|
82
|
+
return fm;
|
|
31
83
|
}
|
|
32
84
|
|
|
33
85
|
function main() {
|
|
@@ -35,25 +87,49 @@ function main() {
|
|
|
35
87
|
const skills = readJson(path.join(root, '.gos', 'skills', 'registry.json')).skills;
|
|
36
88
|
|
|
37
89
|
for (const agent of agents) {
|
|
90
|
+
const agentProfilePath = path.join(root, '.gos', 'agents', 'profiles', agent.path);
|
|
91
|
+
const agentDesc = extractAgentDescription(agentProfilePath) || `${agent.id} agent`;
|
|
92
|
+
|
|
93
|
+
// Claude commands (requires YAML frontmatter with description)
|
|
38
94
|
const claudeFile = path.join(root, '.claude', 'commands', 'gos', 'agents', `${agent.id}.md`);
|
|
39
|
-
|
|
40
|
-
|
|
95
|
+
writeFile(claudeFile, claudeCommandWrapper(`gos-${agent.id}`, agentDesc, relativeTarget(claudeFile, agentProfilePath)));
|
|
96
|
+
|
|
97
|
+
// Qwen commands (requires YAML frontmatter with description)
|
|
98
|
+
const qwenCmd = path.join(root, '.qwen', 'commands', 'gos', 'agents', `${agent.id}.md`);
|
|
99
|
+
writeFile(qwenCmd, qwenCommandWrapper(`gos-${agent.id}`, agentDesc, relativeTarget(qwenCmd, agentProfilePath)));
|
|
100
|
+
|
|
101
|
+
// Qwen sub-agents
|
|
102
|
+
const qwenAgent = path.join(root, '.qwen', 'agents', `gos-${agent.id}.md`);
|
|
103
|
+
const agentTarget = relativeTarget(qwenAgent, agentProfilePath);
|
|
104
|
+
const safeDesc = agentDesc.replace(/"/g, '\\"').replace(/\n/g, ' ').slice(0, 200);
|
|
105
|
+
writeFile(qwenAgent, `---\nname: "gos-${agent.id}"\ndescription: "${safeDesc}"\nmodel: inherit\ntools:\n - Read\n - Glob\n - Grep\n - Bash\n - Edit\n - Write\n---\n\nFonte canonica: \`${agentTarget}\`\nLeia e siga o perfil em \`${agentTarget}\`.`);
|
|
41
106
|
}
|
|
42
107
|
|
|
43
108
|
for (const skill of skills) {
|
|
44
109
|
const skillTargetPath = skill.skillFile || skill.path;
|
|
110
|
+
const canonicalPath = path.join(root, '.gos', skillTargetPath);
|
|
45
111
|
const claudeSkill = path.join(root, '.claude', 'commands', 'gos', 'skills', `${skill.slug}.md`);
|
|
46
|
-
const codexSkill = path.join(root, '.
|
|
112
|
+
const codexSkill = path.join(root, '.agents', 'skills', `gos-${skill.slug}`, 'SKILL.md');
|
|
113
|
+
const antigravitySkill = path.join(root, '.antigravity', 'skills', `gos-${skill.slug}`, 'SKILL.md');
|
|
47
114
|
const geminiSkill = path.join(root, '.gemini', 'skills', `gos-${skill.slug}`, 'SKILL.md');
|
|
48
115
|
const opencodeSkill = path.join(root, '.opencode', 'skills', `gos-${skill.slug}`, 'SKILL.md');
|
|
49
116
|
const qwenSkill = path.join(root, '.qwen', 'skills', `gos-${skill.slug}`, 'SKILL.md');
|
|
50
117
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
118
|
+
const qwenCmd = path.join(root, '.qwen', 'commands', 'gos', 'skills', `${skill.slug}.md`);
|
|
119
|
+
|
|
120
|
+
const skillFm = parseFrontmatter(canonicalPath);
|
|
121
|
+
const skillDesc = skillFm.description || skill.description || skill.name || skill.slug;
|
|
122
|
+
const skillArgHint = skillFm['argument-hint'] || '';
|
|
123
|
+
|
|
124
|
+
writeFile(claudeSkill, skillWrapper(skill.slug, relativeTarget(claudeSkill, canonicalPath), skillDesc));
|
|
125
|
+
writeFile(codexSkill, skillWrapper(skill.slug, relativeTarget(codexSkill, canonicalPath), skillDesc));
|
|
126
|
+
writeFile(antigravitySkill, skillWrapper(skill.slug, relativeTarget(antigravitySkill, canonicalPath), skillDesc));
|
|
127
|
+
writeFile(geminiSkill, skillWrapper(skill.slug, relativeTarget(geminiSkill, canonicalPath), skillDesc));
|
|
128
|
+
writeFile(opencodeSkill, skillWrapper(skill.slug, relativeTarget(opencodeSkill, canonicalPath), skillDesc));
|
|
129
|
+
writeFile(qwenSkill, skillWrapper(skill.slug, relativeTarget(qwenSkill, canonicalPath), skillDesc));
|
|
130
|
+
|
|
131
|
+
writeFile(qwenCmd, qwenCommandWrapper(`gos-${skill.slug}`, skillDesc, relativeTarget(qwenCmd, canonicalPath)));
|
|
132
|
+
writeFile(claudeSkill, claudeCommandWrapper(`gos-${skill.slug}`, skillDesc, relativeTarget(claudeSkill, canonicalPath), skillArgHint));
|
|
57
133
|
}
|
|
58
134
|
|
|
59
135
|
const antigravityInstructions = [
|
|
@@ -68,7 +144,16 @@ function main() {
|
|
|
68
144
|
...agents.map((agent) => `- ${agent.id}`),
|
|
69
145
|
'',
|
|
70
146
|
'Skills curadas:',
|
|
71
|
-
...skills.map((skill) => `- ${skill.slug}`)
|
|
147
|
+
...skills.map((skill) => `- ${skill.slug}`),
|
|
148
|
+
'',
|
|
149
|
+
'## Como invocar Skills',
|
|
150
|
+
'',
|
|
151
|
+
'Para usar uma skill, leia o arquivo canonico e siga suas instrucoes.',
|
|
152
|
+
'Skills tambem disponiveis como adapters em `.antigravity/skills/`.',
|
|
153
|
+
'',
|
|
154
|
+
'| Skill | Arquivo canonico |',
|
|
155
|
+
'|-------|-----------------|',
|
|
156
|
+
...skills.map((skill) => `| \`gos-${skill.slug}\` | \`.gos/${skill.skillFile || skill.path}\` |`)
|
|
72
157
|
].join('\n');
|
|
73
158
|
|
|
74
159
|
writeFile(path.join(root, '.antigravity', 'instructions.md'), antigravityInstructions);
|
package/README.md
CHANGED
|
@@ -112,6 +112,8 @@ O `ganbatte-os` utiliza uma estrutura **encapsulada** para manter seu projeto li
|
|
|
112
112
|
| **plan-to-tasks** | `/gos:skills:plan-to-tasks` | Converte plano em tasks acionaveis |
|
|
113
113
|
| **agent-teams** | `/gos:skills:agent-teams` | Coordena multiplos agentes em time |
|
|
114
114
|
| **git-ssh-setup** | `/gos:skills:git-ssh-setup` | Configura identidade SSH para o workspace |
|
|
115
|
+
| **humanizer** | `/gos:skills:humanizer` | Remove padroes de IA do texto (two-pass audit + soul injection) |
|
|
116
|
+
| **weekly-update** | `/gos:skills:weekly-update` | Resumo semanal de tasks ClickUp → humaniza → posta no Slack (requer aprovacao) |
|
|
115
117
|
|
|
116
118
|
## Documentacao
|
|
117
119
|
|
package/package.json
CHANGED