pmpt-cli 1.14.13 → 1.14.15

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.
@@ -0,0 +1,168 @@
1
+ import * as p from '@clack/prompts';
2
+ import { join, basename } from 'path';
3
+ import { existsSync, readFileSync, writeFileSync } from 'fs';
4
+ import { isInitialized, getDocsDir, getPmptDir } from '../lib/config.js';
5
+ import { getPlanProgress } from '../lib/plan.js';
6
+ import { copyToClipboard } from '../lib/clipboard.js';
7
+ export async function cmdRemix() {
8
+ const projectPath = process.cwd();
9
+ if (!isInitialized(projectPath)) {
10
+ p.log.error('Project not initialized. Run `pmpt init` or `pmpt clone <slug>` first.');
11
+ process.exit(1);
12
+ }
13
+ p.intro('pmpt remix');
14
+ const docsDir = getDocsDir(projectPath);
15
+ const aiMdPath = join(docsDir, 'pmpt.ai.md');
16
+ const planPath = join(getPmptDir(projectPath), 'plan-progress.json');
17
+ // Read original project info
18
+ const originalAiMd = existsSync(aiMdPath) ? readFileSync(aiMdPath, 'utf-8') : '';
19
+ const planProgress = getPlanProgress(projectPath);
20
+ const originalName = planProgress?.answers?.projectName || basename(projectPath);
21
+ const originalIdea = planProgress?.answers?.productIdea || '';
22
+ const originalTech = planProgress?.answers?.techStack || '';
23
+ p.note([
24
+ `Original: ${originalName}`,
25
+ originalIdea ? `Idea: ${originalIdea.slice(0, 100)}${originalIdea.length > 100 ? '...' : ''}` : '',
26
+ originalTech ? `Tech: ${originalTech}` : '',
27
+ ].filter(Boolean).join('\n'), 'Remixing From');
28
+ // Ask remix questions
29
+ const newName = await p.text({
30
+ message: 'New project name?',
31
+ placeholder: `my-${basename(projectPath)}-variant`,
32
+ validate: (v) => {
33
+ if (!v.trim())
34
+ return 'Project name is required.';
35
+ },
36
+ });
37
+ if (p.isCancel(newName)) {
38
+ p.cancel('Cancelled');
39
+ process.exit(0);
40
+ }
41
+ const twist = await p.text({
42
+ message: 'What\'s different about your version? (your key differentiation)',
43
+ placeholder: 'e.g., Web-based version, Korean market focus, B2B instead of B2C',
44
+ validate: (v) => {
45
+ if (!v.trim())
46
+ return 'Please describe your differentiation.';
47
+ },
48
+ });
49
+ if (p.isCancel(twist)) {
50
+ p.cancel('Cancelled');
51
+ process.exit(0);
52
+ }
53
+ const targetAudience = await p.text({
54
+ message: 'Target audience or context? (optional)',
55
+ placeholder: 'e.g., Small business owners, Students, Enterprise teams',
56
+ });
57
+ if (p.isCancel(targetAudience)) {
58
+ p.cancel('Cancelled');
59
+ process.exit(0);
60
+ }
61
+ const techOverride = await p.text({
62
+ message: 'Tech stack? (leave blank to keep original)',
63
+ placeholder: originalTech || 'e.g., Next.js, Supabase, Vercel',
64
+ });
65
+ if (p.isCancel(techOverride)) {
66
+ p.cancel('Cancelled');
67
+ process.exit(0);
68
+ }
69
+ const techStack = (typeof techOverride === 'string' && techOverride.trim())
70
+ ? techOverride.trim()
71
+ : originalTech;
72
+ // Generate remixed pmpt.ai.md
73
+ const contextSection = (typeof targetAudience === 'string' && targetAudience.trim())
74
+ ? `\n## Target Audience\n${targetAudience.trim()}\n`
75
+ : '';
76
+ const techSection = techStack
77
+ ? `\n## Tech Stack\n${techStack}\n`
78
+ : '';
79
+ const remixedPrompt = `<!-- This file is for AI tools only. Do not edit manually. -->
80
+ <!-- Paste this into Claude Code, Codex, Cursor, or any AI coding tool. -->
81
+
82
+ # ${newName.trim()} — Remix
83
+
84
+ ## My Version
85
+ ${twist.trim()}
86
+ ${contextSection}${techSection}
87
+ ---
88
+
89
+ ## Instructions for AI
90
+
91
+ This is a **remix** of an existing project. Build my version based on the differentiation above.
92
+
93
+ 1. Read the original project below to understand the structure and approach.
94
+ 2. Build MY version — same core concept, but with my differentiation applied throughout.
95
+ 3. Do NOT copy content verbatim. Adapt everything to fit my context.
96
+ 4. Start with core features first, then iterate.
97
+
98
+ ### Documentation Rule
99
+
100
+ When you make progress, update \`.pmpt/docs/pmpt.md\`:
101
+ - When architecture or tech decisions are finalized
102
+ - When a feature is implemented (mark as done)
103
+ - When a development phase is completed
104
+
105
+ Keep the Snapshot Log up to date. Run \`pmpt save\` after milestones.
106
+
107
+ ---
108
+
109
+ ## Original Project Reference
110
+
111
+ ${originalAiMd}
112
+ `;
113
+ writeFileSync(aiMdPath, remixedPrompt, 'utf-8');
114
+ // Update pmpt.md project name if exists
115
+ const pmptMdPath = join(docsDir, 'pmpt.md');
116
+ if (existsSync(pmptMdPath)) {
117
+ let content = readFileSync(pmptMdPath, 'utf-8');
118
+ // Replace first heading
119
+ content = content.replace(/^# .+$/m, `# ${newName.trim()}`);
120
+ writeFileSync(pmptMdPath, content, 'utf-8');
121
+ }
122
+ // Update plan-progress.json
123
+ if (existsSync(planPath)) {
124
+ try {
125
+ const plan = JSON.parse(readFileSync(planPath, 'utf-8'));
126
+ plan.answers = {
127
+ ...plan.answers,
128
+ projectName: newName.trim(),
129
+ productIdea: `${originalIdea}\n\nMy differentiation: ${twist.trim()}`,
130
+ techStack,
131
+ };
132
+ writeFileSync(planPath, JSON.stringify(plan, null, 2), 'utf-8');
133
+ }
134
+ catch { /* ignore */ }
135
+ }
136
+ // Copy to clipboard
137
+ const copied = copyToClipboard(remixedPrompt);
138
+ p.log.success(`Remix prompt generated for "${newName.trim()}"`);
139
+ p.log.message('');
140
+ p.log.info('Next steps:');
141
+ p.log.message(' 1. Paste the prompt into your AI tool');
142
+ p.log.message(' 2. Build your version');
143
+ p.log.message(' 3. pmpt save — save your progress');
144
+ p.log.message(' 4. pmpt publish — share your remix');
145
+ p.log.message('');
146
+ if (copied) {
147
+ const banner = [
148
+ '┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓',
149
+ '┃ ┃',
150
+ '┃ 📋 NEXT STEP ┃',
151
+ '┃ ┃',
152
+ '┃ Remix prompt copied to clipboard! ┃',
153
+ '┃ Open your AI coding tool and paste it: ┃',
154
+ '┃ ┃',
155
+ '┃ ⌘ + V (Mac) ┃',
156
+ '┃ Ctrl + V (Windows/Linux) ┃',
157
+ '┃ ┃',
158
+ '┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛',
159
+ '',
160
+ ];
161
+ console.log(banner.join('\n'));
162
+ }
163
+ else {
164
+ p.log.warn('Could not copy to clipboard.');
165
+ p.log.info(`Read it at: ${aiMdPath}`);
166
+ }
167
+ p.outro('Ready to remix!');
168
+ }
@@ -51,7 +51,7 @@ export async function cmdSave(fileOrPath) {
51
51
  p.cancel('Save cancelled.');
52
52
  process.exit(0);
53
53
  }
54
- const note = summary.trim() || undefined;
54
+ const note = typeof summary === 'string' ? summary.trim() || undefined : undefined;
55
55
  // Write summary to pmpt.md Snapshot Log before snapshot
56
56
  if (note) {
57
57
  const pmptMdPath = join(docsDir, 'pmpt.md');
package/dist/index.js CHANGED
@@ -39,6 +39,7 @@ import { cmdEdit } from './commands/edit.js';
39
39
  import { cmdUnpublish } from './commands/unpublish.js';
40
40
  import { cmdGraduate } from './commands/graduate.js';
41
41
  import { cmdClone } from './commands/clone.js';
42
+ import { cmdRemix } from './commands/remix.js';
42
43
  import { cmdExplore } from './commands/browse.js';
43
44
  import { cmdRecover } from './commands/recover.js';
44
45
  import { cmdDiff } from './commands/diff.js';
@@ -196,6 +197,10 @@ program
196
197
  .command('clone <slug>')
197
198
  .description('Clone a project from pmptwiki platform')
198
199
  .action(cmdClone);
200
+ program
201
+ .command('remix')
202
+ .description('Remix a cloned project — customize it with your own twist')
203
+ .action(cmdRemix);
199
204
  program
200
205
  .command('explore')
201
206
  .alias('exp')
package/dist/mcp.js CHANGED
@@ -123,6 +123,10 @@ server.tool('pmpt_save', 'Save a snapshot of .pmpt/docs/ files. Call after compl
123
123
  '',
124
124
  '## Decisions',
125
125
  '',
126
+ '## Constraints',
127
+ '',
128
+ '## Lessons',
129
+ '',
126
130
  ].join('\n');
127
131
  writeFileSync(pmptMdPath, skeleton, 'utf-8');
128
132
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmpt-cli",
3
- "version": "1.14.13",
3
+ "version": "1.14.15",
4
4
  "description": "Record and share your AI-driven product development journey",
5
5
  "type": "module",
6
6
  "bin": {