-
Notifications
You must be signed in to change notification settings - Fork 2
feat: migrate intelligence support #160
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
🦋 Changeset detectedLatest commit: 31df25e The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughAdds an AI Assistant feature: new UI components, streaming chat flow, auth (cloud regions, login with RSA/captcha), context and utilities, hooks, translations (en/zh/ru), styles, package/export updates, dev-proxy, and CI flag change. No existing public API removals. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant Widget as AI Assistant UI
participant Auth as CloudAuthContext
participant Server as /smart/api
Note over Widget,Server: New chat and streaming answer flow
User->>Widget: Type message + Send
Widget->>Widget: Append user msg + placeholder assistant (Thinking)
alt No session
Widget->>Server: POST /new_session (username header)
Server-->>Widget: { session_id }
end
Widget->>Server: POST /smart/api/smart_answer { input_text, session_id }
loop Stream answer
Server-->>Widget: streaming text chunks
Widget->>Widget: parseStreamContent(chunk)
Widget->>Widget: update assistant msg (content/refDocs/thinkingProcess)
end
Widget->>Widget: Auto-scroll chat
Note over Widget: On error → set assistant content to translated NetworkError
sequenceDiagram
autonumber
actor User
participant Preamble as Preamble/LoginForm
participant Cloud as Origin (/api/v1)
participant Auth as CloudAuthContext
Note over Preamble,Cloud: Login with RSA, optional captcha, region selection
User->>Preamble: Select region, enter tenant/username/password
Preamble->>Cloud: GET /pubkey
Cloud-->>Preamble: { pubkey, ts }
Preamble->>Preamble: cryptoPassword(pubkey, password)
Preamble->>Cloud: POST /login (encrypted payload, captchaId if present)
alt Success
Cloud-->>Preamble: { accessToken, ... }
Preamble->>Auth: setAuthBasic({ origin, token })
else PubkeyExpireError
Cloud-->>Preamble: error(reason=PubkeyExpireError)
Preamble->>Preamble: clear cached pubkey and retry
else Error
Cloud-->>Preamble: error(reason, message, captchaId?)
Preamble->>Preamble: show ApiErrorAlert / CaptchaInput if needed
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
Suggested labels
Poem
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
commit: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR implements intelligence support by adding an AI assistant feature with complete login functionality and chat interface. It includes comprehensive UI components for user authentication against cloud portals, chat messaging with streaming responses, and multilingual support.
- Adds AI assistant component with cloud authentication capabilities
- Implements chat interface with streaming responses and document references
- Extends translation support for AI assistant features across multiple languages
Reviewed Changes
Copilot reviewed 45 out of 54 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/doom/styles/*.scss | New SCSS modules for AI assistant, chat, preamble, and form styling |
| packages/doom/src/runtime/translation.ts | Extended translations for AI assistant in English, Chinese, and Russian |
| packages/doom/src/runtime/hooks/* | Added utility hooks for memoized functions and intervals |
| packages/doom/src/global/Intelligence/* | Complete AI assistant implementation with authentication and chat |
| packages/doom/src/cli/load-config.ts | Added proxy configuration for API endpoints |
| packages/doom/package.json | Updated dependencies and exports for new features |
Comments suppressed due to low confidence (2)
packages/doom/styles/intelligence.scss:1
- Hard-coded red color values should use CSS custom properties like other colors in the design system.
.api-error-alert {
packages/doom/styles/intelligence.scss:1
- Hard-coded red color values should use CSS custom properties like other colors in the design system.
.api-error-alert {
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
packages/doom/src/global/Intelligence/AIAssistant/ResizableUserInput/index.tsx
Show resolved
Hide resolved
packages/doom/src/global/Intelligence/AIAssistant/ResizableUserInput/index.tsx
Show resolved
Hide resolved
8449cf6 to
cdaea82
Compare
cdaea82 to
31df25e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 29
♻️ Duplicate comments (7)
packages/doom/styles/chat-ref-docs.module.scss (1)
3-3: Replace hard-coded color with a design tokenUse an existing CSS variable (e.g., var(--rp-c-bg-soft)) for theming consistency and dark-mode support.
- background-color: #f2f8fe; + background-color: var(--rp-c-bg-soft);packages/doom/styles/intelligence.scss (1)
25-29: Use a CSS variable instead of #fff for the primary button textAlign with tokens and ease theme switching.
&--primary { background-color: var(--rp-c-brand-dark); border-radius: 4px; - color: #fff; + color: var(--rp-c-white); }packages/doom/src/global/Intelligence/AIAssistant/Thinking.tsx (1)
19-19: Extract magic number to a named constantApply:
- }, 250) + }, THINKING_ANIMATION_INTERVAL_MS)Add at top:
+const THINKING_ANIMATION_INTERVAL_MS = 250packages/doom/src/global/Intelligence/AIAssistant/utils.ts (2)
1-1: Extract regexes to named constants with docs.Improves readability and testability; aligns with prior feedback.
+const DOCS_BLOCK_REGEX = /<docs>([\s\S]*?)<\/docs>/ +const THINK_BLOCK_REGEX = /<think>([\s\S]*?)<\/think>/gAlso applies to: 31-31
31-38: Correct think-block extraction and typing; current logic always strips the first match and may return a non-string.
- Bug: matched defaults to firstMatched, then removes itself, yielding ''.
- Type: thinkingProcess can become RegExpMatchArray | null, not string | null.
Use a dedicated regex and take the last block’s inner text.Apply:
- const matchThinks = text.match(/<think>[\s\S]*?<\/think>|^[\s\S]*?<\/think>/g) - const firstMatched = matchThinks?.[0] - let matched = firstMatched || matchThinks?.[1] - if (matched) { - matched = removePrefix(firstMatched || '', matched) - } - const thinkingProcess = matchThinks && matched + const thinkMatches = [...text.matchAll(THINK_BLOCK_REGEX)] + const thinkingProcess: string | null = + thinkMatches.length ? thinkMatches[thinkMatches.length - 1][1] : nullAnd update content removal (below).
packages/doom/src/global/Intelligence/AIAssistant/ResizableUserInput/index.tsx (2)
37-37: Extract 2000 into a named constant.- const maxCharsExceeded = innerValue.length > 2000 + const MAX_CHARS_LIMIT = 2000 + const maxCharsExceeded = innerValue.length > MAX_CHARS_LIMIT
83-92: Extract 54 into a named constant and document basis.54 = 27 CJK chars × 2 width units.
+ const FULLWIDTH_UNITS_PER_LINE = 54 @@ - .map((line) => - Math.ceil(stringWidth(line) / /* 27 Chinese characters */ 54), - ) + .map((line) => Math.ceil(stringWidth(line) / FULLWIDTH_UNITS_PER_LINE))
🧹 Nitpick comments (54)
.github/workflows/pkg-pr-new.yml (1)
3-9: Consider restricting triggers or adding path filters to save CI minutes.If desired, add on.push.paths/paths-ignore so publish runs only when package files change.
Apply this diff if you want minimal noise:
on: - - push - - pull_request + push: + paths: + - "packages/**" + - ".github/workflows/pkg-pr-new.yml" + - "package.json" + - "yarn.lock" + pull_request: + paths: + - "packages/**" + - ".github/workflows/pkg-pr-new.yml" + - "package.json" + - "yarn.lock"packages/doom/src/cli/load-config.ts (2)
331-334: Defaulting dev proxies to internal domains may surprise external users; gate behind env.As-is, any consumer of doom gets these proxies by default. Consider enabling them only when explicitly requested and optionally make targets configurable via env.
Apply this diff:
server: { open, - proxy: { - '/api/v1': 'https://cloud.alauda.cn', - '/smart/api': 'https://docs-dev.alauda.cn', - }, + proxy: + process.env.ALAUDA_INTERNAL_PROXY === '1' + ? { + '/api/v1': + process.env.ALAUDA_CLOUD_PROXY_TARGET ?? + 'https://cloud.alauda.cn', + '/smart/api': + process.env.ALAUDA_SMART_API_PROXY_TARGET ?? + 'https://docs-dev.alauda.cn', + } + : undefined, },
345-355: Avoid DefinePlugin values resolving to undefined.When algoliaOptions is falsy, JSON.stringify(undefined) yields undefined, which can produce missing replacements. Coalesce to empty strings (or 'null') to be safe.
Apply this diff:
new rspack.DefinePlugin({ - 'process.env.ALGOLIA_APP_ID': JSON.stringify( - algoliaOptions?.appId, - ), - 'process.env.ALGOLIA_API_KEY': JSON.stringify( - algoliaOptions?.apiKey, - ), - 'process.env.ALGOLIA_INDEX_NAME': JSON.stringify( - algoliaOptions?.indexName, - ), + 'process.env.ALGOLIA_APP_ID': JSON.stringify( + algoliaOptions?.appId ?? '', + ), + 'process.env.ALGOLIA_API_KEY': JSON.stringify( + algoliaOptions?.apiKey ?? '', + ), + 'process.env.ALGOLIA_INDEX_NAME': JSON.stringify( + algoliaOptions?.indexName ?? '', + ), }),packages/doom/package.json (1)
42-114: Optional tidy: drop unused deps.If html-tag-names is no longer used after the UI migration, consider removing it.
package.json (1)
24-24: Single eslint entry-point — fine; consider keeping a type-check script in CI.Since lint:tsc was removed, ensure CI still runs tsc --noEmit for PRs (build may be skipped on docs-only changes).
Example addition:
"scripts": { "build": "yarn clean && tsc -b", + "typecheck": "tsc -b --noEmit", "clean": "tsc -b --clean",packages/doom/src/global/Intelligence/AIAssistant/types.ts (1)
3-8: Use camelCase for field names to match TS conventions.Aligns with existing code style and avoids mixed_case.
export interface RefDoc { content: string - cos_sim: number + cosSim: number id: number path: string }packages/doom/src/runtime/hooks/useMemoizedFn.ts (1)
10-14: Optional: preservethistyping if needed.If consumers rely on
this, add an explicitthis: unknownto T to avoid accidentalthisleakage.- <T extends (...args: any[]) => any>(fn: T): T => { + <T extends (this: unknown, ...args: any[]) => any>(fn: T): T => {packages/doom/styles/intelligence.scss (1)
15-30: Add disabled and focus-visible styles for accessibilityImprove keyboard visibility and clarify disabled state; matches the Button component behavior.
.button { display: inline-flex; align-items: center; justify-content: center; height: 40px; + + &:disabled { + opacity: 0.6; + cursor: not-allowed; + } + + &:focus-visible { + outline: 2px solid var(--rp-c-brand-dark); + outline-offset: 2px; + }packages/doom/styles/global.scss (1)
166-166: Consider migrating @import to @use to avoid Sass deprecation warningsOptional, but future-proof. Using @use will include the CSS once and avoid global name collisions.
-@import 'intelligence.scss'; +@use './intelligence.scss';packages/doom/src/global/Intelligence/types.ts (2)
3-11: Avoid value/type name shadowing for TenantTypeHaving both a value and a type named TenantType is legal but confusing. Rename the constant to reduce cognitive load.
-export const TenantType = { +export const TenantTypes = { Alauda: 'alauda', NONE: 'none', Tencent: 'tencent', Huawei: 'huawei', } as const -export type TenantType = ValueOf<typeof TenantType> +export type TenantType = ValueOf<typeof TenantTypes>
3-8: Normalize enum-like keys for consistencyMixed casing (Alauda/Tencent/Huawei vs NONE) is inconsistent. Consider using a single convention (e.g., PascalCase or SCREAMING_CASE) across all keys.
packages/doom/src/runtime/translation.ts (1)
57-57: Parameterize the “2000 characters” limit instead of hardcodingHardcoding the limit in i18n strings makes future changes noisy and error-prone across locales.
Apply this diff to switch to a placeholder that callers can replace (e.g., with .replace('{max}', String(max))):
- max_chars_exceeded_tip: 'Maximum 2000 characters allowed.', + max_chars_exceeded_tip: 'Maximum {max} characters allowed.',- max_chars_exceeded_tip: '最多允许 2000 个字符。', + max_chars_exceeded_tip: '最多允许 {max} 个字符。',- max_chars_exceeded_tip: 'Максимум 2000 символов.', + max_chars_exceeded_tip: 'Максимум {max} символов.',Also applies to: 118-118, 185-185
packages/doom/src/global/Intelligence/AIAssistant/Preamble/Input/index.tsx (1)
6-7: Prefix/suffix should accept ReactNode, not just stringIcons and formatted fragments are common here; widening to ReactNode improves flexibility. Also mark decorative wrappers aria-hidden to avoid noisy screen reader output.
(Handled in the diff above.)
Also applies to: 19-21
packages/doom/src/runtime/hooks/useInterval.ts (2)
12-21: Type the interval ID for cross-env TS (DOM/Node) compatibilityExplicitly typing the id avoids friction when both DOM and Node types are present.
Apply:
- const id = setInterval( + const id: ReturnType<typeof setInterval> = setInterval( () => { cbRef.current() }, delay, )
6-8: Minor: move callback ref update into an effectFunctionally fine, but placing
cbRef.current = cbinside auseEffectwith[cb]reduces accidental mutations during render.- // Remember the latest callback. - cbRef.current = cb + // Remember the latest callback. + useEffect(() => { + cbRef.current = cb + }, [cb])packages/doom/src/global/Intelligence/AIAssistant/Thinking.tsx (1)
21-21: Improve accessibility: announce status updatesWrap in a live region so screen readers get non-intrusive updates.
- return `${t('thinking')}${CHUNKS[index]}` + return ( + <span aria-live="polite" aria-atomic="true"> + {t('thinking')} + {CHUNKS[index]} + </span> + )packages/doom/styles/chat.module.scss (1)
26-29: Nit: simplify line-height to a numeric constant.
calc(20 / 14)is fine, but a plain number is clearer and avoids any calc parsing edge cases.- line-height: calc(20 / 14); + line-height: 1.4286;packages/doom/src/global/Intelligence/AIAssistant/Preamble/LoginForm/utils.ts (1)
11-14: Propagate encryption failures from cryptoPassword.If
cryptothrows (or you switch to a nullable return), ensure caller handles it to present a clear login error.Want me to wire this through the Login form submit path with user-friendly messages?
packages/doom/src/global/Intelligence/AIAssistant/Preamble/types.ts (1)
3-18: Prefer Record over object for stronger typing and fewer pitfalls.
objectis broad (includes arrays).Record<string, unknown>is safer for structured extras and aligns with JSON payloads.-export interface ApiErrorOptions< - R extends string = string, - E extends object = object, - T = unknown, -> { +export interface ApiErrorOptions< + R extends string = string, + E extends Record<string, unknown> = Record<string, unknown>, + T = unknown, +> { code: number reason: R message: string extra?: E details?: T[] } export type ApiError< - T extends string = string, - E extends object = object, -> = ResponseError<ApiErrorOptions<T, E>> + T extends string = string, + E extends Record<string, unknown> = Record<string, unknown>, +> = ResponseError<ApiErrorOptions<T, E>>packages/doom/src/global/Intelligence/constants.ts (2)
8-24: Avoid mutating exported arrays; compute per-env and freeze for safety.
unshiftmutates the shared instance. Build a per-env array and expose read-only views to prevent accidental downstream mutation.-const CLOUD_AUTH_ORIGINS: CloudAuthRegion[] = [ - { - name: 'global', - value: 'https://cloud.alauda.io', - }, - { - name: 'china', - value: 'https://cloud.alauda.cn', - }, -] - -if (!isProduction()) { - CLOUD_AUTH_ORIGINS.unshift({ - name: 'local', - value: '', - }) -} +const BASE_ORIGINS = Object.freeze([ + Object.freeze<CloudAuthRegion>({ name: 'global', value: 'https://cloud.alauda.io' }), + Object.freeze<CloudAuthRegion>({ name: 'china', value: 'https://cloud.alauda.cn' }), +]) + +const ORIGINS = isProduction() + ? BASE_ORIGINS + : Object.freeze([ + Object.freeze<CloudAuthRegion>({ name: 'local', value: '' }), + ...BASE_ORIGINS, + ])
26-31: Expose read-only views to discourage mutation by consumers.Mark the exports as readonly.
-export const CLOUD_AUTH_ORIGIN_VALUES = CLOUD_AUTH_ORIGINS.map( - ({ value }) => value, -) - -export { CLOUD_AUTH_ORIGINS } +export const CLOUD_AUTH_ORIGINS: ReadonlyArray<Readonly<CloudAuthRegion>> = ORIGINS +export const CLOUD_AUTH_ORIGIN_VALUES = Object.freeze( + CLOUD_AUTH_ORIGINS.map(({ value }) => value) as readonly string[], +)packages/doom/styles/intelligence.module.scss (1)
13-26: Ensure the floating entry button stays on top and is keyboard-visibleAdd a z-index and a clear focus-visible outline for accessibility.
.entry { position: fixed; bottom: 15%; right: 0; display: inline-flex; align-items: center; background-color: var(--rp-c-bg); height: 40px; border-top-left-radius: 100px; border-bottom-left-radius: 100px; box-shadow: 0px 0px 12px 0px var(--rp-c-divider); padding-left: 10px; padding-right: 8px; + z-index: 1000; + + &:focus-visible { + outline: 2px solid var(--rp-c-brand); + outline-offset: 2px; + } }packages/doom/src/global/Intelligence/utils.ts (2)
13-27: Harden JWT payload parsing against malformed tokensAvoid decoding when the token lacks a payload segment; return early without logging noisy errors.
export const getAuthInfoFromToken = ( token?: string | null, ): AuthInfo | undefined => { if (!token) { return } - let authTokenInfo: AuthTokenInfo + let authTokenInfo: AuthTokenInfo + const [, payload] = token.split('.') as [string, string?, ...string[]] + if (!payload) { + return + } try { - authTokenInfo = JSON.parse(decodeUrl(token.split('.')[1])) as AuthTokenInfo + authTokenInfo = JSON.parse(decodeUrl(payload)) as AuthTokenInfo } catch (err) { console.error('jwt decode failed:', err) return }
23-27: Consider softening loggingconsole.error can be noisy in user consoles. Prefer console.debug or a project logger with sampling.
packages/doom/styles/resizable-user-input.module.scss (1)
23-31: Add :focus-within fallback for browsers without :has support:has is not universally reliable in older environments. Provide a focus-within fallback to keep borders and send color consistent.
&:has(textarea:focus) { &:not(.error) { border-color: var(--rp-c-brand-dark); } .send:not(.disabled) { color: var(--rp-c-brand); } } + + /* Fallback for older browsers */ + &:focus-within:not(.error) { + border-color: var(--rp-c-brand-dark); + } + &:focus-within .send:not(.disabled) { + color: var(--rp-c-brand); + }packages/doom/src/global/Intelligence/AIAssistant/Preamble/ApiErrorAlert/index.tsx (2)
28-33: Simplify translation lookup; remove try/catcht() shouldn’t throw. Use a typed key with a nullish-coalesce fallback to message.
- try { - return reason ? t(reason) || reason : message - } catch { - return message - } + const reasonKey = reason as Parameters<typeof t>[0] | undefined + return reasonKey ? (t(reasonKey) ?? message) : message
35-38: Add ARIA semantics for status messagesMake the alert announced by screen readers; hide the icon from accessibility tree.
- <div className="api-error-alert"> - <AlertIcon className="api-error-alert__icon" /> + <div className="api-error-alert" role="alert" aria-live="polite"> + <AlertIcon className="api-error-alert__icon" aria-hidden="true" /> {message} </div>packages/doom/src/global/Intelligence/index.tsx (3)
49-52: Config-driven domain allowlistHardcoding domains means code changes for each new host. Consider reading an allowlist from virtual config/env and falling back to the current defaults.
53-54: Return null instead of undefined for clarityReact treats both as “render nothing,” but null is idiomatic.
- return + return null
31-33: Security note: avoid trusting client-sent usernameAIAssistant sends username from a locally decoded token in the new_session header. Ensure the backend authenticates via cookies/Authorization and treats this header as informational only.
packages/doom/src/global/Intelligence/AIAssistant/Chat/ChatRefDocs/index.tsx (3)
32-38: Make the expander control accessibleUse a button with aria-expanded and keyboard support instead of a clickable span.
- {refDocs.length > 3 && ( - <span className={classes.action} onClick={toggleExpand}> + {refDocs.length > 3 && ( + <button + type="button" + className={classes.action} + onClick={toggleExpand} + aria-expanded={expand} + aria-controls="chat-ref-docs-list" + > {t(expand ? 'view_less_related_docs' : 'view_more_related_docs')} ( {refDocs.length}) <AngleDownIcon className={clsx(classes.icon, expand && classes.expanded)} /> - </span> + </button> )}
41-42: Wire aria-controls to the listGive the docs list an id referenced by the button.
- <ul className={classes.docs}> + <ul id="chat-ref-docs-list" className={classes.docs}>
29-30: Prefer a single i18n key instead of string concatenationUsing two keys for “label + colon” can break locale-specific punctuation. Consider a single key (e.g., referenced_doc_links_label).
- {t('referenced_doc_links') + t('colon')} + {t('referenced_doc_links_label')}Note: add the new translation key in all locales.
packages/doom/src/global/Intelligence/AIAssistant/Preamble/index.tsx (2)
25-25: Use explicit conditional for readabilityAvoid relying on falsy rendering semantics.
- {loggedIn || <LoginForm className={classes.form} />} + {!loggedIn && <LoginForm className={classes.form} />}
18-19: Mark decorative SVG as hidden from assistive techIf the assistant icon conveys no extra meaning, hide it from screen readers.
- <AssistantIcon width={48} height={40} /> + <AssistantIcon width={48} height={40} aria-hidden="true" focusable="false" />packages/doom/src/global/Intelligence/AIAssistant/Preamble/LoginForm/index.tsx (1)
37-44: Optional: guard localStorage for SSRIf this renders server-side, localStorage access will throw. A simple typeof window check avoids that.
- const [origin, setOrigin] = useState(() => { - let origin = localStorage.getItem(CLOUD_AUTH_ORIGIN_KEY) + const [origin, setOrigin] = useState(() => { + if (typeof window === 'undefined') return CLOUD_AUTH_ORIGIN_VALUES[0] + let origin = window.localStorage.getItem(CLOUD_AUTH_ORIGIN_KEY) if (origin == null || !CLOUD_AUTH_ORIGIN_VALUES.includes(origin)) { origin = CLOUD_AUTH_ORIGIN_VALUES[0] - localStorage.setItem(CLOUD_AUTH_ORIGIN_KEY, origin) + window.localStorage.setItem(CLOUD_AUTH_ORIGIN_KEY, origin) } return origin })packages/doom/src/global/Intelligence/AIAssistant/Preamble/CaptchaInput/index.tsx (1)
40-45: Make captcha image refresh keyboard-accessibleClickable img is not reachable by keyboard. Add role, tabIndex, and key handler.
<img className="captcha-input__captcha" src={captcha} - onClick={onRefresh} + onClick={onRefresh} + role="button" + tabIndex={0} + onKeyDown={(e) => { + if (e.key === 'Enter' || e.key === ' ') onRefresh() + }} alt={t('captcha')} />packages/doom/src/global/Intelligence/AIAssistant/utils.ts (2)
17-17: Annotate return type for stronger contracts.-export function parseStreamContent(text: string) { +export function parseStreamContent( + text: string, +): { refDocs: RefDoc[]; thinkingProcess: string | null; content: string } {
7-10: Unicode decoding is OK; consider surrogate-pair safety and optional broader escapes.Current approach is fine for \uXXXX; if needed, extend to handle escaped UTF-16 surrogate pairs explicitly.
packages/doom/src/global/Intelligence/AIAssistant/ResizableUserInput/index.tsx (3)
94-104: Name layout constants and clarify row math.- const inputHeight = useMemo( - () => Math.min(Math.max(textLines, 3), 8) * 20, - [textLines], - ) + const MIN_ROWS = 3 + const MAX_ROWS = 8 + const LINE_HEIGHT_PX = 20 + const inputHeight = useMemo( + () => Math.min(Math.max(textLines, MIN_ROWS), MAX_ROWS) * LINE_HEIGHT_PX, + [textLines], + )
106-114: Honor placeholder prop; add basic a11y.Prefer provided placeholder; expose aria-invalid and maxLength to assist UX.
- <textarea - placeholder={t('ai_assistant_placeholder')} + <textarea + placeholder={placeholder ?? t('ai_assistant_placeholder')} value={innerValue} onChange={handleChange} onKeyDown={onKeyDown} style={inputStyle} + aria-invalid={maxCharsExceeded || undefined} + maxLength={MAX_CHARS_LIMIT} />
115-119: Make send icon accessible and non-interactive when disabled.Expose button semantics and prevent clicks when disabled.
- <SendIcon - className={clsx(classes.send, isSendDisabled && classes.disabled)} - onClick={handleSend} - /> + <SendIcon + role="button" + aria-disabled={isSendDisabled} + tabIndex={isSendDisabled ? -1 : 0} + className={clsx(classes.send, isSendDisabled && classes.disabled)} + onClick={isSendDisabled ? undefined : handleSend} + onKeyDown={(e) => !isSendDisabled && e.key === 'Enter' && handleSend()} + />packages/doom/src/global/Intelligence/AIAssistant/Preamble/FocusInput/index.tsx (2)
20-21: Sync ‘active’ with external value changes.If value is controlled and changed programmatically, active may desync.
const [active, setActive] = useState(!!value) const [focus, setFocus] = useState(false) + useEffect(() => { + setActive(!!value) + }, [value])
47-49: Add accessibility label to the underlying input.Overlay placeholders aren’t read by screen readers. Provide aria-label.
- <Component onFocus={handleFocus} onBlur={handleBlur} {...props} /> + <Component + aria-label={placeholder} + onFocus={handleFocus} + onBlur={handleBlur} + {...props} + />packages/doom/styles/ai-assistant.module.scss (1)
9-10: Drop unnecessary calc(); use min() directly.Pure min() is simpler and equivalent here.
- width: calc(min(100vw, 440px)); - height: calc(min(100vh, 700px)); + width: min(100vw, 440px); + height: min(100vh, 700px);packages/doom/src/global/Intelligence/AIAssistant/Preamble/Radio/RadioGroup.tsx (1)
35-35: Don’t mutate prop variablesAvoid
name ??= id. Use a derived const and passgroupNameto context.Also applies to: 56-60
packages/doom/src/global/Intelligence/AIAssistant/Preamble/LoginForm/types.ts (1)
8-13: Confirm numeric fields’ typesIf the API returns seconds as numbers, prefer
numberforexpiresIn/refreshExpiresInto avoid downstream parsing.packages/doom/src/global/Intelligence/AIAssistant/Preamble/FormItem/index.tsx (1)
73-75: Minor i18n spacingAdd a separator between label and required tip to avoid concatenation.
Apply:
- {label || t('current_field')} - {t('field_required')} + {(label || t('current_field')) + ' '} + {t('field_required')}packages/doom/src/global/Intelligence/context.tsx (2)
19-19: PreferuseContextover experimentaluseUnless you’re on a React build that supports
use(Context)on the client, switch touseContext(CloudAuthContext)for compatibility.Apply:
-import { type ReactNode, createContext, use, useMemo, useState } from 'react' +import { type ReactNode, createContext, useContext, useMemo, useState } from 'react' @@ -export const useCloudAuth = () => use(CloudAuthContext) +export const useCloudAuth = () => useContext(CloudAuthContext)
21-34: GuardlocalStoragefor SSRIf this module can be imported server-side, add a window check to avoid ReferenceErrors.
Apply:
const getCloudAuth = (): CloudAuth | null => { - const origin = localStorage.getItem(CLOUD_AUTH_ORIGIN_KEY) - const token = localStorage.getItem(CLOUD_AUTH_TOKEN_KEY) + if (typeof window === 'undefined') return null + const origin = localStorage.getItem(CLOUD_AUTH_ORIGIN_KEY) + const token = localStorage.getItem(CLOUD_AUTH_TOKEN_KEY)packages/doom/src/global/Intelligence/AIAssistant/index.tsx (4)
96-100: Guard header username and session creation withloggedInAvoid non-null assertions; if usage changes, this prevents runtime errors.
Apply:
- headers: { username: authInfo!.detail!.user.name }, + headers: { username: authInfo?.detail?.user.name ?? '' },And early-return in
onSend_if notloggedIn.
61-71: Optional: avoid dangling timeoutsStore and clear the timeout on unmount to prevent leaks in long sessions.
Apply:
const flushMessages = useMemoizedFn( (setMessagesAction: (messages: ChatMessage[]) => ChatMessage[]) => { setMessages(setMessagesAction) - setTimeout(() => { + const tid = setTimeout(() => { const chatEl = chatRef.current if (!chatEl) { return } chatEl.scrollTop = chatEl.scrollHeight }, 200) }, ) + useEffect(() => () => clearTimeout?.(tid as any), [])
22-26:onCleanupis unusedEither remove it from props or invoke it on close/unmount.
Apply (unmount cleanup):
+ useEffect(() => () => { onCleanup?.() }, [onCleanup])Also applies to: 168-207
104-117: Defensive stream handling
res.bodymay be null/non-iterable in some environments. Add a guard.Apply:
- const res = await xfetch('/smart/api/smart_answer', { + const res = await xfetch('/smart/api/smart_answer', { type: null, method: ApiMethod.POST, body: { input_text: content, session_id: sessionId, }, }) - - textDecoder ??= new TextDecoder() - - let text = '' - - for await (const chunk_ of res.body! as unknown as AsyncIterable<Uint8Array>) { + const body = res.body as unknown as AsyncIterable<Uint8Array> | null + if (!body) throw new Error('Empty stream body') + textDecoder ??= new TextDecoder() + let text = '' + for await (const chunk_ of body) {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (9)
packages/doom/assets/alert.svgis excluded by!**/*.svgpackages/doom/assets/angle-down.svgis excluded by!**/*.svgpackages/doom/assets/assistant.svgis excluded by!**/*.svgpackages/doom/assets/close.svgis excluded by!**/*.svgpackages/doom/assets/logout.svgis excluded by!**/*.svgpackages/doom/assets/new-chat.svgis excluded by!**/*.svgpackages/doom/assets/question-circle.svgis excluded by!**/*.svgpackages/doom/assets/send.svgis excluded by!**/*.svgyarn.lockis excluded by!**/yarn.lock,!**/*.lock
📒 Files selected for processing (46)
.changeset/shaggy-garlics-divide.md(1 hunks).github/workflows/pkg-pr-new.yml(1 hunks)package.json(2 hunks)packages/doom/package.json(4 hunks)packages/doom/src/cli/load-config.ts(1 hunks)packages/doom/src/global/Intelligence/AIAssistant/Chat/ChatRefDocs/index.tsx(1 hunks)packages/doom/src/global/Intelligence/AIAssistant/Chat/ThinkingProcess/index.tsx(1 hunks)packages/doom/src/global/Intelligence/AIAssistant/Chat/index.tsx(1 hunks)packages/doom/src/global/Intelligence/AIAssistant/Preamble/ApiErrorAlert/index.tsx(1 hunks)packages/doom/src/global/Intelligence/AIAssistant/Preamble/Button/index.tsx(1 hunks)packages/doom/src/global/Intelligence/AIAssistant/Preamble/CaptchaInput/index.tsx(1 hunks)packages/doom/src/global/Intelligence/AIAssistant/Preamble/FocusInput/index.tsx(1 hunks)packages/doom/src/global/Intelligence/AIAssistant/Preamble/FormItem/index.tsx(1 hunks)packages/doom/src/global/Intelligence/AIAssistant/Preamble/Input/index.tsx(1 hunks)packages/doom/src/global/Intelligence/AIAssistant/Preamble/LoginForm/index.tsx(1 hunks)packages/doom/src/global/Intelligence/AIAssistant/Preamble/LoginForm/types.ts(1 hunks)packages/doom/src/global/Intelligence/AIAssistant/Preamble/LoginForm/utils.ts(1 hunks)packages/doom/src/global/Intelligence/AIAssistant/Preamble/Radio/Radio.tsx(1 hunks)packages/doom/src/global/Intelligence/AIAssistant/Preamble/Radio/RadioGroup.tsx(1 hunks)packages/doom/src/global/Intelligence/AIAssistant/Preamble/Radio/context.ts(1 hunks)packages/doom/src/global/Intelligence/AIAssistant/Preamble/Radio/index.ts(1 hunks)packages/doom/src/global/Intelligence/AIAssistant/Preamble/index.tsx(1 hunks)packages/doom/src/global/Intelligence/AIAssistant/Preamble/types.ts(1 hunks)packages/doom/src/global/Intelligence/AIAssistant/ResizableUserInput/index.tsx(1 hunks)packages/doom/src/global/Intelligence/AIAssistant/Thinking.tsx(1 hunks)packages/doom/src/global/Intelligence/AIAssistant/index.tsx(1 hunks)packages/doom/src/global/Intelligence/AIAssistant/types.ts(1 hunks)packages/doom/src/global/Intelligence/AIAssistant/utils.ts(1 hunks)packages/doom/src/global/Intelligence/constants.ts(1 hunks)packages/doom/src/global/Intelligence/context.tsx(1 hunks)packages/doom/src/global/Intelligence/index.tsx(1 hunks)packages/doom/src/global/Intelligence/types.ts(1 hunks)packages/doom/src/global/Intelligence/utils.ts(1 hunks)packages/doom/src/global/VersionsNav/NavMenuSingleItem.tsx(1 hunks)packages/doom/src/runtime/hooks/index.ts(1 hunks)packages/doom/src/runtime/hooks/useInterval.ts(1 hunks)packages/doom/src/runtime/hooks/useMemoizedFn.ts(1 hunks)packages/doom/src/runtime/translation.ts(3 hunks)packages/doom/styles/ai-assistant.module.scss(1 hunks)packages/doom/styles/chat-ref-docs.module.scss(1 hunks)packages/doom/styles/chat.module.scss(1 hunks)packages/doom/styles/global.scss(1 hunks)packages/doom/styles/intelligence.module.scss(1 hunks)packages/doom/styles/intelligence.scss(1 hunks)packages/doom/styles/preamble.module.scss(1 hunks)packages/doom/styles/resizable-user-input.module.scss(1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-05-26T09:09:21.339Z
Learnt from: JounQin
PR: alauda/doom#30
File: src/runtime/components/K8sCrd.tsx:5-5
Timestamp: 2025-05-26T09:09:21.339Z
Learning: The alauda/doom project uses yarn v4 for dependency management, which handles package exports and module resolution correctly, so imports like `rspress/core/theme` work without any ESLint errors.
Applied to files:
packages/doom/src/global/VersionsNav/NavMenuSingleItem.tsxpackage.jsonpackages/doom/package.json
📚 Learning: 2025-06-09T03:10:41.010Z
Learnt from: JounQin
PR: alauda/doom#75
File: src/cli/load-config.ts:4-7
Timestamp: 2025-06-09T03:10:41.010Z
Learning: The alauda/doom project uses yarn v4 as the package manager, not npm. Always reference yarn commands when suggesting package management operations.
Applied to files:
package.json
📚 Learning: 2025-05-29T16:25:28.086Z
Learnt from: JounQin
PR: alauda/doom#40
File: src/plugins/sitemap/index.ts:7-7
Timestamp: 2025-05-29T16:25:28.086Z
Learning: In rspress/shared v2.0.0-beta.8, the '/logger' export is available in the package exports field, so imports like `import { logger } from 'rspress/shared/logger'` are valid even if ESLint shows resolution errors. This is used throughout the codebase in files like src/cli/translate.ts, src/cli/load-config.ts, src/utils/git.ts, and src/plugins/sitemap/index.ts.
Applied to files:
packages/doom/src/runtime/hooks/index.ts
🧬 Code graph analysis (21)
packages/doom/src/global/Intelligence/AIAssistant/Preamble/LoginForm/types.ts (1)
packages/doom/src/global/Intelligence/AIAssistant/Preamble/types.ts (1)
ApiError(15-18)
packages/doom/src/global/Intelligence/AIAssistant/Thinking.tsx (2)
packages/doom/src/runtime/hooks/useTranslation.ts (1)
useTranslation(9-16)packages/doom/src/runtime/hooks/useInterval.ts (1)
useInterval(3-24)
packages/doom/src/global/Intelligence/AIAssistant/Preamble/LoginForm/utils.ts (1)
packages/doom/src/global/Intelligence/AIAssistant/Preamble/LoginForm/types.ts (1)
PasswordPubKey(3-6)
packages/doom/src/global/Intelligence/AIAssistant/Chat/ChatRefDocs/index.tsx (3)
packages/doom/src/global/Intelligence/AIAssistant/types.ts (1)
RefDoc(3-8)packages/doom/src/runtime/hooks/useTranslation.ts (1)
useTranslation(9-16)packages/doom/src/runtime/components/_X.tsx (1)
X(3-3)
packages/doom/src/global/Intelligence/constants.ts (1)
packages/doom/src/global/Intelligence/types.ts (1)
CloudAuthRegion(36-39)
packages/doom/src/global/Intelligence/AIAssistant/index.tsx (10)
packages/doom/src/global/Intelligence/context.tsx (2)
CloudAuth(7-10)useCloudAuth(19-19)packages/doom/src/global/Intelligence/types.ts (1)
AuthInfo(30-34)packages/doom/src/runtime/hooks/useTranslation.ts (1)
useTranslation(9-16)packages/doom/src/global/Intelligence/AIAssistant/types.ts (1)
ChatMessage(10-16)packages/doom/src/runtime/hooks/useMemoizedFn.ts (1)
useMemoizedFn(3-15)packages/doom/src/global/Intelligence/AIAssistant/Thinking.tsx (1)
Thinking(9-22)packages/doom/src/global/Intelligence/AIAssistant/utils.ts (1)
parseStreamContent(17-46)packages/doom/src/global/Intelligence/AIAssistant/Chat/index.tsx (1)
Chat(18-37)packages/doom/src/global/Intelligence/AIAssistant/Preamble/index.tsx (1)
Preamble(13-28)packages/doom/src/global/Intelligence/AIAssistant/ResizableUserInput/index.tsx (1)
ResizableUserInput(23-128)
packages/doom/src/global/Intelligence/utils.ts (1)
packages/doom/src/global/Intelligence/types.ts (2)
AuthInfo(30-34)AuthTokenInfo(14-21)
packages/doom/src/global/Intelligence/AIAssistant/Chat/ThinkingProcess/index.tsx (2)
packages/doom/src/runtime/hooks/useTranslation.ts (1)
useTranslation(9-16)packages/doom/src/runtime/components/Markdown.tsx (1)
Markdown(12-21)
packages/doom/src/global/Intelligence/AIAssistant/ResizableUserInput/index.tsx (2)
packages/doom/src/runtime/hooks/useTranslation.ts (1)
useTranslation(9-16)packages/doom/src/runtime/hooks/useMemoizedFn.ts (1)
useMemoizedFn(3-15)
packages/doom/src/global/Intelligence/AIAssistant/Chat/index.tsx (4)
packages/doom/src/global/Intelligence/AIAssistant/types.ts (1)
ChatMessage(10-16)packages/doom/src/global/Intelligence/AIAssistant/Chat/ThinkingProcess/index.tsx (1)
ThinkingProcess(7-15)packages/doom/src/global/Intelligence/AIAssistant/Chat/ChatRefDocs/index.tsx (1)
ChatRefDocs(15-57)packages/doom/src/runtime/components/Markdown.tsx (1)
Markdown(12-21)
packages/doom/src/global/Intelligence/AIAssistant/Preamble/ApiErrorAlert/index.tsx (2)
packages/doom/src/global/Intelligence/AIAssistant/Preamble/types.ts (1)
ApiError(15-18)packages/doom/src/runtime/hooks/useTranslation.ts (1)
useTranslation(9-16)
packages/doom/src/global/Intelligence/AIAssistant/Preamble/FormItem/index.tsx (1)
packages/doom/src/runtime/hooks/useTranslation.ts (1)
useTranslation(9-16)
packages/doom/src/global/Intelligence/AIAssistant/Preamble/LoginForm/index.tsx (13)
packages/doom/src/global/Intelligence/AIAssistant/Preamble/LoginForm/types.ts (3)
LoginError(29-30)PasswordPubKey(3-6)LoginResponse(8-13)packages/doom/src/runtime/hooks/useTranslation.ts (1)
useTranslation(9-16)packages/doom/src/global/Intelligence/constants.ts (3)
CLOUD_AUTH_ORIGIN_KEY(5-5)CLOUD_AUTH_ORIGIN_VALUES(26-28)CLOUD_AUTH_ORIGINS(30-30)packages/doom/src/runtime/hooks/useMemoizedFn.ts (1)
useMemoizedFn(3-15)packages/doom/src/global/Intelligence/context.tsx (1)
useCloudAuth(19-19)packages/doom/src/global/Intelligence/AIAssistant/Preamble/LoginForm/utils.ts (1)
cryptoPassword(11-14)packages/doom/src/global/Intelligence/AIAssistant/Preamble/FormItem/index.tsx (1)
FormItem(26-79)packages/doom/src/global/Intelligence/AIAssistant/Preamble/Radio/RadioGroup.tsx (1)
RadioGroup(22-69)packages/doom/src/global/Intelligence/AIAssistant/Preamble/Radio/Radio.tsx (1)
Radio(11-38)packages/doom/src/global/Intelligence/AIAssistant/Preamble/ApiErrorAlert/index.tsx (1)
ApiErrorAlert(12-40)packages/doom/src/global/Intelligence/AIAssistant/Preamble/FocusInput/index.tsx (1)
FocusInput(10-51)packages/doom/src/global/Intelligence/AIAssistant/Preamble/CaptchaInput/index.tsx (1)
CaptchaInput(17-52)packages/doom/src/global/Intelligence/AIAssistant/Preamble/Button/index.tsx (1)
Button(12-34)
packages/doom/src/global/Intelligence/AIAssistant/Preamble/Radio/Radio.tsx (1)
packages/doom/src/global/Intelligence/AIAssistant/Preamble/Radio/context.ts (2)
RadioGroupContext(3-7)RadioGroupContext(9-9)
packages/doom/src/global/Intelligence/AIAssistant/Preamble/Radio/RadioGroup.tsx (1)
packages/doom/src/global/Intelligence/AIAssistant/Preamble/Radio/context.ts (2)
RadioGroupContext(3-7)RadioGroupContext(9-9)
packages/doom/src/global/Intelligence/index.tsx (5)
packages/doom/src/runtime/hooks/useTranslation.ts (2)
useTranslation(9-16)useLang(7-7)packages/doom/src/runtime/hooks/useMemoizedFn.ts (1)
useMemoizedFn(3-15)packages/doom/src/global/Intelligence/context.tsx (1)
CloudAuthProvider(36-58)packages/doom/src/global/Intelligence/AIAssistant/index.tsx (1)
AIAssistant(34-208)packages/doom/src/shared/constants.ts (1)
ACP_BASE(1-1)
packages/doom/src/global/Intelligence/AIAssistant/Preamble/index.tsx (2)
packages/doom/src/runtime/hooks/useTranslation.ts (1)
useTranslation(9-16)packages/doom/src/global/Intelligence/AIAssistant/Preamble/LoginForm/index.tsx (1)
LoginForm(34-189)
packages/doom/src/global/Intelligence/AIAssistant/utils.ts (1)
packages/doom/src/global/Intelligence/AIAssistant/types.ts (1)
RefDoc(3-8)
packages/doom/src/global/Intelligence/AIAssistant/Preamble/CaptchaInput/index.tsx (3)
packages/doom/src/global/Intelligence/AIAssistant/Preamble/Input/index.tsx (2)
InputProps(4-8)Input(10-24)packages/doom/src/runtime/hooks/useTranslation.ts (1)
useTranslation(9-16)packages/doom/src/global/Intelligence/AIAssistant/Preamble/FormItem/index.tsx (1)
FormItem(26-79)
packages/doom/src/global/Intelligence/context.tsx (3)
packages/doom/src/global/Intelligence/types.ts (1)
AuthInfo(30-34)packages/doom/src/global/Intelligence/constants.ts (2)
CLOUD_AUTH_ORIGIN_KEY(5-5)CLOUD_AUTH_TOKEN_KEY(6-6)packages/doom/src/global/Intelligence/utils.ts (2)
getAuthInfoFromToken(13-39)setLocalStorage(5-11)
packages/doom/src/global/Intelligence/AIAssistant/Preamble/FocusInput/index.tsx (1)
packages/doom/src/global/Intelligence/AIAssistant/Preamble/Input/index.tsx (2)
InputProps(4-8)Input(10-24)
🔇 Additional comments (28)
packages/doom/src/global/VersionsNav/NavMenuSingleItem.tsx (1)
6-7: Ignore .ts-extension removal suggestionYour repository is using NodeNext resolution with
"compilerOptions": { "module": "NodeNext", "moduleResolution": "NodeNext", "rewriteRelativeImportExtensions": true, "verbatimModuleSyntax": true, … }Under these settings, retaining
.tsin import paths is intentional: TypeScript rewritesimport "./foo.ts"→import "./foo.js"in the emitted ESM, ensuring Node can resolve the files. Swapping to extensionless imports would leave them unmodified and break runtime loading.A scan confirms dozens of
.tsimports across bothpackages/doomandpackages/export, indicating a consistent, project-wide pattern:
- doom/src/global/VersionsNav/NavMenuSingleItem.tsx: import from '../../shared/index.ts'
- doom/src/shared/helpers.ts: import from './constants.ts', './types.ts'
- …and many more.
Because this is by design and necessary for correct bundling and Node ESM support, you can safely disregard the recommendation to drop
.tsextensions here.Likely an incorrect or invalid review comment.
.changeset/shaggy-garlics-divide.md (1)
1-5: Changeset looks good; scope and bump match the feature size.Minor bump for @alauda/doom with a concise summary is appropriate.
.github/workflows/pkg-pr-new.yml (1)
35-35: Enable compact output — LGTM.The added --compact flag should reduce CI noise without changing behavior.
packages/doom/src/cli/load-config.ts (1)
104-114: Confirm Algolia keys are search-only and intended to be public.If these are search-only keys, embedding is fine; otherwise move to env/secret injection.
packages/doom/package.json (2)
18-24: Adding assets/styles exports — good call.This enables clean imports like @alauda/doom/styles/… and asset resolution; files already whitelisted.
50-51: Sanity-check new runtime deps for size and compatibility– react-tooltip@^5.29.1
• Peer-requires React ≤18 by default. The Doom plugin itself doesn’t declare React, so the host app (via @rspress/core or consumer) must supply a compatible version.
• Import sites in this package:
• packages/doom/src/global/Intelligence/index.tsx
• packages/doom/src/global/Intelligence/AIAssistant/index.tsx
• packages/doom/src/global/Intelligence/AIAssistant/Preamble/LoginForm/index.tsx
→ Confirm that the application’s React version is ≤18. If you’re on React 19, either pin react-tooltip to a 6.x prerelease or document the mismatch.– openai@^5.16.0
• Only imported in the CLI (packages/doom/src/cli/translate.ts). ESM payload size isn’t tree-shaken in Node, but you can defer loading to reduce CLI startup cost.
→ Consider switching the top-level import to a dynamicawait import('openai')inside the translate command handler.– jsencrypt@^3.5.4 & ab64@^0.1.6
• Pulled into the browser bundle via:
• packages/doom/src/global/Intelligence/AIAssistant/Preamble/LoginForm/utils.ts (JSEncrypt)
• packages/doom/src/global/Intelligence/utils.ts (ab64)
→ These crypto utilities can add ~20–40 KB gzipped each. Lazy-load them in the auth/login flow or isolate into a separate chunk so they don’t bloat your initial UI bundle.package.json (1)
15-16: Pre-clean build is a good hardening.yarn clean && tsc -b reduces stale artifacts in multi-project builds.
packages/doom/src/global/Intelligence/AIAssistant/types.ts (1)
10-14: Consider future-proofing roles and serializability.
- If tools/system messages may appear later, widen role to include 'system' | 'tool'.
- ReactNode content can’t be serialized; if messages will be persisted, keep a parallel string field.
Would you like a follow-up patch adding role: 'user' | 'assistant' | 'system' | 'tool' and contentText?: string?
packages/doom/styles/preamble.module.scss (2)
8-10: Verify CSS Modules usage of the state class.Selector compiles as
.preamble.logged-in{...}; you must apply both classes. Ensure TSX usesstyles.preambleplusstyles['logged-in'](bracket access required due to hyphen).
1-11: LGTM: clean, minimal layout rules.Flex column, centered alignment, and state override read well.
packages/doom/src/runtime/hooks/useMemoizedFn.ts (1)
3-15: Solid implementation; stable identity with latest ref.Pattern matches industry-standard approach; lint disables are appropriate.
packages/doom/src/runtime/hooks/index.ts (1)
1-5: All .ts extension imports are intentional and supported by your TypeScript configuration– A repository-wide search confirms numerous
import/exportstatements ending in.tsacross bothpackages/doomandpackages/export, including yourruntime/hooks/index.tsfile.
–tsconfig.base.jsonis set to"module": "NodeNext","moduleResolution": "NodeNext", and"rewriteRelativeImportExtensions": true, ensuring these.tsextensions are accepted in source and rewritten to.jsin the emitted ESM output.No modifications are necessary.
packages/doom/src/runtime/translation.ts (2)
66-66: Strong typing for i18n shape—niceDeriving Translation from typeof en and typing other locales against it + exporting a stable TRANSLATIONS map is solid. This prevents missing keys at compile time.
Also applies to: 193-193
22-25: Refactor punctuation translations to remove embedded spacesWe discovered that the only call site relying on the trailing space in
t('colon')is here:
packages/doom/src/global/Intelligence/AIAssistant/Chat/ChatRefDocs/index.tsx:29{t('referenced_doc_links') + t('colon')}Removing the space from the translation entries (
exclamation: '!',semicolon: ';',period: '.',colon: ':') will break this line (it will render"Referenced doc links:"without a space).Options:
- Refactor translations: strip trailing spaces and update call sites to add spaces explicitly, for example:
{`${t('referenced_doc_links')}: `}- Or document/guard in
translation.tsthat these four keys include a trailing space and should not be used in JSX expressions without trimming.Please verify all usage of these punctuation keys before removing their spaces to avoid layout regressions.
packages/doom/styles/chat.module.scss (1)
15-19: Verify layout math for assistant vs. user bubbles.
width: calc(100% - 36px)plus.assistant .content { margin-left: 12px; }could produce asymmetric gutters depending on icon width. Please confirm visuals across breakpoints.Also applies to: 58-61
packages/doom/src/global/Intelligence/AIAssistant/Preamble/LoginForm/utils.ts (1)
1-1: No changes required:import { JSEncrypt }is valid
Thejsencryptpackage’s ESM entrypoint (lib/index.js) both re-exportsJSEncryptas a named export and as the default export, so the existingimport { JSEncrypt } from 'jsencrypt'is correct and will work as expected.
• Location needing no change:
- packages/doom/src/global/Intelligence/AIAssistant/Preamble/LoginForm/utils.ts:1
packages/doom/src/global/Intelligence/AIAssistant/Chat/ThinkingProcess/index.tsx (1)
7-15: LGTM — simple, clear component.Label + Markdown is straightforward; translation key usage looks correct.
packages/doom/styles/intelligence.module.scss (1)
1-11: Global react-tooltip theming: confirm intended global scopeYou’re overriding react-tooltip CSS variables at :root for the entire site. Confirm no other tooltips rely on different colors. If scoping is needed later, consider toggling via a host class rather than permanent globals.
packages/doom/src/global/Intelligence/utils.ts (2)
5-11: LocalStorage helper is cleanNullish -> remove, otherwise set. Reads well.
29-38: Mapping looks correcttenant_type/id and user fields are mapped as expected; sensible username fallback.
packages/doom/src/global/Intelligence/AIAssistant/Preamble/ApiErrorAlert/index.tsx (1)
3-3: Import extension consistencyYou import from '../types.js' here, but other files (e.g., index.tsx) import '.ts'. Ensure your bundler/tsconfig supports mixed extensions; otherwise align to one style.
packages/doom/src/global/Intelligence/index.tsx (2)
48-54: Gating to English only: confirm intentYou have translations for zh/ru in this PR, but the gate is lang === 'en'. Is this intentional for a phased rollout?
If not intentional, a simple relaxation:
- if ( - lang !== 'en' || + if ( + !['en', 'zh', 'ru'].includes(lang) || !ALLOWED_DOMAINS.has(location.hostname) || virtual.userBase !== ACP_BASE ) { - return + return null }
59-63: Client-only rendering LGTMWrapping with NoSSR avoids SSR access to window/location and localStorage.
packages/doom/src/global/Intelligence/AIAssistant/Preamble/Radio/Radio.tsx (1)
11-16: Confirm React version for use(Context)This relies on React’s use() for context. Ensure the app runs on a React version where this API is stable across your targets (including SSR).
Would you like me to scan package.json/lockfiles to confirm the React version used across packages?
packages/doom/src/global/Intelligence/AIAssistant/Preamble/CaptchaInput/index.tsx (1)
4-6: Import path extensions: ensure resolver compatibilityMixed usage of .tsx and .js extensions across the preamble components can bite certain TS/ESM setups. Consider extensionless imports for local files (preferred) or verify tsconfig moduleSuffixes/allowImportingTsExtensions handle this.
Want me to scan tsconfig(es) to confirm the resolver settings and propose a repo-wide codemod?
packages/doom/src/global/Intelligence/AIAssistant/Chat/index.tsx (1)
28-31: Sanitization Confirmed – No Changes RequiredThe
Markdowncomponent inpackages/doom/src/runtime/components/Markdown.tsxalready imports and appliesrehype-sanitizein itsrehypePluginsarray, ensuring that any untrusted strings are properly sanitized before rendering.• File:
packages/doom/src/runtime/components/Markdown.tsx
–import rehypeSanitize from 'rehype-sanitize'
–const rehypePlugins = [rehypeRaw, rehypeSanitize]packages/doom/src/global/Intelligence/AIAssistant/Preamble/FocusInput/index.tsx (1)
6-8: Consider forwardRef if refs must reach the actual input.InputProps includes ref, but without forwardRef on both Component and FocusInput, consumer refs won’t work.
Would you like a follow-up patch to convert Input and FocusInput to forwardRef and update call sites?
Also applies to: 10-19
packages/doom/src/global/Intelligence/AIAssistant/Preamble/LoginForm/types.ts (1)
8-13: Types look goodType-only surface is clean and import is type-only. LGTM.
Summary by CodeRabbit
New Features
Chores