Skip to content

feat(cli): add 'project add domain' command#866

Open
pec1985 wants to merge 3 commits intomainfrom
feat/project-add-domain
Open

feat(cli): add 'project add domain' command#866
pec1985 wants to merge 3 commits intomainfrom
feat/project-add-domain

Conversation

@pec1985
Copy link
Contributor

@pec1985 pec1985 commented Feb 5, 2026

Summary

Add a new project add domain subcommand to configure custom domains for existing Agentuity projects.

Changes

  • New domain.ts subcommand under project add
  • Supports interactive mode (prompts for domain) and direct argument (agentuity project add domain example.com)
  • Validates DNS configuration by checking CNAME records point to the Agentuity proxy
  • Prompts user to proceed if DNS isn't configured yet
  • --skip-validation flag to skip DNS check (domain validated on deploy)
  • dns alias for the command
  • Updates agentuity.json deployment.domains array on success

Usage

# Interactive mode
agentuity project add domain

# Direct mode
agentuity project add domain api.example.com

# Skip DNS validation
agentuity project add domain api.example.com --skip-validation

Testing

  • bun bin/cli.ts project add --help shows the new domain subcommand
  • bun bin/cli.ts project add domain --help shows command options

Summary by CodeRabbit

  • New Features
    • Added a domain subcommand to the project add flow allowing users to add custom domains with interactive prompts and format validation.
    • Built-in DNS validation with guidance on required DNS records and an option to skip validation.
    • Dry-run mode previews domain addition without applying changes; prevents adding duplicates and returns the updated domain list on success.
    • CLI examples updated to show domain usage.

@coderabbitai
Copy link

coderabbitai bot commented Feb 5, 2026

📝 Walkthrough

Walkthrough

Adds a new project add domain subcommand that collects a domain, optionally validates DNS, updates deployment.domains in project config, and returns updated domains. Integrates the subcommand into project add and adds example usages.

Changes

Cohort / File(s) Summary
Domain Subcommand
packages/cli/src/cmd/project/add/domain.ts
New domainSubcommand exported via createSubcommand. Implements full handler: args/options/response schema, dry-run, interactive and non-interactive flows, domain regex validation, DNS check (with spinner, skip flag, guidance on failure), prompts, config load/update to append domain, JSON mode output, and error handling.
Project Add Command Integration
packages/cli/src/cmd/project/add/index.ts
Imported and inserted domainSubcommand into addCommand's subcommands array (placed between database and storage). Added two CLI examples: project add domain and project add domain example.com. Review subcommand ordering and example formatting.
🚥 Pre-merge checks | ✅ 1
✅ Passed checks (1 passed)
Check name Status Explanation
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.


📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 86d9c9c and 19a4db5.

📒 Files selected for processing (1)
  • packages/cli/src/cmd/project/add/domain.ts
🧰 Additional context used
📓 Path-based instructions (3)
packages/cli/src/cmd/**/*.ts

📄 CodeRabbit inference engine (packages/cli/AGENTS.md)

packages/cli/src/cmd/**/*.ts: Use tui.* helpers for formatted output instead of raw console logs
Use ctx.logger for logging; call logger.fatal() to log and exit with code 1

Files:

  • packages/cli/src/cmd/project/add/domain.ts
packages/cli/src/**/*.ts

📄 CodeRabbit inference engine (packages/cli/AGENTS.md)

Use Bun.file(f).exists() instead of existsSync(f) for file existence checks

Files:

  • packages/cli/src/cmd/project/add/domain.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use Prettier formatter with tabs (width 3), single quotes, and semicolons for TypeScript files
Use TypeScript strict mode with ESNext target and bundler moduleResolution
Use StructuredError from @agentuity/core for error handling

Files:

  • packages/cli/src/cmd/project/add/domain.ts
🧠 Learnings (1)
📚 Learning: 2025-12-21T00:31:41.858Z
Learnt from: jhaynie
Repo: agentuity/sdk PR: 274
File: packages/cli/src/cmd/build/vite/server-bundler.ts:12-41
Timestamp: 2025-12-21T00:31:41.858Z
Learning: In Bun runtime, BuildMessage and ResolveMessage are global types and are not exported from the bun module. Do not import { BuildMessage } from 'bun' or similar; these types are available globally and should be used without import. This applies to all TypeScript files that target the Bun runtime within the repository.

Applied to files:

  • packages/cli/src/cmd/project/add/domain.ts
🧬 Code graph analysis (1)
packages/cli/src/cmd/project/add/domain.ts (3)
packages/cli/src/config.ts (2)
  • loadProjectConfig (558-592)
  • updateProjectConfig (658-690)
packages/cli/src/index.ts (1)
  • ErrorCode (12-12)
packages/cli/src/domain.ts (3)
  • isSuccess (54-56)
  • isError (46-48)
  • isMisconfigured (38-40)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: Template Integration Tests
  • GitHub Check: Queue CLI Tests
  • GitHub Check: Playwright E2E Smoke Test
  • GitHub Check: Cloud Deployment Tests
  • GitHub Check: Sandbox CLI Tests
  • GitHub Check: Package Installation & Usage Test
  • GitHub Check: Framework Integration Tests (TanStack & Next.js)
  • GitHub Check: SDK Integration Test Suite
  • GitHub Check: Build
🔇 Additional comments (6)
packages/cli/src/cmd/project/add/domain.ts (6)

1-9: LGTM!

Imports are well-organized and all are utilized in the implementation.


11-47: LGTM!

Schema definition follows Zod 4 patterns correctly. The idempotent: true flag appropriately reflects that adding an existing domain returns success without side effects.


49-66: LGTM!

Dry-run handling correctly prevents mutations and provides informative preview output. The destructuring now properly includes both opts and logger from context.


112-122: LGTM!

Idempotent handling is correct—existing domains return early with success and the current domain list, avoiding duplicate entries.


124-167: LGTM!

DNS validation flow is well-implemented with proper use of type guards (isSuccess, isError, isMisconfigured), informative output for DNS configuration guidance, and graceful user prompting when DNS is not yet configured.


169-193: LGTM!

Config update correctly preserves existing deployment settings using spread operator. The return value properly matches the response schema, and output formatting follows the tui.* helper pattern.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


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

@github-actions
Copy link

github-actions bot commented Feb 5, 2026

📦 Canary Packages Published

version: 1.0.1-19a4db5

Packages
Package Version URL
@agentuity/cli 1.0.1-19a4db5 https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-cli-1.0.1-19a4db5.tgz
@agentuity/runtime 1.0.1-19a4db5 https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-runtime-1.0.1-19a4db5.tgz
@agentuity/postgres 1.0.1-19a4db5 https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-postgres-1.0.1-19a4db5.tgz
@agentuity/server 1.0.1-19a4db5 https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-server-1.0.1-19a4db5.tgz
@agentuity/auth 1.0.1-19a4db5 https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-auth-1.0.1-19a4db5.tgz
@agentuity/react 1.0.1-19a4db5 https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-react-1.0.1-19a4db5.tgz
@agentuity/core 1.0.1-19a4db5 https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-core-1.0.1-19a4db5.tgz
@agentuity/schema 1.0.1-19a4db5 https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-schema-1.0.1-19a4db5.tgz
@agentuity/frontend 1.0.1-19a4db5 https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-frontend-1.0.1-19a4db5.tgz
@agentuity/workbench 1.0.1-19a4db5 https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-workbench-1.0.1-19a4db5.tgz
@agentuity/evals 1.0.1-19a4db5 https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-evals-1.0.1-19a4db5.tgz
@agentuity/opencode 1.0.1-19a4db5 https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-opencode-1.0.1-19a4db5.tgz
@agentuity/drizzle 1.0.1-19a4db5 https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-drizzle-1.0.1-19a4db5.tgz
Install

Add to your package.json:

{
  "dependencies": {
    "@agentuity/cli": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-cli-1.0.1-19a4db5.tgz",
    "@agentuity/runtime": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-runtime-1.0.1-19a4db5.tgz",
    "@agentuity/postgres": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-postgres-1.0.1-19a4db5.tgz",
    "@agentuity/server": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-server-1.0.1-19a4db5.tgz",
    "@agentuity/auth": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-auth-1.0.1-19a4db5.tgz",
    "@agentuity/react": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-react-1.0.1-19a4db5.tgz",
    "@agentuity/core": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-core-1.0.1-19a4db5.tgz",
    "@agentuity/schema": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-schema-1.0.1-19a4db5.tgz",
    "@agentuity/frontend": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-frontend-1.0.1-19a4db5.tgz",
    "@agentuity/workbench": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-workbench-1.0.1-19a4db5.tgz",
    "@agentuity/evals": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-evals-1.0.1-19a4db5.tgz",
    "@agentuity/opencode": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-opencode-1.0.1-19a4db5.tgz",
    "@agentuity/drizzle": "https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-drizzle-1.0.1-19a4db5.tgz"
  }
}

Or install directly:

bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-cli-1.0.1-19a4db5.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-runtime-1.0.1-19a4db5.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-postgres-1.0.1-19a4db5.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-server-1.0.1-19a4db5.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-auth-1.0.1-19a4db5.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-react-1.0.1-19a4db5.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-core-1.0.1-19a4db5.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-schema-1.0.1-19a4db5.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-frontend-1.0.1-19a4db5.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-workbench-1.0.1-19a4db5.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-evals-1.0.1-19a4db5.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-opencode-1.0.1-19a4db5.tgz
bun add https://agentuity-sdk-objects.t3.storageapi.dev/npm/1.0.1-19a4db5/agentuity-drizzle-1.0.1-19a4db5.tgz

Copy link

@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: 1

🤖 Fix all issues with AI agents
In `@packages/cli/src/cmd/project/add/domain.ts`:
- Line 125: The handler destructures ctx without opts, causing a type-cast on
options to read skipValidation; update the handler's parameter destructuring to
include opts (alongside args, options, projectDir, config) and replace the
conditional that uses (options as { skipValidation?: boolean }).skipValidation
with a direct check of opts?.skipValidation so the skipValidation flag from
ctx.opts is used (refer to the handler function and the opts symbol and
skipValidation flag).
🧹 Nitpick comments (2)
packages/cli/src/cmd/project/add/domain.ts (2)

49-66: Dry-run returns success: false which may be misleading.

The dry-run mode returns success: false, but this could confuse consumers expecting a preview of what would succeed. Consider returning success: true to indicate the operation would succeed, or add a dryRun: true field to distinguish.


134-138: Consider handling case where results array is empty.

If checkCustomDomainForDNS returns an empty array, results[0] would be undefined, and the code would silently skip validation. While result && !isSuccess(result) handles undefined, it might be worth explicitly handling this edge case with a warning or error.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 77d0f54 and df7a67f.

📒 Files selected for processing (2)
  • packages/cli/src/cmd/project/add/domain.ts
  • packages/cli/src/cmd/project/add/index.ts
🧰 Additional context used
📓 Path-based instructions (3)
packages/cli/src/cmd/**/*.ts

📄 CodeRabbit inference engine (packages/cli/AGENTS.md)

packages/cli/src/cmd/**/*.ts: Use tui.* helpers for formatted output instead of raw console logs
Use ctx.logger for logging; call logger.fatal() to log and exit with code 1

Files:

  • packages/cli/src/cmd/project/add/domain.ts
  • packages/cli/src/cmd/project/add/index.ts
packages/cli/src/**/*.ts

📄 CodeRabbit inference engine (packages/cli/AGENTS.md)

Use Bun.file(f).exists() instead of existsSync(f) for file existence checks

Files:

  • packages/cli/src/cmd/project/add/domain.ts
  • packages/cli/src/cmd/project/add/index.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use Prettier formatter with tabs (width 3), single quotes, and semicolons for TypeScript files
Use TypeScript strict mode with ESNext target and bundler moduleResolution
Use StructuredError from @agentuity/core for error handling

Files:

  • packages/cli/src/cmd/project/add/domain.ts
  • packages/cli/src/cmd/project/add/index.ts
🧠 Learnings (1)
📚 Learning: 2025-12-21T00:31:41.858Z
Learnt from: jhaynie
Repo: agentuity/sdk PR: 274
File: packages/cli/src/cmd/build/vite/server-bundler.ts:12-41
Timestamp: 2025-12-21T00:31:41.858Z
Learning: In Bun runtime, BuildMessage and ResolveMessage are global types and are not exported from the bun module. Do not import { BuildMessage } from 'bun' or similar; these types are available globally and should be used without import. This applies to all TypeScript files that target the Bun runtime within the repository.

Applied to files:

  • packages/cli/src/cmd/project/add/domain.ts
  • packages/cli/src/cmd/project/add/index.ts
🧬 Code graph analysis (1)
packages/cli/src/cmd/project/add/index.ts (1)
packages/cli/src/cmd/project/add/domain.ts (1)
  • domainSubcommand (11-193)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: Queue CLI Tests
  • GitHub Check: Template Integration Tests
  • GitHub Check: Framework Integration Tests (TanStack & Next.js)
  • GitHub Check: Playwright E2E Smoke Test
  • GitHub Check: Pack & Upload
  • GitHub Check: Sandbox CLI Tests
  • GitHub Check: Cloud Deployment Tests
  • GitHub Check: Build
  • GitHub Check: SDK Integration Test Suite
🔇 Additional comments (9)
packages/cli/src/cmd/project/add/domain.ts (6)

1-10: LGTM!

Imports are well-organized and all utilities are appropriately imported from internal modules.


11-47: LGTM!

The subcommand definition is well-structured with clear metadata, appropriate tags, and comprehensive examples including dry-run usage. Schema definitions using zod are properly typed.


85-110: LGTM!

The interactive prompt handling is well-implemented with proper TTY checks, domain validation regex, and stdin cleanup. The validation logic correctly handles empty input and invalid domain formats.


112-122: LGTM!

Good idempotency handling - returning success with existing domains when the domain is already configured prevents duplicate entries and provides a good user experience.


169-191: LGTM!

The config update and success handling are well-implemented. The spread operator correctly preserves existing deployment settings while updating domains, and appropriate user feedback is provided.


143-145: Use tui.output() instead of raw console.log.

These lines use raw console.log which violates the coding guidelines. The tui module provides tui.output() for formatted output.

As per coding guidelines: packages/cli/src/cmd/**/*.ts: Use tui.* helpers for formatted output instead of raw console logs.

🔧 Proposed fix
-				console.log(`  ${tui.colorInfo('Domain:')}  ${tui.colorPrimary(result.domain)}`);
-				console.log(`  ${tui.colorInfo('Type:')}    ${tui.colorPrimary(result.recordType)}`);
-				console.log(`  ${tui.colorInfo('Target:')}  ${tui.colorPrimary(result.target)}`);
+				tui.output(`  ${tui.colorInfo('Domain:')}  ${tui.colorPrimary(result.domain)}`);
+				tui.output(`  ${tui.colorInfo('Type:')}    ${tui.colorPrimary(result.recordType)}`);
+				tui.output(`  ${tui.colorInfo('Target:')}  ${tui.colorPrimary(result.target)}`);

Likely an incorrect or invalid review comment.

packages/cli/src/cmd/project/add/index.ts (3)

3-3: LGTM!

Import follows the existing pattern for other subcommands.


21-24: LGTM!

Examples are well-structured and consistent with the existing database and storage examples, providing both interactive and direct usage patterns.

Also applies to: 33-36


38-38: LGTM!

The subcommand is correctly integrated in alphabetical order alongside the existing subcommands.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Add a new subcommand to configure custom domains for existing projects.

- Supports interactive mode and direct domain argument
- Validates DNS configuration (CNAME to Agentuity proxy)
- Prompts to proceed if DNS isn't configured yet
- Includes --skip-validation flag to skip DNS check
- Adds 'dns' as an alias for the command
- Updates agentuity.json deployment.domains on success

Co-authored-by: Amp <amp@ampcode.com>
Amp-Thread-ID: https://ampcode.com/threads/T-019c2d4d-a962-7709-91c0-dfb685f6ca02
@pec1985 pec1985 force-pushed the feat/project-add-domain branch from df7a67f to 86d9c9c Compare February 5, 2026 13:50
Copy link

@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: 3

🤖 Fix all issues with AI agents
In `@packages/cli/src/cmd/project/add/domain.ts`:
- Around line 49-50: The handler function currently uses tui.fatal for fatal
exit paths; destructure logger from ctx (e.g., const { args, opts, options,
projectDir, config, logger } = ctx) and replace all tui.fatal(...) calls inside
the async handler and any other fatal calls in this file (including the
occurrences referenced around the handler like the ones at the other exits) with
logger.fatal(...) so the CLI uses ctx.logger for logging and exiting as required
by the guidelines.
- Around line 71-110: The direct-argument branch (args.domain) currently only
normalizes the input but skips format validation; reuse the same domainRegex and
validation logic used in the interactive prompt to validate args.domain after
lowercasing/trimming, and if it fails call tui.fatal with a descriptive message
(e.g., "Please enter a valid domain name") and an appropriate ErrorCode so
invalid domains are rejected before persisting (refer to args.domain, domain,
domainRegex, and the tui.fatal usage in the interactive path).
- Around line 140-146: Replace the raw console.log calls with the CLI formatting
helpers (use tui.write or the appropriate tui.* output helper) so output goes
through the tui renderer; specifically, in the block that currently calls
console.log(`  ${tui.colorInfo('Domain:')} 
${tui.colorPrimary(result.domain)}`), console.log(`  ${tui.colorInfo('Type:')}  
${tui.colorPrimary(result.recordType)}`) and console.log(` 
${tui.colorInfo('Target:')}  ${tui.colorPrimary(result.target)}`) change each to
tui.write(...) (or the project’s standard tui output function) and keep the same
string interpolation and color helpers (tui.colorInfo, tui.colorPrimary) so
formatting remains identical while using tui.newline() and tui.warning() as
before.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between df7a67f and 86d9c9c.

📒 Files selected for processing (2)
  • packages/cli/src/cmd/project/add/domain.ts
  • packages/cli/src/cmd/project/add/index.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/cli/src/cmd/project/add/index.ts
🧰 Additional context used
📓 Path-based instructions (3)
packages/cli/src/cmd/**/*.ts

📄 CodeRabbit inference engine (packages/cli/AGENTS.md)

packages/cli/src/cmd/**/*.ts: Use tui.* helpers for formatted output instead of raw console logs
Use ctx.logger for logging; call logger.fatal() to log and exit with code 1

Files:

  • packages/cli/src/cmd/project/add/domain.ts
packages/cli/src/**/*.ts

📄 CodeRabbit inference engine (packages/cli/AGENTS.md)

Use Bun.file(f).exists() instead of existsSync(f) for file existence checks

Files:

  • packages/cli/src/cmd/project/add/domain.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use Prettier formatter with tabs (width 3), single quotes, and semicolons for TypeScript files
Use TypeScript strict mode with ESNext target and bundler moduleResolution
Use StructuredError from @agentuity/core for error handling

Files:

  • packages/cli/src/cmd/project/add/domain.ts
🧠 Learnings (1)
📚 Learning: 2025-12-21T00:31:41.858Z
Learnt from: jhaynie
Repo: agentuity/sdk PR: 274
File: packages/cli/src/cmd/build/vite/server-bundler.ts:12-41
Timestamp: 2025-12-21T00:31:41.858Z
Learning: In Bun runtime, BuildMessage and ResolveMessage are global types and are not exported from the bun module. Do not import { BuildMessage } from 'bun' or similar; these types are available globally and should be used without import. This applies to all TypeScript files that target the Bun runtime within the repository.

Applied to files:

  • packages/cli/src/cmd/project/add/domain.ts
🧬 Code graph analysis (1)
packages/cli/src/cmd/project/add/domain.ts (3)
packages/cli/src/config.ts (2)
  • loadProjectConfig (558-592)
  • updateProjectConfig (658-690)
packages/cli/src/tui.ts (1)
  • prompt (1744-1765)
packages/cli/src/domain.ts (3)
  • isSuccess (54-56)
  • isError (46-48)
  • isMisconfigured (38-40)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Framework Integration Tests (TanStack & Next.js)
  • GitHub Check: Playwright E2E Smoke Test
  • GitHub Check: Sandbox CLI Tests
  • GitHub Check: Pack & Upload
  • GitHub Check: Cloud Deployment Tests
  • GitHub Check: SDK Integration Test Suite
  • GitHub Check: Build
🔇 Additional comments (4)
packages/cli/src/cmd/project/add/domain.ts (4)

11-47: LGTM: subcommand metadata & schema are solid.
Clear naming, aliases, tags, and schema definitions align well with the CLI conventions.


52-66: Dry-run behavior looks good.
Nice preview messaging and JSON-aware output gating.


112-122: LGTM: idempotent existing-domain handling.
Returning the current domains list is clean and avoids unnecessary writes.


169-191: LGTM: config update + success output.
Clear update path and success messaging; nice JSON gating.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines 71 to 110
let domain: string;

if (args.domain) {
domain = args.domain.toLowerCase().trim();
} else {
const isHeadless = !process.stdin.isTTY || !process.stdout.isTTY;
if (isHeadless) {
tui.fatal(
'Domain name is required in non-interactive mode. Usage: ' +
tui.bold(getCommand('project add domain <domain>')),
ErrorCode.MISSING_ARGUMENT
);
}

const prompt = createPrompt();
const entered = await prompt.text({
message: 'Enter the custom domain',
hint: 'e.g., api.example.com',
validate: (value) => {
if (!value || !value.trim()) {
return 'Domain name is required';
}
const domainRegex = /^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)+$/;
if (!domainRegex.test(value.trim())) {
return 'Please enter a valid domain name';
}
return true;
},
});

if (process.stdin.isTTY) {
process.stdin.pause();
}

if (!entered) {
tui.fatal('Operation cancelled', ErrorCode.USER_CANCELLED);
}

domain = entered.toLowerCase().trim();
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Validate direct CLI argument domains before persisting.
The direct-argument path normalizes the domain but skips format validation, so an invalid domain can be written to agentuity.json, especially with --skip-validation. Consider applying the same regex validation to both entry paths.

🛠️ Suggested fix
-		let domain: string;
+		const domainRegex =
+			/^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)+$/;
+		let domain: string;

 		if (args.domain) {
 			domain = args.domain.toLowerCase().trim();
 		} else {
 			const isHeadless = !process.stdin.isTTY || !process.stdout.isTTY;
 			if (isHeadless) {
 				tui.fatal(
 					'Domain name is required in non-interactive mode. Usage: ' +
 						tui.bold(getCommand('project add domain <domain>')),
 					ErrorCode.MISSING_ARGUMENT
 				);
 			}

 			const prompt = createPrompt();
 			const entered = await prompt.text({
 				message: 'Enter the custom domain',
 				hint: 'e.g., api.example.com',
 				validate: (value) => {
 					if (!value || !value.trim()) {
 						return 'Domain name is required';
 					}
-					const domainRegex = /^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)+$/;
 					if (!domainRegex.test(value.trim())) {
 						return 'Please enter a valid domain name';
 					}
 					return true;
 				},
 			});
@@
 			domain = entered.toLowerCase().trim();
 		}
+
+		if (!domainRegex.test(domain)) {
+			tui.fatal('Please enter a valid domain name', ErrorCode.VALIDATION_FAILED);
+		}
🤖 Prompt for AI Agents
In `@packages/cli/src/cmd/project/add/domain.ts` around lines 71 - 110, The
direct-argument branch (args.domain) currently only normalizes the input but
skips format validation; reuse the same domainRegex and validation logic used in
the interactive prompt to validate args.domain after lowercasing/trimming, and
if it fails call tui.fatal with a descriptive message (e.g., "Please enter a
valid domain name") and an appropriate ErrorCode so invalid domains are rejected
before persisting (refer to args.domain, domain, domainRegex, and the tui.fatal
usage in the interactive path).

name: 'domain',
aliases: ['dns'],
description: 'Add a custom domain to the current project',
tags: ['mutating', 'fast', 'requires-auth', 'requires-project'],
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
tags: ['mutating', 'fast', 'requires-auth', 'requires-project'],
tags: ['mutating', 'slow', 'requires-auth', 'requires-project'],

],
schema: {
args: z.object({
domain: z.string().optional().describe('Domain name to add'),
Copy link
Member

Choose a reason for hiding this comment

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

shouldn't this be required? whats the use case to add add without a domain?

domain = args.domain.toLowerCase().trim();
} else {
const isHeadless = !process.stdin.isTTY || !process.stdout.isTTY;
if (isHeadless) {
Copy link
Member

Choose a reason for hiding this comment

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

if required you don't need this

tui.warning(`Domain "${domain}" is already configured for this project`);
}
return {
success: true,
Copy link
Member

Choose a reason for hiding this comment

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

false

logger.fatal('Operation cancelled', ErrorCode.USER_CANCELLED);
}

domain = entered.toLowerCase().trim();
Copy link
Member

Choose a reason for hiding this comment

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

do what code rabbit says

tui.newline();
}

const prompt = createPrompt();
Copy link
Member

Choose a reason for hiding this comment

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

need to check for TTY

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