@mseep/obsidian-agent-client 0.10.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/.claude/hooks/gh-setup.sh +49 -0
  2. package/.claude/settings.json +15 -0
  3. package/.claude/skills/release-notes/SKILL.md +331 -0
  4. package/.editorconfig +10 -0
  5. package/.github/FUNDING.yml +2 -0
  6. package/.github/ISSUE_TEMPLATE/bug_report.yml +90 -0
  7. package/.github/ISSUE_TEMPLATE/config.yml +11 -0
  8. package/.github/ISSUE_TEMPLATE/feature_request.yml +59 -0
  9. package/.github/copilot-instructions.md +45 -0
  10. package/.github/pull_request_template.md +32 -0
  11. package/.github/workflows/ci.yaml +25 -0
  12. package/.github/workflows/docs.yml +58 -0
  13. package/.github/workflows/relay_to_openclaw.yml +59 -0
  14. package/.github/workflows/release.yaml +45 -0
  15. package/.prettierignore +10 -0
  16. package/.prettierrc +13 -0
  17. package/.vscode/extensions.json +7 -0
  18. package/.vscode/settings.json +37 -0
  19. package/.zed/settings.json +42 -0
  20. package/AGENTS.md +330 -0
  21. package/ARCHITECTURE.md +390 -0
  22. package/CONTRIBUTING.md +216 -0
  23. package/LICENSE +202 -0
  24. package/NOTICE +2 -0
  25. package/README.ja.md +121 -0
  26. package/README.md +125 -0
  27. package/docs/.vitepress/config.mts +124 -0
  28. package/docs/.vitepress/theme/custom.css +111 -0
  29. package/docs/.vitepress/theme/index.ts +4 -0
  30. package/docs/agent-setup/claude-code.md +84 -0
  31. package/docs/agent-setup/codex.md +76 -0
  32. package/docs/agent-setup/custom-agents.md +67 -0
  33. package/docs/agent-setup/gemini-cli.md +99 -0
  34. package/docs/agent-setup/index.md +34 -0
  35. package/docs/announcements/gemini-cli-deprecation.md +73 -0
  36. package/docs/getting-started/index.md +78 -0
  37. package/docs/getting-started/quick-start.md +38 -0
  38. package/docs/help/faq.md +181 -0
  39. package/docs/help/troubleshooting.md +221 -0
  40. package/docs/index.md +63 -0
  41. package/docs/public/apple-touch-icon.png +0 -0
  42. package/docs/public/demo.mp4 +0 -0
  43. package/docs/public/favicon-16x16.png +0 -0
  44. package/docs/public/favicon-32x32.png +0 -0
  45. package/docs/public/favicon.ico +0 -0
  46. package/docs/public/images/editing.webp +0 -0
  47. package/docs/public/images/export.webp +0 -0
  48. package/docs/public/images/floating-chat-button.webp +0 -0
  49. package/docs/public/images/floating-chat-instance-menu.webp +0 -0
  50. package/docs/public/images/floating-chat-view.webp +0 -0
  51. package/docs/public/images/mode-selection.webp +0 -0
  52. package/docs/public/images/model-selection.webp +0 -0
  53. package/docs/public/images/multi-session.webp +0 -0
  54. package/docs/public/images/remove-image.webp +0 -0
  55. package/docs/public/images/ribbon-icon.webp +0 -0
  56. package/docs/public/images/selection-context.gif +0 -0
  57. package/docs/public/images/sending-images.webp +0 -0
  58. package/docs/public/images/sending-messages.webp +0 -0
  59. package/docs/public/images/session-history-button.webp +0 -0
  60. package/docs/public/images/slash-commands-1.webp +0 -0
  61. package/docs/public/images/slash-commands-2.webp +0 -0
  62. package/docs/public/images/switch-agent.webp +0 -0
  63. package/docs/public/images/switch-default-agent.webp +0 -0
  64. package/docs/public/images/temporary-disable.gif +0 -0
  65. package/docs/reference/acp-support.md +110 -0
  66. package/docs/usage/chat-export.md +80 -0
  67. package/docs/usage/commands.md +51 -0
  68. package/docs/usage/context-files.md +57 -0
  69. package/docs/usage/editing.md +69 -0
  70. package/docs/usage/floating-chat.md +84 -0
  71. package/docs/usage/index.md +97 -0
  72. package/docs/usage/mcp-tools.md +33 -0
  73. package/docs/usage/mentions.md +70 -0
  74. package/docs/usage/mode-selection.md +28 -0
  75. package/docs/usage/model-selection.md +32 -0
  76. package/docs/usage/multi-session.md +68 -0
  77. package/docs/usage/sending-images.md +64 -0
  78. package/docs/usage/session-history.md +91 -0
  79. package/docs/usage/slash-commands.md +44 -0
  80. package/esbuild.config.mjs +49 -0
  81. package/eslint.config.mjs +25 -0
  82. package/main.js +228 -0
  83. package/manifest.json +11 -0
  84. package/package.json +52 -0
  85. package/src/acp/acp-client.ts +921 -0
  86. package/src/acp/acp-handler.ts +252 -0
  87. package/src/acp/permission-handler.ts +282 -0
  88. package/src/acp/terminal-handler.ts +264 -0
  89. package/src/acp/type-converter.ts +272 -0
  90. package/src/hooks/useAgent.ts +250 -0
  91. package/src/hooks/useAgentMessages.ts +470 -0
  92. package/src/hooks/useAgentSession.ts +544 -0
  93. package/src/hooks/useChatActions.ts +400 -0
  94. package/src/hooks/useHistoryModal.ts +219 -0
  95. package/src/hooks/useSessionHistory.ts +863 -0
  96. package/src/hooks/useSettings.ts +19 -0
  97. package/src/hooks/useSuggestions.ts +342 -0
  98. package/src/main.ts +9 -0
  99. package/src/plugin.ts +1126 -0
  100. package/src/services/chat-exporter.ts +552 -0
  101. package/src/services/message-sender.ts +755 -0
  102. package/src/services/message-state.ts +375 -0
  103. package/src/services/session-helpers.ts +211 -0
  104. package/src/services/session-state.ts +130 -0
  105. package/src/services/session-storage.ts +267 -0
  106. package/src/services/settings-normalizer.ts +255 -0
  107. package/src/services/settings-service.ts +285 -0
  108. package/src/services/update-checker.ts +128 -0
  109. package/src/services/vault-service.ts +558 -0
  110. package/src/services/view-registry.ts +345 -0
  111. package/src/types/agent.ts +92 -0
  112. package/src/types/chat.ts +351 -0
  113. package/src/types/errors.ts +136 -0
  114. package/src/types/obsidian-internals.d.ts +14 -0
  115. package/src/types/session.ts +731 -0
  116. package/src/ui/ChangeDirectoryModal.ts +137 -0
  117. package/src/ui/ChatContext.ts +25 -0
  118. package/src/ui/ChatHeader.tsx +295 -0
  119. package/src/ui/ChatPanel.tsx +1162 -0
  120. package/src/ui/ChatView.tsx +348 -0
  121. package/src/ui/ErrorBanner.tsx +104 -0
  122. package/src/ui/FloatingButton.tsx +351 -0
  123. package/src/ui/FloatingChatView.tsx +531 -0
  124. package/src/ui/InputArea.tsx +1107 -0
  125. package/src/ui/InputToolbar.tsx +371 -0
  126. package/src/ui/MessageBubble.tsx +442 -0
  127. package/src/ui/MessageList.tsx +265 -0
  128. package/src/ui/PermissionBanner.tsx +61 -0
  129. package/src/ui/SessionHistoryModal.tsx +821 -0
  130. package/src/ui/SettingsTab.ts +1337 -0
  131. package/src/ui/SuggestionPopup.tsx +138 -0
  132. package/src/ui/TerminalBlock.tsx +107 -0
  133. package/src/ui/ToolCallBlock.tsx +456 -0
  134. package/src/ui/shared/AttachmentStrip.tsx +57 -0
  135. package/src/ui/shared/IconButton.tsx +55 -0
  136. package/src/ui/shared/MarkdownRenderer.tsx +103 -0
  137. package/src/ui/view-host.ts +56 -0
  138. package/src/utils/error-utils.ts +274 -0
  139. package/src/utils/logger.ts +44 -0
  140. package/src/utils/mention-parser.ts +129 -0
  141. package/src/utils/paths.ts +246 -0
  142. package/src/utils/platform.ts +425 -0
  143. package/styles.css +2322 -0
  144. package/tsconfig.json +18 -0
  145. package/version-bump.mjs +18 -0
  146. package/versions.json +3 -0
@@ -0,0 +1,390 @@
1
+ # Architecture Documentation
2
+
3
+ ## Overview
4
+
5
+ Obsidian plugin for AI agent interaction via ACP. `useAgent` facade hook composes sub-hooks (`useAgentSession` + `useAgentMessages`) and subscribes to a single `onSessionUpdate` channel. `ChatPanel` orchestrates hooks and renders children directly. Services are injected via React Context. ACP protocol details are isolated in the `acp/` layer.
6
+
7
+ ## Directory Structure
8
+
9
+ ```
10
+ src/
11
+ ├── types/ # Type Definitions (no logic, no dependencies)
12
+ │ ├── chat.ts # ChatMessage, MessageContent, PromptContent, AttachedFile, ActivePermission
13
+ │ ├── session.ts # ChatSession, SessionUpdate (12-type union), SessionInfo, Capabilities
14
+ │ ├── agent.ts # AgentConfig, agent settings (Claude/Gemini/Codex/Custom)
15
+ │ └── errors.ts # AcpError, ProcessError, ErrorInfo
16
+
17
+ ├── acp/ # ACP Protocol Layer (SDK dependency confined here)
18
+ │ ├── acp-client.ts # Process lifecycle, UI-facing API (AcpClient class)
19
+ │ ├── acp-handler.ts # SDK event handler + sessionId filter + listener broadcast
20
+ │ ├── type-converter.ts # ACP SDK types ↔ internal types
21
+ │ ├── permission-handler.ts # Permission queue, auto-approve, Promise resolution
22
+ │ └── terminal-handler.ts # Terminal process create/output/kill
23
+
24
+ ├── services/ # Business Logic (non-React, no React imports)
25
+ │ ├── vault-service.ts # Vault access + fuzzy search + CM6 selection tracking
26
+ │ ├── settings-service.ts # Reactive settings store (observer pattern only)
27
+ │ ├── session-storage.ts # Session metadata + message file I/O (sessions/*.json)
28
+ │ ├── settings-normalizer.ts # Settings validation helpers (str, bool, num, enumVal, etc.)
29
+ │ ├── session-helpers.ts # Agent config building, API key injection (pure functions)
30
+ │ ├── session-state.ts # Session state updates (legacy mode/model, config restore)
31
+ │ ├── message-state.ts # Message array transforms (upsert, merge, streaming apply)
32
+ │ ├── message-sender.ts # Prompt preparation + sending (pure functions)
33
+ │ ├── chat-exporter.ts # Markdown export with frontmatter
34
+ │ ├── view-registry.ts # Multi-view management, focus, broadcast
35
+ │ └── update-checker.ts # Agent/plugin version checking
36
+
37
+ ├── hooks/ # React Custom Hooks (state + logic)
38
+ │ ├── useAgent.ts # Facade: composes useAgentSession + useAgentMessages
39
+ │ ├── useAgentSession.ts # Session lifecycle, config options, optimistic updates
40
+ │ ├── useAgentMessages.ts # Message state, streaming (RAF batch), permissions
41
+ │ ├── useSuggestions.ts # @[[note]] mentions + /command suggestions (unified)
42
+ │ ├── useSessionHistory.ts # Session list/load/resume/fork, 5-min cache
43
+ │ ├── useChatActions.ts # Business callbacks (send, newChat, export, restart, etc.)
44
+ │ ├── useHistoryModal.ts # Session history modal lifecycle
45
+ │ └── useSettings.ts # Settings subscription (useSyncExternalStore)
46
+
47
+ ├── ui/ # React Components
48
+ │ ├── ChatContext.ts # React Context (plugin, acpClient, vaultService, settingsService)
49
+ │ ├── ChatPanel.tsx # Orchestrator: calls hooks, workspace events, rendering
50
+ │ ├── ChatView.tsx # Sidebar view (ItemView + Context Provider)
51
+ │ ├── FloatingChatView.tsx # Floating window (position/drag/resize + Context Provider)
52
+ │ ├── FloatingButton.tsx # Draggable launch button
53
+ │ ├── ChatHeader.tsx # Header (sidebar + floating variants)
54
+ │ ├── MessageList.tsx # Virtualized message list (@tanstack/react-virtual)
55
+ │ ├── MessageBubble.tsx # Single message (content dispatch, copy button)
56
+ │ ├── ToolCallBlock.tsx # Tool call display + diff (word-level highlighting)
57
+ │ ├── TerminalBlock.tsx # Terminal output polling
58
+ │ ├── InputArea.tsx # Textarea, attachments, mentions, history
59
+ │ ├── InputToolbar.tsx # Config/mode/model selectors, usage, send button
60
+ │ ├── SuggestionPopup.tsx # Mention/command dropdown
61
+ │ ├── PermissionBanner.tsx # Permission request buttons
62
+ │ ├── ErrorBanner.tsx # Error/notification overlay
63
+ │ ├── SessionHistoryModal.tsx # Session history modal (list + confirm delete)
64
+ │ ├── SettingsTab.ts # Plugin settings UI
65
+ │ ├── view-host.ts # IChatViewHost interface
66
+ │ └── shared/
67
+ │ ├── IconButton.tsx # Icon button + Lucide icon wrapper
68
+ │ ├── MarkdownRenderer.tsx # Obsidian markdown rendering
69
+ │ └── AttachmentStrip.tsx # Attachment preview strip
70
+
71
+ ├── utils/ # Shared Utilities (pure functions)
72
+ │ ├── platform.ts # Shell, WSL, Windows env, command building
73
+ │ ├── paths.ts # Path resolution, file:// URI
74
+ │ ├── error-utils.ts # ACP error conversion
75
+ │ ├── mention-parser.ts # @[[note]] detection/extraction
76
+ │ └── logger.ts # Debug-mode logger
77
+
78
+ ├── plugin.ts # Obsidian plugin lifecycle, commands, view management
79
+ └── main.ts # Entry point (re-exports plugin)
80
+ ```
81
+
82
+ ## Architectural Layers
83
+
84
+ ### 1. Types Layer (`src/types/`)
85
+
86
+ **Purpose**: Pure type definitions. No logic, no dependencies.
87
+
88
+ | File | Contents |
89
+ |------|----------|
90
+ | `chat.ts` | ChatMessage, MessageContent (8+ type union), Role, ToolCallStatus, ToolKind, AttachedFile, ActivePermission, PromptContent |
91
+ | `session.ts` | ChatSession, SessionState, SessionUpdate (12-type union incl. ProcessErrorUpdate), SessionConfigOption, Capabilities, SessionInfo |
92
+ | `agent.ts` | AgentEnvVar, BaseAgentSettings, ClaudeAgentSettings, GeminiAgentSettings, CodexAgentSettings |
93
+ | `errors.ts` | AcpErrorCode, AcpError, ProcessError, ErrorInfo |
94
+
95
+ ---
96
+
97
+ ### 2. ACP Layer (`src/acp/`)
98
+
99
+ **Purpose**: Isolate ACP protocol dependency. All `@agentclientprotocol/sdk` imports are confined here.
100
+
101
+ | File | Purpose |
102
+ |------|---------|
103
+ | `acp-client.ts` | UI-facing API: process spawn/kill, JSON-RPC communication, session management. Owns AcpHandler + managers. Single exit point: `onSessionUpdate` (multiple listeners via Set). |
104
+ | `acp-handler.ts` | SDK-facing: receives sessionUpdate, requestPermission, terminal ops. Filters by `currentSessionId`. Broadcasts to all listeners. |
105
+ | `type-converter.ts` | Converts ACP SDK types to internal types (change buffer for protocol updates) |
106
+ | `permission-handler.ts` | Permission request queue, auto-approve, Promise-based resolution. All UI updates via `onSessionUpdate` (no separate callback path). |
107
+ | `terminal-handler.ts` | Terminal process create/output/kill, stdout/stderr buffering |
108
+
109
+ **Key design**: All agent events (messages, session updates, permissions, errors) flow through a single `onSessionUpdate` channel. No special paths.
110
+
111
+ ---
112
+
113
+ ### 3. Services Layer (`src/services/`)
114
+
115
+ **Purpose**: Non-React business logic. Classes and pure functions. **No React imports.**
116
+
117
+ | File | Purpose |
118
+ |------|---------|
119
+ | `vault-service.ts` | `VaultService` class — vault note access, fuzzy search, CM6 selection tracking. Exports `IVaultAccess`, `NoteMetadata`. |
120
+ | `settings-service.ts` | `SettingsService` class — reactive settings store (observer pattern). Delegates session storage to `SessionStorage`. Exports `ISettingsAccess`. |
121
+ | `session-storage.ts` | `SessionStorage` class — session metadata CRUD (in plugin settings) + message file I/O (sessions/*.json). |
122
+ | `settings-normalizer.ts` | Pure functions — settings validation helpers (`str`, `bool`, `num`, `enumVal`, `obj`, `strRecord`, `xyPoint`), `toAgentConfig`, `parseChatFontSize`. |
123
+ | `session-helpers.ts` | Pure functions — agent config building, API key injection, agent settings resolution |
124
+ | `session-state.ts` | Pure functions — legacy mode/model application, config option restoration |
125
+ | `message-state.ts` | Pure functions — message array transforms (streaming apply, tool call upsert with O(1) index, permission scanning) |
126
+ | `message-sender.ts` | Pure functions — prompt preparation (embedded context vs XML text, shared helpers), sending with auth retry |
127
+ | `chat-exporter.ts` | `ChatExporter` class — markdown export with frontmatter, image handling |
128
+ | `view-registry.ts` | `ChatViewRegistry` class — multi-view focus tracking, broadcast commands. Exports `IChatViewContainer`. |
129
+ | `update-checker.ts` | Agent version checking via npm registry |
130
+
131
+ ---
132
+
133
+ ### 4. Hooks Layer (`src/hooks/`)
134
+
135
+ **Purpose**: React state management. Hook composition via useAgent facade.
136
+
137
+ | Hook | Responsibility |
138
+ |------|---------------|
139
+ | `useAgent` | Facade: composes useAgentSession + useAgentMessages. Single `onSessionUpdate` subscription. Return is `useMemo`-wrapped. |
140
+ | `useAgentSession` | Session lifecycle (create/close/restart), mode/model/configOption with optimistic updates. Uses `sessionRef` pattern. |
141
+ | `useAgentMessages` | Message state, RAF-batched streaming, permissions (activePermission derivation, approve/reject) |
142
+ | `useSuggestions` | @[[note]] mentions + /command suggestions (unified). Return is `useMemo`-wrapped. |
143
+ | `useSessionHistory` | Session list/load/resume/fork, local session storage, 5-min cache. Return is `useMemo`-wrapped. |
144
+ | `useChatActions` | Business callbacks (send, newChat, export, restart, config changes). Individual method deps for stability. |
145
+ | `useHistoryModal` | Session history modal lifecycle (lazy creation, props sync) |
146
+ | `useSettings` | Settings subscription via useSyncExternalStore |
147
+
148
+ **Dependency Rule**: Hooks import from `types/`, `acp/`, `services/`, `utils/`. Never from `ui/`.
149
+
150
+ ---
151
+
152
+ ### 5. UI Layer (`src/ui/`)
153
+
154
+ **Purpose**: React components. Rendering and user interaction.
155
+
156
+ #### Core Architecture
157
+
158
+ **ChatContext** provides shared services to the component tree:
159
+ ```typescript
160
+ interface ChatContextValue {
161
+ plugin: AgentClientPlugin;
162
+ acpClient: AcpClient;
163
+ vaultService: VaultService;
164
+ settingsService: SettingsService;
165
+ }
166
+ ```
167
+
168
+ **ChatPanel** is the central orchestrator:
169
+ - Calls hooks: useAgent, useSuggestions, useSessionHistory, useChatActions, useHistoryModal, useSettings
170
+ - Does NOT route session updates (useAgent handles that internally)
171
+ - Handles workspace events via ref pattern (stable event registration)
172
+ - Renders ChatHeader, MessageList, InputArea directly
173
+
174
+ **ChatView** (sidebar) and **FloatingChatView** (floating window) are thin wrappers:
175
+ - Create services (AcpClient, VaultService) in lifecycle methods
176
+ - Provide ChatContext
177
+ - Render ChatPanel with `variant` prop
178
+ - Implement IChatViewContainer for broadcast commands
179
+
180
+ #### Component Tree
181
+
182
+ ```
183
+ ChatView / FloatingChatView
184
+ └── ChatContextProvider
185
+ └── ChatPanel (variant="sidebar" | "floating")
186
+ ├── ChatHeader (variant-based rendering)
187
+ ├── MessageList (virtualized via @tanstack/react-virtual)
188
+ │ └── MessageBubble (per message, React.memo)
189
+ │ ├── ToolCallBlock (React.memo) → PermissionBanner
190
+ │ ├── TerminalBlock (React.memo)
191
+ │ └── MarkdownRenderer
192
+ ├── InputArea
193
+ │ ├── SuggestionPopup (mentions / commands)
194
+ │ ├── ErrorBanner
195
+ │ ├── AttachmentStrip
196
+ │ └── InputToolbar (config/mode/model/usage/send)
197
+ └── SessionHistoryModal (imperative, via useHistoryModal)
198
+ ```
199
+
200
+ ---
201
+
202
+ ### 6. Utils Layer (`src/utils/`)
203
+
204
+ **Purpose**: Pure utility functions. No React, no Obsidian dependencies (except `platform.ts`).
205
+
206
+ | File | Purpose |
207
+ |------|---------|
208
+ | `platform.ts` | Shell detection, WSL path conversion, Windows PATH from registry, platform-specific command preparation |
209
+ | `paths.ts` | Path resolution (which/where), file:// URI building, relative path conversion |
210
+ | `error-utils.ts` | ACP error code → user-friendly title/suggestion conversion |
211
+ | `mention-parser.ts` | @[[note]] detection, replacement, extraction from text |
212
+ | `logger.ts` | Singleton logger respecting debugMode setting |
213
+
214
+ ---
215
+
216
+ ## Dependency Flow
217
+
218
+ ```
219
+ ┌─────────────────────────────────────────────────────────────┐
220
+ │ UI Layer │
221
+ │ │
222
+ │ ChatView / FloatingChatView (Context Providers) │
223
+ │ └── ChatPanel (hook composition + rendering) │
224
+ │ ├── ChatHeader, MessageList, InputArea │
225
+ │ └── MessageBubble, ToolCallBlock, etc. │
226
+ └─────────────────────────────┬───────────────────────────────┘
227
+ ↓ calls hooks
228
+ ┌─────────────────────────────┴───────────────────────────────┐
229
+ │ Hooks Layer │
230
+ │ useAgent (facade) → useAgentSession + useAgentMessages │
231
+ │ useSuggestions, useSessionHistory, useChatActions, │
232
+ │ useHistoryModal, useSettings │
233
+ └───────────┬─────────────────────────────┬───────────────────┘
234
+ ↓ calls ↓ reads types
235
+ ┌───────────┴───────────┐ ┌─────────────┴───────────────────┐
236
+ │ Services Layer │ │ Types Layer │
237
+ │ VaultService │ │ chat.ts, session.ts, │
238
+ │ SettingsService │ │ agent.ts, errors.ts │
239
+ │ SessionStorage │ └─────────────────────────────────┘
240
+ │ settings-normalizer │
241
+ │ session-helpers │
242
+ │ session-state │
243
+ │ message-state │
244
+ │ message-sender │
245
+ │ chat-exporter │
246
+ │ view-registry │
247
+ └───────────┬───────────┘
248
+ ↓ communicates
249
+ ┌───────────┴───────────┐
250
+ │ ACP Layer │
251
+ │ acp-client.ts │
252
+ │ acp-handler.ts │
253
+ │ type-converter.ts │
254
+ │ permission-handler │
255
+ │ terminal-handler │
256
+ └───────────────────────┘
257
+
258
+ @agentclientprotocol/sdk
259
+ ```
260
+
261
+ ---
262
+
263
+ ## Design Patterns
264
+
265
+ ### 1. useAgent Facade Pattern
266
+ - `useAgent` composes `useAgentSession` + `useAgentMessages`
267
+ - Single `onSessionUpdate` subscription, dispatches to both sub-hooks
268
+ - ChatPanel calls useAgent, not sub-hooks directly
269
+ - Return is `useMemo`-wrapped for referential stability
270
+
271
+ ### 2. React Context for Services
272
+ - `ChatContext` provides plugin, acpClient, vaultService, settingsService
273
+ - Value is stable (service instances don't change)
274
+ - Eliminates prop drilling for shared dependencies
275
+
276
+ ### 3. Single Event Channel
277
+ - All agent events flow through `onSessionUpdate` (messages, session updates, permissions, errors)
278
+ - No special callback paths (onUpdateMessage, onError removed)
279
+ - AcpHandler filters by `currentSessionId` before broadcasting
280
+
281
+ ### 4. ACP Isolation
282
+ - All `@agentclientprotocol/sdk` imports confined to `acp/`
283
+ - `AcpClient` (UI-facing) and `AcpHandler` (SDK-facing) separate concerns
284
+ - `type-converter.ts` is the change buffer for protocol updates
285
+
286
+ ### 5. Performance Patterns
287
+ - **useMemo for return stability**: useAgent, useSuggestions, useSessionHistory wrap returns in useMemo
288
+ - **sessionRef pattern**: useAgentSession stores session in useRef, reads in callbacks without adding to deps
289
+ - **Individual method deps**: useChatActions uses `agent.sendMessage` not `agent` object in deps
290
+ - **Workspace event refs**: ChatPanel stores handler callbacks in refs, keeping useEffect deps minimal
291
+ - **RAF batching**: useAgentMessages batches streaming updates per animation frame
292
+ - **React.memo**: MessageBubble, ToolCallBlock, TerminalBlock for skip-render optimization
293
+ - **Virtual scroll**: MessageList uses @tanstack/react-virtual
294
+ - **O(1) tool call index**: Map<string, number> for tool call upsert
295
+
296
+ ### 6. Observer Pattern
297
+ - `SettingsService` notifies subscribers on change
298
+ - React components use `useSyncExternalStore`
299
+
300
+ ### 7. Ref Pattern for Callbacks
301
+ - IChatViewContainer callbacks use refs for latest values
302
+ - Workspace event handlers use refs to avoid re-registration
303
+ - Unmount cleanup uses refs to access latest state
304
+
305
+ ---
306
+
307
+ ## Key Benefits
308
+
309
+ ### 1. Flat and Readable
310
+ - 4 layers (types → acp/services → hooks → ui)
311
+ - No port/adapter indirection
312
+ - File names reflect functionality
313
+
314
+ ### 2. ACP Change Resistance
315
+ - Only `acp/` directory needs changes for protocol updates
316
+ - `type-converter.ts` localizes type mapping changes
317
+
318
+ ### 3. Easy Feature Addition
319
+ - New hook: create in `hooks/`, call in `ChatPanel`, wrap return in `useMemo`
320
+ - New message type: add to `types/session.ts`, handle in `useAgentMessages` or `message-state.ts`, render in `MessageBubble`
321
+ - New agent: add settings in `plugin.ts`, configure in `SettingsTab`
322
+
323
+ ### 4. Maintainability
324
+ - ~19,800 lines across 56 files
325
+ - Services testable without React (zero React imports)
326
+ - Clear dependency direction (no circular dependencies)
327
+
328
+ ---
329
+
330
+ ## File Naming Conventions
331
+
332
+ | Pattern | Example |
333
+ |---------|---------|
334
+ | Types | `kebab-case.ts` in `types/` |
335
+ | ACP | `kebab-case.ts` in `acp/` |
336
+ | Services | `kebab-case.ts` in `services/` |
337
+ | Hooks | `use*.ts` in `hooks/` |
338
+ | Components | `PascalCase.tsx` in `ui/` |
339
+ | Utilities | `kebab-case.ts` in `utils/` |
340
+
341
+ ---
342
+
343
+ ## Adding New Features
344
+
345
+ ### Adding a New Hook
346
+ 1. Create `hooks/use[Feature].ts`
347
+ 2. Define state with useState/useReducer
348
+ 3. Call the hook in `ui/ChatPanel.tsx`
349
+ 4. Pass state/callbacks to child components as props
350
+ 5. Wrap return object in `useMemo` if passed as dependency to other hooks
351
+
352
+ ### Adding a New Session Update Type
353
+ 1. Add interface to `types/session.ts`, add to `SessionUpdate` union
354
+ 2. Handle in `acp/acp-handler.ts` `sessionUpdate()` switch
355
+ 3. Convert from ACP type in `acp/type-converter.ts` if needed
356
+ 4. Handle in `hooks/useAgentSession.ts` `handleSessionUpdate()` (for session-level)
357
+ 5. Or handle via `applySingleUpdate()` in `services/message-state.ts` (for message-level)
358
+ 6. No routing needed in ChatPanel — useAgent handles dispatch internally
359
+
360
+ ### Adding a New Agent Type
361
+ 1. Add settings type to `types/agent.ts`
362
+ 2. Add config in `plugin.ts` settings
363
+ 3. Add API key injection in `services/session-helpers.ts`
364
+ 4. Update `ui/SettingsTab.ts` for configuration UI
365
+
366
+ ---
367
+
368
+ ## Migration Notes
369
+
370
+ ### March 2026: Simplified Architecture Refactoring
371
+
372
+ Refactored from Port/Adapter Architecture to simplified layered architecture:
373
+
374
+ - **Removed**: `domain/models/` (9 files → `types/` 4 files), `domain/ports/` (5 files → interfaces moved to implementation files), `adapters/` directory, `components/` directory, `shared/` directory
375
+ - **Added**: `types/`, `acp/`, `services/`, `ui/`, `utils/` flat directories, `ChatPanel` + `ChatContext`
376
+ - **Merged**: VaultAdapter + MentionService → VaultService, useMentions + useAutoMention → useMentions
377
+ - **Removed**: useChatController (god hook → ChatPanel component), Port files (no implementation swapping planned)
378
+ - **Result**: 76 → 50 files, 5 → 4 layers, flat directory structure
379
+
380
+ ### April 2026: Simplification & Performance Refactoring
381
+
382
+ Refactored data flow, hooks, services, and performance:
383
+
384
+ - **ACP wiring**: 3 exit points (onSessionUpdate, onError, setUpdateMessageCallback) → 1 (onSessionUpdate only). Multiple listeners via Set. SessionId filter in AcpHandler.
385
+ - **Hook consolidation**: 7 hooks → 4 public hooks. useSession + useMessages + usePermission → useAgent (facade) + useAgentSession + useAgentMessages. useMentions + useSlashCommands → useSuggestions. New: useChatActions, useHistoryModal.
386
+ - **ChatPanel slimmed**: 1,483 → 936 lines. Session update routing removed (moved to useAgent). Business callbacks extracted to useChatActions. History modal extracted to useHistoryModal. Workspace events stabilized with refs.
387
+ - **Services split**: settings-service.ts (722 lines) → settings-service (285) + session-storage (267) + settings-normalizer (264). Pure functions extracted: message-state.ts, session-state.ts.
388
+ - **plugin.ts cleaned**: loadSettings compressed with helper functions (370 → 120 lines). Legacy floatingChatInstances removed. Double-save fixed.
389
+ - **Performance**: useMemo on hook returns (useAgent, useSuggestions, useSessionHistory). sessionRef pattern in useAgentSession. Individual method deps in useChatActions. Workspace event handler refs in ChatPanel.
390
+ - **Result**: 50 → 56 files, ~19,800 lines. Single event channel. All hooks stabilized.
@@ -0,0 +1,216 @@
1
+ # Contributing to Agent Client Plugin
2
+
3
+ Thank you for your interest in contributing to the Agent Client plugin!
4
+
5
+ ## Before You Start
6
+
7
+ ### Please Open an Issue First
8
+
9
+ **For significant changes, please open an issue before writing code:**
10
+
11
+ - New features
12
+ - Architecture changes
13
+ - Adding or modifying external dependencies
14
+ - Implementing draft/experimental ACP specifications
15
+
16
+ This helps ensure alignment with the project direction and saves time for both contributors and maintainers.
17
+
18
+ **You can submit a PR directly for:**
19
+
20
+ - Obvious bug fixes (typos, crashes, etc.)
21
+ - Fixes for existing issues
22
+ - Documentation improvements
23
+
24
+ ### Project Scope
25
+
26
+ This plugin focuses on **ACP client implementation** + **features that make ACP convenient to use in Obsidian**.
27
+
28
+ **In scope:**
29
+
30
+ - ACP protocol implementation
31
+ - Note mentions (`@[[note]]` to pass note content to agents)
32
+ - Obsidian-specific UI integration
33
+
34
+ **Out of scope:**
35
+
36
+ - Features achievable via standard protocols like MCP (these should be provided as MCP servers for a consistent experience across all agents)
37
+ - Agent-specific features (these should be handled via agent-specific config files, e.g., `.claude/` directory)
38
+
39
+ ## Development Setup
40
+
41
+ ### Prerequisites
42
+
43
+ - Node.js 18.x or later
44
+ - npm
45
+
46
+ ### Setup Steps
47
+
48
+ ```bash
49
+ # Navigate to your vault's plugins directory
50
+ cd /path/to/your/vault/.obsidian/plugins
51
+
52
+ # Clone the repository as "agent-client"
53
+ # The directory name must match the id in manifest.json
54
+ git clone https://github.com/RAIT-09/obsidian-agent-client.git agent-client
55
+ cd agent-client
56
+
57
+ # Install dependencies
58
+ npm install
59
+
60
+ # Start development build (watch mode)
61
+ npm run dev
62
+ ```
63
+
64
+ ### Testing in Obsidian
65
+
66
+ 1. After cloning to `.obsidian/plugins/agent-client`, run `npm run dev`
67
+ 2. Enable the plugin in Obsidian Settings → Community Plugins
68
+ 3. Code changes trigger automatic rebuilds, but you need to reload the plugin (toggle it off/on in Community Plugins) to see changes
69
+
70
+ ## Available Commands
71
+
72
+ | Command | Description |
73
+ | ------------------- | ------------------------------------------------ |
74
+ | `npm run dev` | Development build (watch mode) |
75
+ | `npm run build` | Production build (includes TypeScript type check)|
76
+ | `npm run lint` | Run ESLint |
77
+ | `npm run lint:fix` | Run ESLint with auto-fix |
78
+ | `npm run format` | Format code with Prettier |
79
+ | `npm run format:check` | Check formatting (used in CI) |
80
+
81
+ ## Code Style
82
+
83
+ ### Prettier Configuration
84
+
85
+ | Setting | Value |
86
+ | -------------- | ------------- |
87
+ | Indentation | Tabs (width 4)|
88
+ | Semicolons | Yes |
89
+ | Quotes | Double |
90
+ | Trailing comma | All |
91
+ | Print width | 80 |
92
+ | End of line | LF |
93
+
94
+ ### ESLint
95
+
96
+ We use `eslint-plugin-obsidianmd` for Obsidian-specific rules and `typescript-eslint` for TypeScript.
97
+
98
+ ### Obsidian Plugin Guidelines
99
+
100
+ 1. **No innerHTML/outerHTML** — Use `createEl`, `createDiv`, `createSpan`
101
+ 2. **Don't detach leaves in onunload** — This is an anti-pattern
102
+ 3. **Styles in CSS only** — No JS style manipulation
103
+ 4. **Use Platform API** — Don't use `process.platform`
104
+ 5. **Minimize `any`** — Use proper types
105
+
106
+ ### File Naming Conventions
107
+
108
+ - **Types**: `kebab-case.ts` in `types/`
109
+ - **ACP**: `kebab-case.ts` in `acp/`
110
+ - **Services**: `kebab-case.ts` in `services/`
111
+ - **Hooks**: `use*.ts` in `hooks/`
112
+ - **Components**: `PascalCase.tsx` in `ui/`
113
+ - **Utilities**: `kebab-case.ts` in `utils/`
114
+
115
+ ## Branch Naming
116
+
117
+ ```
118
+ {username}/{type}/{description}
119
+ ```
120
+
121
+ **Types:**
122
+
123
+ - `feature/` — New feature
124
+ - `fix/` — Bug fix
125
+ - `refactor/` — Refactoring
126
+ - `docs/` — Documentation
127
+ - `hotfix/` — Urgent fix
128
+
129
+ **Examples:**
130
+
131
+ - `yourname/feature/add-export`
132
+ - `yourname/fix/message-rendering`
133
+
134
+ ## Commit Messages
135
+
136
+ We recommend [Conventional Commits](https://www.conventionalcommits.org/) style:
137
+
138
+ ```
139
+ <type>: <description>
140
+
141
+ <optional body>
142
+ ```
143
+
144
+ **Types:**
145
+
146
+ - `feat:` — New feature
147
+ - `fix:` — Bug fix
148
+ - `refactor:` — Refactoring
149
+ - `docs:` — Documentation
150
+ - `chore:` — Build/dependencies
151
+ - `style:` — Formatting (no functional changes)
152
+
153
+ ## Pull Request Process
154
+
155
+ ### Workflow
156
+
157
+ 1. Create a branch from `master`
158
+ - `master` is the stable branch, `dev` is for development
159
+ - Feature PRs typically target `dev`, hotfixes target `master`
160
+ 2. Make your changes and commit
161
+ 3. Create a pull request
162
+ 4. Ensure CI passes (lint, build)
163
+ 5. Wait for review
164
+
165
+ ### PR Checklist
166
+
167
+ Before submitting, please verify:
168
+
169
+ - [ ] `npm run lint` passes
170
+ - [ ] `npm run build` passes
171
+ - [ ] Tested in Obsidian
172
+ - [ ] Existing functionality still works
173
+ - [ ] Documentation updated if needed
174
+
175
+ ### CI
176
+
177
+ Pull requests automatically run:
178
+
179
+ - ESLint (`npx eslint src/`)
180
+ - Build (`npm run build`)
181
+
182
+ Please ensure these pass locally before submitting.
183
+
184
+ **Note:** "Use sentence case for UI text" lint errors are acceptable for brand names and proper nouns (e.g., "Claude Code", "Gemini CLI").
185
+
186
+ ## Architecture Overview
187
+
188
+ ```
189
+ src/
190
+ ├── types/ # Pure type definitions (no logic, no dependencies)
191
+ ├── acp/ # ACP protocol layer (SDK confined here)
192
+ ├── services/ # Non-React business logic + pure functions
193
+ ├── hooks/ # React custom hooks (useAgent facade + sub-hooks)
194
+ ├── ui/ # React components (ChatPanel orchestrator)
195
+ └── utils/ # Shared utility functions
196
+ ```
197
+
198
+ ### Architecture Principles
199
+
200
+ 1. **useAgent as facade** — Composes useAgentSession + useAgentMessages. Single `onSessionUpdate` subscription.
201
+ 2. **Services have zero React imports** — Pure functions and classes in `services/`
202
+ 3. **ACP isolation** — All `@agentclientprotocol/sdk` imports confined to `acp/`
203
+ 4. **Types have zero deps** — No `obsidian`, no SDK, no React in `types/`
204
+ 5. **Single event channel** — All agent events flow through `onSessionUpdate`. No special callback paths.
205
+
206
+ For more details, see `ARCHITECTURE.md`.
207
+
208
+ ## ACP Notes
209
+
210
+ - Prioritize implementations that conform to the official (stable) ACP specification
211
+ - If implementing draft/experimental specs, please discuss in an issue first
212
+ - Implementations should work with official ACP-compatible agents (e.g., `@agentclientprotocol/claude-agent-acp`)
213
+
214
+ ## Questions?
215
+
216
+ Open an issue if you have any questions!