Move docs/ package mirror into document-navigator plugin
Relocate the ~6k-file docs tree from the repo root into plugins/document-navigator/docs/ so the plugin is self-contained and portable. docs/superpowers/ (specs and plans) stays at the repo root. Moved via cp+rm rather than git mv because directory rename() fails with EPERM on this WSL /mnt DrvFs mount; git rename-detection pairs the identical-content files at commit time. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
# create-suaveplan-plugin (bin)
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
This module is the executable entry-point for the
|
||||
`create-suaveplan-plugin` scaffolder. It parses argv into a
|
||||
`ParsedArgs` record, resolves the matching fixture answer set, and
|
||||
delegates the on-disk work to `scaffold()`. Wrapping the CLI in a
|
||||
single file (with `parseArgs` and `run` exported for in-process
|
||||
testing) keeps the bin layer thin and lets the rest of the package
|
||||
stay framework-agnostic.
|
||||
|
||||
## Features
|
||||
|
||||
- `parseArgs(argv)` — positional plugin name plus `--fixture`,
|
||||
`--force`, `--dir` flags. Defaults to the
|
||||
`sandboxed-none-rest-only` fixture and `<cwd>/<name>` as target.
|
||||
- `run(argv)` — programmatic entry. Returns the resolved
|
||||
`PromptAnswers` so test callers can introspect the chosen fixture.
|
||||
- Auto-runs only when invoked as a binary (`process.argv[1]` ends with
|
||||
`create-suaveplan-plugin.js`), so importing the module never trips a
|
||||
scaffold run.
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic example
|
||||
|
||||
```bash
|
||||
bunx create-suaveplan-plugin my-plugin --fixture trusted-postgres-full
|
||||
```
|
||||
|
||||
### Advanced example
|
||||
|
||||
```bash
|
||||
bunx create-suaveplan-plugin billing-plugin \
|
||||
--fixture isolated-sqlite-rest-only \
|
||||
--dir ./packages/billing-plugin \
|
||||
--force
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `parseArgs(argv: readonly string[]): ParsedArgs` — pure argv parser.
|
||||
- `run(argv: readonly string[]): PromptAnswers` — full scaffold cycle.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- The fixture vocabulary is closed; an unknown `--fixture` value
|
||||
silently falls back to the default rather than throwing — the bin is
|
||||
the user-facing layer and the spec treats unknown fixtures as a
|
||||
no-op rather than a hard error.
|
||||
- The `process.argv[1].endsWith(...)` guard is intentionally permissive
|
||||
so the file works whether invoked through Node, Bun, or a transpiled
|
||||
artefact.
|
||||
- Coverage exclusion for `src/bin/**` keeps the auto-run guard out of
|
||||
the 100% gate; the testable surface (`parseArgs`, `run`) is
|
||||
exercised directly from the test file.
|
||||
@@ -0,0 +1,73 @@
|
||||
# error-codes
|
||||
|
||||
## Purpose
|
||||
|
||||
This module declares the frozen, namespaced registry of every failure
|
||||
code the `create-suaveplan-plugin` scaffold can raise, together with the
|
||||
`ScaffoldError` subclass that carries those codes. Anchoring every
|
||||
failure path to a single, exhaustive code list lets downstream
|
||||
orchestration scripts and CLI wrappers recover programmatically without
|
||||
parsing error messages — they branch on `error.code` and the literal
|
||||
type narrows for them.
|
||||
|
||||
## Features
|
||||
|
||||
- Frozen `SCAFFOLD_CODES` registry via `defineCodes` from
|
||||
`@suaveplan/error`. Every value is a `SCAFFOLD.<REASON>` string
|
||||
literal.
|
||||
- `ScaffoldError` extends `SuaveplanError<ScaffoldErrorCode>` so
|
||||
`instanceof` plus `.code` checks stay exhaustive.
|
||||
- Side-effect import from `src/index.ts` ensures subpath consumers
|
||||
register codes too.
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic example
|
||||
|
||||
```ts
|
||||
import { SCAFFOLD_CODES, ScaffoldError } from "create-suaveplan-plugin";
|
||||
|
||||
throw new ScaffoldError(
|
||||
SCAFFOLD_CODES.INVALID_NAME,
|
||||
"scaffold.invalid_name:Foo",
|
||||
);
|
||||
```
|
||||
|
||||
### Advanced example
|
||||
|
||||
```ts
|
||||
import { ScaffoldError } from "create-suaveplan-plugin";
|
||||
|
||||
try {
|
||||
runScaffold();
|
||||
} catch (err) {
|
||||
if (err instanceof ScaffoldError && err.code === "SCAFFOLD.DIRECTORY_EXISTS") {
|
||||
console.error("Target already exists. Re-run with --force.");
|
||||
process.exit(2);
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `SCAFFOLD_CODES` — frozen record of code-name → `SCAFFOLD.<NAME>`.
|
||||
- `ScaffoldErrorCode` — union of every value of `SCAFFOLD_CODES`.
|
||||
- `class ScaffoldError extends SuaveplanError<ScaffoldErrorCode>` —
|
||||
constructor `(code, messageKey, options?)`.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- The registry is built at module-load time via `defineCodes`, which
|
||||
freezes the resulting object so consumers cannot mutate it.
|
||||
- Every code in this registry is thrown by a production code path —
|
||||
see `prompt/prompt.ts` (`INVALID_NAME`), `generator/generator.ts`
|
||||
(`DIRECTORY_EXISTS`, `WRITE_FAILED`, `UNKNOWN_ENGINE`).
|
||||
- The error is intentionally distinct from `SuaveplanError` so consumer
|
||||
catch clauses can disambiguate scaffold failures from peer-package
|
||||
failures without a code-string match. The class name is set to
|
||||
`ScaffoldError` so structured loggers serialising via the standard
|
||||
`name`/`message`/`stack` triple emit a recognisable identity.
|
||||
- The conformance script enforces a side-effect import of this module
|
||||
from the package barrel; without it, subpath consumers would not
|
||||
register codes in any global telemetry hook.
|
||||
@@ -0,0 +1,69 @@
|
||||
# generator
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
This module turns a validated `PromptAnswers` record into either an
|
||||
in-memory list of `GeneratedFile` records (`generate`) or a tree
|
||||
materialised on disk (`scaffold`). Splitting the two lets snapshot tests
|
||||
inspect the rendered tree byte-for-byte without touching the filesystem,
|
||||
and lets the bin entrypoint stream the same tree out to disk through a
|
||||
single typed failure surface.
|
||||
|
||||
## Features
|
||||
|
||||
- Pure `generate(options)` returns a deterministic, ordered list of
|
||||
files for snapshot comparison.
|
||||
- `scaffold(options)` writes the tree atomically, raising
|
||||
`SCAFFOLD.DIRECTORY_EXISTS` when the target is non-empty (unless
|
||||
`force` is set) and `SCAFFOLD.WRITE_FAILED` for every fs error.
|
||||
- Engine validation raises `SCAFFOLD.UNKNOWN_ENGINE` for any database
|
||||
value outside the closed vocabulary.
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic example
|
||||
|
||||
```ts
|
||||
import { scaffold, answersForFixture } from "create-suaveplan-plugin";
|
||||
|
||||
const answers = answersForFixture("isolated-sqlite-rest-only", "my-plugin");
|
||||
scaffold({ answers, targetDir: "./my-plugin" });
|
||||
```
|
||||
|
||||
### Advanced example
|
||||
|
||||
```ts
|
||||
import { generate, answersForFixture } from "create-suaveplan-plugin";
|
||||
|
||||
const tree = generate({
|
||||
answers: answersForFixture("trusted-postgres-full", "billing"),
|
||||
});
|
||||
for (const file of tree) {
|
||||
console.log(file.path, file.content.length);
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `generate(options: GenerateOptions): readonly GeneratedFile[]` — pure
|
||||
in-memory render. Validates answers first.
|
||||
- `scaffold(options: ScaffoldOptions): ScaffoldResult` — writes to disk.
|
||||
- `GeneratedFile` — `{ readonly path: string; readonly content: string }`.
|
||||
- `ScaffoldOptions` — `{ answers, targetDir, force? }`.
|
||||
- `ScaffoldResult` — `{ files: readonly string[] }` (relative paths).
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- `directoryIsNonEmpty` swallows ENOENT — a missing target is treated
|
||||
as empty so the first-time path needs no special case.
|
||||
- Errors during write are wrapped in `ScaffoldError` with `cause` set
|
||||
to the original `fs` error, so callers retain the original stack via
|
||||
the standard `Error.cause` chain.
|
||||
- The path order returned by `generate` is stable; snapshot tests rely
|
||||
on this when asserting tree equality.
|
||||
- Coverage is enforced at 100% by the snapshot fixtures plus the
|
||||
explicit error-path tests in `generator.test.ts`.
|
||||
@@ -0,0 +1,78 @@
|
||||
# prompt
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
This module defines the closed prompt-answer surface for the scaffold
|
||||
(`PromptAnswers`, `IsolationTier`, `DatabaseEngine`, `CapabilitySelection`),
|
||||
the Zod schema that validates inputs at the package boundary, and the
|
||||
helper that resolves a fixture shorthand to a full answer set. The
|
||||
prompt surface is the only public contract between any interactive
|
||||
front-end (TTY prompt, web UI, programmatic harness) and the generator.
|
||||
|
||||
## Features
|
||||
|
||||
- Strict npm-package-name validation (`@scope/`-aware) that runs before
|
||||
any filesystem work happens.
|
||||
- Zod-derived `PromptAnswersSchema` for boundary validation. Every union
|
||||
member is exhaustive — the scaffold tracks the closed vocabulary of
|
||||
isolation tiers and database engines explicitly.
|
||||
- `answersForFixture(name, fixture)` produces a deterministic answer
|
||||
set for each of the three snapshot fixtures.
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic example
|
||||
|
||||
```ts
|
||||
import { validateAnswers } from "create-suaveplan-plugin";
|
||||
|
||||
const answers = validateAnswers({
|
||||
name: "my-plugin",
|
||||
isolation: "trusted",
|
||||
database: "postgres",
|
||||
capabilities: {
|
||||
rest: true,
|
||||
graphql: false,
|
||||
ws: false,
|
||||
sse: false,
|
||||
sagas: false,
|
||||
twoPhaseCommit: false,
|
||||
perTenantJobs: false,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
### Advanced example
|
||||
|
||||
```ts
|
||||
import { answersForFixture, scaffold } from "create-suaveplan-plugin";
|
||||
|
||||
const answers = answersForFixture("trusted-postgres-full", "billing-plugin");
|
||||
scaffold({ answers, targetDir: "./billing-plugin", force: false });
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `validateAnswers(input: PromptAnswers): PromptAnswers` — returns the
|
||||
frozen, validated answer set. Throws `SCAFFOLD.INVALID_NAME` for any
|
||||
name that fails the npm-package-name rules.
|
||||
- `answersForFixture(fixture, name): PromptAnswers` — shorthand
|
||||
resolver for the three snapshot fixtures.
|
||||
- `PromptAnswersSchema: z.ZodType<PromptAnswers>` — boundary schema.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- The Zod schema runs first because it produces clearer errors for
|
||||
shape mismatches; the npm-name regex layer runs second specifically
|
||||
to raise the typed `SCAFFOLD.INVALID_NAME` code which downstream
|
||||
tooling branches on.
|
||||
- `Object.freeze` is applied at the answer level AND at the nested
|
||||
`capabilities` level so neither shape can be mutated between
|
||||
validation and template rendering.
|
||||
- The fixture shorthand is exported because the scaffold-output snapshot
|
||||
tests rely on a deterministic answer set per fixture; consumers may
|
||||
also use it for in-process orchestration.
|
||||
@@ -0,0 +1,81 @@
|
||||
# templates
|
||||
|
||||
<!-- begin:auto-docs -->
|
||||
_(no submodules)_
|
||||
<!-- end:auto-docs -->
|
||||
|
||||
## Purpose
|
||||
|
||||
This module owns the per-file render functions that produce the
|
||||
scaffolded plugin tree. Every output file (manifest, source, tests,
|
||||
configs, migrations, README, package.json, tsconfig, .gitignore) lives
|
||||
here as a typed string-producer keyed off the validated `PromptAnswers`.
|
||||
Keeping the templates in TypeScript (not as opaque `.tmpl` files) means
|
||||
the type system can refuse a render that references a capability the
|
||||
prompt vocabulary doesn't know about.
|
||||
|
||||
## Features
|
||||
|
||||
- One `renderTree(answers)` entrypoint returning the ordered file list.
|
||||
- Per-capability handler stubs in `src/index.ts.tmpl` so generated test
|
||||
files compile against real handler exports on first run.
|
||||
- Conditional emission of integration test + integration vitest config
|
||||
+ migrations when a DB engine other than `none` is selected.
|
||||
- Generated `vitest.config.ts` always wires `@suaveplan/testing/config`
|
||||
(the `createTestConfig` factory, never `baseVitestConfig`+`mergeConfig`).
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic example
|
||||
|
||||
```ts
|
||||
import { renderTree, answersForFixture } from "create-suaveplan-plugin";
|
||||
|
||||
const files = renderTree(
|
||||
answersForFixture("sandboxed-none-rest-only", "demo"),
|
||||
);
|
||||
for (const f of files) console.log(f.path);
|
||||
```
|
||||
|
||||
### Advanced example
|
||||
|
||||
```ts
|
||||
import { renderTree, validateAnswers } from "create-suaveplan-plugin";
|
||||
|
||||
const files = renderTree(
|
||||
validateAnswers({
|
||||
name: "billing",
|
||||
isolation: "trusted",
|
||||
database: "postgres",
|
||||
capabilities: {
|
||||
rest: true,
|
||||
graphql: true,
|
||||
ws: true,
|
||||
sse: true,
|
||||
sagas: true,
|
||||
twoPhaseCommit: true,
|
||||
perTenantJobs: true,
|
||||
},
|
||||
}),
|
||||
);
|
||||
const migration = files.find((f) =>
|
||||
f.path === "migrations/postgres/0001-init.sql",
|
||||
);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `renderTree(answers: PromptAnswers): readonly GeneratedFile[]` —
|
||||
deterministic, ordered file list.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- Path order is stable, which the snapshot tests depend on; do not
|
||||
reorder file emission when adding new templates.
|
||||
- Every emitted file ends with a trailing newline so they round-trip
|
||||
through editors that auto-append one.
|
||||
- The generated `package.json` declares no external runtime deps so
|
||||
`bun test` against the produced tree works without `bun install`
|
||||
resolving anything.
|
||||
- Integration tests use `vitest` rather than `bun:test` since real
|
||||
testcontainer fixtures are vitest-native.
|
||||
Reference in New Issue
Block a user