context-planning 0.7.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/LICENSE +21 -0
- package/README.md +454 -0
- package/bin/commands/_helpers.js +53 -0
- package/bin/commands/_usage.js +67 -0
- package/bin/commands/capture.js +46 -0
- package/bin/commands/codebase-status.js +41 -0
- package/bin/commands/complete-milestone.js +57 -0
- package/bin/commands/config.js +70 -0
- package/bin/commands/doctor.js +139 -0
- package/bin/commands/gsd-import.js +90 -0
- package/bin/commands/inbox.js +81 -0
- package/bin/commands/index.js +33 -0
- package/bin/commands/init.js +87 -0
- package/bin/commands/install.js +43 -0
- package/bin/commands/scaffold-codebase.js +53 -0
- package/bin/commands/scaffold-milestone.js +58 -0
- package/bin/commands/scaffold-phase.js +65 -0
- package/bin/commands/status.js +42 -0
- package/bin/commands/statusline.js +108 -0
- package/bin/commands/tick.js +49 -0
- package/bin/commands/version.js +9 -0
- package/bin/commands/worktree.js +218 -0
- package/bin/commands/write-summary.js +54 -0
- package/bin/cp.cmd +2 -0
- package/bin/cp.js +54 -0
- package/commands/cp/capture.md +107 -0
- package/commands/cp/complete-milestone.md +166 -0
- package/commands/cp/execute-phase.md +220 -0
- package/commands/cp/map-codebase.md +211 -0
- package/commands/cp/new-milestone.md +136 -0
- package/commands/cp/new-project.md +132 -0
- package/commands/cp/plan-phase.md +195 -0
- package/commands/cp/progress.md +147 -0
- package/commands/cp/quick.md +104 -0
- package/commands/cp/resume.md +125 -0
- package/commands/cp/write-summary.md +33 -0
- package/docs/MIGRATION-v0.5.md +140 -0
- package/docs/architecture.md +189 -0
- package/docs/superpowers/plans/2026-05-20-v0-7-plan-16-01-design-md-infrastructure.md +1064 -0
- package/docs/superpowers/plans/2026-05-20-v0-7-plan-16-02-review-log-infrastructure.md +418 -0
- package/docs/superpowers/plans/2026-05-20-v0-7-plan-16-03-key-decisions-hard-block.md +295 -0
- package/docs/superpowers/specs/2026-05-20-generic-provider-harness-detection-design.md +380 -0
- package/docs/superpowers/specs/2026-05-20-v0-7-design-capture-design.md +400 -0
- package/docs/writing-providers.md +76 -0
- package/install/aider.js +204 -0
- package/install/claude.js +116 -0
- package/install/common.js +65 -0
- package/install/copilot.js +86 -0
- package/install/cursor.js +120 -0
- package/install/echo-provider.js +50 -0
- package/lib/codebase-mapper.js +169 -0
- package/lib/detect.js +280 -0
- package/lib/frontmatter.js +72 -0
- package/lib/gsd-compat.js +165 -0
- package/lib/import.js +543 -0
- package/lib/inbox.js +226 -0
- package/lib/lifecycle.js +929 -0
- package/lib/merge.js +157 -0
- package/lib/milestone.js +595 -0
- package/lib/paths.js +191 -0
- package/lib/provider.js +168 -0
- package/lib/roadmap.js +134 -0
- package/lib/state.js +99 -0
- package/lib/worktree.js +253 -0
- package/package.json +45 -0
- package/templates/DESIGN.md +78 -0
- package/templates/INBOX.md +13 -0
- package/templates/MILESTONE-CONTEXT.md +40 -0
- package/templates/MILESTONES.md +29 -0
- package/templates/PLAN.md +84 -0
- package/templates/PROJECT.md +43 -0
- package/templates/REVIEW-LOG.md +38 -0
- package/templates/ROADMAP.md +34 -0
- package/templates/STATE.md +78 -0
- package/templates/SUMMARY.md +75 -0
- package/templates/codebase/ARCHITECTURE.md +30 -0
- package/templates/codebase/CONCERNS.md +30 -0
- package/templates/codebase/CONVENTIONS.md +30 -0
- package/templates/codebase/INTEGRATIONS.md +30 -0
- package/templates/codebase/STACK.md +26 -0
- package/templates/codebase/STRUCTURE.md +32 -0
- package/templates/codebase/TESTING.md +39 -0
- package/templates/config.json +173 -0
- package/templates/phase-PLAN.md +32 -0
- package/templates/quick-PLAN.md +24 -0
- package/templates/quick-SUMMARY.md +25 -0
package/lib/worktree.js
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* lib/worktree.js — pure helpers for `cp worktree {create,list,remove}`.
|
|
5
|
+
*
|
|
6
|
+
* The cp worktree workflow is intentionally minimal: cp wraps `git worktree`
|
|
7
|
+
* with sensible defaults (sibling-directory layout, `cp/<slug>` branch name)
|
|
8
|
+
* and records a row per worktree in `.planning/WORKTREES.md` for traceability
|
|
9
|
+
* across phases and resumption.
|
|
10
|
+
*
|
|
11
|
+
* If the configured workflow provider (default: Superpowers) is installed
|
|
12
|
+
* AND its `worktree` role resolves to a skill (e.g.
|
|
13
|
+
* `using-git-worktrees`), `cmdWorktree` in bin/cp.js prints a hand-off
|
|
14
|
+
* line so the harness knows to invoke that skill. The cp-native behaviour
|
|
15
|
+
* still runs as a fallback / non-delegated path.
|
|
16
|
+
*
|
|
17
|
+
* v0.4.3.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const fs = require('fs');
|
|
21
|
+
const path = require('path');
|
|
22
|
+
const os = require('os');
|
|
23
|
+
const { spawnSync, execSync } = require('child_process');
|
|
24
|
+
const { planningDir } = require('./paths');
|
|
25
|
+
|
|
26
|
+
const WORKTREES_FILENAME = 'WORKTREES.md';
|
|
27
|
+
|
|
28
|
+
/** Conservative slug: lowercase, alphanumeric + hyphen only. */
|
|
29
|
+
function slugify(name) {
|
|
30
|
+
if (typeof name !== 'string') throw new Error('slugify: name must be a string');
|
|
31
|
+
const out = name
|
|
32
|
+
.toLowerCase()
|
|
33
|
+
.replace(/[_\s]+/g, '-')
|
|
34
|
+
.replace(/[^a-z0-9-]/g, '')
|
|
35
|
+
.replace(/-+/g, '-')
|
|
36
|
+
.replace(/^-|-$/g, '');
|
|
37
|
+
if (out.length === 0) throw new Error(`slugify: "${name}" produced an empty slug`);
|
|
38
|
+
return out;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Default sibling location for a worktree: `<parent-of-repo>/<repo-name>-<slug>`.
|
|
43
|
+
*
|
|
44
|
+
* /work/projects/myrepo → /work/projects/myrepo-cool-feature
|
|
45
|
+
*
|
|
46
|
+
* The user can override with --path; this is just the default.
|
|
47
|
+
*/
|
|
48
|
+
function defaultWorktreePath(repoRoot, slug) {
|
|
49
|
+
const parent = path.dirname(repoRoot);
|
|
50
|
+
const base = path.basename(repoRoot);
|
|
51
|
+
return path.join(parent, `${base}-${slug}`);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function defaultBranchName(slug) {
|
|
55
|
+
return `cp/${slug}`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Parse the output of `git worktree list --porcelain` into objects:
|
|
60
|
+
* { path, head, branch, bare, detached, locked, prunable }
|
|
61
|
+
*
|
|
62
|
+
* Tolerates the slight differences in older git versions.
|
|
63
|
+
*/
|
|
64
|
+
function parseGitWorktreeList(raw) {
|
|
65
|
+
const trees = [];
|
|
66
|
+
let cur = null;
|
|
67
|
+
for (const rawLine of raw.split(/\r?\n/)) {
|
|
68
|
+
const line = rawLine.replace(/\r$/, '');
|
|
69
|
+
if (line === '') {
|
|
70
|
+
if (cur) { trees.push(cur); cur = null; }
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
if (line.startsWith('worktree ')) {
|
|
74
|
+
if (cur) trees.push(cur);
|
|
75
|
+
cur = { path: line.slice('worktree '.length), branch: null };
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (!cur) continue;
|
|
79
|
+
if (line.startsWith('HEAD ')) cur.head = line.slice('HEAD '.length);
|
|
80
|
+
else if (line.startsWith('branch ')) cur.branch = line.slice('branch '.length).replace(/^refs\/heads\//, '');
|
|
81
|
+
else if (line === 'bare') cur.bare = true;
|
|
82
|
+
else if (line === 'detached') cur.detached = true;
|
|
83
|
+
else if (line.startsWith('locked')) cur.locked = true;
|
|
84
|
+
else if (line.startsWith('prunable')) cur.prunable = true;
|
|
85
|
+
}
|
|
86
|
+
if (cur) trees.push(cur);
|
|
87
|
+
return trees;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Render the WORKTREES.md registry from an array of `{ path, branch, slug,
|
|
92
|
+
* phase?, created, notes? }` entries. Stable order: created ascending.
|
|
93
|
+
*/
|
|
94
|
+
function renderWorktreesDoc(entries) {
|
|
95
|
+
const lines = [
|
|
96
|
+
'# Worktrees',
|
|
97
|
+
'',
|
|
98
|
+
'> cp-managed git worktrees for this project. Use `cp worktree create`',
|
|
99
|
+
'> to add an entry. Each row pairs a sibling worktree directory with a',
|
|
100
|
+
'> short slug and (optionally) a phase number for traceability.',
|
|
101
|
+
'',
|
|
102
|
+
'| Slug | Branch | Path | Phase | Created | Notes |',
|
|
103
|
+
'|------|--------|------|-------|---------|-------|',
|
|
104
|
+
];
|
|
105
|
+
const sorted = entries.slice().sort((a, b) => String(a.created).localeCompare(String(b.created)));
|
|
106
|
+
for (const e of sorted) {
|
|
107
|
+
lines.push(`| ${e.slug} | ${e.branch} | ${e.path} | ${e.phase || '—'} | ${e.created} | ${e.notes || ''} |`);
|
|
108
|
+
}
|
|
109
|
+
lines.push('');
|
|
110
|
+
return lines.join('\n');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Parse WORKTREES.md back to an array of registry entries. Tolerates extra
|
|
115
|
+
* narrative the user added before/after the table.
|
|
116
|
+
*/
|
|
117
|
+
function parseWorktreesDoc(content) {
|
|
118
|
+
if (typeof content !== 'string' || content.length === 0) return [];
|
|
119
|
+
const entries = [];
|
|
120
|
+
for (const line of content.split(/\r?\n/)) {
|
|
121
|
+
if (!line.startsWith('|')) continue;
|
|
122
|
+
if (/^\|\s*-+\s*\|/.test(line)) continue; // separator row
|
|
123
|
+
if (/^\|\s*Slug\s*\|/i.test(line)) continue; // header row
|
|
124
|
+
const cells = line.split('|').slice(1, -1).map((c) => c.trim());
|
|
125
|
+
if (cells.length < 5) continue;
|
|
126
|
+
const [slug, branch, p, phase, created, notes = ''] = cells;
|
|
127
|
+
if (!slug || slug === '—') continue;
|
|
128
|
+
entries.push({
|
|
129
|
+
slug, branch, path: p,
|
|
130
|
+
phase: phase && phase !== '—' ? phase : null,
|
|
131
|
+
created, notes,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
return entries;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/** Path to .planning/WORKTREES.md (does not require the file to exist). */
|
|
138
|
+
function worktreesPath(root) {
|
|
139
|
+
return path.join(planningDir(root), WORKTREES_FILENAME);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Compute the action list to add an entry to .planning/WORKTREES.md.
|
|
144
|
+
* Returns `{ actions, entry, alreadyPresent }`. Uses the lifecycle.writeBatch
|
|
145
|
+
* action shape so the caller can scope its commit and atomic-write through
|
|
146
|
+
* the same pipeline as every other cp lifecycle op.
|
|
147
|
+
*/
|
|
148
|
+
function addRegistryEntry(root, entry) {
|
|
149
|
+
const p = worktreesPath(root);
|
|
150
|
+
const existing = fs.existsSync(p) ? fs.readFileSync(p, 'utf8') : '';
|
|
151
|
+
const entries = parseWorktreesDoc(existing);
|
|
152
|
+
const alreadyPresent = entries.some((e) => e.slug === entry.slug);
|
|
153
|
+
if (!alreadyPresent) entries.push(entry);
|
|
154
|
+
const after = renderWorktreesDoc(entries);
|
|
155
|
+
return {
|
|
156
|
+
actions: [{ kind: 'write', path: p, after, label: 'add-worktree-entry' }],
|
|
157
|
+
entry,
|
|
158
|
+
alreadyPresent,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Compute the action list to remove an entry from .planning/WORKTREES.md by slug.
|
|
164
|
+
* Returns `{ actions, removed }` where `removed` is the entry that was removed
|
|
165
|
+
* (or null if no such slug).
|
|
166
|
+
*/
|
|
167
|
+
function removeRegistryEntry(root, slug) {
|
|
168
|
+
const p = worktreesPath(root);
|
|
169
|
+
if (!fs.existsSync(p)) return { actions: [], removed: null };
|
|
170
|
+
const entries = parseWorktreesDoc(fs.readFileSync(p, 'utf8'));
|
|
171
|
+
const removed = entries.find((e) => e.slug === slug) || null;
|
|
172
|
+
if (!removed) return { actions: [], removed: null };
|
|
173
|
+
const remaining = entries.filter((e) => e.slug !== slug);
|
|
174
|
+
const after = renderWorktreesDoc(remaining);
|
|
175
|
+
return {
|
|
176
|
+
actions: [{ kind: 'write', path: p, after, label: 'remove-worktree-entry' }],
|
|
177
|
+
removed,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/** Read current registry. Returns an array of entries (possibly empty). */
|
|
182
|
+
function listRegistry(root) {
|
|
183
|
+
const p = worktreesPath(root);
|
|
184
|
+
if (!fs.existsSync(p)) return [];
|
|
185
|
+
return parseWorktreesDoc(fs.readFileSync(p, 'utf8'));
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function isoDay(d = new Date()) {
|
|
189
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
190
|
+
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Shell out to `git worktree add <path> -b <branch> [<from>]`.
|
|
195
|
+
* Returns the raw spawnSync result (`{ status, stdout, stderr, error }`).
|
|
196
|
+
* The CLI layer owns printing and exit codes; this function is the only
|
|
197
|
+
* place where `git worktree add` is invoked.
|
|
198
|
+
*
|
|
199
|
+
* v0.4.4 — extracted from bin/cp.js so the shell-out lives next to the rest
|
|
200
|
+
* of the worktree lib (matches the pattern in lib/lifecycle.js).
|
|
201
|
+
*/
|
|
202
|
+
function runGitWorktreeAdd(root, { worktreePath, branch, from } = {}) {
|
|
203
|
+
const args = ['worktree', 'add', worktreePath, '-b', branch];
|
|
204
|
+
if (from) args.push(from);
|
|
205
|
+
return spawnSync('git', args, { cwd: root, encoding: 'utf8' });
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Shell out to `git worktree remove [--force] <path>`. Returns the raw
|
|
210
|
+
* spawnSync result. v0.4.4.
|
|
211
|
+
*/
|
|
212
|
+
function runGitWorktreeRemove(root, { worktreePath, force } = {}) {
|
|
213
|
+
const args = ['worktree', 'remove'];
|
|
214
|
+
if (force) args.push('--force');
|
|
215
|
+
args.push(worktreePath);
|
|
216
|
+
return spawnSync('git', args, { cwd: root, encoding: 'utf8' });
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Shell out to `git worktree list --porcelain` and parse the output.
|
|
221
|
+
* Returns an array of `{ path, head, branch, ... }` objects. Swallows
|
|
222
|
+
* errors (returns `[]`) so callers can use it for best-effort
|
|
223
|
+
* cross-referencing without crashing in non-git contexts. v0.4.4.
|
|
224
|
+
*/
|
|
225
|
+
function listGitWorktrees(root) {
|
|
226
|
+
try {
|
|
227
|
+
const raw = execSync('git worktree list --porcelain', {
|
|
228
|
+
cwd: root,
|
|
229
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
230
|
+
}).toString();
|
|
231
|
+
return parseGitWorktreeList(raw);
|
|
232
|
+
} catch {
|
|
233
|
+
return [];
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
module.exports = {
|
|
238
|
+
WORKTREES_FILENAME,
|
|
239
|
+
worktreesPath,
|
|
240
|
+
slugify,
|
|
241
|
+
defaultWorktreePath,
|
|
242
|
+
defaultBranchName,
|
|
243
|
+
parseGitWorktreeList,
|
|
244
|
+
renderWorktreesDoc,
|
|
245
|
+
parseWorktreesDoc,
|
|
246
|
+
addRegistryEntry,
|
|
247
|
+
removeRegistryEntry,
|
|
248
|
+
listRegistry,
|
|
249
|
+
isoDay,
|
|
250
|
+
runGitWorktreeAdd,
|
|
251
|
+
runGitWorktreeRemove,
|
|
252
|
+
listGitWorktrees,
|
|
253
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "context-planning",
|
|
3
|
+
"version": "0.7.0",
|
|
4
|
+
"description": "Lightweight stateful context-management plugin that delegates dev workflow to Superpowers (or any compatible provider).",
|
|
5
|
+
"bin": {
|
|
6
|
+
"cp": "bin/cp.js",
|
|
7
|
+
"cplan": "bin/cp.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"bin",
|
|
11
|
+
"commands",
|
|
12
|
+
"install",
|
|
13
|
+
"lib",
|
|
14
|
+
"templates",
|
|
15
|
+
"docs",
|
|
16
|
+
"README.md"
|
|
17
|
+
],
|
|
18
|
+
"keywords": [
|
|
19
|
+
"ai",
|
|
20
|
+
"context",
|
|
21
|
+
"planning",
|
|
22
|
+
"milestone",
|
|
23
|
+
"superpowers",
|
|
24
|
+
"copilot-cli",
|
|
25
|
+
"claude-code"
|
|
26
|
+
],
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=18.0.0"
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"install:copilot": "node bin/cp.js install copilot",
|
|
33
|
+
"install:claude": "node bin/cp.js install claude",
|
|
34
|
+
"doctor": "node bin/cp.js doctor",
|
|
35
|
+
"test": "node test/roundtrip-gsd.js && node test/dryrun-progress.js && node test/dryrun-complete-milestone.js && node test/dryrun-gsd-import.js && node test/dryrun-resume.js && node test/unit-libs.js && node test/unit-detect.js && node test/unit-merge.js && node test/dryrun-doctor.js && node test/dryrun-config-refresh.js && node test/unit-lifecycle.js && node test/unit-codebase.js && node test/unit-atomic.js && node test/unit-gitcommit.js && node test/unit-v034.js && node test/unit-inbox.js && node test/unit-statusline.js && node test/unit-installers.js && node test/unit-worktree.js && node test/unit-design.js",
|
|
36
|
+
"coverage": "c8 --reporter=text --reporter=html npm test",
|
|
37
|
+
"coverage:ci": "c8 --reporter=text --reporter=lcov --reporter=json-summary --check-coverage --lines 85 --branches 75 npm test"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"yaml": "^2.9.0"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"c8": "^10.1.3"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
# Tier marker: cp scaffold substitutes one of:
|
|
3
|
+
# phase: "{{PHASE_NUM}}" (for phase-tier DESIGN.md)
|
|
4
|
+
# milestone_slug: "{{MILESTONE_SLUG}}" (for milestone-tier DESIGN.md)
|
|
5
|
+
{{TIER_KEY}}
|
|
6
|
+
milestone: {{MILESTONE_NAME}}
|
|
7
|
+
status: proposed
|
|
8
|
+
created: {{DATE}}
|
|
9
|
+
updated: {{DATE}}
|
|
10
|
+
deciders: []
|
|
11
|
+
supersedes: []
|
|
12
|
+
superseded_by: null
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Design: {{TITLE}}
|
|
16
|
+
|
|
17
|
+
## Status
|
|
18
|
+
|
|
19
|
+
{Proposed | Accepted on YYYY-MM-DD | Superseded by …}
|
|
20
|
+
|
|
21
|
+
## Context
|
|
22
|
+
|
|
23
|
+
<!-- Forces driving this design: constraints, prior decisions, requirements. -->
|
|
24
|
+
|
|
25
|
+
## Decision
|
|
26
|
+
|
|
27
|
+
<!-- What we decided. Short, declarative. -->
|
|
28
|
+
|
|
29
|
+
## Consequences
|
|
30
|
+
|
|
31
|
+
### Positive
|
|
32
|
+
-
|
|
33
|
+
|
|
34
|
+
### Negative
|
|
35
|
+
-
|
|
36
|
+
|
|
37
|
+
### Neutral
|
|
38
|
+
-
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Architecture
|
|
43
|
+
|
|
44
|
+
<!-- Boxes-and-lines, ASCII diagrams welcome. -->
|
|
45
|
+
|
|
46
|
+
## Components
|
|
47
|
+
|
|
48
|
+
<!-- Each unit: name, purpose, public interface, dependencies. -->
|
|
49
|
+
|
|
50
|
+
## Data Flow
|
|
51
|
+
|
|
52
|
+
<!-- How data moves through the components. -->
|
|
53
|
+
|
|
54
|
+
## Error Handling
|
|
55
|
+
|
|
56
|
+
<!-- Failure modes and recovery. -->
|
|
57
|
+
|
|
58
|
+
## Testing Strategy
|
|
59
|
+
|
|
60
|
+
<!-- Unit / integration / e2e split, coverage targets. -->
|
|
61
|
+
|
|
62
|
+
## Alternatives Considered
|
|
63
|
+
|
|
64
|
+
### Option A — <name>
|
|
65
|
+
|
|
66
|
+
**Pros:**
|
|
67
|
+
|
|
68
|
+
**Cons:**
|
|
69
|
+
|
|
70
|
+
**Verdict:** rejected because…
|
|
71
|
+
|
|
72
|
+
## Open Questions
|
|
73
|
+
|
|
74
|
+
- [ ]
|
|
75
|
+
|
|
76
|
+
## References
|
|
77
|
+
|
|
78
|
+
-
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Inbox
|
|
2
|
+
|
|
3
|
+
Quick captures awaiting triage. Use `cp capture "..."` to add an item,
|
|
4
|
+
`cp inbox` to list, and the `/cp-capture` slash command to process them
|
|
5
|
+
interactively (route each to a quick task, phase, seed, or discard).
|
|
6
|
+
|
|
7
|
+
## Open
|
|
8
|
+
|
|
9
|
+
<!-- new items get appended here as: `- [ ] [YYYY-MM-DDTHH:mm] <text>` -->
|
|
10
|
+
|
|
11
|
+
## Triaged
|
|
12
|
+
|
|
13
|
+
<!-- triaged items move here as: `- [x] [YYYY-MM-DDTHH:mm] → <destination>: <text>` -->
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Milestone Context: {{MILESTONE_NAME}}
|
|
2
|
+
|
|
3
|
+
<!--
|
|
4
|
+
Transient document written by /cp-new-milestone after the workflow provider's
|
|
5
|
+
`brainstorm` skill returns its design. Consumed by /cp-plan-phase and then
|
|
6
|
+
typically deleted (or moved to .planning/milestones/{slug}/) once all phases
|
|
7
|
+
in the milestone are planned.
|
|
8
|
+
|
|
9
|
+
This is the same name and role as GSD's MILESTONE-CONTEXT.md, so a GSD
|
|
10
|
+
workflow can pick up the same file.
|
|
11
|
+
-->
|
|
12
|
+
|
|
13
|
+
## Goals
|
|
14
|
+
|
|
15
|
+
<!-- The specific outcomes this milestone delivers, in the user's words. -->
|
|
16
|
+
|
|
17
|
+
## In Scope
|
|
18
|
+
|
|
19
|
+
- {feature/change 1}
|
|
20
|
+
- {feature/change 2}
|
|
21
|
+
|
|
22
|
+
## Out of Scope
|
|
23
|
+
|
|
24
|
+
- {explicit exclusion 1} — {why}
|
|
25
|
+
|
|
26
|
+
## Constraints
|
|
27
|
+
|
|
28
|
+
- {tech/timeline/compat constraint}
|
|
29
|
+
|
|
30
|
+
## Proposed Phase Breakdown
|
|
31
|
+
|
|
32
|
+
<!-- The brainstorm skill's recommended phase split. /cp-new-milestone uses
|
|
33
|
+
this to populate ROADMAP.md. -->
|
|
34
|
+
|
|
35
|
+
1. **Phase N: {name}** — {one-line goal}
|
|
36
|
+
2. **Phase N+1: {name}** — {one-line goal}
|
|
37
|
+
|
|
38
|
+
## Decisions Captured
|
|
39
|
+
|
|
40
|
+
- {decision} — {rationale}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Project Milestones: {{PROJECT_NAME}}
|
|
2
|
+
|
|
3
|
+
<!-- Entries in reverse chronological order — newest first.
|
|
4
|
+
Append a block via /cp-complete-milestone. -->
|
|
5
|
+
|
|
6
|
+
<!-- Template per milestone:
|
|
7
|
+
|
|
8
|
+
## v[X.Y] [Name] (Shipped: YYYY-MM-DD)
|
|
9
|
+
|
|
10
|
+
**Delivered:** [One sentence describing what shipped]
|
|
11
|
+
|
|
12
|
+
**Phases completed:** [X-Y] ([Z] plans total)
|
|
13
|
+
|
|
14
|
+
**Key accomplishments:**
|
|
15
|
+
- [Major achievement 1]
|
|
16
|
+
- [Major achievement 2]
|
|
17
|
+
- [Major achievement 3]
|
|
18
|
+
|
|
19
|
+
**Stats:**
|
|
20
|
+
- [X] files created/modified
|
|
21
|
+
- [Y] lines of code (primary language)
|
|
22
|
+
- [Z] phases, [N] plans
|
|
23
|
+
|
|
24
|
+
**Git range:** `feat(XX-XX)` → `feat(YY-YY)`
|
|
25
|
+
|
|
26
|
+
**What's next:** [Brief description of next milestone goals]
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
-->
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
---
|
|
2
|
+
phase: {{PHASE_DIR}}
|
|
3
|
+
plan: {{PLAN_NUM_PADDED}}
|
|
4
|
+
type: execute
|
|
5
|
+
wave: {{WAVE}}
|
|
6
|
+
depends_on: []
|
|
7
|
+
files_modified: []
|
|
8
|
+
autonomous: true
|
|
9
|
+
requirements: []
|
|
10
|
+
user_setup: []
|
|
11
|
+
|
|
12
|
+
# Goal-backward verification (derived during planning, verified after execution)
|
|
13
|
+
must_haves:
|
|
14
|
+
truths: []
|
|
15
|
+
artifacts: []
|
|
16
|
+
key_links: []
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
<objective>
|
|
20
|
+
{{OBJECTIVE}}
|
|
21
|
+
|
|
22
|
+
Purpose: {{PURPOSE}}
|
|
23
|
+
Output: {{OUTPUT}}
|
|
24
|
+
</objective>
|
|
25
|
+
|
|
26
|
+
<execution_context>
|
|
27
|
+
@.planning/config.json
|
|
28
|
+
</execution_context>
|
|
29
|
+
|
|
30
|
+
<context>
|
|
31
|
+
@.planning/PROJECT.md
|
|
32
|
+
@.planning/ROADMAP.md
|
|
33
|
+
@.planning/STATE.md
|
|
34
|
+
|
|
35
|
+
<!--
|
|
36
|
+
Only reference prior plan SUMMARYs if genuinely needed:
|
|
37
|
+
- This plan uses types/exports from prior plan
|
|
38
|
+
- Prior plan made a decision that affects this plan
|
|
39
|
+
Do NOT reflexively chain summaries together.
|
|
40
|
+
-->
|
|
41
|
+
</context>
|
|
42
|
+
|
|
43
|
+
<tasks>
|
|
44
|
+
|
|
45
|
+
<!--
|
|
46
|
+
This section is owned by the workflow provider (configured: {{PROVIDER}},
|
|
47
|
+
plan skill: {{PLAN_SKILL}}). The provider replaces this comment with one
|
|
48
|
+
<task>…</task> block per actionable step. Each task should be 2-5 minutes,
|
|
49
|
+
file-scoped, and have a measurable verify/acceptance criterion.
|
|
50
|
+
|
|
51
|
+
GSD-compatible task shape:
|
|
52
|
+
|
|
53
|
+
<task type="auto">
|
|
54
|
+
<name>Task N: action-oriented name</name>
|
|
55
|
+
<files>path/to/file.ext</files>
|
|
56
|
+
<read_first>path/to/reference.ext</read_first>
|
|
57
|
+
<action>What to do, with concrete values</action>
|
|
58
|
+
<verify>Command or check that proves it worked</verify>
|
|
59
|
+
<acceptance_criteria>
|
|
60
|
+
- Grep-verifiable condition
|
|
61
|
+
</acceptance_criteria>
|
|
62
|
+
<done>Measurable acceptance criteria</done>
|
|
63
|
+
</task>
|
|
64
|
+
-->
|
|
65
|
+
|
|
66
|
+
</tasks>
|
|
67
|
+
|
|
68
|
+
<verification>
|
|
69
|
+
Before declaring plan complete:
|
|
70
|
+
- [ ] {test command}
|
|
71
|
+
- [ ] {build / type check passes}
|
|
72
|
+
- [ ] {behavior verification}
|
|
73
|
+
</verification>
|
|
74
|
+
|
|
75
|
+
<success_criteria>
|
|
76
|
+
- All tasks completed
|
|
77
|
+
- All verification checks pass
|
|
78
|
+
- No errors or warnings introduced
|
|
79
|
+
- {plan-specific criteria}
|
|
80
|
+
</success_criteria>
|
|
81
|
+
|
|
82
|
+
<output>
|
|
83
|
+
After completion, create `.planning/phases/{{PHASE_DIR}}/{{PHASE_PLAN_PREFIX}}-SUMMARY.md`
|
|
84
|
+
</output>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# {{PROJECT_NAME}}
|
|
2
|
+
|
|
3
|
+
## What This Is
|
|
4
|
+
|
|
5
|
+
<!-- 2-3 sentences. What does this product do and who is it for? -->
|
|
6
|
+
|
|
7
|
+
## Core Value
|
|
8
|
+
|
|
9
|
+
<!-- The ONE thing that matters most. If everything else fails, this must work. -->
|
|
10
|
+
|
|
11
|
+
## Requirements
|
|
12
|
+
|
|
13
|
+
### Validated
|
|
14
|
+
<!-- Shipped and confirmed valuable. Format: `- ✓ {requirement} — {milestone}` -->
|
|
15
|
+
|
|
16
|
+
(None yet — ship to validate)
|
|
17
|
+
|
|
18
|
+
### Active
|
|
19
|
+
<!-- Current scope. Building toward these. -->
|
|
20
|
+
|
|
21
|
+
- [ ] {Requirement 1}
|
|
22
|
+
|
|
23
|
+
### Out of Scope
|
|
24
|
+
<!-- Explicit boundaries. Always include reasoning. -->
|
|
25
|
+
|
|
26
|
+
(None yet)
|
|
27
|
+
|
|
28
|
+
## Context
|
|
29
|
+
|
|
30
|
+
<!-- Background that informs implementation: stack, prior work, user feedback, known issues. -->
|
|
31
|
+
|
|
32
|
+
## Constraints
|
|
33
|
+
|
|
34
|
+
<!-- Hard limits. Format: `- **{Type}**: {What} — {Why}` -->
|
|
35
|
+
|
|
36
|
+
## Key Decisions
|
|
37
|
+
|
|
38
|
+
| Decision | Rationale | Outcome |
|
|
39
|
+
|----------|-----------|---------|
|
|
40
|
+
| | | |
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
*Last updated: {{DATE}} after {{TRIGGER}}*
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
phase: "{{PHASE_NUM}}"
|
|
3
|
+
milestone: {{MILESTONE_NAME}}
|
|
4
|
+
created: {{DATE}}
|
|
5
|
+
schema_version: 1
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Review Log: Phase {{PHASE_NUM}} — {{TITLE}}
|
|
9
|
+
|
|
10
|
+
Append-only log of subagent review cycles during execution. Each entry is
|
|
11
|
+
written by the cp-execute-phase orchestrator after a review round
|
|
12
|
+
(spec-compliance or code-quality). The cp aggregator counts entries when
|
|
13
|
+
rolling up the milestone summary.
|
|
14
|
+
|
|
15
|
+
## How to append
|
|
16
|
+
|
|
17
|
+
The orchestrator (cp-execute-phase Step 4.5) appends a block per review:
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
## YYYY-MM-DD HH:MM — Plan NN-MM Task N — <reviewer-role>
|
|
21
|
+
|
|
22
|
+
**Verdict:** approved | rejected | needs-revision
|
|
23
|
+
|
|
24
|
+
**Findings:**
|
|
25
|
+
|
|
26
|
+
- <finding>
|
|
27
|
+
|
|
28
|
+
**Resolution:**
|
|
29
|
+
|
|
30
|
+
<what changed; commit SHA if applied>
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Entries
|
|
36
|
+
|
|
37
|
+
<!-- orchestrator appends below this marker; do not delete the marker -->
|
|
38
|
+
<!-- REVIEW-LOG-ENTRIES-BELOW -->
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Roadmap: {{PROJECT_NAME}}
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
<!-- One paragraph: the journey from here to shipped. -->
|
|
6
|
+
|
|
7
|
+
## Phases
|
|
8
|
+
|
|
9
|
+
<!--
|
|
10
|
+
Milestone heading shape (parsed by lib/milestone.js findMilestoneInRoadmap):
|
|
11
|
+
### 🚧 v0.1 — name (In Progress) (active)
|
|
12
|
+
### 📋 v0.2 — name (Planned) (queued)
|
|
13
|
+
### ✅ v0.1 — name (Shipped YYYY-MM-DD) — wraps a <details> block after close-out
|
|
14
|
+
|
|
15
|
+
Phase heading shape (must follow a milestone heading):
|
|
16
|
+
### Phase 1: name
|
|
17
|
+
### Phase 2.1: name (decimal = urgent insert between integers)
|
|
18
|
+
|
|
19
|
+
After /cp-complete-milestone the milestone heading is replaced with a collapsed
|
|
20
|
+
<details><summary>...</summary>...</details> block; phase headings remain inside.
|
|
21
|
+
|
|
22
|
+
Start your first milestone with:
|
|
23
|
+
cp scaffold-milestone "v0.1 — <your milestone name>"
|
|
24
|
+
cp scaffold-phase 1 --name "<phase name>" --plans <count>
|
|
25
|
+
-->
|
|
26
|
+
|
|
27
|
+
## Progress
|
|
28
|
+
|
|
29
|
+
**Execution Order:**
|
|
30
|
+
Phases execute in numeric order (decimal phases like 2.1 are urgent inserts between integers).
|
|
31
|
+
|
|
32
|
+
| Phase | Milestone | Plans Complete | Status | Completed |
|
|
33
|
+
|-------|-----------|----------------|--------|-----------|
|
|
34
|
+
| *(none yet — run `cp scaffold-phase 1 --name <name> --plans <count>`)* | | | | |
|