prpm 0.1.17 ā 1.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.
- package/dist/index.js +14257 -107
- package/package.json +11 -9
- package/dist/__tests__/e2e/test-helpers.js +0 -151
- package/dist/commands/buy-credits.js +0 -224
- package/dist/commands/catalog.js +0 -365
- package/dist/commands/collections.js +0 -655
- package/dist/commands/config.js +0 -161
- package/dist/commands/credits.js +0 -186
- package/dist/commands/index.js +0 -184
- package/dist/commands/info.js +0 -78
- package/dist/commands/init.js +0 -684
- package/dist/commands/install.js +0 -789
- package/dist/commands/list.js +0 -189
- package/dist/commands/login.js +0 -316
- package/dist/commands/outdated.js +0 -130
- package/dist/commands/playground.js +0 -570
- package/dist/commands/popular.js +0 -33
- package/dist/commands/publish.js +0 -803
- package/dist/commands/schema.js +0 -41
- package/dist/commands/search.js +0 -446
- package/dist/commands/subscribe.js +0 -211
- package/dist/commands/telemetry.js +0 -104
- package/dist/commands/trending.js +0 -86
- package/dist/commands/uninstall.js +0 -120
- package/dist/commands/update.js +0 -121
- package/dist/commands/upgrade.js +0 -121
- package/dist/commands/whoami.js +0 -83
- package/dist/core/claude-config.js +0 -91
- package/dist/core/cursor-config.js +0 -130
- package/dist/core/downloader.js +0 -64
- package/dist/core/errors.js +0 -29
- package/dist/core/filesystem.js +0 -242
- package/dist/core/lockfile.js +0 -292
- package/dist/core/marketplace-converter.js +0 -224
- package/dist/core/registry-client.js +0 -305
- package/dist/core/schema-validator.js +0 -74
- package/dist/core/telemetry.js +0 -253
- package/dist/core/user-config.js +0 -147
- package/dist/types/registry.js +0 -12
- package/dist/types.js +0 -36
- package/dist/utils/license-extractor.js +0 -122
- package/dist/utils/multi-package.js +0 -117
- package/dist/utils/parallel-publisher.js +0 -144
- package/dist/utils/script-executor.js +0 -72
- package/dist/utils/snippet-extractor.js +0 -77
- package/dist/utils/webapp-url.js +0 -44
package/dist/commands/init.js
DELETED
|
@@ -1,684 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Init command implementation
|
|
4
|
-
* Scaffolds a new PRPM package with interactive prompts
|
|
5
|
-
*/
|
|
6
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
-
if (k2 === undefined) k2 = k;
|
|
8
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
-
}
|
|
12
|
-
Object.defineProperty(o, k2, desc);
|
|
13
|
-
}) : (function(o, m, k, k2) {
|
|
14
|
-
if (k2 === undefined) k2 = k;
|
|
15
|
-
o[k2] = m[k];
|
|
16
|
-
}));
|
|
17
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
-
}) : function(o, v) {
|
|
20
|
-
o["default"] = v;
|
|
21
|
-
});
|
|
22
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
-
var ownKeys = function(o) {
|
|
24
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
-
var ar = [];
|
|
26
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
-
return ar;
|
|
28
|
-
};
|
|
29
|
-
return ownKeys(o);
|
|
30
|
-
};
|
|
31
|
-
return function (mod) {
|
|
32
|
-
if (mod && mod.__esModule) return mod;
|
|
33
|
-
var result = {};
|
|
34
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
-
__setModuleDefault(result, mod);
|
|
36
|
-
return result;
|
|
37
|
-
};
|
|
38
|
-
})();
|
|
39
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
-
exports.createInitCommand = createInitCommand;
|
|
41
|
-
const commander_1 = require("commander");
|
|
42
|
-
const promises_1 = require("fs/promises");
|
|
43
|
-
const path_1 = require("path");
|
|
44
|
-
const fs_1 = require("fs");
|
|
45
|
-
const readline = __importStar(require("readline/promises"));
|
|
46
|
-
const process_1 = require("process");
|
|
47
|
-
const types_1 = require("../types");
|
|
48
|
-
const errors_1 = require("../core/errors");
|
|
49
|
-
const FORMAT_EXAMPLES = {
|
|
50
|
-
cursor: {
|
|
51
|
-
description: 'Cursor AI coding rules',
|
|
52
|
-
files: ['.cursorrules', 'README.md'],
|
|
53
|
-
},
|
|
54
|
-
claude: {
|
|
55
|
-
description: 'Claude AI skills and agents',
|
|
56
|
-
files: ['.claude/skills/example-skill/SKILL.md', 'README.md'],
|
|
57
|
-
},
|
|
58
|
-
continue: {
|
|
59
|
-
description: 'Continue AI coding rules',
|
|
60
|
-
files: ['.continuerules', 'README.md'],
|
|
61
|
-
},
|
|
62
|
-
windsurf: {
|
|
63
|
-
description: 'Windsurf AI coding rules',
|
|
64
|
-
files: ['.windsurf/rules', 'README.md'],
|
|
65
|
-
},
|
|
66
|
-
copilot: {
|
|
67
|
-
description: 'GitHub Copilot (repository-wide, path-specific, and chat modes)',
|
|
68
|
-
files: ['.github/copilot-instructions.md', '.github/instructions/typescript.instructions.md', '.github/chatmodes/code-reviewer.chatmode.md', 'README.md'],
|
|
69
|
-
},
|
|
70
|
-
kiro: {
|
|
71
|
-
description: 'Kiro steering files and hooks',
|
|
72
|
-
files: ['.kiro/steering/example.md', '.kiro/hooks/example-hook.kiro.hook', 'README.md'],
|
|
73
|
-
},
|
|
74
|
-
'agents.md': {
|
|
75
|
-
description: 'OpenAI agents.md project instructions',
|
|
76
|
-
files: ['agents.md', 'README.md'],
|
|
77
|
-
},
|
|
78
|
-
generic: {
|
|
79
|
-
description: 'Generic AI prompts',
|
|
80
|
-
files: ['prompts/example.md', 'README.md'],
|
|
81
|
-
},
|
|
82
|
-
mcp: {
|
|
83
|
-
description: 'Model Context Protocol',
|
|
84
|
-
files: ['mcp.json', 'README.md'],
|
|
85
|
-
},
|
|
86
|
-
};
|
|
87
|
-
const EXAMPLE_TEMPLATES = {
|
|
88
|
-
cursor: {
|
|
89
|
-
'.cursorrules': `# Cursor Rules
|
|
90
|
-
|
|
91
|
-
Add your Cursor AI coding rules here.
|
|
92
|
-
|
|
93
|
-
## Code Style
|
|
94
|
-
|
|
95
|
-
- Use TypeScript
|
|
96
|
-
- Follow functional programming patterns
|
|
97
|
-
- Write comprehensive tests
|
|
98
|
-
|
|
99
|
-
## Best Practices
|
|
100
|
-
|
|
101
|
-
- Keep functions small and focused
|
|
102
|
-
- Use meaningful variable names
|
|
103
|
-
- Document complex logic
|
|
104
|
-
`,
|
|
105
|
-
},
|
|
106
|
-
claude: {
|
|
107
|
-
'.claude/skills/example-skill/SKILL.md': `---
|
|
108
|
-
name: example-skill
|
|
109
|
-
description: Example Claude skill - replace with your actual skill
|
|
110
|
-
tags: example, template
|
|
111
|
-
---
|
|
112
|
-
|
|
113
|
-
# Example Skill
|
|
114
|
-
|
|
115
|
-
This is an example Claude skill. Replace this content with your actual skill definition.
|
|
116
|
-
|
|
117
|
-
## What this skill does
|
|
118
|
-
|
|
119
|
-
Describe what this skill helps the AI accomplish.
|
|
120
|
-
|
|
121
|
-
## When to use this skill
|
|
122
|
-
|
|
123
|
-
Explain when this skill should be invoked.
|
|
124
|
-
|
|
125
|
-
## Instructions
|
|
126
|
-
|
|
127
|
-
Provide detailed instructions for the AI to follow when using this skill.
|
|
128
|
-
`,
|
|
129
|
-
},
|
|
130
|
-
windsurf: {
|
|
131
|
-
'.windsurf/rules': `# Windsurf Rules
|
|
132
|
-
|
|
133
|
-
Add your Windsurf AI coding rules here.
|
|
134
|
-
|
|
135
|
-
## Code Conventions
|
|
136
|
-
|
|
137
|
-
- Use TypeScript for type safety
|
|
138
|
-
- Follow React best practices
|
|
139
|
-
- Write unit tests for all components
|
|
140
|
-
|
|
141
|
-
## Architecture
|
|
142
|
-
|
|
143
|
-
- Component-based architecture
|
|
144
|
-
- Separate business logic from UI
|
|
145
|
-
- Use hooks for state management
|
|
146
|
-
`,
|
|
147
|
-
},
|
|
148
|
-
copilot: {
|
|
149
|
-
'.github/copilot-instructions.md': `# GitHub Copilot Repository-Wide Instructions
|
|
150
|
-
|
|
151
|
-
These instructions apply to all files in this repository.
|
|
152
|
-
|
|
153
|
-
## Code Standards
|
|
154
|
-
|
|
155
|
-
- Use TypeScript strict mode
|
|
156
|
-
- Follow ESLint rules
|
|
157
|
-
- Write JSDoc comments for public APIs
|
|
158
|
-
|
|
159
|
-
## Patterns to Follow
|
|
160
|
-
|
|
161
|
-
- Use async/await for asynchronous operations
|
|
162
|
-
- Implement error handling with try/catch
|
|
163
|
-
- Export named functions instead of default exports
|
|
164
|
-
- Write unit tests for all new features
|
|
165
|
-
`,
|
|
166
|
-
'.github/instructions/typescript.instructions.md': `---
|
|
167
|
-
applyTo:
|
|
168
|
-
- "**/*.ts"
|
|
169
|
-
- "**/*.tsx"
|
|
170
|
-
---
|
|
171
|
-
|
|
172
|
-
# TypeScript-Specific Instructions
|
|
173
|
-
|
|
174
|
-
These instructions apply only to TypeScript files.
|
|
175
|
-
|
|
176
|
-
## Type Safety
|
|
177
|
-
|
|
178
|
-
- Use strict null checks
|
|
179
|
-
- Avoid 'any' type - use 'unknown' or specific types
|
|
180
|
-
- Define interfaces for all object shapes
|
|
181
|
-
- Use type guards for runtime type checking
|
|
182
|
-
|
|
183
|
-
## Patterns
|
|
184
|
-
|
|
185
|
-
- Prefer const over let
|
|
186
|
-
- Use template literals for string concatenation
|
|
187
|
-
- Destructure objects and arrays when appropriate
|
|
188
|
-
`,
|
|
189
|
-
'.github/chatmodes/code-reviewer.chatmode.md': `---
|
|
190
|
-
name: Code Reviewer
|
|
191
|
-
description: Expert code reviewer focusing on best practices, security, and maintainability
|
|
192
|
-
---
|
|
193
|
-
|
|
194
|
-
# Example Chat Mode
|
|
195
|
-
|
|
196
|
-
This is an example chat mode. Replace with your actual chat mode persona and instructions.
|
|
197
|
-
|
|
198
|
-
## Role
|
|
199
|
-
|
|
200
|
-
You are a [describe the role/persona].
|
|
201
|
-
|
|
202
|
-
## Capabilities
|
|
203
|
-
|
|
204
|
-
- Capability 1
|
|
205
|
-
- Capability 2
|
|
206
|
-
- Capability 3
|
|
207
|
-
|
|
208
|
-
## Guidelines
|
|
209
|
-
|
|
210
|
-
When responding:
|
|
211
|
-
1. Guideline 1
|
|
212
|
-
2. Guideline 2
|
|
213
|
-
3. Guideline 3
|
|
214
|
-
|
|
215
|
-
## Example Interactions
|
|
216
|
-
|
|
217
|
-
Provide examples of how this chat mode should respond.
|
|
218
|
-
`,
|
|
219
|
-
},
|
|
220
|
-
kiro: {
|
|
221
|
-
'.kiro/steering/example.md': `---
|
|
222
|
-
inclusion: manual
|
|
223
|
-
---
|
|
224
|
-
|
|
225
|
-
# Example Kiro Steering File
|
|
226
|
-
|
|
227
|
-
Add your Kiro steering instructions here.
|
|
228
|
-
|
|
229
|
-
## Context
|
|
230
|
-
|
|
231
|
-
Describe the context where this steering file applies.
|
|
232
|
-
|
|
233
|
-
## Guidelines
|
|
234
|
-
|
|
235
|
-
- Guideline 1
|
|
236
|
-
- Guideline 2
|
|
237
|
-
- Guideline 3
|
|
238
|
-
|
|
239
|
-
## Examples
|
|
240
|
-
|
|
241
|
-
Provide examples of correct patterns.
|
|
242
|
-
`,
|
|
243
|
-
'.kiro/hooks/example-hook.kiro.hook': `{
|
|
244
|
-
"enabled": false,
|
|
245
|
-
"name": "Example Hook",
|
|
246
|
-
"description": "Example Kiro hook - disabled by default. Replace with your actual hook logic.",
|
|
247
|
-
"version": "1",
|
|
248
|
-
"when": {
|
|
249
|
-
"type": "fileEdited",
|
|
250
|
-
"patterns": [
|
|
251
|
-
"**/*.ts",
|
|
252
|
-
"**/*.tsx"
|
|
253
|
-
]
|
|
254
|
-
},
|
|
255
|
-
"then": {
|
|
256
|
-
"type": "askAgent",
|
|
257
|
-
"prompt": "A file has been modified. Please review it for best practices:\\n1. Check for code quality issues\\n2. Verify error handling\\n3. Suggest improvements\\n4. Ensure tests are updated"
|
|
258
|
-
}
|
|
259
|
-
}`,
|
|
260
|
-
},
|
|
261
|
-
'agents.md': {
|
|
262
|
-
'agents.md': `# Project Coding Guidelines
|
|
263
|
-
|
|
264
|
-
Project-specific instructions for AI coding agents (OpenAI Codex, etc.).
|
|
265
|
-
|
|
266
|
-
## TypeScript Conventions
|
|
267
|
-
|
|
268
|
-
- Use strict mode for type safety
|
|
269
|
-
- Prefer interfaces over types for object shapes
|
|
270
|
-
- Use const assertions where appropriate
|
|
271
|
-
|
|
272
|
-
## Testing Requirements
|
|
273
|
-
|
|
274
|
-
- Write tests for all public APIs
|
|
275
|
-
- Maintain >80% code coverage
|
|
276
|
-
- Use descriptive test names
|
|
277
|
-
|
|
278
|
-
## Code Examples
|
|
279
|
-
|
|
280
|
-
### Preferred: Async/Await
|
|
281
|
-
|
|
282
|
-
\`\`\`typescript
|
|
283
|
-
async function fetchData() {
|
|
284
|
-
const response = await fetch('/api/data');
|
|
285
|
-
return response.json();
|
|
286
|
-
}
|
|
287
|
-
\`\`\`
|
|
288
|
-
|
|
289
|
-
### Avoid: Callback Hell
|
|
290
|
-
|
|
291
|
-
\`\`\`typescript
|
|
292
|
-
getData(function(data) {
|
|
293
|
-
processData(data, function(result) {
|
|
294
|
-
// Deeply nested callbacks
|
|
295
|
-
});
|
|
296
|
-
});
|
|
297
|
-
\`\`\`
|
|
298
|
-
`,
|
|
299
|
-
},
|
|
300
|
-
generic: {
|
|
301
|
-
'prompts/example.md': `# Example Prompt
|
|
302
|
-
|
|
303
|
-
This is an example generic AI prompt. Replace with your actual prompt content.
|
|
304
|
-
|
|
305
|
-
## Purpose
|
|
306
|
-
|
|
307
|
-
Describe what this prompt is meant to accomplish.
|
|
308
|
-
|
|
309
|
-
## Instructions
|
|
310
|
-
|
|
311
|
-
Provide clear instructions for the AI.
|
|
312
|
-
|
|
313
|
-
## Examples
|
|
314
|
-
|
|
315
|
-
Include examples if helpful.
|
|
316
|
-
`,
|
|
317
|
-
},
|
|
318
|
-
};
|
|
319
|
-
/**
|
|
320
|
-
* Prompt user for input with a default value
|
|
321
|
-
*/
|
|
322
|
-
async function prompt(rl, question, defaultValue) {
|
|
323
|
-
const promptText = defaultValue
|
|
324
|
-
? `${question} (${defaultValue}): `
|
|
325
|
-
: `${question}: `;
|
|
326
|
-
const answer = await rl.question(promptText);
|
|
327
|
-
return answer.trim() || defaultValue || '';
|
|
328
|
-
}
|
|
329
|
-
/**
|
|
330
|
-
* Prompt user to select from a list
|
|
331
|
-
*/
|
|
332
|
-
async function select(rl, question, options, defaultValue) {
|
|
333
|
-
console.log(`\n${question}`);
|
|
334
|
-
options.forEach((opt, idx) => {
|
|
335
|
-
const isDefault = opt === defaultValue;
|
|
336
|
-
console.log(` ${idx + 1}. ${opt}${isDefault ? ' (default)' : ''}`);
|
|
337
|
-
});
|
|
338
|
-
const answer = await rl.question('\nSelect (1-' + options.length + '): ');
|
|
339
|
-
const selection = parseInt(answer.trim(), 10);
|
|
340
|
-
if (!answer.trim() && defaultValue) {
|
|
341
|
-
return defaultValue;
|
|
342
|
-
}
|
|
343
|
-
if (selection >= 1 && selection <= options.length) {
|
|
344
|
-
return options[selection - 1];
|
|
345
|
-
}
|
|
346
|
-
console.log('Invalid selection, using default.');
|
|
347
|
-
return defaultValue || options[0];
|
|
348
|
-
}
|
|
349
|
-
/**
|
|
350
|
-
* Extract metadata from file content (YAML frontmatter or comments)
|
|
351
|
-
*/
|
|
352
|
-
async function extractMetadataFromFile(filePath) {
|
|
353
|
-
try {
|
|
354
|
-
const content = await (0, promises_1.readFile)(filePath, 'utf-8');
|
|
355
|
-
const metadata = {};
|
|
356
|
-
// Try to extract YAML frontmatter (---\nkey: value\n---)
|
|
357
|
-
const frontmatterMatch = content.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
358
|
-
if (frontmatterMatch) {
|
|
359
|
-
const frontmatter = frontmatterMatch[1];
|
|
360
|
-
// Extract description
|
|
361
|
-
const descMatch = frontmatter.match(/description:\s*(.+)/i);
|
|
362
|
-
if (descMatch) {
|
|
363
|
-
metadata.description = descMatch[1].trim().replace(/^["']|["']$/g, '');
|
|
364
|
-
}
|
|
365
|
-
// Extract name
|
|
366
|
-
const nameMatch = frontmatter.match(/name:\s*(.+)/i);
|
|
367
|
-
if (nameMatch) {
|
|
368
|
-
metadata.name = nameMatch[1].trim().replace(/^["']|["']$/g, '');
|
|
369
|
-
}
|
|
370
|
-
// Extract tags
|
|
371
|
-
const tagsMatch = frontmatter.match(/tags:\s*(.+)/i);
|
|
372
|
-
if (tagsMatch) {
|
|
373
|
-
const tagsStr = tagsMatch[1].trim();
|
|
374
|
-
// Handle both array format [tag1, tag2] and comma-separated
|
|
375
|
-
if (tagsStr.startsWith('[')) {
|
|
376
|
-
metadata.tags = tagsStr
|
|
377
|
-
.replace(/[\[\]]/g, '')
|
|
378
|
-
.split(',')
|
|
379
|
-
.map(t => t.trim().replace(/^["']|["']$/g, ''))
|
|
380
|
-
.filter(Boolean);
|
|
381
|
-
}
|
|
382
|
-
else {
|
|
383
|
-
metadata.tags = tagsStr
|
|
384
|
-
.split(',')
|
|
385
|
-
.map(t => t.trim().replace(/^["']|["']$/g, ''))
|
|
386
|
-
.filter(Boolean);
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
// If no frontmatter, try to extract from first heading or comments
|
|
391
|
-
if (!metadata.description) {
|
|
392
|
-
// Try markdown heading
|
|
393
|
-
const headingMatch = content.match(/^#\s+(.+)/m);
|
|
394
|
-
if (headingMatch) {
|
|
395
|
-
metadata.description = headingMatch[1].trim();
|
|
396
|
-
}
|
|
397
|
-
else {
|
|
398
|
-
// Try HTML/JSDoc style comment
|
|
399
|
-
const commentMatch = content.match(/\/\*\*\s*\n\s*\*\s*(.+)/);
|
|
400
|
-
if (commentMatch) {
|
|
401
|
-
metadata.description = commentMatch[1].trim();
|
|
402
|
-
}
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
return metadata;
|
|
406
|
-
}
|
|
407
|
-
catch (error) {
|
|
408
|
-
// File might not exist yet, that's okay
|
|
409
|
-
return {};
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
/**
|
|
413
|
-
* Get package name from current directory or git config
|
|
414
|
-
*/
|
|
415
|
-
function getDefaultPackageName() {
|
|
416
|
-
const cwd = process.cwd();
|
|
417
|
-
const dirName = cwd.split('/').pop() || 'my-package';
|
|
418
|
-
// Normalize to package name format
|
|
419
|
-
return dirName.toLowerCase().replace(/[^a-z0-9-]/g, '-');
|
|
420
|
-
}
|
|
421
|
-
/**
|
|
422
|
-
* Get author from git config
|
|
423
|
-
*/
|
|
424
|
-
function getDefaultAuthor() {
|
|
425
|
-
try {
|
|
426
|
-
const { execSync } = require('child_process');
|
|
427
|
-
const name = execSync('git config user.name', { encoding: 'utf-8' }).trim();
|
|
428
|
-
const email = execSync('git config user.email', { encoding: 'utf-8' }).trim();
|
|
429
|
-
if (name && email) {
|
|
430
|
-
return `${name} <${email}>`;
|
|
431
|
-
}
|
|
432
|
-
if (name) {
|
|
433
|
-
return name;
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
catch {
|
|
437
|
-
// Git not configured
|
|
438
|
-
}
|
|
439
|
-
return '';
|
|
440
|
-
}
|
|
441
|
-
/**
|
|
442
|
-
* Create example files based on format
|
|
443
|
-
*/
|
|
444
|
-
async function createExampleFiles(format, files, packageName) {
|
|
445
|
-
const templates = EXAMPLE_TEMPLATES[format] || {};
|
|
446
|
-
for (const file of files) {
|
|
447
|
-
const filePath = (0, path_1.join)(process.cwd(), file);
|
|
448
|
-
const dirPath = (0, path_1.join)(filePath, '..');
|
|
449
|
-
// Create directory if it doesn't exist
|
|
450
|
-
if (!(0, fs_1.existsSync)(dirPath)) {
|
|
451
|
-
await (0, promises_1.mkdir)(dirPath, { recursive: true });
|
|
452
|
-
}
|
|
453
|
-
// Skip if file already exists
|
|
454
|
-
if ((0, fs_1.existsSync)(filePath)) {
|
|
455
|
-
console.log(` Skipping ${file} (already exists)`);
|
|
456
|
-
continue;
|
|
457
|
-
}
|
|
458
|
-
// Use template or create empty file
|
|
459
|
-
let content = templates[file] || `# ${file}\n\nAdd your content here.\n`;
|
|
460
|
-
// Replace 'example-skill' placeholder with actual package name in template content
|
|
461
|
-
content = content.replace(/example-skill/g, packageName);
|
|
462
|
-
await (0, promises_1.writeFile)(filePath, content, 'utf-8');
|
|
463
|
-
console.log(` Created ${file}`);
|
|
464
|
-
}
|
|
465
|
-
}
|
|
466
|
-
/**
|
|
467
|
-
* Create README.md
|
|
468
|
-
*/
|
|
469
|
-
async function createReadme(config) {
|
|
470
|
-
const readmePath = (0, path_1.join)(process.cwd(), 'README.md');
|
|
471
|
-
if ((0, fs_1.existsSync)(readmePath)) {
|
|
472
|
-
console.log(' Skipping README.md (already exists)');
|
|
473
|
-
return;
|
|
474
|
-
}
|
|
475
|
-
const content = `# ${config.name}
|
|
476
|
-
|
|
477
|
-
${config.description}
|
|
478
|
-
|
|
479
|
-
## Installation
|
|
480
|
-
|
|
481
|
-
\`\`\`bash
|
|
482
|
-
prpm install ${config.name}
|
|
483
|
-
\`\`\`
|
|
484
|
-
|
|
485
|
-
## Format
|
|
486
|
-
|
|
487
|
-
${config.format}${config.subtype ? ` (${config.subtype})` : ''}
|
|
488
|
-
|
|
489
|
-
## Files
|
|
490
|
-
|
|
491
|
-
${config.files.map(f => `- ${f}`).join('\n')}
|
|
492
|
-
|
|
493
|
-
## Author
|
|
494
|
-
|
|
495
|
-
${config.author}
|
|
496
|
-
|
|
497
|
-
## License
|
|
498
|
-
|
|
499
|
-
${config.license}
|
|
500
|
-
`;
|
|
501
|
-
await (0, promises_1.writeFile)(readmePath, content, 'utf-8');
|
|
502
|
-
console.log(' Created README.md');
|
|
503
|
-
}
|
|
504
|
-
/**
|
|
505
|
-
* Initialize a new PRPM package
|
|
506
|
-
*/
|
|
507
|
-
async function initPackage(options) {
|
|
508
|
-
const manifestPath = (0, path_1.join)(process.cwd(), 'prpm.json');
|
|
509
|
-
// Check if prpm.json already exists
|
|
510
|
-
if ((0, fs_1.existsSync)(manifestPath) && !options.force) {
|
|
511
|
-
throw new Error('prpm.json already exists. Use --force to overwrite, or run this command in a different directory.');
|
|
512
|
-
}
|
|
513
|
-
const config = {};
|
|
514
|
-
// Use defaults if --yes flag
|
|
515
|
-
if (options.yes) {
|
|
516
|
-
config.name = getDefaultPackageName();
|
|
517
|
-
config.version = '1.0.0';
|
|
518
|
-
config.description = 'A PRPM package';
|
|
519
|
-
config.format = 'cursor';
|
|
520
|
-
config.subtype = 'rule';
|
|
521
|
-
config.author = getDefaultAuthor() || 'Your Name';
|
|
522
|
-
config.license = 'MIT';
|
|
523
|
-
config.tags = [];
|
|
524
|
-
// Replace 'example-skill' with actual package name in file paths
|
|
525
|
-
config.files = FORMAT_EXAMPLES.cursor.files.map(f => f.replace(/example-skill/g, config.name || 'example-skill'));
|
|
526
|
-
}
|
|
527
|
-
else {
|
|
528
|
-
// Interactive prompts
|
|
529
|
-
const rl = readline.createInterface({ input: process_1.stdin, output: process_1.stdout });
|
|
530
|
-
try {
|
|
531
|
-
console.log('\nš Welcome to PRPM package initialization!\n');
|
|
532
|
-
console.log('This utility will walk you through creating a prpm.json file.\n');
|
|
533
|
-
// Package name
|
|
534
|
-
const defaultName = getDefaultPackageName();
|
|
535
|
-
config.name = await prompt(rl, 'Package name', defaultName);
|
|
536
|
-
// Version
|
|
537
|
-
config.version = await prompt(rl, 'Version', '1.0.0');
|
|
538
|
-
// Description
|
|
539
|
-
config.description = await prompt(rl, 'Description', 'A PRPM package for AI coding assistants');
|
|
540
|
-
// Format
|
|
541
|
-
config.format = await select(rl, 'Select package format:', types_1.FORMATS, 'cursor');
|
|
542
|
-
// Subtype
|
|
543
|
-
config.subtype = await select(rl, 'Select package subtype:', types_1.SUBTYPES, 'rule');
|
|
544
|
-
// Author
|
|
545
|
-
const defaultAuthor = getDefaultAuthor();
|
|
546
|
-
config.author = await prompt(rl, 'Author', defaultAuthor || 'Your Name');
|
|
547
|
-
// License
|
|
548
|
-
config.license = await prompt(rl, 'License', 'MIT');
|
|
549
|
-
// Repository
|
|
550
|
-
const includeRepo = await prompt(rl, 'Add repository URL? (y/N)', 'n');
|
|
551
|
-
if (includeRepo.toLowerCase() === 'y') {
|
|
552
|
-
config.repository = await prompt(rl, 'Repository URL', '');
|
|
553
|
-
}
|
|
554
|
-
// Tags
|
|
555
|
-
const tagsInput = await prompt(rl, 'Tags (comma-separated)', config.format);
|
|
556
|
-
config.tags = tagsInput
|
|
557
|
-
.split(',')
|
|
558
|
-
.map(t => t.trim())
|
|
559
|
-
.filter(Boolean);
|
|
560
|
-
// Files - use examples based on format
|
|
561
|
-
const formatExamples = FORMAT_EXAMPLES[config.format];
|
|
562
|
-
// Replace 'example-skill' with actual package name in file paths
|
|
563
|
-
const exampleFiles = formatExamples.files.map(f => f.replace(/example-skill/g, config.name || 'example-skill'));
|
|
564
|
-
console.log(`\nExample files for ${config.format}:`);
|
|
565
|
-
exampleFiles.forEach((f, idx) => console.log(` ${idx + 1}. ${f}`));
|
|
566
|
-
const useExamples = await prompt(rl, '\nUse example file structure? (Y/n)', 'y');
|
|
567
|
-
if (useExamples.toLowerCase() !== 'n') {
|
|
568
|
-
config.files = exampleFiles;
|
|
569
|
-
}
|
|
570
|
-
else {
|
|
571
|
-
const filesInput = await prompt(rl, 'Files (comma-separated)', exampleFiles.join(', '));
|
|
572
|
-
config.files = filesInput
|
|
573
|
-
.split(',')
|
|
574
|
-
.map(f => f.trim())
|
|
575
|
-
.filter(Boolean);
|
|
576
|
-
}
|
|
577
|
-
// Try to extract metadata from the first file if it exists
|
|
578
|
-
if (config.files.length > 0) {
|
|
579
|
-
const firstFile = config.files[0];
|
|
580
|
-
console.log(`\nš Checking ${firstFile} for metadata...`);
|
|
581
|
-
const extractedMetadata = await extractMetadataFromFile(firstFile);
|
|
582
|
-
if (extractedMetadata.description) {
|
|
583
|
-
console.log(` Found description: "${extractedMetadata.description}"`);
|
|
584
|
-
const useExtracted = await prompt(rl, ' Use this description? (Y/n)', 'y');
|
|
585
|
-
if (useExtracted.toLowerCase() !== 'n') {
|
|
586
|
-
config.description = extractedMetadata.description;
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
if (extractedMetadata.tags && extractedMetadata.tags.length > 0) {
|
|
590
|
-
console.log(` Found tags: ${extractedMetadata.tags.join(', ')}`);
|
|
591
|
-
const useExtractedTags = await prompt(rl, ' Use these tags? (Y/n)', 'y');
|
|
592
|
-
if (useExtractedTags.toLowerCase() !== 'n') {
|
|
593
|
-
config.tags = extractedMetadata.tags;
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
if (extractedMetadata.name && !config.name.includes(extractedMetadata.name)) {
|
|
597
|
-
console.log(` Found name: "${extractedMetadata.name}"`);
|
|
598
|
-
const useExtractedName = await prompt(rl, ' Include in package name? (y/N)', 'n');
|
|
599
|
-
if (useExtractedName.toLowerCase() === 'y') {
|
|
600
|
-
config.name = `${config.name}-${extractedMetadata.name.toLowerCase().replace(/\s+/g, '-')}`;
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
// Ask if user wants to add more files
|
|
605
|
-
let addingMoreFiles = true;
|
|
606
|
-
while (addingMoreFiles) {
|
|
607
|
-
const addMore = await prompt(rl, '\nAdd more files to the package? (y/N)', 'n');
|
|
608
|
-
if (addMore.toLowerCase() === 'y') {
|
|
609
|
-
const additionalFiles = await prompt(rl, 'Additional files (comma-separated)', '');
|
|
610
|
-
const newFiles = additionalFiles
|
|
611
|
-
.split(',')
|
|
612
|
-
.map(f => f.trim())
|
|
613
|
-
.filter(Boolean);
|
|
614
|
-
if (newFiles.length > 0) {
|
|
615
|
-
config.files = [...config.files, ...newFiles];
|
|
616
|
-
console.log(`\nCurrent files (${config.files.length}):`);
|
|
617
|
-
config.files.forEach((f, idx) => console.log(` ${idx + 1}. ${f}`));
|
|
618
|
-
}
|
|
619
|
-
}
|
|
620
|
-
else {
|
|
621
|
-
addingMoreFiles = false;
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
finally {
|
|
626
|
-
rl.close();
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
// Create manifest
|
|
630
|
-
const manifest = {
|
|
631
|
-
name: config.name,
|
|
632
|
-
version: config.version,
|
|
633
|
-
description: config.description,
|
|
634
|
-
format: config.format,
|
|
635
|
-
subtype: config.subtype || 'rule', // Default to 'rule' if not specified
|
|
636
|
-
};
|
|
637
|
-
manifest.author = config.author;
|
|
638
|
-
manifest.license = config.license;
|
|
639
|
-
if (config.repository) {
|
|
640
|
-
manifest.repository = config.repository;
|
|
641
|
-
}
|
|
642
|
-
if (config.tags && config.tags.length > 0) {
|
|
643
|
-
manifest.tags = config.tags;
|
|
644
|
-
}
|
|
645
|
-
manifest.files = config.files;
|
|
646
|
-
// Write prpm.json
|
|
647
|
-
await (0, promises_1.writeFile)(manifestPath, JSON.stringify(manifest, null, 2) + '\n', 'utf-8');
|
|
648
|
-
console.log('\nā
Created prpm.json\n');
|
|
649
|
-
// Create example files
|
|
650
|
-
if (config.files && config.format && config.name) {
|
|
651
|
-
console.log('Creating example files...\n');
|
|
652
|
-
// Filter out README.md since createReadme will handle it with proper content
|
|
653
|
-
const filesToCreate = config.files.filter(f => f !== 'README.md');
|
|
654
|
-
await createExampleFiles(config.format, filesToCreate, config.name);
|
|
655
|
-
// Create README
|
|
656
|
-
await createReadme(config);
|
|
657
|
-
}
|
|
658
|
-
console.log('\n⨠Package initialized successfully!\n');
|
|
659
|
-
console.log('Next steps:');
|
|
660
|
-
console.log(' 1. Edit the generated files with your content');
|
|
661
|
-
console.log(' 2. Review and update prpm.json as needed');
|
|
662
|
-
console.log(' 3. Run `prpm publish` to publish your package\n');
|
|
663
|
-
}
|
|
664
|
-
/**
|
|
665
|
-
* Create init command
|
|
666
|
-
*/
|
|
667
|
-
function createInitCommand() {
|
|
668
|
-
const command = new commander_1.Command('init');
|
|
669
|
-
command
|
|
670
|
-
.description('Initialize a new PRPM package with interactive prompts')
|
|
671
|
-
.option('-y, --yes', 'Skip prompts and use defaults')
|
|
672
|
-
.option('--private', 'Create a private package')
|
|
673
|
-
.option('-f, --force', 'Overwrite existing prpm.json')
|
|
674
|
-
.action(async (options) => {
|
|
675
|
-
try {
|
|
676
|
-
await initPackage(options);
|
|
677
|
-
}
|
|
678
|
-
catch (error) {
|
|
679
|
-
console.error('\nā Error:', error instanceof Error ? error.message : error);
|
|
680
|
-
throw new errors_1.CLIError('\nā Error: ' + (error instanceof Error ? error.message : error), 1);
|
|
681
|
-
}
|
|
682
|
-
});
|
|
683
|
-
return command;
|
|
684
|
-
}
|