@ckelsoe/prompt-architect 3.0.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.
Files changed (76) hide show
  1. package/.claude-plugin/marketplace.json +20 -0
  2. package/.claude-plugin/plugin.json +18 -0
  3. package/CHANGELOG.md +264 -0
  4. package/LICENSE +21 -0
  5. package/MIGRATION.md +66 -0
  6. package/README.md +1184 -0
  7. package/adapters/README.md +267 -0
  8. package/adapters/for-cursor.mdc +138 -0
  9. package/adapters/for-gemini-cli.md +70 -0
  10. package/adapters/for-github-copilot.md +141 -0
  11. package/adapters/for-openai-codex-cli.md +158 -0
  12. package/adapters/for-windsurf.md +136 -0
  13. package/adapters/system-prompt.md +243 -0
  14. package/package.json +135 -0
  15. package/scripts/install.js +490 -0
  16. package/scripts/test.js +213 -0
  17. package/scripts/validate-skill.js +350 -0
  18. package/skills/prompt-architect/SKILL.md +331 -0
  19. package/skills/prompt-architect/assets/templates/ape_template.txt +5 -0
  20. package/skills/prompt-architect/assets/templates/bab_template.txt +15 -0
  21. package/skills/prompt-architect/assets/templates/broke_template.txt +15 -0
  22. package/skills/prompt-architect/assets/templates/cai-critique-revise_template.txt +18 -0
  23. package/skills/prompt-architect/assets/templates/care_template.txt +16 -0
  24. package/skills/prompt-architect/assets/templates/chain-of-density_template.txt +46 -0
  25. package/skills/prompt-architect/assets/templates/chain-of-thought_template.txt +49 -0
  26. package/skills/prompt-architect/assets/templates/co-star_template.txt +17 -0
  27. package/skills/prompt-architect/assets/templates/crispe_template.txt +14 -0
  28. package/skills/prompt-architect/assets/templates/ctf_template.txt +15 -0
  29. package/skills/prompt-architect/assets/templates/devils-advocate_template.txt +25 -0
  30. package/skills/prompt-architect/assets/templates/hybrid_template.txt +101 -0
  31. package/skills/prompt-architect/assets/templates/least-to-most_template.txt +16 -0
  32. package/skills/prompt-architect/assets/templates/plan-and-solve_template.txt +7 -0
  33. package/skills/prompt-architect/assets/templates/pre-mortem_template.txt +27 -0
  34. package/skills/prompt-architect/assets/templates/race_template.txt +19 -0
  35. package/skills/prompt-architect/assets/templates/rcot_template.txt +31 -0
  36. package/skills/prompt-architect/assets/templates/react_template.txt +27 -0
  37. package/skills/prompt-architect/assets/templates/reverse-role_template.txt +11 -0
  38. package/skills/prompt-architect/assets/templates/rise-ie_template.txt +23 -0
  39. package/skills/prompt-architect/assets/templates/rise-ix_template.txt +28 -0
  40. package/skills/prompt-architect/assets/templates/risen_template.txt +21 -0
  41. package/skills/prompt-architect/assets/templates/rpef_template.txt +26 -0
  42. package/skills/prompt-architect/assets/templates/rtf_template.txt +13 -0
  43. package/skills/prompt-architect/assets/templates/self-refine_template.txt +16 -0
  44. package/skills/prompt-architect/assets/templates/skeleton-of-thought_template.txt +15 -0
  45. package/skills/prompt-architect/assets/templates/step-back_template.txt +10 -0
  46. package/skills/prompt-architect/assets/templates/tidd-ec_template.txt +45 -0
  47. package/skills/prompt-architect/assets/templates/tree-of-thought_template.txt +30 -0
  48. package/skills/prompt-architect/references/frameworks/ape.md +200 -0
  49. package/skills/prompt-architect/references/frameworks/bab.md +242 -0
  50. package/skills/prompt-architect/references/frameworks/broke.md +242 -0
  51. package/skills/prompt-architect/references/frameworks/cai-critique-revise.md +230 -0
  52. package/skills/prompt-architect/references/frameworks/care.md +235 -0
  53. package/skills/prompt-architect/references/frameworks/chain-of-density.md +479 -0
  54. package/skills/prompt-architect/references/frameworks/chain-of-thought.md +424 -0
  55. package/skills/prompt-architect/references/frameworks/co-star.md +256 -0
  56. package/skills/prompt-architect/references/frameworks/crispe.md +253 -0
  57. package/skills/prompt-architect/references/frameworks/ctf.md +207 -0
  58. package/skills/prompt-architect/references/frameworks/devils-advocate.md +206 -0
  59. package/skills/prompt-architect/references/frameworks/least-to-most.md +226 -0
  60. package/skills/prompt-architect/references/frameworks/plan-and-solve.md +210 -0
  61. package/skills/prompt-architect/references/frameworks/pre-mortem.md +197 -0
  62. package/skills/prompt-architect/references/frameworks/race.md +243 -0
  63. package/skills/prompt-architect/references/frameworks/rcot.md +203 -0
  64. package/skills/prompt-architect/references/frameworks/react.md +304 -0
  65. package/skills/prompt-architect/references/frameworks/reverse-role.md +189 -0
  66. package/skills/prompt-architect/references/frameworks/rise.md +555 -0
  67. package/skills/prompt-architect/references/frameworks/risen.md +297 -0
  68. package/skills/prompt-architect/references/frameworks/rpef.md +195 -0
  69. package/skills/prompt-architect/references/frameworks/rtf.md +358 -0
  70. package/skills/prompt-architect/references/frameworks/self-refine.md +205 -0
  71. package/skills/prompt-architect/references/frameworks/skeleton-of-thought.md +186 -0
  72. package/skills/prompt-architect/references/frameworks/step-back.md +206 -0
  73. package/skills/prompt-architect/references/frameworks/tidd-ec.md +470 -0
  74. package/skills/prompt-architect/references/frameworks/tree-of-thought.md +260 -0
  75. package/skills/prompt-architect/scripts/framework_analyzer.py +807 -0
  76. package/skills/prompt-architect/scripts/prompt_evaluator.py +336 -0
@@ -0,0 +1,490 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Prompt Architect — Multi-Agent Installer
5
+ *
6
+ * Detects installed AI agents and lets users choose where to install.
7
+ * Uses @clack/prompts for interactive UI, falls back to non-interactive
8
+ * for postinstall hooks and CI environments.
9
+ *
10
+ * Usage:
11
+ * npx @ckelsoe/prompt-architect # Interactive multi-agent install
12
+ * npx @ckelsoe/prompt-architect --all # Install to all detected agents
13
+ * npx @ckelsoe/prompt-architect --claude # Install to Claude Code only
14
+ */
15
+
16
+ const fs = require('fs');
17
+ const path = require('path');
18
+ const os = require('os');
19
+ const { execSync } = require('child_process');
20
+
21
+ // Configuration
22
+ const SKILL_NAME = 'prompt-architect';
23
+ const PACKAGE_NAME = '@ckelsoe/prompt-architect';
24
+ const SKILL_SOURCE_DIR = 'skills';
25
+
26
+ // ─── Agent Registry ──────────────────────────────────────────────
27
+
28
+ const AGENTS = [
29
+ {
30
+ id: 'claude',
31
+ name: 'Claude Code',
32
+ detect: () => fs.existsSync(path.join(os.homedir(), '.claude')),
33
+ installPath: (project) => project
34
+ ? path.join(process.cwd(), '.claude', 'skills', SKILL_NAME)
35
+ : path.join(os.homedir(), '.claude', 'skills', SKILL_NAME),
36
+ format: 'skill',
37
+ hint: (project) => project ? '.claude/skills/ (project)' : '~/.claude/skills/',
38
+ },
39
+ {
40
+ id: 'gemini',
41
+ name: 'Gemini CLI',
42
+ detect: () => {
43
+ if (fs.existsSync(path.join(os.homedir(), '.gemini'))) return true;
44
+ try {
45
+ execSync(process.platform === 'win32' ? 'where gemini' : 'which gemini', { stdio: 'ignore' });
46
+ return true;
47
+ } catch { return false; }
48
+ },
49
+ installPath: () => path.join(os.homedir(), '.gemini', 'skills', SKILL_NAME),
50
+ format: 'skill',
51
+ hint: () => '~/.gemini/skills/',
52
+ },
53
+ {
54
+ id: 'agents',
55
+ name: 'Agent Skills (universal)',
56
+ detect: () => true, // Always available
57
+ alwaysShow: true,
58
+ installPath: () => path.join(os.homedir(), '.agents', 'skills', SKILL_NAME),
59
+ format: 'skill',
60
+ hint: () => '~/.agents/skills/ (30+ compatible agents)',
61
+ },
62
+ {
63
+ id: 'cursor',
64
+ name: 'Cursor',
65
+ detect: () => {
66
+ return fs.existsSync(path.join(os.homedir(), '.cursor')) ||
67
+ fs.existsSync(path.join(process.cwd(), '.cursor'));
68
+ },
69
+ installPath: () => path.join(process.cwd(), '.cursor', 'rules', 'prompt-architect.mdc'),
70
+ format: 'adapter',
71
+ adapterFile: 'for-cursor.mdc',
72
+ hint: () => '.cursor/rules/ (project)',
73
+ },
74
+ {
75
+ id: 'copilot',
76
+ name: 'GitHub Copilot',
77
+ detect: () => {
78
+ try {
79
+ execSync(process.platform === 'win32' ? 'where code' : 'which code', { stdio: 'ignore' });
80
+ return true;
81
+ } catch {
82
+ return fs.existsSync(path.join(process.cwd(), '.vscode')) ||
83
+ fs.existsSync(path.join(process.cwd(), '.github'));
84
+ }
85
+ },
86
+ installPath: () => path.join(process.cwd(), '.github', 'copilot-instructions.md'),
87
+ format: 'adapter',
88
+ adapterFile: 'for-github-copilot.md',
89
+ appendMode: true,
90
+ hint: () => '.github/copilot-instructions.md (project)',
91
+ },
92
+ {
93
+ id: 'windsurf',
94
+ name: 'Windsurf',
95
+ detect: () => {
96
+ return fs.existsSync(path.join(process.cwd(), '.windsurfrules')) ||
97
+ fs.existsSync(path.join(os.homedir(), '.windsurf'));
98
+ },
99
+ installPath: () => path.join(process.cwd(), '.windsurfrules'),
100
+ format: 'adapter',
101
+ adapterFile: 'for-windsurf.md',
102
+ appendMode: true,
103
+ hint: () => '.windsurfrules (project)',
104
+ },
105
+ {
106
+ id: 'codex',
107
+ name: 'OpenAI Codex CLI',
108
+ detect: () => {
109
+ try {
110
+ execSync(process.platform === 'win32' ? 'where codex' : 'which codex', { stdio: 'ignore' });
111
+ return true;
112
+ } catch {
113
+ return fs.existsSync(path.join(process.cwd(), 'AGENTS.md'));
114
+ }
115
+ },
116
+ installPath: () => path.join(process.cwd(), 'AGENTS.md'),
117
+ format: 'adapter',
118
+ adapterFile: 'for-openai-codex-cli.md',
119
+ appendMode: true,
120
+ hint: () => 'AGENTS.md (project)',
121
+ },
122
+ ];
123
+
124
+ // ─── Source Path Resolution ──────────────────────────────────────
125
+
126
+ function findSourcePath() {
127
+ // Try relative to this script (development or npm package)
128
+ const fromScript = path.join(__dirname, '..', SKILL_SOURCE_DIR, SKILL_NAME);
129
+ if (fs.existsSync(fromScript)) return fromScript;
130
+
131
+ // Try local node_modules
132
+ const localPath = path.join(process.cwd(), 'node_modules', PACKAGE_NAME, SKILL_SOURCE_DIR, SKILL_NAME);
133
+ if (fs.existsSync(localPath)) return localPath;
134
+
135
+ // Try global node_modules
136
+ try {
137
+ const globalRoot = execSync('npm root -g', { encoding: 'utf8' }).trim();
138
+ const globalPath = path.join(globalRoot, PACKAGE_NAME, SKILL_SOURCE_DIR, SKILL_NAME);
139
+ if (fs.existsSync(globalPath)) return globalPath;
140
+ } catch { /* ignore */ }
141
+
142
+ return null;
143
+ }
144
+
145
+ function findAdaptersPath() {
146
+ const fromScript = path.join(__dirname, '..', 'adapters');
147
+ if (fs.existsSync(fromScript)) return fromScript;
148
+
149
+ const localPath = path.join(process.cwd(), 'node_modules', PACKAGE_NAME, 'adapters');
150
+ if (fs.existsSync(localPath)) return localPath;
151
+
152
+ try {
153
+ const globalRoot = execSync('npm root -g', { encoding: 'utf8' }).trim();
154
+ const globalPath = path.join(globalRoot, PACKAGE_NAME, 'adapters');
155
+ if (fs.existsSync(globalPath)) return globalPath;
156
+ } catch { /* ignore */ }
157
+
158
+ return null;
159
+ }
160
+
161
+ // ─── File Operations ─────────────────────────────────────────────
162
+
163
+ function copyRecursive(src, dest) {
164
+ const stats = fs.statSync(src);
165
+ if (stats.isDirectory()) {
166
+ if (!fs.existsSync(dest)) fs.mkdirSync(dest, { recursive: true });
167
+ for (const entry of fs.readdirSync(src)) {
168
+ copyRecursive(path.join(src, entry), path.join(dest, entry));
169
+ }
170
+ } else {
171
+ fs.copyFileSync(src, dest);
172
+ }
173
+ }
174
+
175
+ const MARKER_START = '<!-- prompt-architect-start -->';
176
+ const MARKER_END = '<!-- prompt-architect-end -->';
177
+
178
+ function installSkillDir(sourcePath, destPath) {
179
+ const parentDir = path.dirname(destPath);
180
+ if (!fs.existsSync(parentDir)) fs.mkdirSync(parentDir, { recursive: true });
181
+
182
+ // Remove existing installation
183
+ if (fs.existsSync(destPath)) fs.rmSync(destPath, { recursive: true, force: true });
184
+
185
+ copyRecursive(sourcePath, destPath);
186
+
187
+ // Verify
188
+ if (!fs.existsSync(path.join(destPath, 'SKILL.md'))) {
189
+ throw new Error('SKILL.md not found after copy');
190
+ }
191
+ }
192
+
193
+ function installAdapter(adaptersPath, agent, destPath) {
194
+ const adapterSrc = path.join(adaptersPath, agent.adapterFile);
195
+ if (!fs.existsSync(adapterSrc)) {
196
+ throw new Error(`Adapter file not found: ${agent.adapterFile}`);
197
+ }
198
+
199
+ const adapterContent = fs.readFileSync(adapterSrc, 'utf8');
200
+ const markedContent = `\n${MARKER_START}\n${adapterContent}\n${MARKER_END}\n`;
201
+
202
+ if (agent.appendMode && fs.existsSync(destPath)) {
203
+ const existing = fs.readFileSync(destPath, 'utf8');
204
+ // Remove old content if present
205
+ const cleaned = existing.replace(
206
+ new RegExp(`\\n?${escapeRegex(MARKER_START)}[\\s\\S]*?${escapeRegex(MARKER_END)}\\n?`),
207
+ ''
208
+ );
209
+ fs.writeFileSync(destPath, cleaned + markedContent, 'utf8');
210
+ } else {
211
+ const parentDir = path.dirname(destPath);
212
+ if (!fs.existsSync(parentDir)) fs.mkdirSync(parentDir, { recursive: true });
213
+ fs.writeFileSync(destPath, adapterContent, 'utf8');
214
+ }
215
+ }
216
+
217
+ function escapeRegex(str) {
218
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
219
+ }
220
+
221
+ // ─── Version ─────────────────────────────────────────────────────
222
+
223
+ function getVersion() {
224
+ try {
225
+ const pkg = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), 'utf8'));
226
+ return pkg.version || 'unknown';
227
+ } catch { return 'unknown'; }
228
+ }
229
+
230
+ // ─── CLI Argument Parsing ────────────────────────────────────────
231
+
232
+ function parseArgs() {
233
+ const args = process.argv.slice(2);
234
+ const flags = {
235
+ help: args.includes('--help') || args.includes('-h'),
236
+ all: args.includes('--all') || args.includes('-a'),
237
+ yes: args.includes('--yes') || args.includes('-y'),
238
+ force: args.includes('--force') || args.includes('-f'),
239
+ project: args.includes('--project') || args.includes('-p'),
240
+ // Individual agent flags
241
+ claude: args.includes('--claude'),
242
+ gemini: args.includes('--gemini'),
243
+ agents: args.includes('--agents'),
244
+ cursor: args.includes('--cursor'),
245
+ copilot: args.includes('--copilot'),
246
+ windsurf: args.includes('--windsurf'),
247
+ codex: args.includes('--codex'),
248
+ };
249
+
250
+ const specificAgents = ['claude', 'gemini', 'agents', 'cursor', 'copilot', 'windsurf', 'codex']
251
+ .filter(a => flags[a]);
252
+
253
+ return { flags, specificAgents };
254
+ }
255
+
256
+ // ─── Help ────────────────────────────────────────────────────────
257
+
258
+ function showHelp() {
259
+ const version = getVersion();
260
+ console.log(`
261
+ Prompt Architect v${version} — Multi-Agent Installer
262
+
263
+ Usage:
264
+ npx ${PACKAGE_NAME} Interactive multi-agent install
265
+ npx ${PACKAGE_NAME} --all Install to all detected agents
266
+ npx ${PACKAGE_NAME} --claude Install to Claude Code only
267
+
268
+ Agent flags (skip interactive, install to specified targets):
269
+ --claude Claude Code (~/.claude/skills/)
270
+ --gemini Gemini CLI (~/.gemini/skills/)
271
+ --agents Agent Skills universal (~/.agents/skills/)
272
+ --cursor Cursor (.cursor/rules/)
273
+ --copilot GitHub Copilot (.github/)
274
+ --windsurf Windsurf (.windsurfrules)
275
+ --codex OpenAI Codex CLI (AGENTS.md)
276
+
277
+ Options:
278
+ -a, --all Install to all detected agents
279
+ -p, --project Use project-local paths where applicable
280
+ -f, --force Overwrite existing installations
281
+ -y, --yes Accept defaults (all detected agents)
282
+ -h, --help Show this help
283
+ `);
284
+ }
285
+
286
+ // ─── Non-Interactive Install ─────────────────────────────────────
287
+
288
+ function installNonInteractive(agentIds, sourcePath, adaptersPath, isProject) {
289
+ const version = getVersion();
290
+ const results = [];
291
+
292
+ for (const agent of AGENTS) {
293
+ if (!agentIds.includes(agent.id)) continue;
294
+
295
+ const destPath = agent.installPath(isProject);
296
+ try {
297
+ if (agent.format === 'skill') {
298
+ installSkillDir(sourcePath, destPath);
299
+ } else {
300
+ installAdapter(adaptersPath, agent, destPath);
301
+ }
302
+ results.push({ agent: agent.name, path: destPath, success: true });
303
+ } catch (err) {
304
+ results.push({ agent: agent.name, path: destPath, success: false, error: err.message });
305
+ }
306
+ }
307
+
308
+ // Print results
309
+ console.log(`\n Prompt Architect v${version}\n`);
310
+ for (const r of results) {
311
+ if (r.success) {
312
+ console.log(` \x1b[32m✓\x1b[0m ${r.agent} → ${r.path}`);
313
+ } else {
314
+ console.log(` \x1b[31m✗\x1b[0m ${r.agent}: ${r.error}`);
315
+ }
316
+ }
317
+
318
+ const succeeded = results.filter(r => r.success).length;
319
+ const failed = results.filter(r => !r.success).length;
320
+ if (succeeded > 0) {
321
+ console.log(`\n \x1b[32m${succeeded} installed successfully.\x1b[0m Restart your AI agent to load the skill.\n`);
322
+ }
323
+ if (failed > 0) {
324
+ console.log(` \x1b[31m${failed} failed.\x1b[0m\n`);
325
+ process.exit(1);
326
+ }
327
+ }
328
+
329
+ // ─── Interactive Install ─────────────────────────────────────────
330
+
331
+ async function installInteractive(sourcePath, adaptersPath, isProject) {
332
+ const p = require('@clack/prompts');
333
+ const version = getVersion();
334
+
335
+ p.intro(`Prompt Architect v${version}`);
336
+
337
+ // Detect agents
338
+ const detected = AGENTS.filter(a => a.detect());
339
+ const notDetected = AGENTS.filter(a => !a.detect());
340
+
341
+ if (detected.length === 0) {
342
+ p.log.warn('No AI agents detected on your system.');
343
+ p.log.info('You can still install to any location using the flags below.');
344
+ showHelp();
345
+ p.outro('No installation performed.');
346
+ return;
347
+ }
348
+
349
+ const detectedNames = detected
350
+ .filter(a => !a.alwaysShow)
351
+ .map(a => a.name)
352
+ .join(', ');
353
+ if (detectedNames) {
354
+ p.log.info(`Detected: ${detectedNames}`);
355
+ }
356
+
357
+ // Build options — detected first (pre-selected), then others
358
+ const options = [];
359
+
360
+ for (const agent of detected) {
361
+ options.push({
362
+ value: agent.id,
363
+ label: agent.name,
364
+ hint: agent.hint(isProject),
365
+ });
366
+ }
367
+
368
+ for (const agent of notDetected) {
369
+ options.push({
370
+ value: agent.id,
371
+ label: `${agent.name} (not detected)`,
372
+ hint: agent.hint(isProject),
373
+ });
374
+ }
375
+
376
+ const initialValues = detected
377
+ .filter(a => !a.alwaysShow) // Don't pre-select "universal" since it's always available
378
+ .map(a => a.id);
379
+
380
+ const selected = await p.multiselect({
381
+ message: 'Select agents to install for:',
382
+ options,
383
+ initialValues,
384
+ required: true,
385
+ });
386
+
387
+ if (p.isCancel(selected)) {
388
+ p.cancel('Installation cancelled.');
389
+ process.exit(0);
390
+ }
391
+
392
+ // Install to each selected agent
393
+ const s = p.spinner();
394
+ const results = [];
395
+
396
+ for (const agentId of selected) {
397
+ const agent = AGENTS.find(a => a.id === agentId);
398
+ if (!agent) continue;
399
+
400
+ const destPath = agent.installPath(isProject);
401
+ s.start(`Installing to ${agent.name}...`);
402
+
403
+ try {
404
+ if (agent.format === 'skill') {
405
+ installSkillDir(sourcePath, destPath);
406
+ } else {
407
+ installAdapter(adaptersPath, agent, destPath);
408
+ }
409
+ s.stop(`${agent.name} → ${destPath}`);
410
+ results.push({ agent: agent.name, success: true });
411
+ } catch (err) {
412
+ s.stop(`${agent.name}: ${err.message}`);
413
+ results.push({ agent: agent.name, success: false, error: err.message });
414
+ }
415
+ }
416
+
417
+ // Summary
418
+ const succeeded = results.filter(r => r.success).length;
419
+ const failed = results.filter(r => !r.success).length;
420
+
421
+ if (failed > 0) {
422
+ p.log.warn(`${failed} installation(s) failed.`);
423
+ }
424
+
425
+ if (succeeded > 0) {
426
+ p.outro(`${succeeded} agent(s) configured. Restart your AI agent to load the skill.`);
427
+ } else {
428
+ p.outro('No installations succeeded.');
429
+ process.exit(1);
430
+ }
431
+ }
432
+
433
+ // ─── Main ────────────────────────────────────────────────────────
434
+
435
+ async function main() {
436
+ const { flags, specificAgents } = parseArgs();
437
+
438
+ if (flags.help) {
439
+ showHelp();
440
+ process.exit(0);
441
+ }
442
+
443
+ // Find source files
444
+ const sourcePath = findSourcePath();
445
+ const adaptersPath = findAdaptersPath();
446
+
447
+ if (!sourcePath) {
448
+ console.error(`\n \x1b[31mError: Could not find ${SKILL_NAME} skill files.\x1b[0m`);
449
+ console.error(` Try reinstalling: npm install -g ${PACKAGE_NAME}\n`);
450
+ process.exit(1);
451
+ }
452
+
453
+ const isProject = flags.project;
454
+ const isInteractive = process.stdin.isTTY && process.stdout.isTTY && !process.env.CI;
455
+
456
+ // Mode 1: Specific agent flags provided
457
+ if (specificAgents.length > 0) {
458
+ installNonInteractive(specificAgents, sourcePath, adaptersPath, isProject);
459
+ return;
460
+ }
461
+
462
+ // Mode 2: --all flag
463
+ if (flags.all) {
464
+ const detected = AGENTS.filter(a => a.detect()).map(a => a.id);
465
+ installNonInteractive(detected, sourcePath, adaptersPath, isProject);
466
+ return;
467
+ }
468
+
469
+ // Mode 3: --yes flag (accept defaults = all detected, non-interactive)
470
+ if (flags.yes) {
471
+ const detected = AGENTS.filter(a => a.detect() && !a.alwaysShow).map(a => a.id);
472
+ installNonInteractive(detected.length > 0 ? detected : ['claude'], sourcePath, adaptersPath, isProject);
473
+ return;
474
+ }
475
+
476
+ // Mode 4: Interactive
477
+ if (isInteractive) {
478
+ await installInteractive(sourcePath, adaptersPath, isProject);
479
+ return;
480
+ }
481
+
482
+ // Mode 5: Non-interactive fallback (postinstall, CI)
483
+ installNonInteractive(['claude'], sourcePath, adaptersPath, isProject);
484
+ console.log(` Run \x1b[36mnpx ${PACKAGE_NAME}\x1b[0m for interactive multi-agent setup.\n`);
485
+ }
486
+
487
+ main().catch(err => {
488
+ console.error(`\n \x1b[31mInstallation error: ${err.message}\x1b[0m\n`);
489
+ process.exit(1);
490
+ });
@@ -0,0 +1,213 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Test Script
5
+ *
6
+ * Runs basic tests to verify the skill package is properly configured.
7
+ */
8
+
9
+ const fs = require('fs');
10
+ const path = require('path');
11
+
12
+ const colors = {
13
+ reset: '\x1b[0m',
14
+ red: '\x1b[31m',
15
+ green: '\x1b[32m',
16
+ yellow: '\x1b[33m',
17
+ blue: '\x1b[34m',
18
+ };
19
+
20
+ function log(message, color = 'reset') {
21
+ console.log(`${colors[color]}${message}${colors.reset}`);
22
+ }
23
+
24
+ log('\n🧪 Running tests for Prompt Architect skill...\n', 'blue');
25
+
26
+ let passed = 0;
27
+ let failed = 0;
28
+
29
+ function test(description, fn) {
30
+ try {
31
+ fn();
32
+ log(`✅ ${description}`, 'green');
33
+ passed++;
34
+ } catch (error) {
35
+ log(`❌ ${description}`, 'red');
36
+ log(` ${error.message}`, 'red');
37
+ failed++;
38
+ }
39
+ }
40
+
41
+ // Tests
42
+ test('package.json exists', () => {
43
+ if (!fs.existsSync('package.json')) throw new Error('Not found');
44
+ });
45
+
46
+ test('package.json is valid JSON', () => {
47
+ JSON.parse(fs.readFileSync('package.json', 'utf8'));
48
+ });
49
+
50
+ test('SKILL.md exists', () => {
51
+ if (!fs.existsSync('skills/prompt-architect/SKILL.md')) throw new Error('Not found');
52
+ });
53
+
54
+ test('LICENSE exists', () => {
55
+ if (!fs.existsSync('LICENSE')) throw new Error('Not found');
56
+ });
57
+
58
+ test('README.md exists', () => {
59
+ if (!fs.existsSync('README.md')) throw new Error('Not found');
60
+ });
61
+
62
+ test('CHANGELOG.md exists', () => {
63
+ if (!fs.existsSync('CHANGELOG.md')) throw new Error('Not found');
64
+ });
65
+
66
+ test('All framework files exist', () => {
67
+ const frameworks = [
68
+ 'co-star.md',
69
+ 'risen.md',
70
+ 'rise.md',
71
+ 'tidd-ec.md',
72
+ 'rtf.md',
73
+ 'chain-of-thought.md',
74
+ 'chain-of-density.md',
75
+ ];
76
+ frameworks.forEach(f => {
77
+ const fpath = path.join('skills', 'prompt-architect', 'references', 'frameworks', f);
78
+ if (!fs.existsSync(fpath)) {
79
+ throw new Error(`Framework ${f} not found`);
80
+ }
81
+ });
82
+ });
83
+
84
+ test('All templates exist', () => {
85
+ const templates = [
86
+ 'co-star_template.txt',
87
+ 'risen_template.txt',
88
+ 'rise-ie_template.txt',
89
+ 'rise-ix_template.txt',
90
+ 'tidd-ec_template.txt',
91
+ 'rtf_template.txt',
92
+ 'hybrid_template.txt',
93
+ ];
94
+ templates.forEach(t => {
95
+ const tpath = path.join('skills', 'prompt-architect', 'assets', 'templates', t);
96
+ if (!fs.existsSync(tpath)) {
97
+ throw new Error(`Template ${t} not found`);
98
+ }
99
+ });
100
+ });
101
+
102
+ test('Python scripts exist', () => {
103
+ const scripts = ['framework_analyzer.py', 'prompt_evaluator.py'];
104
+ scripts.forEach(s => {
105
+ const spath = path.join('skills', 'prompt-architect', 'scripts', s);
106
+ if (!fs.existsSync(spath)) {
107
+ throw new Error(`Script ${s} not found`);
108
+ }
109
+ });
110
+ });
111
+
112
+ test('package.json has required fields', () => {
113
+ const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
114
+ const required = ['name', 'version', 'description', 'main', 'keywords', 'license'];
115
+ required.forEach(field => {
116
+ if (!pkg[field]) throw new Error(`Missing field: ${field}`);
117
+ });
118
+ });
119
+
120
+ test('package.json keywords include "claude-code"', () => {
121
+ const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
122
+ if (!pkg.keywords || !pkg.keywords.includes('claude-code')) {
123
+ throw new Error('Missing "claude-code" keyword');
124
+ }
125
+ });
126
+
127
+ // Plugin manifest tests
128
+ test('.claude-plugin/plugin.json exists and is valid', () => {
129
+ const pluginPath = '.claude-plugin/plugin.json';
130
+ if (!fs.existsSync(pluginPath)) throw new Error('Not found');
131
+ const plugin = JSON.parse(fs.readFileSync(pluginPath, 'utf8'));
132
+ if (!plugin.name) throw new Error('Missing name');
133
+ if (!plugin.description) throw new Error('Missing description');
134
+ if (!plugin.version) throw new Error('Missing version');
135
+ });
136
+
137
+ test('.claude-plugin/marketplace.json exists and is valid', () => {
138
+ const mktPath = '.claude-plugin/marketplace.json';
139
+ if (!fs.existsSync(mktPath)) throw new Error('Not found');
140
+ const mkt = JSON.parse(fs.readFileSync(mktPath, 'utf8'));
141
+ if (!mkt.name) throw new Error('Missing name');
142
+ if (!mkt.owner) throw new Error('Missing owner');
143
+ if (!mkt.plugins || mkt.plugins.length === 0) throw new Error('No plugins defined');
144
+ });
145
+
146
+ test('plugin.json version matches package.json version', () => {
147
+ const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
148
+ const plugin = JSON.parse(fs.readFileSync('.claude-plugin/plugin.json', 'utf8'));
149
+ if (pkg.version !== plugin.version) {
150
+ throw new Error(`Version mismatch: package.json=${pkg.version}, plugin.json=${plugin.version}`);
151
+ }
152
+ });
153
+
154
+ // Adapter tests
155
+ test('Gemini CLI adapter exists', () => {
156
+ if (!fs.existsSync('adapters/for-gemini-cli.md')) throw new Error('Not found');
157
+ });
158
+
159
+ test('All adapter files exist', () => {
160
+ const adapters = [
161
+ 'system-prompt.md',
162
+ 'for-openai-codex-cli.md',
163
+ 'for-cursor.mdc',
164
+ 'for-github-copilot.md',
165
+ 'for-windsurf.md',
166
+ 'for-gemini-cli.md',
167
+ 'README.md',
168
+ ];
169
+ adapters.forEach(a => {
170
+ if (!fs.existsSync(path.join('adapters', a))) throw new Error(`Adapter ${a} not found`);
171
+ });
172
+ });
173
+
174
+ // Agent Skills compliance tests
175
+ test('SKILL.md has Agent Skills required fields', () => {
176
+ const content = fs.readFileSync('skills/prompt-architect/SKILL.md', 'utf8');
177
+ const fm = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
178
+ if (!fm) throw new Error('No frontmatter');
179
+ if (!fm[1].includes('name:')) throw new Error('Missing name');
180
+ if (!fm[1].includes('description:')) throw new Error('Missing description');
181
+ });
182
+
183
+ test('SKILL.md has optional Agent Skills fields', () => {
184
+ const content = fs.readFileSync('skills/prompt-architect/SKILL.md', 'utf8');
185
+ const fm = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
186
+ if (!fm) throw new Error('No frontmatter');
187
+ if (!fm[1].includes('license:')) throw new Error('Missing license');
188
+ if (!fm[1].includes('compatibility:')) throw new Error('Missing compatibility');
189
+ if (!fm[1].includes('metadata:')) throw new Error('Missing metadata');
190
+ });
191
+
192
+ test('SKILL.md name matches directory name', () => {
193
+ const content = fs.readFileSync('skills/prompt-architect/SKILL.md', 'utf8');
194
+ const nameMatch = content.match(/name:\s*([^\n\r]+)/);
195
+ if (!nameMatch) throw new Error('No name field');
196
+ if (nameMatch[1].trim() !== 'prompt-architect') {
197
+ throw new Error(`Name "${nameMatch[1].trim()}" does not match directory "prompt-architect"`);
198
+ }
199
+ });
200
+
201
+ // Summary
202
+ log('\n' + '='.repeat(50), 'blue');
203
+ log(`Tests completed: ${passed + failed} total`, 'blue');
204
+ log(`✅ Passed: ${passed}`, 'green');
205
+ if (failed > 0) {
206
+ log(`❌ Failed: ${failed}`, 'red');
207
+ log('='.repeat(50) + '\n', 'blue');
208
+ process.exit(1);
209
+ } else {
210
+ log('='.repeat(50), 'blue');
211
+ log('\n✨ All tests passed!\n', 'green');
212
+ process.exit(0);
213
+ }