export declare function toSnake(name: string): string; export declare const SQL_RESERVED_TABLE_NAMES: ReadonlySet; /** Simple English plural, used to escape a reserved-word table name. */ export declare function pluralizeReserved(name: string): string; /** * Class name -> table name (singular by default), with a resolution side effect: * a name that collides with a SQL reserved word is pluralised (Order -> orders) * AND recorded on the current run's resolution as a `reserved_word_pluralize` * transformation. Every generator routes through here so the model, migration, * routes and tests all agree on the same table name. */ export declare function toTableName(name: string): string; /** * The table name a generator uses (issue #123) — honours `--table-name` and * speaks up instead of renaming SILENTLY. Mirrors the Python master's * `_resolve_table` (tina4-python/tina4_python/cli/__init__.py). * * `announce` prints the note/warning; it is TRUE only for `generateModel` (where * the table is born). Composite generators (crud) let the model sub-call * announce, and generators that target an EXISTING table (route/seeder/form/view/ * migration) still honour `--table-name` but stay quiet so the note is not * repeated — the note prints exactly once per `generate`. * * • `--table-name ` wins verbatim. If that name is ITSELF a reserved word, * warn loudly (when announcing): Tina4 interpolates table names UNQUOTED, so * the ORM's generated SQL will fail on it — quoting it in raw SQL + migrations * is now the developer's job (we do NOT silently quote; identifier quoting is a * global storage invariant, not a local fix). * • Otherwise fall back to `toTableName` (snake + reserved-word pluralise). When * that auto-pluralises a reserved-word class name (`Order` -> `orders`), print a * one-line NOTE (when announcing) naming the rename and the `--table-name` * escape hatch, so the developer is informed rather than surprised. * * The note/warning goes to STDERR (console.error) so a `generate … --json` run * keeps its stdout envelope pristine for a downstream `| jq`. `toTableName`'s * `reserved_word_pluralize` envelope transformation is UNCHANGED (this ADDS the * announce path; it does not touch the envelope contract). */ export declare function resolveTable(name: string, flags: Record | undefined, opts?: { announce?: boolean; }): string; /** One transformation the resolver made — visible to the caller so an AI * agent (or human) knows exactly why the output differs from the input. */ export interface ResolutionTransformation { kind: string; from?: string; to?: string; reason?: string; override?: string; } export interface ResolutionInput { name: string; fields: string | null; } /** * One `// tina4:edit …` marker found in a written (or would-be-written) * template file. `file` is repo-relative POSIX (matches the rest of the * envelope's paths); `line` is 1-based; `label` is the short imperative label * that followed the marker on the same line. */ export interface EditHint { file: string; line: number; label: string; } export interface ResolutionBody { class_name?: string; table_name?: string; file_path?: string; migration_path?: string; routes?: string[]; test_paths?: string[]; edit_hints?: EditHint[]; next?: string[]; transformations: ResolutionTransformation[]; } export interface ResolutionEnvelope { command: "generate"; target: string; input: ResolutionInput; resolution: ResolutionBody; actions_taken: string[]; dry_run: boolean; } /** * A stable version tag on the JSON envelope. `commands --json` echoes this in * `resolution_contract.envelope` so the tina4 client (or any consumer) can * discover the exact contract this framework speaks. Bump when a breaking * key rename / removal lands; keep unchanged when new OPTIONAL keys are added. * * `generate_v1_1` (ADR-0063, 3.13.120) is a PURELY ADDITIVE superset of * `generate_v1`: every v1 field is preserved, and two new optional arrays * appear — `resolution.edit_hints[]` (one entry per `// tina4:edit` marker * baked into a template) and `resolution.next[]` (curated per-verb actionable * next steps). `resolution.test_paths[]` was already in v1; v1.1 surfaces it * in the human stderr block too. */ export declare const RESOLUTION_ENVELOPE_VERSION = "generate_v1_1"; /** Read-only snapshot of the current resolution — exported for tests that * want to inspect it in-process (the CLI itself uses only the envelope). */ export declare function currentResolution(): ResolutionEnvelope; /** slug-of-anything → PascalCase (order-emails → OrderEmails). */ export declare function toPascal(name: string): string; export declare function parseFields(fieldsStr: string): Array<[string, string]>; export declare const DEFAULT_FIELDS: ReadonlyArray<[string, string]>; /** Parsed --fields, or the default single `name` column when none given. */ export declare function fieldsOrDefault(fieldsStr: string): Array<[string, string]>; export declare function parseCliArgs(args: string[]): { flags: Record; positional: string[]; }; /** * Parse a `--every` duration ("5m", "30s", "2h", "1d", or bare seconds) → seconds. * Falls back to 60s on an empty/unparseable value so a scaffold always has a * valid ServiceRunner interval. */ export declare function parseEvery(every: string | boolean | undefined): number; /** * The canonical AI-FILL placeholder for a LOGIC-shaped stub — a tight, grounded * fill-spec (not a vague `// TODO`) so a coding agent (or dev) completes it * correctly. `throw new Error(...)` makes an unfilled scaffold fail LOUD; the * greppable `AI-FILL` banner lets a human/agent jump to every gap. `use` names * only REAL tina4-nodejs symbols (verified in source). */ export declare function aiFill(fn: string, spec: { intent: string; given?: string; use: string; ret?: string; ground: string; raise: string; }, indent?: string): string; /** * The lighter EXTEND marker for CRUD-shaped WORKING code — no throw (the * boilerplate IS the feature); just a greppable hint at the natural extension * point (custom validation / business rules / authorization). */ export declare function extend(note: string, hint?: string, indent?: string): string; export interface GeneratorSpec { handler: (name: string, flags: Record) => void; /** Arg/flag hint shown in `tina4nodejs help` (human only). */ usage: string; summary: string; } export declare const GENERATORS: Record; export declare function generate(what: string, name: string, extraArgs?: string[]): Promise; /** * Programmatic entry point for in-process consumers (MCP tools, tests, hosted * agents) — does everything `generate()` does EXCEPT print. * * Reset the resolution → dispatch to the requested generator → populate `next[]` * → return the envelope. Files still land on disk (unless `--dry-run` is passed * in `extraArgs`); only the human "Created …" per-file log and the * `printResolution()` output are suppressed (via `jsonMode: true`, the same * suppression `--json` uses on the CLI). * * Used by the MCP `migration_create` tool (packages/core/src/mcp.ts) so the * ADR-0063 `generate_v1_1` envelope drives every surface (CLI, MCP, tests) * without a subprocess round-trip. */ export declare function generateProgrammatic(what: string, name: string, extraArgs?: string[]): Promise; export declare function generateMigration(name: string, flags: Record, fieldsOverride?: Array<[string, string]>, tableOverride?: string, emitTest?: boolean): void;