pmpt-cli 1.14.7 → 1.14.8

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.
Files changed (2) hide show
  1. package/dist/mcp.js +129 -1
  2. package/package.json +1 -1
package/dist/mcp.js CHANGED
@@ -15,7 +15,7 @@ import { createRequire } from 'module';
15
15
  import { isInitialized, loadConfig, saveConfig, getDocsDir, getHistoryDir } from './lib/config.js';
16
16
  import { createFullSnapshot, getAllSnapshots, getTrackedFiles, resolveFullSnapshot } from './lib/history.js';
17
17
  import { computeQuality } from './lib/quality.js';
18
- import { getPlanProgress, savePlanProgress, savePlanDocuments, PLAN_QUESTIONS } from './lib/plan.js';
18
+ import { getPlanProgress, savePlanProgress, savePlanDocuments, PLAN_QUESTIONS, generatePlanDocument, generateAIPrompt } from './lib/plan.js';
19
19
  import { isGitRepo } from './lib/git.js';
20
20
  import { diffSnapshots } from './lib/diff.js';
21
21
  import { loadAuth } from './lib/auth.js';
@@ -689,6 +689,134 @@ server.tool('pmpt_publish', 'Publish the project to pmptwiki.com. Non-interactiv
689
689
  return { content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true };
690
690
  }
691
691
  });
692
+ server.tool('pmpt_edit_plan', 'Edit existing plan fields (productIdea, coreFeatures, techStack, additionalContext, projectName). Use this to update plan content — e.g., translate productIdea to English, add new features, change tech stack. Only provided fields are updated; others stay unchanged. Regenerates plan.md and pmpt.ai.md automatically. pmpt.md progress/log sections are preserved — only the plan-derived sections (Product Idea, Features, Tech Stack, Additional Context) are updated.', {
693
+ projectPath: z.string().optional().describe('Project root path. Defaults to cwd.'),
694
+ projectName: z.string().optional().describe('New project name.'),
695
+ productIdea: z.string().optional().describe('New product idea description.'),
696
+ coreFeatures: z.string().optional().describe('New core features (comma or semicolon separated).'),
697
+ techStack: z.string().optional().describe('New tech stack preference.'),
698
+ additionalContext: z.string().optional().describe('New additional context.'),
699
+ }, async ({ projectPath, projectName, productIdea, coreFeatures, techStack, additionalContext }) => {
700
+ try {
701
+ const pp = resolveProjectPath(projectPath);
702
+ assertInitialized(pp);
703
+ const progress = getPlanProgress(pp);
704
+ if (!progress?.completed || !progress.answers) {
705
+ return { content: [{ type: 'text', text: 'No plan found. Run pmpt_plan first to create a plan.' }], isError: true };
706
+ }
707
+ // Track what changed
708
+ const changes = [];
709
+ const answers = { ...progress.answers };
710
+ if (projectName !== undefined) {
711
+ answers.projectName = projectName;
712
+ changes.push(`projectName → "${projectName}"`);
713
+ }
714
+ if (productIdea !== undefined) {
715
+ answers.productIdea = productIdea;
716
+ changes.push(`productIdea updated`);
717
+ }
718
+ if (coreFeatures !== undefined) {
719
+ answers.coreFeatures = coreFeatures;
720
+ changes.push(`coreFeatures updated`);
721
+ }
722
+ if (techStack !== undefined) {
723
+ answers.techStack = techStack;
724
+ changes.push(`techStack → "${techStack}"`);
725
+ }
726
+ if (additionalContext !== undefined) {
727
+ answers.additionalContext = additionalContext;
728
+ changes.push(`additionalContext updated`);
729
+ }
730
+ if (changes.length === 0) {
731
+ return { content: [{ type: 'text', text: 'No fields provided. Pass at least one field to update.' }] };
732
+ }
733
+ // Update plan-progress.json
734
+ savePlanProgress(pp, { ...progress, answers });
735
+ // Regenerate plan.md and pmpt.ai.md
736
+ const docsDir = getDocsDir(pp);
737
+ const planPath = join(docsDir, 'plan.md');
738
+ writeFileSync(planPath, generatePlanDocument(answers), 'utf-8');
739
+ const aiMdPath = join(docsDir, 'pmpt.ai.md');
740
+ writeFileSync(aiMdPath, generateAIPrompt(answers), 'utf-8');
741
+ // Update pmpt.md plan-derived sections (preserve progress, log, decisions)
742
+ const pmptMdPath = join(docsDir, 'pmpt.md');
743
+ if (existsSync(pmptMdPath)) {
744
+ let content = readFileSync(pmptMdPath, 'utf-8');
745
+ // Update title (first # heading)
746
+ content = content.replace(/^# .+$/m, `# ${answers.projectName}`);
747
+ // Update Product Idea section
748
+ const ideaRegex = /## Product Idea\n[\s\S]*?(?=\n## )/;
749
+ if (ideaRegex.test(content)) {
750
+ content = content.replace(ideaRegex, `## Product Idea\n${answers.productIdea}\n`);
751
+ }
752
+ // Update Features section (only unchecked items get replaced; checked items are preserved)
753
+ const featuresRegex = /## Features\n[\s\S]*?(?=\n## )/;
754
+ if (featuresRegex.test(content)) {
755
+ const existingMatch = content.match(featuresRegex);
756
+ if (existingMatch) {
757
+ // Extract already-checked features
758
+ const checked = existingMatch[0]
759
+ .split('\n')
760
+ .filter(line => line.startsWith('- [x]'))
761
+ .join('\n');
762
+ const newFeatures = answers.coreFeatures
763
+ .split(/[,;\n]/)
764
+ .map((f) => f.trim())
765
+ .filter((f) => f)
766
+ .map((f) => `- [ ] ${f}`)
767
+ .join('\n');
768
+ const featuresSection = checked
769
+ ? `## Features\n${checked}\n${newFeatures}\n`
770
+ : `## Features\n${newFeatures}\n`;
771
+ content = content.replace(featuresRegex, featuresSection);
772
+ }
773
+ }
774
+ // Update Tech Stack section
775
+ if (answers.techStack) {
776
+ const techRegex = /## Tech Stack\n[\s\S]*?(?=\n## )/;
777
+ if (techRegex.test(content)) {
778
+ content = content.replace(techRegex, `## Tech Stack\n${answers.techStack}\n`);
779
+ }
780
+ else {
781
+ // Insert before Progress section
782
+ const progressIdx = content.indexOf('\n## Progress');
783
+ if (progressIdx !== -1) {
784
+ content = content.slice(0, progressIdx) + `\n## Tech Stack\n${answers.techStack}\n` + content.slice(progressIdx);
785
+ }
786
+ }
787
+ }
788
+ // Update Additional Context section
789
+ if (answers.additionalContext) {
790
+ const ctxRegex = /## Additional Context\n[\s\S]*?(?=\n## )/;
791
+ if (ctxRegex.test(content)) {
792
+ content = content.replace(ctxRegex, `## Additional Context\n${answers.additionalContext}\n`);
793
+ }
794
+ else {
795
+ const ideaEnd = content.indexOf('\n## ', content.indexOf('## Product Idea') + 1);
796
+ if (ideaEnd !== -1) {
797
+ content = content.slice(0, ideaEnd) + `\n## Additional Context\n${answers.additionalContext}\n` + content.slice(ideaEnd);
798
+ }
799
+ }
800
+ }
801
+ writeFileSync(pmptMdPath, content, 'utf-8');
802
+ }
803
+ return {
804
+ content: [{
805
+ type: 'text',
806
+ text: [
807
+ `Plan updated:`,
808
+ ...changes.map(c => ` - ${c}`),
809
+ '',
810
+ 'Regenerated: plan.md, pmpt.ai.md, pmpt.md (progress preserved)',
811
+ 'Run pmpt_save to snapshot this change.',
812
+ ].join('\n'),
813
+ }],
814
+ };
815
+ }
816
+ catch (error) {
817
+ return { content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }], isError: true };
818
+ }
819
+ });
692
820
  server.tool('pmpt_graduate', 'Graduate a project on pmptwiki — archives it with a Hall of Fame badge. The project can no longer be updated. Non-interactive. User must have run `pmpt login` once before.', {
693
821
  slug: z.string().describe('Project slug to graduate.'),
694
822
  note: z.string().optional().describe('Graduation note (e.g., "Reached 1000 users!").'),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmpt-cli",
3
- "version": "1.14.7",
3
+ "version": "1.14.8",
4
4
  "description": "Record and share your AI-driven product development journey",
5
5
  "type": "module",
6
6
  "bin": {