Rehome shared modules by ownership boundary

This commit is contained in:
murashit 2026-06-30 23:47:59 +09:00
parent 4ed285cedd
commit 5a1d55de22
130 changed files with 306 additions and 345 deletions

View file

@ -9,43 +9,30 @@
// Project-wide source shape and placement.
{
"path": "./scripts/grit/source-shape/no-handwritten-reexports.grit",
"includes": ["**/*.ts", "**/*.tsx", "**/*.mjs"]
"includes": ["**/*.{ts,tsx,mjs}"]
},
{
"path": "./scripts/grit/source-shape/no-responsibility-root-module-files.grit",
"includes": [
"**/src/app-server/*.ts",
"**/src/app-server/*.tsx",
"**/src/domain/*.ts",
"**/src/domain/*.tsx",
"**/src/features/chat/*.ts",
"**/src/features/chat/*.tsx",
"**/src/features/threads/*.ts",
"**/src/features/threads/*.tsx",
"**/src/shared/*.ts",
"**/src/shared/*.tsx"
]
"includes": ["**/src/{app-server,domain}/*.{ts,tsx}", "**/src/features/{chat,threads}/*.{ts,tsx}"]
},
{
"path": "./scripts/grit/source-shape/no-misplaced-tsx.grit",
"includes": [
"**/src/**/*.tsx",
"!**/src/features/chat/panel/**",
"!**/src/features/chat/ui/**",
"!**/src/features/selection-rewrite/*.dom.tsx",
"!**/src/features/turn-diff/*.dom.tsx",
"!**/src/features/threads-view/*.dom.tsx",
"!**/src/settings/**",
"!**/src/shared/ui/**"
"!**/src/{settings,shared/ui}/**",
"!**/src/features/chat/{panel,ui}/**",
"!**/src/features/{selection-rewrite,threads-view,turn-diff}/*.dom.tsx",
"!**/src/shared/dom/*.dom.tsx",
"!**/src/shared/obsidian/*.obsidian.tsx"
]
},
{
"path": "./scripts/grit/source-shape/no-self-referential-initializer-callback.grit",
"includes": ["**/*.ts", "**/*.tsx", "**/*.mjs"]
"includes": ["**/*.{ts,tsx,mjs}"]
},
{
"path": "./scripts/grit/source-shape/no-unsafe-iterator-value.grit",
"includes": ["**/*.ts", "**/*.tsx", "**/*.mjs"]
"includes": ["**/*.{ts,tsx,mjs}"]
},
{
"path": "./scripts/grit/source-shape/no-uncontrolled-preact-form-state.grit",
@ -59,7 +46,7 @@
},
{
"path": "./scripts/grit/import-boundaries/no-lower-level-feature-imports.grit",
"includes": ["**/src/app-server/**/*.ts", "**/src/shared/**/*.ts", "**/src/shared/**/*.tsx"]
"includes": ["**/src/app-server/**/*.ts", "**/src/shared/**/*.{ts,tsx}"]
},
// App-server and generated protocol boundaries.
@ -69,17 +56,16 @@
},
{
"path": "./scripts/grit/import-boundaries/no-app-server-connection-boundary-imports.grit",
"includes": ["**/src/app-server/protocol/**/*.ts", "**/src/domain/**/*.ts", "**/src/shared/**/*.ts", "**/src/shared/**/*.tsx"]
"includes": ["**/src/app-server/protocol/**/*.ts", "**/src/domain/**/*.ts", "**/src/shared/**/*.{ts,tsx}"]
},
{
"path": "./scripts/grit/import-boundaries/no-app-server-protocol-boundary-imports.grit",
"includes": ["**/src/**/*.ts", "**/src/**/*.tsx", "!**/src/app-server/**"]
"includes": ["**/src/**/*.{ts,tsx}", "!**/src/app-server/**"]
},
{
"path": "./scripts/grit/import-boundaries/no-generated-app-server-boundary-imports.grit",
"includes": [
"**/src/**/*.ts",
"**/src/**/*.tsx",
"**/src/**/*.{ts,tsx}",
"!**/src/app-server/connection/**",
"!**/src/app-server/protocol/server-requests.ts",
"!**/src/app-server/protocol/turn.ts"
@ -87,16 +73,16 @@
},
{
"path": "./scripts/grit/runtime/no-app-server-direct-rpcs.grit",
"includes": ["**/src/**/*.ts", "**/src/**/*.tsx", "!**/src/app-server/**", "!**/src/features/chat/app-server/**"]
"includes": ["**/src/**/*.{ts,tsx}", "!**/src/app-server/**", "!**/src/features/chat/app-server/**"]
},
// Workspace and feature coordination boundaries.
{
"path": "./scripts/grit/import-boundaries/no-chat-workspace-boundary-imports.grit",
"includes": ["**/src/features/chat/**/*.ts", "**/src/features/chat/**/*.tsx"]
"includes": ["**/src/features/chat/**/*.{ts,tsx}"]
},
{
"path": "./scripts/grit/import-boundaries/no-feature-workspace-boundary-imports.grit",
"includes": ["**/src/features/**/*.ts", "**/src/features/**/*.tsx", "!**/src/features/chat/**"]
"includes": ["**/src/features/**/*.{ts,tsx}", "!**/src/features/chat/**"]
},
{
"path": "./scripts/grit/import-boundaries/no-workspace-chat-internal-imports.grit",
@ -118,7 +104,7 @@
},
{
"path": "./scripts/grit/import-boundaries/no-chat-panel-runtime-boundary-imports.grit",
"includes": ["**/src/features/chat/panel/**/*.ts", "**/src/features/chat/panel/**/*.tsx"]
"includes": ["**/src/features/chat/panel/**/*.{ts,tsx}"]
},
{
"path": "./scripts/grit/import-boundaries/no-chat-presentation-outer-layer-imports.grit",
@ -126,40 +112,34 @@
},
{
"path": "./scripts/grit/import-boundaries/no-chat-ui-outer-layer-imports.grit",
"includes": ["**/src/features/chat/ui/**/*.ts", "**/src/features/chat/ui/**/*.tsx"]
"includes": ["**/src/features/chat/ui/**/*.{ts,tsx}"]
},
// Chat state and runtime ownership.
{
"path": "./scripts/grit/import-boundaries/no-preact-signal-imports.grit",
"includes": [
"**/src/**/*.ts",
"**/src/**/*.tsx",
"**/src/**/*.{ts,tsx}",
"!**/src/features/chat/panel/shell-read-model.ts",
"!**/src/features/chat/panel/surface/**/*.ts",
"!**/src/features/chat/panel/surface/**/*.tsx"
"!**/src/features/chat/panel/surface/**/*.{ts,tsx}"
]
},
{
"path": "./scripts/grit/import-boundaries/no-chat-shell-read-model-imports.grit",
"includes": [
"**/src/features/chat/**/*.ts",
"**/src/features/chat/**/*.tsx",
"**/src/features/chat/**/*.{ts,tsx}",
"!**/src/features/chat/panel/shell-read-model.ts",
"!**/src/features/chat/panel/shell.dom.tsx",
"!**/src/features/chat/panel/composer-controller.ts",
"!**/src/features/chat/panel/surface/**/*.ts",
"!**/src/features/chat/panel/surface/**/*.tsx"
"!**/src/features/chat/panel/surface/**/*.{ts,tsx}"
]
},
{
"path": "./scripts/grit/import-boundaries/no-chat-signal-type-references.grit",
"includes": [
"**/src/features/chat/**/*.ts",
"**/src/features/chat/**/*.tsx",
"**/src/features/chat/**/*.{ts,tsx}",
"!**/src/features/chat/panel/shell-read-model.ts",
"!**/src/features/chat/panel/surface/**/*.ts",
"!**/src/features/chat/panel/surface/**/*.tsx"
"!**/src/features/chat/panel/surface/**/*.{ts,tsx}"
]
},
{
@ -170,40 +150,15 @@
// DOM bridge and Preact root boundaries.
{
"path": "./scripts/grit/dom/no-implicit-dom-bridges.grit",
"includes": [
"**/src/**/*.ts",
"**/src/**/*.tsx",
"!**/src/**/*.dom.ts",
"!**/src/**/*.dom.tsx",
"!**/src/**/*.obsidian.ts",
"!**/src/**/*.obsidian.tsx",
"!**/src/**/*.measure.ts",
"!**/src/**/*.measure.tsx"
]
"includes": ["**/src/**/*.{ts,tsx}", "!**/src/**/*.{dom,obsidian,measure}.{ts,tsx}"]
},
{
"path": "./scripts/grit/dom/no-dom-events-imports.grit",
"includes": [
"**/src/**/*.ts",
"**/src/**/*.tsx",
"!**/src/**/*.dom.ts",
"!**/src/**/*.dom.tsx",
"!**/src/**/*.obsidian.ts",
"!**/src/**/*.obsidian.tsx",
"!**/src/**/*.measure.ts",
"!**/src/**/*.measure.tsx"
]
"includes": ["**/src/**/*.{ts,tsx}", "!**/src/**/*.{dom,obsidian,measure}.{ts,tsx}"]
},
{
"path": "./scripts/grit/dom/no-ui-root-imports.grit",
"includes": [
"**/src/**/*.ts",
"**/src/**/*.tsx",
"!**/src/**/*.dom.ts",
"!**/src/**/*.dom.tsx",
"!**/src/**/*.obsidian.ts",
"!**/src/**/*.obsidian.tsx"
]
"path": "./scripts/grit/dom/no-preact-root-imports.grit",
"includes": ["**/src/**/*.{ts,tsx}", "!**/src/**/*.{dom,obsidian}.{ts,tsx}"]
},
// CSS source policy.

View file

@ -31,17 +31,15 @@ npm run check
The generation script uses `codex app-server generate-ts --experimental` because the panel depends on experimental app-server fields. Do not hand-edit generated bindings.
## Source Layout
## Placement Rules
The source tree is organized by implementation ownership, not by the single Obsidian plugin entrypoint. Put behavior where its reason to change lives: app-server protocol adaptation at the app-server boundary, app-server-independent domain models in domain code, feature-neutral helpers in shared code, feature workflows under their owning feature, and Obsidian lifecycle or workspace wiring at Obsidian-facing boundaries.
The source tree is organized by implementation ownership, not by the single Obsidian plugin entrypoint. Put behavior where its reason to change lives: app-server protocol adaptation at the app-server boundary, app-server-independent domain models in domain code, cross-feature reusable adapters and primitives under `src/shared/`, and feature workflows under their owning feature. Keep shared subfolders named by the boundary or primitive they own, such as DOM, Obsidian, runtime, or UI rendering.
Within chat, keep state transitions and workflow orchestration separate from app-server adaptation, session/Obsidian wiring, and rendering surfaces. Tests should mirror the ownership boundary of the code under test.
## Placement Rules
Keep new code near the state or API it owns. A feature may import another feature only for a capability that feature owns. When moving behavior across an ownership boundary or adding a new shared classification, update the lint policy and its tests with that boundary in the same change.
Keep new code near the state or API it owns. A feature may import another feature only for a capability that feature owns. Move feature-neutral helpers to `src/shared/`, panel-wide domain models to `src/domain/`, and app-server protocol adaptation to `src/app-server/`.
Generated app-server types should stay behind app-server connection and protocol adapter modules. If domain, shared, settings, workspace, or UI code needs app-server data, add or reuse a panel-owned projection at the boundary instead of importing generated payload types directly.
Generated app-server types should stay behind app-server connection and protocol adapter modules. If domain, shared code, settings, workspace, or feature code needs app-server data, add or reuse a panel-owned projection at the boundary instead of importing generated payload types directly.
Chat application workflows should receive chat-owned contracts, not root `src/app-server/` modules or direct `AppServerClient` access. Keep app-server access, connection freshness checks, vault-path injection, and payload projection in `src/features/chat/app-server/` transports or host-owned wiring.
@ -53,7 +51,7 @@ Chat modules should not import `src/workspace/` directly; workspace operations e
Use DOM reads, writes, measurements, hit-tests, focus/selection operations, and DOM event listener wiring only from explicit bridge modules, Obsidian-owned API boundaries, or rendering and measurement code that cannot be expressed cleanly as Preact components. Normal modules may keep refs and call named adapters, but they should not interpret DOM structure or layout directly. Name bridge files with a `.dom`, `.obsidian`, or `.measure` suffix.
Use `.tsx` only in rendering-owned source folders: chat panel and UI modules, Obsidian/settings surfaces, shared UI components, and explicit `.dom.tsx` rendering boundaries such as the selection rewrite popover and threads view shell. Non-rendering source should use `.ts`.
Use `.tsx` only where the module owns rendering or a host rendering bridge. Non-rendering source should use `.ts`; when a new rendering-owned location is intentional, update the source-shape lint policy and its tests rather than relying on convention alone.
## CSS Rules

View file

@ -8,6 +8,6 @@ private pattern js_module_reference() {
}
js_module_reference() as $stmt where {
$stmt <: contains `$source` where { $source <: r"^[\"'].*shared/ui/dom-events\.dom[\"']$" },
$stmt <: contains `$source` where { $source <: r"^[\"'].*shared/dom/events\.dom[\"']$" },
register_diagnostic(span=$stmt, message="Import DOM event listener helpers only from explicit .dom, .obsidian, or .measure bridge files.", severity="error")
}

View file

@ -8,6 +8,6 @@ private pattern js_module_reference() {
}
js_module_reference() as $stmt where {
$stmt <: contains `$source` where { $source <: r"^[\"'].*shared/ui/ui-root\.dom[\"']$" },
$stmt <: contains `$source` where { $source <: r"^[\"'].*shared/dom/preact-root\.dom[\"']$" },
register_diagnostic(span=$stmt, message="Import the Preact root adapter only from explicit root bridge files.", severity="error")
}

View file

@ -9,8 +9,8 @@ private pattern js_module_reference() {
private pattern root_outer_layer_source() {
or {
r"^[\"'](?:\.\./)+(?:app-server|settings|workspace|shared/ui|features)(?:/.*)?[\"']$",
r"^[\"']src/(?:app-server|settings|workspace|shared/ui|features)(?:/.*)?[\"']$",
r"^[\"'](?:\.\./)+(?:app-server|settings|workspace|shared|features)(?:/.*)?[\"']$",
r"^[\"']src/(?:app-server|settings|workspace|shared|features)(?:/.*)?[\"']$",
r"^[\"']obsidian[\"']$"
}
}

View file

@ -9,5 +9,5 @@ private pattern js_module_reference() {
js_module_reference() as $stmt where {
$stmt <: contains `$source` where { $source <: r"^[\"'](?:(?:\.\./)+features|src/features)(?:/.*)?[\"']$" },
register_diagnostic(span=$stmt, message="Do not import feature modules from this layer. Move shared behavior to shared, domain, or app-server adapters.", severity="error")
register_diagnostic(span=$stmt, message="Do not import feature modules from this layer. Move reusable behavior to domain, shared DOM/Obsidian/runtime/UI, or app-server adapters.", severity="error")
}

View file

@ -1,3 +1,4 @@
import { jsonPreview } from "../../domain/display/json-preview";
import type {
ApprovalAction,
ApprovalActionIntent,
@ -12,9 +13,8 @@ import type {
PendingUserInput,
PendingUserInputQuestion,
} from "../../domain/pending-requests/model";
import { pathRelativeToRoot } from "../../domain/vault/paths";
import type { ServerRequest as GeneratedServerRequest } from "../../generated/app-server/ServerRequest";
import { pathRelativeToRoot } from "../../shared/path/file-paths";
import { jsonPreview } from "../../shared/text/preview";
interface AppServerGrantedPermissionProfile {
network?: unknown;

View file

@ -3,7 +3,6 @@ import type { ModelMetadata } from "../../domain/catalog/metadata";
import { createServerDiagnostics, diagnosticProbeError, diagnosticProbeOk, diagnosticsWithProbe } from "../../domain/server/diagnostics";
import type { SharedServerMetadata } from "../../domain/server/metadata";
import type { Thread } from "../../domain/threads/model";
import type { ObservedResult, ObservedResultListener } from "../../shared/query/observed-result";
import type { AppServerClient } from "../connection/client";
import type { AppServerClientAccessOptions } from "../connection/client-access";
import { runtimeConfigSnapshotFromAppServerConfig } from "../protocol/runtime-config";
@ -21,6 +20,7 @@ import {
cloneAppServerQueryContext,
} from "./keys";
import { readRateLimitMetadataProbe, readSkillMetadataProbe } from "./metadata-probes";
import type { ObservedResult, ObservedResultListener } from "./observed-result";
import { cloneModelMetadata, cloneSharedServerMetadata, cloneThreads } from "./snapshots";
const THREAD_LIST_STALE_TIME_MS = 10_000;

View file

@ -1,7 +1,6 @@
import type { ModelMetadata } from "../../domain/catalog/metadata";
import type { SharedServerMetadata } from "../../domain/server/metadata";
import type { Thread } from "../../domain/threads/model";
import type { ObservedResultListener } from "../../shared/query/observed-result";
import type { AppServerQueryCache } from "./cache";
import {
type AppServerQueryContext,
@ -9,6 +8,7 @@ import {
appServerQueryContextRawEquals,
cloneAppServerQueryContext,
} from "./keys";
import type { ObservedResultListener } from "./observed-result";
export interface AppServerSharedQueriesOptions {
cache: AppServerQueryCache;

View file

@ -1,4 +1,4 @@
import { listenAbortSignal } from "../../shared/lifecycle/abort-signal";
import { listenAbortSignal } from "../../shared/runtime/abort-signal";
import { AppServerClient, type AppServerClientHandlers } from "../connection/client";
import type { AppServerClientRequestPolicy } from "../connection/client-access";
import type { ServerNotification } from "../connection/rpc-messages";

View file

@ -0,0 +1,7 @@
export function jsonPreview(value: unknown): string {
try {
return JSON.stringify(value, null, 2);
} catch {
return String(value);
}
}

View file

@ -1,11 +1,3 @@
export function truncate(value: string, maxLength: number): string {
return value.length > maxLength ? `${value.slice(0, maxLength - 1)}...` : value;
}
export function jsonPreview(value: unknown): string {
try {
return JSON.stringify(value, null, 2);
} catch {
return String(value);
}
}

View file

@ -1,11 +1,5 @@
import {
isExternalFileHref,
isFilesystemAbsolutePath,
isVaultConfigPath,
normalizeFilePath,
parseFileHref,
vaultRelativePath,
} from "../../shared/path/file-paths";
import { isExternalFileHref, parseFileHref } from "../vault/file-hrefs";
import { isFilesystemAbsolutePath, isVaultConfigPath, normalizeFilePath, vaultRelativePath } from "../vault/paths";
import type { Thread } from "./model";
import { referencedThreadMetadataFromPrompt } from "./reference";
import { threadArchiveTitle } from "./title";

View file

@ -1,4 +1,4 @@
import { truncate } from "../../shared/text/preview";
import { truncate } from "../display/text-preview";
import type { ThreadConversationSummary } from "./transcript";
const THREAD_TITLE_CONTEXT_MAX_CHARS = 4_000;

View file

@ -1,4 +1,4 @@
import { shortThreadId } from "../../shared/id/thread-id";
import { shortThreadId } from "./id";
import type { Thread } from "./model";
const MAX_ARCHIVED_THREAD_DISPLAY_TITLE_LENGTH = 96;

View file

@ -0,0 +1,56 @@
import { isFilesystemAbsolutePath, isVaultConfigPath, normalizeFilePath, vaultRelativePath } from "./paths";
export interface ParsedFileHref {
path: string;
subpath: string;
}
export function parseFileHref(href: string): ParsedFileHref | null {
const trimmed = href.trim();
if (!trimmed || isExternalFileHref(trimmed)) return null;
const fragmentIndex = trimmed.indexOf("#");
const withoutFragment = fragmentIndex === -1 ? trimmed : trimmed.slice(0, fragmentIndex);
if (!withoutFragment) return null;
const decoded = decodeFileHref(withoutFragment);
const path = decoded.replace(/:(\d+)(?::\d+)?$/, "");
const subpath = fragmentIndex === -1 ? "" : decodeFileHref(trimmed.slice(fragmentIndex));
return path ? { path, subpath } : null;
}
export function isExternalFileHref(href: string): boolean {
if (/^[a-z]:[\\/]/i.test(href)) return false;
return /^[a-z][a-z\d+.-]*:/i.test(href) || href.startsWith("//");
}
export function vaultRelativeFileLinkTarget(vaultPath: string, configDir: string, href: string): string | null {
const relativePath = vaultRelativeFileHref(vaultPath, configDir, href);
return relativePath ? `${relativePath.path}${relativePath.subpath}` : null;
}
export function isAbsoluteFileHref(href: string): boolean {
const parsed = parseFileHref(href);
return parsed ? isFilesystemAbsolutePath(normalizeFilePath(parsed.path)) : false;
}
export function vaultRelativeFileHref(vaultPath: string, configDir: string, href: string): { path: string; subpath: string } | null {
const parsed = parseFileHref(href);
if (!parsed) return null;
const relativePath = vaultRelativePath(vaultPath, parsed.path, { allowRelative: true });
if (!relativePath) return null;
const normalized = normalizeFilePath(relativePath);
if (isVaultConfigPath(normalized, configDir)) return null;
return { path: normalized, subpath: parsed.subpath };
}
function decodeFileHref(href: string): string {
try {
return decodeURI(href);
} catch {
return href;
}
}

View file

@ -1,31 +1,7 @@
export interface ParsedFileHref {
path: string;
subpath: string;
}
export interface VaultRelativePathOptions {
allowRelative?: boolean;
}
export function parseFileHref(href: string): ParsedFileHref | null {
const trimmed = href.trim();
if (!trimmed || isExternalFileHref(trimmed)) return null;
const fragmentIndex = trimmed.indexOf("#");
const withoutFragment = fragmentIndex === -1 ? trimmed : trimmed.slice(0, fragmentIndex);
if (!withoutFragment) return null;
const decoded = decodeFileHref(withoutFragment);
const path = decoded.replace(/:(\d+)(?::\d+)?$/, "");
const subpath = fragmentIndex === -1 ? "" : decodeFileHref(trimmed.slice(fragmentIndex));
return path ? { path, subpath } : null;
}
export function isExternalFileHref(href: string): boolean {
if (isWindowsAbsolutePath(href)) return false;
return /^[a-z][a-z\d+.-]*:/i.test(href) || href.startsWith("//");
}
export function vaultRelativePath(vaultPath: string, path: string, options: VaultRelativePathOptions = {}): string | null {
const normalizedPath = normalizeFilePath(path);
const normalizedVaultPath = normalizeFilePath(vaultPath);
@ -61,14 +37,6 @@ export function normalizeFilePath(path: string): string {
return normalized.replace(/^\.\//, "");
}
function decodeFileHref(href: string): string {
try {
return decodeURI(href);
} catch {
return href;
}
}
function isWindowsAbsolutePath(path: string): boolean {
return /^[a-z]:[\\/]/i.test(path);
}

View file

@ -14,9 +14,9 @@ import {
type PendingUserInput,
} from "../../../../domain/pending-requests/model";
import type { ThreadConversationSummary } from "../../../../domain/threads/transcript";
import type { LocalIdSource } from "../../../../shared/id/local-id";
import type { ThreadCatalogEvent } from "../../../threads/catalog/thread-catalog";
import { activeTurnId } from "../../application/conversation/turn-state";
import type { LocalIdSource } from "../../application/local-id-source";
import type { ChatAction, ChatState } from "../../application/state/root-reducer";
import type { ChatStateStore } from "../../application/state/store";
import { createStructuredSystemItem, createSystemItem } from "../../domain/message-stream/factories/system-items";

View file

@ -1,9 +1,9 @@
import type { ServerNotification } from "../../../../app-server/connection/rpc-messages";
import { threadFromAppServerRecord } from "../../../../app-server/services/threads";
import { jsonPreview } from "../../../../domain/display/json-preview";
import { threadTokenUsageFromRuntimeUsage } from "../../../../domain/runtime/metrics";
import { normalizeExplicitThreadName } from "../../../../domain/threads/model";
import type { ThreadConversationSummary } from "../../../../domain/threads/transcript";
import { jsonPreview } from "../../../../shared/text/preview";
import type { ThreadCatalogEvent } from "../../../threads/catalog/thread-catalog";
import { activeTurnId, pendingTurnStart as pendingTurnStartForState } from "../../application/conversation/turn-state";
import { activeThreadSettingsAppliedAction } from "../../application/state/actions";

View file

@ -1,4 +1,4 @@
import { pathRelativeToRoot } from "../../../../../shared/path/file-paths";
import { pathRelativeToRoot } from "../../../../../domain/vault/paths";
import { permissionRows } from "../../../domain/message-stream/format/permission-rows";
import type { ExecutionState, MessageStreamAuditFact, MessageStreamItem } from "../../../domain/message-stream/items";
import { type ExecutionStateByStatus, executionStateFromStatus, RUNNING_EXECUTION_STATE } from "./execution-state";

View file

@ -4,10 +4,10 @@ import {
type TurnRecord,
turnUserItemText,
} from "../../../../../app-server/protocol/turn";
import { jsonPreview } from "../../../../../domain/display/json-preview";
import type { HistoricalTurn } from "../../../../../domain/threads/history";
import { referencedThreadMetadataFromPrompt } from "../../../../../domain/threads/reference";
import type { ThreadConversationSummary } from "../../../../../domain/threads/transcript";
import { jsonPreview } from "../../../../../shared/text/preview";
import { fileMentionsFromInput } from "../../../domain/message-stream/format/file-mentions";
import { normalizeProposedPlanMarkdown } from "../../../domain/message-stream/format/proposed-plan";
import { userMessageDisplayText } from "../../../domain/message-stream/format/user-message-text";

View file

@ -1,8 +1,8 @@
import { readReferencedThreadConversationSummaries, type ThreadConversationSummaryClient } from "../../../app-server/services/threads";
import { type CodexInput, codexTextInputWithAttachments } from "../../../domain/chat/input";
import { shortThreadId } from "../../../domain/threads/id";
import type { Thread } from "../../../domain/threads/model";
import { REFERENCED_THREAD_TURN_LIMIT, referencedThreadPromptBundle } from "../../../domain/threads/reference";
import { shortThreadId } from "../../../shared/id/thread-id";
import type { ThreadReferenceInput } from "../application/conversation/slash-command-execution";
interface ThreadReferenceResolverHost {

View file

@ -1,9 +1,9 @@
import { prepareFuzzySearch, type SearchResult, sortSearchResults } from "obsidian";
import type { ModelMetadata, SkillMetadata } from "../../../../domain/catalog/metadata";
import { findModelMetadataByIdOrName, sortedModelMetadata, supportedEffortsForModelMetadata } from "../../../../domain/catalog/metadata";
import { shortThreadId } from "../../../../domain/threads/id";
import type { Thread } from "../../../../domain/threads/model";
import { threadDisplayTitle } from "../../../../domain/threads/title";
import { shortThreadId } from "../../../../shared/id/thread-id";
import {
type ActiveNoteContextReference,
activeNoteContextReferenceMarker,

View file

@ -1,7 +1,7 @@
import type { ServerInitialization } from "../../../../domain/server/initialization";
import type { ActiveConnectionWork, ConnectionWorkTracker } from "../../../../shared/lifecycle/connection-work";
import type { ChatConnectionPhase } from "../state/root-reducer";
import type { ChatStateStore } from "../state/store";
import type { ActiveConnectionWork, ConnectionWorkTracker } from "./connection-work";
const STATUS_CONNECTION_STOPPED = "Codex app-server stopped.";
const STATUS_CONNECTION_STARTING = "Starting Codex app-server...";

View file

@ -1,7 +1,7 @@
import type { CodexInput } from "../../../../domain/chat/input";
import type { Thread } from "../../../../domain/threads/model";
import type { LocalIdSource } from "../../../../shared/id/local-id";
import type { MessageStreamNoticeSection } from "../../domain/message-stream/items";
import type { LocalIdSource } from "../local-id-source";
import type { ChatRuntimeSettingsActions } from "../runtime/settings-actions";
import type { ChatStateStore } from "../state/store";
import type { GoalActions } from "../threads/goal-actions";

View file

@ -2,10 +2,10 @@ import type { ReasoningEffort } from "../../../../domain/catalog/metadata";
import { normalizeReasoningEffort } from "../../../../domain/catalog/metadata";
import type { CodexInput } from "../../../../domain/chat/input";
import type { ThreadGoal } from "../../../../domain/threads/goal";
import { shortThreadId } from "../../../../domain/threads/id";
import type { Thread } from "../../../../domain/threads/model";
import type { ReferencedThreadMetadata } from "../../../../domain/threads/reference";
import { threadDisplayTitle } from "../../../../domain/threads/title";
import { shortThreadId } from "../../../../shared/id/thread-id";
import type { MessageStreamAuditFact, MessageStreamNoticeSection } from "../../domain/message-stream/items";
import { modelOverrideMessage, reasoningEffortOverrideMessage } from "../../domain/runtime/labels";
import {

View file

@ -1,6 +1,6 @@
import type { CodexInput } from "../../../../domain/chat/input";
import type { ReferencedThreadMetadata } from "../../../../domain/threads/reference";
import type { LocalIdSource } from "../../../../shared/id/local-id";
import type { LocalIdSource } from "../local-id-source";
import type { ChatStateStore } from "../state/store";
import {
acknowledgeOptimisticTurnStart,

View file

@ -1,7 +1,7 @@
import type { ThreadGoal, ThreadGoalStatus, ThreadGoalUpdate } from "../../../../domain/threads/goal";
import type { LocalIdSource } from "../../../../shared/id/local-id";
import { goalChangeItem } from "../../domain/message-stream/factories/goal-items";
import type { GoalMessageStreamItem } from "../../domain/message-stream/items";
import type { LocalIdSource } from "../local-id-source";
import type { ChatStateStore } from "../state/store";
import type { ThreadGoalReadTransport, ThreadGoalTransport } from "./goal-transport";

View file

@ -1,5 +1,5 @@
import { truncate } from "../../../../../domain/display/text-preview";
import type { ThreadGoal, ThreadGoalStatus } from "../../../../../domain/threads/goal";
import { truncate } from "../../../../../shared/text/preview";
import type { GoalMessageStreamItem } from "../items";
const GOAL_SUMMARY_LIMIT = 140;

View file

@ -1,4 +1,4 @@
import { jsonPreview } from "../../../../../shared/text/preview";
import { jsonPreview } from "../../../../../domain/display/json-preview";
interface DetailRow {
key: string;

View file

@ -1,4 +1,4 @@
import { truncate } from "../../../../../shared/text/preview";
import { truncate } from "../../../../../domain/display/text-preview";
import type {
AgentRunSummary,
AgentRunSummaryAgent,

View file

@ -3,8 +3,6 @@ import { Notice } from "obsidian";
import type { AppServerClient } from "../../../../app-server/connection/client";
import { type ConnectionManager, StaleConnectionError } from "../../../../app-server/connection/connection-manager";
import { isStaleAppServerSharedQueryContextError } from "../../../../app-server/query/shared-queries";
import type { LocalIdSource } from "../../../../shared/id/local-id";
import type { ConnectionWorkTracker } from "../../../../shared/lifecycle/connection-work";
import { type ChatServerDiagnosticsActions, createChatServerDiagnosticsActions } from "../../app-server/actions/diagnostics";
import { type ChatServerMetadataActions, createChatServerMetadataActions } from "../../app-server/actions/metadata";
import { type ChatServerThreadActions, createChatServerThreadActions } from "../../app-server/actions/threads";
@ -14,6 +12,8 @@ import {
createChatConnectionController,
handleChatConnectionExit,
} from "../../application/connection/connection-controller";
import type { ConnectionWorkTracker } from "../../application/connection/connection-work";
import type { LocalIdSource } from "../../application/local-id-source";
import { runtimeSnapshotForChatState } from "../../application/runtime/snapshot";
import type { ChatConnectionPhase } from "../../application/state/root-reducer";
import type { ChatStateStore } from "../../application/state/store";

View file

@ -1,5 +1,5 @@
import type { ConnectionManager } from "../../../../app-server/connection/connection-manager";
import type { ConnectionWorkTracker } from "../../../../shared/lifecycle/connection-work";
import type { ConnectionWorkTracker } from "../../application/connection/connection-work";
import { type ChatReconnectActionsHost, reconnectPanel } from "../../application/connection/reconnect-actions";
import type { ChatConnectionPhase } from "../../application/state/root-reducer";
import type { ChatStateStore } from "../../application/state/store";

View file

@ -2,11 +2,11 @@ import { Notice } from "obsidian";
import { recoverRolloutTokenUsage } from "../../../../app-server/services/rollout-token-usage";
import { normalizeExplicitThreadName } from "../../../../domain/threads/model";
import type { LocalIdSource } from "../../../../shared/id/local-id";
import { createThreadOperations, type ThreadOperations } from "../../../threads/workflows/thread-operations";
import { createThreadTitleService, type ThreadTitleService } from "../../../threads/workflows/thread-title-service";
import type { ChatServerThreadActions } from "../../app-server/actions/threads";
import type { ChatAppServerGateway } from "../../app-server/session-gateway";
import type { LocalIdSource } from "../../application/local-id-source";
import { messageStreamItems } from "../../application/state/message-stream";
import type { ChatStateStore } from "../../application/state/store";
import type { ActiveThreadIdentitySync } from "../../application/threads/active-thread-identity-sync";

View file

@ -1,4 +1,3 @@
import type { LocalIdSource } from "../../../../shared/id/local-id";
import type { ChatServerThreadActions } from "../../app-server/actions/threads";
import type { ChatInboundHandler } from "../../app-server/inbound/handler";
import type { ChatAppServerGateway } from "../../app-server/session-gateway";
@ -6,6 +5,7 @@ import {
type ConversationTurnActions as ChatPanelConversationTurnActions,
createConversationTurnActions,
} from "../../application/conversation/composition";
import type { LocalIdSource } from "../../application/local-id-source";
import { createPendingRequestActions, type PendingRequestActions } from "../../application/pending-requests/pending-request-actions";
import type { ChatStateStore } from "../../application/state/store";
import type { AutoTitleCoordinator } from "../../application/threads/auto-title-coordinator";

View file

@ -2,12 +2,12 @@ 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 { ObservedResultListener } from "../../../app-server/query/observed-result";
import type { ModelMetadata, ReasoningEffort } from "../../../domain/catalog/metadata";
import type { SendShortcut } from "../../../domain/input/send-shortcut";
import type { PendingRequestCounts } from "../../../domain/pending-requests/aggregate";
import type { SharedServerMetadata } from "../../../domain/server/metadata";
import type { ArchiveExportSettings } from "../../../domain/threads/archive-markdown";
import type { ObservedResultListener } from "../../../shared/query/observed-result";
import type { SendShortcut } from "../../../shared/ui/keyboard";
import type { ThreadCatalogActiveReader, ThreadCatalogEventSink } from "../../threads/catalog/thread-catalog";
import type { ArchiveExportDestination } from "../../threads/workflows/archive-export";
import type { TurnDiffViewState } from "../../turn-diff/model";

View file

@ -1,8 +1,8 @@
import { ConnectionManager } from "../../../app-server/connection/connection-manager";
import { isStaleAppServerSharedQueryContextError } from "../../../app-server/query/shared-queries";
import { createLocalIdSource, type LocalIdSource } from "../../../shared/id/local-id";
import type { ConnectionWorkTracker } from "../../../shared/lifecycle/connection-work";
import { createChatAppServerGateway } from "../app-server/session-gateway";
import type { ConnectionWorkTracker } from "../application/connection/connection-work";
import { createLocalIdSource, type LocalIdSource } from "../application/local-id-source";
import type { ChatAction, ChatConnectionPhase } from "../application/state/root-reducer";
import type { ChatStateStore } from "../application/state/store";
import type { ActiveThreadIdentitySync } from "../application/threads/active-thread-identity-sync";

View file

@ -2,7 +2,7 @@ import type { AppServerClient } from "../../../app-server/connection/client";
import { type AppServerQueryContext, appServerQueryContextMatches, appServerQueryContextRawEquals } from "../../../app-server/query/keys";
import { pendingRequestCountsFromQueues } from "../../../domain/pending-requests/aggregate";
import { threadMeaningfulTitle, threadWindowTitle } from "../../../domain/threads/title";
import { ConnectionWorkTracker } from "../../../shared/lifecycle/connection-work";
import { ConnectionWorkTracker } from "../application/connection/connection-work";
import type { ChatState } from "../application/state/root-reducer";
import { type ChatStateStore, createChatStateStore } from "../application/state/store";
import { parseRestoredThreadState, type RestoredThreadPlaceholderState } from "../application/threads/restored-thread-lifecycle";

View file

@ -1,4 +1,4 @@
import { DeferredTask, type DeferredTaskWindow } from "../../../../shared/lifecycle/deferred-task";
import { DeferredTask, type DeferredTaskWindow } from "../../../../shared/runtime/deferred-task";
export interface ChatViewDeferredTasks {
scheduleDiagnostics(callback: () => void): void;

View file

@ -1,8 +1,8 @@
import type { ObservedResult } from "../../../../app-server/query/observed-result";
import { observedValue } from "../../../../app-server/query/observed-result";
import type { ModelMetadata } from "../../../../domain/catalog/metadata";
import type { SharedServerMetadata } from "../../../../domain/server/metadata";
import type { Thread } from "../../../../domain/threads/model";
import type { ObservedResult } from "../../../../shared/query/observed-result";
import { observedValue } from "../../../../shared/query/observed-result";
import type { ChatStateStore } from "../../application/state/store";
import type { ChatPanelConnectionBundle } from "../bundles/connection-bundle";

View file

@ -1,8 +1,8 @@
import { ItemView, type ViewStateResult, type WorkspaceLeaf } from "obsidian";
import { VIEW_TYPE_CODEX_PANEL } from "../../../constants";
import { createLocalIdSource } from "../../../shared/id/local-id";
import { createObsidianArchiveExportDestination } from "../../../shared/obsidian/archive-export-destination";
import { createObsidianArchiveExportDestination } from "../../threads/obsidian/archive-export-destination.obsidian";
import { createLocalIdSource } from "../application/local-id-source";
import type { ChatPanelHandle, CodexChatHost } from "./contracts";
import { ChatPanelSession } from "./session";

View file

@ -1,4 +1,4 @@
import { textareaCursorAtVisualBoundary } from "../../../shared/ui/textarea-caret.measure";
import { textareaCursorAtVisualBoundary } from "../../../shared/dom/textarea-caret.measure";
import { type ComposerBoundaryScrollAction, composerBoundaryScrollDirection } from "../application/composer/boundary-scroll";
import { composerSuggestionSignature } from "../application/composer/suggestions";
import { syncComposerHeight } from "../ui/composer.dom";

View file

@ -1,5 +1,5 @@
import type { CodexInput } from "../../../domain/chat/input";
import { isComposerSendKey, type SendShortcut } from "../../../shared/ui/keyboard";
import { isComposerSendKey, type SendShortcut } from "../../../domain/input/send-shortcut";
import {
type ComposerAttachment,
type ComposerAttachmentHandler,

View file

@ -1,6 +1,6 @@
import type { ComponentChild as UiNode } from "preact";
import { listenDomEvent } from "../../../shared/ui/dom-events.dom";
import { renderUiRoot, unmountUiRoot } from "../../../shared/ui/ui-root.dom";
import { listenDomEvent } from "../../../shared/dom/events.dom";
import { renderUiRoot, unmountUiRoot } from "../../../shared/dom/preact-root.dom";
import type { ChatStateStore } from "../application/state/store";
import type { ToolbarActions } from "../ui/toolbar";
import { type ChatPanelShellReadModelBinding, createChatPanelShellReadModelBinding } from "./shell-read-model";

View file

@ -1,6 +1,6 @@
import type { ComponentChild as UiNode } from "preact";
import { h } from "preact";
import type { SendShortcut } from "../../../../shared/ui/keyboard";
import type { SendShortcut } from "../../../../domain/input/send-shortcut";
import type { GoalPanelActions, GoalPanelDisplayState, GoalPanelEditorState, GoalPanelOptions } from "../../ui/goal";
import { GoalPanel } from "../../ui/goal";
import type { ChatPanelGoalReadModel } from "../shell-read-model";

View file

@ -1,7 +1,7 @@
import type { App, Component } from "obsidian";
import type { ComponentChild as UiNode } from "preact";
import { h } from "preact";
import { copyTextWithNotice } from "../../../../shared/ui/clipboard";
import { copyTextWithNotice } from "../../../../shared/obsidian/clipboard.obsidian";
import type { TurnDiffViewState } from "../../../turn-diff/model";
import type { PendingRequestBlockActions } from "../../application/pending-requests/block";
import type { ChatAction } from "../../application/state/root-reducer";

View file

@ -1,4 +1,4 @@
import { copyTextWithNotice } from "../../../shared/ui/clipboard";
import { copyTextWithNotice } from "../../../shared/obsidian/clipboard.obsidian";
import type { ChatConnectionController } from "../application/connection/connection-controller";
import type { ChatAction, ChatState } from "../application/state/root-reducer";
import type { ChatStateStore } from "../application/state/store";

View file

@ -1,6 +1,6 @@
import { shortThreadId } from "../../../../shared/id/thread-id";
import { pathRelativeToRoot } from "../../../../shared/path/file-paths";
import { truncate } from "../../../../shared/text/preview";
import { truncate } from "../../../../domain/display/text-preview";
import { shortThreadId } from "../../../../domain/threads/id";
import { pathRelativeToRoot } from "../../../../domain/vault/paths";
import type {
AgentMessageStreamItem,
ApprovalResultMessageStreamItem,

View file

@ -1,4 +1,4 @@
import { pathRelativeToRoot } from "../../../../shared/path/file-paths";
import { pathRelativeToRoot } from "../../../../domain/vault/paths";
import type { MessageStreamItem } from "../../domain/message-stream/items";
import { messageStreamSemanticClassifications } from "../../domain/message-stream/semantics/classify";
import {

View file

@ -1,4 +1,4 @@
import { shortThreadId } from "../../../../shared/id/thread-id";
import { shortThreadId } from "../../../../domain/threads/id";
import type {
AgentRunSummary,
AgentRunSummaryAgent,

View file

@ -1,6 +1,6 @@
import { jsonPreview } from "../../../../domain/display/json-preview";
import { type RuntimeConfigSnapshot, runtimeConfigOrDefault } from "../../../../domain/runtime/config";
import type { RateLimitWindow, SpendControlLimitSnapshot, ThreadTokenUsage } from "../../../../domain/runtime/metrics";
import { jsonPreview } from "../../../../shared/text/preview";
import { serviceTierLabel as formatServiceTierLabel, pendingRuntimeSettingLabel } from "../../domain/runtime/labels";
import { resolveRuntimeControls } from "../../domain/runtime/resolution";
import type { RuntimeSnapshot } from "../../domain/runtime/snapshot";

View file

@ -1,7 +1,7 @@
import { setIcon } from "obsidian";
import { disposeDomListeners, listenDomEscapeKey, listenDomEvent, listenOutsideDomEvent } from "../../../shared/ui/dom-events.dom";
import { syncTextareaHeight } from "../../../shared/ui/textarea-autogrow.measure";
import { disposeDomListeners, listenDomEscapeKey, listenDomEvent, listenOutsideDomEvent } from "../../../shared/dom/events.dom";
import { syncTextareaHeight } from "../../../shared/dom/textarea-autogrow.measure";
const COMPOSER_META_EFFORT_HIDDEN_CLASS = "is-effort-hidden";
const COMPOSER_META_MODEL_HIDDEN_CLASS = "is-model-hidden";

View file

@ -1,7 +1,7 @@
import type { ButtonHTMLAttributes, Ref, ComponentChild as UiNode } from "preact";
import { useLayoutEffect, useRef, useState } from "preact/hooks";
import { IconButton } from "../../../shared/ui/components.obsidian";
import { IconButton } from "../../../shared/obsidian/components.obsidian";
import {
type ComposerMetaPickerState,
closeComposerMetaPickerOnOutsidePointer,

View file

@ -1,5 +1,5 @@
import { disposeDomListeners, listenDomEscapeKey, listenOutsideDomEvent } from "../../../shared/ui/dom-events.dom";
import { syncTextareaHeight } from "../../../shared/ui/textarea-autogrow.measure";
import { disposeDomListeners, listenDomEscapeKey, listenOutsideDomEvent } from "../../../shared/dom/events.dom";
import { syncTextareaHeight } from "../../../shared/dom/textarea-autogrow.measure";
export function syncGoalObjectiveHeight(textarea: HTMLTextAreaElement | null): void {
syncTextareaHeight(textarea, {

View file

@ -1,9 +1,8 @@
import type { ComponentChild as UiNode } from "preact";
import { useEffect, useLayoutEffect, useRef, useState } from "preact/hooks";
import { isComposerSendKey, type SendShortcut } from "../../../domain/input/send-shortcut";
import type { ThreadGoal, ThreadGoalStatus } from "../../../domain/threads/goal";
import { IconButton } from "../../../shared/ui/components.obsidian";
import { isComposerSendKey, type SendShortcut } from "../../../shared/ui/keyboard";
import { IconButton } from "../../../shared/obsidian/components.obsidian";
import {
closeGoalEditorOnOutsidePointer,
collapseGoalObjectiveOnOutsidePointer,

View file

@ -1,6 +1,6 @@
import type { ComponentChild as UiNode } from "preact";
import { RawDiffView } from "../../../../shared/ui/diff";
import { RawDiffView } from "../../../../shared/ui/diff-view";
import type { DetailSection, DetailView } from "../../presentation/message-stream/detail-view";
import type { MessageStreamDisclosureState } from "./context";

View file

@ -1,6 +1,6 @@
import { Component, h, type ComponentChild as UiNode } from "preact";
import { disposeDomListeners, listenDomEvent } from "../../../../shared/ui/dom-events.dom";
import { disposeDomListeners, listenDomEvent } from "../../../../shared/dom/events.dom";
import { MESSAGE_CONTENT_RENDERED_EVENT } from "./content-rendered-event.dom";
type MessageScrollDirection = -1 | 1;

View file

@ -1,7 +1,8 @@
import { micromark } from "micromark";
import { type App, type Component, MarkdownRenderer, Notice } from "obsidian";
import { isAbsoluteFileHref, vaultFileLinkTarget, vaultRelativeFileLinkTarget } from "../../../../shared/obsidian/file-links";
import { isAbsoluteFileHref, vaultRelativeFileLinkTarget } from "../../../../domain/vault/file-hrefs";
import { vaultFileLinkTarget } from "../../../../shared/obsidian/vault-file-links.obsidian";
import { notifyMessageContentRendered } from "./content-rendered-event.dom";
interface MarkdownMessageRendererOptions {

View file

@ -1,7 +1,7 @@
import type { Ref, ComponentChild as UiNode } from "preact";
import { useEffect, useLayoutEffect, useRef, useState } from "preact/hooks";
import { listenDomEvent, listenOutsideDomEvent } from "../../../../shared/ui/dom-events.dom";
import { listenDomEvent, listenOutsideDomEvent } from "../../../../shared/dom/events.dom";
import type { MessageStreamTextView } from "../../presentation/message-stream/text-view";
import { MESSAGE_CONTENT_RENDERED_EVENT } from "./content-rendered-event.dom";
import type { TextItemContentContext } from "./context";

View file

@ -1,4 +1,4 @@
import { listenOutsideDomEvent } from "../../../../shared/ui/dom-events.dom";
import { listenOutsideDomEvent } from "../../../../shared/dom/events.dom";
export function closeMessageRoleMenuOnOutsidePointer(root: HTMLElement, onClose: () => void): () => void {
return listenOutsideDomEvent(root, "pointerdown", onClose, true);

View file

@ -1,6 +1,6 @@
import { Fragment, type ComponentChild as UiNode } from "preact";
import { useEffect, useRef } from "preact/hooks";
import { IconButton } from "../../../../shared/ui/components.obsidian";
import { IconButton } from "../../../../shared/obsidian/components.obsidian";
import type {
EditedFilesTextView,
MentionedFileTextView,

View file

@ -1,6 +1,6 @@
import type { ButtonHTMLAttributes, ComponentChild as UiNode } from "preact";
import { useLayoutEffect, useRef } from "preact/hooks";
import { IconButton, ObsidianToolbarAction, type ObsidianToolbarActionProps } from "../../../shared/ui/components.obsidian";
import { IconButton, ObsidianToolbarAction, type ObsidianToolbarActionProps } from "../../../shared/obsidian/components.obsidian";
import type { RateLimitSummary } from "../presentation/runtime/status";
import { focusToolbarRenameInput } from "./toolbar.dom";

View file

@ -1,5 +1,5 @@
import { type Editor, MarkdownView, Notice, type Plugin } from "obsidian";
import type { SendShortcut } from "../../shared/ui/keyboard";
import type { SendShortcut } from "../../domain/input/send-shortcut";
import type { SelectionRewriteRuntimeSettings, SelectionRewriteState } from "./model";
import { SelectionRewritePopover } from "./popover.dom";

View file

@ -1,13 +1,12 @@
import { type Editor, Notice } from "obsidian";
import type { TargetedKeyboardEvent, ComponentChild as UiNode } from "preact";
import { IconButton } from "../../shared/ui/components.obsidian";
import { DiffLineList, unifiedDiffDisplayLines } from "../../shared/ui/diff";
import { listenDomEscapeKey, listenDomEvent, listenOutsideDomEvent } from "../../shared/ui/dom-events.dom";
import { isComposerSendKey, type SendShortcut } from "../../shared/ui/keyboard";
import { syncTextareaHeight } from "../../shared/ui/textarea-autogrow.measure";
import { textareaCursorAtVisualBoundary } from "../../shared/ui/textarea-caret.measure";
import { renderUiRoot, unmountUiRoot } from "../../shared/ui/ui-root.dom";
import { isComposerSendKey, type SendShortcut } from "../../domain/input/send-shortcut";
import { listenDomEscapeKey, listenDomEvent, listenOutsideDomEvent } from "../../shared/dom/events.dom";
import { renderUiRoot, unmountUiRoot } from "../../shared/dom/preact-root.dom";
import { syncTextareaHeight } from "../../shared/dom/textarea-autogrow.measure";
import { textareaCursorAtVisualBoundary } from "../../shared/dom/textarea-caret.measure";
import { IconButton } from "../../shared/obsidian/components.obsidian";
import { DiffLineList, unifiedDiffDisplayLines } from "../../shared/ui/diff-view";
import { buildSelectionUnifiedDiff } from "./diff";
import {
canApplySelectionRewrite,

View file

@ -1,8 +1,7 @@
import { type App, Notice, Platform, SuggestModal } from "obsidian";
import { shortThreadId } from "../../domain/threads/id";
import { type Thread, threadRecencyAt } from "../../domain/threads/model";
import { threadDisplayTitle } from "../../domain/threads/title";
import { shortThreadId } from "../../shared/id/thread-id";
import type { ThreadCatalogActiveReader } from "../threads/catalog/thread-catalog";
export interface ThreadPickerHost {

View file

@ -1,12 +1,12 @@
import { Notice } from "obsidian";
import type { AppServerClientAccess } from "../../app-server/connection/client-access";
import type { ObservedResult } from "../../app-server/query/observed-result";
import { observedInitialError, observedInitialLoading, observedValue } from "../../app-server/query/observed-result";
import { isStaleAppServerSharedQueryContextError } from "../../app-server/query/shared-queries";
import type { ReasoningEffort } from "../../domain/catalog/metadata";
import type { ArchiveExportSettings } from "../../domain/threads/archive-markdown";
import type { Thread } from "../../domain/threads/model";
import type { ObservedResult } from "../../shared/query/observed-result";
import { observedInitialError, observedInitialLoading, observedValue } from "../../shared/query/observed-result";
import type { ThreadCatalogActiveReader, ThreadCatalogEventSink } from "../threads/catalog/thread-catalog";
import type { ArchiveExportDestination } from "../threads/workflows/archive-export";
import { createThreadOperations, type ThreadOperations } from "../threads/workflows/thread-operations";

View file

@ -1,8 +1,7 @@
import type { ButtonHTMLAttributes, ComponentChild as UiNode } from "preact";
import { useLayoutEffect, useRef } from "preact/hooks";
import { IconButton, ObsidianToolbarAction, type ObsidianToolbarActionProps } from "../../shared/ui/components.obsidian";
import { renderUiRoot, unmountUiRoot } from "../../shared/ui/ui-root.dom";
import { renderUiRoot, unmountUiRoot } from "../../shared/dom/preact-root.dom";
import { IconButton, ObsidianToolbarAction, type ObsidianToolbarActionProps } from "../../shared/obsidian/components.obsidian";
import type { ThreadsRowModel } from "./state";
type ButtonProps = ButtonHTMLAttributes & {

View file

@ -1,4 +1,4 @@
import { DeferredTask, type DeferredTaskWindow } from "../../shared/lifecycle/deferred-task";
import { DeferredTask, type DeferredTaskWindow } from "../../shared/runtime/deferred-task";
export type ThreadsViewRefreshLifecycleState = { kind: "idle" } | { kind: "loading" };
export type ActiveThreadsViewRefresh = Extract<ThreadsViewRefreshLifecycleState, { kind: "loading" }>;

View file

@ -1,7 +1,7 @@
import { ItemView, type WorkspaceLeaf } from "obsidian";
import { VIEW_TYPE_CODEX_THREADS } from "../../constants";
import { createObsidianArchiveExportDestination } from "../../shared/obsidian/archive-export-destination";
import { createObsidianArchiveExportDestination } from "../threads/obsidian/archive-export-destination.obsidian";
import { type ThreadsViewHost, ThreadsViewSession } from "./session";
export class CodexThreadsView extends ItemView {

View file

@ -1,5 +1,5 @@
import type { ObservedResultListener } from "../../../app-server/query/observed-result";
import type { Thread } from "../../../domain/threads/model";
import type { ObservedResultListener } from "../../../shared/query/observed-result";
type ThreadListObserver = ObservedResultListener<readonly Thread[]>;

View file

@ -1,6 +1,6 @@
import { type ArchiveExportSettings, type ArchiveThreadInput, archivedThreadMarkdown } from "../../../domain/threads/archive-markdown";
import { shortThreadId } from "../../../domain/threads/id";
import { threadArchiveTitle } from "../../../domain/threads/title";
import { shortThreadId } from "../../../shared/id/thread-id";
export interface ArchiveExportResult {
path: string;

View file

@ -1,9 +1,9 @@
import type { ComponentChild as UiNode } from "preact";
import { shortThreadId } from "../../shared/id/thread-id";
import { IconButton } from "../../shared/ui/components.obsidian";
import { UnifiedDiffView } from "../../shared/ui/diff";
import { renderUiRoot } from "../../shared/ui/ui-root.dom";
import { shortThreadId } from "../../domain/threads/id";
import { renderUiRoot } from "../../shared/dom/preact-root.dom";
import { IconButton } from "../../shared/obsidian/components.obsidian";
import { UnifiedDiffView } from "../../shared/ui/diff-view";
import type { PersistedTurnDiffViewState, TurnDiffViewState } from "./model";
export interface TurnDiffViewActions {

View file

@ -1,8 +1,8 @@
import { ItemView, type ViewStateResult } from "obsidian";
import { VIEW_TYPE_CODEX_TURN_DIFF } from "../../constants";
import { copyTextWithNotice } from "../../shared/ui/clipboard";
import { unmountUiRoot } from "../../shared/ui/ui-root.dom";
import { unmountUiRoot } from "../../shared/dom/preact-root.dom";
import { copyTextWithNotice } from "../../shared/obsidian/clipboard.obsidian";
import { isPersistedTurnDiffViewState, type PersistedTurnDiffViewState, persistedTurnDiffViewState, type TurnDiffViewState } from "./model";
import { renderTurnDiffView } from "./render.dom";

View file

@ -1,11 +1,11 @@
import type { AppServerClient } from "../app-server/connection/client";
import type { AppServerClientAccess } from "../app-server/connection/client-access";
import type { ObservedResultListener } from "../app-server/query/observed-result";
import { isStaleAppServerSharedQueryContextError } from "../app-server/query/shared-queries";
import { listHookCatalog, setHookItemEnabled, trustHookItem } from "../app-server/services/catalog";
import { deleteThread, restoreArchivedThread as restoreArchivedThreadOnAppServer } from "../app-server/services/threads";
import type { ModelMetadata } from "../domain/catalog/metadata";
import type { ThreadCatalogArchivedReader, ThreadCatalogEventSink } from "../features/threads/catalog/thread-catalog";
import type { ObservedResultListener } from "../shared/query/observed-result";
import { type SettingsDynamicDataAccess, type SettingsHookCatalog, StaleSettingsDynamicDataContextError } from "./dynamic-data";
interface SettingsAppServerQueries {

View file

@ -1,9 +1,8 @@
import type { ComponentChild as UiNode } from "preact";
import { shortThreadId } from "../domain/threads/id";
import type { Thread } from "../domain/threads/model";
import { threadArchiveDisplayTitle } from "../domain/threads/title";
import { shortThreadId } from "../shared/id/thread-id";
import { ObsidianExtraButton, ObsidianTextInput, ObsidianToggle } from "../shared/ui/components.obsidian";
import { ObsidianExtraButton, ObsidianTextInput, ObsidianToggle } from "../shared/obsidian/components.obsidian";
import type { ArchivedThreadSectionState } from "./section-state";
import { SettingRow, SettingsGroup, SettingsHeading, SettingsItems, SettingsStatusRow } from "./setting-components";

View file

@ -1,6 +1,6 @@
import type { ObservedResultListener } from "../app-server/query/observed-result";
import type { HookItem, ModelMetadata } from "../domain/catalog/metadata";
import type { Thread } from "../domain/threads/model";
import type { ObservedResultListener } from "../shared/query/observed-result";
export interface SettingsHookCatalog {
hooks: readonly HookItem[];

View file

@ -1,9 +1,9 @@
import type { ObservedResult } from "../app-server/query/observed-result";
import { observedValue } from "../app-server/query/observed-result";
import type { HookItem, ModelMetadata, ReasoningEffort } from "../domain/catalog/metadata";
import { findModelMetadataByIdOrName, sortedModelMetadata, supportedEffortsForModelMetadata } from "../domain/catalog/metadata";
import type { Thread } from "../domain/threads/model";
import { threadArchiveDisplayTitle } from "../domain/threads/title";
import type { ObservedResult } from "../shared/query/observed-result";
import { observedValue } from "../shared/query/observed-result";
import { isStaleSettingsDynamicDataContextError } from "./dynamic-data";
import type { SettingsDynamicSectionsHost } from "./host";
import {

View file

@ -2,7 +2,7 @@ import type { ComponentChild as UiNode } from "preact";
import type { ModelMetadata, ReasoningEffort } from "../domain/catalog/metadata";
import { findModelMetadataByIdOrName, supportedEffortsForModelMetadata } from "../domain/catalog/metadata";
import { ObsidianDropdown } from "../shared/ui/components.obsidian";
import { ObsidianDropdown } from "../shared/obsidian/components.obsidian";
import type { HelperSettingsState } from "./section-state";
import { SettingRow, SettingsGroup, SettingsHeading, SettingsItems } from "./setting-components";

View file

@ -1,7 +1,7 @@
import type { ComponentChild as UiNode } from "preact";
import type { HookItem } from "../domain/catalog/metadata";
import { ObsidianButton } from "../shared/ui/components.obsidian";
import { ObsidianButton } from "../shared/obsidian/components.obsidian";
import type { HookSectionState } from "./section-state";
import { SettingRow, SettingsGroup, SettingsHeading, SettingsItems, SettingsStatusRow } from "./setting-components";

View file

@ -3,7 +3,7 @@ import { type App, FileSystemAdapter } from "obsidian";
import { DEFAULT_CODEX_PATH } from "../constants";
import type { ReasoningEffort } from "../domain/catalog/metadata";
import { normalizeReasoningEffort } from "../domain/catalog/metadata";
import type { SendShortcut } from "../shared/ui/keyboard";
import type { SendShortcut } from "../domain/input/send-shortcut";
export interface CodexPanelSettings {
codexPath: string;

View file

@ -1,8 +1,8 @@
import type { ComponentChild as UiNode } from "preact";
import { DEFAULT_CODEX_PATH } from "../constants";
import { IconButton, ObsidianCommitTextInput, ObsidianDropdown, ObsidianToggle } from "../shared/ui/components.obsidian";
import type { SendShortcut } from "../shared/ui/keyboard";
import type { SendShortcut } from "../domain/input/send-shortcut";
import { IconButton, ObsidianCommitTextInput, ObsidianDropdown, ObsidianToggle } from "../shared/obsidian/components.obsidian";
import { ArchivedThreadSection } from "./archived-section";
import { HelperSettingsSection } from "./helper-section";
import { HookSection } from "./hook-section";

View file

@ -2,8 +2,8 @@ import { type App, Notice, type Plugin, PluginSettingTab } from "obsidian";
import { DEFAULT_CODEX_PATH } from "../constants";
import type { ReasoningEffort } from "../domain/catalog/metadata";
import { listenDomEvent } from "../shared/ui/dom-events.dom";
import { renderUiRoot, unmountUiRoot } from "../shared/ui/ui-root.dom";
import { listenDomEvent } from "../shared/dom/events.dom";
import { renderUiRoot, unmountUiRoot } from "../shared/dom/preact-root.dom";
import { SettingsDynamicSectionsController } from "./dynamic-sections-controller";
import type { CodexPanelSettingTabHost } from "./host";
import { DEFAULT_ATTACHMENT_FOLDER } from "./model";

View file

@ -2,7 +2,7 @@ import { ButtonComponent, DropdownComponent, ExtraButtonComponent, setIcon, Text
import type { ButtonHTMLAttributes, HTMLAttributes, Ref, ComponentChild as UiNode } from "preact";
import { useLayoutEffect, useRef } from "preact/hooks";
import { disposeDomListeners, listenDomEvent } from "./dom-events.dom";
import { disposeDomListeners, listenDomEvent } from "../dom/events.dom";
interface ObsidianIconProps {
icon: string;

View file

@ -1,34 +0,0 @@
import { type App, TFile } from "obsidian";
import { isFilesystemAbsolutePath, isVaultConfigPath, normalizeFilePath, parseFileHref, vaultRelativePath } from "../path/file-paths";
export function vaultFileLinkTarget(app: App, vaultPath: string, href: string): string | null {
const relativePath = vaultRelativeFileHref(vaultPath, app.vault.configDir, href);
if (!relativePath) return null;
const abstractFile = app.vault.getAbstractFileByPath(relativePath.path);
return abstractFile instanceof TFile ? `${relativePath.path}${relativePath.subpath}` : null;
}
export function vaultRelativeFileLinkTarget(vaultPath: string, configDir: string, href: string): string | null {
const relativePath = vaultRelativeFileHref(vaultPath, configDir, href);
return relativePath ? `${relativePath.path}${relativePath.subpath}` : null;
}
export function isAbsoluteFileHref(href: string): boolean {
const parsed = parseFileHref(href);
return parsed ? isFilesystemAbsolutePath(normalizeFilePath(parsed.path)) : false;
}
function vaultRelativeFileHref(vaultPath: string, configDir: string, href: string): { path: string; subpath: string } | null {
const parsed = parseFileHref(href);
if (!parsed) return null;
const relativePath = vaultRelativePath(vaultPath, parsed.path, { allowRelative: true });
if (!relativePath) return null;
const normalized = normalizeFilePath(relativePath);
if (isVaultConfigPath(normalized, configDir)) return null;
return { path: normalized, subpath: parsed.subpath };
}

View file

@ -0,0 +1,11 @@
import { type App, TFile } from "obsidian";
import { vaultRelativeFileHref } from "../../domain/vault/file-hrefs";
export function vaultFileLinkTarget(app: App, vaultPath: string, href: string): string | null {
const relativePath = vaultRelativeFileHref(vaultPath, app.vault.configDir, href);
if (!relativePath) return null;
const abstractFile = app.vault.getAbstractFileByPath(relativePath.path);
return abstractFile instanceof TFile ? `${relativePath.path}${relativePath.subpath}` : null;
}

View file

@ -1,7 +1,7 @@
import { describe, expect, it } from "vitest";
import type { ObservedResult } from "../../../src/shared/query/observed-result";
import { observedInitialError, observedInitialLoading, observedValue } from "../../../src/shared/query/observed-result";
import type { ObservedResult } from "../../../src/app-server/query/observed-result";
import { observedInitialError, observedInitialLoading, observedValue } from "../../../src/app-server/query/observed-result";
describe("observed query result helpers", () => {
it("treats successful empty arrays as current values", () => {

Some files were not shown because too many files have changed in this diff Show more