@aslomon/effectum 0.2.1 → 0.3.0
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 +23 -16
- package/bin/install.js +182 -108
- package/bin/lib/app-types.js +96 -0
- package/bin/lib/config.js +22 -3
- package/bin/lib/constants.js +14 -30
- package/bin/lib/foundation.js +63 -0
- package/bin/lib/languages.js +77 -0
- package/bin/lib/recommendation.js +392 -0
- package/bin/lib/specializations.js +123 -0
- package/bin/lib/template.js +2 -1
- package/bin/lib/ui.js +350 -21
- package/bin/reconfigure.js +29 -3
- package/package.json +1 -1
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Intelligent Setup Recommender — rules-based recommendation engine v1.
|
|
3
|
+
*
|
|
4
|
+
* Derives a complete Claude Code setup from:
|
|
5
|
+
* stack + appType + description + autonomyLevel + language
|
|
6
|
+
*
|
|
7
|
+
* Returns: commands, hooks, skills, mcps, subagents, agentTeams flag.
|
|
8
|
+
*/
|
|
9
|
+
"use strict";
|
|
10
|
+
|
|
11
|
+
const { APP_TYPE_TAGS } = require("./app-types");
|
|
12
|
+
const { SUBAGENT_SPECS, STACK_SUBAGENTS } = require("./specializations");
|
|
13
|
+
const { MCP_SERVERS } = require("./constants");
|
|
14
|
+
|
|
15
|
+
// ─── Keyword → Tag mapping ─────────────────────────────────────────────────
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Description keywords mapped to intent tags.
|
|
19
|
+
* @type {Record<string, string[]>}
|
|
20
|
+
*/
|
|
21
|
+
const KEYWORD_TAG_MAP = {
|
|
22
|
+
dashboard: ["dashboard", "frontend-heavy", "data-visualization"],
|
|
23
|
+
crm: ["crm", "internal-tool", "auth-needed", "db-needed", "multi-user"],
|
|
24
|
+
admin: ["internal-tool", "auth-needed", "db-needed", "multi-user"],
|
|
25
|
+
auth: ["auth-needed"],
|
|
26
|
+
login: ["auth-needed"],
|
|
27
|
+
signup: ["auth-needed"],
|
|
28
|
+
register: ["auth-needed"],
|
|
29
|
+
api: ["api-first"],
|
|
30
|
+
rest: ["api-first"],
|
|
31
|
+
graphql: ["api-first", "graphql"],
|
|
32
|
+
database: ["db-needed"],
|
|
33
|
+
postgres: ["db-needed", "postgres"],
|
|
34
|
+
supabase: ["supabase", "db-needed"],
|
|
35
|
+
"e-commerce": ["e-commerce", "payments", "auth-needed", "db-needed"],
|
|
36
|
+
ecommerce: ["e-commerce", "payments", "auth-needed", "db-needed"],
|
|
37
|
+
shop: ["e-commerce", "payments", "auth-needed", "db-needed"],
|
|
38
|
+
payment: ["payments", "auth-needed"],
|
|
39
|
+
stripe: ["payments", "auth-needed"],
|
|
40
|
+
chat: ["realtime", "websocket", "multi-user"],
|
|
41
|
+
realtime: ["realtime", "websocket"],
|
|
42
|
+
websocket: ["realtime", "websocket"],
|
|
43
|
+
ai: ["ai-agent"],
|
|
44
|
+
agent: ["ai-agent"],
|
|
45
|
+
llm: ["ai-agent"],
|
|
46
|
+
openai: ["ai-agent"],
|
|
47
|
+
claude: ["ai-agent"],
|
|
48
|
+
bot: ["ai-agent", "automation"],
|
|
49
|
+
automation: ["automation", "background-jobs"],
|
|
50
|
+
workflow: ["automation", "background-jobs"],
|
|
51
|
+
cron: ["automation", "background-jobs"],
|
|
52
|
+
blog: ["content", "seo", "frontend-heavy"],
|
|
53
|
+
cms: ["content", "auth-needed", "db-needed"],
|
|
54
|
+
portfolio: ["content", "seo", "frontend-heavy"],
|
|
55
|
+
landing: ["content", "seo", "frontend-heavy"],
|
|
56
|
+
saas: ["multi-user", "auth-needed", "db-needed", "payments", "multi-tenant"],
|
|
57
|
+
"multi-tenant": ["multi-tenant", "multi-user", "auth-needed"],
|
|
58
|
+
tenant: ["multi-tenant", "multi-user"],
|
|
59
|
+
analytics: ["analytics", "data-visualization", "db-needed"],
|
|
60
|
+
monitoring: ["analytics", "data-visualization", "realtime"],
|
|
61
|
+
docker: ["devops", "automation"],
|
|
62
|
+
kubernetes: ["devops", "automation"],
|
|
63
|
+
ci: ["devops", "automation"],
|
|
64
|
+
deploy: ["devops"],
|
|
65
|
+
test: ["testing-heavy"],
|
|
66
|
+
testing: ["testing-heavy"],
|
|
67
|
+
e2e: ["testing-heavy", "e2e"],
|
|
68
|
+
mobile: ["native-ui", "frontend-heavy"],
|
|
69
|
+
ios: ["native-ui", "swift"],
|
|
70
|
+
android: ["native-ui"],
|
|
71
|
+
react: ["react", "frontend-heavy"],
|
|
72
|
+
next: ["nextjs", "frontend-heavy"],
|
|
73
|
+
nextjs: ["nextjs", "frontend-heavy"],
|
|
74
|
+
python: ["python"],
|
|
75
|
+
fastapi: ["python", "api-first"],
|
|
76
|
+
django: ["python", "frontend-heavy", "db-needed"],
|
|
77
|
+
swift: ["swift", "native-ui"],
|
|
78
|
+
electron: ["desktop", "frontend-heavy"],
|
|
79
|
+
tauri: ["desktop", "frontend-heavy"],
|
|
80
|
+
cli: ["terminal-ui", "scripting"],
|
|
81
|
+
scraper: ["automation", "data-pipeline"],
|
|
82
|
+
crawler: ["automation", "data-pipeline"],
|
|
83
|
+
pipeline: ["data-pipeline", "automation"],
|
|
84
|
+
etl: ["data-pipeline", "automation"],
|
|
85
|
+
ml: ["data-pipeline", "compute-heavy"],
|
|
86
|
+
"machine learning": ["data-pipeline", "compute-heavy"],
|
|
87
|
+
model: ["data-pipeline", "compute-heavy"],
|
|
88
|
+
library: ["api-design", "testing-heavy", "docs-needed"],
|
|
89
|
+
sdk: ["api-design", "testing-heavy", "docs-needed"],
|
|
90
|
+
plugin: ["api-design", "testing-heavy"],
|
|
91
|
+
mcp: ["mcp", "ai-agent"],
|
|
92
|
+
security: ["auth-needed", "security"],
|
|
93
|
+
upload: ["storage", "file-handling"],
|
|
94
|
+
image: ["storage", "file-handling"],
|
|
95
|
+
file: ["storage", "file-handling"],
|
|
96
|
+
notification: ["realtime", "multi-user"],
|
|
97
|
+
email: ["automation", "multi-user"],
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
// ─── Stack → Tag mapping ────────────────────────────────────────────────────
|
|
101
|
+
|
|
102
|
+
/** @type {Record<string, string[]>} */
|
|
103
|
+
const STACK_TAGS = {
|
|
104
|
+
"nextjs-supabase": [
|
|
105
|
+
"nextjs",
|
|
106
|
+
"react",
|
|
107
|
+
"supabase",
|
|
108
|
+
"typescript",
|
|
109
|
+
"frontend-heavy",
|
|
110
|
+
"db-needed",
|
|
111
|
+
"postgres",
|
|
112
|
+
],
|
|
113
|
+
"python-fastapi": ["python", "api-first", "backend-heavy"],
|
|
114
|
+
"swift-ios": ["swift", "native-ui", "frontend-heavy"],
|
|
115
|
+
generic: [],
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// ─── Tag extraction ─────────────────────────────────────────────────────────
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Extract intent tags from all inputs.
|
|
122
|
+
* @param {{ appType: string, stack: string, description: string }} input
|
|
123
|
+
* @returns {string[]}
|
|
124
|
+
*/
|
|
125
|
+
function extractTags({ appType, stack, description }) {
|
|
126
|
+
const tags = new Set();
|
|
127
|
+
|
|
128
|
+
// App-type tags
|
|
129
|
+
const appTags = APP_TYPE_TAGS[appType] || [];
|
|
130
|
+
appTags.forEach((t) => tags.add(t));
|
|
131
|
+
|
|
132
|
+
// Stack tags
|
|
133
|
+
const stackTags = STACK_TAGS[stack] || [];
|
|
134
|
+
stackTags.forEach((t) => tags.add(t));
|
|
135
|
+
|
|
136
|
+
// Description keyword matching
|
|
137
|
+
const lower = (description || "").toLowerCase();
|
|
138
|
+
for (const [keyword, keyTags] of Object.entries(KEYWORD_TAG_MAP)) {
|
|
139
|
+
if (lower.includes(keyword)) {
|
|
140
|
+
keyTags.forEach((t) => tags.add(t));
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return [...tags];
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// ─── Recommendation rules ───────────────────────────────────────────────────
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* All available optional commands with the tags that trigger them.
|
|
151
|
+
* @type {Array<{ key: string, label: string, tags: string[], always?: boolean }>}
|
|
152
|
+
*/
|
|
153
|
+
const COMMAND_RULES = [
|
|
154
|
+
{ key: "plan", label: "/plan", tags: [], always: true },
|
|
155
|
+
{ key: "tdd", label: "/tdd", tags: [], always: true },
|
|
156
|
+
{ key: "verify", label: "/verify", tags: [], always: true },
|
|
157
|
+
{ key: "code-review", label: "/code-review", tags: [], always: true },
|
|
158
|
+
{ key: "build-fix", label: "/build-fix", tags: [], always: true },
|
|
159
|
+
{ key: "refactor-clean", label: "/refactor-clean", tags: [], always: true },
|
|
160
|
+
{ key: "e2e", label: "/e2e", tags: [], always: true },
|
|
161
|
+
{ key: "ralph-loop", label: "/ralph-loop", tags: [], always: true },
|
|
162
|
+
{ key: "checkpoint", label: "/checkpoint", tags: [], always: true },
|
|
163
|
+
{ key: "update-docs", label: "/update-docs", tags: ["docs-needed"] },
|
|
164
|
+
{ key: "test-coverage", label: "/test-coverage", tags: ["testing-heavy"] },
|
|
165
|
+
{
|
|
166
|
+
key: "simplify",
|
|
167
|
+
label: "/simplify",
|
|
168
|
+
tags: ["backend-heavy", "frontend-heavy"],
|
|
169
|
+
},
|
|
170
|
+
];
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Optional hooks (beyond foundation) with trigger tags.
|
|
174
|
+
* @type {Array<{ key: string, label: string, tags: string[], always?: boolean }>}
|
|
175
|
+
*/
|
|
176
|
+
const HOOK_RULES = [
|
|
177
|
+
{ key: "commit-gate", label: "Commit Message Gate", tags: [], always: true },
|
|
178
|
+
{
|
|
179
|
+
key: "changelog-update",
|
|
180
|
+
label: "CHANGELOG Auto-Update",
|
|
181
|
+
tags: [],
|
|
182
|
+
always: true,
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
key: "completion-verifier",
|
|
186
|
+
label: "Completion Verifier",
|
|
187
|
+
tags: [],
|
|
188
|
+
always: true,
|
|
189
|
+
},
|
|
190
|
+
{
|
|
191
|
+
key: "subagent-verifier",
|
|
192
|
+
label: "Subagent Quality Gate",
|
|
193
|
+
tags: [],
|
|
194
|
+
always: true,
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
key: "desktop-notifications",
|
|
198
|
+
label: "Desktop Notifications",
|
|
199
|
+
tags: [],
|
|
200
|
+
always: true,
|
|
201
|
+
},
|
|
202
|
+
];
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Skills with trigger tags and mandatory-per-stack rules.
|
|
206
|
+
* @type {Array<{ key: string, label: string, tags: string[], mandatoryForStacks?: string[] }>}
|
|
207
|
+
*/
|
|
208
|
+
const SKILL_RULES = [
|
|
209
|
+
{
|
|
210
|
+
key: "frontend-design",
|
|
211
|
+
label: "Frontend Design",
|
|
212
|
+
tags: ["frontend-heavy", "ui-design"],
|
|
213
|
+
mandatoryForStacks: ["nextjs-supabase"],
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
key: "security-check",
|
|
217
|
+
label: "Security Check",
|
|
218
|
+
tags: ["auth-needed", "multi-user", "payments", "security"],
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
key: "webapp-testing",
|
|
222
|
+
label: "Web App Testing",
|
|
223
|
+
tags: ["frontend-heavy", "e2e"],
|
|
224
|
+
mandatoryForStacks: ["nextjs-supabase"],
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
key: "doc-coauthoring",
|
|
228
|
+
label: "Doc Co-Authoring",
|
|
229
|
+
tags: ["docs-needed"],
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
key: "claude-api",
|
|
233
|
+
label: "Claude API",
|
|
234
|
+
tags: ["ai-agent"],
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
key: "mcp-builder",
|
|
238
|
+
label: "MCP Builder",
|
|
239
|
+
tags: ["mcp", "ai-agent"],
|
|
240
|
+
},
|
|
241
|
+
];
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* MCP server trigger rules.
|
|
245
|
+
* @type {Array<{ key: string, tags: string[], always?: boolean }>}
|
|
246
|
+
*/
|
|
247
|
+
const MCP_RULES = [
|
|
248
|
+
{ key: "context7", tags: [], always: true },
|
|
249
|
+
{ key: "playwright", tags: [], always: true },
|
|
250
|
+
{ key: "sequential-thinking", tags: [], always: true },
|
|
251
|
+
{ key: "filesystem", tags: ["file-handling", "storage"] },
|
|
252
|
+
];
|
|
253
|
+
|
|
254
|
+
// ─── Core recommendation functions ──────────────────────────────────────────
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Recommend commands based on tags.
|
|
258
|
+
* @param {string[]} tags
|
|
259
|
+
* @returns {string[]}
|
|
260
|
+
*/
|
|
261
|
+
function recommendCommands(tags) {
|
|
262
|
+
const tagSet = new Set(tags);
|
|
263
|
+
return COMMAND_RULES.filter(
|
|
264
|
+
(r) => r.always || r.tags.some((t) => tagSet.has(t)),
|
|
265
|
+
).map((r) => r.key);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Recommend optional hooks based on tags.
|
|
270
|
+
* @param {string[]} tags
|
|
271
|
+
* @returns {string[]}
|
|
272
|
+
*/
|
|
273
|
+
function recommendHooks(tags) {
|
|
274
|
+
const tagSet = new Set(tags);
|
|
275
|
+
return HOOK_RULES.filter(
|
|
276
|
+
(r) => r.always || r.tags.some((t) => tagSet.has(t)),
|
|
277
|
+
).map((r) => r.key);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Recommend skills based on tags and stack.
|
|
282
|
+
* @param {string[]} tags
|
|
283
|
+
* @param {string} stack
|
|
284
|
+
* @returns {string[]}
|
|
285
|
+
*/
|
|
286
|
+
function recommendSkills(tags, stack) {
|
|
287
|
+
const tagSet = new Set(tags);
|
|
288
|
+
return SKILL_RULES.filter(
|
|
289
|
+
(r) =>
|
|
290
|
+
r.tags.some((t) => tagSet.has(t)) ||
|
|
291
|
+
(r.mandatoryForStacks && r.mandatoryForStacks.includes(stack)),
|
|
292
|
+
).map((r) => r.key);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Recommend MCP servers based on tags.
|
|
297
|
+
* @param {string[]} tags
|
|
298
|
+
* @returns {string[]}
|
|
299
|
+
*/
|
|
300
|
+
function recommendMcps(tags) {
|
|
301
|
+
const tagSet = new Set(tags);
|
|
302
|
+
return MCP_RULES.filter((r) => r.always || r.tags.some((t) => tagSet.has(t)))
|
|
303
|
+
.map((r) => r.key)
|
|
304
|
+
.filter((key) => MCP_SERVERS.some((s) => s.key === key));
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Recommend subagent specializations based on tags and stack.
|
|
309
|
+
* @param {string[]} tags
|
|
310
|
+
* @param {string} stack
|
|
311
|
+
* @returns {string[]}
|
|
312
|
+
*/
|
|
313
|
+
function recommendSubagents(tags, stack) {
|
|
314
|
+
const tagSet = new Set(tags);
|
|
315
|
+
const result = new Set();
|
|
316
|
+
|
|
317
|
+
// Stack base recommendations
|
|
318
|
+
const stackBase = STACK_SUBAGENTS[stack] || STACK_SUBAGENTS.generic;
|
|
319
|
+
stackBase.forEach((s) => result.add(s));
|
|
320
|
+
|
|
321
|
+
// Tag-based additions
|
|
322
|
+
for (const spec of SUBAGENT_SPECS) {
|
|
323
|
+
if (spec.tags.some((t) => tagSet.has(t))) {
|
|
324
|
+
result.add(spec.key);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return [...result];
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// ─── Main recommendation entry point ────────────────────────────────────────
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Generate a complete recommended setup from user inputs.
|
|
335
|
+
*
|
|
336
|
+
* @param {{ stack: string, appType: string, description: string, autonomyLevel: string, language: string }} input
|
|
337
|
+
* @returns {{ commands: string[], hooks: string[], skills: string[], mcps: string[], subagents: string[], agentTeams: boolean, tags: string[] }}
|
|
338
|
+
*/
|
|
339
|
+
function recommend({ stack, appType, description, autonomyLevel, language }) {
|
|
340
|
+
const tags = extractTags({ appType, stack, description });
|
|
341
|
+
|
|
342
|
+
return {
|
|
343
|
+
commands: recommendCommands(tags),
|
|
344
|
+
hooks: recommendHooks(tags),
|
|
345
|
+
skills: recommendSkills(tags, stack),
|
|
346
|
+
mcps: recommendMcps(tags),
|
|
347
|
+
subagents: recommendSubagents(tags, stack),
|
|
348
|
+
agentTeams: false,
|
|
349
|
+
tags,
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
// ─── Catalog accessors (for manual/customize mode) ──────────────────────────
|
|
354
|
+
|
|
355
|
+
/** Get all available commands for manual selection. */
|
|
356
|
+
function getAllCommands() {
|
|
357
|
+
return COMMAND_RULES.map((r) => ({ key: r.key, label: r.label }));
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/** Get all available optional hooks for manual selection. */
|
|
361
|
+
function getAllHooks() {
|
|
362
|
+
return HOOK_RULES.map((r) => ({ key: r.key, label: r.label }));
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/** Get all available skills for manual selection. */
|
|
366
|
+
function getAllSkills() {
|
|
367
|
+
return SKILL_RULES.map((r) => ({ key: r.key, label: r.label }));
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/** Get all available MCP servers for manual selection. */
|
|
371
|
+
function getAllMcps() {
|
|
372
|
+
return MCP_SERVERS.map((s) => ({ key: s.key, label: s.label, desc: s.desc }));
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/** Get all available subagent specializations for manual selection. */
|
|
376
|
+
function getAllSubagents() {
|
|
377
|
+
return SUBAGENT_SPECS.map((s) => ({ key: s.key, label: s.label }));
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
module.exports = {
|
|
381
|
+
recommend,
|
|
382
|
+
extractTags,
|
|
383
|
+
getAllCommands,
|
|
384
|
+
getAllHooks,
|
|
385
|
+
getAllSkills,
|
|
386
|
+
getAllMcps,
|
|
387
|
+
getAllSubagents,
|
|
388
|
+
COMMAND_RULES,
|
|
389
|
+
HOOK_RULES,
|
|
390
|
+
SKILL_RULES,
|
|
391
|
+
MCP_RULES,
|
|
392
|
+
};
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subagent specialization definitions and stack/app-type mappings.
|
|
3
|
+
* Drives the recommendation engine's subagent suggestions.
|
|
4
|
+
*/
|
|
5
|
+
"use strict";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* All available subagent specializations with the tags they match.
|
|
9
|
+
* @type {Array<{ key: string, label: string, tags: string[] }>}
|
|
10
|
+
*/
|
|
11
|
+
const SUBAGENT_SPECS = [
|
|
12
|
+
{
|
|
13
|
+
key: "frontend-developer",
|
|
14
|
+
label: "Frontend Developer",
|
|
15
|
+
tags: ["frontend-heavy", "ui-design"],
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
key: "backend-developer",
|
|
19
|
+
label: "Backend Developer",
|
|
20
|
+
tags: ["backend-heavy", "api-first", "db-needed"],
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
key: "fullstack-developer",
|
|
24
|
+
label: "Fullstack Developer",
|
|
25
|
+
tags: ["frontend-heavy", "db-needed"],
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
key: "react-specialist",
|
|
29
|
+
label: "React Specialist",
|
|
30
|
+
tags: ["nextjs", "react"],
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
key: "nextjs-developer",
|
|
34
|
+
label: "Next.js Developer",
|
|
35
|
+
tags: ["nextjs"],
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
key: "postgres-pro",
|
|
39
|
+
label: "PostgreSQL Pro",
|
|
40
|
+
tags: ["db-needed", "supabase", "postgres"],
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
key: "security-engineer",
|
|
44
|
+
label: "Security Engineer",
|
|
45
|
+
tags: ["auth-needed", "multi-user", "payments"],
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
key: "test-automator",
|
|
49
|
+
label: "Test Automator",
|
|
50
|
+
tags: ["testing-heavy"],
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
key: "api-designer",
|
|
54
|
+
label: "API Designer",
|
|
55
|
+
tags: ["api-first", "api-design"],
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
key: "ui-designer",
|
|
59
|
+
label: "UI Designer",
|
|
60
|
+
tags: ["native-ui", "ui-design"],
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
key: "debugger",
|
|
64
|
+
label: "Debugger",
|
|
65
|
+
tags: ["data-pipeline", "compute-heavy"],
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
key: "performance-engineer",
|
|
69
|
+
label: "Performance Engineer",
|
|
70
|
+
tags: ["compute-heavy", "data-pipeline"],
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
key: "devops-engineer",
|
|
74
|
+
label: "DevOps Engineer",
|
|
75
|
+
tags: ["automation", "background-jobs", "devops"],
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
key: "docker-expert",
|
|
79
|
+
label: "Docker Expert",
|
|
80
|
+
tags: ["automation", "devops"],
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
key: "typescript-pro",
|
|
84
|
+
label: "TypeScript Pro",
|
|
85
|
+
tags: ["nextjs", "typescript"],
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
key: "mcp-developer",
|
|
89
|
+
label: "MCP Developer",
|
|
90
|
+
tags: ["ai-agent", "mcp"],
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
key: "code-reviewer",
|
|
94
|
+
label: "Code Reviewer",
|
|
95
|
+
tags: ["testing-heavy", "docs-needed"],
|
|
96
|
+
},
|
|
97
|
+
];
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Stack-specific base subagent recommendations.
|
|
101
|
+
* These are always included for the given stack, regardless of tags.
|
|
102
|
+
* @type {Record<string, string[]>}
|
|
103
|
+
*/
|
|
104
|
+
const STACK_SUBAGENTS = {
|
|
105
|
+
"nextjs-supabase": [
|
|
106
|
+
"frontend-developer",
|
|
107
|
+
"backend-developer",
|
|
108
|
+
"postgres-pro",
|
|
109
|
+
"security-engineer",
|
|
110
|
+
"test-automator",
|
|
111
|
+
],
|
|
112
|
+
"python-fastapi": [
|
|
113
|
+
"backend-developer",
|
|
114
|
+
"debugger",
|
|
115
|
+
"security-engineer",
|
|
116
|
+
"test-automator",
|
|
117
|
+
"api-designer",
|
|
118
|
+
],
|
|
119
|
+
"swift-ios": ["ui-designer", "test-automator"],
|
|
120
|
+
generic: ["debugger", "test-automator"],
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
module.exports = { SUBAGENT_SPECS, STACK_SUBAGENTS };
|
package/bin/lib/template.js
CHANGED
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
|
|
8
8
|
const fs = require("fs");
|
|
9
9
|
const path = require("path");
|
|
10
|
-
const { FORMATTER_MAP
|
|
10
|
+
const { FORMATTER_MAP } = require("./constants");
|
|
11
|
+
const { LANGUAGE_INSTRUCTIONS } = require("./languages");
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Build a substitution map from user config and parsed stack sections.
|