mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 06:57:10 +00:00
Constrain app-server root module placement
This commit is contained in:
parent
7b1b789f3b
commit
19dc423f21
43 changed files with 182 additions and 70 deletions
12
biome.jsonc
12
biome.jsonc
|
|
@ -7,6 +7,18 @@
|
|||
},
|
||||
"plugins": [
|
||||
// App-server protocol and generated binding boundaries.
|
||||
{
|
||||
"path": "./scripts/lint/no-app-server-root-module-files.grit",
|
||||
"includes": ["**/src/app-server/*.ts"]
|
||||
},
|
||||
{
|
||||
"path": "./scripts/lint/no-app-server-root-module-imports.grit",
|
||||
"includes": ["**/src/**/*.ts", "**/src/**/*.tsx"]
|
||||
},
|
||||
{
|
||||
"path": "./scripts/lint/no-app-server-subfolder-root-imports.grit",
|
||||
"includes": ["**/src/app-server/**/*.ts"]
|
||||
},
|
||||
{
|
||||
"path": "./scripts/lint/no-app-server-projection-rpcs.grit",
|
||||
"includes": ["**/src/features/chat/application/**/*.ts"]
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ The generation script uses `codex app-server generate-ts --experimental` because
|
|||
The source tree is organized by implementation ownership, not by the single Obsidian plugin entrypoint:
|
||||
|
||||
- `src/main.ts` and `src/plugin-runtime.ts` own Obsidian plugin registration, lifecycle wiring, and cross-surface runtime coordination.
|
||||
- `src/app-server/` owns the app-server boundary, including connection code, protocol adapters, app-server services, shared queries, and generated payload adaptation.
|
||||
- `src/app-server/` owns the app-server boundary through responsibility subfolders such as `connection/`, `protocol/`, `query/`, `routing/`, and `services/`. Do not add root-level app-server modules.
|
||||
- `src/features/` contains feature-owned surfaces and workflows. Feature-to-feature imports are acceptable only when the imported feature owns a concrete capability.
|
||||
- `src/workspace/` and `src/settings/` own Obsidian workspace coordination and settings-tab behavior.
|
||||
- `src/domain/` contains panel-owned, generated-independent meaning models and pure derivations. Domain code must not import app-server protocol, generated bindings, feature modules, UI, or Obsidian APIs.
|
||||
|
|
|
|||
5
scripts/lint/no-app-server-root-module-files.grit
Normal file
5
scripts/lint/no-app-server-root-module-files.grit
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
language js
|
||||
|
||||
`$program` where {
|
||||
register_diagnostic(span=$program, message="Keep app-server modules in responsibility subfolders; src/app-server root must not accumulate boundary adapters.", severity="error")
|
||||
}
|
||||
16
scripts/lint/no-app-server-root-module-imports.grit
Normal file
16
scripts/lint/no-app-server-root-module-imports.grit
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
language js
|
||||
|
||||
private pattern js_module_reference() {
|
||||
or {
|
||||
JsImport(),
|
||||
JsExportNamedFromClause(),
|
||||
JsExportFromClause(),
|
||||
TsImportType(),
|
||||
JsImportCallExpression()
|
||||
}
|
||||
}
|
||||
|
||||
js_module_reference() as $stmt where {
|
||||
$stmt <: contains `$source` where { $source <: r"^[\"'](?:(?:\./)?app-server|(?:\.\./)+app-server|src/app-server)/[^/\"']+[\"']$" },
|
||||
register_diagnostic(span=$stmt, message="Import app-server boundary modules from responsibility subfolders, not src/app-server root modules.", severity="error")
|
||||
}
|
||||
16
scripts/lint/no-app-server-subfolder-root-imports.grit
Normal file
16
scripts/lint/no-app-server-subfolder-root-imports.grit
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
language js
|
||||
|
||||
private pattern js_module_reference() {
|
||||
or {
|
||||
JsImport(),
|
||||
JsExportNamedFromClause(),
|
||||
JsExportFromClause(),
|
||||
TsImportType(),
|
||||
JsImportCallExpression()
|
||||
}
|
||||
}
|
||||
|
||||
js_module_reference() as $stmt where {
|
||||
$stmt <: contains `$source` where { $source <: r"^[\"']\.\./[^/\"']+[\"']$" },
|
||||
register_diagnostic(span=$stmt, message="App-server subfolders must not import sibling root modules; move the dependency into a responsibility subfolder.", severity="error")
|
||||
}
|
||||
|
|
@ -4,11 +4,11 @@ import type { ObservedResult, ObservedResultListener } from "../../domain/observ
|
|||
import { createServerDiagnostics, diagnosticProbeError, diagnosticProbeOk, diagnosticsWithProbe } from "../../domain/server/diagnostics";
|
||||
import type { SharedServerMetadata } from "../../domain/server/metadata";
|
||||
import type { Thread } from "../../domain/threads/model";
|
||||
import { listModelMetadata } from "../catalog";
|
||||
import type { AppServerClient } from "../connection/client";
|
||||
import type { AppServerClientAccessOptions } from "../connection/client-access";
|
||||
import { runtimeConfigSnapshotFromAppServerConfig } from "../protocol/runtime-config";
|
||||
import { listThreads } from "../threads";
|
||||
import { listModelMetadata } from "../services/catalog";
|
||||
import { listThreads } from "../services/threads";
|
||||
import {
|
||||
type AppServerQueryContext,
|
||||
activeThreadsQueryKey,
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import type { SkillMetadata } from "../../domain/catalog/metadata";
|
||||
import type { RateLimitSnapshot } from "../../domain/runtime/metrics";
|
||||
import { type Diagnostics, diagnosticProbeError, diagnosticProbeOk } from "../../domain/server/diagnostics";
|
||||
import { listSkillCatalog } from "../catalog";
|
||||
import type { AppServerClient } from "../connection/client";
|
||||
import { accountRateLimitsSummaryFromResponse, rateLimitSnapshotFromAccountRateLimitsResponse } from "../protocol/runtime-metrics";
|
||||
import { listSkillCatalog } from "../services/catalog";
|
||||
|
||||
interface MetadataProbeResult<T, K extends keyof Diagnostics["probes"]> {
|
||||
value: T;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { ObservedResultListener } from "../domain/observed-result";
|
||||
import type { Thread } from "../domain/threads/model";
|
||||
import type { ObservedResultListener } from "../../domain/observed-result";
|
||||
import type { Thread } from "../../domain/threads/model";
|
||||
|
||||
type ThreadListObserver = ObservedResultListener<readonly Thread[]>;
|
||||
|
||||
|
|
@ -5,8 +5,8 @@ import type {
|
|||
PendingApproval,
|
||||
PendingMcpElicitation,
|
||||
PendingUserInput,
|
||||
} from "../domain/pending-requests/model";
|
||||
import type { ServerRequest } from "./connection/rpc-messages";
|
||||
} from "../../domain/pending-requests/model";
|
||||
import type { ServerRequest } from "../connection/rpc-messages";
|
||||
import {
|
||||
appServerApprovalRequest,
|
||||
appServerApprovalResponse,
|
||||
|
|
@ -14,14 +14,14 @@ import {
|
|||
appServerMcpElicitationResponse,
|
||||
appServerUserInputRequest,
|
||||
appServerUserInputResponse,
|
||||
} from "./protocol/server-requests";
|
||||
} from "../protocol/server-requests";
|
||||
import {
|
||||
type ActiveRouteScope,
|
||||
fallbackMessageScope,
|
||||
isMessageScopeInActiveRouteScope,
|
||||
isTurnScopedMessageForIdleActiveThread,
|
||||
type MessageScope,
|
||||
} from "./route-scope";
|
||||
} from "./scope";
|
||||
|
||||
export type ServerRequestRoute =
|
||||
| { kind: "approval"; request: ServerRequest; approval: PendingApproval }
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
import type { HookItem, ModelMetadata, SkillMetadata } from "../domain/catalog/metadata";
|
||||
import type { AppServerClient } from "./connection/client";
|
||||
import type { HookItem, ModelMetadata, SkillMetadata } from "../../domain/catalog/metadata";
|
||||
import type { AppServerClient } from "../connection/client";
|
||||
import {
|
||||
appServerHookOperationFromHookItem,
|
||||
type CatalogModel,
|
||||
hookItemsFromCatalogHooks,
|
||||
modelMetadataFromCatalogModels,
|
||||
skillMetadataFromCatalogSkills,
|
||||
} from "./protocol/catalog";
|
||||
} from "../protocol/catalog";
|
||||
|
||||
export interface HookCatalog {
|
||||
hooks: HookItem[];
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
import { listenAbortSignal } from "../../shared/lifecycle/abort-signal";
|
||||
import type { ModelMetadataClient } from "../catalog";
|
||||
import {
|
||||
AppServerClient,
|
||||
type AppServerClientHandlers,
|
||||
|
|
@ -9,6 +8,7 @@ import {
|
|||
import type { AppServerClientRequestPolicy } from "../connection/client-access";
|
||||
import type { ServerNotification } from "../connection/rpc-messages";
|
||||
import { lastAgentMessageTextFromTurnRecord, type TurnItem, type TurnRecord } from "../protocol/turn";
|
||||
import type { ModelMetadataClient } from "./catalog";
|
||||
|
||||
export type StructuredTurnOutputSchema = AppServerStartStructuredTurnOptions["outputSchema"];
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { ModelMetadata, ReasoningEffort } from "../../domain/catalog/metadata";
|
||||
import { findModelMetadataByIdOrName, supportedEffortsForModelMetadata } from "../../domain/catalog/metadata";
|
||||
import { listModelMetadata, type ModelMetadataClient } from "../catalog";
|
||||
import { listModelMetadata, type ModelMetadataClient } from "./catalog";
|
||||
|
||||
export interface RuntimeOverrideSettings {
|
||||
model: string | null;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import type { ArchiveExportSettings } from "../../domain/threads/archive-markdown";
|
||||
import type { AppServerClient } from "../connection/client";
|
||||
import { readThreadForArchiveExport } from "../threads";
|
||||
import { type ArchiveExportDestination, exportArchivedThreadMarkdown } from "./thread-archive-markdown";
|
||||
import { readThreadForArchiveExport } from "./threads";
|
||||
|
||||
export interface ArchiveThreadOptions {
|
||||
settings: ArchiveExportSettings;
|
||||
|
|
|
|||
|
|
@ -1,21 +1,21 @@
|
|||
import { normalizeReasoningEffort } from "../domain/catalog/metadata";
|
||||
import type { ApprovalsReviewer, ServiceTier } from "../domain/runtime/policy";
|
||||
import { parseServiceTier } from "../domain/runtime/policy";
|
||||
import type { ThreadActivationSnapshot } from "../domain/threads/activation";
|
||||
import type { ArchiveThreadInput } from "../domain/threads/archive-markdown";
|
||||
import type { ThreadGoal, ThreadGoalUpdate } from "../domain/threads/goal";
|
||||
import type { HistoricalTurn } from "../domain/threads/history";
|
||||
import type { Thread } from "../domain/threads/model";
|
||||
import { REFERENCED_THREAD_TURN_LIMIT } from "../domain/threads/reference";
|
||||
import type { ThreadConversationSummary } from "../domain/threads/transcript";
|
||||
import type { AppServerClient } from "./connection/client";
|
||||
import { type ThreadRecord, threadFromThreadRecord, threadsFromThreadRecords } from "./protocol/thread";
|
||||
import { appServerThreadGoalUserHistoryItem, threadGoalFromAppServerGoal } from "./protocol/thread-goal";
|
||||
import { normalizeReasoningEffort } from "../../domain/catalog/metadata";
|
||||
import type { ApprovalsReviewer, ServiceTier } from "../../domain/runtime/policy";
|
||||
import { parseServiceTier } from "../../domain/runtime/policy";
|
||||
import type { ThreadActivationSnapshot } from "../../domain/threads/activation";
|
||||
import type { ArchiveThreadInput } from "../../domain/threads/archive-markdown";
|
||||
import type { ThreadGoal, ThreadGoalUpdate } from "../../domain/threads/goal";
|
||||
import type { HistoricalTurn } from "../../domain/threads/history";
|
||||
import type { Thread } from "../../domain/threads/model";
|
||||
import { REFERENCED_THREAD_TURN_LIMIT } from "../../domain/threads/reference";
|
||||
import type { ThreadConversationSummary } from "../../domain/threads/transcript";
|
||||
import type { AppServerClient } from "../connection/client";
|
||||
import { type ThreadRecord, threadFromThreadRecord, threadsFromThreadRecords } from "../protocol/thread";
|
||||
import { appServerThreadGoalUserHistoryItem, threadGoalFromAppServerGoal } from "../protocol/thread-goal";
|
||||
import {
|
||||
chronologicalConversationSummariesFromTurnRecords,
|
||||
completedConversationSummariesFromTurnRecords,
|
||||
transcriptEntriesFromTurnRecords,
|
||||
} from "./protocol/turn";
|
||||
} from "../protocol/turn";
|
||||
|
||||
const THREAD_LIST_PAGE_LIMIT = 100;
|
||||
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import type { SkillMetadata } from "../domain/catalog/metadata";
|
||||
import type { SkillMetadata } from "../../domain/catalog/metadata";
|
||||
import {
|
||||
type DiagnosticProbeResult,
|
||||
diagnosticProbeError,
|
||||
|
|
@ -6,16 +6,16 @@ import {
|
|||
type McpServerDiagnostic,
|
||||
type McpServerStatusSummary,
|
||||
mcpServerStatusSummariesFromStatuses,
|
||||
} from "../domain/server/diagnostics";
|
||||
} from "../../domain/server/diagnostics";
|
||||
import type {
|
||||
ToolInventoryApp,
|
||||
ToolInventoryMarketplaceError,
|
||||
ToolInventoryPlugin,
|
||||
ToolInventorySnapshot,
|
||||
} from "../domain/server/tool-inventory";
|
||||
} from "../../domain/server/tool-inventory";
|
||||
import type { AppServerClient } from "../connection/client";
|
||||
import { toolInventoryAppsFromAppInfos, toolInventoryPluginsFromInstalledResponse } from "../protocol/tool-inventory";
|
||||
import { listSkillCatalog } from "./catalog";
|
||||
import type { AppServerClient } from "./connection/client";
|
||||
import { toolInventoryAppsFromAppInfos, toolInventoryPluginsFromInstalledResponse } from "./protocol/tool-inventory";
|
||||
|
||||
const APP_PAGE_LIMIT = 100;
|
||||
const APP_PAGE_LOOP_LIMIT = 20;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import type { AppServerClient } from "../../../../app-server/connection/client";
|
||||
import { readRateLimitMetadataProbe } from "../../../../app-server/query/metadata-probes";
|
||||
import { readToolInventory } from "../../../../app-server/tool-inventory";
|
||||
import { readToolInventory } from "../../../../app-server/services/tool-inventory";
|
||||
import {
|
||||
cloneServerDiagnostics,
|
||||
type DiagnosticProbeMethod,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { ThreadCatalogEvent } from "../../../../app-server/thread-catalog";
|
||||
import { threadActivationSnapshotFromAppServerResponse } from "../../../../app-server/threads";
|
||||
import type { ThreadCatalogEvent } from "../../../../app-server/query/thread-catalog";
|
||||
import { threadActivationSnapshotFromAppServerResponse } from "../../../../app-server/services/threads";
|
||||
import { runtimeConfigOrDefault } from "../../../../domain/runtime/config";
|
||||
import type { Thread } from "../../../../domain/threads/model";
|
||||
import { resumedThreadAction } from "../../application/state/actions";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { readThreadGoal, recordThreadGoalUserMessage, setThreadGoal } from "../../../../app-server/threads";
|
||||
import { readThreadGoal, recordThreadGoalUserMessage, setThreadGoal } from "../../../../app-server/services/threads";
|
||||
import type { ThreadGoalReadTransport, ThreadGoalTransport } from "../../application/threads/goal-transport";
|
||||
import type { ConnectedChatAppServerClientHost, CurrentChatAppServerClientHost } from "../client-scope";
|
||||
import { chatAppServerClientIsStale, withConnectedChatAppServerClient, withCurrentChatAppServerClient } from "../client-scope";
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import type { RequestId, ServerNotification, ServerRequest } from "../../../../app-server/connection/rpc-messages";
|
||||
import type { ThreadCatalogEvent } from "../../../../app-server/query/thread-catalog";
|
||||
import {
|
||||
routeServerRequest,
|
||||
serverRequestApprovalResponse,
|
||||
serverRequestCurrentTimeResponse,
|
||||
serverRequestMcpElicitationResponse,
|
||||
serverRequestUserInputResponse,
|
||||
} from "../../../../app-server/server-requests";
|
||||
import type { ThreadCatalogEvent } from "../../../../app-server/thread-catalog";
|
||||
} from "../../../../app-server/routing/server-requests";
|
||||
import {
|
||||
type ApprovalAction,
|
||||
contentForPendingMcpElicitation,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { ServerNotification } from "../../../../app-server/connection/rpc-messages";
|
||||
import type { ThreadCatalogEvent } from "../../../../app-server/thread-catalog";
|
||||
import { threadFromAppServerRecord } from "../../../../app-server/threads";
|
||||
import type { ThreadCatalogEvent } from "../../../../app-server/query/thread-catalog";
|
||||
import { threadFromAppServerRecord } from "../../../../app-server/services/threads";
|
||||
import { threadTokenUsageFromRuntimeUsage } from "../../../../domain/runtime/metrics";
|
||||
import { normalizeExplicitThreadName } from "../../../../domain/threads/model";
|
||||
import type { ThreadConversationSummary } from "../../../../domain/threads/transcript";
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import {
|
|||
isMessageScopeInActiveRouteScope,
|
||||
isTurnScopedMessageForIdleActiveThread,
|
||||
type MessageScope,
|
||||
} from "../../../../app-server/route-scope";
|
||||
} from "../../../../app-server/routing/scope";
|
||||
|
||||
type ServerNotificationMethod = ServerNotification["method"];
|
||||
type RoutedNotification<M extends ServerNotificationMethod> = Extract<ServerNotification, { method: M }>;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { readReferencedThreadConversationSummaries, type ThreadConversationSummaryClient } from "../../../../app-server/threads";
|
||||
import { readReferencedThreadConversationSummaries, type ThreadConversationSummaryClient } from "../../../../app-server/services/threads";
|
||||
import { type CodexInput, codexTextInputWithAttachments } from "../../../../domain/chat/input";
|
||||
import type { Thread } from "../../../../domain/threads/model";
|
||||
import { REFERENCED_THREAD_TURN_LIMIT, referencedThreadPromptBundle } from "../../../../domain/threads/reference";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { AppServerClient } from "../../../../app-server/connection/client";
|
||||
import { threadActivationSnapshotFromAppServerResponse } from "../../../../app-server/threads";
|
||||
import { threadActivationSnapshotFromAppServerResponse } from "../../../../app-server/services/threads";
|
||||
import type { ThreadTurnsPage } from "../../../../domain/threads/history";
|
||||
import type { ThreadHistoryPage, ThreadResumeSnapshot } from "../../application/threads/thread-loading-transport";
|
||||
import { messageStreamItemsFromTurns } from "../mappers/message-stream/turn-items";
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { compactThread, forkThread, rollbackThread } from "../../../../app-server/threads";
|
||||
import { compactThread, forkThread, rollbackThread } from "../../../../app-server/services/threads";
|
||||
import type { ThreadMutationTransport, ThreadRollbackSnapshot } from "../../application/threads/thread-mutation-transport";
|
||||
import type { ConnectedChatAppServerClientHost } from "../client-scope";
|
||||
import { withConnectedChatAppServerClient } from "../client-scope";
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ import type { App, Component, EventRef } from "obsidian";
|
|||
|
||||
import type { AppServerClient } from "../../../app-server/connection/client";
|
||||
import type { AppServerQueryContext } from "../../../app-server/query/keys";
|
||||
import type { ThreadCatalogActiveReader, ThreadCatalogEventSink } from "../../../app-server/query/thread-catalog";
|
||||
import type { ArchiveExportDestination } from "../../../app-server/services/thread-archive-markdown";
|
||||
import type { ThreadCatalogActiveReader, ThreadCatalogEventSink } from "../../../app-server/thread-catalog";
|
||||
import type { ModelMetadata } from "../../../domain/catalog/metadata";
|
||||
import type { ObservedResultListener } from "../../../domain/observed-result";
|
||||
import type { SharedServerMetadata } from "../../../domain/server/metadata";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { ModelMetadataClient } from "../../app-server/catalog";
|
||||
import type { AppServerClientHandlers } from "../../app-server/connection/client";
|
||||
import type { ModelMetadataClient } from "../../app-server/services/catalog";
|
||||
import {
|
||||
type EphemeralStructuredTurnClient,
|
||||
runEphemeralStructuredTurnForLastAgentText,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { type App, Notice, Platform, SuggestModal } from "obsidian";
|
||||
|
||||
import type { ThreadCatalogActiveReader } from "../../app-server/thread-catalog";
|
||||
import type { ThreadCatalogActiveReader } from "../../app-server/query/thread-catalog";
|
||||
import { type Thread, threadRecencyAt } from "../../domain/threads/model";
|
||||
import { threadDisplayTitle } from "../../domain/threads/title";
|
||||
import { shortThreadId } from "../../shared/id/thread-id";
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ import { Notice } from "obsidian";
|
|||
|
||||
import type { AppServerClientAccess } from "../../app-server/connection/client-access";
|
||||
import { isStaleAppServerSharedQueryContextError } from "../../app-server/query/shared-queries";
|
||||
import type { ThreadCatalogActiveReader, ThreadCatalogEventSink } from "../../app-server/query/thread-catalog";
|
||||
import type { ArchiveExportDestination } from "../../app-server/services/thread-archive-markdown";
|
||||
import type { ThreadCatalogActiveReader, ThreadCatalogEventSink } from "../../app-server/thread-catalog";
|
||||
import type { ReasoningEffort } from "../../domain/catalog/metadata";
|
||||
import type { ObservedResult } from "../../domain/observed-result";
|
||||
import { observedInitialError, observedInitialLoading, observedValue } from "../../domain/observed-result";
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import type { AppServerClientAccess } from "../../app-server/connection/client-access";
|
||||
import type { ThreadCatalogEventSink } from "../../app-server/query/thread-catalog";
|
||||
import { type ArchiveThreadResult, archiveThreadOnAppServer } from "../../app-server/services/thread-archive";
|
||||
import type { ArchiveExportDestination } from "../../app-server/services/thread-archive-markdown";
|
||||
import type { ThreadCatalogEventSink } from "../../app-server/thread-catalog";
|
||||
import type { ArchiveExportSettings } from "../../domain/threads/archive-markdown";
|
||||
import { normalizeExplicitThreadName } from "../../domain/threads/model";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { AppServerClientAccess } from "../../app-server/connection/client-access";
|
||||
import { generateThreadTitleWithCodex } from "../../app-server/services/thread-title-generation";
|
||||
import { readCompletedConversationSummariesPage } from "../../app-server/threads";
|
||||
import { readCompletedConversationSummariesPage } from "../../app-server/services/threads";
|
||||
import type { ReasoningEffort } from "../../domain/catalog/metadata";
|
||||
import {
|
||||
findThreadTitleContext,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import { withShortLivedAppServerClient } from "./app-server/connection/short-liv
|
|||
import { AppServerQueryCache } from "./app-server/query/cache";
|
||||
import { type AppServerQueryContext, appServerQueryContextIsComplete } from "./app-server/query/keys";
|
||||
import { AppServerSharedQueries } from "./app-server/query/shared-queries";
|
||||
import { createThreadCatalog, type ThreadCatalog, type ThreadCatalogEvent } from "./app-server/thread-catalog";
|
||||
import { createThreadCatalog, type ThreadCatalog, type ThreadCatalogEvent } from "./app-server/query/thread-catalog";
|
||||
import { VIEW_TYPE_CODEX_THREADS, VIEW_TYPE_CODEX_TURN_DIFF } from "./constants";
|
||||
import type { ChatTurnDiffViewState } from "./features/chat/domain/turn-diff";
|
||||
import { persistedChatTurnDiffViewState } from "./features/chat/domain/turn-diff";
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { type HookCatalog, listHookCatalog, setHookItemEnabled, trustHookItem } from "../app-server/catalog";
|
||||
import type { AppServerClient } from "../app-server/connection/client";
|
||||
import { isStaleAppServerSharedQueryContextError } from "../app-server/query/shared-queries";
|
||||
import { restoreArchivedThread as restoreArchivedThreadOnAppServer } from "../app-server/threads";
|
||||
import { type HookCatalog, listHookCatalog, setHookItemEnabled, trustHookItem } from "../app-server/services/catalog";
|
||||
import { restoreArchivedThread as restoreArchivedThreadOnAppServer } from "../app-server/services/threads";
|
||||
import type { HookItem, ModelMetadata, ReasoningEffort } from "../domain/catalog/metadata";
|
||||
import { findModelMetadataByIdOrName, sortedModelMetadata, supportedEffortsForModelMetadata } from "../domain/catalog/metadata";
|
||||
import type { ObservedResult } from "../domain/observed-result";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { AppServerClientAccess } from "../app-server/connection/client-access";
|
||||
import type { ThreadCatalogArchivedReader, ThreadCatalogEventSink } from "../app-server/thread-catalog";
|
||||
import type { ThreadCatalogArchivedReader, ThreadCatalogEventSink } from "../app-server/query/thread-catalog";
|
||||
import type { ModelMetadata } from "../domain/catalog/metadata";
|
||||
import type { ObservedResultListener } from "../domain/observed-result";
|
||||
import type { CodexPanelSettings } from "./model";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { describe, expect, it, vi } from "vitest";
|
||||
import { listHookCatalog, listSkillCatalog } from "../../src/app-server/catalog";
|
||||
import type { AppServerClient } from "../../src/app-server/connection/client";
|
||||
import {
|
||||
appServerHookOperationFromHookItem,
|
||||
|
|
@ -7,6 +6,7 @@ import {
|
|||
modelMetadataFromCatalogModels,
|
||||
skillMetadataFromCatalogSkills,
|
||||
} from "../../src/app-server/protocol/catalog";
|
||||
import { listHookCatalog, listSkillCatalog } from "../../src/app-server/services/catalog";
|
||||
import type { HookMetadata } from "../../src/generated/app-server/v2/HookMetadata";
|
||||
import type { Model } from "../../src/generated/app-server/v2/Model";
|
||||
import type { SkillMetadata } from "../../src/generated/app-server/v2/SkillMetadata";
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { threadActivationSnapshotFromAppServerResponse } from "../../src/app-server/threads";
|
||||
import { threadActivationSnapshotFromAppServerResponse } from "../../src/app-server/services/threads";
|
||||
import type { Thread as AppServerThread } from "../../src/generated/app-server/v2/Thread";
|
||||
import type { ThreadResumeResponse } from "../../src/generated/app-server/v2/ThreadResumeResponse";
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { describe, expect, it, type Mock, vi } from "vitest";
|
|||
|
||||
import { AppServerQueryCache } from "../../src/app-server/query/cache";
|
||||
import { AppServerSharedQueries } from "../../src/app-server/query/shared-queries";
|
||||
import { createThreadCatalog, type ThreadCatalogEventObserver } from "../../src/app-server/thread-catalog";
|
||||
import { createThreadCatalog, type ThreadCatalogEventObserver } from "../../src/app-server/query/thread-catalog";
|
||||
import type { Thread } from "../../src/domain/threads/model";
|
||||
|
||||
describe("ThreadCatalog", () => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
import type { AppServerClient } from "../../src/app-server/connection/client";
|
||||
import { listThreads } from "../../src/app-server/threads";
|
||||
import { listThreads } from "../../src/app-server/services/threads";
|
||||
|
||||
describe("app-server thread response adapters", () => {
|
||||
it("maps listed threads to domain threads with archive state", async () => {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { describe, expect, it, vi } from "vitest";
|
||||
|
||||
import type { AppServerClient } from "../../src/app-server/connection/client";
|
||||
import { readToolInventory } from "../../src/app-server/tool-inventory";
|
||||
import { readToolInventory } from "../../src/app-server/services/tool-inventory";
|
||||
|
||||
describe("tool inventory", () => {
|
||||
it("reads plugin details with exactly one marketplace locator", async () => {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { describe, expect, it, vi } from "vitest";
|
|||
import type { ServerNotification, ServerRequest } from "../../../../../src/app-server/connection/rpc-messages";
|
||||
import { appServerApprovalRequest, appServerUserInputRequest } from "../../../../../src/app-server/protocol/server-requests";
|
||||
import type { TurnRecord } from "../../../../../src/app-server/protocol/turn";
|
||||
import type { ThreadCatalogEvent } from "../../../../../src/app-server/thread-catalog";
|
||||
import type { ThreadCatalogEvent } from "../../../../../src/app-server/query/thread-catalog";
|
||||
import type { Thread as PanelThread } from "../../../../../src/domain/threads/model";
|
||||
import {
|
||||
type ChatInboundHandler,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { readFileSync } from "node:fs";
|
|||
import path from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import type { ServerNotification, ServerRequest } from "../../../../../src/app-server/connection/rpc-messages";
|
||||
import { routeServerRequest } from "../../../../../src/app-server/server-requests";
|
||||
import { routeServerRequest } from "../../../../../src/app-server/routing/server-requests";
|
||||
import { planChatNotification } from "../../../../../src/features/chat/app-server/inbound/notification-plan";
|
||||
import { routeServerNotification } from "../../../../../src/features/chat/app-server/inbound/notification-routing";
|
||||
import { chatStateFixture, chatStateWith } from "../../support/state";
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vite
|
|||
import type { ServerNotification } from "../../../../src/app-server/connection/rpc-messages";
|
||||
import { modelMetadataFromCatalogModels } from "../../../../src/app-server/protocol/catalog";
|
||||
import type { ThreadRecord } from "../../../../src/app-server/protocol/thread";
|
||||
import type { ThreadCatalogEvent } from "../../../../src/app-server/thread-catalog";
|
||||
import type { ThreadCatalogEvent } from "../../../../src/app-server/query/thread-catalog";
|
||||
import type { ModelMetadata } from "../../../../src/domain/catalog/metadata";
|
||||
import type { ObservedResult } from "../../../../src/domain/observed-result";
|
||||
import { emptyRuntimeConfigSnapshot } from "../../../../src/domain/runtime/config";
|
||||
|
|
|
|||
|
|
@ -16,6 +16,12 @@ const projectPluginByName = new Map(
|
|||
);
|
||||
const APP_SERVER_PROTOCOL_BOUNDARY_MESSAGE =
|
||||
"Source modules outside root src/app-server must use domain models and app-server services instead of app-server protocol modules. Chat turn-item conversion may consume turn protocol at its app-server boundary; feature state and UI must use Panel-owned models.";
|
||||
const APP_SERVER_ROOT_MODULE_FILE_MESSAGE =
|
||||
"Keep app-server modules in responsibility subfolders; src/app-server root must not accumulate boundary adapters.";
|
||||
const APP_SERVER_ROOT_MODULE_IMPORT_MESSAGE =
|
||||
"Import app-server boundary modules from responsibility subfolders, not src/app-server root modules.";
|
||||
const APP_SERVER_SUBFOLDER_ROOT_IMPORT_MESSAGE =
|
||||
"App-server subfolders must not import sibling root modules; move the dependency into a responsibility subfolder.";
|
||||
const CHAT_APPLICATION_OUTER_LAYER_MESSAGE =
|
||||
"Chat application modules must not import app-server, host, panel, presentation, or UI layers; expose state and workflow contracts instead.";
|
||||
const CHAT_APP_SERVER_OUTER_LAYER_MESSAGE = "Chat app-server adapters must not import chat host, panel, presentation, or UI layers.";
|
||||
|
|
@ -705,13 +711,70 @@ export const value = statusText;
|
|||
]);
|
||||
});
|
||||
|
||||
it("keeps app-server root from becoming a boundary escape hatch", async () => {
|
||||
const cwd = await tempBiomeWorkspace([
|
||||
"no-app-server-root-module-files.grit",
|
||||
"no-app-server-root-module-imports.grit",
|
||||
"no-app-server-subfolder-root-imports.grit",
|
||||
]);
|
||||
await writeFile(
|
||||
path.join(cwd, "src/app-server/escape.ts"),
|
||||
`
|
||||
import type { AppServerClient } from "./connection/client";
|
||||
|
||||
export type Escape = AppServerClient;
|
||||
`.trimStart(),
|
||||
);
|
||||
await writeFile(
|
||||
path.join(cwd, "src/features/chat/app-server/root-import.ts"),
|
||||
`
|
||||
import { listThreads } from "../../../../app-server/threads";
|
||||
|
||||
export const read = listThreads;
|
||||
`.trimStart(),
|
||||
);
|
||||
await writeFile(
|
||||
path.join(cwd, "src/app-server/services/root-import.ts"),
|
||||
`
|
||||
import { listThreads } from "../threads";
|
||||
|
||||
export const read = listThreads;
|
||||
`.trimStart(),
|
||||
);
|
||||
await writeFile(
|
||||
path.join(cwd, "src/app-server/services/allowed.ts"),
|
||||
`
|
||||
import type { AppServerClient } from "../connection/client";
|
||||
import { listThreads } from "./threads";
|
||||
|
||||
export type Allowed = AppServerClient;
|
||||
export const read = listThreads;
|
||||
`.trimStart(),
|
||||
);
|
||||
|
||||
const report = biomeLint(
|
||||
[
|
||||
"src/app-server/escape.ts",
|
||||
"src/features/chat/app-server/root-import.ts",
|
||||
"src/app-server/services/root-import.ts",
|
||||
"src/app-server/services/allowed.ts",
|
||||
],
|
||||
cwd,
|
||||
);
|
||||
|
||||
expect(pluginMessages(report, "src/app-server/escape.ts")).toEqual([APP_SERVER_ROOT_MODULE_FILE_MESSAGE]);
|
||||
expect(pluginMessages(report, "src/features/chat/app-server/root-import.ts")).toEqual([APP_SERVER_ROOT_MODULE_IMPORT_MESSAGE]);
|
||||
expect(pluginMessages(report, "src/app-server/services/root-import.ts")).toEqual([APP_SERVER_SUBFOLDER_ROOT_IMPORT_MESSAGE]);
|
||||
expect(pluginDiagnostics(report, "src/app-server/services/allowed.ts")).toEqual([]);
|
||||
});
|
||||
|
||||
it("keeps chat application app-server projection RPCs behind facades", async () => {
|
||||
const report = await appServerBoundaryPolicyReport();
|
||||
|
||||
expect(pluginMessages(report, "src/features/chat/application/threads/history.ts")).toEqual([
|
||||
"Keep app-server projection RPCs behind app-server facades; consume Panel-owned snapshots or view models here.",
|
||||
]);
|
||||
expect(pluginDiagnostics(report, "src/app-server/threads.ts")).toEqual([]);
|
||||
expect(pluginDiagnostics(report, "src/app-server/services/threads.ts")).toEqual([]);
|
||||
expect(pluginDiagnostics(report, "src/features/chat/host/connection-bundle.ts")).toEqual([]);
|
||||
});
|
||||
|
||||
|
|
@ -999,7 +1062,7 @@ export const response = [appServerUserInputResponse, runtimeMetrics] satisfies u
|
|||
await writeFile(
|
||||
path.join(cwd, "src/domain/threads/model.ts"),
|
||||
`
|
||||
import { listThreads } from "../../app-server/threads";
|
||||
import { listThreads } from "../../app-server/services/threads";
|
||||
import type { ThreadPickerModal } from "../../features/thread-picker/modal";
|
||||
import { copyText } from "../../shared/ui/clipboard";
|
||||
import type { App } from "obsidian";
|
||||
|
|
@ -1117,9 +1180,9 @@ export async function read(appServerClient: AppServerClient): Promise<void> {
|
|||
`.trimStart(),
|
||||
);
|
||||
await writeFile(
|
||||
path.join(cwd, "src/app-server/threads.ts"),
|
||||
path.join(cwd, "src/app-server/services/threads.ts"),
|
||||
`
|
||||
import type { AppServerClient } from "./connection/client";
|
||||
import type { AppServerClient } from "../connection/client";
|
||||
|
||||
export async function read(client: AppServerClient): Promise<void> {
|
||||
await client.threadTurnsList("thread", null, 20);
|
||||
|
|
@ -1165,7 +1228,7 @@ export type AppServerThreadResumeClient = Pick<AppServerClient, "resumeThread">;
|
|||
"src/domain/connection-client.ts",
|
||||
"src/shared/connection-client.ts",
|
||||
"src/features/chat/application/threads/history.ts",
|
||||
"src/app-server/threads.ts",
|
||||
"src/app-server/services/threads.ts",
|
||||
"src/features/chat/host/connection-bundle.ts",
|
||||
],
|
||||
cwd,
|
||||
|
|
|
|||
Loading…
Reference in a new issue