Skip to content

CMS-151 | CLI Authoring Workflow#34

Merged
woywro merged 35 commits into
mainfrom
CMS-151
Apr 9, 2026
Merged

CMS-151 | CLI Authoring Workflow#34
woywro merged 35 commits into
mainfrom
CMS-151

Conversation

@woywro
Copy link
Copy Markdown
Collaborator

@woywro woywro commented Apr 8, 2026

Summary by CodeRabbit

  • New Features

    • Interactive mdcms init wizard (project/environment creation, schema inference, optional import, git integration)
    • mdcms schema sync with persisted local schema state and hash
    • mdcms status showing content and schema drift
    • Projects API (create/list projects & environments)
    • Enhanced push/pull (new/delete handling, validation, smarter plans) and draft-revision conflict detection
    • Improved interactive prompts and multi-selects; locale detection for content
  • Bug Fixes

    • Standardized config load errors
    • Path-traversal protection for content paths
    • Frontmatter sanitization to exclude unknown fields
  • Documentation

    • Updated ADRs and specs for project/environment and schema-sync workflows

woywro added 27 commits March 31, 2026 08:18
@chatgpt-codex-connector
Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

@vercel
Copy link
Copy Markdown

vercel Bot commented Apr 8, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
mdcms-studio-review Ready Ready Preview, Comment Apr 9, 2026 6:17am

Request Review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 8, 2026

Note

Reviews paused

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a complete CLI init wizard, robust schema sync/state and status commands, expanded push/pull validation and conflict handling, new Projects API and project/environment management, schema-hash utilities and persisted schema state, optimistic concurrency for content writes, and multiple supporting CLI/server utilities and tests.

Changes

Cohort / File(s) Summary
CLI: Init & supporting modules
apps/cli/package.json, apps/cli/src/lib/init.ts, apps/cli/src/lib/init/*.ts, apps/cli/src/lib/init/*.test.ts
New interactive init command and extensive supporting code: OAuth login flow, project/env creation, file scanning, schema inference, locale detection, config generation, schema sync, manifest import, git cleanup, and comprehensive tests.
CLI: Framework, prompting & discovery
apps/cli/src/lib/framework.ts, apps/cli/src/lib/framework.test.ts, apps/cli/src/lib/init/prompt.ts, apps/cli/src/lib/discover.ts, apps/cli/src/lib/discover.test.ts, apps/cli/src/lib/config.ts
Switched prompting to @inquirer/prompts, added multi-select prompt support, improved multi-word command resolution and argument handling, added discoverUntrackedFiles, and standardized config import error handling.
CLI: Schema sync & state, status
apps/cli/src/lib/schema-sync.ts, apps/cli/src/lib/schema-state.ts, apps/cli/src/lib/status.ts, tests...
New schema sync command, atomic per-(project,environment) schema state file (read/write/resolve), and status command reporting content and schema drift vs server.
CLI: Push / Pull / Validate
apps/cli/src/lib/push.ts, apps/cli/src/lib/pull.ts, apps/cli/src/lib/validate.ts, tests...
Major push/pull refactor: push supports validate/create/update/delete phases, schema-hash gating, conflict handling (stale revisions, schema mismatches, path conflicts), interactive selection; pull adds richer change categories and skip behavior; validation module for frontmatter/schema checks added.
CLI: Scan / Infer / Generate helpers
apps/cli/src/lib/init/scan.ts, apps/cli/src/lib/init/infer-schema.ts, apps/cli/src/lib/init/detect-locale.ts, apps/cli/src/lib/init/generate-config.ts, tests...
New utilities to scan markdown/mdx, infer schema/types from frontmatter, detect locales and aliases, and generate TypeScript config source with zod/reference imports; accompanied by tests.
CLI: Git helpers & untracked discovery
apps/cli/src/lib/init/git-cleanup.ts, tests...
Utilities to update .gitignore, detect git-tracked managed files, and untrack files (git rm --cached) with tests.
CLI: Login changes
apps/cli/src/lib/login.ts, apps/cli/src/lib/login.test.ts
Login no longer requires project/environment; request uses scopes array; exported loopback/browser utilities; stored profile keys default to "*" when project/env absent.
Shared contracts: schema hashing & state
packages/shared/src/lib/contracts/schema.ts, .../schema-hash.ts, packages/shared/package.json, tests...
Added toRawConfigSnapshot, buildSchemaSyncPayload (deterministic schemaHash via sha256) and SchemaStateFile type; added server export subpath; tests updated.
Server: Projects API & runtime
apps/server/src/lib/projects-api.ts, apps/server/src/lib/runtime-with-modules.ts
New Projects API layer (list/create projects, list/create environments) with DB-backed store and route mounting integrated into runtime with authorization handlers.
Server: Content API & stores
apps/server/src/lib/content-api/routes.ts, .../database-store.ts, .../in-memory-store.ts, .../responses.ts, .../parsing.ts, tests...
Added optimistic concurrency via expectedDraftRevision producing STALE_DRAFT_REVISION (409); strip unknown frontmatter fields in responses; tightened path validation (reject traversal); extended write payload/options to carry revision/publishedVersion.
Server: Auth & RBAC
apps/server/src/lib/auth.ts, apps/server/src/lib/rbac.ts, apps/server/src/lib/db/schema.ts, apps/server/drizzle/*
Made CLI login project/environment optional, introduced projects:read/projects:write scopes and RBAC mappings, hardened path-prefix matching against traversal, and updated DB schema/migration to allow nullable challenge project/environment fields.
Server: Seeding & demo key
apps/server/src/lib/demo-seed.ts, apps/server/src/bin/demo-seed-api-key.ts
Refactored demo seeding to use shared schema-hash payload; expanded demo API key scopes to include additional content and schema permissions.
Docs & ADRs
docs/adrs/*, docs/specs/*, blazebot/memory/*
Docs updated: ADRs/specs reflect project/environment creation via API, schema-hash pinning accepted, schema state file spec, and expanded CLI behaviors; session notes edited.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CLI as mdcms CLI
    participant Server
    participant DB as Database
    participant Browser

    User->>CLI: mdcms init
    CLI->>Server: GET /api/v1/healthz
    Server-->>CLI: 200

    CLI->>Browser: Open OAuth login URL
    Browser->>Server: POST /api/v1/auth/cli/login/start (scopes)
    Server->>DB: Insert challenge
    Server-->>Browser: OAuth redirect / code
    Browser->>Server: POST /api/v1/auth/cli/login/exchange
    Server->>DB: Create API key
    Server-->>CLI: { apiKey }

    CLI->>Server: GET /api/v1/projects
    Server->>DB: Query projects
    Server-->>CLI: [projects]

    CLI->>CLI: scanContentFiles / inferSchema / detectLocale / generateConfig
    CLI->>Server: PUT /api/v1/schema (schema payload + x-mdcms-schema-hash)
    Server->>DB: validate & persist schema sync
    Server-->>CLI: { schemaHash }
    CLI->>CLI: write .mdcms/schema/<proj>.<env>.json
Loading
sequenceDiagram
    participant User
    participant CLI as mdcms CLI
    participant Store as Local Store
    participant Server

    User->>CLI: mdcms push --validate
    CLI->>Store: readSchemaState()
    Store-->>CLI: { schemaHash }

    CLI->>CLI: build push plan (changed / new / deleted)
    CLI->>CLI: validate frontmatter against schema

    alt validation fails
        CLI->>User: print validation errors
    else validation passes
        CLI->>Server: PUT /api/v1/content/:id (with schemaHash, draftRevision)
        alt stale revision / schema mismatch / conflict
            Server-->>CLI: 409 { code }
            CLI->>User: record [FAILED] and continue
        else success
            Server-->>CLI: 200
            CLI->>Store: flush manifest update
        end
        CLI->>Server: POST /api/v1/content (for new)
        Server-->>CLI: 201 { id }
        CLI->>Store: add manifest entry
        CLI->>Server: DELETE /api/v1/content/:id (for deletions)
        Server-->>CLI: 204
        CLI->>Store: remove manifest entry
        CLI->>User: print summary [UPDATED/CREATED/DELETED]
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Poem

🐰 A rabbit's ode to manifests and syncs
I hopped through files with frontmatter bright,
Found locales and types by lantern light,
Pinned hashes, synced schemas, wrote the state,
Pulled, pushed, resolved conflicts—no more wait,
Projects planted, manifests snug and tight. ✨

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the primary change: introducing the CLI authoring workflow feature under ticket CMS-151, which aligns with the extensive changes across init, push, pull, status, and schema-sync commands.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch CMS-151

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 8, 2026

Note

Docstrings generation - SUCCESS
Generated docstrings for this pull request at #35

coderabbitai Bot added a commit that referenced this pull request Apr 8, 2026
Docstrings generation was requested by @woywro.

* #34 (comment)

The following files were modified:

* `apps/cli/src/lib/config.ts`
* `apps/cli/src/lib/discover.ts`
* `apps/cli/src/lib/framework.ts`
* `apps/cli/src/lib/init.ts`
* `apps/cli/src/lib/init/detect-locale.ts`
* `apps/cli/src/lib/init/generate-config.ts`
* `apps/cli/src/lib/init/git-cleanup.ts`
* `apps/cli/src/lib/init/infer-schema.ts`
* `apps/cli/src/lib/init/prompt.ts`
* `apps/cli/src/lib/init/scan.ts`
* `apps/cli/src/lib/login.ts`
* `apps/cli/src/lib/pull.ts`
* `apps/cli/src/lib/push.ts`
* `apps/cli/src/lib/schema-state.ts`
* `apps/cli/src/lib/schema-sync.ts`
* `apps/cli/src/lib/status.ts`
* `apps/cli/src/lib/validate.ts`
* `apps/server/src/lib/auth.ts`
* `apps/server/src/lib/content-api/database-store.ts`
* `apps/server/src/lib/content-api/in-memory-store.ts`
* `apps/server/src/lib/content-api/parsing.ts`
* `apps/server/src/lib/content-api/responses.ts`
* `apps/server/src/lib/content-api/routes.ts`
* `apps/server/src/lib/demo-seed.ts`
* `apps/server/src/lib/projects-api.ts`
* `apps/server/src/lib/rbac.ts`
* `apps/server/src/lib/runtime-with-modules.ts`
* `packages/shared/src/lib/contracts/schema-hash.ts`
* `packages/shared/src/lib/contracts/schema.ts`
@woywro
Copy link
Copy Markdown
Collaborator Author

woywro commented Apr 8, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 8, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 20

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/cli/src/lib/framework.ts (1)

288-339: ⚠️ Potential issue | 🟡 Minor

Fix type mismatch: serverUrl can be undefined when requiresTarget is false

The resolveExecutionContext function return type declares serverUrl: string (non-optional), but the implementation only validates and enforces a value when input.requiresTarget is true. This allows serverUrl to be undefined for commands like login (where requiresTarget: false), even though the type system promises it will always be a string. The login command uses context.serverUrl directly in URL interpolation without null checks, which would fail at runtime if undefined.

Either validate serverUrl regardless of requiresTarget, or update the return type to serverUrl: string | undefined and handle undefined values in callers.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/cli/src/lib/framework.ts` around lines 288 - 339, The function
resolveExecutionContext currently promises serverUrl: string but only enforces
presence when input.requiresTarget is true; change the function's return type to
make serverUrl optional (serverUrl: string | undefined) and update all callers
(e.g., commands like login that use context.serverUrl) to handle the undefined
case explicitly (guard before interpolation or provide a fallback) so runtime
errors are avoided; keep the existing validation branch for requiresTarget as-is
and ensure TypeScript types and any related interfaces referencing
resolveExecutionContext are updated to reflect the optional serverUrl.
🧹 Nitpick comments (13)
apps/cli/src/lib/config.ts (1)

67-81: Good error handling, consider preserving the original error cause.

The error extraction logic correctly handles various error shapes. For improved debuggability, consider preserving the original error as a cause property in the RuntimeError details.

💡 Optional: Preserve original error for debugging
     throw new RuntimeError({
       code: "CONFIG_LOAD_FAILED",
       message: `Failed to load config from "${configPath}": ${message}`,
       statusCode: 400,
-      details: { configPath },
+      details: { configPath, cause: error },
     });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/cli/src/lib/config.ts` around lines 67 - 81, The catch block that builds
and throws the RuntimeError (throw new RuntimeError({...})) should preserve the
original error as a cause: capture the caught error (currently referred to as
error / message) and include it in the RuntimeError construction using the cause
property (e.g., cause: error) or include it inside details (e.g., details: {
configPath, cause: error }) so callers can inspect the original exception;
update the RuntimeError invocation in the catch block that references configPath
and message to attach the original error as the cause.
apps/cli/src/lib/init/git-cleanup.ts (1)

64-98: Function is marked async but uses synchronous operations.

detectTrackedFiles is declared async but only uses synchronous execSync/execFileSync calls. This is misleading and adds unnecessary promise wrapping overhead.

♻️ Remove unnecessary async
-export async function detectTrackedFiles(
+export function detectTrackedFiles(
   cwd: string,
   managedDirectories: string[],
-): Promise<string[]> {
+): string[] {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/cli/src/lib/init/git-cleanup.ts` around lines 64 - 98, The function
detectTrackedFiles is declared async but only uses synchronous
execSync/execFileSync calls; change its signature to a synchronous function
(remove the async keyword and change the return type from Promise<string[]> to
string[]) and keep the current synchronous logic (execSync/execFileSync) inside;
also update any callers of detectTrackedFiles to stop awaiting it (handle the
returned string[] directly) so there’s no needless Promise wrapping.
apps/server/src/lib/content-api.test.ts (1)

1971-1971: Remove unused noopCsrf variable.

The noopCsrf function is defined in all three CMS-151 tests but never used. It appears to be leftover boilerplate.

🧹 Suggested cleanup
 test("CMS-151: stale draftRevision is rejected with 409 STALE_DRAFT_REVISION", async () => {
   const handler = createHandler();
-  const noopCsrf = (headers: Record<string, string> = {}) => headers;

   const created = await createContentDocument(handler, noopCsrf, scopeHeaders, {
+  const created = await createContentDocument(handler, (h) => h, scopeHeaders, {

Apply similar changes to the other two tests.

Also applies to: 2025-2025, 2063-2063

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/server/src/lib/content-api.test.ts` at line 1971, Remove the unused
noopCsrf helper from the CMS-151 tests: delete the const noopCsrf = (headers:
Record<string, string> = {}) => headers; declarations wherever they appear in
the CMS-151 test blocks in content-api.test.ts (there are three occurrences),
leaving the rest of the tests unchanged.
packages/shared/src/lib/contracts/schema-hash.ts (1)

19-21: Consider sorting object keys for guaranteed deterministic hashing.

JSON.stringify does not guarantee consistent key ordering for objects across all JavaScript engines. While the resolvedSchema is explicitly sorted in serializeResolvedEnvironmentSchema, the rawConfigSnapshot object (especially nested locales.aliases) may have non-deterministic key ordering.

For reliable cross-environment hash consistency, consider using a sorted JSON serializer:

♻️ Suggested approach
+function stableStringify(value: unknown): string {
+  return JSON.stringify(value, (_, v) =>
+    v && typeof v === "object" && !Array.isArray(v)
+      ? Object.fromEntries(Object.entries(v).sort(([a], [b]) => a.localeCompare(b)))
+      : v
+  );
+}
+
 export function buildSchemaSyncPayload(
   config: ParsedMdcmsConfig,
   environment: string,
 ): SchemaRegistrySyncPayload {
   const rawConfigSnapshot = toRawConfigSnapshot(config);
   const resolvedSchema = serializeResolvedEnvironmentSchema(
     config,
     environment,
   );
   const schemaHash = createHash("sha256")
-    .update(JSON.stringify({ environment, rawConfigSnapshot, resolvedSchema }))
+    .update(stableStringify({ environment, rawConfigSnapshot, resolvedSchema }))
     .digest("hex");
   return { rawConfigSnapshot, resolvedSchema, schemaHash };
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/shared/src/lib/contracts/schema-hash.ts` around lines 19 - 21, The
hash generation in schemaHash uses JSON.stringify on { environment,
rawConfigSnapshot, resolvedSchema } which can produce non-deterministic key
order; create a deterministic serialization step (e.g., deep-sort object keys or
use a stable stringify) and apply it to rawConfigSnapshot and the full payload
before calling createHash in schemaHash; ensure
serializeResolvedEnvironmentSchema's sorted output is used or re-sorted as part
of this deterministic serializer so the resulting digest("hex") is stable across
JS engines.
apps/cli/src/lib/login.ts (1)

312-322: Verify the hardcoded scopes list is complete and consider externalizing.

The scopes array is hardcoded directly in the login flow. While this works, consider:

  1. Is this the complete set of scopes the CLI needs?
  2. Should this be a constant or configurable for different CLI use cases?

The current scopes appear comprehensive for typical CLI operations (projects, schema, content read/write/delete).

🔧 Optional: Extract scopes to a named constant
+const CLI_LOGIN_SCOPES = [
+  "projects:read",
+  "projects:write",
+  "schema:read",
+  "schema:write",
+  "content:read",
+  "content:read:draft",
+  "content:write",
+  "content:write:draft",
+  "content:delete",
+] as const;
+
 // In the login flow:
             body: JSON.stringify({
               redirectUri: listener.redirectUri,
               state,
-              scopes: [
-                "projects:read",
-                "projects:write",
-                "schema:read",
-                "schema:write",
-                "content:read",
-                "content:read:draft",
-                "content:write",
-                "content:write:draft",
-                "content:delete",
-              ],
+              scopes: CLI_LOGIN_SCOPES,
             }),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/cli/src/lib/login.ts` around lines 312 - 322, The hardcoded scopes array
in the login flow should be validated and extracted: confirm the list
(projects:read/write, schema:read/write, content:read, content:read:draft,
content:write, content:write:draft, content:delete) covers all CLI operations,
then move that array into a named constant (e.g., DEFAULT_OAUTH_SCOPES) and
expose it as configurable (environment variable, config file, or CLI flag) so
callers can override for different use cases; update the code that currently
constructs the OAuth request (the scopes array in login.ts) to reference the
constant and respect any provided override.
apps/cli/src/lib/schema-state.test.ts (1)

3-4: Consider consolidating path imports.

The dirname and join functions are imported from node:path on separate lines. This works but could be cleaner.

🔧 Suggested consolidation
-import { dirname } from "node:path";
-import { join } from "node:path";
+import { dirname, join } from "node:path";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/cli/src/lib/schema-state.test.ts` around lines 3 - 4, Consolidate the
two separate imports from "node:path" into a single import that includes both
dirname and join; locate the import statements that currently import dirname and
join separately and replace them with one line importing { dirname, join } from
"node:path" so the code is cleaner and avoids duplicate module imports.
packages/shared/src/lib/contracts/schema.test.ts (1)

484-494: Consider if this type-usability test adds value.

This test only verifies that SchemaStateFile can be used as a type annotation and that property access works. TypeScript compilation already validates this. Unless there's a specific concern about the type export, this test may be redundant.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/shared/src/lib/contracts/schema.test.ts` around lines 484 - 494, The
test "SchemaStateFile type is usable as a value type" is redundant because
TypeScript already enforces type annotations at compile time; remove this test
block (the test referencing SchemaStateFile) or replace it with a meaningful
runtime check (e.g., validate an actual runtime parser/validator function for
the expected shape) if you intended to assert runtime behavior—locate the test
by the name or the SchemaStateFile symbol and either delete the entire test
function or swap it for a runtime validation that calls your shape validator
instead.
apps/cli/src/lib/schema-state.ts (1)

33-37: Consider validating the parsed JSON structure.

The JSON.parse(raw) as SchemaStateFile cast trusts the file content without validation. If the file is malformed but valid JSON (e.g., {}), it could lead to runtime errors when accessing expected properties downstream.

A Zod schema or simple property check could catch corruption early:

💡 Optional validation example
   try {
-    return JSON.parse(raw) as SchemaStateFile;
+    const parsed = JSON.parse(raw);
+    if (typeof parsed?.schemaHash !== "string") {
+      return undefined;
+    }
+    return parsed as SchemaStateFile;
   } catch {
     return undefined;
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/cli/src/lib/schema-state.ts` around lines 33 - 37, Replace the unchecked
cast "JSON.parse(raw) as SchemaStateFile" with runtime validation: parse raw,
validate the resulting object against a SchemaStateFile shape (either with a Zod
schema like schemaStateFileSchema or explicit property/type checks for required
fields) and only return the object when validation passes; if validation fails,
return undefined (and optionally log the parse/validation error). Ensure you
add/consume a validator symbol (e.g., schemaStateFileSchema or
validateSchemaStateFile) next to the existing JSON.parse(raw) call so downstream
code guaranteed receives a correctly shaped SchemaStateFile.
apps/cli/src/lib/init/generate-config.ts (1)

36-55: Field names and type names should be validated or escaped.

renderType interpolates type.name, type.directory, and field name directly. While these are typically alphanumeric, malformed input could break the generated config.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/cli/src/lib/init/generate-config.ts` around lines 36 - 55, renderType
currently interpolates type.name, type.directory and unquoted field identifiers
directly into the generated config which can produce invalid output for
malformed names; update renderType to validate or escape these values: sanitize
or validate InferredType.name (and fallback or throw on invalid chars) and
escape type.directory using a safe string-escaping helper (e.g., use a function
that JSON-encodes or escapes quotes/backslashes) and ensure field keys are
rendered safely by quoting them (or validating they match identifier regex)
before emitting (refer to renderType, InferredType, and renderFieldValue where
field names are iterated and emitted).
apps/cli/src/lib/init.test.ts (2)

205-205: Unused variable stderrOutput - consider removing or asserting.

The stderrOutput variable is declared but never used. Consider adding an assertion like assert.ok(stderrOutput.includes("503")) to verify the error message, or remove the variable.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/cli/src/lib/init.test.ts` at line 205, The test declares an unused
variable stderrOutput; either remove the declaration or add an assertion to use
it (e.g., assert that stderrOutput contains the expected error code/message).
Locate the variable stderrOutput in init.test.ts and either delete the let
stderrOutput = "" line or replace it by asserting its contents (for example
using assert.ok or expect) where the test captures stderr, ensuring the test
actually verifies the error output.

129-129: Unused variable stdoutOutput - consider removing or asserting.

The stdoutOutput variable captures stdout but is never used in assertions. Either remove it or add assertions to verify expected output messages.

Suggested fix
-    let stdoutOutput = "";
-
     const command = createInitCommand({
       prompter,
       fetcher,
       skipAuth: true,
     });

     const exitCode = await runMdcmsCli(["init"], {
       cwd,
       commands: [command],
-      stdout: {
-        write: (chunk: string) => {
-          stdoutOutput += chunk;
-        },
-      },
+      stdout: { write: () => undefined },
       stderr: { write: () => undefined },
       fetcher,
     });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/cli/src/lib/init.test.ts` at line 129, The test declares a unused
variable stdoutOutput in init.test.ts; either remove its declaration and any
associated stdout capture setup, or add assertions that validate expected CLI
output (e.g., assert stdoutOutput contains the expected strings) so the variable
is used; locate the stdoutOutput variable and update the surrounding test body
(the test function and any mocking of process.stdout or capture helpers)
accordingly.
apps/cli/src/lib/init/scan.ts (2)

92-98: Silent failure on parse errors may hide issues.

While treating malformed frontmatter as empty is reasonable for a scan function, consider logging a debug-level warning so users can identify files with parsing issues during init.

Optional enhancement
     let frontmatter: Record<string, unknown> = {};
     try {
       const content = await readFile(fullPath, "utf-8");
       const parsed = parseMarkdownDocument(content);
       frontmatter = parsed.frontmatter;
-    } catch {
+    } catch (err) {
       // Malformed frontmatter — treat as empty
+      // Could optionally log: console.debug(`Skipped malformed frontmatter in ${relPath}`);
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/cli/src/lib/init/scan.ts` around lines 92 - 98, The try-catch around
readFile/parseMarkdownDocument currently swallows parse errors silently; modify
the catch in the scan routine to log a debug-level message containing the file
identifier (use fullPath) and the caught error before continuing and treating
frontmatter as empty. Locate the block that calls readFile(fullPath, "utf-8")
and parseMarkdownDocument(...) and add a processLogger.debug or logger.debug
(matching the existing logger in scope) inside the catch to record `fullPath`
and `error` while keeping the existing behavior of setting frontmatter to empty.

61-111: Sequential file reads may slow down large content directories.

The scanner reads files sequentially. For repositories with many content files, consider batching reads with Promise.all (with concurrency limits) for better performance.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/cli/src/lib/init/scan.ts` around lines 61 - 111, The walkDirectory
function currently reads each markdown file sequentially; change it to batch
file reads per directory by collecting file-entry tasks and using a
concurrency-limited Promise.all to parse files in parallel (e.g., use p-limit or
a small worker pool). Keep directory recursion (walkDirectory) synchronous
per-directory traversal but for each directory build an array of async handlers
that call readFile(fullPath, "utf-8"), parseMarkdownDocument(content) and
detectLocaleHint(relPath, frontmatter), then await the limited Promise.all and
push results into results; ensure error handling for malformed frontmatter
remains (catch per-task) and preserve creation of frontmatterKeys and format
logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/cli/package.json`:
- Around line 40-42: The package lists "zod" under devDependencies but the CLI
runtime (see apps/cli/src/lib/init.ts which calls z.string(), z.number(), etc.)
loads zod at runtime, so move "zod": "^4.3.6" from devDependencies into
dependencies in package.json (remove it from devDependencies and add it under
dependencies with the same version), then update the lockfile / reinstall so the
dependency is included for published installs.

In `@apps/cli/src/lib/discover.ts`:
- Around line 55-61: The relative path comparison fails on Windows because
relative(input.cwd, absolutePath) yields backslashes; update the loop that
computes relativePath (used with trackedPaths.has and untracked.push) to
normalize separators to forward slashes before checking/adding (same approach as
scan.ts: import sep from "node:path" and replace all occurrences of sep with "/"
on the relativePath), ensuring trackedPaths.has(relativePath) and later
consumers (e.g., push.ts splitting logic) receive POSIX-style paths.

In `@apps/cli/src/lib/init.ts`:
- Line 494: The call to await prompter.confirm("Confirm inferred types?")
ignores the user's answer; capture its boolean result into a variable and, if
false, abort the init flow (return/throw) or loop back to let the user revise
types before any side effects; specifically, update the code around
prompter.confirm in init.ts to: const confirmed = await prompter.confirm(...);
if (!confirmed) return (or re-prompt) so that subsequent operations that write
mdcms.config.ts or call syncSchema()/importContent() do not run.
- Around line 638-649: When setting locale for an imported file in the block
that currently checks file.localeHint, change the resolution to consult the
user-provided alias map before falling back to the raw value: look up
localeConfig?.aliases[file.localeHint.rawValue] and use that mapped value if
present, otherwise call normalizeLocale(file.localeHint.rawValue) and then fall
back to file.localeHint.rawValue; update the code that assigns locale (the
variable named locale in this block) to use this alias-first logic so files like
post.english.md honor detectLocaleConfig() mappings.

In `@apps/cli/src/lib/init/detect-locale.ts`:
- Around line 100-108: The code only sets type.localized when typeLocales.size
>= 2; change the check to >= 1 so any type whose filenames encode a locale (even
a single locale like *.en.md or en/) is marked localized. Update the condition
involving typeLocales, type.localized and hasMultiLocaleType in detect-locale.ts
(the block that currently uses "if (typeLocales.size >= 2)") to use ">= 1" so
those types are treated as localized and later have their locale suffix/folder
stripped.

In `@apps/cli/src/lib/init/generate-config.ts`:
- Around line 84-86: The generated locale lines currently interpolate
lc.defaultLocale and lc.supported without escaping, so inject malicious
characters or break the output; update the code in generate-config.ts where
lines.push is called for the default and supported entries to emit properly
escaped JSON strings (e.g., use JSON.stringify or an equivalent string-escaping
helper) for lc.defaultLocale and for the array of lc.supported values (serialize
the whole array with JSON.stringify instead of manual map/join) so both default
and supported locale values are safely escaped in the generated config.
- Around line 73-78: The template construction in generate-config.ts uses direct
interpolation (lines.push calls referencing input.project, input.environment,
input.serverUrl, and input.contentDirectories.map(...)) which can break if
values contain quotes; update those pushes to escape values safely by passing
each user value through JSON.stringify (including each element inside
input.contentDirectories) before inserting into the generated TypeScript so the
produced strings are properly quoted and escaped.

In `@apps/cli/src/lib/init/git-cleanup.ts`:
- Around line 100-131: Remove the unnecessary async/Promise typing from
untrackFiles and detectTrackedFiles since they only use execFileSync/execSync
and return synchronously: drop the async keyword and change the return types
from Promise<string[]> (or Promise<...>) to plain string[] (or the appropriate
non-promise type) and return the value directly. Update all call sites that
currently await these functions to call them synchronously (remove await) —
specifically the two production places that call untrackFiles/detectTrackedFiles
and the corresponding test that awaits them. Keep the existing parsing logic (no
regex changes) and ensure exported signatures and tests reflect the non-async
return types.

In `@apps/cli/src/lib/init/infer-schema.test.ts`:
- Around line 20-38: The inferSchema implementation currently marks all inferred
fields optional; update the logic in inferSchema where field metadata is
constructed (use the tracked count for each field) so that optional is set to
count < fileCount rather than always true; locate the block that builds each
field entry (references: inferSchema, the local count variable, and the
fileCount property) and change the optional assignment to evaluate whether the
field appears in every file.

In `@apps/cli/src/lib/pull.ts`:
- Around line 407-413: The code deletes the old file (rm(join(input.context.cwd,
change.previousPath))) before writing the replacement, so if
writeContentFile(...) fails the local copy is lost; change the sequence for
move/rename cases (where change.status === "Moved/Renamed" || "Moved/Renamed
(locally modified)" and change.previousPath exists) to first create/write the
new content (call writeContentFile for change.path in the target cwd) and only
after successful write remove the previousPath; apply the same ordering fix to
the other similar block that removes previousPath around writeContentFile
(ensure removal is skipped on write failure).

In `@apps/cli/src/lib/push.ts`:
- Around line 46-52: The deletion flow is sending unconditional DELETEs and
ignores the draftRevision/publishedVersion carried in DeletionCandidate, so make
deletes conflict-aware by passing the revision constraints through to the server
and failing if they don't match: update deleteDocument(...) (and the analogous
logic at the other locations flagged) to accept a DeletionCandidate (or include
draftRevision/publishedVersion) and send them with the delete request (e.g., as
If-Match/If-Unmodified-Since headers or as body/query params per API) so the
server can reject stale deletions; on conflict, surface a clear error and skip
removing the local file. Ensure all call sites that build DeletionCandidate use
the updated signature.
- Around line 876-899: The catch block around resolveCreatePayload(...) is
catching all errors and always emitting a "no content type maps to directory"
warning; change it to only treat the specific "no type mapping" error as a
warning and rethrow or surface other errors (e.g. malformed localized filenames
/ INVALID_LOCAL_DOCUMENT). Specifically, inside the try/catch that calls
resolveCreatePayload (used to build newCandidates), inspect the thrown error
(error.code, error.name or a sentinel from resolveCreatePayload) and: if it
matches the type-mapping-not-found case, emit the current warning using
file.path and dir; otherwise rethrow the error (or write an appropriate error
message) so malformed filenames and INVALID_LOCAL_DOCUMENT failures are not
silently swallowed.

In `@apps/cli/src/lib/validate.ts`:
- Around line 123-128: The date branch currently accepts any string; update the
"date" case in validate.ts to actually validate date content by allowing Date
instances or non-empty strings that parse to valid dates (e.g., use
Date.parse/new Date and check !isNaN(date.valueOf())). Reject empty strings and
strings that don't produce a valid date, returning an error using the existing
message format with path and typeof value. Ensure you reference the same "case
'date'", value and path variables so behavior and return shape remain unchanged.

In `@apps/server/src/bin/demo-seed-api-key.ts`:
- Around line 19-27: DEMO_KEY_SCOPES currently includes mutating scopes
(content:write, content:delete, schema:write); change seeding to require
explicit opt-in or fail in non-local environments by: make the default
DEMO_KEY_SCOPES read-only (only content:read, content:read:draft, schema:read),
add an explicit boolean guard (e.g., DEMO_SEED_ALLOW_MUTATING or check NODE_ENV
=== "development"/LOCAL flag) before appending mutating scopes to
DEMO_KEY_SCOPES, and if not local and the opt-in flag is missing, throw or exit
to hard-fail; update the code paths that read DEMO_KEY_SCOPES to use this gated
value.

In `@apps/server/src/lib/auth.ts`:
- Around line 3455-3485: The bug is that an empty metadata.contextAllowlist is
treated like "no restrictions" allowing unrestricted keys; change the logic so
empty arrays are treated as "no allowed contexts" (deny), not skip checks:
update the guard around metadata.contextAllowlist and apiKeyAllowsTarget so that
apiKeyAllowsTarget([]) returns false and the code path that currently skips RBAC
when contextAllowlist.length === 0 instead enforces checks; also ensure
assertSessionCanIssueApiKeyScopes continues to perform RBAC evaluation when an
allowlist is empty (i.e., do not short-circuit on empty lists) and add a clear
error when attempting to mint an API key with an empty allowlist for
project/environment-bound keys.
- Around line 3807-3825: The issue is that environment: "*" is stored but
apiKeyAllowsTarget() does exact matches, so project-scoped CLI keys created in
this block (see createApiKeyForUser invocation and normalizeRequestedCliScopes
call) won't match real environments; fix by making the created key use
undefined/null for unspecified environment (instead of the literal "*") or
update apiKeyAllowsTarget() to treat the stored "*" as a wildcard; in practice
prefer changing this creation site to set environment: undefined when
challenge.environment is not provided (and adjust any DB schema handling) or
alternatively implement wildcard logic in apiKeyAllowsTarget() to accept "*" as
matching any target environment.

In `@apps/server/src/lib/content-api/routes.ts`:
- Around line 161-218: The loop currently returns from inside for (const doc of
response.data), so only the first document is processed; fix by changing the
control flow to: 1) iterate over response.data and call
stripUnknownFrontmatterFields(doc.frontmatter, schemaCache.get(doc.type)) for
every doc (use the existing stripUnknownFrontmatterFields and schemaCache logic
inside the loop but do not return), 2) move the options.resolveUsers block out
of the per-document loop so uniqueUserIds = [...new Set(response.data.flatMap(d
=> [d.createdBy, d.updatedBy]))] and await options.resolveUsers(...) runs once
and assigns to response.users, 3) after processing all docs, check if
resolvePaths.length === 0 and return response if so, otherwise call
prepareResolvePlan({ scope, store: options.store, documentType: resolvedType!,
paths: resolvePaths }) once and then replace response.data with
Promise.all(response.data.map(document => applyResolvePlan({ authorize:
options.authorize, request, requiredScope, scope, store: options.store, draft,
document, plan: resolvePlan }))); ensure no early returns inside the
per-document loop and use the existing function names
stripUnknownFrontmatterFields, prepareResolvePlan, and applyResolvePlan.

In `@apps/server/src/lib/projects-api.ts`:
- Around line 222-252: Add a DB-level unique constraint on (projectId, name) for
the environments table and change the create flow to handle insert conflicts
atomically: keep or remove the preflight select (optional) but update the
insertion of environments to either use an upsert/ON CONFLICT handler or catch
the unique-violation error from the DB and rethrow a RuntimeError with code
"INVALID_INPUT" and the same message/details used for duplicates (use the same
message template: Environment with name "${name}" already exists for project
"${normalizedSlug}" and include details: { project: normalizedSlug, name }).
Reference symbols: environments (table), the preflight select that builds
existing, the insert call that returns created, and the RuntimeError with code
"INVALID_INPUT".

In `@docs/adrs/ADR-006-schema-hash-pinning-for-write-clients.md`:
- Line 5: The ADR's metadata field "last_updated" is stale; update the
"last_updated" YAML field in ADR-006-schema-hash-pinning-for-write-clients.md to
the actual revision/acceptance date (e.g., 2026-04-08) so the document reflects
the PR edit date for traceability.

In `@docs/specs/SPEC-008-cli-and-sdk.md`:
- Line 117: Update the description at the earlier occurrence that says
credentials are "keyed by `serverUrl + project + environment`" so it matches the
later detailed behavior: change it to state the credential store is keyed by
`serverUrl` only (remove `+ project + environment`), and clarify that login is
not scoped to project/environment; ensure any references to scoping in the
wizard or "credential store" text use the `serverUrl`-only key consistently
throughout the document.

---

Outside diff comments:
In `@apps/cli/src/lib/framework.ts`:
- Around line 288-339: The function resolveExecutionContext currently promises
serverUrl: string but only enforces presence when input.requiresTarget is true;
change the function's return type to make serverUrl optional (serverUrl: string
| undefined) and update all callers (e.g., commands like login that use
context.serverUrl) to handle the undefined case explicitly (guard before
interpolation or provide a fallback) so runtime errors are avoided; keep the
existing validation branch for requiresTarget as-is and ensure TypeScript types
and any related interfaces referencing resolveExecutionContext are updated to
reflect the optional serverUrl.

---

Nitpick comments:
In `@apps/cli/src/lib/config.ts`:
- Around line 67-81: The catch block that builds and throws the RuntimeError
(throw new RuntimeError({...})) should preserve the original error as a cause:
capture the caught error (currently referred to as error / message) and include
it in the RuntimeError construction using the cause property (e.g., cause:
error) or include it inside details (e.g., details: { configPath, cause: error
}) so callers can inspect the original exception; update the RuntimeError
invocation in the catch block that references configPath and message to attach
the original error as the cause.

In `@apps/cli/src/lib/init.test.ts`:
- Line 205: The test declares an unused variable stderrOutput; either remove the
declaration or add an assertion to use it (e.g., assert that stderrOutput
contains the expected error code/message). Locate the variable stderrOutput in
init.test.ts and either delete the let stderrOutput = "" line or replace it by
asserting its contents (for example using assert.ok or expect) where the test
captures stderr, ensuring the test actually verifies the error output.
- Line 129: The test declares a unused variable stdoutOutput in init.test.ts;
either remove its declaration and any associated stdout capture setup, or add
assertions that validate expected CLI output (e.g., assert stdoutOutput contains
the expected strings) so the variable is used; locate the stdoutOutput variable
and update the surrounding test body (the test function and any mocking of
process.stdout or capture helpers) accordingly.

In `@apps/cli/src/lib/init/generate-config.ts`:
- Around line 36-55: renderType currently interpolates type.name, type.directory
and unquoted field identifiers directly into the generated config which can
produce invalid output for malformed names; update renderType to validate or
escape these values: sanitize or validate InferredType.name (and fallback or
throw on invalid chars) and escape type.directory using a safe string-escaping
helper (e.g., use a function that JSON-encodes or escapes quotes/backslashes)
and ensure field keys are rendered safely by quoting them (or validating they
match identifier regex) before emitting (refer to renderType, InferredType, and
renderFieldValue where field names are iterated and emitted).

In `@apps/cli/src/lib/init/git-cleanup.ts`:
- Around line 64-98: The function detectTrackedFiles is declared async but only
uses synchronous execSync/execFileSync calls; change its signature to a
synchronous function (remove the async keyword and change the return type from
Promise<string[]> to string[]) and keep the current synchronous logic
(execSync/execFileSync) inside; also update any callers of detectTrackedFiles to
stop awaiting it (handle the returned string[] directly) so there’s no needless
Promise wrapping.

In `@apps/cli/src/lib/init/scan.ts`:
- Around line 92-98: The try-catch around readFile/parseMarkdownDocument
currently swallows parse errors silently; modify the catch in the scan routine
to log a debug-level message containing the file identifier (use fullPath) and
the caught error before continuing and treating frontmatter as empty. Locate the
block that calls readFile(fullPath, "utf-8") and parseMarkdownDocument(...) and
add a processLogger.debug or logger.debug (matching the existing logger in
scope) inside the catch to record `fullPath` and `error` while keeping the
existing behavior of setting frontmatter to empty.
- Around line 61-111: The walkDirectory function currently reads each markdown
file sequentially; change it to batch file reads per directory by collecting
file-entry tasks and using a concurrency-limited Promise.all to parse files in
parallel (e.g., use p-limit or a small worker pool). Keep directory recursion
(walkDirectory) synchronous per-directory traversal but for each directory build
an array of async handlers that call readFile(fullPath, "utf-8"),
parseMarkdownDocument(content) and detectLocaleHint(relPath, frontmatter), then
await the limited Promise.all and push results into results; ensure error
handling for malformed frontmatter remains (catch per-task) and preserve
creation of frontmatterKeys and format logic.

In `@apps/cli/src/lib/login.ts`:
- Around line 312-322: The hardcoded scopes array in the login flow should be
validated and extracted: confirm the list (projects:read/write,
schema:read/write, content:read, content:read:draft, content:write,
content:write:draft, content:delete) covers all CLI operations, then move that
array into a named constant (e.g., DEFAULT_OAUTH_SCOPES) and expose it as
configurable (environment variable, config file, or CLI flag) so callers can
override for different use cases; update the code that currently constructs the
OAuth request (the scopes array in login.ts) to reference the constant and
respect any provided override.

In `@apps/cli/src/lib/schema-state.test.ts`:
- Around line 3-4: Consolidate the two separate imports from "node:path" into a
single import that includes both dirname and join; locate the import statements
that currently import dirname and join separately and replace them with one line
importing { dirname, join } from "node:path" so the code is cleaner and avoids
duplicate module imports.

In `@apps/cli/src/lib/schema-state.ts`:
- Around line 33-37: Replace the unchecked cast "JSON.parse(raw) as
SchemaStateFile" with runtime validation: parse raw, validate the resulting
object against a SchemaStateFile shape (either with a Zod schema like
schemaStateFileSchema or explicit property/type checks for required fields) and
only return the object when validation passes; if validation fails, return
undefined (and optionally log the parse/validation error). Ensure you
add/consume a validator symbol (e.g., schemaStateFileSchema or
validateSchemaStateFile) next to the existing JSON.parse(raw) call so downstream
code guaranteed receives a correctly shaped SchemaStateFile.

In `@apps/server/src/lib/content-api.test.ts`:
- Line 1971: Remove the unused noopCsrf helper from the CMS-151 tests: delete
the const noopCsrf = (headers: Record<string, string> = {}) => headers;
declarations wherever they appear in the CMS-151 test blocks in
content-api.test.ts (there are three occurrences), leaving the rest of the tests
unchanged.

In `@packages/shared/src/lib/contracts/schema-hash.ts`:
- Around line 19-21: The hash generation in schemaHash uses JSON.stringify on {
environment, rawConfigSnapshot, resolvedSchema } which can produce
non-deterministic key order; create a deterministic serialization step (e.g.,
deep-sort object keys or use a stable stringify) and apply it to
rawConfigSnapshot and the full payload before calling createHash in schemaHash;
ensure serializeResolvedEnvironmentSchema's sorted output is used or re-sorted
as part of this deterministic serializer so the resulting digest("hex") is
stable across JS engines.

In `@packages/shared/src/lib/contracts/schema.test.ts`:
- Around line 484-494: The test "SchemaStateFile type is usable as a value type"
is redundant because TypeScript already enforces type annotations at compile
time; remove this test block (the test referencing SchemaStateFile) or replace
it with a meaningful runtime check (e.g., validate an actual runtime
parser/validator function for the expected shape) if you intended to assert
runtime behavior—locate the test by the name or the SchemaStateFile symbol and
either delete the entire test function or swap it for a runtime validation that
calls your shape validator instead.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 493bcf6f-7981-4e6c-b5d4-65209b33fa0f

📥 Commits

Reviewing files that changed from the base of the PR and between e2733e7 and 53b4258.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (61)
  • apps/cli/package.json
  • apps/cli/src/lib/config.ts
  • apps/cli/src/lib/discover.test.ts
  • apps/cli/src/lib/discover.ts
  • apps/cli/src/lib/framework.test.ts
  • apps/cli/src/lib/framework.ts
  • apps/cli/src/lib/init.test.ts
  • apps/cli/src/lib/init.ts
  • apps/cli/src/lib/init/detect-locale.test.ts
  • apps/cli/src/lib/init/detect-locale.ts
  • apps/cli/src/lib/init/generate-config.test.ts
  • apps/cli/src/lib/init/generate-config.ts
  • apps/cli/src/lib/init/git-cleanup.test.ts
  • apps/cli/src/lib/init/git-cleanup.ts
  • apps/cli/src/lib/init/infer-schema.test.ts
  • apps/cli/src/lib/init/infer-schema.ts
  • apps/cli/src/lib/init/prompt.test.ts
  • apps/cli/src/lib/init/prompt.ts
  • apps/cli/src/lib/init/scan.test.ts
  • apps/cli/src/lib/init/scan.ts
  • apps/cli/src/lib/login.test.ts
  • apps/cli/src/lib/login.ts
  • apps/cli/src/lib/pull.test.ts
  • apps/cli/src/lib/pull.ts
  • apps/cli/src/lib/push.test.ts
  • apps/cli/src/lib/push.ts
  • apps/cli/src/lib/schema-state.test.ts
  • apps/cli/src/lib/schema-state.ts
  • apps/cli/src/lib/schema-sync.test.ts
  • apps/cli/src/lib/schema-sync.ts
  • apps/cli/src/lib/status.test.ts
  • apps/cli/src/lib/status.ts
  • apps/cli/src/lib/validate.test.ts
  • apps/cli/src/lib/validate.ts
  • apps/server/drizzle/0010_keen_blockbuster.sql
  • apps/server/drizzle/meta/0010_snapshot.json
  • apps/server/drizzle/meta/_journal.json
  • apps/server/src/bin/demo-seed-api-key.ts
  • apps/server/src/lib/auth.ts
  • apps/server/src/lib/content-api.integration.test.ts
  • apps/server/src/lib/content-api.test.ts
  • apps/server/src/lib/content-api/database-store.ts
  • apps/server/src/lib/content-api/in-memory-store.ts
  • apps/server/src/lib/content-api/parsing.ts
  • apps/server/src/lib/content-api/responses.ts
  • apps/server/src/lib/content-api/routes.ts
  • apps/server/src/lib/content-api/types.ts
  • apps/server/src/lib/db/schema.ts
  • apps/server/src/lib/demo-seed.ts
  • apps/server/src/lib/projects-api.ts
  • apps/server/src/lib/rbac.ts
  • apps/server/src/lib/runtime-with-modules.ts
  • blazebot/memory/CMS-181.md
  • docs/adrs/ADR-004-project-environment-hierarchy.md
  • docs/adrs/ADR-006-schema-hash-pinning-for-write-clients.md
  • docs/specs/SPEC-004-schema-system-and-sync.md
  • docs/specs/SPEC-008-cli-and-sdk.md
  • packages/shared/package.json
  • packages/shared/src/lib/contracts/schema-hash.ts
  • packages/shared/src/lib/contracts/schema.test.ts
  • packages/shared/src/lib/contracts/schema.ts

Comment thread apps/cli/package.json Outdated
Comment thread apps/cli/src/lib/discover.ts
Comment thread apps/cli/src/lib/init.ts Outdated
Comment thread apps/cli/src/lib/init.ts
Comment thread apps/cli/src/lib/init/detect-locale.ts Outdated
Comment thread apps/server/src/lib/auth.ts Outdated
Comment thread apps/server/src/lib/content-api/routes.ts
Comment thread apps/server/src/lib/projects-api.ts Outdated
Comment thread docs/adrs/ADR-006-schema-hash-pinning-for-write-clients.md Outdated
Comment thread docs/specs/SPEC-008-cli-and-sdk.md Outdated
@woywro
Copy link
Copy Markdown
Collaborator Author

woywro commented Apr 8, 2026

@CodeRabbit pause

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 8, 2026

✅ Actions performed

Reviews paused.

@woywro woywro merged commit 35738ac into main Apr 9, 2026
5 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant