From 7ebe802e0b8f2fe7a49b07353be10c0693350235 Mon Sep 17 00:00:00 2001 From: murashit Date: Fri, 12 Jun 2026 17:29:04 +0900 Subject: [PATCH] Refresh lint boundaries and validation cleanup --- docs/development.md | 2 +- eslint.config.mjs | 130 +++++------------- scripts/generated-app-server-boundary.json | 6 - src/app-server/connection/client.ts | 9 +- src/app-server/protocol/diagnostics.ts | 2 +- src/app-server/protocol/runtime-config.ts | 2 +- src/app-server/protocol/runtime-metrics.ts | 2 +- src/app-server/protocol/turn.ts | 4 +- .../connection/server-actions/diagnostics.ts | 11 +- .../pending-requests/view-model.ts | 9 +- src/features/chat/display/item-actions.ts | 6 +- src/features/chat/display/items/agent.ts | 2 +- .../chat/display/items/task-progress.ts | 2 +- src/features/chat/display/turn-items.ts | 6 +- src/features/chat/panel/regions/ports.ts | 2 +- .../chat/protocol/inbound/controller.ts | 5 +- .../protocol/inbound/notification-plan.ts | 7 +- src/features/chat/runtime/effective.ts | 6 +- .../chat/runtime/thread-settings-update.ts | 6 +- .../chat/state/message-stream-updates.ts | 4 +- src/features/chat/state/reducer.ts | 7 +- src/features/chat/state/selectors.ts | 9 +- src/features/chat/threads/goal-actions.ts | 14 +- .../chat/threads/history-controller.ts | 6 +- .../chat/threads/rename-controller.ts | 6 +- src/features/chat/threads/resume.ts | 5 +- .../ui/message-stream/markdown-renderer.ts | 2 +- .../chat/ui/message-stream/text-item.tsx | 8 +- .../chat/ui/message-stream/work-items.tsx | 7 +- src/features/chat/ui/toolbar.tsx | 2 +- tests/app-server/app-server-client.test.ts | 6 +- tests/app-server/thread-settings.test.ts | 6 +- .../chat/display/display-model.test.ts | 11 +- .../chat/protocol/inbound/controller.test.ts | 28 +++- .../chat/threads/selection-actions.test.ts | 5 +- .../selection-rewrite.test.ts | 6 +- .../thread-title/thread-title.test.ts | 6 +- tests/runtime/runtime-settings.test.ts | 10 +- 38 files changed, 180 insertions(+), 187 deletions(-) delete mode 100644 scripts/generated-app-server-boundary.json diff --git a/docs/development.md b/docs/development.md index ee95c3e0..659804ef 100644 --- a/docs/development.md +++ b/docs/development.md @@ -29,7 +29,7 @@ The source tree is organized by responsibility rather than by the original singl - `src/domain/threads/` contains thread title, reference, transcript, naming, and archive export helpers shared outside the chat feature. Some helpers still read app-server turn/item types directly when they are pure protocol interpreters, but new shared UI/workspace/settings-facing behavior should prefer panel-owned models or small adapters at the app-server boundary. - `src/styles/` contains the authored CSS modules and `order.json` concatenation order. `scripts/build-styles.mjs` concatenates them into the ignored root `styles.css`, which remains the Obsidian release asset. -Keep new code near the state or API it owns. Feature code should not import from another feature directly; move shared behavior to `src/shared/`, `src/domain/`, or `src/app-server/` when more than one feature needs it. +Keep new code near the state or API it owns. Feature-to-feature imports are allowed when the imported feature owns a concrete capability or integration point, such as thread export, thread title generation, or an Obsidian view. Do not use another feature as a generic utility bucket; move truly feature-neutral behavior to `src/shared/`, `src/domain/`, or `src/app-server/`. Lower-level modules in `src/app-server/`, `src/domain/`, and `src/shared/` must remain independent from `src/features/`; ESLint enforces that dependency direction. Codex Panel's runtime UI is Preact-owned through the direct Preact APIs. Keep chat panel UI, the Threads view, and the selection rewrite popover in Preact components. The chat panel shell is a single Preact tree; toolbar, goal, message stream, and composer content should be composed as Preact nodes rather than mounted through HTMLElement region renderers. Use `preact/hooks` for hooks, `preact` for component types and fragments, and the shared root adapter for mounting and unmounting Preact subtrees. Imperative DOM writes are limited to explicit bridge modules or Obsidian-owned API boundaries such as `MarkdownRenderer`, TanStack Virtual measurement/lifecycle glue, diff rendering, icon rendering, `SuggestModal`, and the Obsidian `Setting`-based settings tab. ESLint enforces this boundary with allowlisted bridge files; add a new allowlist entry only when the code is genuinely bridging an external DOM API. diff --git a/eslint.config.mjs b/eslint.config.mjs index 775853ff..f60a7d21 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -21,24 +21,9 @@ const removedChatStateEscapeHatchRestrictions = [ message: "Use a named ChatAction instead of reintroducing the generic state patch escape hatch.", }, ]; -const generatedAppServerSourceImportPatterns = [ - "src/generated/app-server/**", - "../generated/app-server/**", - "../../generated/app-server/**", - "../../../generated/app-server/**", - "../../../../generated/app-server/**", - "../../../../../generated/app-server/**", - "../../../../../../generated/app-server/**", -]; -const generatedAppServerTestImportPatterns = [ - "src/generated/app-server/**", - "../src/generated/app-server/**", - "../../src/generated/app-server/**", - "../../../src/generated/app-server/**", - "../../../../src/generated/app-server/**", - "../../../../../src/generated/app-server/**", - "../../../../../../src/generated/app-server/**", -]; +const generatedAppServerSourceImportPatterns = importBoundaryPatterns("generated/app-server", "src/generated/app-server", 6); +const generatedAppServerTestImportPatterns = importBoundaryPatterns("src/generated/app-server", "src/generated/app-server", 6); +const lowerLevelFeatureImportPatterns = importBoundaryPatterns("features", "src/features", 6); const generatedAppServerThreadImportRestrictions = [ { selector: @@ -99,17 +84,16 @@ const pureChatModelRestrictions = [ ]; const chatExternalDomBridgeFiles = [ "src/features/chat/ui/message-stream/markdown-renderer.ts", - "src/features/chat/ui/message-stream/rendered-markdown-links.ts", - "src/features/chat/ui/message-virtualizer.ts", + "src/features/chat/ui/message-stream/virtualizer.ts", ]; const chatPreactDomBridgeFiles = [ + "src/features/chat/ui/goal.tsx", "src/features/chat/ui/message-stream/text-item-actions.tsx", "src/features/chat/ui/message-stream/text-item.tsx", - "src/features/chat/ui/message-stream/render.tsx", + "src/features/chat/ui/message-stream/tool-result.tsx", + "src/features/chat/ui/message-stream/viewport.tsx", "src/features/chat/ui/composer.tsx", - "src/features/chat/ui/goal-banner.tsx", "src/features/chat/ui/shell.tsx", - "src/features/chat/ui/tool-result.tsx", "src/features/chat/turn-diff/render.tsx", ]; const chatImperativeDomBridgeFiles = [...chatExternalDomBridgeFiles, ...chatPreactDomBridgeFiles]; @@ -125,6 +109,16 @@ const nonChatImperativeDomBridgeFiles = [ "src/shared/ui/ui-root.tsx", ]; const nonUiEventListenerFiles = ["src/shared/lifecycle/abortable.ts"]; +const baseSourceSyntaxRestrictions = [ + ...removedChatStateEscapeHatchRestrictions, + ...generatedAppServerThreadImportRestrictions, + ...unsafeIteratorRestrictions, + ...preactFormRestrictions, +]; +const sourceSyntaxRestrictions = [...baseSourceSyntaxRestrictions, ...imperativeDomRestrictions]; +const domBridgeSyntaxRestrictions = baseSourceSyntaxRestrictions; +const eventBridgeSyntaxRestrictions = [...baseSourceSyntaxRestrictions, ...imperativeDomWriteRestrictions]; +const pureChatModelSyntaxRestrictions = [...sourceSyntaxRestrictions, ...pureChatModelRestrictions]; const codexPanelEslintPlugin = { rules: { "no-self-referential-initializer-callback": { @@ -179,6 +173,17 @@ const codexPanelEslintPlugin = { }, }; +function importBoundaryPatterns(relativeTarget, absoluteTarget, maxParentDepth) { + const targets = [absoluteTarget, ...Array.from({ length: maxParentDepth }, (_, index) => `${"../".repeat(index + 1)}${relativeTarget}`)]; + return targets.flatMap((target) => [target, `${target}/**`]); +} + +function restrictedSyntaxRule(restrictions) { + return { + "no-restricted-syntax": ["error", ...restrictions], + }; +} + function isChatStateMember(node) { if (!isMemberExpression(node)) return false; @@ -328,7 +333,7 @@ export default defineConfig([ "@typescript-eslint/no-unsafe-member-access": "off", "@typescript-eslint/no-unnecessary-type-assertion": "off", "@typescript-eslint/require-await": "off", - "no-restricted-syntax": ["error", ...generatedAppServerThreadImportRestrictions], + ...restrictedSyntaxRule(generatedAppServerThreadImportRestrictions), }, }, { @@ -351,107 +356,48 @@ export default defineConfig([ { files: ["src/**/*.{ts,tsx}"], ignores: ["src/features/chat/**/*.{ts,tsx}", ...nonChatImperativeDomBridgeFiles, ...nonUiEventListenerFiles], - rules: { - "no-restricted-syntax": [ - "error", - ...removedChatStateEscapeHatchRestrictions, - ...generatedAppServerThreadImportRestrictions, - ...unsafeIteratorRestrictions, - ...imperativeDomRestrictions, - ...preactFormRestrictions, - ], - }, + rules: restrictedSyntaxRule(sourceSyntaxRestrictions), }, { files: ["src/features/chat/**/*.{ts,tsx}"], ignores: chatImperativeDomBridgeFiles, rules: { - "no-restricted-syntax": [ - "error", - ...removedChatStateEscapeHatchRestrictions, - ...generatedAppServerThreadImportRestrictions, - ...unsafeIteratorRestrictions, - ...imperativeDomRestrictions, - ...preactFormRestrictions, - ], + ...restrictedSyntaxRule(sourceSyntaxRestrictions), "codex-panel/no-chat-state-direct-mutation": "error", }, }, { files: chatImperativeDomBridgeFiles, rules: { - "no-restricted-syntax": [ - "error", - ...removedChatStateEscapeHatchRestrictions, - ...generatedAppServerThreadImportRestrictions, - ...unsafeIteratorRestrictions, - ...preactFormRestrictions, - ], + ...restrictedSyntaxRule(domBridgeSyntaxRestrictions), "codex-panel/no-chat-state-direct-mutation": "error", }, }, { files: nonChatImperativeDomBridgeFiles, - rules: { - "no-restricted-syntax": [ - "error", - ...removedChatStateEscapeHatchRestrictions, - ...generatedAppServerThreadImportRestrictions, - ...unsafeIteratorRestrictions, - ...preactFormRestrictions, - ], - }, + rules: restrictedSyntaxRule(domBridgeSyntaxRestrictions), }, { files: nonUiEventListenerFiles, - rules: { - "no-restricted-syntax": [ - "error", - ...removedChatStateEscapeHatchRestrictions, - ...generatedAppServerThreadImportRestrictions, - ...unsafeIteratorRestrictions, - ...imperativeDomWriteRestrictions, - ...preactFormRestrictions, - ], - }, + rules: restrictedSyntaxRule(eventBridgeSyntaxRestrictions), }, { files: ["src/features/chat/state/reducer.ts", "src/features/chat/display/**/*.{ts,tsx}"], rules: { - "no-restricted-syntax": [ - "error", - ...removedChatStateEscapeHatchRestrictions, - ...generatedAppServerThreadImportRestrictions, - ...unsafeIteratorRestrictions, - ...imperativeDomRestrictions, - ...preactFormRestrictions, - ...pureChatModelRestrictions, - ], + ...restrictedSyntaxRule(pureChatModelSyntaxRestrictions), "codex-panel/no-chat-state-direct-mutation": "error", }, }, { - files: ["src/app-server/**/*.{ts,tsx}", "src/domain/**/*.{ts,tsx}", "src/runtime/**/*.{ts,tsx}", "src/shared/**/*.{ts,tsx}"], + files: ["src/app-server/**/*.{ts,tsx}", "src/domain/**/*.{ts,tsx}", "src/shared/**/*.{ts,tsx}"], rules: { "no-restricted-imports": [ "error", { patterns: [ { - group: [ - "src/features", - "src/features/**", - "../features", - "../features/**", - "../../features", - "../../features/**", - "../../../features", - "../../../features/**", - "../../../../features", - "../../../../features/**", - ], - message: - "Lower-level modules must not import feature modules. Move shared behavior to shared, domain, runtime, or app-server.", + group: lowerLevelFeatureImportPatterns, + message: "Lower-level modules must not import feature modules. Move shared behavior to shared, domain, or app-server.", }, ], }, diff --git a/scripts/generated-app-server-boundary.json b/scripts/generated-app-server-boundary.json deleted file mode 100644 index 04adbb01..00000000 --- a/scripts/generated-app-server-boundary.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "protocolAdapterFiles": [ - "src/features/chat/protocol/display-items.ts", - "src/features/chat/protocol/inbound/notification-plan.ts" - ] -} diff --git a/src/app-server/connection/client.ts b/src/app-server/connection/client.ts index 1f384ded..6e0ff7ce 100644 --- a/src/app-server/connection/client.ts +++ b/src/app-server/connection/client.ts @@ -39,7 +39,14 @@ import type { TurnSteerResponse } from "../../generated/app-server/v2/TurnSteerR import type { UserInput } from "../../generated/app-server/v2/UserInput"; import { CLIENT_VERSION } from "../../constants"; import { StdioAppServerTransport, type AppServerTransport, type AppServerTransportHandlers } from "./transport"; -import type { ClientRequestMethod, ClientRequestParams, PendingRequest, RpcError, RpcInboundMessage, RpcOutboundMessage } from "./rpc-messages"; +import type { + ClientRequestMethod, + ClientRequestParams, + PendingRequest, + RpcError, + RpcInboundMessage, + RpcOutboundMessage, +} from "./rpc-messages"; import type { ServerNotification } from "../../generated/app-server/ServerNotification"; import type { ServerRequest } from "../../generated/app-server/ServerRequest"; import type { JsonValue } from "../../generated/app-server/serde_json/JsonValue"; diff --git a/src/app-server/protocol/diagnostics.ts b/src/app-server/protocol/diagnostics.ts index 4c720ca7..e32b770a 100644 --- a/src/app-server/protocol/diagnostics.ts +++ b/src/app-server/protocol/diagnostics.ts @@ -12,7 +12,7 @@ export const DIAGNOSTIC_PROBE_METHODS = [ export type DiagnosticProbeMethod = (typeof DIAGNOSTIC_PROBE_METHODS)[number]; type DiagnosticProbeStatus = "unknown" | "ok" | "failed"; -export type McpAuthStatus = "unsupported" | "notLoggedIn" | "bearerToken" | "oAuth"; +type McpAuthStatus = "unsupported" | "notLoggedIn" | "bearerToken" | "oAuth"; export type McpServerStartupStatus = "starting" | "ready" | "failed" | "cancelled"; export interface McpServerStatus { diff --git a/src/app-server/protocol/runtime-config.ts b/src/app-server/protocol/runtime-config.ts index 558aa552..2aba48b8 100644 --- a/src/app-server/protocol/runtime-config.ts +++ b/src/app-server/protocol/runtime-config.ts @@ -121,7 +121,7 @@ function asRecordOrNull(value: unknown): Record | null { } function asConfigRecord(value: unknown): ConfigProjectionRecord { - return asRecord(value) as ConfigProjectionRecord; + return asRecord(value); } function selectedConfigProfile(layers: ConfigReadResult["layers"]): string | null { diff --git a/src/app-server/protocol/runtime-metrics.ts b/src/app-server/protocol/runtime-metrics.ts index ae320a00..85532c4b 100644 --- a/src/app-server/protocol/runtime-metrics.ts +++ b/src/app-server/protocol/runtime-metrics.ts @@ -41,7 +41,7 @@ export interface TokenUsageBreakdown { reasoningOutputTokens: number; } -export function rateLimitSnapshotFromAppServerSnapshot(snapshot: AppServerRateLimitSnapshot): RateLimitSnapshot { +function rateLimitSnapshotFromAppServerSnapshot(snapshot: AppServerRateLimitSnapshot): RateLimitSnapshot { return { limitId: snapshot.limitId, limitName: snapshot.limitName, diff --git a/src/app-server/protocol/turn.ts b/src/app-server/protocol/turn.ts index a59e5e21..3c417559 100644 --- a/src/app-server/protocol/turn.ts +++ b/src/app-server/protocol/turn.ts @@ -21,7 +21,7 @@ export function transcriptEntriesFromTurnRecords(turns: readonly TurnRecord[]): return turns.flatMap(transcriptEntriesFromTurnRecord); } -export function conversationSummaryFromTurnRecord(turn: TurnRecord): ThreadConversationSummary { +function conversationSummaryFromTurnRecord(turn: TurnRecord): ThreadConversationSummary { return conversationSummaryFromTranscriptEntries(transcriptEntriesFromTurnRecord(turn)); } @@ -42,7 +42,7 @@ export function completedConversationSummariesFromTurnRecords(turns: readonly Tu }); } -export function conversationSummariesFromTurnRecords(turns: readonly TurnRecord[]): ThreadConversationSummary[] { +function conversationSummariesFromTurnRecords(turns: readonly TurnRecord[]): ThreadConversationSummary[] { return nonEmptyConversationSummaries(turns.map(conversationSummaryFromTurnRecord)); } diff --git a/src/features/chat/connection/server-actions/diagnostics.ts b/src/features/chat/connection/server-actions/diagnostics.ts index effbdbc0..7c435834 100644 --- a/src/features/chat/connection/server-actions/diagnostics.ts +++ b/src/features/chat/connection/server-actions/diagnostics.ts @@ -73,11 +73,7 @@ async function refreshDiagnosticProbes( return `${String(count)} skills`; }, ), - probeDiagnostic( - "account/rateLimits/read", - () => client.readAccountRateLimits(), - accountRateLimitsSummaryFromResponse, - ), + probeDiagnostic("account/rateLimits/read", () => client.readAccountRateLimits(), accountRateLimitsSummaryFromResponse), ); } @@ -148,10 +144,7 @@ async function mcpStatusLines(host: ChatServerDiagnosticsActionsHost): Promise; type WebSearchItem = Extract; type ImageViewItem = Extract; type ImageGenerationItem = Extract; -type ReviewModeItem = - | Extract - | Extract; +type ReviewModeItem = Extract | Extract; type ContextCompactionItem = Extract; type DisplayExecutionState = Exclude; type ExecutionStateByStatus = Readonly>; @@ -693,7 +691,7 @@ export function dynamicToolCallExecutionState(status: string, success?: boolean return success === true ? "completed" : null; } -export function imageGenerationExecutionState(status: string): ExecutionState { +function imageGenerationExecutionState(status: string): ExecutionState { return standardToolCallExecutionState(status); } diff --git a/src/features/chat/panel/regions/ports.ts b/src/features/chat/panel/regions/ports.ts index d385222f..416671aa 100644 --- a/src/features/chat/panel/regions/ports.ts +++ b/src/features/chat/panel/regions/ports.ts @@ -28,7 +28,7 @@ interface ChatPanelGoalActions { setEditingOpen: (open: boolean) => void; } -export interface ChatPanelStatePort { +interface ChatPanelStatePort { state: { chat: () => ChatState; }; diff --git a/src/features/chat/protocol/inbound/controller.ts b/src/features/chat/protocol/inbound/controller.ts index 1a232daf..1693c485 100644 --- a/src/features/chat/protocol/inbound/controller.ts +++ b/src/features/chat/protocol/inbound/controller.ts @@ -111,7 +111,10 @@ export class ChatInboundController { } addStructuredSystemMessage(text: string, details: DisplayDetailSection[]): void { - this.dispatch({ type: "message-stream/system-item-added", item: createStructuredSystemItem(this.localItemId("system"), text, details) }); + this.dispatch({ + type: "message-stream/system-item-added", + item: createStructuredSystemItem(this.localItemId("system"), text, details), + }); } addDedupedSystemMessage(text: string): void { diff --git a/src/features/chat/protocol/inbound/notification-plan.ts b/src/features/chat/protocol/inbound/notification-plan.ts index 15a804b9..5137a802 100644 --- a/src/features/chat/protocol/inbound/notification-plan.ts +++ b/src/features/chat/protocol/inbound/notification-plan.ts @@ -21,7 +21,12 @@ import { completeReasoningItems, upsertDisplayItem, } from "../../state/message-stream-updates"; -import { displayItemFromTurnItem, displayItemsFromTurns, normalizeFileChanges, shouldSuppressLifecycleItem } from "../../display/turn-items"; +import { + displayItemFromTurnItem, + displayItemsFromTurns, + normalizeFileChanges, + shouldSuppressLifecycleItem, +} from "../../display/turn-items"; import { taskProgressDisplayItem } from "../../display/items/task-progress"; import { createSystemItem } from "../../display/items/system"; import type { DisplayItem, DisplayKind, MessageDisplayItem } from "../../display/types"; diff --git a/src/features/chat/runtime/effective.ts b/src/features/chat/runtime/effective.ts index 11de662d..32c92646 100644 --- a/src/features/chat/runtime/effective.ts +++ b/src/features/chat/runtime/effective.ts @@ -1,4 +1,8 @@ -import { cloneRuntimeConfigSnapshot, emptyRuntimeConfigSnapshot, type RuntimeConfigSnapshot } from "../../../app-server/protocol/runtime-config"; +import { + cloneRuntimeConfigSnapshot, + emptyRuntimeConfigSnapshot, + type RuntimeConfigSnapshot, +} from "../../../app-server/protocol/runtime-config"; import { findModelMetadataByIdOrName, type ModelMetadata } from "../../../domain/catalog/metadata"; import type { ApprovalPolicy, ApprovalsReviewer } from "../../../app-server/protocol/runtime-policy"; import { supportedEffortsForModelMetadata, type ReasoningEffort } from "../../../domain/catalog/metadata"; diff --git a/src/features/chat/runtime/thread-settings-update.ts b/src/features/chat/runtime/thread-settings-update.ts index 67a51486..f418bab0 100644 --- a/src/features/chat/runtime/thread-settings-update.ts +++ b/src/features/chat/runtime/thread-settings-update.ts @@ -1,4 +1,8 @@ -import { applyThreadSettingsValue, appServerCollaborationMode, type ThreadSettingsUpdate } from "../../../app-server/protocol/thread-settings"; +import { + applyThreadSettingsValue, + appServerCollaborationMode, + type ThreadSettingsUpdate, +} from "../../../app-server/protocol/thread-settings"; import type { ServiceTierRequest } from "../../../app-server/protocol/thread-settings"; import { currentModel, currentReasoningEffort, fastServiceTierRequestValue } from "./effective"; import type { RuntimeConfigSnapshot } from "../../../app-server/protocol/runtime-config"; diff --git a/src/features/chat/state/message-stream-updates.ts b/src/features/chat/state/message-stream-updates.ts index 646558be..fec14534 100644 --- a/src/features/chat/state/message-stream-updates.ts +++ b/src/features/chat/state/message-stream-updates.ts @@ -30,7 +30,9 @@ function mergeChanges(previous: DisplayItem, next: DisplayItem): DisplayFileChan } export function appendAssistantDelta(items: readonly DisplayItem[], sourceItemId: string, turnId: string, delta: string): DisplayItem[] { - const index = items.findIndex((item) => item.sourceItemId === sourceItemId && item.kind === "message" && item.messageKind === "assistantResponse"); + const index = items.findIndex( + (item) => item.sourceItemId === sourceItemId && item.kind === "message" && item.messageKind === "assistantResponse", + ); if (index !== -1) { return items.map((item, itemIndex) => itemIndex === index && item.kind === "message" && item.messageKind === "assistantResponse" diff --git a/src/features/chat/state/reducer.ts b/src/features/chat/state/reducer.ts index 04c97956..97cd397e 100644 --- a/src/features/chat/state/reducer.ts +++ b/src/features/chat/state/reducer.ts @@ -46,7 +46,12 @@ import type { TurnStartFailedAction, UserInputDraftSetAction, } from "./actions"; -import { initialChatMessageStreamState, reduceMessageStreamSlice, type ChatMessageStreamState, type MessageStreamAction } from "./message-stream"; +import { + initialChatMessageStreamState, + reduceMessageStreamSlice, + type ChatMessageStreamState, + type MessageStreamAction, +} from "./message-stream"; import { initialChatRequestState, reduceRequestSlice, diff --git a/src/features/chat/state/selectors.ts b/src/features/chat/state/selectors.ts index 8f454b9e..e40f1c54 100644 --- a/src/features/chat/state/selectors.ts +++ b/src/features/chat/state/selectors.ts @@ -1,5 +1,12 @@ import { activeTurnId as selectActiveTurnId, chatTurnBusy, pendingTurnStart } from "./reducer"; -import type { ChatActiveThreadState, ChatRuntimeState, ChatState, ChatMessageStreamState, ChatTurnState, PendingTurnStart } from "./reducer"; +import type { + ChatActiveThreadState, + ChatRuntimeState, + ChatState, + ChatMessageStreamState, + ChatTurnState, + PendingTurnStart, +} from "./reducer"; import type { Thread } from "../../../domain/threads/model"; import type { DisplayItem } from "../display/types"; diff --git a/src/features/chat/threads/goal-actions.ts b/src/features/chat/threads/goal-actions.ts index dc7982a5..6dfff8e8 100644 --- a/src/features/chat/threads/goal-actions.ts +++ b/src/features/chat/threads/goal-actions.ts @@ -49,12 +49,7 @@ async function syncThreadGoal(host: GoalActionsHost, threadId: string): Promise< } } -async function setObjective( - host: GoalActionsHost, - threadId: string, - objective: string, - tokenBudget: number | null, -): Promise { +async function setObjective(host: GoalActionsHost, threadId: string, objective: string, tokenBudget: number | null): Promise { const trimmed = objective.trim(); if (!trimmed) { host.addSystemMessage("Goal objective cannot be empty."); @@ -104,12 +99,7 @@ async function setGoal(host: GoalActionsHost, threadId: string, params: ThreadGo } } -function applyGoalIfActive( - host: GoalActionsHost, - threadId: string, - goal: ThreadGoal | null, - options: { reportChange: boolean }, -): boolean { +function applyGoalIfActive(host: GoalActionsHost, threadId: string, goal: ThreadGoal | null, options: { reportChange: boolean }): boolean { const state = host.stateStore.getState(); if (state.activeThread.id !== threadId) return false; const item = options.reportChange ? goalChangeItem(goalEventId(), state.activeThread.goal, goal) : null; diff --git a/src/features/chat/threads/history-controller.ts b/src/features/chat/threads/history-controller.ts index 630f3b30..5c7e7c34 100644 --- a/src/features/chat/threads/history-controller.ts +++ b/src/features/chat/threads/history-controller.ts @@ -58,7 +58,11 @@ export class HistoryController { if (this.state.activeThread.id !== threadId) return false; this.host.setThreadTurnPresence(response.data.length > 0); this.host.showLatestPageAtBottom(); - this.dispatch({ type: "message-stream/items-replaced", items: displayItemsFromTurns(response.data), historyCursor: response.nextCursor }); + this.dispatch({ + type: "message-stream/items-replaced", + items: displayItemsFromTurns(response.data), + historyCursor: response.nextCursor, + }); this.host.render(); return true; } diff --git a/src/features/chat/threads/rename-controller.ts b/src/features/chat/threads/rename-controller.ts index b89e98d1..b8306e8a 100644 --- a/src/features/chat/threads/rename-controller.ts +++ b/src/features/chat/threads/rename-controller.ts @@ -4,11 +4,7 @@ import { getThreadTitle } from "../../../domain/threads/model"; import type { Thread } from "../../../domain/threads/model"; import type { CodexPanelSettings } from "../../../settings/model"; import { generateThreadTitleWithCodex } from "../../thread-title/generation"; -import { - findThreadTitleContext, - THREAD_TITLE_CONTEXT_UNAVAILABLE_MESSAGE, - type ThreadTitleContext, -} from "../../thread-title/model"; +import { findThreadTitleContext, THREAD_TITLE_CONTEXT_UNAVAILABLE_MESSAGE, type ThreadTitleContext } from "../../thread-title/model"; import type { ChatState, ChatStateStore } from "../state/reducer"; import { renameConnectedThread } from "./rename-actions"; import { firstThreadTitleContextFromDisplayItems } from "./title-context"; diff --git a/src/features/chat/threads/resume.ts b/src/features/chat/threads/resume.ts index 46c4b0b0..84174c72 100644 --- a/src/features/chat/threads/resume.ts +++ b/src/features/chat/threads/resume.ts @@ -2,7 +2,10 @@ import { parseServiceTier } from "../../../app-server/protocol/runtime-policy"; import { upsertThread } from "../../../domain/threads/model"; import { normalizeReasoningEffort } from "../../../domain/catalog/metadata"; import type { Thread } from "../../../domain/threads/model"; -import { threadActivationSnapshotFromAppServerResponse, type ThreadActivationSnapshot } from "../../../app-server/services/thread-activation"; +import { + threadActivationSnapshotFromAppServerResponse, + type ThreadActivationSnapshot, +} from "../../../app-server/services/thread-activation"; import type { ChatRuntimeState } from "../runtime/state"; import type { DisplayItem } from "../display/types"; import type { ActiveThreadResumedAction } from "../state/actions"; diff --git a/src/features/chat/ui/message-stream/markdown-renderer.ts b/src/features/chat/ui/message-stream/markdown-renderer.ts index 40fb27d0..53a32ba0 100644 --- a/src/features/chat/ui/message-stream/markdown-renderer.ts +++ b/src/features/chat/ui/message-stream/markdown-renderer.ts @@ -52,7 +52,7 @@ export function bindRenderedWikiLinks(parent: HTMLElement, sourcePath: string, c }); } -export function bindRenderedMarkdownFileLinks(parent: HTMLElement, sourcePath: string, context: RenderedMarkdownLinkContext): void { +function bindRenderedMarkdownFileLinks(parent: HTMLElement, sourcePath: string, context: RenderedMarkdownLinkContext): void { parent.querySelectorAll("a[href]:not(.internal-link)").forEach((link) => { const href = link.getAttribute("href") ?? ""; const target = vaultFileLinkTarget(context.app, context.vaultPath, href); diff --git a/src/features/chat/ui/message-stream/text-item.tsx b/src/features/chat/ui/message-stream/text-item.tsx index 41a90edf..25fd26c6 100644 --- a/src/features/chat/ui/message-stream/text-item.tsx +++ b/src/features/chat/ui/message-stream/text-item.tsx @@ -93,7 +93,13 @@ function CollapsibleTextItemContent({ item, context }: { item: TextDisplayItem; .filter(Boolean) .join(" ")} > - +