pmpt-cli 1.1.0 → 1.2.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.
@@ -0,0 +1,206 @@
1
+ import * as p from '@clack/prompts';
2
+ import { resolve, join, basename } from 'path';
3
+ import { existsSync, writeFileSync, statSync } from 'fs';
4
+ import { execSync } from 'child_process';
5
+ import { isInitialized, getConfigDir, getHistoryDir, loadConfig } from '../lib/config.js';
6
+ import { getAllSnapshots } from '../lib/history.js';
7
+ import { getPlanProgress } from '../lib/plan.js';
8
+ /**
9
+ * Create a zip file without external dependencies
10
+ * Uses native zip command on macOS/Linux, PowerShell on Windows
11
+ */
12
+ function createZip(sourceDir, outputPath) {
13
+ try {
14
+ const platform = process.platform;
15
+ if (platform === 'win32') {
16
+ // PowerShell Compress-Archive
17
+ execSync(`powershell -command "Compress-Archive -Path '${sourceDir}/*' -DestinationPath '${outputPath}'"`, {
18
+ stdio: 'pipe',
19
+ });
20
+ }
21
+ else {
22
+ // Unix zip command
23
+ execSync(`cd "${sourceDir}" && zip -r "${outputPath}" .`, {
24
+ stdio: 'pipe',
25
+ });
26
+ }
27
+ return true;
28
+ }
29
+ catch {
30
+ return false;
31
+ }
32
+ }
33
+ /**
34
+ * Generate metadata markdown file
35
+ */
36
+ function generateMetadataMarkdown(projectPath, snapshots, planProgress, config) {
37
+ const answers = planProgress?.answers || {};
38
+ const projectName = answers.projectName || basename(projectPath);
39
+ // Timeline info
40
+ const firstSnapshot = snapshots[0];
41
+ const lastSnapshot = snapshots[snapshots.length - 1];
42
+ const startDate = firstSnapshot?.timestamp || 'N/A';
43
+ const lastDate = lastSnapshot?.timestamp || 'N/A';
44
+ // Git info from last snapshot
45
+ const gitInfo = lastSnapshot?.git;
46
+ // All unique files across snapshots
47
+ const allFiles = new Set();
48
+ for (const snapshot of snapshots) {
49
+ for (const file of snapshot.files) {
50
+ allFiles.add(file);
51
+ }
52
+ }
53
+ // Parse features
54
+ const features = answers.coreFeatures
55
+ ? answers.coreFeatures
56
+ .split(/[,;\n]/)
57
+ .map((f) => f.trim())
58
+ .filter((f) => f)
59
+ .map((f) => `- ${f}`)
60
+ .join('\n')
61
+ : 'Not specified';
62
+ let md = `# ${projectName}
63
+
64
+ > Exported from pmpt-cli
65
+
66
+ ## Project Overview
67
+
68
+ **Product Idea:**
69
+ ${answers.productIdea || 'Not specified'}
70
+
71
+ ${answers.additionalContext ? `**Additional Context:**\n${answers.additionalContext}\n` : ''}
72
+ **Key Features:**
73
+ ${features}
74
+
75
+ **Tech Stack:**
76
+ ${answers.techStack || 'Not specified'}
77
+
78
+ ---
79
+
80
+ ## Export Information
81
+
82
+ | Item | Value |
83
+ |------|-------|
84
+ | Total Iterations | ${snapshots.length} |
85
+ | First Version | ${startDate} |
86
+ | Last Version | ${lastDate} |
87
+ | Files Tracked | ${allFiles.size} |
88
+ `;
89
+ if (gitInfo) {
90
+ md += `| Git Branch | ${gitInfo.branch} |
91
+ | Last Commit | ${gitInfo.commit} |
92
+ `;
93
+ }
94
+ md += `
95
+ ---
96
+
97
+ ## Version Timeline
98
+
99
+ | Version | Date | Files | Git |
100
+ |---------|------|-------|-----|
101
+ `;
102
+ for (const snapshot of snapshots) {
103
+ const gitCol = snapshot.git
104
+ ? `${snapshot.git.commit}${snapshot.git.dirty ? ' (dirty)' : ''}`
105
+ : '-';
106
+ md += `| v${snapshot.version} | ${snapshot.timestamp} | ${snapshot.files.length} | ${gitCol} |\n`;
107
+ }
108
+ md += `
109
+ ---
110
+
111
+ ## File List
112
+
113
+ `;
114
+ for (const file of Array.from(allFiles).sort()) {
115
+ md += `- ${file}\n`;
116
+ }
117
+ md += `
118
+ ---
119
+
120
+ *Generated by [pmpt-cli](https://pmptwiki.com)*
121
+ `;
122
+ return md;
123
+ }
124
+ export async function cmdExport(path, options) {
125
+ const projectPath = path ? resolve(path) : process.cwd();
126
+ if (!isInitialized(projectPath)) {
127
+ p.log.error('Project not initialized. Run `pmpt init` first.');
128
+ process.exit(1);
129
+ }
130
+ p.intro('pmpt export');
131
+ const config = loadConfig(projectPath);
132
+ const snapshots = getAllSnapshots(projectPath);
133
+ const planProgress = getPlanProgress(projectPath);
134
+ if (snapshots.length === 0) {
135
+ p.log.warn('No snapshots found.');
136
+ p.log.info('Run `pmpt save` or `pmpt plan` first to create versions.');
137
+ p.outro('');
138
+ return;
139
+ }
140
+ const projectName = planProgress?.answers?.projectName || basename(projectPath);
141
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 10);
142
+ const exportName = `pmpt-export-${projectName}-${timestamp}`;
143
+ // Output path
144
+ const outputPath = options?.output
145
+ ? resolve(options.output)
146
+ : resolve(projectPath, `${exportName}.zip`);
147
+ const s = p.spinner();
148
+ s.start('Preparing export...');
149
+ // Create temp directory for export
150
+ const tempDir = join(projectPath, '.pmpt', '.export-temp');
151
+ execSync(`rm -rf "${tempDir}" && mkdir -p "${tempDir}"`, { stdio: 'pipe' });
152
+ // Copy history folder
153
+ const historyDir = getHistoryDir(projectPath);
154
+ execSync(`cp -r "${historyDir}" "${tempDir}/history"`, { stdio: 'pipe' });
155
+ // Generate and save metadata
156
+ const metadataContent = generateMetadataMarkdown(projectPath, snapshots, planProgress, config);
157
+ writeFileSync(join(tempDir, 'README.md'), metadataContent, 'utf-8');
158
+ // Copy current docs if exists
159
+ const docsDir = join(getConfigDir(projectPath), 'docs');
160
+ if (existsSync(docsDir)) {
161
+ execSync(`cp -r "${docsDir}" "${tempDir}/docs"`, { stdio: 'pipe' });
162
+ }
163
+ // Copy config (without sensitive data)
164
+ if (config) {
165
+ const exportConfig = {
166
+ projectPath: basename(projectPath),
167
+ docsPath: config.docsPath,
168
+ createdAt: config.createdAt,
169
+ trackGit: config.trackGit,
170
+ };
171
+ writeFileSync(join(tempDir, 'config.json'), JSON.stringify(exportConfig, null, 2), 'utf-8');
172
+ }
173
+ // Copy plan progress if exists
174
+ if (planProgress) {
175
+ writeFileSync(join(tempDir, 'plan.json'), JSON.stringify(planProgress, null, 2), 'utf-8');
176
+ }
177
+ s.message('Creating archive...');
178
+ // Create zip
179
+ const zipSuccess = createZip(tempDir, outputPath);
180
+ // Cleanup temp directory
181
+ execSync(`rm -rf "${tempDir}"`, { stdio: 'pipe' });
182
+ if (!zipSuccess) {
183
+ s.stop('Export failed');
184
+ p.log.error('Failed to create zip archive.');
185
+ p.log.info('Make sure `zip` command is available on your system.');
186
+ process.exit(1);
187
+ }
188
+ s.stop('Export complete!');
189
+ // Summary
190
+ const fileSizeBytes = statSync(outputPath).size;
191
+ const fileSize = fileSizeBytes < 1024
192
+ ? `${fileSizeBytes} B`
193
+ : fileSizeBytes < 1024 * 1024
194
+ ? `${(fileSizeBytes / 1024).toFixed(1)} KB`
195
+ : `${(fileSizeBytes / 1024 / 1024).toFixed(1)} MB`;
196
+ const summary = [
197
+ `Project: ${projectName}`,
198
+ `Versions: ${snapshots.length}`,
199
+ `Size: ${fileSize}`,
200
+ '',
201
+ `Output: ${outputPath}`,
202
+ ];
203
+ p.note(summary.join('\n'), 'Export Summary');
204
+ p.log.info('Share this file to let others reproduce your AI development journey!');
205
+ p.outro('');
206
+ }
@@ -86,8 +86,24 @@ export async function cmdPlan(path, options) {
86
86
  if (copied) {
87
87
  p.log.success('AI prompt copied to clipboard!');
88
88
  p.log.message('');
89
- p.log.step('Now open Claude, ChatGPT, or Codex and press Ctrl+V (Cmd+V on Mac)');
90
- p.log.message('Your product journey starts now!');
89
+ // Eye-catching next step banner
90
+ const banner = [
91
+ '',
92
+ '┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓',
93
+ '┃ ┃',
94
+ '┃ 📋 NEXT STEP ┃',
95
+ '┃ ┃',
96
+ '┃ Open your AI coding tool and press: ┃',
97
+ '┃ ┃',
98
+ '┃ ⌘ + V (Mac) ┃',
99
+ '┃ Ctrl + V (Windows/Linux) ┃',
100
+ '┃ ┃',
101
+ '┃ Your product journey starts now! 🚀 ┃',
102
+ '┃ ┃',
103
+ '┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛',
104
+ '',
105
+ ];
106
+ console.log(banner.join('\n'));
91
107
  }
92
108
  else {
93
109
  p.log.warn('Could not copy to clipboard. Showing content instead:');
@@ -182,9 +198,24 @@ export async function cmdPlan(path, options) {
182
198
  p.log.message('');
183
199
  p.log.success('AI prompt copied to clipboard!');
184
200
  p.log.message('');
185
- p.log.step('Open Claude, ChatGPT, or Codex and press Ctrl+V (Cmd+V on Mac)');
186
- p.log.message('Your product journey starts now!');
187
- p.log.message('');
201
+ // Eye-catching next step banner
202
+ const banner = [
203
+ '',
204
+ '┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓',
205
+ '┃ ┃',
206
+ '┃ 📋 NEXT STEP ┃',
207
+ '┃ ┃',
208
+ '┃ Open your AI coding tool and press: ┃',
209
+ '┃ ┃',
210
+ '┃ ⌘ + V (Mac) ┃',
211
+ '┃ Ctrl + V (Windows/Linux) ┃',
212
+ '┃ ┃',
213
+ '┃ Your product journey starts now! 🚀 ┃',
214
+ '┃ ┃',
215
+ '┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛',
216
+ '',
217
+ ];
218
+ console.log(banner.join('\n'));
188
219
  }
189
220
  else {
190
221
  // Fallback: show prompt
package/dist/index.js CHANGED
@@ -10,6 +10,7 @@ import { cmdWatch } from './commands/watch.js';
10
10
  import { cmdPlan } from './commands/plan.js';
11
11
  import { cmdSave } from './commands/save.js';
12
12
  import { cmdSquash } from './commands/squash.js';
13
+ import { cmdExport } from './commands/export.js';
13
14
  const program = new Command();
14
15
  program
15
16
  .name('pmpt')
@@ -18,12 +19,13 @@ program
18
19
  .addHelpText('after', `
19
20
  Examples:
20
21
  $ pmpt init Initialize project
21
- $ pmpt plan Start product planning (6 questions → AI prompt)
22
+ $ pmpt plan Start product planning (5 questions → AI prompt)
22
23
  $ pmpt save Save snapshot of docs folder
23
24
  $ pmpt watch Auto-detect file changes
24
25
  $ pmpt history View version history
25
26
  $ pmpt history --compact Hide minor changes
26
27
  $ pmpt squash v2 v5 Merge versions v2-v5 into v2
28
+ $ pmpt export Export history as shareable zip
27
29
 
28
30
  Folder structure:
29
31
  .pmpt/
@@ -60,9 +62,14 @@ program
60
62
  .command('squash <from> <to> [path]')
61
63
  .description('Squash multiple versions into one (e.g., pmpt squash v2 v5)')
62
64
  .action(cmdSquash);
65
+ program
66
+ .command('export [path]')
67
+ .description('Export project history as a shareable zip archive')
68
+ .option('-o, --output <file>', 'Output file path')
69
+ .action(cmdExport);
63
70
  program
64
71
  .command('plan [path]')
65
- .description('Quick product planning with 6 questions — auto-generate AI prompt')
72
+ .description('Quick product planning with 5 questions — auto-generate AI prompt')
66
73
  .option('--reset', 'Restart plan from scratch')
67
74
  .action(cmdPlan);
68
75
  // Contribution commands
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmpt-cli",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Record and share your AI-driven product development journey",
5
5
  "type": "module",
6
6
  "bin": {