pixelcrew 0.2.3 → 0.2.6
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 +389 -315
- package/bin/pixel-agents.js +306 -149
- package/package.json +3 -1
- package/skill/SKILL.md +185 -0
- package/skill/references/anti-ai-rubric.md +30 -0
- package/skill/references/anti-ai-slop-encyclopedia.md +181 -0
- package/skill/references/commands-reference.md +135 -0
- package/skill/references/testing-and-qa-strategy.md +25 -0
- package/skill/references/token-efficiency.md +20 -0
- package/src/adapters/adapter.interface.js +77 -0
- package/src/adapters/antigravity.js +138 -0
- package/src/adapters/claude-code.js +149 -0
- package/src/adapters/codex.js +131 -0
- package/src/adapters/cursor.js +133 -0
- package/src/adapters/generic.js +63 -0
- package/src/adapters/index.js +15 -0
- package/src/adapters/kiro.js +134 -0
- package/src/adapters/registry.js +150 -0
- package/src/backend/analyzer/complexity-analyzer.js +104 -0
- package/src/backend/analyzer/requirement-analyzer.js +213 -0
- package/src/backend/analyzer/threat-analyzer.js +122 -0
- package/src/backend/api/api-designer.js +90 -0
- package/src/backend/api/error-contract.js +132 -0
- package/src/backend/api/route-generator.js +92 -0
- package/src/backend/api/schema-generator.js +64 -0
- package/src/backend/architecture/adr-generator.js +62 -0
- package/src/backend/architecture/architecture-reasoner.js +119 -0
- package/src/backend/architecture/architecture-selector.js +57 -0
- package/src/backend/architecture/tradeoff-analyzer.js +92 -0
- package/src/backend/data/data-modeler.js +114 -0
- package/src/backend/data/index-analyzer.js +93 -0
- package/src/backend/data/query-analyzer.js +41 -0
- package/src/backend/data/schema-generator.js +92 -0
- package/src/backend/data/transaction-analyzer.js +49 -0
- package/src/backend/index.js +67 -0
- package/src/backend/observability/logging-engine.js +80 -0
- package/src/backend/observability/metrics-engine.js +31 -0
- package/src/backend/observability/tracing-engine.js +16 -0
- package/src/backend/patterns/pattern-registry.js +74 -0
- package/src/backend/patterns/pattern-selector.js +39 -0
- package/src/backend/patterns/tradeoff-engine.js +17 -0
- package/src/backend/performance/cache-analyzer.js +31 -0
- package/src/backend/performance/concurrency-analyzer.js +34 -0
- package/src/backend/performance/performance-engine.js +98 -0
- package/src/backend/performance/query-optimizer.js +16 -0
- package/src/backend/reliability/failure-analyzer.js +22 -0
- package/src/backend/reliability/idempotency-engine.js +56 -0
- package/src/backend/reliability/resilience-engine.js +141 -0
- package/src/backend/reliability/retry-analyzer.js +15 -0
- package/src/backend/security/auth-selector.js +33 -0
- package/src/backend/security/authorization-engine.js +90 -0
- package/src/backend/security/policy-engine.js +49 -0
- package/src/backend/security/secret-analyzer.js +39 -0
- package/src/backend/security/security-engine.js +122 -0
- package/src/backend/security/threat-model.js +59 -0
- package/src/backend/synthesis/backend-synthesizer.js +98 -0
- package/src/backend/synthesis/infrastructure-synthesizer.js +108 -0
- package/src/backend/synthesis/module-synthesizer.js +262 -0
- package/src/backend/validation/architecture-validator.js +70 -0
- package/src/backend/validation/backend-quality-validator.js +71 -0
- package/src/backend/validation/dependency-validator.js +20 -0
- package/src/backend/validation/performance-validator.js +38 -0
- package/src/backend/validation/security-validator.js +73 -0
- package/src/commands/adapt.js +105 -0
- package/src/commands/add.js +78 -0
- package/src/commands/animate.js +48 -0
- package/src/commands/assemble.js +57 -0
- package/src/commands/audit.js +93 -0
- package/src/commands/backend.js +125 -0
- package/src/commands/bento.js +25 -0
- package/src/commands/blueprint.js +65 -0
- package/src/commands/bolder.js +48 -0
- package/src/commands/boss-fight.js +60 -0
- package/src/commands/build.js +39 -0
- package/src/commands/calibrate.js +25 -0
- package/src/commands/chromatic.js +25 -0
- package/src/commands/clarify.js +52 -0
- package/src/commands/colorize.js +57 -0
- package/src/commands/command.interface.js +28 -0
- package/src/commands/commands.js +84 -0
- package/src/commands/craft.js +57 -0
- package/src/commands/crew.js +66 -0
- package/src/commands/critique.js +25 -0
- package/src/commands/de-slop.js +25 -0
- package/src/commands/delight.js +46 -0
- package/src/commands/deploy.js +42 -0
- package/src/commands/distill.js +48 -0
- package/src/commands/doctor.js +89 -0
- package/src/commands/document.js +83 -0
- package/src/commands/eight-bit.js +25 -0
- package/src/commands/extract.js +75 -0
- package/src/commands/fix.js +46 -0
- package/src/commands/harden.js +85 -0
- package/src/commands/index.js +67 -0
- package/src/commands/install.js +75 -0
- package/src/commands/layout.js +48 -0
- package/src/commands/live.js +44 -0
- package/src/commands/manifest.js +25 -0
- package/src/commands/office.js +25 -0
- package/src/commands/onboard.js +46 -0
- package/src/commands/oneshot.js +60 -0
- package/src/commands/optimize.js +46 -0
- package/src/commands/overdrive.js +46 -0
- package/src/commands/parser.js +143 -0
- package/src/commands/pixelcrew.js +96 -0
- package/src/commands/plan.js +66 -0
- package/src/commands/polish.js +45 -0
- package/src/commands/quieter.js +48 -0
- package/src/commands/recap.js +358 -0
- package/src/commands/registry.js +353 -0
- package/src/commands/render.js +26 -0
- package/src/commands/retrofit.js +25 -0
- package/src/commands/review.js +118 -0
- package/src/commands/roster.js +25 -0
- package/src/commands/sentinel.js +25 -0
- package/src/commands/shape.js +66 -0
- package/src/commands/skills.js +57 -0
- package/src/commands/status.js +48 -0
- package/src/commands/stop.js +50 -0
- package/src/commands/sync.js +58 -0
- package/src/commands/typeset.js +58 -0
- package/src/commands/warp.js +25 -0
- package/src/core/agent-runtime.js +94 -0
- package/src/core/event-bus.js +98 -0
- package/src/core/index.js +9 -0
- package/src/core/orchestrator.js +234 -0
- package/src/core/scheduler.js +124 -0
- package/src/core/task-graph.js +185 -0
- package/src/dashboard/app.js +1172 -30
- package/src/dashboard/index.html +223 -23
- package/src/dashboard/styles.css +870 -0
- package/src/index.js +16 -0
- package/src/orchestrator/artifact-graph.js +104 -0
- package/src/orchestrator/ast-normalizer.js +147 -0
- package/src/orchestrator/code-generator.js +632 -780
- package/src/orchestrator/design-engine.js +203 -0
- package/src/orchestrator/engine.js +307 -38
- package/src/orchestrator/oneshot.js +367 -380
- package/src/orchestrator/ontology.js +394 -0
- package/src/orchestrator/planner.js +231 -258
- package/src/orchestrator/repair-planner.js +67 -0
- package/src/orchestrator/requirement-contract.js +177 -0
- package/src/orchestrator/requirement-validator.js +39 -0
- package/src/orchestrator/semantic-engine.js +582 -0
- package/src/orchestrator/semantic-reviewer.js +179 -0
- package/src/orchestrator/task-planner.js +111 -0
- package/src/orchestrator/telemetry.js +209 -0
- package/src/orchestrator/ui-synthesizer.js +245 -0
- package/src/orchestrator/visual-critic.js +106 -0
- package/src/policies/architecture/layering.policy.js +14 -0
- package/src/policies/performance/indexing.policy.js +13 -0
- package/src/policies/reliability/resilience.policy.js +13 -0
- package/src/policies/security/auth.policy.js +31 -0
- package/src/protocol/agent.js +124 -0
- package/src/protocol/event.js +78 -0
- package/src/protocol/index.js +8 -0
- package/src/protocol/skill.js +54 -0
- package/src/protocol/task.js +100 -0
- package/src/scaffold/claude-generator.js +60 -0
- package/src/scaffold/commands-catalog.js +321 -0
- package/src/scaffold/cursor-generator.js +74 -0
- package/src/scaffold/ide-rules.js +133 -0
- package/src/scaffold/init.js +415 -91
- package/src/scaffold/installer.js +571 -0
- package/src/scaffold/kiro-generator.js +86 -0
- package/src/scaffold/skills-bundle.js +520 -0
- package/src/scaffold/templates.js +57 -4
- package/src/scaffold/workstations.js +364 -0
- package/src/server/server.js +283 -40
- package/src/utils/fs-safe.js +168 -0
- package/src/utils/markdown-report.js +175 -0
|
@@ -0,0 +1,571 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PIXEL CREW — Multi-Provider Skill Installer & Sync Engine
|
|
3
|
+
*
|
|
4
|
+
* Installs, configures, and synchronizes agent skills across:
|
|
5
|
+
* - .pixel-crew/ (Pixel Crew Swarm Manifest & Local Skills)
|
|
6
|
+
* - .claude/ (Anthropic Claude Code)
|
|
7
|
+
* - .cursor/ (Cursor AI IDE)
|
|
8
|
+
* - .kiro/ (Kiro AI IDE)
|
|
9
|
+
* - .agents/ (Google Antigravity & Agentic IDEs)
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import fs from 'node:fs/promises';
|
|
13
|
+
import fsSync from 'node:fs';
|
|
14
|
+
import path from 'node:path';
|
|
15
|
+
import os from 'node:os';
|
|
16
|
+
import { fileURLToPath } from 'node:url';
|
|
17
|
+
import { SKILL_DEFINITIONS } from '../orchestrator/skills-registry.js';
|
|
18
|
+
import { SKILL_MARKDOWNS } from './templates.js';
|
|
19
|
+
import { getSkillBundle, sanitizeFrontmatter } from './skills-bundle.js';
|
|
20
|
+
import { generateKiroFiles } from './kiro-generator.js';
|
|
21
|
+
import { generateCursorFiles, generateAntigravityFiles, generateClaudeFiles } from './ide-rules.js';
|
|
22
|
+
import { safeWriteFile, safeMkdir, DryRunReporter } from '../utils/fs-safe.js';
|
|
23
|
+
|
|
24
|
+
export const PROVIDER_PATHS = {
|
|
25
|
+
'claude-code': (targetDir, skillName) => path.join(targetDir, '.claude', 'skills', skillName, 'SKILL.md'),
|
|
26
|
+
'cursor': (targetDir, skillName) => path.join(targetDir, '.cursor', 'skills', skillName, 'SKILL.md'),
|
|
27
|
+
'kiro': (targetDir, skillName) => path.join(targetDir, '.kiro', 'skills', skillName, 'SKILL.md'),
|
|
28
|
+
'antigravity': (targetDir, skillName) => path.join(targetDir, '.agents', 'skills', skillName, 'SKILL.md'),
|
|
29
|
+
'codex': (targetDir, skillName) => path.join(targetDir, '.codex', 'skills', skillName, 'SKILL.md'),
|
|
30
|
+
'pixel-crew': (targetDir, skillName) => path.join(targetDir, '.pixel-crew', 'skills', `${skillName}.md`)
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const GLOBAL_PROVIDER_PATHS = {
|
|
34
|
+
'claude-code': (skillName, home = (process.env.PIXELCREW_HOME || os.homedir())) => path.join(home, '.claude', 'skills', skillName, 'SKILL.md'),
|
|
35
|
+
'cursor': (skillName, home = (process.env.PIXELCREW_HOME || os.homedir())) => path.join(home, '.cursor', 'skills', skillName, 'SKILL.md'),
|
|
36
|
+
'kiro': (skillName, home = (process.env.PIXELCREW_HOME || os.homedir())) => path.join(home, '.kiro', 'skills', skillName, 'SKILL.md'),
|
|
37
|
+
'antigravity': (skillName, home = (process.env.PIXELCREW_HOME || os.homedir())) => path.join(home, '.gemini', 'config', 'skills', skillName, 'SKILL.md'),
|
|
38
|
+
'codex': (skillName, home = (process.env.PIXELCREW_HOME || os.homedir())) => path.join(home, '.codex', 'skills', skillName, 'SKILL.md'),
|
|
39
|
+
'pixel-crew': (skillName, home = (process.env.PIXELCREW_HOME || os.homedir())) => path.join(home, '.pixel-crew', 'skills', `${skillName}.md`)
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Detects which IDE / Coding Agent environment the current terminal shell is executing inside
|
|
44
|
+
*/
|
|
45
|
+
export function detectActiveIDE(targetDir = process.cwd()) {
|
|
46
|
+
const env = process.env;
|
|
47
|
+
|
|
48
|
+
// 1. Kiro AI
|
|
49
|
+
if (
|
|
50
|
+
env.KIRO === '1' ||
|
|
51
|
+
env.KIRO_AGENT ||
|
|
52
|
+
env.KIRO_SESSION ||
|
|
53
|
+
env.KIRO_APP_DIR ||
|
|
54
|
+
env.TERM_PROGRAM === 'kiro' ||
|
|
55
|
+
env.VSCODE_GIT_ASKPASS_NODE?.toLowerCase().includes('kiro')
|
|
56
|
+
) {
|
|
57
|
+
return {
|
|
58
|
+
id: 'kiro',
|
|
59
|
+
name: 'Kiro AI',
|
|
60
|
+
globalPath: path.join(os.homedir(), '.kiro', 'skills'),
|
|
61
|
+
detectedVia: 'env'
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// 2. Cursor AI
|
|
66
|
+
if (
|
|
67
|
+
env.CURSOR === '1' ||
|
|
68
|
+
env.CURSOR_AGENT ||
|
|
69
|
+
env.CURSOR_SESSION ||
|
|
70
|
+
env.CURSOR_APP_DIR ||
|
|
71
|
+
env.TERM_PROGRAM === 'cursor' ||
|
|
72
|
+
env.VSCODE_GIT_ASKPASS_NODE?.toLowerCase().includes('cursor')
|
|
73
|
+
) {
|
|
74
|
+
return {
|
|
75
|
+
id: 'cursor',
|
|
76
|
+
name: 'Cursor IDE',
|
|
77
|
+
globalPath: path.join(os.homedir(), '.cursor', 'skills'),
|
|
78
|
+
detectedVia: 'env'
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// 3. Google Antigravity
|
|
83
|
+
if (
|
|
84
|
+
env.ANTIGRAVITY_APP_DIR ||
|
|
85
|
+
env.AGY_SESSION ||
|
|
86
|
+
env.ANTIGRAVITY ||
|
|
87
|
+
env.ANTIGRAVITY_IDE ||
|
|
88
|
+
env.AGY ||
|
|
89
|
+
env.TERM_PROGRAM === 'antigravity' ||
|
|
90
|
+
env.VSCODE_GIT_ASKPASS_NODE?.toLowerCase().includes('antigravity') ||
|
|
91
|
+
(env.CORPUS_NAME && env.CONVERSATION_ID)
|
|
92
|
+
) {
|
|
93
|
+
return {
|
|
94
|
+
id: 'antigravity',
|
|
95
|
+
name: 'Google Antigravity',
|
|
96
|
+
globalPath: path.join(os.homedir(), '.gemini', 'config', 'skills'),
|
|
97
|
+
detectedVia: 'env'
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// 4. Claude Code
|
|
102
|
+
if (env.CLAUDE_CODE || env.CLAUDE_SESSION || env.CLAUDE_AGENT) {
|
|
103
|
+
return {
|
|
104
|
+
id: 'claude-code',
|
|
105
|
+
name: 'Claude Code',
|
|
106
|
+
globalPath: path.join(os.homedir(), '.claude', 'skills'),
|
|
107
|
+
detectedVia: 'env'
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// 5. OpenAI Codex
|
|
112
|
+
if (env.CODEX_SESSION || env.CODEX_AGENT || env.CODEX) {
|
|
113
|
+
return {
|
|
114
|
+
id: 'codex',
|
|
115
|
+
name: 'OpenAI Codex',
|
|
116
|
+
globalPath: path.join(os.homedir(), '.codex', 'skills'),
|
|
117
|
+
detectedVia: 'env'
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// 6. Check existing workspace markers in targetDir
|
|
122
|
+
try {
|
|
123
|
+
if (
|
|
124
|
+
fsSync.existsSync(path.join(targetDir, '.kiro')) ||
|
|
125
|
+
fsSync.existsSync(path.join(targetDir, '.kirorules')) ||
|
|
126
|
+
fsSync.existsSync(path.join(targetDir, 'kiro.json'))
|
|
127
|
+
) {
|
|
128
|
+
return {
|
|
129
|
+
id: 'kiro',
|
|
130
|
+
name: 'Kiro AI',
|
|
131
|
+
globalPath: path.join(os.homedir(), '.kiro', 'skills'),
|
|
132
|
+
detectedVia: 'workspace'
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
if (
|
|
136
|
+
fsSync.existsSync(path.join(targetDir, '.cursor')) ||
|
|
137
|
+
fsSync.existsSync(path.join(targetDir, '.cursorrules'))
|
|
138
|
+
) {
|
|
139
|
+
return {
|
|
140
|
+
id: 'cursor',
|
|
141
|
+
name: 'Cursor IDE',
|
|
142
|
+
globalPath: path.join(os.homedir(), '.cursor', 'skills'),
|
|
143
|
+
detectedVia: 'workspace'
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
if (
|
|
147
|
+
fsSync.existsSync(path.join(targetDir, '.agents')) ||
|
|
148
|
+
fsSync.existsSync(path.join(targetDir, 'AGENTS.md'))
|
|
149
|
+
) {
|
|
150
|
+
return {
|
|
151
|
+
id: 'antigravity',
|
|
152
|
+
name: 'Google Antigravity',
|
|
153
|
+
globalPath: path.join(os.homedir(), '.gemini', 'config', 'skills'),
|
|
154
|
+
detectedVia: 'workspace'
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
if (
|
|
158
|
+
fsSync.existsSync(path.join(targetDir, '.claude')) ||
|
|
159
|
+
fsSync.existsSync(path.join(targetDir, 'CLAUDE.md'))
|
|
160
|
+
) {
|
|
161
|
+
return {
|
|
162
|
+
id: 'claude-code',
|
|
163
|
+
name: 'Claude Code',
|
|
164
|
+
globalPath: path.join(os.homedir(), '.claude', 'skills'),
|
|
165
|
+
detectedVia: 'workspace'
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
} catch {}
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
id: 'pixel-crew',
|
|
172
|
+
name: 'Pixel Crew',
|
|
173
|
+
globalPath: path.join(os.homedir(), '.pixel-crew', 'skills'),
|
|
174
|
+
detectedVia: 'default'
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Detects which agent environments exist in the target directory
|
|
180
|
+
*/
|
|
181
|
+
export async function detectInstalledProviders(targetDir = process.cwd()) {
|
|
182
|
+
const detected = new Set(['pixel-crew']);
|
|
183
|
+
|
|
184
|
+
const checks = [
|
|
185
|
+
{ provider: 'claude-code', paths: [path.join(targetDir, '.claude'), path.join(targetDir, 'CLAUDE.md')] },
|
|
186
|
+
{ provider: 'cursor', paths: [path.join(targetDir, '.cursor'), path.join(targetDir, '.cursorrules')] },
|
|
187
|
+
{ provider: 'kiro', paths: [path.join(targetDir, '.kiro'), path.join(targetDir, '.kirorules'), path.join(targetDir, 'kiro.json'), path.join(targetDir, '.kiro.json')] },
|
|
188
|
+
{ provider: 'antigravity', paths: [path.join(targetDir, '.agents'), path.join(targetDir, 'AGENTS.md'), path.join(targetDir, '.gemini')] },
|
|
189
|
+
{ provider: 'pixel-crew', paths: [path.join(targetDir, '.pixel-crew'), path.join(targetDir, '.pixel-agents')] }
|
|
190
|
+
];
|
|
191
|
+
|
|
192
|
+
for (const check of checks) {
|
|
193
|
+
for (const p of check.paths) {
|
|
194
|
+
try {
|
|
195
|
+
await fs.access(p);
|
|
196
|
+
detected.add(check.provider);
|
|
197
|
+
break;
|
|
198
|
+
} catch {}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return Array.from(detected);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Normalizes skill identifier into standard ID and kebab-case name
|
|
207
|
+
*/
|
|
208
|
+
export function normalizeSkillId(rawInput) {
|
|
209
|
+
let cleaned = (rawInput || '').trim();
|
|
210
|
+
// Strip @pixel-crew/ or pixel-crew/
|
|
211
|
+
cleaned = cleaned.replace(/^@?pixel-crew\//, '');
|
|
212
|
+
cleaned = cleaned.replace(/^skills?\//, '');
|
|
213
|
+
|
|
214
|
+
// Check direct match in SKILL_DEFINITIONS
|
|
215
|
+
if (SKILL_DEFINITIONS[cleaned]) {
|
|
216
|
+
const s = SKILL_DEFINITIONS[cleaned];
|
|
217
|
+
const skillName = s.id.includes('/') ? s.id.split('/')[1] : s.id;
|
|
218
|
+
return { id: s.id, name: skillName, definition: s };
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Check by suffix or name match
|
|
222
|
+
for (const [id, def] of Object.entries(SKILL_DEFINITIONS)) {
|
|
223
|
+
const subName = id.includes('/') ? id.split('/')[1] : id;
|
|
224
|
+
if (subName.toLowerCase() === cleaned.toLowerCase() || id.toLowerCase() === cleaned.toLowerCase()) {
|
|
225
|
+
return { id, name: subName, definition: def };
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Fallback for custom skills or oneshot
|
|
230
|
+
const safeName = cleaned.replace(/[^a-zA-Z0-9_-]/g, '-').toLowerCase();
|
|
231
|
+
return {
|
|
232
|
+
id: cleaned,
|
|
233
|
+
name: safeName,
|
|
234
|
+
definition: {
|
|
235
|
+
id: cleaned,
|
|
236
|
+
name: safeName.replace(/-/g, ' ').replace(/\b\w/g, c => c.toUpperCase()),
|
|
237
|
+
category: 'general',
|
|
238
|
+
description: `Skill capability definition for ${cleaned}`,
|
|
239
|
+
targetAgents: ['frontend', 'backend', 'orchestrator']
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Generates formatted SKILL.md markdown with standard YAML frontmatter
|
|
246
|
+
*/
|
|
247
|
+
export function generateSkillMarkdown(skillMeta) {
|
|
248
|
+
const { id, name, definition } = skillMeta;
|
|
249
|
+
|
|
250
|
+
// Check if we have pre-existing detailed markdown in templates
|
|
251
|
+
const markdownKey = `${name}.md`;
|
|
252
|
+
if (SKILL_MARKDOWNS[markdownKey]) {
|
|
253
|
+
const raw = SKILL_MARKDOWNS[markdownKey].trim();
|
|
254
|
+
if (raw.startsWith('---')) {
|
|
255
|
+
return sanitizeFrontmatter(raw + '\n');
|
|
256
|
+
}
|
|
257
|
+
return sanitizeFrontmatter(`---
|
|
258
|
+
name: ${name}
|
|
259
|
+
description: ${definition.description || 'Pixel Crew Agent Skill'}
|
|
260
|
+
category: ${definition.category || 'general'}
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
${raw}
|
|
264
|
+
`);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return sanitizeFrontmatter(`---
|
|
268
|
+
name: ${name}
|
|
269
|
+
description: ${definition.description || 'Pixel Crew Agent Skill'}
|
|
270
|
+
category: ${definition.category || 'general'}
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
# ${definition.name || name}
|
|
274
|
+
|
|
275
|
+
${definition.description || 'Custom capability skill.'}
|
|
276
|
+
|
|
277
|
+
## Targeted Agents
|
|
278
|
+
${(definition.targetAgents || ['all']).map(a => `- ${a}`).join('\n')}
|
|
279
|
+
|
|
280
|
+
## Usage & Guidelines
|
|
281
|
+
- Follow domain-specific best practices and avoid generic anti-patterns.
|
|
282
|
+
- Enforce strict typing, comprehensive testing, and modular architecture.
|
|
283
|
+
`);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Installs a skill across detected or specified agent providers (project or global scope)
|
|
288
|
+
*/
|
|
289
|
+
export async function installSkill(targetDir = process.cwd(), rawSkillInput, options = {}) {
|
|
290
|
+
const {
|
|
291
|
+
dryRun = false,
|
|
292
|
+
provider = null,
|
|
293
|
+
scope = (options.global ? 'global' : (options.scope || 'project')),
|
|
294
|
+
reporter = new DryRunReporter(targetDir)
|
|
295
|
+
} = options;
|
|
296
|
+
|
|
297
|
+
const skillMeta = normalizeSkillId(rawSkillInput);
|
|
298
|
+
const bundle = await getSkillBundle(rawSkillInput);
|
|
299
|
+
const content = (bundle && bundle.content) ? bundle.content : generateSkillMarkdown(skillMeta);
|
|
300
|
+
const activeIDE = detectActiveIDE(targetDir);
|
|
301
|
+
|
|
302
|
+
// Determine target providers
|
|
303
|
+
let targetProviders = [];
|
|
304
|
+
if (provider && provider !== 'auto') {
|
|
305
|
+
if (provider === 'all' || provider === 'multi') {
|
|
306
|
+
targetProviders = Object.keys(PROVIDER_PATHS);
|
|
307
|
+
} else if (provider === 'none' || provider === 'cli' || provider === 'pixel-crew') {
|
|
308
|
+
targetProviders = ['pixel-crew'];
|
|
309
|
+
} else {
|
|
310
|
+
const p = provider.toLowerCase();
|
|
311
|
+
if (PROVIDER_PATHS[p]) targetProviders.push(p);
|
|
312
|
+
else if (p === 'claude') targetProviders.push('claude-code');
|
|
313
|
+
else if (p === 'agents') targetProviders.push('antigravity');
|
|
314
|
+
}
|
|
315
|
+
} else {
|
|
316
|
+
if (scope === 'global') {
|
|
317
|
+
targetProviders = [activeIDE.id];
|
|
318
|
+
} else {
|
|
319
|
+
// Auto-detect environments
|
|
320
|
+
targetProviders = await detectInstalledProviders(targetDir);
|
|
321
|
+
if (activeIDE.id !== 'pixel-crew' && !targetProviders.includes(activeIDE.id)) {
|
|
322
|
+
targetProviders.push(activeIDE.id);
|
|
323
|
+
}
|
|
324
|
+
if (options.allProviders || scope === 'all') {
|
|
325
|
+
targetProviders = Object.keys(PROVIDER_PATHS);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Ensure pixel-crew is included for project-level manifests
|
|
331
|
+
if (scope !== 'global' && (!provider || provider === 'auto') && !targetProviders.includes('pixel-crew')) {
|
|
332
|
+
targetProviders.push('pixel-crew');
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const writtenPaths = [];
|
|
336
|
+
|
|
337
|
+
// 1. Write Project-Level skills if scope is 'project', 'both', or 'all'
|
|
338
|
+
if (scope !== 'global') {
|
|
339
|
+
for (const p of targetProviders) {
|
|
340
|
+
const pathFn = PROVIDER_PATHS[p];
|
|
341
|
+
if (!pathFn) continue;
|
|
342
|
+
|
|
343
|
+
const fullPath = pathFn(targetDir, skillMeta.name);
|
|
344
|
+
const res = await safeWriteFile(fullPath, content, {
|
|
345
|
+
dryRun,
|
|
346
|
+
reporter,
|
|
347
|
+
targetDir
|
|
348
|
+
});
|
|
349
|
+
writtenPaths.push({ provider: p, scope: 'project', path: fullPath, ...res });
|
|
350
|
+
|
|
351
|
+
// Write attached reference documents for directory-based providers
|
|
352
|
+
if (p !== 'pixel-crew' && bundle?.references && Object.keys(bundle.references).length > 0) {
|
|
353
|
+
const skillDir = path.dirname(fullPath);
|
|
354
|
+
for (const [refName, refContent] of Object.entries(bundle.references)) {
|
|
355
|
+
const refFullPath = path.join(skillDir, 'references', refName);
|
|
356
|
+
await safeWriteFile(refFullPath, refContent, { dryRun, reporter, targetDir });
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Keep a manifest only when the PixelCrew provider itself is selected.
|
|
362
|
+
if (targetProviders.includes('pixel-crew')) {
|
|
363
|
+
// Update .pixel-crew/pixel.json manifest
|
|
364
|
+
const manifestPath = path.join(targetDir, '.pixel-crew', 'pixel.json');
|
|
365
|
+
let manifest = {
|
|
366
|
+
name: path.basename(targetDir),
|
|
367
|
+
version: '0.2.5',
|
|
368
|
+
skills: {},
|
|
369
|
+
installedAt: new Date().toISOString()
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
try {
|
|
373
|
+
const raw = await fs.readFile(manifestPath, 'utf-8');
|
|
374
|
+
manifest = JSON.parse(raw);
|
|
375
|
+
} catch {}
|
|
376
|
+
|
|
377
|
+
if (!manifest.skills) manifest.skills = {};
|
|
378
|
+
manifest.skills[skillMeta.id] = {
|
|
379
|
+
name: skillMeta.name,
|
|
380
|
+
category: skillMeta.definition.category || 'general',
|
|
381
|
+
providers: targetProviders,
|
|
382
|
+
installedAt: new Date().toISOString()
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
await safeWriteFile(manifestPath, JSON.stringify(manifest, null, 2) + '\n', {
|
|
386
|
+
dryRun,
|
|
387
|
+
reporter,
|
|
388
|
+
targetDir
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// 2. Write Global skills if scope is 'global' or 'both'
|
|
394
|
+
if (scope === 'global' || scope === 'both') {
|
|
395
|
+
const globalProviders = provider && provider !== 'auto'
|
|
396
|
+
? (provider === 'all' ? Object.keys(GLOBAL_PROVIDER_PATHS) : [provider.toLowerCase() === 'claude' ? 'claude-code' : (provider.toLowerCase() === 'agents' ? 'antigravity' : provider.toLowerCase())])
|
|
397
|
+
: [activeIDE.id];
|
|
398
|
+
|
|
399
|
+
for (const gp of globalProviders) {
|
|
400
|
+
const globalPathFn = GLOBAL_PROVIDER_PATHS[gp];
|
|
401
|
+
if (!globalPathFn) continue;
|
|
402
|
+
|
|
403
|
+
const fullGlobalPath = globalPathFn(skillMeta.name);
|
|
404
|
+
const res = await safeWriteFile(fullGlobalPath, content, {
|
|
405
|
+
dryRun,
|
|
406
|
+
reporter,
|
|
407
|
+
targetDir: os.homedir()
|
|
408
|
+
});
|
|
409
|
+
writtenPaths.push({ provider: gp, scope: 'global', path: fullGlobalPath, ...res });
|
|
410
|
+
|
|
411
|
+
// Write attached reference documents globally
|
|
412
|
+
if (gp !== 'pixel-crew' && bundle?.references && Object.keys(bundle.references).length > 0) {
|
|
413
|
+
const skillDir = path.dirname(fullGlobalPath);
|
|
414
|
+
for (const [refName, refContent] of Object.entries(bundle.references)) {
|
|
415
|
+
const refFullPath = path.join(skillDir, 'references', refName);
|
|
416
|
+
await safeWriteFile(refFullPath, refContent, { dryRun, reporter, targetDir: os.homedir() });
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
return {
|
|
423
|
+
success: true,
|
|
424
|
+
skillId: skillMeta.id,
|
|
425
|
+
skillName: skillMeta.name,
|
|
426
|
+
providers: targetProviders,
|
|
427
|
+
scope,
|
|
428
|
+
activeIDE,
|
|
429
|
+
writtenPaths,
|
|
430
|
+
dryRun,
|
|
431
|
+
reporter
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Synchronizes all installed skills across all detected or specified IDE agent directories
|
|
437
|
+
*/
|
|
438
|
+
export async function syncSkills(targetDir = process.cwd(), options = {}) {
|
|
439
|
+
const {
|
|
440
|
+
dryRun = false,
|
|
441
|
+
provider = null,
|
|
442
|
+
scope = (options.global ? 'global' : (options.scope || 'project')),
|
|
443
|
+
reporter = new DryRunReporter(targetDir)
|
|
444
|
+
} = options;
|
|
445
|
+
|
|
446
|
+
const manifestPath = path.join(targetDir, '.pixel-crew', 'pixel.json');
|
|
447
|
+
let manifest = null;
|
|
448
|
+
|
|
449
|
+
try {
|
|
450
|
+
const raw = await fs.readFile(manifestPath, 'utf-8');
|
|
451
|
+
manifest = JSON.parse(raw);
|
|
452
|
+
} catch {}
|
|
453
|
+
|
|
454
|
+
// Discover skills from manifest or .pixel-crew/skills directory
|
|
455
|
+
const skillsToSync = new Set();
|
|
456
|
+
|
|
457
|
+
if (manifest?.skills) {
|
|
458
|
+
for (const sId of Object.keys(manifest.skills)) {
|
|
459
|
+
skillsToSync.add(sId);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// Check .pixel-crew/skills directory
|
|
464
|
+
const pixelCrewSkillsDir = path.join(targetDir, '.pixel-crew', 'skills');
|
|
465
|
+
try {
|
|
466
|
+
const files = await fs.readdir(pixelCrewSkillsDir);
|
|
467
|
+
for (const f of files) {
|
|
468
|
+
if (f.endsWith('.md')) {
|
|
469
|
+
skillsToSync.add(f.replace(/\.md$/, ''));
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
} catch {}
|
|
473
|
+
|
|
474
|
+
// Always ensure all canonical core production skills and domain aliases are synced
|
|
475
|
+
const canonicalSkills = [
|
|
476
|
+
'pixelcrew',
|
|
477
|
+
'anti-ai-patterns',
|
|
478
|
+
'design-director',
|
|
479
|
+
'frontend-engineering',
|
|
480
|
+
'backend-engineering',
|
|
481
|
+
'database-engineering',
|
|
482
|
+
'performance-engineering',
|
|
483
|
+
'codebase-intelligence',
|
|
484
|
+
'token-efficiency',
|
|
485
|
+
'design/ui-design',
|
|
486
|
+
'design/typography',
|
|
487
|
+
'frontend/nextjs',
|
|
488
|
+
'anti-ai/slop-guardian'
|
|
489
|
+
];
|
|
490
|
+
for (const s of canonicalSkills) {
|
|
491
|
+
skillsToSync.add(s);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
const results = [];
|
|
495
|
+
for (const sId of skillsToSync) {
|
|
496
|
+
const res = await installSkill(targetDir, sId, {
|
|
497
|
+
dryRun,
|
|
498
|
+
provider,
|
|
499
|
+
scope,
|
|
500
|
+
reporter
|
|
501
|
+
});
|
|
502
|
+
results.push(res);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// Generate IDE-specific workflow definitions and steering rules
|
|
506
|
+
const detected = await detectInstalledProviders(targetDir);
|
|
507
|
+
const activeIDE = detectActiveIDE(targetDir);
|
|
508
|
+
|
|
509
|
+
const shouldGenerate = (ideId) => {
|
|
510
|
+
if (provider && provider !== 'auto') {
|
|
511
|
+
return provider === 'all' || provider === 'multi' || provider.toLowerCase() === ideId || (provider.toLowerCase() === 'claude' && ideId === 'claude-code') || (provider.toLowerCase() === 'agents' && ideId === 'antigravity');
|
|
512
|
+
}
|
|
513
|
+
return activeIDE.id === ideId || (detected.includes(ideId) && ideId !== 'pixel-crew');
|
|
514
|
+
};
|
|
515
|
+
|
|
516
|
+
// 1. Kiro Workflows & Rules
|
|
517
|
+
if (shouldGenerate('kiro')) {
|
|
518
|
+
if (scope !== 'global') {
|
|
519
|
+
const kiroFiles = generateKiroFiles(targetDir, false);
|
|
520
|
+
for (const kf of kiroFiles) {
|
|
521
|
+
await safeWriteFile(kf.path, kf.content, { dryRun, reporter, targetDir });
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
if (scope === 'global' || scope === 'both') {
|
|
525
|
+
const kiroGlobalFiles = generateKiroFiles(os.homedir(), true);
|
|
526
|
+
for (const kf of kiroGlobalFiles) {
|
|
527
|
+
await safeWriteFile(kf.path, kf.content, { dryRun, reporter, targetDir: os.homedir() });
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// 2. Cursor Rules & MDC
|
|
533
|
+
if (shouldGenerate('cursor')) {
|
|
534
|
+
if (scope !== 'global') {
|
|
535
|
+
const cursorFiles = generateCursorFiles(targetDir);
|
|
536
|
+
for (const cf of cursorFiles) {
|
|
537
|
+
await safeWriteFile(cf.path, cf.content, { dryRun, reporter, targetDir });
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
// 3. Antigravity Agent Instructions (AGENTS.md, GEMINI.md, .agents/rules/)
|
|
543
|
+
if (shouldGenerate('antigravity')) {
|
|
544
|
+
if (scope !== 'global') {
|
|
545
|
+
const antigravityFiles = generateAntigravityFiles(targetDir);
|
|
546
|
+
for (const af of antigravityFiles) {
|
|
547
|
+
await safeWriteFile(af.path, af.content, { dryRun, reporter, targetDir });
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// 4. Claude Code Instructions (CLAUDE.md, .claude-plugin/)
|
|
553
|
+
if (shouldGenerate('claude-code')) {
|
|
554
|
+
if (scope !== 'global') {
|
|
555
|
+
const claudeFiles = generateClaudeFiles(targetDir);
|
|
556
|
+
for (const clf of claudeFiles) {
|
|
557
|
+
await safeWriteFile(clf.path, clf.content, { dryRun, reporter, targetDir });
|
|
558
|
+
}
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
return {
|
|
563
|
+
success: true,
|
|
564
|
+
skillsSynced: Array.from(skillsToSync),
|
|
565
|
+
scope,
|
|
566
|
+
results,
|
|
567
|
+
dryRun,
|
|
568
|
+
reporter
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PIXEL CREW — Kiro Workflows & Prompts Generator
|
|
3
|
+
*
|
|
4
|
+
* Generates individual .kiro/workflows/*.md, .kiro/prompts/*.md, and .kirorules
|
|
5
|
+
* files so that every PixelCrew slash command (/recap, /assemble, /blueprint, /render, etc.)
|
|
6
|
+
* is natively recognized in the Kiro chat box autocomplete and prompt menu.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import path from 'node:path';
|
|
10
|
+
import { FLOOR42_COMMANDS } from './commands-catalog.js';
|
|
11
|
+
|
|
12
|
+
export const KIRO_COMMANDS = FLOOR42_COMMANDS;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Generates all Kiro workflow, prompt, and rule files
|
|
16
|
+
*/
|
|
17
|
+
export function generateKiroFiles(targetDir, isGlobal = false) {
|
|
18
|
+
const baseDir = isGlobal ? targetDir : path.join(targetDir, '.kiro');
|
|
19
|
+
const files = [];
|
|
20
|
+
|
|
21
|
+
// 1. Workflows (.kiro/workflows/*.md)
|
|
22
|
+
for (const cmd of KIRO_COMMANDS) {
|
|
23
|
+
const workflowPath = path.join(baseDir, 'workflows', `${cmd.name}.md`);
|
|
24
|
+
const workflowContent = `---
|
|
25
|
+
name: ${cmd.name}
|
|
26
|
+
description: ${cmd.description}
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
# /${cmd.name} — PixelCrew Command
|
|
30
|
+
|
|
31
|
+
${cmd.prompt}
|
|
32
|
+
`;
|
|
33
|
+
files.push({ path: workflowPath, content: workflowContent });
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// 2. Prompts (.kiro/prompts/*.md)
|
|
37
|
+
for (const cmd of KIRO_COMMANDS) {
|
|
38
|
+
const promptPath = path.join(baseDir, 'prompts', `${cmd.name}.md`);
|
|
39
|
+
const promptContent = `---
|
|
40
|
+
name: ${cmd.name}
|
|
41
|
+
description: ${cmd.description}
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
${cmd.prompt}
|
|
45
|
+
`;
|
|
46
|
+
files.push({ path: promptPath, content: promptContent });
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// 3. Rules (.kirorules and .kiro/rules/pixelcrew.md)
|
|
50
|
+
const rulesContent = `# 🏢 PixelCrew Swarm Rules for Kiro
|
|
51
|
+
|
|
52
|
+
You are integrated with PixelCrew, an autonomous multi-agent engineering swarm (Floor 42, Pixel Corps HQ).
|
|
53
|
+
|
|
54
|
+
## ⚡ Slash Commands in Kiro Chat:
|
|
55
|
+
${KIRO_COMMANDS.map(c => `- **\`/${c.name}\`**: ${c.description}`).join('\n')}
|
|
56
|
+
|
|
57
|
+
## 🛡️ Anti-AI Slop Directive:
|
|
58
|
+
- Enforce intentional asymmetry, mathematical fluid \`clamp()\` typography, and high-contrast surface tiers.
|
|
59
|
+
- Reject generic AI purple/cyan glowing blobs on flat black.
|
|
60
|
+
- Reject cliché copy (*"Elevate your workflow"*, *"Seamlessly innovate"*) and uniform 3-card grids.
|
|
61
|
+
`;
|
|
62
|
+
|
|
63
|
+
if (!isGlobal) {
|
|
64
|
+
files.push({ path: path.join(targetDir, '.kirorules'), content: rulesContent });
|
|
65
|
+
files.push({ path: path.join(baseDir, 'rules', 'pixelcrew.md'), content: rulesContent });
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// 4. Skills (.kiro/skills/<cmd>/SKILL.md) for direct slash command invocation in Kiro AI chat
|
|
69
|
+
for (const cmd of KIRO_COMMANDS) {
|
|
70
|
+
if (cmd.name === 'pixelcrew') continue;
|
|
71
|
+
const skillPath = path.join(baseDir, 'skills', cmd.name, 'SKILL.md');
|
|
72
|
+
const skillContent = `---
|
|
73
|
+
name: ${cmd.name}
|
|
74
|
+
description: >-
|
|
75
|
+
${cmd.description}. Triggers Floor 42 command /${cmd.name}.
|
|
76
|
+
---
|
|
77
|
+
|
|
78
|
+
# /${cmd.name} — PixelCrew Command
|
|
79
|
+
|
|
80
|
+
${cmd.prompt}
|
|
81
|
+
`;
|
|
82
|
+
files.push({ path: skillPath, content: skillContent });
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return files;
|
|
86
|
+
}
|