Skip to content

chore: migrate worker and mocks into nx packages - #22

Merged
kentcdodds merged 10 commits into
mainfrom
cursor/nx-monorepo-structure-f8d3
Mar 21, 2026
Merged

kentcdodds merged 10 commits into
mainfrom
cursor/nx-monorepo-structure-f8d3

Conversation

@kentcdodds

@kentcdodds kentcdodds commented Mar 20, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • add Nx workspace metadata plus Bun workspaces for the repo root
  • move the main worker into packages/worker and each mock worker into packages/mock-servers/*
  • move the MCP server implementation into packages/worker/src/mcp/* so the worker package owns the server it serves
  • update Wrangler path resolution, generated config paths, CI workflows, test paths, and docs for the new package layout
  • preserve root developer commands while restoring validation and local env loading after the package move
  • sync bun.lock with the workspace manifests so CI bun install --frozen-lockfile succeeds again
  • harden dotenv/Wrangler helpers so .env backfills follow dotenv precedence rules and packaged Wrangler runs share one sync path

Testing

  • bun install --frozen-lockfile
  • bun run format
  • bun run format:check
  • bun test ./packages/worker/src/mcp/mcp-server-e2e.test.ts
  • bun run test:e2e
  • bun run test
  • bun run test:mcp
  • bun run validate
  • GitHub Actions: ✅ Validate
  • GitHub Actions: 🔎 Preview

Summary by CodeRabbit

  • Chores

    • Reorganized repo into an Nx workspace and added package-based worker & mock-server projects.
    • Updated CI/workflow behavior and defaults to operate against the new package layout.
    • Updated documentation throughout to reference relocated source and config locations.
  • New Features

    • Added packageized mock servers and related project manifests.
  • Tools

    • CLI tooling now auto-selects the worker config and syncs root .env into the worker package when needed.
  • Tests

    • Test invocations updated to run against package-scoped test paths.
  • Types

    • Adjusted generated typings to reference the relocated main module and narrowed environment typings.

Note

Medium Risk
Medium risk because it restructures the repo into an Nx/Bun monorepo and rewires CI deploy/test paths and Wrangler config locations, which can break builds, deployments, and local env loading if any path assumptions are missed.

Overview
Migrates the codebase to an Nx monorepo with Bun workspaces, moving the main Worker to packages/worker (including MCP server under packages/worker/src/mcp/*) and mock Workers to packages/mock-servers/* with per-package project.json and manifests.

Updates Wrangler configuration and CI workflows to point at the new config locations and generated config outputs (now under packages/worker/), including secrets syncing, D1 migrations, preview mock deployment loops, and .gitignore entries.

Rewires root scripts, import aliases, and tests to use the new package paths, and adjusts MCP E2E to run Wrangler with --config packages/worker/wrangler.jsonc while copying .env into the package to preserve local secret loading; docs are updated throughout to reflect the new structure, and bun.lock is refreshed (adds nx and workspace packages).

Written by Cursor Bugbot for commit a091583. This will update automatically on new commits. Configure here.

Open in Web Open in Cursor 

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
@coderabbitai

coderabbitai Bot commented Mar 20, 2026 •

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

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

The PR converts the repo to an Nx monorepo layout: moving Worker code to packages/worker/src/, mock servers to packages/mock-servers/*/src/, adding Nx/project manifests, updating import aliases and relative imports, adjusting Wrangler config paths, CI workflow steps, tooling defaults, tests, types, and documentation to the new layout.

Changes

Cohort / File(s) Summary
Monorepo config & workspace
nx.json, package.json
Add Nx workspace config, workspace layout pointing to packages/, add workspaces, Nx scripts, and ESM import mappings (#worker/*, #mcp/*).
Worker package metadata & project
packages/worker/package.json, packages/worker/project.json, packages/worker/wrangler.jsonc
Create worker package manifest and Nx project; update Wrangler main → ./src/index.ts and asset/migrations paths.
Source import migrations (worker & mcp)
packages/worker/src/..., packages/worker/src/mcp/...
Replace many alias imports (#server/*, #shared/*, #sentry/*, #mcp/*) with relative paths; update dynamic import paths; minor string/description tweak in one capability test.
Mock-server packages & configs
packages/mock-servers/*/package.json, packages/mock-servers/*/project.json, packages/mock-servers/*/wrangler.jsonc, packages/mock-servers/*/src/*
Add package manifests and Nx project configs for mock servers; move worker entrypoints to src/worker.ts; update wrangler schema/main and migration dirs; adjust test config references.
CI / Workflows / tooling defaults
.github/workflows/deploy.yml, .github/workflows/preview.yml, tools/ci/production-resources.ts, tools/ci/preview-resources.ts, wrangler-env.ts
Change generated Wrangler output paths to packages/worker/..., iterate mock servers under packages/mock-servers/*, add WRANGLER_CONFIG env passing, switch secret sync to use --config, add auto-injection of default --config and .env sync behavior.
E2E & test updates
packages/worker/src/mcp/mcp-server-e2e.test.ts, tools/prepare-e2e-env.ts, tools/seed-test-data.test.ts, test files under packages/worker/src/...
Add robust .env parsing/updating and syncing, update tests to pass packages/worker/wrangler*.generated.json paths, adjust projectRoot and wrangler invocations in e2e helper.
Type & TS config updates
types/worker-configuration.d.ts, types/tsconfig-worker.json, types/tsconfig-tools.json
Update mainModule and DurableObject import paths to ../packages/worker/src/...; remove several Env string bindings from generated Cloudflare.Env; adjust TS include globs to packages/ locations.
Docs and README
README.md, .cursor/CLOUD.md, docs/**
Update 20+ documentation files and diagrams to reference new packages/worker/src/* and packages/mock-servers/* paths and updated Wrangler config locations.
Ignore / misc
.gitignore, packages/* additions
Ignore .nx and generated Wrangler JSON files under packages/worker/; add new package manifests and small code updates (mostly path changes).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Add GitHub GraphQL capability and docs #20 — Repository layout and mock-server path moves into packages/worker and packages/mock-servers, directly overlapping the same path changes and mock server configurations.

Poem

🐰 In burrows of code I hopped and planned,
Paths shifted, packages neatly scanned,
Workers nested, mocks in rows,
Imports fixed where rivers flow—
A hop, a patch, the tree now stands. 🌿

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: migrating the worker and mock servers into an Nx monorepo package structure, which is the primary objective of this changeset.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ 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 cursor/nx-monorepo-structure-f8d3

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
@kentcdodds
kentcdodds marked this pull request as ready for review March 20, 2026 17:43

@cursor cursor Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Duplicate env key appended instead of replaced
    • Replaced or appended the COOKIE_SECRET entry via a helper so empty existing keys are updated instead of duplicated.
  • ✅ Fixed: New getConfigArg duplicates existing getPortArg logic
    • Extracted shared argument parsing into a reusable helper and reused it for both flags.

Comment thread tools/prepare-e2e-env.ts Outdated
Comment thread wrangler-env.ts
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (7)
mcp/capabilities/meta/meta-run-skill.ts (1)

36-36: Cosmetic change unrelated to monorepo migration.

The formatting change to the description string (unescaping the JSON example quotes) improves readability, but this modification doesn't appear related to the PR's stated objective of migrating to an Nx monorepo structure.

If this was an incidental change during the migration, consider whether it should be in a separate commit or PR for clarity.

💅 Optional: Consider using a template literal for improved readability

For long, multi-sentence strings with embedded examples, template literals can improve maintainability:

-		'Execute a saved skill\'s codemode in the same sandbox as the MCP execute tool. When the skill defines parameters, pass them in params; the code receives them via the params variable or the first function argument. Example: meta_run_skill({ "skill_id": "<id>", "params": { "owner": "kentcdodds", "days": 3 } }). On failure, the structured result includes a hint for updating the skill (meta_update_skill).',
+		`Execute a saved skill's codemode in the same sandbox as the MCP execute tool. When the skill defines parameters, pass them in params; the code receives them via the params variable or the first function argument. Example: meta_run_skill({ "skill_id": "<id>", "params": { "owner": "kentcdodds", "days": 3 } }). On failure, the structured result includes a hint for updating the skill (meta_update_skill).`,

This eliminates the need to escape the apostrophe in "skill's" while maintaining the same output.

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

In `@mcp/capabilities/meta/meta-run-skill.ts` at line 36, The description string
for meta_run_skill was cosmetically changed (unescaped example quotes) which is
unrelated to the monorepo migration; either revert that string back to its
original formatting or move this cosmetic change into its own commit/PR for
separation of concerns, and if you prefer readability use a template literal for
the description (the string assigned to the meta_run_skill capability) so you
can avoid escaping the apostrophe and keep the same output.
packages/worker/src/ai-runtime.ts (1)

9-14: LGTM! Import paths correctly updated for monorepo structure.

The relative import paths are accurate for the new packages/worker/src/ location, correctly navigating up three directory levels to reach the root-level shared/ directory.

💡 Optional: Consider preserving path aliases for maintainability

While the relative paths are correct, moving from path aliases (#shared/*) to relative imports (../../../shared/*) can make the codebase more fragile when files are relocated. If the build tooling supports it, you might consider configuring path aliases in the Nx/TypeScript configuration to maintain cleaner, more maintainable import statements across the monorepo.

This is purely a maintenance consideration and doesn't affect correctness.

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

In `@packages/worker/src/ai-runtime.ts` around lines 9 - 14, No functional change
required—the imports in ai-runtime.ts (the three relative imports:
getRemoteAiLocalDevCredentialsError, AiMode, buildMockAiScenario/MockAiResponse)
are correct for the new packages/worker/src location; leave them as-is but
optionally consider restoring a path alias (e.g., '#shared/*') in the monorepo
TypeScript/Nx config to simplify imports and prevent fragility if files move.
packages/mock-servers/ai/package.json (1)

1-5: LGTM! Minimal but appropriate package manifest.

The package manifest correctly configures the mock AI server as a private ES module package with a properly scoped name (@kody/mock-ai). This is suitable for an internal monorepo package.

📦 Optional: Consider adding descriptive metadata

For better developer experience, you might consider adding optional fields like:

{
  "name": "@kody/mock-ai",
  "version": "0.0.0",
  "description": "Mock AI server for local development",
  "private": true,
  "type": "module"
}

This is entirely optional and doesn't affect functionality, but can help document the package's purpose.

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

In `@packages/mock-servers/ai/package.json` around lines 1 - 5, Add optional
descriptive metadata to the package manifest by updating the JSON object to
include "version" and "description" fields alongside the existing "name",
"private", and "type" keys; specifically, add a "version" (e.g., "0.0.0") and a
short "description" (e.g., "Mock AI server for local development") to
package.json to improve developer discoverability while keeping "private": true
and "type": "module" unchanged.
tools/prepare-e2e-env.ts (1)

7-16: Consider handling quoted values in dotenv parsing.

The parseDotenvValue helper doesn't strip surrounding quotes from values. If .env contains COOKIE_SECRET="some-value" or COOKIE_SECRET='some-value', the returned value will include the quotes, which could cause issues when the secret is used.

🔧 Optional fix to handle quoted values
 function parseDotenvValue(content: string, key: string) {
 	for (const rawLine of content.split(/\r?\n/)) {
 		const line = rawLine.trim()
 		if (!line || line.startsWith('#')) continue
 		const withoutExport = line.startsWith('export ') ? line.slice(7) : line
 		if (!withoutExport.startsWith(`${key}=`)) continue
-		return withoutExport.slice(key.length + 1).trim()
+		const value = withoutExport.slice(key.length + 1).trim()
+		if ((value.startsWith('"') && value.endsWith('"')) ||
+		    (value.startsWith("'") && value.endsWith("'"))) {
+			return value.slice(1, -1)
+		}
+		return value
 	}
 	return null
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/prepare-e2e-env.ts` around lines 7 - 16, The parseDotenvValue function
currently returns values with surrounding quotes intact (e.g.,
COOKIE_SECRET="x"), causing downstream issues; update parseDotenvValue to detect
and strip matching surrounding single or double quotes from the extracted value
(and unescape common escaped characters if present) before returning, making
sure to still trim whitespace and handle empty/null correctly so callers of
parseDotenvValue receive the actual unquoted secret.
packages/worker/src/oauth-handlers.ts (1)

5-14: Same import path strategy concern as index.ts.

These imports were also changed from alias-based (#server/*) to relative paths (../../../server/*), creating the same fragility and maintenance concerns discussed in packages/worker/src/index.ts.

The ../../../ paths make the code brittle to directory restructuring. Consider either:

  1. Using the defined aliases consistently for cleaner imports, OR
  2. Removing the unused aliases from package.json if the team prefers relative imports

See the detailed verification script in the index.ts review comment.

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

In `@packages/worker/src/oauth-handlers.ts` around lines 5 - 14, The imports in
oauth-handlers.ts use brittle relative paths (e.g.,
'../../../server/auth-session.ts')—update them to use the project path alias
(e.g., import { readAuthSessionResult, setAuthSessionSecret } from
'#server/auth-session') for all referenced symbols (getRequestIp, logAuditEvent,
readAuthSessionResult, setAuthSessionSecret, getEnv, toHex, verifyPassword,
Layout, render) so they match the rest of the codebase; alternatively, if the
team intentionally prefers relative imports, remove/adjust the path aliases in
package.json/tsconfig so the alias is not expected—pick one approach and apply
it consistently across oauth-handlers.ts (and mirror the same change made to
index.ts).
packages/worker/src/index.ts (1)

3-7: Update imports to use the defined aliases for consistency.

The imports use relative paths (../../../...) while other files across the codebase consistently use the defined aliases (#worker/*, #sentry/*, #mcp/*, #shared/*, #server/*). This file should follow the same pattern for consistency and to avoid brittle relative paths.

Change lines 3-7 to:

import { getWorkerSentryOptions } from '#sentry/cloudflare-options.ts'
import { ChatAgent } from '#worker/chat-agent.ts'
import { MCP } from '#mcp/index.ts'
import { chatAgentBasePath } from '#shared/chat-routes.ts'
import { handleRequest } from '#server/handler.ts'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/worker/src/index.ts` around lines 3 - 7, Replace the brittle
relative imports with the project alias imports: update the import statements
that reference getWorkerSentryOptions, ChatAgent, MCP, chatAgentBasePath, and
handleRequest to use the aliases (`#sentry/`*, `#worker/`*, `#mcp/`*, `#shared/`*,
`#server/`*) instead of ../../../ paths so they match the rest of the codebase and
resolve consistently.
wrangler-env.ts (1)

186-201: Consider adding a notice when overwriting the config directory .env.

The syncDotenvForConfig function silently overwrites any existing .env file in the config directory (e.g., packages/worker/.env). If a developer has customized that file, their changes would be lost without warning.

This might be intentional (always using root .env as source of truth), but consider either:

  1. Logging a notice when copying (so developers know it happened)
  2. Only copying if the target doesn't exist or is older
💡 Optional: Add a notice when copying
 function syncDotenvForConfig(configPath: string | undefined) {
 	if (!configPath) return

 	const rootEnvPath = path.join(process.cwd(), '.env')
 	if (!existsSync(rootEnvPath)) return

 	const resolvedConfigPath = path.resolve(process.cwd(), configPath)
 	const configDir = path.dirname(resolvedConfigPath)
 	const configEnvPath = path.join(configDir, '.env')

 	if (path.resolve(configEnvPath) === path.resolve(rootEnvPath)) {
 		return
 	}

+	console.error(`Syncing .env to ${configEnvPath}`)
 	copyFileSync(rootEnvPath, configEnvPath)
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wrangler-env.ts` around lines 186 - 201, The syncDotenvForConfig function
currently unconditionally overwrites the config directory .env via copyFileSync;
update it to avoid silent overwrites by either (A) logging a clear notice via
the existing logger before copying when configEnvPath already exists, or (B)
only performing the copy when configEnvPath does not exist or when rootEnvPath
is newer than configEnvPath (compare mtimes) — modify syncDotenvForConfig to
check existsSync(configEnvPath) and statSync(...).mtime as appropriate and use
processLogger (or the module logger) to emit a concise message referencing
rootEnvPath and configEnvPath before calling copyFileSync.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@types/worker-configuration.d.ts`:
- Line 28: The generated ProcessEnv typing was narrowed to only
AI_MODE/AI_MODEL/SENTRY_ENVIRONMENT which removed required keys like
COOKIE_SECRET used in types/env-schema.ts and server/handler.ts; restore the
missing env keys by either (a) updating the wrangler config / types input and
regenerating the declarations so ProcessEnv (the interface using
StringifyValues<Pick<Cloudflare.Env, ...>>) includes COOKIE_SECRET and any other
required vars, or (b) add a stable ambient augmentation file that extends the
ProcessEnv interface (or Cloudflare.Env) to declare COOKIE_SECRET and other
non-wrangler-managed secrets so the type contract matches types/env-schema.ts
and usages in server/handler.ts.

---

Nitpick comments:
In `@mcp/capabilities/meta/meta-run-skill.ts`:
- Line 36: The description string for meta_run_skill was cosmetically changed
(unescaped example quotes) which is unrelated to the monorepo migration; either
revert that string back to its original formatting or move this cosmetic change
into its own commit/PR for separation of concerns, and if you prefer readability
use a template literal for the description (the string assigned to the
meta_run_skill capability) so you can avoid escaping the apostrophe and keep the
same output.

In `@packages/mock-servers/ai/package.json`:
- Around line 1-5: Add optional descriptive metadata to the package manifest by
updating the JSON object to include "version" and "description" fields alongside
the existing "name", "private", and "type" keys; specifically, add a "version"
(e.g., "0.0.0") and a short "description" (e.g., "Mock AI server for local
development") to package.json to improve developer discoverability while keeping
"private": true and "type": "module" unchanged.

In `@packages/worker/src/ai-runtime.ts`:
- Around line 9-14: No functional change required—the imports in ai-runtime.ts
(the three relative imports: getRemoteAiLocalDevCredentialsError, AiMode,
buildMockAiScenario/MockAiResponse) are correct for the new packages/worker/src
location; leave them as-is but optionally consider restoring a path alias (e.g.,
'#shared/*') in the monorepo TypeScript/Nx config to simplify imports and
prevent fragility if files move.

In `@packages/worker/src/index.ts`:
- Around line 3-7: Replace the brittle relative imports with the project alias
imports: update the import statements that reference getWorkerSentryOptions,
ChatAgent, MCP, chatAgentBasePath, and handleRequest to use the aliases
(`#sentry/`*, `#worker/`*, `#mcp/`*, `#shared/`*, `#server/`*) instead of ../../../ paths
so they match the rest of the codebase and resolve consistently.

In `@packages/worker/src/oauth-handlers.ts`:
- Around line 5-14: The imports in oauth-handlers.ts use brittle relative paths
(e.g., '../../../server/auth-session.ts')—update them to use the project path
alias (e.g., import { readAuthSessionResult, setAuthSessionSecret } from
'#server/auth-session') for all referenced symbols (getRequestIp, logAuditEvent,
readAuthSessionResult, setAuthSessionSecret, getEnv, toHex, verifyPassword,
Layout, render) so they match the rest of the codebase; alternatively, if the
team intentionally prefers relative imports, remove/adjust the path aliases in
package.json/tsconfig so the alias is not expected—pick one approach and apply
it consistently across oauth-handlers.ts (and mirror the same change made to
index.ts).

In `@tools/prepare-e2e-env.ts`:
- Around line 7-16: The parseDotenvValue function currently returns values with
surrounding quotes intact (e.g., COOKIE_SECRET="x"), causing downstream issues;
update parseDotenvValue to detect and strip matching surrounding single or
double quotes from the extracted value (and unescape common escaped characters
if present) before returning, making sure to still trim whitespace and handle
empty/null correctly so callers of parseDotenvValue receive the actual unquoted
secret.

In `@wrangler-env.ts`:
- Around line 186-201: The syncDotenvForConfig function currently
unconditionally overwrites the config directory .env via copyFileSync; update it
to avoid silent overwrites by either (A) logging a clear notice via the existing
logger before copying when configEnvPath already exists, or (B) only performing
the copy when configEnvPath does not exist or when rootEnvPath is newer than
configEnvPath (compare mtimes) — modify syncDotenvForConfig to check
existsSync(configEnvPath) and statSync(...).mtime as appropriate and use
processLogger (or the module logger) to emit a concise message referencing
rootEnvPath and configEnvPath before calling copyFileSync.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 072a557a-29aa-4496-8b04-7cbd465ddbdd

📥 Commits

Reviewing files that changed from the base of the PR and between cfb4d4e and 003186b.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (71)
  • .cursor/CLOUD.md
  • .github/workflows/deploy.yml
  • .github/workflows/preview.yml
  • .gitignore
  • README.md
  • docs/agents/cloudflare-agents-sdk.md
  • docs/agents/end-to-end-testing.md
  • docs/agents/mcp-apps-starter-guide.md
  • docs/agents/mock-api-servers.md
  • docs/agents/remix/data-table-sqlite.md
  • docs/agents/remix/data-table.md
  • docs/agents/remix/index.md
  • docs/agents/setup.md
  • docs/agents/typescript-setup.md
  • docs/architecture/authentication.md
  • docs/architecture/data-storage.md
  • docs/architecture/index.md
  • docs/architecture/request-lifecycle.md
  • docs/cloudflare-offerings.md
  • docs/environment-variables.md
  • docs/getting-started.md
  • docs/setup-manifest.md
  • mcp/capabilities/coding/coding-capabilities.test.ts
  • mcp/capabilities/meta/meta-run-skill.ts
  • mcp/cursor/cursor-cloud-client.test.ts
  • mcp/github/github-client.test.ts
  • mcp/github/github-graphql-client.test.ts
  • mcp/mcp-server-e2e.test.ts
  • nx.json
  • package.json
  • packages/mock-servers/ai/package.json
  • packages/mock-servers/ai/project.json
  • packages/mock-servers/ai/src/worker.ts
  • packages/mock-servers/ai/wrangler.jsonc
  • packages/mock-servers/cursor/package.json
  • packages/mock-servers/cursor/project.json
  • packages/mock-servers/cursor/src/worker.ts
  • packages/mock-servers/cursor/wrangler.jsonc
  • packages/mock-servers/github/package.json
  • packages/mock-servers/github/project.json
  • packages/mock-servers/github/src/github-mock.test.ts
  • packages/mock-servers/github/src/worker.ts
  • packages/mock-servers/github/wrangler.jsonc
  • packages/mock-servers/resend/package.json
  • packages/mock-servers/resend/project.json
  • packages/mock-servers/resend/src/resend-mock.test.ts
  • packages/mock-servers/resend/src/worker.ts
  • packages/mock-servers/resend/wrangler.jsonc
  • packages/worker/package.json
  • packages/worker/project.json
  • packages/worker/src/ai-runtime.test.ts
  • packages/worker/src/ai-runtime.ts
  • packages/worker/src/capability-maintenance.ts
  • packages/worker/src/chat-agent-routing.ts
  • packages/worker/src/chat-agent.ts
  • packages/worker/src/d1-data-table-adapter.ts
  • packages/worker/src/db.ts
  • packages/worker/src/index.ts
  • packages/worker/src/mcp-auth.test.ts
  • packages/worker/src/mcp-auth.ts
  • packages/worker/src/oauth-handlers.test.ts
  • packages/worker/src/oauth-handlers.ts
  • packages/worker/src/utils.ts
  • packages/worker/wrangler.jsonc
  • tools/ci/preview-resources.ts
  • tools/ci/production-resources.ts
  • tools/prepare-e2e-env.ts
  • tools/seed-test-data.test.ts
  • types/tsconfig-worker.json
  • types/worker-configuration.d.ts
  • wrangler-env.ts

};
declare namespace NodeJS {
interface ProcessEnv extends StringifyValues<Pick<Cloudflare.Env, "AI_MODE" | "AI_MODEL" | "SENTRY_ENVIRONMENT" | "COOKIE_SECRET" | "APP_BASE_URL" | "RESEND_API_BASE_URL" | "RESEND_API_KEY" | "RESEND_FROM_EMAIL" | "AI_GATEWAY_ID" | "CLOUDFLARE_API_TOKEN" | "CLOUDFLARE_ACCOUNT_ID" | "SENTRY_DSN">> {}
interface ProcessEnv extends StringifyValues<Pick<Cloudflare.Env, "AI_MODE" | "AI_MODEL" | "SENTRY_ENVIRONMENT">> {}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Restore required env keys in the generated typing contract.

Line 28 reflects a narrowed env surface, but the app still expects additional vars (for example COOKIE_SECRET is required in types/env-schema.ts and used in server/handler.ts). This creates type/runtime contract drift after the move.

Prefer fixing the source of generation (wrangler config/types input) and regenerating, or add a stable augmentation file for non-Wrangler-managed env keys so required secrets remain typed.

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

In `@types/worker-configuration.d.ts` at line 28, The generated ProcessEnv typing
was narrowed to only AI_MODE/AI_MODEL/SENTRY_ENVIRONMENT which removed required
keys like COOKIE_SECRET used in types/env-schema.ts and server/handler.ts;
restore the missing env keys by either (a) updating the wrangler config / types
input and regenerating the declarations so ProcessEnv (the interface using
StringifyValues<Pick<Cloudflare.Env, ...>>) includes COOKIE_SECRET and any other
required vars, or (b) add a stable ambient augmentation file that extends the
ProcessEnv interface (or Cloudflare.Env) to declare COOKIE_SECRET and other
non-wrangler-managed secrets so the type contract matches types/env-schema.ts
and usages in server/handler.ts.

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
@github-actions

github-actions Bot commented Mar 20, 2026 •

Copy link
Copy Markdown
Contributor

🔎 Preview deployed: https://kody-pr-22.kentcdodds.workers.dev

Worker: kody-pr-22
D1: kody-pr-22-db
KV: kody-pr-22-oauth-kv

Mocks:

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tools/prepare-e2e-env.ts`:
- Around line 7-31: parseDotenvValue and setDotenvValue currently only match
exact `KEY=` with no spaces and take the first match; update them to mirror
runtime parsing by allowing optional whitespace around `=` and after `export`
and by letting the last assignment win. In parseDotenvValue, change the logic to
accept lines like `export? <key>\\s*=\\s*value` (trim quotes if present) and
iterate all lines returning the last matched value instead of the first. In
setDotenvValue, adjust the keyPattern to allow optional spaces around the `=`
and `export`, and when replacing, target the last occurrence of that key (not
the first) so you overwrite the effective runtime value; if no match, append the
new `KEY=value` line as before. Reference functions: parseDotenvValue and
setDotenvValue.
- Around line 33-44: Current logic aborts if .env.example is missing before
checking .env and copies .env.example then exits before validating
COOKIE_SECRET; change flow to first check envPath (existsSync(envPath)) and only
consult/copy examplePath (existsSync(examplePath), copyFileSync(examplePath,
envPath)) when env is missing, and after ensuring env exists (original or
copied) run the COOKIE_SECRET presence/validation (the check around
COOKIE_SECRET at lines 52-58) so that having a pre-existing .env bypasses the
need for .env.example and copied files don’t short-circuit the validation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bbb4b8b0-b7c9-45b1-8fe8-756f748a07b3

📥 Commits

Reviewing files that changed from the base of the PR and between 003186b and 24a661c.

📒 Files selected for processing (2)
  • tools/prepare-e2e-env.ts
  • wrangler-env.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • wrangler-env.ts

Comment thread tools/prepare-e2e-env.ts Outdated
Comment thread tools/prepare-e2e-env.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@wrangler-env.ts`:
- Around line 160-174: The getArgValue function currently uses
inlineArg.split('=') which drops any '=' characters in the value; change the
parsing to only split on the first '=' (e.g., find the first '=' with indexOf
and slice, or use split with a limit of 2) so that inlineArg yields the full
value (e.g., keep reference to getArgValue and the inlineArg variable), and
return undefined if no value after the first '=' as before.
- Around line 176-191: The syncDotenvForConfig function currently
unconditionally calls copyFileSync and can overwrite an existing package .env;
update syncDotenvForConfig to first check if configEnvPath exists and if so read
and compare its contents to rootEnvPath (using rootEnvPath and configEnvPath)
and only perform copyFileSync when the files differ; if the target exists and is
identical, do nothing, and if it exists and differs prefer skipping the
overwrite and emit a clear warning/log message (instead of silently copying) so
developers' custom .env entries (and vars declared in wrangler.jsonc) are
preserved.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d5c3ec04-e08b-4b19-bd4c-3f3d670299f5

📥 Commits

Reviewing files that changed from the base of the PR and between 24a661c and d720550.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (1)
  • wrangler-env.ts

Comment thread wrangler-env.ts
Comment thread wrangler-env.ts Outdated
Comment on lines +176 to +191
function syncDotenvForConfig(configPath: string | undefined) {
if (!configPath) return

const rootEnvPath = path.join(process.cwd(), '.env')
if (!existsSync(rootEnvPath)) return

const resolvedConfigPath = path.resolve(process.cwd(), configPath)
const configDir = path.dirname(resolvedConfigPath)
const configEnvPath = path.join(configDir, '.env')

if (path.resolve(configEnvPath) === path.resolve(rootEnvPath)) {
return
}

copyFileSync(rootEnvPath, configEnvPath)
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Unconditional overwrite may cause unexpected behavior.

The function overwrites packages/worker/.env every time the script runs, regardless of whether the target file already exists or has different content. This could silently discard a developer's custom .env in the worker package.

Additionally, per packages/worker/wrangler.jsonc (lines 22-76), the config already declares vars like AI_MODE and AI_MODEL. When wrangler loads both the copied .env and the hardcoded vars, the precedence may cause unexpected behavior depending on wrangler's loading order.

Consider:

  1. Skipping the copy if the target .env already exists (or logging a warning)
  2. Comparing file contents before overwriting
🛡️ Optional: Skip copy if target exists
 function syncDotenvForConfig(configPath: string | undefined) {
 	if (!configPath) return
 
 	const rootEnvPath = path.join(process.cwd(), '.env')
 	if (!existsSync(rootEnvPath)) return
 
 	const resolvedConfigPath = path.resolve(process.cwd(), configPath)
 	const configDir = path.dirname(resolvedConfigPath)
 	const configEnvPath = path.join(configDir, '.env')
 
 	if (path.resolve(configEnvPath) === path.resolve(rootEnvPath)) {
 		return
 	}
 
+	if (existsSync(configEnvPath)) {
+		// Target .env already exists; skip to avoid overwriting custom config
+		return
+	}
+
 	copyFileSync(rootEnvPath, configEnvPath)
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function syncDotenvForConfig(configPath: string | undefined) {
if (!configPath) return
const rootEnvPath = path.join(process.cwd(), '.env')
if (!existsSync(rootEnvPath)) return
const resolvedConfigPath = path.resolve(process.cwd(), configPath)
const configDir = path.dirname(resolvedConfigPath)
const configEnvPath = path.join(configDir, '.env')
if (path.resolve(configEnvPath) === path.resolve(rootEnvPath)) {
return
}
copyFileSync(rootEnvPath, configEnvPath)
}
function syncDotenvForConfig(configPath: string | undefined) {
if (!configPath) return
const rootEnvPath = path.join(process.cwd(), '.env')
if (!existsSync(rootEnvPath)) return
const resolvedConfigPath = path.resolve(process.cwd(), configPath)
const configDir = path.dirname(resolvedConfigPath)
const configEnvPath = path.join(configDir, '.env')
if (path.resolve(configEnvPath) === path.resolve(rootEnvPath)) {
return
}
if (existsSync(configEnvPath)) {
// Target .env already exists; skip to avoid overwriting custom config
return
}
copyFileSync(rootEnvPath, configEnvPath)
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@wrangler-env.ts` around lines 176 - 191, The syncDotenvForConfig function
currently unconditionally calls copyFileSync and can overwrite an existing
package .env; update syncDotenvForConfig to first check if configEnvPath exists
and if so read and compare its contents to rootEnvPath (using rootEnvPath and
configEnvPath) and only perform copyFileSync when the files differ; if the
target exists and is identical, do nothing, and if it exists and differs prefer
skipping the overwrite and emit a clear warning/log message (instead of silently
copying) so developers' custom .env entries (and vars declared in
wrangler.jsonc) are preserved.

@cursor cursor Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: Misleading error message after control flow refactoring
    • Updated the error message to only reference the missing .env.example file in the current control flow.
  • ✅ Fixed: MCP e2e test bypasses dotenv sync for wrangler
    • Synced the root .env into the worker config directory before each wrangler spawn in the MCP e2e tests.

Comment thread tools/prepare-e2e-env.ts Outdated
Comment thread packages/worker/src/mcp/mcp-server-e2e.test.ts
cursoragent and others added 3 commits March 20, 2026 18:05
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

♻️ Duplicate comments (2)
tools/prepare-e2e-env.ts (2)

33-44: ⚠️ Potential issue | 🟠 Major

Don’t fail fast on missing .env.example before checking existing .env.

Line 33 blocks valid setups where .env already has COOKIE_SECRET, and Line 43 exits success right after copy, skipping the validation path in Lines 52-58 for newly created .env.

Suggested flow fix
-if (!existsSync(examplePath)) {
-	console.error(
-		'Missing .env.example; cannot prepare E2E environment.',
-	)
-	process.exit(1)
-}
-
 if (!existsSync(envPath)) {
+	if (!existsSync(examplePath)) {
+		console.error('Missing .env.example; cannot prepare E2E environment.')
+		process.exit(1)
+	}
 	copyFileSync(examplePath, envPath)
 	console.log('Created .env from .env.example for E2E tests.')
-	process.exit(0)
 }
 
 const envContents = readFileSync(envPath, 'utf8')
 const existingCookieSecret = parseDotenvValue(envContents, 'COOKIE_SECRET')
 if (existingCookieSecret && existingCookieSecret.length > 0) {
 	process.exit(0)
 }
 
+if (!existsSync(examplePath)) {
+	console.error('Missing .env.example; cannot prepare E2E environment.')
+	process.exit(1)
+}
 const exampleContents = readFileSync(examplePath, 'utf8')

Also applies to: 52-58

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

In `@tools/prepare-e2e-env.ts` around lines 33 - 44, Rework the control flow
around examplePath and envPath so we don't fail fast: first check if envPath
exists and validate it contains COOKIE_SECRET (reuse the existing validation
logic present later in the file), and only if envPath is missing attempt to copy
from examplePath; if examplePath is missing then fail, otherwise copy
examplePath to envPath and continue to the same validation path (do not
process.exit(0) immediately after copy). In short: change the order to prefer
validating an existing envPath, remove the early exit after copy, and ensure the
subsequent COOKIE_SECRET validation (the validation block referenced later in
the file) runs for both preexisting and newly copied .env files.

7-31: ⚠️ Potential issue | 🟠 Major

Match dotenv parsing/update semantics to effective runtime values.

Line 12/20 require KEY= (no spaces), and Line 13 returns the first match while dotenv-style configs can include KEY = value and later overrides. This can read/update the wrong COOKIE_SECRET.

Suggested fix
 function parseDotenvValue(content: string, key: string) {
-	for (const rawLine of content.split(/\r?\n/)) {
-		const line = rawLine.trim()
-		if (!line || line.startsWith('#')) continue
-		const withoutExport = line.startsWith('export ') ? line.slice(7) : line
-		if (!withoutExport.startsWith(`${key}=`)) continue
-		return withoutExport.slice(key.length + 1).trim()
-	}
-	return null
+	const keyPattern = new RegExp(
+		`^\\s*(?:export\\s+)?${key}\\s*=\\s*(.*)$`,
+	)
+	let lastValue: string | null = null
+	for (const rawLine of content.split(/\r?\n/)) {
+		const line = rawLine.trim()
+		if (!line || line.startsWith('#')) continue
+		const match = rawLine.match(keyPattern)
+		if (!match) continue
+		lastValue = match[1]?.trim() ?? ''
+	}
+	return lastValue
 }
 
 function setDotenvValue(content: string, key: string, value: string) {
-	const keyPattern = new RegExp(
-		`(^|\\r?\\n)(\\s*(?:export\\s+)?${key}=)[^\\r\\n]*`,
-	)
-	if (keyPattern.test(content)) {
-		return content.replace(
-			keyPattern,
-			(_match, leading, prefix) => `${leading}${prefix}${value}`,
-		)
-	}
-	return content.endsWith('\n')
-		? `${content}${key}=${value}\n`
-		: `${content}\n${key}=${value}\n`
+	const lines = content.split(/\r?\n/)
+	const keyPattern = new RegExp(`^\\s*((?:export\\s+)?${key}\\s*=\\s*).*$`)
+	let lastIndex = -1
+	let prefix = `${key}=`
+	for (let i = 0; i < lines.length; i++) {
+		const match = lines[i]?.match(keyPattern)
+		if (!match) continue
+		lastIndex = i
+		prefix = match[1] ?? prefix
+	}
+	if (lastIndex >= 0) {
+		lines[lastIndex] = `${prefix}${value}`
+		return `${lines.join('\n').replace(/\n*$/, '\n')}`
+	}
+	return `${content.replace(/\n*$/, '\n')}${key}=${value}\n`
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/prepare-e2e-env.ts` around lines 7 - 31, parseDotenvValue and
setDotenvValue currently require "KEY=" with no spaces and only act on the first
match; change both to handle dotenv semantics: allow optional whitespace around
the equals (e.g. "KEY = value"), support quoted values and trimming, and treat
the last occurrence as the effective override (so parseDotenvValue should scan
all lines and return the last matched value for the given key, and
setDotenvValue should update the last occurrence if present). Update the
matching logic in parseDotenvValue to use a regex that accepts optional spaces
and captures the value (then trim surrounding quotes/spaces), and change
setDotenvValue to search globally for matches of the same pattern and replace
only the last match (preserving any "export " prefix and surrounding spacing),
otherwise append a new "KEY=value" line.
🧹 Nitpick comments (1)
packages/worker/src/mcp/mcp-server-e2e.test.ts (1)

47-59: Consider reusing the shared dotenv sync helper to avoid drift.

This function is effectively the same behavior as wrangler-env.ts:176-191 (syncDotenvForConfig). Duplicating this logic in tests increases maintenance risk when sync rules change.

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

In `@packages/worker/src/mcp/mcp-server-e2e.test.ts` around lines 47 - 59, The
syncDotenvForWranglerConfig function duplicates logic from the shared helper
syncDotenvForConfig (in wrangler-env.ts); replace the local function by
importing and calling the shared syncDotenvForConfig to keep behavior
centralized and avoid drift—remove syncDotenvForWranglerConfig and add an import
for syncDotenvForConfig, then invoke syncDotenvForConfig() where the local
function was used.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@tools/prepare-e2e-env.ts`:
- Around line 33-44: Rework the control flow around examplePath and envPath so
we don't fail fast: first check if envPath exists and validate it contains
COOKIE_SECRET (reuse the existing validation logic present later in the file),
and only if envPath is missing attempt to copy from examplePath; if examplePath
is missing then fail, otherwise copy examplePath to envPath and continue to the
same validation path (do not process.exit(0) immediately after copy). In short:
change the order to prefer validating an existing envPath, remove the early exit
after copy, and ensure the subsequent COOKIE_SECRET validation (the validation
block referenced later in the file) runs for both preexisting and newly copied
.env files.
- Around line 7-31: parseDotenvValue and setDotenvValue currently require "KEY="
with no spaces and only act on the first match; change both to handle dotenv
semantics: allow optional whitespace around the equals (e.g. "KEY = value"),
support quoted values and trimming, and treat the last occurrence as the
effective override (so parseDotenvValue should scan all lines and return the
last matched value for the given key, and setDotenvValue should update the last
occurrence if present). Update the matching logic in parseDotenvValue to use a
regex that accepts optional spaces and captures the value (then trim surrounding
quotes/spaces), and change setDotenvValue to search globally for matches of the
same pattern and replace only the last match (preserving any "export " prefix
and surrounding spacing), otherwise append a new "KEY=value" line.

---

Nitpick comments:
In `@packages/worker/src/mcp/mcp-server-e2e.test.ts`:
- Around line 47-59: The syncDotenvForWranglerConfig function duplicates logic
from the shared helper syncDotenvForConfig (in wrangler-env.ts); replace the
local function by importing and calling the shared syncDotenvForConfig to keep
behavior centralized and avoid drift—remove syncDotenvForWranglerConfig and add
an import for syncDotenvForConfig, then invoke syncDotenvForConfig() where the
local function was used.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ff01c3f8-b1e7-4ea3-803f-e2fb10107946

📥 Commits

Reviewing files that changed from the base of the PR and between d720550 and 7574c6b.

📒 Files selected for processing (86)
  • docs/agents/adding-capabilities.md
  • docs/agents/cloudflare-agents-sdk.md
  • docs/agents/mcp-apps-starter-guide.md
  • docs/agents/testing-principles.md
  • docs/agents/typescript-setup.md
  • docs/architecture/data-storage.md
  • docs/architecture/index.md
  • docs/architecture/request-lifecycle.md
  • docs/environment-variables.md
  • docs/mcp-server-patterns.md
  • docs/setup-manifest.md
  • package.json
  • packages/worker/package.json
  • packages/worker/src/capability-maintenance.ts
  • packages/worker/src/chat-agent.ts
  • packages/worker/src/index.ts
  • packages/worker/src/mcp-auth.ts
  • packages/worker/src/mcp/apps/calculator-ui-entry-point.ts
  • packages/worker/src/mcp/capabilities/build-capability-registry.test.ts
  • packages/worker/src/mcp/capabilities/build-capability-registry.ts
  • packages/worker/src/mcp/capabilities/builtin-domains.ts
  • packages/worker/src/mcp/capabilities/capability-reindex.ts
  • packages/worker/src/mcp/capabilities/capability-search.test.ts
  • packages/worker/src/mcp/capabilities/capability-search.ts
  • packages/worker/src/mcp/capabilities/coding/coding-capabilities.test.ts
  • packages/worker/src/mcp/capabilities/coding/cursor-cloud-agent-docs.ts
  • packages/worker/src/mcp/capabilities/coding/cursor-cloud-rest.ts
  • packages/worker/src/mcp/capabilities/coding/domain.ts
  • packages/worker/src/mcp/capabilities/coding/fetch-markdown-doc.ts
  • packages/worker/src/mcp/capabilities/coding/github-docs-path.ts
  • packages/worker/src/mcp/capabilities/coding/github-graphql-api-docs.ts
  • packages/worker/src/mcp/capabilities/coding/github-graphql.ts
  • packages/worker/src/mcp/capabilities/coding/github-rest-api-docs.ts
  • packages/worker/src/mcp/capabilities/coding/github-rest.ts
  • packages/worker/src/mcp/capabilities/coding/index.ts
  • packages/worker/src/mcp/capabilities/define-capability.ts
  • packages/worker/src/mcp/capabilities/define-domain-capability.ts
  • packages/worker/src/mcp/capabilities/define-domain.ts
  • packages/worker/src/mcp/capabilities/domain-metadata.ts
  • packages/worker/src/mcp/capabilities/math/do-math.ts
  • packages/worker/src/mcp/capabilities/math/domain.ts
  • packages/worker/src/mcp/capabilities/math/index.ts
  • packages/worker/src/mcp/capabilities/meta/domain.ts
  • packages/worker/src/mcp/capabilities/meta/meta-delete-skill.ts
  • packages/worker/src/mcp/capabilities/meta/meta-get-skill.ts
  • packages/worker/src/mcp/capabilities/meta/meta-run-skill.ts
  • packages/worker/src/mcp/capabilities/meta/meta-save-skill.ts
  • packages/worker/src/mcp/capabilities/meta/meta-update-skill.ts
  • packages/worker/src/mcp/capabilities/meta/require-user.ts
  • packages/worker/src/mcp/capabilities/registry.ts
  • packages/worker/src/mcp/capabilities/types.ts
  • packages/worker/src/mcp/capabilities/unified-search.test.ts
  • packages/worker/src/mcp/capabilities/unified-search.ts
  • packages/worker/src/mcp/context.test.ts
  • packages/worker/src/mcp/context.ts
  • packages/worker/src/mcp/cursor/cursor-cloud-client.test.ts
  • packages/worker/src/mcp/cursor/cursor-cloud-client.ts
  • packages/worker/src/mcp/executor.ts
  • packages/worker/src/mcp/github/github-client.test.ts
  • packages/worker/src/mcp/github/github-graphql-client.test.ts
  • packages/worker/src/mcp/github/github-graphql-client.ts
  • packages/worker/src/mcp/github/github-rest-client.ts
  • packages/worker/src/mcp/index.ts
  • packages/worker/src/mcp/mcp-server-e2e.test.ts
  • packages/worker/src/mcp/observability.test.ts
  • packages/worker/src/mcp/observability.ts
  • packages/worker/src/mcp/register-resources.ts
  • packages/worker/src/mcp/register-tools.ts
  • packages/worker/src/mcp/resources/calculator-app-resource.ts
  • packages/worker/src/mcp/run-codemode-registry.ts
  • packages/worker/src/mcp/skills/infer-codemode-capabilities.test.ts
  • packages/worker/src/mcp/skills/infer-codemode-capabilities.ts
  • packages/worker/src/mcp/skills/mcp-skills-repo.ts
  • packages/worker/src/mcp/skills/mcp-skills-types.ts
  • packages/worker/src/mcp/skills/skill-embed-and-flags.test.ts
  • packages/worker/src/mcp/skills/skill-embed-and-flags.ts
  • packages/worker/src/mcp/skills/skill-mutation.ts
  • packages/worker/src/mcp/skills/skill-parameters.test.ts
  • packages/worker/src/mcp/skills/skill-parameters.ts
  • packages/worker/src/mcp/skills/skill-vectorize.ts
  • packages/worker/src/mcp/tools/execute.ts
  • packages/worker/src/mcp/tools/open-calculator-ui.ts
  • packages/worker/src/mcp/tools/search.ts
  • tools/prepare-e2e-env.ts
  • types/tsconfig-tools.json
  • types/tsconfig-worker.json
✅ Files skipped from review due to trivial changes (24)
  • packages/worker/src/mcp/github/github-client.test.ts
  • packages/worker/src/mcp/index.ts
  • packages/worker/src/mcp/observability.ts
  • types/tsconfig-tools.json
  • packages/worker/src/mcp/github/github-graphql-client.test.ts
  • packages/worker/src/capability-maintenance.ts
  • packages/worker/src/mcp/capabilities/meta/require-user.ts
  • packages/worker/src/chat-agent.ts
  • docs/agents/testing-principles.md
  • docs/architecture/index.md
  • docs/agents/typescript-setup.md
  • docs/mcp-server-patterns.md
  • docs/agents/adding-capabilities.md
  • packages/worker/src/mcp/capabilities/coding/coding-capabilities.test.ts
  • docs/agents/cloudflare-agents-sdk.md
  • packages/worker/src/mcp/run-codemode-registry.ts
  • packages/worker/src/mcp-auth.ts
  • packages/worker/src/mcp/capabilities/types.ts
  • packages/worker/src/mcp/capabilities/meta/meta-run-skill.ts
  • packages/worker/src/mcp/cursor/cursor-cloud-client.test.ts
  • packages/worker/src/index.ts
  • types/tsconfig-worker.json
  • packages/worker/src/mcp/context.ts
  • packages/worker/package.json
🚧 Files skipped from review as they are similar to previous changes (5)
  • docs/architecture/data-storage.md
  • docs/architecture/request-lifecycle.md
  • docs/setup-manifest.md
  • package.json
  • docs/agents/mcp-apps-starter-guide.md

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

♻️ Duplicate comments (2)
tools/prepare-e2e-env.ts (2)

33-42: ⚠️ Potential issue | 🟠 Major

Don’t require .env.example before you know you need it.

This still fails the happy path when .env already exists with a valid COOKIE_SECRET but .env.example is absent, and the early success exit after copying means the copied .env is never validated. Only consult .env.example in the branches that actually need fallback data, then run the COOKIE_SECRET check after .env is guaranteed to exist.

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

In `@tools/prepare-e2e-env.ts` around lines 33 - 42, The script currently exits if
.env.example is missing before verifying whether .env exists and contains
COOKIE_SECRET, and it exits immediately after copying .env from example without
validating COOKIE_SECRET; change the flow so you first check for envPath and
only if envPath is missing consult examplePath to copy examplePath -> envPath
(using examplePath), remove the premature process.exit(0) after copy, and then
run the COOKIE_SECRET validation after envPath is guaranteed to exist; locate
and update the blocks referencing examplePath, envPath and the COOKIE_SECRET
check to implement this new ordering.

7-16: ⚠️ Potential issue | 🟠 Major

Match dotenv parsing and replacement to the effective assignment.

parseDotenvValue still only recognizes the first exact KEY= form, and setDotenvValue still rewrites the first match. Lines like COOKIE_SECRET = ..., export COOKIE_SECRET=..., or a later override in the file will be handled incorrectly, so this script can skip or backfill against the wrong value.

Also applies to: 18-26

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

In `@tools/prepare-e2e-env.ts` around lines 7 - 16, parseDotenvValue currently
only matches an exact "KEY=" at line start and returns the first hit, which
misses variants like leading "export", extra spaces around the key or "=", and
later overrides; update parseDotenvValue to scan all lines with a regex that
accepts optional "export", any whitespace around the key and "=", and captures
the value (handle optional single/double quotes and trimming), and return the
last matching assignment (the effective value). Similarly update setDotenvValue
to locate and replace the last matching assignment (using the same flexible
regex) rather than the first, and if no match exists append a normalized
assignment ("KEY=value") to the end; reference the functions parseDotenvValue
and setDotenvValue when applying these changes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@tools/prepare-e2e-env.ts`:
- Around line 33-42: The script currently exits if .env.example is missing
before verifying whether .env exists and contains COOKIE_SECRET, and it exits
immediately after copying .env from example without validating COOKIE_SECRET;
change the flow so you first check for envPath and only if envPath is missing
consult examplePath to copy examplePath -> envPath (using examplePath), remove
the premature process.exit(0) after copy, and then run the COOKIE_SECRET
validation after envPath is guaranteed to exist; locate and update the blocks
referencing examplePath, envPath and the COOKIE_SECRET check to implement this
new ordering.
- Around line 7-16: parseDotenvValue currently only matches an exact "KEY=" at
line start and returns the first hit, which misses variants like leading
"export", extra spaces around the key or "=", and later overrides; update
parseDotenvValue to scan all lines with a regex that accepts optional "export",
any whitespace around the key and "=", and captures the value (handle optional
single/double quotes and trimming), and return the last matching assignment (the
effective value). Similarly update setDotenvValue to locate and replace the last
matching assignment (using the same flexible regex) rather than the first, and
if no match exists append a normalized assignment ("KEY=value") to the end;
reference the functions parseDotenvValue and setDotenvValue when applying these
changes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 45d62ed7-141c-45e6-be81-018e74f0057a

📥 Commits

Reviewing files that changed from the base of the PR and between 7574c6b and a091583.

📒 Files selected for processing (1)
  • tools/prepare-e2e-env.ts

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Comment thread packages/mock-servers/ai/src/worker.ts Outdated
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Comment thread packages/mock-servers/ai/package.json Outdated
"type": "module",
"imports": {
"#worker/*": "../../worker/src/*",
"#shared/*": "../../shared/*"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Mock server #shared/* import alias resolves wrong directory

High Severity

The #shared/* import alias in the mock-ai and mock-resend package.json files maps to ../../shared/*, which resolves to packages/shared/*. The actual shared/ directory lives at the repo root, so the correct mapping is ../../../shared/*. Both mock workers actively use this alias (e.g., #shared/mock-ai.ts and #shared/resend-email.ts), so these workers will fail to start.

Additional Locations (1)
Fix in Cursor Fix in Web

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

@cursor, is there a reason we don't just have a @kody-internal/shared package that these packages can use in their deps to reference each other?

Let's fix this issue. Also make sure to take a look at CI and ensure that still works.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Taking a look!

Open in Web Open in Cursor 

- Move root shared/ into packages/shared with workspace exports
- Replace #shared and relative shared imports with @kody-internal/shared
- Export @kody/worker for mock servers; use @kody/worker/db in mocks
- Update tsconfigs, README, test script, and lockfile

Made-with: Cursor
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.

2 participants