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
- 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.`;
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
- const target = relativeTarget(claudeFile, path.join(root, '.gos', 'agents', 'profiles', agent.path));
40
- writeFile(claudeFile, agentWrapper(agent.id, target));
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, '.codex', 'skills', `gos-${skill.slug}.md`);
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
- writeFile(claudeSkill, skillWrapper(skill.slug, relativeTarget(claudeSkill, path.join(root, '.gos', skillTargetPath))));
52
- writeFile(codexSkill, skillWrapper(skill.slug, relativeTarget(codexSkill, path.join(root, '.gos', skillTargetPath))));
53
- writeFile(geminiSkill, skillWrapper(skill.slug, relativeTarget(geminiSkill, path.join(root, '.gos', skillTargetPath))));
54
- writeFile(opencodeSkill, skillWrapper(skill.slug, relativeTarget(opencodeSkill, path.join(root, '.gos', skillTargetPath))));
55
- ensureDir(path.dirname(qwenSkill));
56
- writeFile(qwenSkill, skillWrapper(skill.slug, relativeTarget(qwenSkill, path.join(root, '.gos', skillTargetPath))));
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ganbatte-os",
3
- "version": "0.2.16",
3
+ "version": "0.2.18",
4
4
  "description": "Framework operacional para design-to-code, squads de entrega e sprint sync com ClickUp.",
5
5
  "bin": {
6
6
  "ganbatte-os": ".gos/scripts/cli/gos-cli.js",