viepilot 2.4.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.
- package/CHANGELOG.md +127 -0
- package/README.md +6 -5
- package/docs/brainstorm/session-2026-04-11.md +194 -0
- package/docs/skills-reference.md +46 -0
- package/docs/user/features/proposal.md +196 -0
- package/lib/google-slides-exporter.cjs +80 -0
- package/lib/proposal-generator.cjs +249 -0
- package/lib/screenshot-artifact.cjs +142 -0
- package/lib/viepilot-config.cjs +32 -1
- package/package.json +8 -1
- package/skills/vp-audit/SKILL.md +11 -0
- package/skills/vp-crystallize/SKILL.md +27 -0
- package/skills/vp-proposal/SKILL.md +175 -0
- package/templates/proposal/docx/project-detail.docx +0 -0
- package/templates/proposal/pptx/general.pptx +0 -0
- package/templates/proposal/pptx/product-pitch.pptx +0 -0
- package/templates/proposal/pptx/project-proposal-creative.pptx +0 -0
- package/templates/proposal/pptx/project-proposal-enterprise.pptx +0 -0
- package/templates/proposal/pptx/project-proposal-modern-tech.pptx +0 -0
- package/templates/proposal/pptx/project-proposal.pptx +0 -0
- package/templates/proposal/pptx/tech-architecture.pptx +0 -0
- package/workflows/crystallize.md +514 -0
- package/workflows/proposal.md +807 -0
package/workflows/crystallize.md
CHANGED
|
@@ -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
|
|