pmpt-cli 1.14.6 → 1.14.7
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/save.js +42 -9
- package/dist/commands/watch.js +4 -1
- package/dist/lib/watcher.js +12 -3
- package/dist/mcp.js +16 -8
- package/package.json +1 -1
package/dist/commands/save.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as p from '@clack/prompts';
|
|
2
|
-
import { resolve } from 'path';
|
|
3
|
-
import { existsSync, statSync } from 'fs';
|
|
2
|
+
import { resolve, join } from 'path';
|
|
3
|
+
import { existsSync, statSync, readFileSync, writeFileSync } from 'fs';
|
|
4
4
|
import { isInitialized, getDocsDir } from '../lib/config.js';
|
|
5
|
-
import { createFullSnapshot, getTrackedFiles } from '../lib/history.js';
|
|
5
|
+
import { createFullSnapshot, getTrackedFiles, getAllSnapshots } from '../lib/history.js';
|
|
6
6
|
export async function cmdSave(fileOrPath) {
|
|
7
7
|
const projectPath = fileOrPath && existsSync(fileOrPath) && statSync(fileOrPath).isDirectory()
|
|
8
8
|
? resolve(fileOrPath)
|
|
@@ -21,10 +21,46 @@ export async function cmdSave(fileOrPath) {
|
|
|
21
21
|
p.outro('');
|
|
22
22
|
return;
|
|
23
23
|
}
|
|
24
|
+
// Ask for summary
|
|
25
|
+
const summary = await p.text({
|
|
26
|
+
message: 'What did you accomplish? (this is shown on your project page)',
|
|
27
|
+
placeholder: 'e.g. Added user auth with JWT, built login/signup pages',
|
|
28
|
+
});
|
|
29
|
+
if (p.isCancel(summary)) {
|
|
30
|
+
p.cancel('Save cancelled.');
|
|
31
|
+
process.exit(0);
|
|
32
|
+
}
|
|
33
|
+
const note = summary.trim() || undefined;
|
|
34
|
+
// Write summary to pmpt.md Snapshot Log before snapshot
|
|
35
|
+
if (note) {
|
|
36
|
+
const pmptMdPath = join(docsDir, 'pmpt.md');
|
|
37
|
+
if (existsSync(pmptMdPath)) {
|
|
38
|
+
let content = readFileSync(pmptMdPath, 'utf-8');
|
|
39
|
+
const snapshots = getAllSnapshots(projectPath);
|
|
40
|
+
const nextVersion = snapshots.length + 1;
|
|
41
|
+
const date = new Date().toISOString().slice(0, 10);
|
|
42
|
+
const noteLines = note.split(/(?:\.\s+|\n)/).filter(s => s.trim()).map(s => {
|
|
43
|
+
const trimmed = s.trim().replace(/\.?$/, '');
|
|
44
|
+
return `- ${trimmed}`;
|
|
45
|
+
});
|
|
46
|
+
const entry = `\n### v${nextVersion} — ${date}\n${noteLines.join('\n')}\n`;
|
|
47
|
+
const logIndex = content.indexOf('## Snapshot Log');
|
|
48
|
+
if (logIndex !== -1) {
|
|
49
|
+
const afterHeader = content.indexOf('\n', logIndex);
|
|
50
|
+
const nextSection = content.indexOf('\n## ', afterHeader + 1);
|
|
51
|
+
const insertPos = nextSection !== -1 ? nextSection : content.length;
|
|
52
|
+
content = content.slice(0, insertPos) + entry + content.slice(insertPos);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
content += `\n## Snapshot Log${entry}`;
|
|
56
|
+
}
|
|
57
|
+
writeFileSync(pmptMdPath, content, 'utf-8');
|
|
58
|
+
}
|
|
59
|
+
}
|
|
24
60
|
const s = p.spinner();
|
|
25
61
|
s.start(`Creating snapshot of ${files.length} file(s)...`);
|
|
26
62
|
try {
|
|
27
|
-
const entry = createFullSnapshot(projectPath);
|
|
63
|
+
const entry = createFullSnapshot(projectPath, { note });
|
|
28
64
|
s.stop('Snapshot saved');
|
|
29
65
|
let msg = `v${entry.version} saved`;
|
|
30
66
|
if (entry.git) {
|
|
@@ -38,11 +74,8 @@ export async function cmdSave(fileOrPath) {
|
|
|
38
74
|
msg += ` (${changedCount} changed, ${unchangedCount} skipped)`;
|
|
39
75
|
}
|
|
40
76
|
p.log.success(msg);
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
p.log.message('');
|
|
44
|
-
p.log.warn('pmpt.md has not been updated since the last save.');
|
|
45
|
-
p.log.message(' Tip: Mark completed features and update the Snapshot Log before saving.');
|
|
77
|
+
if (note) {
|
|
78
|
+
p.log.info(`Summary: ${note}`);
|
|
46
79
|
}
|
|
47
80
|
p.log.message('');
|
|
48
81
|
p.log.info('Files included:');
|
package/dist/commands/watch.js
CHANGED
|
@@ -14,7 +14,7 @@ export function cmdWatch(path) {
|
|
|
14
14
|
p.log.info('Auto-saving snapshots on MD file changes.');
|
|
15
15
|
p.log.info('Press Ctrl+C to stop.');
|
|
16
16
|
p.log.message('');
|
|
17
|
-
const watcher = startWatching(projectPath, (version, files, git) => {
|
|
17
|
+
const watcher = startWatching(projectPath, (version, files, git, note) => {
|
|
18
18
|
let msg = `v${version} saved (${files.length} file(s))`;
|
|
19
19
|
if (git) {
|
|
20
20
|
msg += ` · ${git.commit}`;
|
|
@@ -22,6 +22,9 @@ export function cmdWatch(path) {
|
|
|
22
22
|
msg += ' (uncommitted)';
|
|
23
23
|
}
|
|
24
24
|
p.log.success(msg);
|
|
25
|
+
if (note) {
|
|
26
|
+
p.log.info(` ${note}`);
|
|
27
|
+
}
|
|
25
28
|
});
|
|
26
29
|
process.on('SIGINT', () => {
|
|
27
30
|
p.log.message('');
|
package/dist/lib/watcher.js
CHANGED
|
@@ -2,7 +2,7 @@ import chokidar from 'chokidar';
|
|
|
2
2
|
import { loadConfig, getDocsDir } from './config.js';
|
|
3
3
|
import { createFullSnapshot } from './history.js';
|
|
4
4
|
import { readFileSync } from 'fs';
|
|
5
|
-
import { join } from 'path';
|
|
5
|
+
import { join, relative } from 'path';
|
|
6
6
|
export function startWatching(projectPath, onSnapshot) {
|
|
7
7
|
const config = loadConfig(projectPath);
|
|
8
8
|
if (!config) {
|
|
@@ -19,11 +19,18 @@ export function startWatching(projectPath, onSnapshot) {
|
|
|
19
19
|
},
|
|
20
20
|
});
|
|
21
21
|
const fileContents = new Map();
|
|
22
|
+
const pendingChanges = new Set();
|
|
22
23
|
let debounceTimer = null;
|
|
23
24
|
const saveSnapshot = () => {
|
|
24
|
-
|
|
25
|
+
// Build auto-note from changed file names
|
|
26
|
+
const changedNames = [...pendingChanges].map(p => relative(docsDir, p));
|
|
27
|
+
const note = changedNames.length > 0
|
|
28
|
+
? `Updated ${changedNames.join(', ')}`
|
|
29
|
+
: undefined;
|
|
30
|
+
pendingChanges.clear();
|
|
31
|
+
const entry = createFullSnapshot(projectPath, { note });
|
|
25
32
|
if (onSnapshot) {
|
|
26
|
-
onSnapshot(entry.version, entry.files, entry.git);
|
|
33
|
+
onSnapshot(entry.version, entry.files, entry.git, note);
|
|
27
34
|
}
|
|
28
35
|
};
|
|
29
36
|
// Debounced snapshot save (1 second)
|
|
@@ -37,6 +44,7 @@ export function startWatching(projectPath, onSnapshot) {
|
|
|
37
44
|
try {
|
|
38
45
|
const content = readFileSync(path, 'utf-8');
|
|
39
46
|
fileContents.set(path, content);
|
|
47
|
+
pendingChanges.add(path);
|
|
40
48
|
debouncedSave();
|
|
41
49
|
}
|
|
42
50
|
catch {
|
|
@@ -50,6 +58,7 @@ export function startWatching(projectPath, onSnapshot) {
|
|
|
50
58
|
// Only snapshot if content actually changed
|
|
51
59
|
if (oldContent !== newContent) {
|
|
52
60
|
fileContents.set(path, newContent);
|
|
61
|
+
pendingChanges.add(path);
|
|
53
62
|
debouncedSave();
|
|
54
63
|
}
|
|
55
64
|
}
|
package/dist/mcp.js
CHANGED
|
@@ -98,9 +98,9 @@ function formatDiffs(diffs) {
|
|
|
98
98
|
return lines.join('\n');
|
|
99
99
|
}
|
|
100
100
|
// ── Tools ───────────────────────────────────────────
|
|
101
|
-
server.tool('pmpt_save', 'Save a snapshot of .pmpt/docs/ files. Call after completing features, fixes, or milestones. CRITICAL: Always provide a summary parameter — it becomes the version description shown on pmptwiki.com. Without a summary, the version appears empty on the project page. Write a
|
|
101
|
+
server.tool('pmpt_save', 'Save a snapshot of .pmpt/docs/ files. Call after completing features, fixes, or milestones. CRITICAL: Always provide a detailed summary parameter — it becomes the version description shown publicly on pmptwiki.com. Without a summary, the version appears empty on the project page. Write a DETAILED summary (3-5 sentences) that explains: (1) WHAT was built or changed, (2) WHY it matters, (3) key technical decisions made. Think of it as a mini dev blog entry that helps others learn from your journey.', {
|
|
102
102
|
projectPath: z.string().optional().describe('Project root path. Defaults to cwd.'),
|
|
103
|
-
summary: z.string().optional().describe('
|
|
103
|
+
summary: z.string().optional().describe('Detailed description of what was accomplished since the last save. Write 3-5 sentences that tell the story: what you built, why, and how. This is shown publicly on the project page. BAD example: "Added auth" — too vague. GOOD example: "Implemented user authentication using JWT with refresh token rotation. Chose JWT over session-based auth for stateless API compatibility. Added login/signup pages with form validation and error handling. Protected routes now redirect unauthenticated users to login."'),
|
|
104
104
|
}, async ({ projectPath, summary }) => {
|
|
105
105
|
try {
|
|
106
106
|
const pp = resolveProjectPath(projectPath);
|
|
@@ -118,7 +118,11 @@ server.tool('pmpt_save', 'Save a snapshot of .pmpt/docs/ files. Call after compl
|
|
|
118
118
|
const snapshots = getAllSnapshots(pp);
|
|
119
119
|
const nextVersion = snapshots.length + 1;
|
|
120
120
|
const date = new Date().toISOString().slice(0, 10);
|
|
121
|
-
const
|
|
121
|
+
const summaryLines = summary.split(/(?:\.\s+|\n)/).filter(s => s.trim()).map(s => {
|
|
122
|
+
const trimmed = s.trim().replace(/\.?$/, '');
|
|
123
|
+
return `- ${trimmed}`;
|
|
124
|
+
});
|
|
125
|
+
const entry = `\n### v${nextVersion} — ${date}\n${summaryLines.join('\n')}\n`;
|
|
122
126
|
const logIndex = content.indexOf('## Snapshot Log');
|
|
123
127
|
if (logIndex !== -1) {
|
|
124
128
|
const afterHeader = content.indexOf('\n', logIndex);
|
|
@@ -476,11 +480,11 @@ server.tool('pmpt_read_context', 'Read project context to understand current sta
|
|
|
476
480
|
return { content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true };
|
|
477
481
|
}
|
|
478
482
|
});
|
|
479
|
-
server.tool('pmpt_update_doc', 'Update pmpt.md: check off completed features, add progress notes, or backfill missing version summaries. Use after completing work OR before publishing to fill in empty Snapshot Log entries. To backfill: set snapshotVersion="v2 —
|
|
483
|
+
server.tool('pmpt_update_doc', 'Update pmpt.md: check off completed features, add progress notes, or backfill missing version summaries. Use after completing work OR before publishing to fill in empty Snapshot Log entries. To backfill: use pmpt_diff to understand what changed, then set snapshotVersion="v2 — Short Title" and progressNote with DETAILED multi-sentence description. Write as if explaining to another developer what happened in this version and why.', {
|
|
480
484
|
projectPath: z.string().optional().describe('Project root path. Defaults to cwd.'),
|
|
481
485
|
completedFeatures: z.array(z.string()).optional().describe('Feature names to mark as done (matches against checkbox items in pmpt.md).'),
|
|
482
|
-
progressNote: z.string().optional().describe('
|
|
483
|
-
snapshotVersion: z.string().optional().describe('Version label for the snapshot log entry (e.g. "v3
|
|
486
|
+
progressNote: z.string().optional().describe('Detailed progress note (3-5 sentences) to append to the Snapshot Log. Explain what was done, why, and any key decisions. Each sentence becomes a bullet point. BAD: "Fixed bugs". GOOD: "Fixed authentication redirect loop caused by token expiry race condition. Added token refresh middleware that silently renews expired tokens. Users no longer get logged out unexpectedly during long sessions."'),
|
|
487
|
+
snapshotVersion: z.string().optional().describe('Version label for the snapshot log entry (e.g. "v3 — Auth Complete"). Auto-generated if omitted.'),
|
|
484
488
|
}, async ({ projectPath, completedFeatures, progressNote, snapshotVersion }) => {
|
|
485
489
|
try {
|
|
486
490
|
const pp = resolveProjectPath(projectPath);
|
|
@@ -507,7 +511,11 @@ server.tool('pmpt_update_doc', 'Update pmpt.md: check off completed features, ad
|
|
|
507
511
|
if (progressNote) {
|
|
508
512
|
const snapshots = getAllSnapshots(pp);
|
|
509
513
|
const label = snapshotVersion || `v${snapshots.length} - Progress`;
|
|
510
|
-
const
|
|
514
|
+
const noteLines = progressNote.split(/(?:\.\s+|\n)/).filter(s => s.trim()).map(s => {
|
|
515
|
+
const trimmed = s.trim().replace(/\.?$/, '');
|
|
516
|
+
return `- ${trimmed}`;
|
|
517
|
+
});
|
|
518
|
+
const entry = `\n### ${label}\n${noteLines.join('\n')}\n`;
|
|
511
519
|
const logIndex = content.indexOf('## Snapshot Log');
|
|
512
520
|
if (logIndex !== -1) {
|
|
513
521
|
// Find the end of the Snapshot Log header line
|
|
@@ -582,7 +590,7 @@ server.tool('pmpt_log_decision', 'Record an architectural or technical decision
|
|
|
582
590
|
return { content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true };
|
|
583
591
|
}
|
|
584
592
|
});
|
|
585
|
-
server.tool('pmpt_publish', 'Publish the project to pmptwiki.com. Non-interactive — just provide slug and optional metadata. MANDATORY pre-publish checklist: (1) Run pmpt_history — if ANY version lacks a note/summary, you MUST fix it before publishing. (2) For each empty version, run pmpt_diff for that version to understand
|
|
593
|
+
server.tool('pmpt_publish', 'Publish the project to pmptwiki.com. Non-interactive — just provide slug and optional metadata. MANDATORY pre-publish checklist: (1) Run pmpt_history — if ANY version lacks a note/summary, you MUST fix it before publishing. (2) For each empty version, run pmpt_diff for that version to understand what changed, then use pmpt_update_doc with a DETAILED progressNote (3-5 sentences explaining what, why, and key decisions) and snapshotVersion. Write like a dev blog — others will read this to learn from your journey. (3) After backfilling all versions, run pmpt_save with a detailed summary. (4) Run pmpt_quality to verify readiness. DO NOT publish with empty or vague single-line versions — they display poorly on the project page. Note: user must have run `pmpt login` once before.', {
|
|
586
594
|
projectPath: z.string().optional().describe('Project root path. Defaults to cwd.'),
|
|
587
595
|
slug: z.string().describe('Project slug (3-50 chars, lowercase alphanumeric and hyphens).'),
|
|
588
596
|
description: z.string().optional().describe('Project description (max 500 chars).'),
|