/ constants / product.ts
product.ts
 1  export const PRODUCT_URL = 'https://claude.com/claude-code'
 2  
 3  // Claude Code Remote session URLs
 4  export const CLAUDE_AI_BASE_URL = 'https://claude.ai'
 5  export const CLAUDE_AI_STAGING_BASE_URL = 'https://claude-ai.staging.ant.dev'
 6  export const CLAUDE_AI_LOCAL_BASE_URL = 'http://localhost:4000'
 7  
 8  /**
 9   * Determine if we're in a staging environment for remote sessions.
10   * Checks session ID format and ingress URL.
11   */
12  export function isRemoteSessionStaging(
13    sessionId?: string,
14    ingressUrl?: string,
15  ): boolean {
16    return (
17      sessionId?.includes('_staging_') === true ||
18      ingressUrl?.includes('staging') === true
19    )
20  }
21  
22  /**
23   * Determine if we're in a local-dev environment for remote sessions.
24   * Checks session ID format (e.g. `session_local_...`) and ingress URL.
25   */
26  export function isRemoteSessionLocal(
27    sessionId?: string,
28    ingressUrl?: string,
29  ): boolean {
30    return (
31      sessionId?.includes('_local_') === true ||
32      ingressUrl?.includes('localhost') === true
33    )
34  }
35  
36  /**
37   * Get the base URL for Claude AI based on environment.
38   */
39  export function getClaudeAiBaseUrl(
40    sessionId?: string,
41    ingressUrl?: string,
42  ): string {
43    if (isRemoteSessionLocal(sessionId, ingressUrl)) {
44      return CLAUDE_AI_LOCAL_BASE_URL
45    }
46    if (isRemoteSessionStaging(sessionId, ingressUrl)) {
47      return CLAUDE_AI_STAGING_BASE_URL
48    }
49    return CLAUDE_AI_BASE_URL
50  }
51  
52  /**
53   * Get the full session URL for a remote session.
54   *
55   * The cse_→session_ translation is a temporary shim gated by
56   * tengu_bridge_repl_v2_cse_shim_enabled (see isCseShimEnabled). Worker
57   * endpoints (/v1/code/sessions/{id}/worker/*) want `cse_*` but the claude.ai
58   * frontend currently routes on `session_*` (compat/convert.go:27 validates
59   * TagSession). Same UUID body, different tag prefix. Once the server tags by
60   * environment_kind and the frontend accepts `cse_*` directly, flip the gate
61   * off. No-op for IDs already in `session_*` form. See toCompatSessionId in
62   * src/bridge/sessionIdCompat.ts for the canonical helper (lazy-required here
63   * to keep constants/ leaf-of-DAG at module-load time).
64   */
65  export function getRemoteSessionUrl(
66    sessionId: string,
67    ingressUrl?: string,
68  ): string {
69    /* eslint-disable @typescript-eslint/no-require-imports */
70    const { toCompatSessionId } =
71      require('../bridge/sessionIdCompat.js') as typeof import('../bridge/sessionIdCompat.js')
72    /* eslint-enable @typescript-eslint/no-require-imports */
73    const compatId = toCompatSessionId(sessionId)
74    const baseUrl = getClaudeAiBaseUrl(compatId, ingressUrl)
75    return `${baseUrl}/code/${compatId}`
76  }