ganbatte-os 0.2.16 → 0.2.17

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
  }
@@ -30,30 +30,102 @@ function skillWrapper(slug, target) {
30
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
31
  }
32
32
 
33
+ function qwenCommandWrapper(name, description, target) {
34
+ const desc = (description || name).replace(/"/g, '\\"').replace(/\n/g, ' ').slice(0, 200);
35
+ 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}}`;
36
+ }
37
+
38
+ function claudeCommandWrapper(name, description, target, argumentHint) {
39
+ const desc = (description || name).replace(/"/g, '\\"').replace(/\n/g, ' ').slice(0, 200);
40
+ const hint = argumentHint ? `\nargument-hint: "${argumentHint.replace(/"/g, '\\"')}"` : '\nargument-hint: "[argumentos opcionais]"';
41
+ 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`;
42
+ }
43
+
44
+ function extractAgentDescription(filePath) {
45
+ if (!fs.existsSync(filePath)) return '';
46
+ const content = fs.readFileSync(filePath, 'utf8');
47
+ const topBlock = content.split(/\n\s+persona:/)[0];
48
+ for (const field of ['role', 'title', 'description']) {
49
+ const re = new RegExp(`^\\s{2,4}${field}:\\s*(.+)`, 'm');
50
+ const match = topBlock.match(re);
51
+ if (match) return match[1].trim().replace(/^['"]|['"]$/g, '');
52
+ }
53
+ const useForMatch = content.match(/Use para:\s*\n+\s*-\s*(.+)/);
54
+ if (useForMatch) return `Agent para ${useForMatch[1].trim()}`;
55
+ return '';
56
+ }
57
+
58
+ function parseFrontmatter(filePath) {
59
+ if (!fs.existsSync(filePath)) return {};
60
+ const content = fs.readFileSync(filePath, 'utf8');
61
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
62
+ if (!match) return {};
63
+ const fm = {};
64
+ const lines = match[1].split('\n');
65
+ for (let i = 0; i < lines.length; i++) {
66
+ const kv = lines[i].match(/^(\w[\w-]*):\s*(.*)/);
67
+ if (!kv) continue;
68
+ let val = kv[2].trim();
69
+ if (val.startsWith('"') && val.endsWith('"')) val = val.slice(1, -1);
70
+ if (val === '>' || val === '|' || val === '>-' || val === '|-') {
71
+ const parts = [];
72
+ while (i + 1 < lines.length && /^\s+\S/.test(lines[i + 1])) {
73
+ parts.push(lines[++i].trim());
74
+ }
75
+ val = parts.join(' ');
76
+ }
77
+ fm[kv[1]] = val;
78
+ }
79
+ return fm;
80
+ }
81
+
33
82
  function main() {
34
83
  const agents = readJson(path.join(root, '.gos', 'agents', 'profiles', 'index.json')).profiles;
35
84
  const skills = readJson(path.join(root, '.gos', 'skills', 'registry.json')).skills;
36
85
 
37
86
  for (const agent of agents) {
87
+ const agentProfilePath = path.join(root, '.gos', 'agents', 'profiles', agent.path);
88
+ const agentDesc = extractAgentDescription(agentProfilePath) || `${agent.id} agent`;
89
+
90
+ // Claude commands (requires YAML frontmatter with description)
38
91
  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));
92
+ writeFile(claudeFile, claudeCommandWrapper(`gos-${agent.id}`, agentDesc, relativeTarget(claudeFile, agentProfilePath)));
93
+
94
+ // Qwen commands (requires YAML frontmatter with description)
95
+ const qwenCmd = path.join(root, '.qwen', 'commands', 'gos', 'agents', `${agent.id}.md`);
96
+ writeFile(qwenCmd, qwenCommandWrapper(`gos-${agent.id}`, agentDesc, relativeTarget(qwenCmd, agentProfilePath)));
97
+
98
+ // Qwen sub-agents
99
+ const qwenAgent = path.join(root, '.qwen', 'agents', `gos-${agent.id}.md`);
100
+ const agentTarget = relativeTarget(qwenAgent, agentProfilePath);
101
+ const safeDesc = agentDesc.replace(/"/g, '\\"').replace(/\n/g, ' ').slice(0, 200);
102
+ 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
103
  }
42
104
 
43
105
  for (const skill of skills) {
44
106
  const skillTargetPath = skill.skillFile || skill.path;
107
+ const canonicalPath = path.join(root, '.gos', skillTargetPath);
45
108
  const claudeSkill = path.join(root, '.claude', 'commands', 'gos', 'skills', `${skill.slug}.md`);
46
- const codexSkill = path.join(root, '.codex', 'skills', `gos-${skill.slug}.md`);
109
+ const codexSkill = path.join(root, '.agents', 'skills', `gos-${skill.slug}`, 'SKILL.md');
110
+ const antigravitySkill = path.join(root, '.antigravity', 'skills', `gos-${skill.slug}`, 'SKILL.md');
47
111
  const geminiSkill = path.join(root, '.gemini', 'skills', `gos-${skill.slug}`, 'SKILL.md');
48
112
  const opencodeSkill = path.join(root, '.opencode', 'skills', `gos-${skill.slug}`, 'SKILL.md');
49
113
  const qwenSkill = path.join(root, '.qwen', 'skills', `gos-${skill.slug}`, 'SKILL.md');
50
114
 
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))));
115
+ const qwenCmd = path.join(root, '.qwen', 'commands', 'gos', 'skills', `${skill.slug}.md`);
116
+
117
+ writeFile(claudeSkill, skillWrapper(skill.slug, relativeTarget(claudeSkill, canonicalPath)));
118
+ writeFile(codexSkill, skillWrapper(skill.slug, relativeTarget(codexSkill, canonicalPath)));
119
+ writeFile(antigravitySkill, skillWrapper(skill.slug, relativeTarget(antigravitySkill, canonicalPath)));
120
+ writeFile(geminiSkill, skillWrapper(skill.slug, relativeTarget(geminiSkill, canonicalPath)));
121
+ writeFile(opencodeSkill, skillWrapper(skill.slug, relativeTarget(opencodeSkill, canonicalPath)));
122
+ writeFile(qwenSkill, skillWrapper(skill.slug, relativeTarget(qwenSkill, canonicalPath)));
123
+ const skillFm = parseFrontmatter(canonicalPath);
124
+ const skillDesc = skillFm.description || skill.description || skill.name || skill.slug;
125
+ const skillArgHint = skillFm['argument-hint'] || '';
126
+ writeFile(qwenCmd, qwenCommandWrapper(`gos-${skill.slug}`, skillDesc, relativeTarget(qwenCmd, canonicalPath)));
127
+ // Overwrite Claude skill with frontmatter version
128
+ writeFile(claudeSkill, claudeCommandWrapper(`gos-${skill.slug}`, skillDesc, relativeTarget(claudeSkill, canonicalPath), skillArgHint));
57
129
  }
58
130
 
59
131
  const antigravityInstructions = [
@@ -68,7 +140,16 @@ function main() {
68
140
  ...agents.map((agent) => `- ${agent.id}`),
69
141
  '',
70
142
  'Skills curadas:',
71
- ...skills.map((skill) => `- ${skill.slug}`)
143
+ ...skills.map((skill) => `- ${skill.slug}`),
144
+ '',
145
+ '## Como invocar Skills',
146
+ '',
147
+ 'Para usar uma skill, leia o arquivo canonico e siga suas instrucoes.',
148
+ 'Skills tambem disponiveis como adapters em `.antigravity/skills/`.',
149
+ '',
150
+ '| Skill | Arquivo canonico |',
151
+ '|-------|-----------------|',
152
+ ...skills.map((skill) => `| \`gos-${skill.slug}\` | \`.gos/${skill.skillFile || skill.path}\` |`)
72
153
  ].join('\n');
73
154
 
74
155
  writeFile(path.join(root, '.antigravity', 'instructions.md'), antigravityInstructions);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ganbatte-os",
3
- "version": "0.2.16",
3
+ "version": "0.2.17",
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",