pmpt-cli 1.8.3 → 1.9.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.
- package/dist/commands/clone.js +41 -1
- package/dist/commands/diff.js +11 -4
- package/dist/commands/plan.js +13 -3
- package/dist/commands/publish.js +9 -9
- package/dist/commands/recover.js +30 -23
- package/dist/commands/status.js +3 -3
- package/dist/lib/plan.js +45 -20
- package/dist/lib/pmptFile.js +5 -2
- package/dist/lib/quality.js +8 -8
- package/package.json +1 -1
package/dist/commands/clone.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as p from '@clack/prompts';
|
|
2
2
|
import { join, dirname, resolve, sep } from 'path';
|
|
3
|
-
import { existsSync, mkdirSync, writeFileSync, readdirSync } from 'fs';
|
|
3
|
+
import { existsSync, mkdirSync, writeFileSync, readFileSync, readdirSync } from 'fs';
|
|
4
4
|
import { isInitialized, getConfigDir, getHistoryDir, getDocsDir, initializeProject } from '../lib/config.js';
|
|
5
5
|
import { validatePmptFile, isSafeFilename } from '../lib/pmptFile.js';
|
|
6
6
|
import { fetchPmptFile, trackClone } from '../lib/api.js';
|
|
@@ -110,6 +110,46 @@ export async function cmdClone(slug) {
|
|
|
110
110
|
if (pmptData.docs) {
|
|
111
111
|
restoreDocs(docsDir, pmptData.docs);
|
|
112
112
|
}
|
|
113
|
+
// Write AI-facing clone guide to pmpt.ai.md
|
|
114
|
+
const author = pmptData.meta.author || 'unknown';
|
|
115
|
+
const projectName = pmptData.meta.projectName;
|
|
116
|
+
const cloneVersionCount = pmptData.history.length;
|
|
117
|
+
const versionGuide = pmptData.history.map((v) => {
|
|
118
|
+
const summary = v.summary || Object.keys(v.files).join(', ');
|
|
119
|
+
return `- v${v.version}: ${summary}`;
|
|
120
|
+
}).join('\n');
|
|
121
|
+
// Read original pmpt.ai.md if it exists (from the cloned project)
|
|
122
|
+
const aiMdPath = join(docsDir, 'pmpt.ai.md');
|
|
123
|
+
const originalAiMd = existsSync(aiMdPath) ? readFileSync(aiMdPath, 'utf-8') : '';
|
|
124
|
+
const cloneGuide = [
|
|
125
|
+
`<!-- This file is for AI tools only. Do not edit manually. -->`,
|
|
126
|
+
`<!-- Paste this into Claude Code, Codex, Cursor, or any AI coding tool. -->`,
|
|
127
|
+
'',
|
|
128
|
+
`# Cloned Project — Fresh Start`,
|
|
129
|
+
'',
|
|
130
|
+
`This project was cloned from **@${author}**'s project **"${projectName}"**.`,
|
|
131
|
+
`The original AI prompt below is for **reference only**. Do not execute it as-is.`,
|
|
132
|
+
'',
|
|
133
|
+
`## Context`,
|
|
134
|
+
'',
|
|
135
|
+
`- This is a new project. Use the original as inspiration, but build an independent product.`,
|
|
136
|
+
`- If the original prompt below contains checkboxes, those reflect the **original author's progress**, not this project's. Everything here starts from scratch.`,
|
|
137
|
+
`- The original evolved over ${cloneVersionCount} versions:`,
|
|
138
|
+
versionGuide,
|
|
139
|
+
'',
|
|
140
|
+
`## Instructions for AI`,
|
|
141
|
+
'',
|
|
142
|
+
`1. Read the original prompt below to understand the project's structure and approach.`,
|
|
143
|
+
`2. Reference the version history (v1→v${cloneVersionCount}) to follow a similar step-by-step evolution pattern.`,
|
|
144
|
+
`3. Start with core features (like v1) and incrementally add functionality.`,
|
|
145
|
+
`4. Write new pmpt.md and pmpt.ai.md for this project. Do not copy the original content verbatim.`,
|
|
146
|
+
`5. Update pmpt.md (human-facing) with progress tracking.`,
|
|
147
|
+
'',
|
|
148
|
+
'---',
|
|
149
|
+
'',
|
|
150
|
+
originalAiMd,
|
|
151
|
+
].join('\n');
|
|
152
|
+
writeFileSync(aiMdPath, cloneGuide, 'utf-8');
|
|
113
153
|
if (pmptData.plan) {
|
|
114
154
|
writeFileSync(join(pmptDir, 'plan-progress.json'), JSON.stringify({
|
|
115
155
|
completed: true,
|
package/dist/commands/diff.js
CHANGED
|
@@ -74,16 +74,23 @@ function printSummary(diffs) {
|
|
|
74
74
|
p.log.info(`${pc.green(`+${additions}`)} additions, ${pc.red(`-${deletions}`)} deletions`);
|
|
75
75
|
}
|
|
76
76
|
export function cmdDiff(v1, v2, pathOrOptions, maybeOptions) {
|
|
77
|
-
// Commander passes args
|
|
78
|
-
//
|
|
79
|
-
// pmpt diff v1 v2 → (v1, v2, options)
|
|
80
|
-
// pmpt diff v1 v2 /path → (v1, v2, path, options)
|
|
77
|
+
// Commander passes args in order: pmpt diff v1 [v2] [path] [options]
|
|
78
|
+
// Smart parsing: if v2 looks like a path (not a version pattern), treat it as path.
|
|
81
79
|
let v2Str;
|
|
82
80
|
let path;
|
|
83
81
|
let options = {};
|
|
82
|
+
const isVersion = (s) => /^v?\d+$/.test(s);
|
|
84
83
|
if (typeof v2 === 'object') {
|
|
84
|
+
// pmpt diff v1 --file x → (v1, options)
|
|
85
85
|
options = v2;
|
|
86
86
|
}
|
|
87
|
+
else if (v2 !== undefined && !isVersion(v2)) {
|
|
88
|
+
// pmpt diff v1 /some/path → v2 is actually a path
|
|
89
|
+
path = v2;
|
|
90
|
+
if (typeof pathOrOptions === 'object') {
|
|
91
|
+
options = pathOrOptions;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
87
94
|
else {
|
|
88
95
|
v2Str = v2;
|
|
89
96
|
if (typeof pathOrOptions === 'object') {
|
package/dist/commands/plan.js
CHANGED
|
@@ -52,7 +52,11 @@ export async function cmdPlan(path, options) {
|
|
|
52
52
|
const { existsSync } = await import('fs');
|
|
53
53
|
const { join } = await import('path');
|
|
54
54
|
const pmptDir = getPmptDir(projectPath);
|
|
55
|
-
|
|
55
|
+
// Prefer pmpt.ai.md, fall back to pmpt.md for older projects
|
|
56
|
+
let promptPath = join(pmptDir, 'pmpt.ai.md');
|
|
57
|
+
if (!existsSync(promptPath)) {
|
|
58
|
+
promptPath = join(pmptDir, 'pmpt.md');
|
|
59
|
+
}
|
|
56
60
|
try {
|
|
57
61
|
if (existsSync(promptPath)) {
|
|
58
62
|
const content = readFileSync(promptPath, 'utf-8');
|
|
@@ -153,16 +157,22 @@ export async function cmdPlan(path, options) {
|
|
|
153
157
|
p.log.message('');
|
|
154
158
|
p.log.success('Two documents have been created:');
|
|
155
159
|
p.log.message('');
|
|
160
|
+
const pmptMdPath = promptPath.replace('pmpt.ai.md', 'pmpt.md');
|
|
156
161
|
const docExplanation = [
|
|
157
162
|
`1. plan.md — Your product overview`,
|
|
158
163
|
` • Features checklist to track progress`,
|
|
159
164
|
` • Reference for you`,
|
|
160
165
|
` Location: ${planPath}`,
|
|
161
166
|
'',
|
|
162
|
-
`2. pmpt.md —
|
|
167
|
+
`2. pmpt.md — Your project document`,
|
|
168
|
+
` • Track progress, decisions, and milestones`,
|
|
169
|
+
` • Human-readable — write in any language`,
|
|
170
|
+
` Location: ${pmptMdPath}`,
|
|
171
|
+
'',
|
|
172
|
+
`3. pmpt.ai.md — AI prompt (THE IMPORTANT ONE!)`,
|
|
163
173
|
` • Copy this to Claude Code / Codex / Cursor`,
|
|
164
174
|
` • AI will help you build step by step`,
|
|
165
|
-
` •
|
|
175
|
+
` • Always in English for best AI performance`,
|
|
166
176
|
` Location: ${promptPath}`,
|
|
167
177
|
];
|
|
168
178
|
p.note(docExplanation.join('\n'), 'What are these files?');
|
package/dist/commands/publish.js
CHANGED
|
@@ -44,23 +44,23 @@ export async function cmdPublish(path, options) {
|
|
|
44
44
|
p.outro('');
|
|
45
45
|
return;
|
|
46
46
|
}
|
|
47
|
-
// Validate pmpt.md exists and has content
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
47
|
+
// Validate pmpt.ai.md exists and has content
|
|
48
|
+
const docsDir = getDocsDir(projectPath);
|
|
49
|
+
const aiMdPath = join(docsDir, 'pmpt.ai.md');
|
|
50
|
+
if (!existsSync(aiMdPath)) {
|
|
51
|
+
p.log.error('pmpt.ai.md not found. Run `pmpt plan` to generate it first.');
|
|
51
52
|
process.exit(1);
|
|
52
53
|
}
|
|
53
|
-
const
|
|
54
|
-
if (
|
|
55
|
-
p.log.error('pmpt.md is empty. Run `pmpt plan` to generate content.');
|
|
54
|
+
const aiMdContent = readFileSync(aiMdPath, 'utf-8').trim();
|
|
55
|
+
if (aiMdContent.length === 0) {
|
|
56
|
+
p.log.error('pmpt.ai.md is empty. Run `pmpt plan` to generate content.');
|
|
56
57
|
process.exit(1);
|
|
57
58
|
}
|
|
58
59
|
// Quality gate
|
|
59
|
-
const docsDir = getDocsDir(projectPath);
|
|
60
60
|
const trackedFiles = glob.sync('**/*.md', { cwd: docsDir });
|
|
61
61
|
const hasGit = snapshots.some(s => !!s.git);
|
|
62
62
|
const quality = computeQuality({
|
|
63
|
-
|
|
63
|
+
pmptAiMd: aiMdContent,
|
|
64
64
|
planAnswers: planProgress?.answers ?? null,
|
|
65
65
|
versionCount: snapshots.length,
|
|
66
66
|
docFiles: trackedFiles,
|
package/dist/commands/recover.js
CHANGED
|
@@ -14,14 +14,14 @@ export async function cmdRecover(path) {
|
|
|
14
14
|
}
|
|
15
15
|
p.intro('pmpt recover');
|
|
16
16
|
const docsDir = getDocsDir(projectPath);
|
|
17
|
-
const
|
|
17
|
+
const aiMdPath = join(docsDir, 'pmpt.ai.md');
|
|
18
18
|
const planMdPath = join(docsDir, 'plan.md');
|
|
19
19
|
// Check current state
|
|
20
|
-
const currentExists = existsSync(
|
|
21
|
-
const currentContent = currentExists ? readFileSync(
|
|
20
|
+
const currentExists = existsSync(aiMdPath);
|
|
21
|
+
const currentContent = currentExists ? readFileSync(aiMdPath, 'utf-8').trim() : '';
|
|
22
22
|
if (currentExists && currentContent.length > 100) {
|
|
23
23
|
const proceed = await p.confirm({
|
|
24
|
-
message: `pmpt.md exists (${currentContent.length} chars). Overwrite with recovered version?`,
|
|
24
|
+
message: `pmpt.ai.md exists (${currentContent.length} chars). Overwrite with recovered version?`,
|
|
25
25
|
initialValue: false,
|
|
26
26
|
});
|
|
27
27
|
if (p.isCancel(proceed) || !proceed) {
|
|
@@ -59,24 +59,28 @@ export async function cmdRecover(path) {
|
|
|
59
59
|
context.push('');
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
|
-
// 3. Last known good pmpt.md from history
|
|
62
|
+
// 3. Last known good pmpt.ai.md from history
|
|
63
63
|
const snapshots = getAllSnapshots(projectPath);
|
|
64
|
-
let
|
|
65
|
-
let
|
|
64
|
+
let lastAiMd = null;
|
|
65
|
+
let lastAiMdVersion = 0;
|
|
66
66
|
if (snapshots.length > 0) {
|
|
67
67
|
for (let i = snapshots.length - 1; i >= 0; i--) {
|
|
68
|
-
|
|
68
|
+
// Try pmpt.ai.md first, fall back to pmpt.md for older projects
|
|
69
|
+
let content = resolveFileContent(snapshots, i, 'pmpt.ai.md');
|
|
70
|
+
if (!content || content.trim().length <= 50) {
|
|
71
|
+
content = resolveFileContent(snapshots, i, 'pmpt.md');
|
|
72
|
+
}
|
|
69
73
|
if (content && content.trim().length > 50) {
|
|
70
|
-
|
|
71
|
-
|
|
74
|
+
lastAiMd = content;
|
|
75
|
+
lastAiMdVersion = snapshots[i].version;
|
|
72
76
|
break;
|
|
73
77
|
}
|
|
74
78
|
}
|
|
75
79
|
}
|
|
76
|
-
if (
|
|
77
|
-
context.push(`## Last Known
|
|
80
|
+
if (lastAiMd) {
|
|
81
|
+
context.push(`## Last Known AI Prompt (from v${lastAiMdVersion})`);
|
|
78
82
|
context.push('```markdown');
|
|
79
|
-
context.push(
|
|
83
|
+
context.push(lastAiMd);
|
|
80
84
|
context.push('```');
|
|
81
85
|
context.push('');
|
|
82
86
|
}
|
|
@@ -119,18 +123,18 @@ export async function cmdRecover(path) {
|
|
|
119
123
|
sources.push('plan answers');
|
|
120
124
|
if (existsSync(planMdPath))
|
|
121
125
|
sources.push('plan.md');
|
|
122
|
-
if (
|
|
123
|
-
sources.push(`history v${
|
|
126
|
+
if (lastAiMd)
|
|
127
|
+
sources.push(`history v${lastAiMdVersion}`);
|
|
124
128
|
if (existsSync(pkgPath))
|
|
125
129
|
sources.push('package.json');
|
|
126
130
|
p.log.info(`Found context: ${sources.join(', ')}`);
|
|
127
131
|
// Build recovery prompt
|
|
128
132
|
const projectName = planProgress?.answers?.projectName || basename(projectPath);
|
|
129
|
-
const prompt = `# pmpt.md Recovery Request
|
|
133
|
+
const prompt = `# pmpt.ai.md Recovery Request
|
|
130
134
|
|
|
131
|
-
I need you to regenerate the \`.pmpt/docs/pmpt.md\` file for my project "${projectName}".
|
|
135
|
+
I need you to regenerate the \`.pmpt/docs/pmpt.ai.md\` file for my project "${projectName}".
|
|
132
136
|
|
|
133
|
-
This file is the
|
|
137
|
+
This file is the AI instruction document — it contains the product development context that gets pasted into AI tools (Claude Code, Codex, Cursor, etc.) to continue development. It is separate from \`pmpt.md\` which is the human-facing project document.
|
|
134
138
|
|
|
135
139
|
## Available Context
|
|
136
140
|
|
|
@@ -138,9 +142,12 @@ ${context.join('\n')}
|
|
|
138
142
|
|
|
139
143
|
## Instructions
|
|
140
144
|
|
|
141
|
-
Based on the context above, regenerate \`.pmpt/docs/pmpt.md\` with the following structure:
|
|
145
|
+
Based on the context above, regenerate \`.pmpt/docs/pmpt.ai.md\` with the following structure:
|
|
142
146
|
|
|
143
147
|
\`\`\`
|
|
148
|
+
<!-- This file is for AI tools only. Do not edit manually. -->
|
|
149
|
+
<!-- Paste this into Claude Code, Codex, Cursor, or any AI coding tool. -->
|
|
150
|
+
|
|
144
151
|
# {Project Name} — Product Development Request
|
|
145
152
|
|
|
146
153
|
## What I Want to Build
|
|
@@ -170,16 +177,16 @@ I'll confirm progress at each step before moving to the next.
|
|
|
170
177
|
|
|
171
178
|
## Documentation Rule
|
|
172
179
|
|
|
173
|
-
**Important:**
|
|
180
|
+
**Important:** When you make progress, update \`.pmpt/docs/pmpt.md\` (the human-facing project document) at these moments:
|
|
174
181
|
- When architecture or tech decisions are finalized
|
|
175
182
|
- When a feature is implemented (mark as done)
|
|
176
183
|
- When a development phase is completed
|
|
177
184
|
- When requirements change or new decisions are made
|
|
178
185
|
\`\`\`
|
|
179
186
|
|
|
180
|
-
${
|
|
187
|
+
${lastAiMd ? 'Use the "Last Known AI Prompt" as the primary reference — update it rather than starting from scratch.' : 'Generate a fresh pmpt.ai.md based on the available context.'}
|
|
181
188
|
|
|
182
|
-
Write the content
|
|
189
|
+
Write the content to \`.pmpt/docs/pmpt.ai.md\`. After writing, run \`pmpt save\` to create a snapshot.`;
|
|
183
190
|
// Copy to clipboard
|
|
184
191
|
const copied = copyToClipboard(prompt);
|
|
185
192
|
if (copied) {
|
|
@@ -191,7 +198,7 @@ Write the content directly to \`.pmpt/docs/pmpt.md\`. After writing, run \`pmpt
|
|
|
191
198
|
}
|
|
192
199
|
p.note([
|
|
193
200
|
'1. Paste the prompt into your AI tool (Claude Code, Cursor, etc.)',
|
|
194
|
-
'2. The AI will regenerate .pmpt/docs/pmpt.md',
|
|
201
|
+
'2. The AI will regenerate .pmpt/docs/pmpt.ai.md',
|
|
195
202
|
'3. Run `pmpt save` to snapshot the recovered file',
|
|
196
203
|
].join('\n'), 'Next Steps');
|
|
197
204
|
p.outro('');
|
package/dist/commands/status.js
CHANGED
|
@@ -37,12 +37,12 @@ export function cmdStatus(path) {
|
|
|
37
37
|
p.note(notes.join('\n'), 'Project Info');
|
|
38
38
|
// Quality Score
|
|
39
39
|
const docsDir = getDocsDir(projectPath);
|
|
40
|
-
const
|
|
41
|
-
const
|
|
40
|
+
const aiMdPath = join(docsDir, 'pmpt.ai.md');
|
|
41
|
+
const pmptAiMd = existsSync(aiMdPath) ? readFileSync(aiMdPath, 'utf-8') : null;
|
|
42
42
|
const planProgress = getPlanProgress(projectPath);
|
|
43
43
|
const hasGit = snapshots.some(s => !!s.git);
|
|
44
44
|
const quality = computeQuality({
|
|
45
|
-
|
|
45
|
+
pmptAiMd,
|
|
46
46
|
planAnswers: planProgress?.answers ?? null,
|
|
47
47
|
versionCount: snapshots.length,
|
|
48
48
|
docFiles: tracked,
|
package/dist/lib/plan.js
CHANGED
|
@@ -41,7 +41,7 @@ export const PLAN_QUESTIONS = [
|
|
|
41
41
|
required: false,
|
|
42
42
|
},
|
|
43
43
|
];
|
|
44
|
-
// Generate AI
|
|
44
|
+
// Generate AI instruction file (pmpt.ai.md) — always English, AI-facing
|
|
45
45
|
export function generateAIPrompt(answers) {
|
|
46
46
|
// Parse features (support comma, semicolon, or newline separators)
|
|
47
47
|
const features = answers.coreFeatures
|
|
@@ -56,7 +56,10 @@ export function generateAIPrompt(answers) {
|
|
|
56
56
|
const techSection = answers.techStack
|
|
57
57
|
? `\n## Tech Stack Preferences\n${answers.techStack}\n`
|
|
58
58
|
: '';
|
|
59
|
-
return
|
|
59
|
+
return `<!-- This file is for AI tools only. Do not edit manually. -->
|
|
60
|
+
<!-- Paste this into Claude Code, Codex, Cursor, or any AI coding tool. -->
|
|
61
|
+
|
|
62
|
+
# ${answers.projectName} — Product Development Request
|
|
60
63
|
|
|
61
64
|
## What I Want to Build
|
|
62
65
|
${answers.productIdea}
|
|
@@ -77,32 +80,50 @@ I'll confirm progress at each step before moving to the next.
|
|
|
77
80
|
|
|
78
81
|
## Documentation Rule
|
|
79
82
|
|
|
80
|
-
**Important:**
|
|
83
|
+
**Important:** When you make progress, update \`.pmpt/docs/pmpt.md\` (the human-facing project document) at these moments:
|
|
81
84
|
- When architecture or tech decisions are finalized
|
|
82
85
|
- When a feature is implemented (mark as done)
|
|
83
86
|
- When a development phase is completed
|
|
84
87
|
- When requirements change or new decisions are made
|
|
85
88
|
|
|
86
|
-
|
|
87
|
-
|
|
89
|
+
Keep the Progress and Snapshot Log sections in pmpt.md up to date.
|
|
90
|
+
After significant milestones, run \`pmpt save\` to create a snapshot.
|
|
91
|
+
`;
|
|
92
|
+
}
|
|
93
|
+
// Generate human-facing project document (pmpt.md)
|
|
94
|
+
export function generateHumanDoc(answers) {
|
|
95
|
+
const features = answers.coreFeatures
|
|
96
|
+
.split(/[,;\n]/)
|
|
97
|
+
.map((f) => f.trim())
|
|
98
|
+
.filter((f) => f)
|
|
99
|
+
.map((f) => `- [ ] ${f}`)
|
|
100
|
+
.join('\n');
|
|
101
|
+
const contextSection = answers.additionalContext
|
|
102
|
+
? `\n## Additional Context\n${answers.additionalContext}\n`
|
|
103
|
+
: '';
|
|
104
|
+
const techSection = answers.techStack
|
|
105
|
+
? `\n## Tech Stack\n${answers.techStack}\n`
|
|
106
|
+
: '';
|
|
107
|
+
return `# ${answers.projectName}
|
|
108
|
+
|
|
109
|
+
## Product Idea
|
|
110
|
+
${answers.productIdea}
|
|
111
|
+
${contextSection}
|
|
112
|
+
## Features
|
|
113
|
+
${features}
|
|
114
|
+
${techSection}
|
|
88
115
|
## Progress
|
|
89
|
-
- [
|
|
90
|
-
- [ ]
|
|
91
|
-
|
|
116
|
+
- [ ] Project setup
|
|
117
|
+
- [ ] Core features implementation
|
|
118
|
+
- [ ] Testing & polish
|
|
92
119
|
|
|
93
|
-
Also, add a "## Snapshot Log" section to record what was built at each checkpoint:
|
|
94
|
-
\`\`\`
|
|
95
120
|
## Snapshot Log
|
|
96
121
|
### v1 - Initial Setup
|
|
97
|
-
-
|
|
98
|
-
- Installed dependencies: React, Tailwind
|
|
99
|
-
|
|
100
|
-
### v2 - Auth Feature
|
|
101
|
-
- Implemented login/signup
|
|
102
|
-
- Added JWT authentication
|
|
103
|
-
\`\`\`
|
|
122
|
+
- Project initialized with pmpt
|
|
104
123
|
|
|
105
|
-
|
|
124
|
+
---
|
|
125
|
+
*This document tracks your project progress. Update it as you build.*
|
|
126
|
+
*AI instructions are in \`pmpt.ai.md\` — paste that into your AI tool.*
|
|
106
127
|
`;
|
|
107
128
|
}
|
|
108
129
|
// Generate plan document
|
|
@@ -166,8 +187,12 @@ export function savePlanDocuments(projectPath, answers) {
|
|
|
166
187
|
const planPath = join(pmptDir, 'plan.md');
|
|
167
188
|
const planContent = generatePlanDocument(answers);
|
|
168
189
|
writeFileSync(planPath, planContent, 'utf-8');
|
|
169
|
-
// Save
|
|
170
|
-
const
|
|
190
|
+
// Save human-facing project document
|
|
191
|
+
const pmptMdPath = join(pmptDir, 'pmpt.md');
|
|
192
|
+
const pmptMdContent = generateHumanDoc(answers);
|
|
193
|
+
writeFileSync(pmptMdPath, pmptMdContent, 'utf-8');
|
|
194
|
+
// Save AI instruction file
|
|
195
|
+
const promptPath = join(pmptDir, 'pmpt.ai.md');
|
|
171
196
|
const promptContent = generateAIPrompt(answers);
|
|
172
197
|
writeFileSync(promptPath, promptContent, 'utf-8');
|
|
173
198
|
// Create initial snapshot
|
package/dist/lib/pmptFile.js
CHANGED
|
@@ -130,8 +130,11 @@ const AI_GUIDE = [
|
|
|
130
130
|
'- "plan" contains the original intent: what the creator wanted to build, key features, and tech preferences.',
|
|
131
131
|
'- "history" is an ordered array of snapshots (v1, v2, v3...). Each snapshot captures every tracked file at that point in time.',
|
|
132
132
|
'- To understand the evolution, compare files across versions sequentially. Look for what was added, removed, or rewritten between each version.',
|
|
133
|
-
'- "docs" contains the latest working documents
|
|
134
|
-
'-
|
|
133
|
+
'- "docs" contains the latest working documents:',
|
|
134
|
+
' - plan.md: product plan overview',
|
|
135
|
+
' - pmpt.md: human-facing project document (progress, decisions, milestones)',
|
|
136
|
+
' - pmpt.ai.md: AI instruction file (paste into AI tools like Claude Code, Codex, Cursor)',
|
|
137
|
+
'- "git" fields in each version link snapshots to source code commits.',
|
|
135
138
|
'',
|
|
136
139
|
'Key insight: The value of this file is not just the final result — it is the journey. The sequence of iterations reveals how decisions were made, what was tried, and how the product evolved through AI-assisted development.',
|
|
137
140
|
].join('\n');
|
package/dist/lib/quality.js
CHANGED
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
const MIN_PUBLISH_SCORE = 40;
|
|
6
6
|
export function computeQuality(data) {
|
|
7
7
|
const details = [];
|
|
8
|
-
// 1. pmpt.md content (30 points)
|
|
8
|
+
// 1. pmpt.ai.md content (30 points)
|
|
9
9
|
{
|
|
10
10
|
let score = 0;
|
|
11
11
|
let tip;
|
|
12
|
-
const len = data.
|
|
12
|
+
const len = data.pmptAiMd?.trim().length ?? 0;
|
|
13
13
|
if (len > 0)
|
|
14
14
|
score += 10;
|
|
15
15
|
if (len >= 200)
|
|
@@ -18,10 +18,10 @@ export function computeQuality(data) {
|
|
|
18
18
|
score += 10;
|
|
19
19
|
if (score < 30) {
|
|
20
20
|
tip = len === 0
|
|
21
|
-
? 'Run `pmpt plan` to generate pmpt.md'
|
|
22
|
-
: `pmpt.md is ${len} chars — expand to 500+ for full score`;
|
|
21
|
+
? 'Run `pmpt plan` to generate pmpt.ai.md'
|
|
22
|
+
: `pmpt.ai.md is ${len} chars — expand to 500+ for full score`;
|
|
23
23
|
}
|
|
24
|
-
details.push({ label: '
|
|
24
|
+
details.push({ label: 'AI prompt', score, maxScore: 30, tip });
|
|
25
25
|
}
|
|
26
26
|
// 2. Plan completeness (25 points)
|
|
27
27
|
{
|
|
@@ -66,7 +66,7 @@ export function computeQuality(data) {
|
|
|
66
66
|
let tip;
|
|
67
67
|
if (data.docFiles.includes('plan.md'))
|
|
68
68
|
score += 5;
|
|
69
|
-
if (data.docFiles.includes('pmpt.md'))
|
|
69
|
+
if (data.docFiles.includes('pmpt.ai.md'))
|
|
70
70
|
score += 5;
|
|
71
71
|
if (data.docFiles.length > 2)
|
|
72
72
|
score += 5;
|
|
@@ -74,8 +74,8 @@ export function computeQuality(data) {
|
|
|
74
74
|
const missing = [];
|
|
75
75
|
if (!data.docFiles.includes('plan.md'))
|
|
76
76
|
missing.push('plan.md');
|
|
77
|
-
if (!data.docFiles.includes('pmpt.md'))
|
|
78
|
-
missing.push('pmpt.md');
|
|
77
|
+
if (!data.docFiles.includes('pmpt.ai.md'))
|
|
78
|
+
missing.push('pmpt.ai.md');
|
|
79
79
|
if (data.docFiles.length <= 2)
|
|
80
80
|
missing.push('additional docs');
|
|
81
81
|
tip = `Add: ${missing.join(', ')}`;
|