viepilot 2.1.0 → 2.12.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.
Files changed (48) hide show
  1. package/CHANGELOG.md +220 -0
  2. package/README.md +32 -21
  3. package/bin/viepilot.cjs +12 -4
  4. package/docs/brainstorm/session-2026-04-11.md +194 -0
  5. package/docs/skills-reference.md +46 -0
  6. package/docs/user/features/adapters.md +74 -0
  7. package/docs/user/features/proposal.md +196 -0
  8. package/lib/adapters/antigravity.cjs +33 -0
  9. package/lib/adapters/claude-code.cjs +2 -2
  10. package/lib/adapters/codex.cjs +34 -0
  11. package/lib/adapters/cursor.cjs +2 -1
  12. package/lib/adapters/index.cjs +4 -2
  13. package/lib/google-slides-exporter.cjs +80 -0
  14. package/lib/proposal-generator.cjs +249 -0
  15. package/lib/screenshot-artifact.cjs +142 -0
  16. package/lib/viepilot-config.cjs +32 -1
  17. package/lib/viepilot-install.cjs +8 -10
  18. package/package.json +8 -3
  19. package/skills/vp-audit/SKILL.md +13 -2
  20. package/skills/vp-auto/SKILL.md +2 -2
  21. package/skills/vp-brainstorm/SKILL.md +2 -2
  22. package/skills/vp-crystallize/SKILL.md +30 -3
  23. package/skills/vp-debug/SKILL.md +2 -2
  24. package/skills/vp-docs/SKILL.md +1 -1
  25. package/skills/vp-evolve/SKILL.md +1 -1
  26. package/skills/vp-info/SKILL.md +1 -1
  27. package/skills/vp-pause/SKILL.md +2 -2
  28. package/skills/vp-proposal/SKILL.md +175 -0
  29. package/skills/vp-request/SKILL.md +2 -2
  30. package/skills/vp-resume/SKILL.md +2 -2
  31. package/skills/vp-rollback/SKILL.md +1 -1
  32. package/skills/vp-ui-components/SKILL.md +2 -2
  33. package/skills/vp-update/SKILL.md +1 -1
  34. package/templates/proposal/docx/project-detail.docx +0 -0
  35. package/templates/proposal/pptx/general.pptx +0 -0
  36. package/templates/proposal/pptx/product-pitch.pptx +0 -0
  37. package/templates/proposal/pptx/project-proposal-creative.pptx +0 -0
  38. package/templates/proposal/pptx/project-proposal-enterprise.pptx +0 -0
  39. package/templates/proposal/pptx/project-proposal-modern-tech.pptx +0 -0
  40. package/templates/proposal/pptx/project-proposal.pptx +0 -0
  41. package/templates/proposal/pptx/tech-architecture.pptx +0 -0
  42. package/workflows/autonomous.md +32 -0
  43. package/workflows/brainstorm.md +1 -1
  44. package/workflows/crystallize.md +519 -0
  45. package/workflows/evolve.md +2 -0
  46. package/workflows/proposal.md +807 -0
  47. package/dev-install.sh +0 -171
  48. package/install.sh +0 -125
@@ -104,6 +104,520 @@ Ask the user for project information:
104
104
  Store all metadata for template generation.
105
105
  </step>
106
106
 
107
+ <step name="brownfield_detection">
108
+ ## Step 0-B: Brownfield Mode Detection (FEAT-018)
109
+
110
+ **Trigger brownfield mode when ANY of the following is true:**
111
+ - `--brownfield` flag passed explicitly, OR
112
+ - `docs/brainstorm/` directory does not exist or is empty (no `session-*.md` files) **AND** `.viepilot/` directory does not yet exist
113
+
114
+ **If NEITHER condition is met** (greenfield path): skip this entire step; proceed to Step 1.
115
+
116
+ **If brownfield triggered AND `.viepilot/` already exists:**
117
+ - Warn: "`.viepilot/` already exists. Re-running brownfield mode will overwrite artifacts."
118
+ - Ask: "Continue? (y/n)" — abort if n.
119
+
120
+ **When brownfield mode is active:**
121
+ 1. Run the full 12-category codebase scanner (Signal Categories 1–12 below).
122
+ 2. Produce a structured **Scan Report** (see schema at end of this step).
123
+ 3. Classify every field as DETECTED / ASSUMED / MISSING per Gap Detection Rules.
124
+ 4. Present Scan Report summary to user; interactively fill every MISSING MUST-DETECT field.
125
+ 5. User confirms ASSUMED fields (may accept all or override individually).
126
+ 6. After confirmation: proceed to Step 0-C (brainstorm stub generation).
127
+ 7. Then skip Step 1 (`analyze_brainstorm`); continue from Step 0 (metadata collection) → Step 2 onward using the confirmed Scan Report as input.
128
+
129
+ ---
130
+
131
+ ### Signal Category 1 — Build Manifest & Package Identity
132
+
133
+ Probe the following files in order of priority (first match per language wins):
134
+
135
+ | Language / Platform | Files to probe |
136
+ |---------------------|----------------|
137
+ | Node.js | `package.json` |
138
+ | Java / Maven | `pom.xml` |
139
+ | Java / Gradle | `build.gradle`, `build.gradle.kts`, `settings.gradle` |
140
+ | Python | `pyproject.toml`, `setup.py`, `setup.cfg`, `requirements.txt`, `Pipfile` |
141
+ | Rust | `Cargo.toml` |
142
+ | Go | `go.mod` |
143
+ | PHP | `composer.json` |
144
+ | Ruby | `Gemfile`, `*.gemspec` |
145
+ | .NET | `*.csproj`, `*.sln`, `global.json` |
146
+ | Elixir / Erlang | `mix.exs` |
147
+ | Swift | `Package.swift` |
148
+
149
+ **Fields to extract per manifest:**
150
+ - `project_name` — package name / artifactId / module name
151
+ - `current_version` — version field
152
+ - `primary_language` — derived from manifest type
153
+ - `runtime_version` — engines/node, java.version, python_requires, go version
154
+ - `entry_points` — main, bin, spring-boot:run target, etc.
155
+ - `raw_dependencies[]` — full dependency list (used by Signal Category 2)
156
+ - `raw_dev_dependencies[]` — dev/test deps
157
+
158
+ **Monorepo detection** (check before single-manifest scan):
159
+ - npm workspaces: `package.json` → `"workspaces"` field + `packages/*/package.json`
160
+ - Nx / Turborepo: `nx.json`, `turbo.json` + `apps/*/` and `libs/*/`
161
+ - Maven multi-module: `pom.xml` with `<modules>`
162
+ - Gradle multi-project: `settings.gradle` with `include`
163
+ - Cargo workspace: `Cargo.toml` with `[workspace]`
164
+ - Go workspace: `go.work`
165
+
166
+ If monorepo detected → scan each module separately; aggregate into `modules[]` in Scan Report.
167
+
168
+ If no manifest found → `primary_language` = MISSING; user must provide.
169
+
170
+ ---
171
+
172
+ ### Signal Category 2 — Framework & Library Detection
173
+
174
+ Infer from `raw_dependencies[]` + `raw_dev_dependencies[]`:
175
+
176
+ **Backend frameworks:**
177
+ | Signal pattern | Framework |
178
+ |---------------|-----------|
179
+ | `spring-boot-starter-*` | Spring Boot |
180
+ | `express`, `fastify`, `koa`, `hapi` | Node.js HTTP |
181
+ | `nestjs/core` | NestJS |
182
+ | `fastapi`, `flask`, `django` | Python HTTP |
183
+ | `gin-gonic/gin`, `gofiber/fiber`, `labstack/echo` | Go HTTP |
184
+ | `rails`, `sinatra` | Ruby |
185
+ | `laravel/framework`, `slim/slim` | PHP |
186
+ | `actix-web`, `axum`, `rocket` | Rust HTTP |
187
+ | `phoenix` (mix.exs) | Elixir |
188
+ | `Microsoft.AspNetCore.*` | .NET ASP.NET Core |
189
+
190
+ **Frontend frameworks:**
191
+ | Signal pattern | Framework |
192
+ |---------------|-----------|
193
+ | `react`, `react-dom` | React |
194
+ | `vue` | Vue.js |
195
+ | `@angular/core` | Angular |
196
+ | `svelte` | Svelte |
197
+ | `next` | Next.js |
198
+ | `nuxt` | Nuxt.js |
199
+ | `remix` | Remix |
200
+ | `astro` | Astro |
201
+ | `solid-js` | SolidJS |
202
+
203
+ **ORM / Database clients:**
204
+ | Signal pattern | ORM / DB |
205
+ |---------------|----------|
206
+ | `mybatis-spring-boot-starter`, `mybatis` | MyBatis |
207
+ | `spring-boot-starter-data-jpa`, `hibernate-*` | Hibernate / JPA |
208
+ | `typeorm` | TypeORM |
209
+ | `prisma` | Prisma |
210
+ | `sequelize` | Sequelize |
211
+ | `sqlalchemy`, `alembic` | SQLAlchemy |
212
+ | `gorm.io/gorm` | GORM |
213
+ | `mongoose` | Mongoose (MongoDB) |
214
+ | `pg`, `mysql2`, `mariadb`, `better-sqlite3` | Raw SQL clients |
215
+ | `redis`, `ioredis` | Redis client |
216
+
217
+ **Message broker clients:**
218
+ | Signal pattern | Broker |
219
+ |---------------|--------|
220
+ | `spring-kafka`, `kafka-clients` | Apache Kafka |
221
+ | `amqplib`, `spring-rabbit` | RabbitMQ |
222
+ | `@aws-sdk/client-sqs` | AWS SQS |
223
+ | `nats` | NATS |
224
+ | `bullmq`, `bull` | Redis-based queue |
225
+
226
+ **Auth libraries:**
227
+ | Signal pattern | Auth mechanism |
228
+ |---------------|----------------|
229
+ | `spring-security`, `spring-boot-starter-security` | Spring Security |
230
+ | `jsonwebtoken`, `jose`, `passport-jwt` | JWT |
231
+ | `passport` | OAuth / multi-strategy |
232
+ | `keycloak-*`, `keycloak-connect` | Keycloak |
233
+ | `next-auth`, `@auth/core` | NextAuth |
234
+ | `authlib`, `python-jose`, `djangorestframework-simplejwt` | Python auth |
235
+
236
+ **Test frameworks:**
237
+ | Signal pattern | Framework |
238
+ |---------------|-----------|
239
+ | `jest`, `@jest/core` | Jest |
240
+ | `vitest` | Vitest |
241
+ | `mocha` | Mocha |
242
+ | `jasmine` | Jasmine |
243
+ | `junit`, `spring-boot-starter-test` | JUnit |
244
+ | `pytest` | pytest |
245
+ | `rspec-rails`, `rspec` | RSpec |
246
+ | `cypress` | Cypress E2E |
247
+ | `playwright` | Playwright E2E |
248
+ | `@testing-library/*` | Testing Library |
249
+ | `testify` | Testify (Go) |
250
+
251
+ Rule: If zero backend AND zero frontend frameworks detected → add entry to `open_questions[]` and ask user.
252
+
253
+ ---
254
+
255
+ ### Signal Category 3 — Architecture Layer Inference (Directory Structure)
256
+
257
+ Glob the following path patterns; presence implies the corresponding layer:
258
+
259
+ | Pattern(s) | Inferred layer |
260
+ |------------|----------------|
261
+ | `src/main/java/**`, `src/main/kotlin/**` | Java/Kotlin Maven standard layout |
262
+ | `src/controllers/`, `app/controllers/`, `**/controller/**` | MVC — Controller layer |
263
+ | `src/api/`, `api/`, `routes/`, `src/routes/` | API / Router layer |
264
+ | `src/services/`, `services/`, `**/service/**` | Service / Business logic layer |
265
+ | `src/repositories/`, `repositories/`, `**/repository/**`, `**/dao/**` | Repository / DAO layer |
266
+ | `src/models/`, `models/`, `**/model/**`, `**/entity/**` | Domain models / Entities |
267
+ | `src/middleware/`, `middleware/` | Middleware layer |
268
+ | `src/utils/`, `utils/`, `helpers/`, `common/` | Utilities / Shared |
269
+ | `frontend/`, `client/`, `web/`, `src/client/` | Frontend module |
270
+ | `backend/`, `server/`, `src/server/` | Backend module |
271
+ | `packages/`, `apps/`, `libs/` | Monorepo layout |
272
+ | `infrastructure/`, `infra/`, `terraform/`, `helm/`, `k8s/`, `kubernetes/` | Infrastructure / IaC |
273
+ | `scripts/`, `bin/`, `tools/` | Developer tooling |
274
+ | `public/`, `static/`, `assets/` | Static assets |
275
+ | `docs/`, `documentation/` | Documentation |
276
+ | `config/`, `configs/`, `settings/` | Configuration |
277
+ | `tests/`, `test/`, `__tests__/`, `spec/`, `e2e/` | Test suite root |
278
+ | `migrations/`, `db/migrate/`, `alembic/` | Database migrations |
279
+
280
+ Output: `architecture_layers[]` — each with `{ layer, evidence_path }`.
281
+
282
+ ---
283
+
284
+ ### Signal Category 4 — Database Schema Signals
285
+
286
+ Probe for migration/schema evidence:
287
+
288
+ | Pattern | Evidence type |
289
+ |---------|---------------|
290
+ | `db/migrate/*.rb` | Rails ActiveRecord migrations |
291
+ | `migrations/*.sql`, `migrations/*.js`, `migrations/*.ts` | Generic migrations |
292
+ | `src/main/resources/db/migration/V*.sql` | Flyway |
293
+ | `db/changelog*.xml`, `db/changelog*.yaml` | Liquibase |
294
+ | `alembic/versions/*.py` | SQLAlchemy Alembic |
295
+ | `src/migrations/**` | TypeORM / Sequelize migrations |
296
+ | `prisma/schema.prisma` | Prisma schema |
297
+ | `**/schema.sql`, `**/init.sql`, `**/seed.sql` | Raw SQL schema / seed |
298
+ | `docker-compose.yml` → service names | Implied DB types (postgres, mysql, mongo, redis…) |
299
+
300
+ Output: `database_signals[]` — each with `{ type, evidence_path, migration_tool }`.
301
+
302
+ Rule: If none found but ORM dep exists → `database_signals` = ASSUMED with rationale note.
303
+
304
+ ---
305
+
306
+ ### Signal Category 5 — API Contract Files
307
+
308
+ | File pattern | Contract type |
309
+ |-------------|---------------|
310
+ | `openapi.yaml`, `openapi.json`, `swagger.yaml`, `swagger.json` | OpenAPI / Swagger |
311
+ | `api-docs.yaml`, `api.yaml`, `api-spec.yaml`, `api/*.yaml` | OpenAPI (alternate) |
312
+ | `*.proto`, `proto/**/*.proto` | gRPC / Protocol Buffers |
313
+ | `schema.graphql`, `**/*.graphql` | GraphQL |
314
+ | `src/main/resources/static/v3/api-docs*` | Spring Swagger (generated) |
315
+ | `postman_collection.json`, `*.postman_collection.json` | Postman |
316
+ | `insomnia.yaml`, `.insomnia/` | Insomnia |
317
+
318
+ `api_style` inference:
319
+ - REST → if OpenAPI/Swagger file found
320
+ - gRPC → if `*.proto` found (set `mixed` if REST also found)
321
+ - GraphQL → if `schema.graphql` / `*.graphql` found
322
+ - ASSUMED REST → if REST framework detected but no contract file found
323
+ - MISSING → if api_style still unknown after all signals; user prompted
324
+
325
+ ---
326
+
327
+ ### Signal Category 6 — Infrastructure & Deployment Configuration
328
+
329
+ | File pattern | Deployment signal |
330
+ |-------------|------------------|
331
+ | `Dockerfile` | Containerized — read `FROM` for base image |
332
+ | `docker-compose.yml`, `docker-compose*.yml` | Service topology (list all services) |
333
+ | `.github/workflows/*.yml` | GitHub Actions CI/CD |
334
+ | `.gitlab-ci.yml` | GitLab CI |
335
+ | `Jenkinsfile` | Jenkins pipeline |
336
+ | `.circleci/config.yml` | CircleCI |
337
+ | `bitbucket-pipelines.yml` | Bitbucket Pipelines |
338
+ | `k8s/**/*.yaml`, `kubernetes/**/*.yaml` | Kubernetes manifests |
339
+ | `helm/**`, `Chart.yaml` | Helm charts |
340
+ | `terraform/**/*.tf` | Terraform IaC |
341
+ | `pulumi/**`, `Pulumi.yaml` | Pulumi IaC |
342
+ | `ansible/**`, `playbook.yml` | Ansible |
343
+ | `nginx.conf`, `nginx/**` | Nginx reverse proxy |
344
+ | `serverless.yml`, `serverless.ts` | Serverless Framework |
345
+ | `fly.toml` | Fly.io |
346
+ | `vercel.json`, `.vercel/` | Vercel |
347
+ | `netlify.toml` | Netlify |
348
+ | `render.yaml` | Render |
349
+
350
+ Output: `deployment_signals[]` — each with `{ platform, file_path, notes }`.
351
+
352
+ Rule: If no deployment signal found → `deployment_signals` = MISSING; user prompted.
353
+
354
+ ---
355
+
356
+ ### Signal Category 7 — Environment & Configuration Shape
357
+
358
+ | File pattern | Purpose |
359
+ |-------------|---------|
360
+ | `.env.example`, `.env.sample`, `.env.template` | Required env key shape |
361
+ | `application.properties`, `application.yml`, `application-*.yml` | Spring Boot config |
362
+ | `config/database.yml` | Rails DB config |
363
+ | `config/settings.py`, `config/*.py` | Django / Python config |
364
+ | `appsettings.json`, `appsettings.*.json` | .NET config |
365
+ | `config/config.exs`, `config/runtime.exs` | Elixir config |
366
+ | `config.yaml`, `config.yml` (project root or config/) | Generic config |
367
+
368
+ **Rule:** Read `.env.example` / `.env.sample` / `.env.template` to extract key names into `config_keys[]`.
369
+ **SAFETY: Never read `.env` (live secrets file) — scanner explicitly skips it.**
370
+
371
+ ---
372
+
373
+ ### Signal Category 8 — Test Coverage Signals
374
+
375
+ | File pattern | Test framework |
376
+ |-------------|----------------|
377
+ | `jest.config.js`, `jest.config.ts`, `jest.config.mjs` | Jest |
378
+ | `vitest.config.ts`, `vitest.config.js` | Vitest |
379
+ | `.mocharc.js`, `.mocharc.yaml` | Mocha |
380
+ | `pytest.ini`, `setup.cfg [tool:pytest]`, `pyproject.toml [tool.pytest.ini_options]` | pytest |
381
+ | `karma.conf.js` | Karma |
382
+ | `cypress.config.js`, `cypress.config.ts`, `cypress.json` | Cypress |
383
+ | `playwright.config.ts`, `playwright.config.js` | Playwright |
384
+ | `phpunit.xml`, `phpunit.xml.dist` | PHPUnit |
385
+
386
+ **Coverage indicators:** presence of `coverage/`, `htmlcov/`, `.nyc_output/`, `target/site/jacoco/` → `has_coverage_reports = true`.
387
+
388
+ Output: `test_frameworks[]`, `test_root_dirs[]`, `has_coverage_reports`.
389
+
390
+ Rule: If no test signals found → `test_frameworks` = MISSING; note added to generated `SYSTEM-RULES.md` quality gates section.
391
+
392
+ ---
393
+
394
+ ### Signal Category 9 — Code Quality & Tooling
395
+
396
+ | File pattern | Tool |
397
+ |-------------|------|
398
+ | `.eslintrc*`, `eslint.config.*` | ESLint |
399
+ | `.prettierrc*`, `prettier.config.*` | Prettier |
400
+ | `sonar-project.properties`, `sonar-project.yml` | SonarQube |
401
+ | `.pre-commit-config.yaml` | pre-commit hooks |
402
+ | `checkstyle.xml` | Checkstyle (Java) |
403
+ | `.pylintrc`, `pylint.cfg` | Pylint |
404
+ | `.flake8`, `setup.cfg [flake8]` | Flake8 |
405
+ | `mypy.ini`, `pyproject.toml [tool.mypy]` | mypy |
406
+ | `rustfmt.toml`, `.rustfmt.toml` | rustfmt |
407
+ | `.golangci.yml` | golangci-lint |
408
+ | `.editorconfig` | EditorConfig |
409
+ | `commitlint.config.js`, `.commitlintrc*` | Conventional Commits enforcement |
410
+ | `.husky/` | Husky git hooks |
411
+ | `lint-staged.config.*`, `package.json "lint-staged"` | lint-staged |
412
+
413
+ Output: `quality_tools[]` — used to populate `SYSTEM-RULES.md` quality gates section.
414
+
415
+ ---
416
+
417
+ ### Signal Category 10 — Documentation Files
418
+
419
+ | File | Priority |
420
+ |------|----------|
421
+ | `README.md` | MUST-READ — extract: project name, description, quickstart |
422
+ | `CHANGELOG.md`, `HISTORY.md`, `RELEASES.md` | SHOULD-READ — extract: version history, latest changes |
423
+ | `CONTRIBUTING.md` | SHOULD-READ — extract: contribution rules |
424
+ | `ARCHITECTURE.md`, `docs/architecture*.md` | SHOULD-READ — extract: any existing arch notes |
425
+ | `docs/adr/`, `ADR/`, `decisions/` | SHOULD-READ — Architecture Decision Records |
426
+ | `docs/**/*.md` (top 10 by mtime) | NICE-TO-READ — project-specific docs |
427
+ | `LICENSE` | MUST-READ — extract license type |
428
+
429
+ Output: `docs_extracted[]` — each with `{ file, summary, key_facts[] }`.
430
+
431
+ Rule: If `README.md` absent → `project_name` elevated to MISSING (must ask user).
432
+
433
+ ---
434
+
435
+ ### Signal Category 11 — Git History & Version Signals
436
+
437
+ Run the following git commands (read-only):
438
+
439
+ | Command | Purpose |
440
+ |---------|---------|
441
+ | `git log --oneline -100` | Commit message patterns (Conventional Commits? Jira refs? free-form?) |
442
+ | `git tag --sort=-version:refname \| head -20` | Version history + tag naming convention |
443
+ | `git log --format="%H %s" --diff-filter=A -- "*.md" \| head -20` | When key docs were added |
444
+ | `git branch -a \| head -20` | Branch naming convention |
445
+ | `git log --stat -3` | Most recently changed files |
446
+ | `git shortlog -sn --no-merges \| head -10` | Top contributors |
447
+ | `git remote get-url origin` | Repository URL |
448
+
449
+ Extract: `commit_convention` (Conventional Commits / Jira-ref / free-form / mixed), `version_pattern` (semver / calver / custom), `latest_tag`, `active_branches[]`, `top_contributors[]`, `repo_url`.
450
+
451
+ Rule: If not a git repo → all git fields = MISSING; user warned.
452
+
453
+ ---
454
+
455
+ ### Signal Category 12 — File Extension Language Survey
456
+
457
+ Glob source file extensions to detect secondary languages:
458
+
459
+ ```
460
+ Glob: src/**/*.{ts,tsx,js,jsx,py,java,kt,go,rs,rb,php,cs,swift,ex,exs,scala,clj,elm,dart}
461
+ (also check project root if no src/ directory)
462
+ ```
463
+
464
+ Count files per extension → `language_distribution{}` (e.g. `{ ts: 142, java: 38, sql: 12 }`).
465
+
466
+ Rule: `secondary_languages[]` = languages with ≥5 files that are not `primary_language`.
467
+
468
+ ---
469
+
470
+ ### Scan Report Schema (finalized)
471
+
472
+ After running all 12 signal categories, produce this structured Scan Report:
473
+
474
+ ```yaml
475
+ # ViePilot Brownfield Scan Report
476
+ project_name: string # from manifest or README
477
+ current_version: string # from manifest or latest git tag
478
+ primary_language: string # from manifest
479
+ secondary_languages: [] # from file extension survey
480
+ runtime_version: string # node/java/python/go version
481
+ frameworks:
482
+ backend: []
483
+ frontend: []
484
+ orm: []
485
+ auth: []
486
+ message_broker: []
487
+ build_tool: string
488
+ package_manager: string
489
+ monorepo: bool
490
+ modules: [] # if monorepo
491
+ architecture_layers: [] # { layer, evidence_path }
492
+ database_signals: [] # { type, evidence_path, migration_tool }
493
+ api_contracts: [] # { style, file_path }
494
+ api_style: string # REST | GraphQL | gRPC | mixed | unknown
495
+ deployment_signals: [] # { platform, file_path }
496
+ test_frameworks: []
497
+ test_root_dirs: []
498
+ has_coverage_reports: bool
499
+ quality_tools: []
500
+ config_keys: [] # from .env.example (key names only — no values)
501
+ commit_convention: string # conventional | jira | free-form | mixed
502
+ version_pattern: string # semver | calver | custom
503
+ latest_tag: string
504
+ repo_url: string
505
+ top_contributors: []
506
+ docs_extracted: [] # { file, summary, key_facts[] }
507
+ language_distribution: {} # { ts: 142, java: 38, ... }
508
+ open_questions: [] # fields not resolved by user input
509
+ ```
510
+
511
+ ---
512
+
513
+ ### Gap Detection Rules
514
+
515
+ Every field in Scan Report is classified as:
516
+
517
+ | Status | Meaning | Required action |
518
+ |--------|---------|-----------------|
519
+ | **DETECTED** | Inferred from codebase with high confidence | Show for confirmation — no user action required |
520
+ | **ASSUMED** | Inferred with low confidence or indirect signal | Show to user with rationale; user may correct |
521
+ | **MISSING** | Not found anywhere in codebase | **Must ask user** before generating artifacts |
522
+
523
+ **MUST-DETECT fields** (MISSING = hard blocker — cannot generate artifacts until user fills):
524
+ - `project_name`
525
+ - `primary_language`
526
+ - At least one entry in `frameworks.backend` OR `frameworks.frontend`
527
+ - `current_version`
528
+
529
+ **SHOULD-DETECT fields** (MISSING = warning — document assumption, continue with user acknowledgment):
530
+ - `api_style`
531
+ - At least one entry in `database_signals` (if ORM dep found)
532
+ - `test_frameworks`
533
+ - `commit_convention`
534
+ - `deployment_signals`
535
+
536
+ **NICE-TO-DETECT fields** (MISSING = note only — generate with placeholder):
537
+ - `auth` frameworks, `message_broker`, `config_keys`, `top_contributors`, `has_coverage_reports`
538
+
539
+ **Assumption documentation rule:** For every ASSUMED or MISSING field that proceeds without user fill, append to `open_questions[]` and insert a `> ⚠️ Assumed: {rationale}` callout in the relevant `.viepilot/` artifact section.
540
+
541
+ ---
542
+
543
+ ### Interactive Gap-Filling (Step 0-B-ii)
544
+
545
+ After scanner completes:
546
+
547
+ 1. Display Scan Report summary table to user (field | value | status).
548
+ 2. For each MUST-DETECT field that is MISSING → **pause and ask user to provide value**. Do not proceed until all MUST-DETECT fields are filled.
549
+ 3. Present ASSUMED fields in a confirmation table → user may accept all with "y" or override individually.
550
+ 4. Capture all user responses; update Scan Report fields accordingly.
551
+ 5. All remaining unresolved items → `open_questions[]`.
552
+
553
+ ---
554
+
555
+ ### Brownfield Brainstorm Stub Generation (Step 0-C)
556
+
557
+ After gap-filling is complete, write:
558
+
559
+ **Path:** `docs/brainstorm/session-brownfield-import.md`
560
+
561
+ **Content:**
562
+ ```markdown
563
+ # Brownfield Import — {project_name}
564
+
565
+ ## Meta
566
+ - **Import date**: {scan_date}
567
+ - **Import source**: `vp-crystallize --brownfield`
568
+ - **Scanner version**: FEAT-018
569
+
570
+ ## Scan Report
571
+
572
+ \`\`\`yaml
573
+ {full confirmed Scan Report YAML}
574
+ \`\`\`
575
+ ```
576
+
577
+ **Purpose:** This stub allows `vp-audit` and other ViePilot tools to not error on missing brainstorm session files. The presence of `session-brownfield-import.md` is treated as a valid brownfield import.
578
+
579
+ ---
580
+
581
+ ### Safety Rules
582
+
583
+ The brownfield scanner MUST:
584
+
585
+ ```
586
+ NEVER read:
587
+ .env (live secrets)
588
+ *.key, *.pem, *.p12, *.jks, id_rsa, id_ed25519
589
+
590
+ ALWAYS skip these directories:
591
+ node_modules/
592
+ .git/
593
+ target/
594
+ build/
595
+ dist/
596
+ __pycache__/
597
+ .venv/
598
+ vendor/
599
+
600
+ NEVER write any files until the user has confirmed the Scan Report.
601
+
602
+ NEVER overwrite existing .viepilot/ without explicit user confirmation (y/n prompt).
603
+ ```
604
+
605
+ ---
606
+
607
+ ### TRACKER.md Continuity Annotation
608
+
609
+ When generating TRACKER.md in Step 9 (brownfield mode only), append:
610
+
611
+ ```markdown
612
+ ## Brownfield Import
613
+ - **Import date**: {scan_date}
614
+ - **Imported version**: {current_version}
615
+ - **Note**: Project history pre-dates ViePilot adoption.
616
+ - **Scan Report**: `docs/brainstorm/session-brownfield-import.md`
617
+ ```
618
+
619
+ </step>
620
+
107
621
  <step name="analyze_brainstorm">
108
622
  ## Step 1: Analyze Brainstorm
109
623
 
@@ -140,6 +654,11 @@ If gaps found → ask user to clarify or return to brainstorm.
140
654
  <step name="consume_ui_direction">
141
655
  ## Step 1A: Consume UI Direction Artifacts (for UI/UX projects)
142
656
 
657
+ > ⛔ **PATH GUARD (BUG-011):** The ONLY valid ui-direction path is `.viepilot/ui-direction/`.
658
+ > If a `{root}/ui-direction/` directory exists at the project root — **IGNORE it completely**.
659
+ > It is user-managed reference material, NOT ViePilot artifacts.
660
+ > Never read, glob, or reference any file under `{root}/ui-direction/` in this workflow.
661
+
143
662
  ### UI Scope Detection (ENH-026 hard gate)
144
663
 
145
664
  Before checking for artifacts, scan brainstorm session files (`docs/brainstorm/session-*.md`) for UI signal keywords:
@@ -135,6 +135,8 @@ If unsure of the repo-relative path, inspect:
135
135
  - `ls bin/` → CLI files
136
136
  - `ls templates/` → template files
137
137
 
138
+ **Resolution rule (BUG-012):** Paths in `## Paths` are always resolved from `{cwd}` (the repo root where `package.json` lives) — never from `~/.claude/`, `~/.cursor/`, or any install directory. When both a codebase copy and an installed copy exist, `{cwd}` wins.
139
+
138
140
  ### Create Phase Directory
139
141
  ```bash
140
142
  mkdir -p .viepilot/phases/{NN}-{feature-slug}/tasks/