ccsetup 1.1.1 → 1.2.1

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.
Files changed (86) hide show
  1. package/README.md +144 -342
  2. package/bin/create-project.js +1246 -90
  3. package/bin/lib/claudeInterface.js +209 -0
  4. package/lib/aiAgentSelector.js +155 -0
  5. package/lib/templates/README.md +176 -0
  6. package/lib/templates/catalog.js +230 -0
  7. package/lib/templates/filter.js +257 -0
  8. package/lib/templates/index.js +45 -0
  9. package/lib/templates/metadata/agents.json +413 -0
  10. package/lib/templates/metadata-extractor.js +329 -0
  11. package/lib/templates/search.js +356 -0
  12. package/package.json +13 -5
  13. package/template/{agents → .claude/agents}/checker.md +29 -0
  14. package/template/.claude/settings.json +32 -0
  15. package/template/.claude/skills/codex-review/SKILL.md +139 -0
  16. package/template/.claude/skills/prd/SKILL.md +343 -0
  17. package/template/.claude/skills/ralph/SKILL.md +339 -0
  18. package/template/.claude/skills/secops/SKILL.md +259 -0
  19. package/template/.codex/skills/codex-review/SKILL.md +139 -0
  20. package/template/.codex/skills/prd/SKILL.md +343 -0
  21. package/template/.codex/skills/ralph/SKILL.md +339 -0
  22. package/template/AGENTS.md +43 -0
  23. package/template/CLAUDE.md +141 -21
  24. package/template/CONTRIBUTING.md +37 -0
  25. package/template/agents/README.md +15 -171
  26. package/template/docs/ROADMAP.md +0 -36
  27. package/template/docs/agent-orchestration.md +24 -141
  28. package/template/docs/codex-setup.md +32 -0
  29. package/template/hooks/codex-review/index.js +105 -0
  30. package/template/hooks/workflow-selector/index.js +398 -0
  31. package/template/scripts/codex-review/codex-review.sh +266 -0
  32. package/template/scripts/ralph/CLAUDE.md +174 -0
  33. package/template/scripts/ralph/CODEX.md +76 -0
  34. package/template/scripts/ralph/ralph.sh +150 -0
  35. package/template/tickets/ticket-list.md +17 -68
  36. package/template/agents/ai-engineer.md +0 -31
  37. package/template/agents/api-documenter.md +0 -31
  38. package/template/agents/architect-review.md +0 -42
  39. package/template/agents/backend-architect.md +0 -29
  40. package/template/agents/business-analyst.md +0 -34
  41. package/template/agents/c-pro.md +0 -34
  42. package/template/agents/cloud-architect.md +0 -31
  43. package/template/agents/code-reviewer.md +0 -28
  44. package/template/agents/content-marketer.md +0 -34
  45. package/template/agents/context-manager.md +0 -63
  46. package/template/agents/cpp-pro.md +0 -37
  47. package/template/agents/customer-support.md +0 -34
  48. package/template/agents/data-engineer.md +0 -31
  49. package/template/agents/data-scientist.md +0 -28
  50. package/template/agents/database-admin.md +0 -31
  51. package/template/agents/database-optimizer.md +0 -31
  52. package/template/agents/debugger.md +0 -29
  53. package/template/agents/deployment-engineer.md +0 -31
  54. package/template/agents/devops-troubleshooter.md +0 -31
  55. package/template/agents/dx-optimizer.md +0 -62
  56. package/template/agents/error-detective.md +0 -31
  57. package/template/agents/frontend-developer.md +0 -30
  58. package/template/agents/golang-pro.md +0 -31
  59. package/template/agents/graphql-architect.md +0 -31
  60. package/template/agents/incident-responder.md +0 -73
  61. package/template/agents/javascript-pro.md +0 -34
  62. package/template/agents/legacy-modernizer.md +0 -31
  63. package/template/agents/ml-engineer.md +0 -31
  64. package/template/agents/mlops-engineer.md +0 -56
  65. package/template/agents/mobile-developer.md +0 -31
  66. package/template/agents/network-engineer.md +0 -31
  67. package/template/agents/payment-integration.md +0 -31
  68. package/template/agents/performance-engineer.md +0 -31
  69. package/template/agents/prompt-engineer.md +0 -58
  70. package/template/agents/python-pro.md +0 -31
  71. package/template/agents/quant-analyst.md +0 -31
  72. package/template/agents/risk-manager.md +0 -40
  73. package/template/agents/rust-pro.md +0 -34
  74. package/template/agents/sales-automator.md +0 -34
  75. package/template/agents/search-specialist.md +0 -58
  76. package/template/agents/security-auditor.md +0 -31
  77. package/template/agents/sql-pro.md +0 -34
  78. package/template/agents/terraform-specialist.md +0 -34
  79. package/template/agents/test-automator.md +0 -31
  80. /package/template/{agents → .claude/agents}/backend.md +0 -0
  81. /package/template/{agents → .claude/agents}/blockchain.md +0 -0
  82. /package/template/{agents → .claude/agents}/coder.md +0 -0
  83. /package/template/{agents → .claude/agents}/frontend.md +0 -0
  84. /package/template/{agents → .claude/agents}/planner.md +0 -0
  85. /package/template/{agents → .claude/agents}/researcher.md +0 -0
  86. /package/template/{agents → .claude/agents}/shadcn.md +0 -0
@@ -0,0 +1,230 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+ const MetadataExtractor = require('./metadata-extractor');
4
+
5
+ class TemplateCatalog {
6
+ constructor() {
7
+ this.cache = null;
8
+ this.cacheTimestamp = null;
9
+ this.cacheValidityMs = 5 * 60 * 1000; // 5 minutes
10
+ }
11
+
12
+ async load(forceRefresh = false) {
13
+ if (!forceRefresh && this.isCacheValid()) {
14
+ return this.cache;
15
+ }
16
+
17
+ try {
18
+ const metadataPath = path.join(__dirname, 'metadata/agents.json');
19
+
20
+ if (fs.existsSync(metadataPath) && !forceRefresh) {
21
+ const content = fs.readFileSync(metadataPath, 'utf8');
22
+ this.cache = JSON.parse(content);
23
+ this.cacheTimestamp = Date.now();
24
+ return this.cache;
25
+ }
26
+
27
+ console.log('Generating fresh catalog from agent templates...');
28
+ const catalog = MetadataExtractor.generateCatalogFromAgents();
29
+
30
+ MetadataExtractor.saveCatalogToFile(catalog, metadataPath);
31
+
32
+ this.cache = catalog;
33
+ this.cacheTimestamp = Date.now();
34
+
35
+ return this.cache;
36
+ } catch (error) {
37
+ console.error('Error loading template catalog:', error.message);
38
+
39
+ return {
40
+ agents: [],
41
+ categories: {},
42
+ stats: {
43
+ totalAgents: 0,
44
+ categories: 0,
45
+ lastUpdated: new Date().toISOString(),
46
+ error: error.message
47
+ }
48
+ };
49
+ }
50
+ }
51
+
52
+ isCacheValid() {
53
+ return this.cache &&
54
+ this.cacheTimestamp &&
55
+ (Date.now() - this.cacheTimestamp) < this.cacheValidityMs;
56
+ }
57
+
58
+ async getTemplates(category = null, tags = [], searchQuery = null) {
59
+ const catalog = await this.load();
60
+ let templates = catalog.agents || [];
61
+
62
+ if (category && category !== 'all') {
63
+ if (category === 'agents') {
64
+ // Already filtered to agents
65
+ } else {
66
+ templates = templates.filter(t => t.subcategory === category);
67
+ }
68
+ }
69
+
70
+ if (tags && tags.length > 0) {
71
+ templates = templates.filter(t =>
72
+ tags.some(tag => t.tags.includes(tag.toLowerCase()))
73
+ );
74
+ }
75
+
76
+ if (searchQuery && searchQuery.trim()) {
77
+ const query = searchQuery.toLowerCase().trim();
78
+ templates = templates.filter(t => {
79
+ const searchableText = [
80
+ t.name,
81
+ t.description,
82
+ ...t.tags,
83
+ ...t.examples
84
+ ].join(' ').toLowerCase();
85
+
86
+ return searchableText.includes(query);
87
+ });
88
+ }
89
+
90
+ return templates;
91
+ }
92
+
93
+ async getTemplate(id) {
94
+ const catalog = await this.load();
95
+ return catalog.agents.find(agent => agent.id === id);
96
+ }
97
+
98
+ async getCategories() {
99
+ const catalog = await this.load();
100
+ return catalog.categories || {};
101
+ }
102
+
103
+ async getStats() {
104
+ const catalog = await this.load();
105
+ return catalog.stats || {};
106
+ }
107
+
108
+ async searchTemplates(query, options = {}) {
109
+ const {
110
+ category = null,
111
+ tags = [],
112
+ limit = 50,
113
+ sortBy = 'name'
114
+ } = options;
115
+
116
+ let templates = await this.getTemplates(category, tags, query);
117
+
118
+ if (sortBy === 'name') {
119
+ templates.sort((a, b) => a.name.localeCompare(b.name));
120
+ } else if (sortBy === 'category') {
121
+ templates.sort((a, b) => {
122
+ const categoryCompare = a.subcategory.localeCompare(b.subcategory);
123
+ return categoryCompare !== 0 ? categoryCompare : a.name.localeCompare(b.name);
124
+ });
125
+ }
126
+
127
+ return templates.slice(0, limit);
128
+ }
129
+
130
+ async validateTemplate(template) {
131
+ const requiredFields = ['id', 'name', 'category', 'description'];
132
+ const validation = {
133
+ valid: true,
134
+ errors: [],
135
+ warnings: []
136
+ };
137
+
138
+ for (const field of requiredFields) {
139
+ if (!template[field]) {
140
+ validation.valid = false;
141
+ validation.errors.push(`Missing required field: ${field}`);
142
+ }
143
+ }
144
+
145
+ if (template.category !== 'agents') {
146
+ validation.warnings.push(`Unexpected category: ${template.category}`);
147
+ }
148
+
149
+ if (!template.files || template.files.length === 0) {
150
+ validation.valid = false;
151
+ validation.errors.push('Template must specify at least one file');
152
+ }
153
+
154
+ if (template.files) {
155
+ const templateDir = path.join(__dirname, '../../template/.claude/agents');
156
+ for (const file of template.files) {
157
+ const filePath = path.join(templateDir, file);
158
+ if (!fs.existsSync(filePath)) {
159
+ validation.valid = false;
160
+ validation.errors.push(`Template file not found: ${file}`);
161
+ }
162
+ }
163
+ }
164
+
165
+ if (!template.tags || template.tags.length === 0) {
166
+ validation.warnings.push('Template has no tags - may be hard to discover');
167
+ }
168
+
169
+ return validation;
170
+ }
171
+
172
+ async refreshCatalog() {
173
+ console.log('Refreshing template catalog...');
174
+
175
+ const catalog = MetadataExtractor.generateCatalogFromAgents();
176
+ const metadataPath = path.join(__dirname, 'metadata/agents.json');
177
+
178
+ const saved = MetadataExtractor.saveCatalogToFile(catalog, metadataPath);
179
+
180
+ if (saved) {
181
+ this.cache = catalog;
182
+ this.cacheTimestamp = Date.now();
183
+ console.log(`Catalog refreshed: ${catalog.stats.totalAgents} agents processed`);
184
+ return catalog;
185
+ } else {
186
+ throw new Error('Failed to save refreshed catalog');
187
+ }
188
+ }
189
+
190
+ async getCatalogBySubcategory() {
191
+ const catalog = await this.load();
192
+ const result = {};
193
+
194
+ for (const agent of catalog.agents) {
195
+ if (!result[agent.subcategory]) {
196
+ result[agent.subcategory] = [];
197
+ }
198
+ result[agent.subcategory].push(agent);
199
+ }
200
+
201
+ Object.keys(result).forEach(category => {
202
+ result[category].sort((a, b) => a.name.localeCompare(b.name));
203
+ });
204
+
205
+ return result;
206
+ }
207
+
208
+ async getTagCloud() {
209
+ const catalog = await this.load();
210
+ const tagCounts = {};
211
+
212
+ for (const agent of catalog.agents) {
213
+ for (const tag of agent.tags) {
214
+ tagCounts[tag] = (tagCounts[tag] || 0) + 1;
215
+ }
216
+ }
217
+
218
+ const sortedTags = Object.entries(tagCounts)
219
+ .sort((a, b) => b[1] - a[1])
220
+ .map(([tag, count]) => ({ tag, count }));
221
+
222
+ return sortedTags;
223
+ }
224
+
225
+ static createInstance() {
226
+ return new TemplateCatalog();
227
+ }
228
+ }
229
+
230
+ module.exports = TemplateCatalog;
@@ -0,0 +1,257 @@
1
+ class TemplateFilter {
2
+ constructor(templates = []) {
3
+ this.templates = templates;
4
+ }
5
+
6
+ setTemplates(templates) {
7
+ this.templates = templates;
8
+ return this;
9
+ }
10
+
11
+ byCategory(category) {
12
+ if (!category || category === 'all') {
13
+ return new TemplateFilter(this.templates);
14
+ }
15
+
16
+ const filtered = this.templates.filter(template => {
17
+ if (category === 'agents') {
18
+ return template.category === 'agents';
19
+ }
20
+ return template.subcategory === category;
21
+ });
22
+
23
+ return new TemplateFilter(filtered);
24
+ }
25
+
26
+ byTags(tags) {
27
+ if (!tags || tags.length === 0) {
28
+ return new TemplateFilter(this.templates);
29
+ }
30
+
31
+ const normalizedTags = tags.map(tag => tag.toLowerCase());
32
+ const filtered = this.templates.filter(template => {
33
+ if (!template.tags || template.tags.length === 0) {
34
+ return false;
35
+ }
36
+
37
+ return normalizedTags.some(tag =>
38
+ template.tags.some(templateTag =>
39
+ templateTag.toLowerCase().includes(tag)
40
+ )
41
+ );
42
+ });
43
+
44
+ return new TemplateFilter(filtered);
45
+ }
46
+
47
+ byExactTags(tags) {
48
+ if (!tags || tags.length === 0) {
49
+ return new TemplateFilter(this.templates);
50
+ }
51
+
52
+ const normalizedTags = tags.map(tag => tag.toLowerCase());
53
+ const filtered = this.templates.filter(template => {
54
+ if (!template.tags || template.tags.length === 0) {
55
+ return false;
56
+ }
57
+
58
+ return normalizedTags.every(tag =>
59
+ template.tags.some(templateTag =>
60
+ templateTag.toLowerCase() === tag
61
+ )
62
+ );
63
+ });
64
+
65
+ return new TemplateFilter(filtered);
66
+ }
67
+
68
+ byAnyTag(tags) {
69
+ if (!tags || tags.length === 0) {
70
+ return new TemplateFilter(this.templates);
71
+ }
72
+
73
+ const normalizedTags = tags.map(tag => tag.toLowerCase());
74
+ const filtered = this.templates.filter(template => {
75
+ if (!template.tags || template.tags.length === 0) {
76
+ return false;
77
+ }
78
+
79
+ return normalizedTags.some(tag =>
80
+ template.tags.some(templateTag =>
81
+ templateTag.toLowerCase() === tag
82
+ )
83
+ );
84
+ });
85
+
86
+ return new TemplateFilter(filtered);
87
+ }
88
+
89
+ byAllTags(tags) {
90
+ if (!tags || tags.length === 0) {
91
+ return new TemplateFilter(this.templates);
92
+ }
93
+
94
+ const normalizedTags = tags.map(tag => tag.toLowerCase());
95
+ const filtered = this.templates.filter(template => {
96
+ if (!template.tags || template.tags.length === 0) {
97
+ return false;
98
+ }
99
+
100
+ return normalizedTags.every(tag =>
101
+ template.tags.some(templateTag =>
102
+ templateTag.toLowerCase() === tag
103
+ )
104
+ );
105
+ });
106
+
107
+ return new TemplateFilter(filtered);
108
+ }
109
+
110
+ combine(filters = {}) {
111
+ let result = this.templates;
112
+
113
+ if (filters.category) {
114
+ result = new TemplateFilter(result).byCategory(filters.category).getResults();
115
+ }
116
+
117
+ if (filters.tags && filters.tags.length > 0) {
118
+ const tagMode = filters.tagMode || 'any';
119
+ if (tagMode === 'all') {
120
+ result = new TemplateFilter(result).byAllTags(filters.tags).getResults();
121
+ } else if (tagMode === 'exact') {
122
+ result = new TemplateFilter(result).byExactTags(filters.tags).getResults();
123
+ } else {
124
+ result = new TemplateFilter(result).byAnyTag(filters.tags).getResults();
125
+ }
126
+ }
127
+
128
+ if (filters.subcategories && filters.subcategories.length > 0) {
129
+ result = result.filter(template =>
130
+ filters.subcategories.includes(template.subcategory)
131
+ );
132
+ }
133
+
134
+ return new TemplateFilter(result);
135
+ }
136
+
137
+ getResults() {
138
+ return [...this.templates];
139
+ }
140
+
141
+ getCount() {
142
+ return this.templates.length;
143
+ }
144
+
145
+ getCategories() {
146
+ const categories = new Set();
147
+ this.templates.forEach(template => {
148
+ if (template.category) {
149
+ categories.add(template.category);
150
+ }
151
+ });
152
+ return Array.from(categories).sort();
153
+ }
154
+
155
+ getSubcategories() {
156
+ const subcategories = new Set();
157
+ this.templates.forEach(template => {
158
+ if (template.subcategory) {
159
+ subcategories.add(template.subcategory);
160
+ }
161
+ });
162
+ return Array.from(subcategories).sort();
163
+ }
164
+
165
+ getAllTags() {
166
+ const tags = new Set();
167
+ this.templates.forEach(template => {
168
+ if (template.tags && Array.isArray(template.tags)) {
169
+ template.tags.forEach(tag => tags.add(tag.toLowerCase()));
170
+ }
171
+ });
172
+ return Array.from(tags).sort();
173
+ }
174
+
175
+ getTagsByFrequency() {
176
+ const tagCounts = {};
177
+ this.templates.forEach(template => {
178
+ if (template.tags && Array.isArray(template.tags)) {
179
+ template.tags.forEach(tag => {
180
+ const normalizedTag = tag.toLowerCase();
181
+ tagCounts[normalizedTag] = (tagCounts[normalizedTag] || 0) + 1;
182
+ });
183
+ }
184
+ });
185
+
186
+ return Object.entries(tagCounts)
187
+ .sort((a, b) => b[1] - a[1])
188
+ .map(([tag, count]) => ({ tag, count }));
189
+ }
190
+
191
+ sortBy(field, direction = 'asc') {
192
+ const sorted = [...this.templates].sort((a, b) => {
193
+ let valueA = a[field];
194
+ let valueB = b[field];
195
+
196
+ if (typeof valueA === 'string' && typeof valueB === 'string') {
197
+ valueA = valueA.toLowerCase();
198
+ valueB = valueB.toLowerCase();
199
+ }
200
+
201
+ if (valueA < valueB) {
202
+ return direction === 'asc' ? -1 : 1;
203
+ }
204
+ if (valueA > valueB) {
205
+ return direction === 'asc' ? 1 : -1;
206
+ }
207
+ return 0;
208
+ });
209
+
210
+ return new TemplateFilter(sorted);
211
+ }
212
+
213
+ limit(count) {
214
+ return new TemplateFilter(this.templates.slice(0, count));
215
+ }
216
+
217
+ offset(count) {
218
+ return new TemplateFilter(this.templates.slice(count));
219
+ }
220
+
221
+ paginate(page, pageSize) {
222
+ const start = (page - 1) * pageSize;
223
+ const end = start + pageSize;
224
+ return new TemplateFilter(this.templates.slice(start, end));
225
+ }
226
+
227
+ isEmpty() {
228
+ return this.templates.length === 0;
229
+ }
230
+
231
+ first() {
232
+ return this.templates.length > 0 ? this.templates[0] : null;
233
+ }
234
+
235
+ last() {
236
+ return this.templates.length > 0 ? this.templates[this.templates.length - 1] : null;
237
+ }
238
+
239
+ find(predicate) {
240
+ return this.templates.find(predicate);
241
+ }
242
+
243
+ some(predicate) {
244
+ return this.templates.some(predicate);
245
+ }
246
+
247
+ every(predicate) {
248
+ return this.templates.every(predicate);
249
+ }
250
+
251
+ static createFromCatalog(catalog) {
252
+ const templates = catalog?.agents || [];
253
+ return new TemplateFilter(templates);
254
+ }
255
+ }
256
+
257
+ module.exports = TemplateFilter;
@@ -0,0 +1,45 @@
1
+ const TemplateCatalog = require('./catalog');
2
+ const MetadataExtractor = require('./metadata-extractor');
3
+ const TemplateFilter = require('./filter');
4
+ const TemplateSearch = require('./search');
5
+
6
+ module.exports = {
7
+ TemplateCatalog,
8
+ MetadataExtractor,
9
+ TemplateFilter,
10
+ TemplateSearch,
11
+
12
+ async createCatalog() {
13
+ return TemplateCatalog.createInstance();
14
+ },
15
+
16
+ async refreshCatalog() {
17
+ const catalog = TemplateCatalog.createInstance();
18
+ return await catalog.refreshCatalog();
19
+ },
20
+
21
+ async getCatalogStats() {
22
+ const catalog = TemplateCatalog.createInstance();
23
+ return await catalog.getStats();
24
+ },
25
+
26
+ createFilter(templates) {
27
+ return new TemplateFilter(templates);
28
+ },
29
+
30
+ createSearch(templates) {
31
+ return new TemplateSearch(templates);
32
+ },
33
+
34
+ async searchTemplates(query, options = {}) {
35
+ const catalog = TemplateCatalog.createInstance();
36
+ const templates = await catalog.load();
37
+ return new TemplateSearch(templates.agents || []).search(query, options);
38
+ },
39
+
40
+ async filterTemplates(filters = {}) {
41
+ const catalog = TemplateCatalog.createInstance();
42
+ const templates = await catalog.load();
43
+ return new TemplateFilter(templates.agents || []).combine(filters);
44
+ }
45
+ };