diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6d2db254..66bc5a5a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
+- CLI: Add `chains` command to list and lookup CCIP chain configurations (uses docs config API)
- SDK: **Breaking**: Reduce bundle size by eliminating cross-chain imports
- Move `DEFAULT_GAS_LIMIT` from `evm/const.ts` to `shared/constants.ts`
- Move BCS codecs and encoding utils to `shared/bcs-codecs.ts` (shared by Aptos/Sui)
diff --git a/ccip-api-ref/docs-cli/chains.mdx b/ccip-api-ref/docs-cli/chains.mdx
new file mode 100644
index 00000000..754c663f
--- /dev/null
+++ b/ccip-api-ref/docs-cli/chains.mdx
@@ -0,0 +1,249 @@
+---
+id: chains
+title: 'chains'
+description: 'List and lookup CCIP chain configurations with chain identifiers, selectors, and family information.'
+sidebar_label: chains
+sidebar_position: 1
+custom_edit_url: null
+---
+
+# chains
+
+
+
+List and lookup CCIP-supported chains with their identifiers, chain selectors, and chain family.
+
+## Synopsis
+
+```bash
+ccip-cli chains [identifier] [options]
+```
+
+## Description
+
+The `chains` command provides chain identifier mappings for CCIP-supported networks. Each chain has:
+
+- **Name**: Internal chain identifier (e.g., `ethereum-mainnet`)
+- **Chain ID**: Native chain identifier (e.g., `1` for Ethereum)
+- **Chain Selector**: Unique CCIP identifier used in cross-chain messaging
+
+Chain data is sourced from the [CCIP Directory](https://docs.chain.link/ccip/directory). Use this command to find the correct identifiers before using other CLI commands like `send`, `show`, or `laneLatency`.
+
+## Arguments
+
+| Argument | Type | Required | Description |
+| -------------- | ------ | -------- | -------------------------------------------------------- |
+| `[identifier]` | string | No | Chain name, chainId, or selector for single chain lookup |
+
+When an identifier is provided, displays detailed information for that chain. Without an identifier, lists all chains.
+
+## Options
+
+### Filter Options
+
+| Option | Alias | Type | Description |
+| ----------- | ----- | ------- | ----------------------------------------------------------- |
+| `--family` | - | string | Filter by chain family: `EVM`, `SVM`, `APTOS`, `SUI`, `TON` |
+| `--mainnet` | - | boolean | Show only mainnet chains |
+| `--testnet` | - | boolean | Show only testnet chains |
+| `--search` | `-s` | string | Search chains by name or display name |
+
+### Output Options
+
+| Option | Alias | Type | Description |
+| --------------- | ----- | ------- | -------------------------------------------- |
+| `--count` | - | boolean | Output chain count only |
+| `--field` | - | string | Extract a single field value (for scripting) |
+| `--interactive` | `-i` | boolean | Interactive search with type-ahead filtering |
+
+See [Configuration](/cli/configuration) for global options (`--format`, etc.).
+
+## Command Builder
+
+Build your `chains` command interactively:
+
+
+
+## Examples
+
+### List all supported chains
+
+```bash
+ccip-cli chains
+```
+
+### Lookup a specific chain by name
+
+```bash
+ccip-cli chains ethereum-mainnet
+```
+
+Output:
+
+```
+Name: ethereum-mainnet
+DisplayName: Ethereum
+Selector: 5009297550715157269
+ChainId: 1
+Family: EVM
+Testnet: false
+Supported: Yes
+```
+
+### Lookup by chain selector
+
+```bash
+ccip-cli chains 5009297550715157269
+```
+
+### Lookup by chain ID
+
+```bash
+ccip-cli chains 1
+```
+
+### Filter by chain family
+
+```bash
+# List all EVM chains
+ccip-cli chains --family EVM
+
+# List all Solana chains
+ccip-cli chains --family SVM
+```
+
+### Filter by network type
+
+```bash
+# Mainnets only
+ccip-cli chains --mainnet
+
+# Testnets only
+ccip-cli chains --testnet
+```
+
+### Search for chains
+
+```bash
+# Find chains with "arbitrum" in the name
+ccip-cli chains -s arbitrum
+
+# Find chains by partial chain ID
+ccip-cli chains -s 42161
+```
+
+### Combine filters
+
+```bash
+# EVM mainnets only
+ccip-cli chains --family EVM --mainnet
+```
+
+### Count chains
+
+```bash
+# Total supported chains
+ccip-cli chains --count
+
+# Count EVM testnets
+ccip-cli chains --family EVM --testnet --count
+```
+
+### Extract specific field for scripting
+
+```bash
+# Get chain selector for use in scripts
+SELECTOR=$(ccip-cli chains ethereum-mainnet --field chainSelector)
+echo $SELECTOR
+# Output: 5009297550715157269
+```
+
+### JSON output
+
+```bash
+ccip-cli chains ethereum-mainnet --format json
+```
+
+Output:
+
+```json
+{
+ "chainId": 1,
+ "chainSelector": "5009297550715157269",
+ "name": "ethereum-mainnet",
+ "family": "EVM",
+ "networkType": "MAINNET",
+ "displayName": "Ethereum",
+ "environment": "mainnet"
+}
+```
+
+### Interactive search mode
+
+```bash
+ccip-cli chains -i
+```
+
+Provides type-ahead filtering to find chains by name.
+
+## Output Fields
+
+### List Output
+
+| Column | Description |
+| ----------- | ---------------------------------------------------- |
+| DisplayName | Human-readable chain name (e.g., `Ethereum`) |
+| Name | Internal chain identifier (e.g., `ethereum-mainnet`) |
+| Selector | CCIP chain selector (unique identifier) |
+| Family | Chain family (EVM, SVM, APTOS, SUI, TON) |
+| Network | Environment (mainnet or testnet) |
+| Supported | Whether chain is supported by CCIP |
+
+### Single Chain Output
+
+| Field | Description |
+| ----------- | ---------------------------------------------------- |
+| Name | Internal chain identifier (e.g., `ethereum-mainnet`) |
+| DisplayName | Human-readable chain name |
+| Selector | CCIP chain selector (use in `--dest`, `--source`) |
+| ChainId | Native chain ID |
+| Family | Chain family |
+| Testnet | Whether chain is a testnet |
+| Supported | Whether chain is supported by CCIP |
+
+## Chain Families
+
+| Family | Description |
+| ------- | ------------------------------- |
+| `EVM` | Ethereum Virtual Machine chains |
+| `SVM` | Solana Virtual Machine (Solana) |
+| `APTOS` | Aptos blockchain |
+| `SUI` | Sui blockchain |
+| `TON` | TON blockchain |
+
+## Data Source
+
+Chain data is fetched from the CCIP docs configuration API, which reflects the current supported chains in the [CCIP Directory](https://docs.chain.link/ccip/directory). The API includes search and filtering capabilities.
+
+Data is cached for 5 minutes to reduce API calls. The SDK's `networkInfo()` provides canonical chain data (name, chainId, selector, family), while the API provides display names.
+
+## See Also
+
+- [CCIP Directory](https://docs.chain.link/ccip/directory) - Official supported chains reference
+- [send](/cli/send) - Send a cross-chain message (use chain name or selector)
+- [show](/cli/show) - Display details of a CCIP request
+- [laneLatency](/cli/lane-latency) - Query lane latency between chains
+- [Configuration](/cli/configuration) - RPC and output format options
+
+## Exit Codes
+
+| Code | Meaning |
+| ---- | -------------------------------------- |
+| `0` | Success - chain(s) found and displayed |
+| `1` | Error (chain not found, API failure) |
+
+Use in scripts:
+
+```bash
+ccip-cli chains ethereum-mainnet --field chainSelector && echo "Found" || echo "Not found"
+```
diff --git a/ccip-api-ref/docs-cli/index.mdx b/ccip-api-ref/docs-cli/index.mdx
index cae6c13d..2e922ea8 100644
--- a/ccip-api-ref/docs-cli/index.mdx
+++ b/ccip-api-ref/docs-cli/index.mdx
@@ -138,6 +138,7 @@ ccip-cli show
| Task | Command | Documentation |
| ----------------------- | ---------------------------------------------------- | ------------------------------------------- |
+| List/lookup chains | `ccip-cli chains [identifier]` | [chains](/cli/chains) |
| Track a message | `ccip-cli show ` | [show](/cli/show) |
| Send a message | `ccip-cli send -s -d -r ` | [send](/cli/send) |
| Execute pending message | `ccip-cli manualExec ` | [manualExec](/cli/manual-exec) |
diff --git a/ccip-api-ref/sidebars-cli.ts b/ccip-api-ref/sidebars-cli.ts
index df5efb15..e6d302c8 100644
--- a/ccip-api-ref/sidebars-cli.ts
+++ b/ccip-api-ref/sidebars-cli.ts
@@ -48,6 +48,11 @@ const sidebars: SidebarsConfig = {
label: 'Commands',
collapsed: false,
items: [
+ {
+ type: 'doc',
+ id: 'chains',
+ label: 'chains',
+ },
{
type: 'doc',
id: 'show',
diff --git a/ccip-cli/README.md b/ccip-cli/README.md
index 902b0640..1fde0afc 100644
--- a/ccip-cli/README.md
+++ b/ccip-cli/README.md
@@ -116,6 +116,44 @@ don't support large ranges)
- `CCIP_VERBOSE=true` → same as `--verbose`
- `CCIP_FORMAT=json` → same as `--format=json`
+### `chains`
+
+```sh
+ccip-cli chains [identifier] [--family EVM|SVM|APTOS|SUI|TON] [--mainnet|--testnet] [-s search]
+```
+
+List and lookup CCIP chain configurations. Use this to find chain names, chain IDs, and chain selectors.
+
+| Option | Alias | Description |
+|--------|-------|-------------|
+| `identifier` | | Chain name, chainId, or selector for single lookup |
+| `--family` | | Filter by chain family |
+| `--mainnet` | | Show only mainnets |
+| `--testnet` | | Show only testnets |
+| `--search` | `-s` | Search chains by name |
+| `--count` | | Output count only |
+| `--field` | | Extract single field value |
+| `--interactive` | `-i` | Interactive type-ahead search |
+
+#### Examples
+
+```sh
+# List all chains
+ccip-cli chains
+
+# Lookup specific chain
+ccip-cli chains ethereum-mainnet
+
+# Filter EVM mainnets
+ccip-cli chains --family EVM --mainnet
+
+# Search for chains
+ccip-cli chains -s arbitrum
+
+# Get chain selector for scripting
+ccip-cli chains ethereum-mainnet --field chainSelector
+```
+
### `send`
```sh
diff --git a/ccip-cli/src/commands/chains.ts b/ccip-cli/src/commands/chains.ts
new file mode 100644
index 00000000..cb4aa2d9
--- /dev/null
+++ b/ccip-cli/src/commands/chains.ts
@@ -0,0 +1,241 @@
+/**
+ * CCIP Chain Discovery Command
+ *
+ * Lists and looks up CCIP chain configurations with support for:
+ * - Single chain lookup by name, chainId, or selector
+ * - Filtering by chain family, mainnet/testnet
+ * - Search for chains by name
+ * - Interactive search with type-ahead filtering
+ * - JSON output for scripting
+ * - Field extraction for specific values
+ */
+
+import { type Logger, ChainFamily, networkInfo } from '@chainlink/ccip-sdk/src/index.ts'
+import { search } from '@inquirer/prompts'
+import type { Argv } from 'yargs'
+
+import type { GlobalOpts } from '../index.ts'
+import { type Ctx, Format } from './types.ts'
+import { getCtx, logParsedError } from './utils.ts'
+import {
+ type ChainInfo,
+ type Environment,
+ fetchAllChains,
+ getAllChainsFlat,
+ searchChainsAPI,
+} from '../services/docs-config-api.ts'
+
+export const command = 'chains [identifier]'
+export const describe = 'List and lookup CCIP chain configuration'
+
+/**
+ * Yargs builder for the chains command.
+ * @param yargs - Yargs instance.
+ * @returns Configured yargs instance with command options.
+ */
+export const builder = (yargs: Argv) =>
+ yargs
+ .positional('identifier', {
+ type: 'string',
+ describe: 'Chain name, chainId, or selector to lookup',
+ })
+ .options({
+ family: {
+ type: 'string',
+ choices: [
+ ChainFamily.EVM,
+ ChainFamily.Solana,
+ ChainFamily.Aptos,
+ ChainFamily.Sui,
+ ChainFamily.TON,
+ ] as const,
+ describe: 'Filter by chain family (EVM, SVM, APTOS, SUI, TON)',
+ },
+ mainnet: { type: 'boolean', describe: 'Show only mainnets' },
+ testnet: { type: 'boolean', describe: 'Show only testnets' },
+ search: { alias: 's', type: 'string', describe: 'Search chains by name' },
+ interactive: {
+ alias: 'i',
+ type: 'boolean',
+ describe: 'Interactive search with type-ahead filtering',
+ },
+ count: { type: 'boolean', describe: 'Show count summary only' },
+ field: { type: 'string', describe: 'Output only a specific field value' },
+ })
+
+/**
+ * Handler for the chains command.
+ * @param argv - Command line arguments.
+ */
+export async function handler(argv: Awaited['argv']> & GlobalOpts) {
+ const [ctx, destroy] = getCtx(argv)
+ return listChains(ctx, argv)
+ .catch((err) => {
+ process.exitCode = 1
+ if (!logParsedError.call(ctx, err)) ctx.logger.error(err)
+ })
+ .finally(destroy)
+}
+
+/**
+ * Helper for BigInt serialization in JSON.
+ */
+function replacer(_key: string, value: unknown) {
+ return typeof value === 'bigint' ? value.toString() : value
+}
+
+async function listChains(
+ ctx: Ctx,
+ argv: Awaited['argv']> & GlobalOpts,
+) {
+ const { logger } = ctx
+
+ // Determine environment from flags (passthrough to API)
+ const environment: Environment | undefined = argv.mainnet
+ ? 'mainnet'
+ : argv.testnet
+ ? 'testnet'
+ : undefined
+
+ // 1. Fetch chains from API (passthrough environment and search to API)
+ const searchTerm = argv.identifier ?? argv.search
+ let chains: ChainInfo[]
+ try {
+ const responses = searchTerm
+ ? await searchChainsAPI(searchTerm, environment, logger)
+ : await fetchAllChains(environment, logger)
+ chains = getAllChainsFlat(responses)
+ } catch (err) {
+ logger.error('Failed to fetch chains from API after retries:', (err as Error).message)
+ process.exitCode = 1
+ return
+ }
+
+ if (chains.length === 0) {
+ logger.error(searchTerm ? `No chains found for: ${searchTerm}` : 'No chains found')
+ process.exitCode = 1
+ return
+ }
+
+ // 2. Apply family filter using SDK's networkInfo for consistent family values
+ if (argv.family) {
+ chains = chains.filter((chain) => {
+ try {
+ const info = networkInfo(BigInt(chain.chainSelector))
+ return info.family === argv.family
+ } catch {
+ // Chain not in SDK - exclude from family filter results
+ return false
+ }
+ })
+ }
+
+ // 3. Output
+ if (argv.count) {
+ logger.log(chains.length)
+ return
+ }
+
+ if (argv.field) {
+ for (const chain of chains) {
+ logger.log(String(chain[argv.field as keyof ChainInfo]))
+ }
+ return
+ }
+
+ if (argv.format === Format.json) {
+ logger.log(JSON.stringify(chains, replacer, 2))
+ return
+ }
+
+ // 6. Interactive search mode
+ if (argv.interactive) {
+ const selected = await interactiveSearch(chains, environment, logger)
+ if (selected) {
+ logger.log(`\nName: ${selected.name}`)
+ logger.log(`DisplayName: ${selected.displayName}`)
+ logger.log(`Selector: ${selected.chainSelector}`)
+ logger.log(`ChainId: ${selected.chainId}`)
+ logger.log(`Family: ${selected.family}`)
+ logger.log(`Environment: ${selected.environment}`)
+ logger.log(`Supported: ${selected.supported ? 'Yes' : 'No'}`)
+ }
+ return
+ }
+
+ // Table output
+ const displayNameWidth = Math.min(
+ 25,
+ Math.max(12, ...chains.map((n) => n.displayName.length)) + 2,
+ )
+ const nameWidth = Math.min(35, Math.max(20, ...chains.map((n) => n.name.length)) + 2)
+ const selectorWidth = 22
+ const familyWidth = 7
+ const envWidth = 9
+ const supportedWidth = 10
+
+ logger.log(
+ 'DisplayName'.padEnd(displayNameWidth) +
+ 'Name'.padEnd(nameWidth) +
+ 'Selector'.padEnd(selectorWidth) +
+ 'Family'.padEnd(familyWidth) +
+ 'Network'.padEnd(envWidth) +
+ 'Supported',
+ )
+ logger.log(
+ '-'.repeat(
+ displayNameWidth + nameWidth + selectorWidth + familyWidth + envWidth + supportedWidth,
+ ),
+ )
+
+ for (const n of chains) {
+ logger.log(
+ n.displayName.padEnd(displayNameWidth) +
+ n.name.padEnd(nameWidth) +
+ n.chainSelector.padEnd(selectorWidth) +
+ n.family.padEnd(familyWidth) +
+ n.environment.padEnd(envWidth) +
+ (n.supported ? 'Yes' : 'No'),
+ )
+ }
+ logger.log(`\nTotal: ${chains.length} chains`)
+}
+
+/**
+ * Interactive search with type-ahead filtering using inquirer/prompts.
+ * Uses API search on each keystroke (passthrough to API).
+ */
+async function interactiveSearch(
+ initialChains: ChainInfo[],
+ environment?: Environment,
+ logger?: Logger,
+): Promise {
+ if (initialChains.length === 0) {
+ return undefined
+ }
+
+ return search({
+ message: 'Search and select a chain:',
+ pageSize: 15,
+ source: async (term) => {
+ // Use API search when term provided, otherwise use initial chains (cached)
+ const chains = term
+ ? getAllChainsFlat(await searchChainsAPI(term, environment, logger))
+ : initialChains
+
+ if (chains.length === 0) {
+ return []
+ }
+
+ const nameWidth = Math.min(30, Math.max(15, ...chains.map((c) => c.displayName.length)))
+ const familyWidth = 8
+
+ return chains.map((chain, i) => ({
+ name: `${chain.displayName.padEnd(nameWidth)} ${chain.family.padEnd(familyWidth)}`,
+ value: chain,
+ short: chain.displayName,
+ description: `${i + 1}/${chains.length} | selector: ${chain.chainSelector}`,
+ }))
+ },
+ })
+}
diff --git a/ccip-cli/src/index.ts b/ccip-cli/src/index.ts
index 60df92b0..3311c528 100755
--- a/ccip-cli/src/index.ts
+++ b/ccip-cli/src/index.ts
@@ -11,7 +11,7 @@ import { Format } from './commands/index.ts'
util.inspect.defaultOptions.depth = 6 // print down to tokenAmounts in requests
// generate:nofail
// `const VERSION = '${require('./package.json').version}-${require('child_process').execSync('git rev-parse --short HEAD').toString().trim()}'`
-const VERSION = '0.96.0-9917492'
+const VERSION = '0.96.0-bee96cb'
// generate:end
const globalOpts = {
diff --git a/ccip-cli/src/services/docs-config-api.ts b/ccip-cli/src/services/docs-config-api.ts
new file mode 100644
index 00000000..569ce54c
--- /dev/null
+++ b/ccip-cli/src/services/docs-config-api.ts
@@ -0,0 +1,191 @@
+/**
+ * CCIP Docs Config API Client
+ * Fetches chain configuration from https://docs.chain.link/api/ccip/v1/chains
+ * Note: This is NOT the official CCIP API - used for display names only
+ */
+
+import {
+ type Logger,
+ CCIPHttpError,
+ DEFAULT_API_RETRY_CONFIG,
+ NetworkType,
+ networkInfo,
+ withRetry,
+} from '@chainlink/ccip-sdk/src/index.ts'
+
+/** Chain details returned by the CCIP docs config API. */
+export interface ChainDetailsAPI {
+ chainId: number | string
+ displayName: string
+ selector: string
+ internalId: string
+ feeTokens: string[]
+ router: string
+ chainFamily: string
+ supported: boolean
+}
+
+/** Response structure from the CCIP docs config API. */
+export interface ChainsAPIResponse {
+ metadata: {
+ environment: 'mainnet' | 'testnet'
+ timestamp: string
+ validChainCount: number
+ }
+ data: Record> // family -> chains
+}
+
+/** Environment type for CCIP chains. */
+export type Environment = 'mainnet' | 'testnet'
+
+/** Chain info from API (passthrough, no SDK processing). */
+export type ChainInfo = {
+ name: string // internalId from API
+ chainId: number | string
+ chainSelector: string
+ family: string // chainFamily from API
+ displayName: string
+ environment: Environment
+ supported: boolean
+}
+
+// Constants
+const API_BASE = 'https://docs.chain.link/api/ccip/v1/chains'
+const CACHE_TTL_MS = 5 * 60 * 1000 // 5 minutes
+
+// Cache structure
+const cache = new Map()
+
+/**
+ * Fetch chains from the CCIP docs config API for a specific environment.
+ * Uses exponential backoff for transient errors.
+ * @param environment - The environment to fetch chains for ('mainnet' or 'testnet')
+ * @param logger - Optional logger for retry attempts
+ * @returns Promise resolving to the API response
+ */
+export async function fetchChains(
+ environment: Environment,
+ logger?: Logger,
+): Promise {
+ // Check cache first
+ const cached = cache.get(environment)
+ if (cached && Date.now() - cached.timestamp < CACHE_TTL_MS) {
+ return cached.data
+ }
+
+ const url = `${API_BASE}?environment=${environment}&outputKey=selector`
+
+ const data = await withRetry(
+ async () => {
+ const response = await fetch(url)
+ if (!response.ok) {
+ throw new CCIPHttpError(response.status, response.statusText)
+ }
+ return (await response.json()) as ChainsAPIResponse
+ },
+ { ...DEFAULT_API_RETRY_CONFIG, logger },
+ )
+
+ cache.set(environment, { data, timestamp: Date.now() })
+ return data
+}
+
+/**
+ * Fetch chains from one or both environments.
+ * Uses exponential backoff for transient errors.
+ * @param environment - Optional environment filter ('mainnet' or 'testnet'). If not provided, fetches both.
+ * @param logger - Optional logger for retry attempts and warnings
+ * @returns Promise resolving to an array of API responses
+ */
+export async function fetchAllChains(
+ environment?: Environment,
+ logger?: Logger,
+): Promise {
+ if (environment) {
+ return [await fetchChains(environment, logger)]
+ }
+ return Promise.all([fetchChains('mainnet', logger), fetchChains('testnet', logger)])
+}
+
+/**
+ * Search chains using the API's search parameter.
+ * The API auto-detects search type (displayName, selector, internalId).
+ * @param search - Search term
+ * @param environment - Optional environment filter ('mainnet' or 'testnet'). If not provided, searches both.
+ * @param logger - Optional logger for retry attempts
+ * @returns Promise resolving to an array of API responses
+ */
+export async function searchChainsAPI(
+ search: string,
+ environment?: Environment,
+ logger?: Logger,
+): Promise {
+ const searchEnv = async (env: Environment): Promise => {
+ const url = `${API_BASE}?environment=${env}&outputKey=selector&search=${encodeURIComponent(search)}`
+
+ return withRetry(
+ async () => {
+ const response = await fetch(url)
+ if (!response.ok) {
+ throw new CCIPHttpError(response.status, response.statusText)
+ }
+ return (await response.json()) as ChainsAPIResponse
+ },
+ { ...DEFAULT_API_RETRY_CONFIG, logger },
+ )
+ }
+
+ if (environment) {
+ return [await searchEnv(environment)]
+ }
+ return Promise.all([searchEnv('mainnet'), searchEnv('testnet')])
+}
+
+/**
+ * Flatten the nested API response structure into a flat array of ChainInfo objects.
+ * Uses SDK's networkInfo for name, family, and environment for consistency.
+ * @param responses - Array of API responses from fetchAllChains
+ * @returns Flat array of ChainInfo objects
+ */
+export function getAllChainsFlat(responses: ChainsAPIResponse[]): ChainInfo[] {
+ const chains: ChainInfo[] = []
+
+ for (const response of responses) {
+ const apiEnvironment = response.metadata.environment
+ for (const familyChains of Object.values(response.data)) {
+ for (const details of Object.values(familyChains)) {
+ // Use SDK networkInfo for consistent name, family, and environment
+ let name = details.internalId
+ let family = details.chainFamily.toUpperCase()
+ let environment: Environment = apiEnvironment
+
+ try {
+ const info = networkInfo(BigInt(details.selector))
+ name = info.name
+ family = info.family
+ environment = info.networkType === NetworkType.Testnet ? 'testnet' : 'mainnet'
+ } catch {
+ // Chain not in SDK - use API values
+ }
+
+ chains.push({
+ name,
+ chainId: details.chainId,
+ chainSelector: details.selector,
+ family,
+ displayName: details.displayName,
+ environment,
+ supported: details.supported,
+ })
+ }
+ }
+ }
+ return chains
+}
+
+/**
+ * Clear the cache for all environments.
+ */
+export function clearCache(): void {
+ cache.clear()
+}
diff --git a/ccip-cli/src/services/index.ts b/ccip-cli/src/services/index.ts
new file mode 100644
index 00000000..b95cd804
--- /dev/null
+++ b/ccip-cli/src/services/index.ts
@@ -0,0 +1 @@
+export * from './docs-config-api.ts'