Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .changeset/fix-mssql-tarn-bundle-interop-cli.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"@noormdev/cli": patch
---

fix(mssql): noorm db create / run no longer crash with "Pool is not a constructor"

In the bundled CLI, `await import('tarn')` / `await import('tedious')` expose
their exports under `.default`, so kysely's MSSQL dialect received an undefined
`Pool` and every MSSQL command (`noorm db create`, `run`, `change`, etc.) failed
with `Cannot connect to server: Pool is not a constructor`. Normalize the CJS
interop, mirroring the postgres dialect.
11 changes: 11 additions & 0 deletions .changeset/fix-mssql-tarn-bundle-interop.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
"@noormdev/sdk": patch
---

fix(mssql): construct tarn/tedious through CJS-interop guard in bundles

When the SDK is bundled (tsup), `await import('tarn')` / `await import('tedious')`
expose their exports under `.default`, so spreading the namespace left
`tarn.Pool` undefined and kysely threw `Pool is not a constructor` on every
MSSQL connection. Normalize both with `module.default ?? module`, mirroring the
postgres dialect's existing guard.
13 changes: 13 additions & 0 deletions .changeset/reset-ignores-preserve-tables-cli.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"@noormdev/cli": patch
---

fix(cli): noorm db reset rebuilds cleanly regardless of preserveTables

`noorm db reset` (teardown + build) honored `settings.teardown.preserveTables`
during the teardown phase, so preserved tables (e.g. reference vocabulary kept
for the `noorm db truncate` workflow) survived and then collided with the
build's `CREATE TABLE`, aborting the rebuild and leaving a partial schema.
`noorm db reset` now performs a full teardown that ignores `preserveTables` —
a full rebuild starts from nothing. `noorm db teardown` and `noorm db truncate`
still honor the setting.
13 changes: 13 additions & 0 deletions .changeset/reset-ignores-preserve-tables.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"@noormdev/sdk": patch
---

fix(sdk): db.reset() no longer preserves tables before rebuilding

`db.reset()` (teardown + build) honored `settings.teardown.preserveTables`,
so any preserved table (e.g. reference vocabulary kept for the per-test
`truncate()` workflow) survived the teardown and then collided with the
build's `CREATE TABLE`, aborting the rebuild and leaving a partial schema.
reset() now performs a full teardown that ignores `preserveTables` — a full
rebuild starts from nothing. `preserveTables` still applies to standalone
`teardown()` and `truncate()`.
13 changes: 13 additions & 0 deletions .changeset/teardown-mssql-check-constraint-udf-cli.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"@noormdev/cli": patch
---

fix(cli): noorm db teardown drops MSSQL CHECK constraints before functions

`noorm db teardown` (and `noorm db reset`) aborted with MSSQL error 3729 on
any schema where a scalar UDF is referenced by a CHECK constraint (the
canonical base/subtype "IsType" pattern). Functions are dropped before tables
to satisfy schema-bound dependents, which left the CHECK-constraint dependency
intact. Teardown now severs it first by dropping all user-schema CHECK
constraints (excluding the `noorm` schema) ahead of the function drops, so
both schema-bound functions and CHECK-backed functions tear down cleanly.
13 changes: 13 additions & 0 deletions .changeset/teardown-mssql-check-constraint-udf.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
"@noormdev/sdk": patch
---

fix(teardown): drop MSSQL CHECK constraints before functions

`teardown()` aborted with MSSQL error 3729 on any schema where a scalar UDF
is referenced by a CHECK constraint (the canonical base/subtype "IsType"
pattern). Functions are dropped before tables to satisfy schema-bound
dependents, but that left the CHECK-constraint dependency intact. Teardown
now severs it first by dropping all user-schema CHECK constraints (excluding
the `noorm` schema) ahead of the function drops, so both schema-bound
functions and CHECK-backed functions tear down cleanly.
1,059 changes: 1,059 additions & 0 deletions .claude/project/deterministic-signals.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions .claude/project/followups/CLOSED.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- 2026-06-06 mssql-build-non-idempotent-create-type — "MSSQL build non-idempotent: bare CREATE TYPE blocks db.reset() rebuild" — *(closed 2026-06-06)*
21 changes: 21 additions & 0 deletions .claude/project/followups/INDEX.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Project follow-ups index

Auto-generated by `atomic followups render`. Do not edit.

Open: 2 • Stale: 0 • Last rendered: 2026-06-06

## 📋 plans (0)

(none)

## 🟡 risks (1)

- [config-module-scope-env-snapshot](config-module-scope-env-snapshot.md) — Move makeNestedConfig to call-time in config module (5d)

## 🔵 nits (1)

- [debug-process-test-no-assertions](debug-process-test-no-assertions.md) — debug-process.test.ts has no assertions (passes unconditionally) (5d)

## ❓ questions (0)

(none)
13 changes: 13 additions & 0 deletions .claude/project/followups/config-module-scope-env-snapshot.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
id: config-module-scope-env-snapshot
title: Move makeNestedConfig to call-time in config module
created: "2026-06-01"
origin: |
refresh-signals scan
kind: finding
severity: risk
review_by: "2026-07-31"
status: open
file: src/core/config/index.ts:34
---

13 changes: 13 additions & 0 deletions .claude/project/followups/debug-process-test-no-assertions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
id: debug-process-test-no-assertions
title: debug-process.test.ts has no assertions (passes unconditionally)
created: "2026-06-01"
origin: |
refresh-signals scan
kind: finding
severity: nit
review_by: "2026-07-31"
status: open
file: tests/core/config/debug-process.test.ts
---

21 changes: 21 additions & 0 deletions .claude/project/signals-steering.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Signals steering
#
# User-provided hints for the signals inferrer. When this file exists,
# the inferrer reads it before writing signals.md and treats its
# content as ground truth — steering wins over detection when they
# conflict. Delete sections you don't need.
#
# ## Framework
# NestJS monorepo (not plain Express)
#
# ## Domains
# - src/billing/ and src/payments/ are one domain ("payments")
# - src/internal-tools/ is scratch code — not a real domain
#
# ## Build
# - Build: pnpm turbo build
# - Test: pnpm test:ci (not pnpm test — that runs watch mode)
#
# ## Ignore for domains
# - vendor/
# - generated/
79 changes: 79 additions & 0 deletions .claude/project/signals.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Project signals

## Framework & runtime

- **Language:** TypeScript (80% LOC, 872 files), Bun runtime (>=1.2), Node >=22.13
- **SQL layer:** Kysely query builder + executor; dialect-aware across PostgreSQL, MySQL, MSSQL, SQLite
- **TUI:** Ink 6 + React 19 (`src/tui/`); Citty for CLI arg parsing (`src/cli/`)
- **Event bus:** `@logosdx/observer` (`ObserverEngine`); module-scope singleton in `src/core/observer.ts`
- **Templating:** Eta 4 for `.sql.tmpl` files; data loaders for JSON5/YAML/CSV/JS side-cars
- **Error handling:** `@logosdx/utils` `attempt`/`attemptSync` tuples — no try-catch in source
- **Encryption:** AES-256-GCM for state (`src/core/state/encryption/`), Ed25519-like keypairs for identity
- **MCP:** `@modelcontextprotocol/sdk` wrapping RPC registry over stdio

## Build / test / lint

| Purpose | Command | Source |
|---------|---------|--------|
| Build (tsc) | `bun run build` | `package.json` |
| Build packages | `bun run build:packages` | `scripts/build.mjs` (tsup) |
| Build binary | `bun run build:binary` | `scripts/build-binary.mjs` (bun compile) |
| Dev watch | `bun run dev` | `package.json` |
| Test (all, serial) | `bun run test` | `package.json` |
| Test CI group 1 | `bun test --serial $(find tests/utils tests/core tests/sdk -name '*.test.ts' \| grep -v tests/core/transfer \| sort \| tr '\n' ' ')` | `.github/workflows/ci.yml:127` |
| Test CI group 2 | `bun test --serial tests/core/transfer` | `.github/workflows/ci.yml:132` |
| Test CI group 3 | `bun test --serial tests/cli` | `.github/workflows/ci.yml:137` |
| Test CI group 4 | `bun test --serial tests/integration` | `.github/workflows/ci.yml:142` |
| Lint | `bun run lint` | ESLint, `eslint.config.js` |
| Typecheck | `bun run typecheck` | `tsconfig.json` |

CI gate: lint → typecheck → build → 4 test groups → 3 example jobs. Integration tests require live DB services (docker-compose or CI service containers).

## Language breakdown

| Language | LOC | Files | % |
|----------|-----|-------|---|
| TypeScript | 199535 | 872 | 80% |
| Markdown | 42464 | 186 | 17% |
| YAML | 1114 | 16 | 1% |
| JavaScript | 1005 | 22 | 1% |
| HTML | 955 | 26 | 2% |
| CSS | 913 | 3 | <1% |
| Shell | 726 | 4 | <1% |

## DevOps & CI

- **CI:** GitHub Actions (`ubuntu-24.04`), Bun 1.3.11 pinned; 4 test groups + 3 example jobs per push to master/main
- **DB services (CI):** Postgres 17 on 15432, MySQL 8.0 on 13306, MSSQL 2022 on 11433
- **DB services (local):** `docker-compose.yml` at repo root (same ports)
- **Publish:** Changesets-driven (`changeset publish`) via `.github/workflows/publish.yml`; packages: `@noormdev/cli` and `@noormdev/sdk`
- **Binary release:** `bun build --compile` → GitHub Releases via `.github/workflows/release-binary.yml`
- **Docs:** VitePress, deployed via `.github/workflows/docs.yml`

## Domains

| Domain | Repo paths | One-liner | Detail |
|--------|------------|-----------|--------|
| core-change | `src/core/change/`, `src/cli/change/`, `tests/core/change/` | Versioned DB changes: scaffold, parse, execute, history | .claude/project/signals/core-change.md |
| core-runner | `src/core/runner/`, `src/core/template/`, `src/cli/run/`, `tests/core/runner/`, `tests/core/template/` | SQL file execution with checksum dedup and Eta templating | .claude/project/signals/core-runner.md |
| core-db | `src/core/db/`, `src/core/connection/`, `src/core/explore/`, `src/core/teardown/`, `src/core/transfer/`, `src/cli/db/`, `tests/core/connection/`, `tests/core/explore/`, `tests/core/teardown/`, `tests/core/transfer/`, `tests/integration/` | DB lifecycle: create/drop, explore schema, teardown, cross-DB transfer | .claude/project/signals/core-db.md |
| core-state | `src/core/state/`, `src/core/settings/`, `src/core/config/`, `src/core/lifecycle/`, `src/core/version/`, `src/core/project.ts`, `src/core/project-init.ts`, `src/core/environment.ts`, `src/core/observer.ts`, `tests/core/state/`, `tests/core/settings/`, `tests/core/config/`, `tests/core/lifecycle/`, `tests/core/version/` | Encrypted state, settings.yml, config resolution, lifecycle, version migration | .claude/project/signals/core-state.md |
| core-identity | `src/core/identity/`, `src/core/vault/`, `src/core/logger/`, `src/core/sql-terminal/`, `src/cli/identity/`, `src/cli/secret/`, `src/cli/vault/`, `src/cli/sql/`, `tests/core/identity/`, `tests/core/vault/`, `tests/core/logger/`, `tests/core/sql-terminal/` | Identity keypairs, vault secrets, structured logger, SQL terminal history | .claude/project/signals/core-identity.md |
| sdk | `src/sdk/`, `src/core/dt/`, `packages/sdk/`, `tests/sdk/`, `tests/integration/sdk/` | Programmatic API (`createContext`) + DT binary serialization format | .claude/project/signals/sdk.md |
| cli | `src/cli/`, `packages/cli/`, `skills/noorm/`, `tests/cli/` | Citty CLI with 17 command groups, headless mode, binary distribution | .claude/project/signals/cli.md |
| tui | `src/tui/`, `src/hooks/`, `.claude/rules/tui-development.md`, `tests/cli/components/`, `tests/cli/hooks/`, `tests/cli/screens/` | Ink/React TUI with focus manager, keyboard routing, per-domain screens | .claude/project/signals/tui.md |
| mcp-rpc | `src/mcp/`, `src/rpc/`, `src/cli/mcp/`, `tests/core/mcp/`, `tests/core/rpc/` | MCP server over stdio wrapping flat RPC command registry | .claude/project/signals/mcp-rpc.md |
| worker-bridge | `src/core/worker-bridge/`, `src/workers/`, `tests/core/worker-bridge/`, `tests/workers/` | Hub-and-spoke worker threads for DT serialization and DB connection worker | .claude/project/signals/worker-bridge.md |
| infra | `.github/`, `scripts/`, `examples/`, `docs/`, `tsup.*.config.ts`, `docker-compose.yml`, `bunfig.toml` | CI, build pipeline, binary release, example projects, VitePress docs | .claude/project/signals/infra.md |

## Cross-cutting

**Test layout:** Tests mirror `src/` under `tests/`. `tests/utils/` holds shared DB helpers. `tests/fixtures/` has SQL fixtures per dialect. `tests/integration/` requires live databases. `tests/global-setup.ts` / `tests/global-teardown.ts` coordinate integration DB bootstrap.

**Known contamination:** `src/core/config/index.ts:34` calls `makeNestedConfig(process.env, …)` at module scope — snaps env at first import. This causes test cross-contamination when running the full suite in one process. Workaround: run test groups in separate `bun test --serial` invocations (same as CI).

**Convention pointers:** `.claude/rules/typescript.md` (4-block function structure, `attempt` over try-catch), `.claude/rules/tui-development.md` (focus system, Ink layout), `.claude/rules/testing.md` (test naming, coverage), `.claude/rules/documentation.md` (three-pillar structure).

**Domain partitioning basis:** Domains are functional vertical slices. `core-state` groups the startup/persistence concerns (state, settings, config, lifecycle, version) because they all initialize together in `project-init.ts`. `core-identity` groups crypto identity, vault, logger, and SQL terminal because they share the "user-facing sensitive data" concern. `core-db` groups connection, explore, transfer, and teardown because they all operate against a live database connection. `core-change` and `core-runner` are separate because changes are versioned operations while runner handles idempotent file execution — they share `runFile` but have distinct lifecycles.

**Deterministic substrate:** `.claude/project/deterministic-signals.md` (generated 2026-06-01T02:30:22Z, atomic 3.0.0)
68 changes: 68 additions & 0 deletions .claude/project/signals/cli.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# cli

## What it does

Citty-based CLI with 17 top-level command groups. Each command group maps to a subdirectory under `src/cli/`. Commands emit events via the observer and delegate to core modules. Headless mode (`--yes`, `--json`) suppresses interactive prompts and formats output as JSON.

Published as `@noormdev/cli` from `packages/cli/`.

## Artifacts

- `packages/cli/package.json` — published package `@noormdev/cli`, version `1.0.0-alpha.35`; entry `noorm.js`
- `packages/cli/noorm.js` — thin wrapper that runs the compiled binary
- `packages/cli/scripts/postinstall.js` — postinstall script for binary extraction
- `packages/cli/CHANGELOG.md` — CLI release history
- `skills/noorm/SKILL.md` — Claude Code skill for noorm CLI usage
- `skills/noorm/references/cli.md` — comprehensive CLI command reference (1011L)
- `skills/noorm/references/config.md` — config management reference
- `skills/noorm/references/sdk.md` — SDK reference for skill use
- `skills/noorm/references/templates.md` — template reference for skill use

## CLI code

- `src/cli/index.ts` — citty entry point; registers all subcommands, help interceptor, `--cwd` global flag
- `src/cli/_utils.ts` — shared CLI utilities: headless detection, output formatting, flag parsing
- `src/cli/change/` — `change add|edit|ff|history|list|next|revert|rewind|rm|run` (13 files)
- `src/cli/ci/` — `ci init|secrets|identity/*` — CI automation commands
- `src/cli/config/` — `config add|cp|edit|export|import|list|rm|use|validate` (10 files)
- `src/cli/db/` — `db create|drop|explore*|reset|teardown|transfer|truncate` (16 files)
- `src/cli/dev/` — `dev test-helpers|test-workers` — internal diagnostics
- `src/cli/identity/` — `identity edit|export|init|list`
- `src/cli/lock/` — `lock acquire|force|release|status`
- `src/cli/mcp/` — `mcp init|serve`
- `src/cli/run/` — `run build|dir|exec|file|files|inspect|preview` (8 files)
- `src/cli/secret/` — `secret list|rm|set`
- `src/cli/settings/` — `settings build|edit|init|secret` (5 files)
- `src/cli/sql/` — `sql clear|history|query|repl`
- `src/cli/vault/` — `vault cp|init|list|propagate|rm|set`
- `src/cli/init.ts` — `noorm init` — project initialization wizard
- `src/cli/info.ts` — `noorm info` — display project + env info
- `src/cli/ui.ts` — `noorm ui` — launch TUI
- `src/cli/update.ts` — `noorm update` — self-update
- `src/cli/version.ts` — `noorm version` — print version info

## Docs

- `docs/cli/` — 9 user-facing CLI reference pages
- `docs/dev/headless.md` — headless mode internals
- `docs/guide/automation/non-interactive.md` — non-interactive usage
- `docs/guide/automation/ci.md` — CI usage
- `docs/guide/automation/mcp.md` — MCP usage
- `docs/headless.md` — public headless reference (1592L)

## Coupling

- Every CLI command imports from `src/core/` — any core API change may require CLI command updates.
- `src/cli/ui.ts` launches the TUI (`src/tui/app.tsx`) — TUI startup is a CLI concern.
- `src/cli/mcp/serve.ts` starts the MCP server from `src/mcp/server.ts` — MCP domain depends on CLI entry.
- Headless mode output shape is consumed by CI pipelines and SDK integration tests.
- `settings.paths.sql` and `settings.paths.changes` from `settings.yml` are the correct path sources (not per-config `paths` fields) — several run-related screens use `settings?.paths?.changes ?? 'changes'` pattern.

## Conventions worth knowing

- Commands attach `examples: string[]` to their `defineCommand` result; the help interceptor in `src/cli/index.ts` appends them after citty's auto-generated usage.
- `--cwd <path>` global flag (like `git -C`) must precede the subcommand.
- `--yes` / `-y` flag suppresses all confirmation prompts (headless mode).
- `--json` flag formats output as machine-readable JSON.
- Build produces a standalone binary via `bun build --compile` — worker paths must use `resolveWorker()`.
- Workspace package `@noormdev/cli` publishes the pre-built binary; `postinstall.js` extracts it.
42 changes: 42 additions & 0 deletions .claude/project/signals/core-change.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# core-change

## What it does

Manages versioned database changes: scaffold (create/add/remove/reorder files), parse (discover + validate), execute (forward/revert with tracking), and history (execution records per change and per file).

Change directories hold a `manifest.json` and SQL files. Each change has a description-based name, forward files, and optional revert files. Execution state is stored in the `__noorm_change__` and `__noorm_executions__` noorm tables.

## CLI code

- `src/core/change/scaffold.ts` — create/add/remove/rename/reorder change files on disk
- `src/core/change/parser.ts` — `parseChange`, `discoverChanges`, `resolveManifest`, `validateChange`, `parseSequence`, `parseDescription`
- `src/core/change/executor.ts` — `executeChange`, `revertChange`; applies SQL via the runner, records results
- `src/core/change/history.ts` — `ChangeHistory`; queries `__noorm_change__` and `__noorm_executions__` for per-change and per-file history
- `src/core/change/tracker.ts` — `ChangeTracker`; `canRevert` logic, orphaned-change detection
- `src/core/change/manager.ts` — `ChangeManager`; high-level facade: `list`, `run`, `revert`, `ff` (fast-forward)
- `src/core/change/validation.ts` — `validateChangeContent`; structural content checks
- `src/core/change/types.ts` — all change types, error classes (`ChangeValidationError`, `ChangeNotFoundError`, etc.)

## Docs

- `docs/dev/change.md` — developer reference for change internals
- `docs/guide/changes/overview.md` — user-facing: what changes are
- `docs/guide/changes/forward-revert.md` — forward and revert semantics
- `docs/guide/changes/history.md` — history querying
- `docs/cli/run.md` — run command docs (also covers change run)

## Coupling

- Calls `runner` (`runFile`) to execute SQL inside a change — changes in runner's `RunOptions` or file-execution semantics propagate here.
- Reads config via `src/core/config/` to resolve the active database connection — config schema changes affect `ChangeContext` construction.
- Emits events via `src/core/observer.ts` (`change:*` events) — the TUI subscribes via `useChangeProgress` hook.
- Writes to `__noorm_change__` and `__noorm_executions__` tables defined in `src/core/shared/tables.ts` — table renames propagate to executor and history queries.
- CLI commands in `src/cli/change/` call manager + scaffold functions — CLI argument shape changes here require CLI command updates.

## Conventions worth knowing

- Change directory names follow the pattern `YYYY-MM-DD-<description>`.
- `manifest.json` lists files in execution order; reorder functions rewrite it.
- `parseSequence` extracts a numeric prefix from filename for ordering.
- `DEFAULT_CHANGE_OPTIONS` and `DEFAULT_BATCH_OPTIONS` define timeout and retry defaults.
- Error classes extend `Error` with a `code` field; callers check `code` to distinguish failure modes.
Loading
Loading