fix: align new-project map gate and guard onboarding summary overwrite

init new-project now uses the same seven-file codebase map completeness
check as init onboard, so partial .planning/codebase/ directories no longer
skip the brownfield mapping offer after onboarding warns about an incomplete
map.

The onboard workflow now branches on onboarding_summary_exists and asks for
confirmation before regenerating SUMMARY.md on repeat runs.
This commit is contained in:
Cursor Agent
2026-07-03 15:30:48 +00:00
committed by Codesmith
parent 53f81ab5a9
commit 7b3bf9be3f
3 changed files with 36 additions and 4 deletions

View File

@@ -177,6 +177,33 @@ true, continue.
Create `.planning/onboarding/SUMMARY.md` only after PROJECT.md exists. If it already
exists, update it only after confirmation; do not overwrite silently.
If `onboarding_summary_exists` is true:
- If `TEXT_MODE=true`, print:
```text
Onboarding summary already exists at .planning/onboarding/SUMMARY.md.
1. Update summary — regenerate from current artifact status (Recommended)
2. Keep existing summary — skip writing
Enter number:
```
Stop and wait for the user's reply.
- Otherwise use AskUserQuestion:
- header: "Onboarding Summary"
- question: "Onboarding summary already exists. Update it from current artifact status?"
- options:
- "Update summary" — Regenerate `.planning/onboarding/SUMMARY.md` (Recommended)
- "Keep existing summary" — Skip writing
If the user chooses to keep the existing summary, skip to Step 7 without writing.
If `onboarding_summary_exists` is false or the user confirms an update, write the summary
using the template below.
Summary contents:
```markdown

View File

@@ -747,6 +747,9 @@ function cmdInitNewProject(cwd: string, raw: boolean): void {
const hasCode = hasCodeFilesInternal(cwd);
const hasPackageFile = hasPackageFileInternal(cwd);
const isBrownfield = hasCode || hasPackageFile;
const codebaseMapFiles = listCodebaseMapFiles(cwd);
const hasCodebaseMap = codebaseMapFiles.length === REQUIRED_CODEBASE_MAP_FILES.length;
const result: Record<string, unknown> = {
researcher_model: resolveModelInternal(cwd, 'gsd-project-researcher'),
@@ -756,14 +759,13 @@ function cmdInitNewProject(cwd: string, raw: boolean): void {
commit_docs: config.commit_docs,
project_exists: pathExistsInternal(cwd, '.planning/PROJECT.md'),
has_codebase_map: pathExistsInternal(cwd, '.planning/codebase'),
has_codebase_map: hasCodebaseMap,
planning_exists: pathExistsInternal(cwd, '.planning'),
has_existing_code: hasCode,
has_package_file: hasPackageFile,
is_brownfield: hasCode || hasPackageFile,
needs_codebase_map:
(hasCode || hasPackageFile) && !pathExistsInternal(cwd, '.planning/codebase'),
is_brownfield: isBrownfield,
needs_codebase_map: isBrownfield && !hasCodebaseMap,
...getInitGitState(cwd),

View File

@@ -1599,6 +1599,9 @@ describe('cmdInitNewProject', () => {
test('brownfield with codebase map does not need map', () => {
fs.writeFileSync(path.join(tmpDir, 'package.json'), '{"name":"test"}');
fs.mkdirSync(path.join(tmpDir, '.planning', 'codebase'), { recursive: true });
for (const name of ['STACK', 'ARCHITECTURE', 'STRUCTURE', 'CONVENTIONS', 'TESTING', 'INTEGRATIONS', 'CONCERNS']) {
fs.writeFileSync(path.join(tmpDir, '.planning', 'codebase', `${name}.md`), `# ${name}\n`);
}
const result = runGsdTools('init new-project', tmpDir);
assert.ok(result.success, `Command failed: ${result.error}`);