pmpt-cli 1.17.0 → 1.18.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.
package/README.md CHANGED
@@ -96,6 +96,7 @@ The generated prompt is **automatically copied to your clipboard**. Just paste i
96
96
  | Command | Description |
97
97
  |---------|-------------|
98
98
  | `pmpt init` | Initialize project — sets up `.pmpt/`, selects AI tool, creates entry points |
99
+ | `pmpt harness` | Add harness to existing project — missing pmpt.md sections + index.md + tool entry points |
99
100
  | `pmpt plan` | 5 questions → AI prompt (auto-copied to clipboard) |
100
101
  | `pmpt plan --template` | Generate a fillable `answers.json` (Windows/PowerShell friendly) |
101
102
  | `pmpt plan --answers-file <f>` | Run plan non-interactively from a JSON file |
@@ -0,0 +1,59 @@
1
+ import * as p from '@clack/prompts';
2
+ import { resolve, basename } from 'path';
3
+ import { isInitialized } from '../lib/config.js';
4
+ import { addMissingSections, ensureIndexMd, ensureCursorRules, ensureAgentsMd, ensureClaudeMdRef, } from '../lib/harness.js';
5
+ export async function cmdHarness(path) {
6
+ const projectPath = path ? resolve(path) : process.cwd();
7
+ const projectName = basename(projectPath);
8
+ p.intro('pmpt harness');
9
+ if (!isInitialized(projectPath)) {
10
+ p.log.error('Project not initialized. Run `pmpt init` first.');
11
+ process.exit(1);
12
+ }
13
+ // 1. Add missing sections to pmpt.md
14
+ const added = addMissingSections(projectPath);
15
+ if (added.length > 0) {
16
+ p.log.success(`Added to pmpt.md: ${added.join(', ')}`);
17
+ }
18
+ else {
19
+ p.log.info('pmpt.md already has all harness sections.');
20
+ }
21
+ // 2. Create .pmpt/index.md
22
+ ensureIndexMd(projectPath, projectName);
23
+ p.log.success('Created: .pmpt/index.md');
24
+ // 3. Ask which AI tool
25
+ const toolChoice = await p.select({
26
+ message: 'Which AI coding tool do you use?',
27
+ options: [
28
+ { value: 'claude', label: 'Claude Code', hint: 'CLAUDE.md → .pmpt/index.md' },
29
+ { value: 'cursor', label: 'Cursor', hint: '.cursorrules → .pmpt/index.md' },
30
+ { value: 'codex', label: 'Codex', hint: 'AGENTS.md → .pmpt/index.md' },
31
+ { value: 'all', label: 'All of the above' },
32
+ { value: 'skip', label: 'Skip' },
33
+ ],
34
+ });
35
+ if (p.isCancel(toolChoice) || toolChoice === 'skip') {
36
+ p.outro('Done. .pmpt/index.md created, pmpt.md updated.');
37
+ return;
38
+ }
39
+ const tool = toolChoice;
40
+ const created = [];
41
+ if (tool === 'claude' || tool === 'all') {
42
+ ensureClaudeMdRef(projectPath);
43
+ created.push('CLAUDE.md (updated)');
44
+ }
45
+ if (tool === 'cursor' || tool === 'all') {
46
+ ensureCursorRules(projectPath);
47
+ created.push('.cursorrules');
48
+ }
49
+ if (tool === 'codex' || tool === 'all') {
50
+ ensureAgentsMd(projectPath, projectName);
51
+ created.push('AGENTS.md');
52
+ }
53
+ if (created.length > 0) {
54
+ p.log.success(`Created: ${created.join(', ')}`);
55
+ }
56
+ p.log.message('');
57
+ p.log.info('AI tools will now read .pmpt/index.md → .pmpt/docs/pmpt.md at session start.');
58
+ p.outro('Harness ready.');
59
+ }
package/dist/index.js CHANGED
@@ -47,6 +47,7 @@ import { cmdInternalSeed } from './commands/internal-seed.js';
47
47
  import { cmdMcpSetup } from './commands/mcp-setup.js';
48
48
  import { cmdDoctor } from './commands/doctor.js';
49
49
  import { cmdConstraint } from './commands/constraint.js';
50
+ import { cmdHarness } from './commands/harness.js';
50
51
  import { trackCommand } from './lib/api.js';
51
52
  import { checkForUpdates } from './lib/update-check.js';
52
53
  import { createRequire } from 'module';
@@ -154,6 +155,10 @@ program
154
155
  ...options,
155
156
  template: options.template === true ? 'answers.json' : options.template,
156
157
  }));
158
+ program
159
+ .command('harness [path]')
160
+ .description('Set up AI context harness for existing projects — adds missing pmpt.md sections and creates tool entry points')
161
+ .action(cmdHarness);
157
162
  program
158
163
  .command('constraint <action>')
159
164
  .description('Manage architecture constraints — add, list, or remove rules')
@@ -77,6 +77,9 @@ export function setupHarnessForTools(projectPath, projectName, tools) {
77
77
  ensureClaudeMdIndexRef(projectPath);
78
78
  }
79
79
  }
80
+ export function ensureClaudeMdRef(projectPath) {
81
+ ensureClaudeMdIndexRef(projectPath);
82
+ }
80
83
  function ensureClaudeMdIndexRef(projectPath) {
81
84
  const claudeMdPath = join(projectPath, 'CLAUDE.md');
82
85
  const marker = '<!-- pmpt-index -->';
@@ -94,6 +97,54 @@ function ensureClaudeMdIndexRef(projectPath) {
94
97
  writeFileSync(claudeMdPath, section + '\n\n' + content, 'utf-8');
95
98
  }
96
99
  }
100
+ // ─── pmpt.md section migration ────────────────────────────────────
101
+ const HARNESS_SECTIONS = [
102
+ {
103
+ heading: '## Architecture',
104
+ comment: '<!-- High-level structure. Update as it evolves. -->\n<!-- Example: "Next.js frontend → Cloudflare Workers API → D1 database" -->',
105
+ },
106
+ {
107
+ heading: '## Active Work',
108
+ comment: '<!-- What\'s currently being built. Clear when done, move to Snapshot Log. -->',
109
+ },
110
+ {
111
+ heading: '## Constraints',
112
+ comment: '<!-- Platform or library limitations discovered during development. -->\n<!-- Format: - [Platform/Tool]: what doesn\'t work → workaround used -->',
113
+ },
114
+ {
115
+ heading: '## Lessons',
116
+ comment: '<!-- Anti-patterns and "tried X, broke because Y" discoveries. -->\n<!-- Format: - [What failed] → [Root cause] → [Fix applied] -->',
117
+ },
118
+ ];
119
+ /**
120
+ * Add missing harness sections to an existing pmpt.md.
121
+ * Returns list of section headings that were added.
122
+ */
123
+ export function addMissingSections(projectPath) {
124
+ const pmptMdPath = join(getDocsDir(projectPath), 'pmpt.md');
125
+ if (!existsSync(pmptMdPath))
126
+ return [];
127
+ let content = readFileSync(pmptMdPath, 'utf-8');
128
+ const added = [];
129
+ for (const section of HARNESS_SECTIONS) {
130
+ if (content.includes(section.heading))
131
+ continue;
132
+ // Insert before ## Decisions if it exists, otherwise append
133
+ const insertBefore = '## Decisions';
134
+ const block = `${section.heading}\n${section.comment}\n`;
135
+ if (content.includes(insertBefore)) {
136
+ content = content.replace(insertBefore, block + '\n' + insertBefore);
137
+ }
138
+ else {
139
+ content = content.trimEnd() + '\n\n' + block;
140
+ }
141
+ added.push(section.heading);
142
+ }
143
+ if (added.length > 0) {
144
+ writeFileSync(pmptMdPath, content, 'utf-8');
145
+ }
146
+ return added;
147
+ }
97
148
  // ─── Constraint management — reads/writes pmpt.md ## Constraints ──
98
149
  export function readConstraints(projectPath) {
99
150
  const pmptMdPath = join(getDocsDir(projectPath), 'pmpt.md');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pmpt-cli",
3
- "version": "1.17.0",
3
+ "version": "1.18.0",
4
4
  "description": "Record and share your AI-driven product development journey",
5
5
  "type": "module",
6
6
  "bin": {