@deerdesign/deertools 1.0.3 → 1.0.4
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/README.md +12 -2
- package/package.json +1 -1
- package/src/agent-detector.js +160 -0
- package/src/commands.js +22 -8
package/README.md
CHANGED
|
@@ -122,9 +122,19 @@ deertools api rendermind POST /api/v1/visualizations --data-file request.json
|
|
|
122
122
|
# Analyze architectural floor plan PDF and calculate cost estimate (Estimate / Kosztorys):
|
|
123
123
|
deertools estimate --file floorplan.pdf --kitchen 6
|
|
124
124
|
|
|
125
|
-
#
|
|
125
|
+
# Auto-detect installed AI agents (Antigravity, Claude, Codex, Hermes, Cursor) and install skills:
|
|
126
126
|
deertools skill install catalog
|
|
127
|
-
deertools skill install
|
|
127
|
+
deertools skill install all
|
|
128
|
+
|
|
129
|
+
# Install for a specific agent platform:
|
|
130
|
+
deertools skill install all --agent claude # ~/.claude/skills/
|
|
131
|
+
deertools skill install all --agent codex # ~/.codex/skills/
|
|
132
|
+
deertools skill install all --agent hermes # ~/.hermes/skills/
|
|
133
|
+
deertools skill install all --agent cursor # .cursor/rules/*.mdc
|
|
134
|
+
deertools skill install all --agent antigravity # ~/.gemini/config/skills/
|
|
135
|
+
|
|
136
|
+
# Force install across all supported platforms simultaneously:
|
|
137
|
+
deertools skill install all --all-agents
|
|
128
138
|
```
|
|
129
139
|
|
|
130
140
|
---
|
package/package.json
CHANGED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const os = require('os');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Rejestr obsługiwanych platform agentów AI.
|
|
8
|
+
* Obsługuje: Google Antigravity / Gemini, Claude Code, OpenAI Codex, Hermes AI,
|
|
9
|
+
* Cursor IDE (.mdc), Windsurf / Codeium oraz lokalne projekty (.agents/skills).
|
|
10
|
+
*/
|
|
11
|
+
const KNOWN_AGENTS = [
|
|
12
|
+
{
|
|
13
|
+
id: 'antigravity',
|
|
14
|
+
name: 'Google Antigravity / Gemini',
|
|
15
|
+
detect: (home) => fs.existsSync(path.join(home, '.gemini')) || fs.existsSync(path.join(home, '.antigravity')),
|
|
16
|
+
getTarget: (home) => path.join(home, '.gemini', 'config', 'skills'),
|
|
17
|
+
format: 'skill_md',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
id: 'claude',
|
|
21
|
+
name: 'Claude Code',
|
|
22
|
+
detect: (home) => fs.existsSync(path.join(home, '.claude')),
|
|
23
|
+
getTarget: (home) => path.join(home, '.claude', 'skills'),
|
|
24
|
+
format: 'skill_md',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: 'codex',
|
|
28
|
+
name: 'OpenAI Codex',
|
|
29
|
+
detect: (home) => fs.existsSync(path.join(home, '.codex')),
|
|
30
|
+
getTarget: (home) => path.join(home, '.codex', 'skills'),
|
|
31
|
+
format: 'skill_md',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
id: 'hermes',
|
|
35
|
+
name: 'Hermes AI',
|
|
36
|
+
detect: (home) => fs.existsSync(path.join(home, '.hermes')) || fs.existsSync(path.join(home, '.config', 'hermes')) || Boolean(process.env.HERMES_HOME),
|
|
37
|
+
getTarget: (home) => process.env.HERMES_SKILLS_DIR || path.join(home, '.hermes', 'skills'),
|
|
38
|
+
format: 'skill_md',
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
id: 'cursor',
|
|
42
|
+
name: 'Cursor IDE',
|
|
43
|
+
detect: (home, cwd) => fs.existsSync(path.join(cwd, '.cursor')) || fs.existsSync(path.join(home, '.cursor')),
|
|
44
|
+
getTarget: (home, cwd) => fs.existsSync(path.join(cwd, '.cursor')) ? path.join(cwd, '.cursor', 'rules') : path.join(home, '.cursor', 'rules'),
|
|
45
|
+
format: 'cursor_mdc',
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: 'windsurf',
|
|
49
|
+
name: 'Windsurf / Codeium',
|
|
50
|
+
detect: (home, cwd) => fs.existsSync(path.join(cwd, '.windsurfrules')) || fs.existsSync(path.join(cwd, '.windsurf')) || fs.existsSync(path.join(home, '.codeium')),
|
|
51
|
+
getTarget: (home, cwd) => path.join(cwd, '.windsurf', 'rules'),
|
|
52
|
+
format: 'skill_md',
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
id: 'project',
|
|
56
|
+
name: 'Bieżący projekt (.agents/skills)',
|
|
57
|
+
detect: (_home, cwd) => fs.existsSync(path.join(cwd, '.agents')),
|
|
58
|
+
getTarget: (_home, cwd) => path.join(cwd, '.agents', 'skills'),
|
|
59
|
+
format: 'skill_md',
|
|
60
|
+
},
|
|
61
|
+
];
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Wykrywa zainstalowane środowiska agentów lub filtruje według flagi --agent.
|
|
65
|
+
*/
|
|
66
|
+
function detectAgents(options = {}) {
|
|
67
|
+
const home = os.homedir();
|
|
68
|
+
const cwd = process.cwd();
|
|
69
|
+
|
|
70
|
+
// Wskazany bezpośredni katalog instalacji (--dir)
|
|
71
|
+
if (options.dir) {
|
|
72
|
+
return [{
|
|
73
|
+
id: 'custom',
|
|
74
|
+
name: 'Wskazany katalog (--dir)',
|
|
75
|
+
targetDir: path.resolve(options.dir),
|
|
76
|
+
format: 'skill_md',
|
|
77
|
+
}];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Wymuszenie instalacji do WSZYSTKICH obsługiwanych platform (--all-agents)
|
|
81
|
+
if (options['all-agents']) {
|
|
82
|
+
return KNOWN_AGENTS.map((spec) => ({
|
|
83
|
+
id: spec.id,
|
|
84
|
+
name: spec.name,
|
|
85
|
+
targetDir: spec.getTarget(home, cwd),
|
|
86
|
+
format: spec.format,
|
|
87
|
+
}));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Wskazanie konkretnego agenta (--agent claude / --agent codex / --agent hermes / etc.)
|
|
91
|
+
if (options.agent && options.agent !== 'all' && options.agent !== 'auto') {
|
|
92
|
+
const requested = options.agent.toLowerCase().trim();
|
|
93
|
+
const spec = KNOWN_AGENTS.find((a) => a.id === requested);
|
|
94
|
+
if (spec) {
|
|
95
|
+
return [{
|
|
96
|
+
id: spec.id,
|
|
97
|
+
name: spec.name,
|
|
98
|
+
targetDir: spec.getTarget(home, cwd),
|
|
99
|
+
format: spec.format,
|
|
100
|
+
}];
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Automatyczne wykrywanie obecnych agentów
|
|
105
|
+
const matched = [];
|
|
106
|
+
for (const spec of KNOWN_AGENTS) {
|
|
107
|
+
try {
|
|
108
|
+
if (spec.detect(home, cwd)) {
|
|
109
|
+
matched.push({
|
|
110
|
+
id: spec.id,
|
|
111
|
+
name: spec.name,
|
|
112
|
+
targetDir: spec.getTarget(home, cwd),
|
|
113
|
+
format: spec.format,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
} catch (_) { /* ignore */ }
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Fallback: jeśli nic nie wykryto, domyślnie Antigravity
|
|
120
|
+
if (matched.length === 0) {
|
|
121
|
+
matched.push({
|
|
122
|
+
id: 'antigravity',
|
|
123
|
+
name: 'Google Antigravity (~/.gemini)',
|
|
124
|
+
targetDir: path.join(home, '.gemini', 'config', 'skills'),
|
|
125
|
+
format: 'skill_md',
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return matched;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Zapisuje zawartość skilla we właściwym formacie dla danej platformy:
|
|
134
|
+
* - 'skill_md': <targetDir>/<skillName>/SKILL.md (Antigravity, Claude, Codex, Hermes, Project)
|
|
135
|
+
* - 'cursor_mdc': <targetDir>/<skillName>.mdc (Cursor)
|
|
136
|
+
*/
|
|
137
|
+
function installSkillContent(agent, skillName, rawMarkdown) {
|
|
138
|
+
fs.mkdirSync(agent.targetDir, { recursive: true });
|
|
139
|
+
|
|
140
|
+
if (agent.format === 'cursor_mdc') {
|
|
141
|
+
const filePath = path.join(agent.targetDir, `${skillName}.mdc`);
|
|
142
|
+
let content = rawMarkdown;
|
|
143
|
+
if (!rawMarkdown.startsWith('---')) {
|
|
144
|
+
let desc = `DeerTools ${skillName} skill`;
|
|
145
|
+
const descMatch = rawMarkdown.match(/description:\s*([^\n]+)/);
|
|
146
|
+
if (descMatch) desc = descMatch[1].trim();
|
|
147
|
+
content = `---\ndescription: ${desc}\nglobs: *\nalwaysApply: false\n---\n\n${rawMarkdown}`;
|
|
148
|
+
}
|
|
149
|
+
fs.writeFileSync(filePath, content, 'utf8');
|
|
150
|
+
return filePath;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const skillFolder = path.join(agent.targetDir, skillName);
|
|
154
|
+
fs.mkdirSync(skillFolder, { recursive: true });
|
|
155
|
+
const filePath = path.join(skillFolder, 'SKILL.md');
|
|
156
|
+
fs.writeFileSync(filePath, rawMarkdown, 'utf8');
|
|
157
|
+
return filePath;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
module.exports = { KNOWN_AGENTS, detectAgents, installSkillContent };
|
package/src/commands.js
CHANGED
|
@@ -161,20 +161,34 @@ async function cmdEstimate(pos, flags) {
|
|
|
161
161
|
for (const p of d.packages || []) out(` ▶ ${String(p.name).padEnd(12)} ${fmt(p.total_gross)} zł / ${fmt(p.total_net)} zł${p.is_lump_sum ? ' (ryczałt < 45 m²)' : ''}`);
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
+
const { detectAgents, installSkillContent } = require('./agent-detector');
|
|
165
|
+
|
|
164
166
|
async function cmdSkill(pos, flags) {
|
|
165
|
-
if ((pos[0] || 'install') !== 'install') fail('Użycie: deertools skill install [produkt|all] [--dir <katalog
|
|
167
|
+
if ((pos[0] || 'install') !== 'install') fail('Użycie: deertools skill install [produkt|all] [--dir <katalog>] [--agent <antigravity|claude|cursor|project|all>]', 2);
|
|
166
168
|
const products = resolveProducts(pos[1]);
|
|
167
|
-
const
|
|
169
|
+
const agents = detectAgents({ dir: flags.dir, agent: flags.agent });
|
|
170
|
+
|
|
171
|
+
if (agents.length > 1 && !flags.json) {
|
|
172
|
+
out(`Wykryte środowiska agentów AI (${agents.length}):`);
|
|
173
|
+
for (const a of agents) out(` • ${a.name} → ${a.targetDir}`);
|
|
174
|
+
out('');
|
|
175
|
+
}
|
|
176
|
+
|
|
168
177
|
let installed = 0;
|
|
169
178
|
for (const product of products) {
|
|
170
179
|
const r = await fetchText(`${product.site}/skill/SKILL.md`);
|
|
171
180
|
if (!r.ok) { err(`– ${product.name}: brak skilla (${product.site}/skill/SKILL.md → ${r.status})`); continue; }
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
181
|
+
const skillName = parseFrontmatterName(r.text) || `deer-${product.id}`;
|
|
182
|
+
|
|
183
|
+
for (const agent of agents) {
|
|
184
|
+
try {
|
|
185
|
+
const dest = installSkillContent(agent, skillName, r.text);
|
|
186
|
+
out(`✓ [${agent.id}] ${product.name}: ${dest}`);
|
|
187
|
+
installed += 1;
|
|
188
|
+
} catch (e) {
|
|
189
|
+
err(`✗ [${agent.id}] ${product.name}: ${e.message}`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
178
192
|
}
|
|
179
193
|
if (!installed) fail('Nie zainstalowano żadnego skilla.', 4);
|
|
180
194
|
}
|