@lapis-notes/ai 0.1.0

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 (266) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/LICENSE.md +8 -0
  3. package/README.md +20 -0
  4. package/dist/ai-plugin.d.ts +88 -0
  5. package/dist/ai-plugin.js +742 -0
  6. package/dist/bootstrap/build.d.ts +15 -0
  7. package/dist/bootstrap/build.js +28 -0
  8. package/dist/bootstrap/folder-instructions.d.ts +4 -0
  9. package/dist/bootstrap/folder-instructions.js +49 -0
  10. package/dist/bootstrap/format.d.ts +2 -0
  11. package/dist/bootstrap/format.js +46 -0
  12. package/dist/bootstrap/instructions.d.ts +1 -0
  13. package/dist/bootstrap/instructions.js +8 -0
  14. package/dist/bootstrap/types.d.ts +36 -0
  15. package/dist/bootstrap/types.js +3 -0
  16. package/dist/catalog/ai-catalog-panel.svelte +742 -0
  17. package/dist/catalog/ai-catalog-panel.svelte.d.ts +13 -0
  18. package/dist/catalog/ai-catalog-view-type.d.ts +1 -0
  19. package/dist/catalog/ai-catalog-view-type.js +1 -0
  20. package/dist/catalog/ai-catalog-view.d.ts +22 -0
  21. package/dist/catalog/ai-catalog-view.js +48 -0
  22. package/dist/catalog/filter.d.ts +3 -0
  23. package/dist/catalog/filter.js +24 -0
  24. package/dist/catalog/inventory.d.ts +21 -0
  25. package/dist/catalog/inventory.js +255 -0
  26. package/dist/catalog/tree.d.ts +12 -0
  27. package/dist/catalog/tree.js +60 -0
  28. package/dist/catalog/types.d.ts +44 -0
  29. package/dist/catalog/types.js +1 -0
  30. package/dist/chat/ai-approval-card.svelte +54 -0
  31. package/dist/chat/ai-approval-card.svelte.d.ts +9 -0
  32. package/dist/chat/ai-chat-panel.svelte +1288 -0
  33. package/dist/chat/ai-chat-panel.svelte.d.ts +50 -0
  34. package/dist/chat/ai-inventory-result.css +55 -0
  35. package/dist/chat/ai-inventory-result.svelte +63 -0
  36. package/dist/chat/ai-inventory-result.svelte.d.ts +5 -0
  37. package/dist/chat/ai-question-card.svelte +132 -0
  38. package/dist/chat/ai-question-card.svelte.d.ts +9 -0
  39. package/dist/chat/ai-view-bootstrap.d.ts +13 -0
  40. package/dist/chat/ai-view-bootstrap.js +86 -0
  41. package/dist/chat/ai-view-panel.svelte +89 -0
  42. package/dist/chat/ai-view-panel.svelte.d.ts +13 -0
  43. package/dist/chat/ai-view-type.d.ts +1 -0
  44. package/dist/chat/ai-view-type.js +1 -0
  45. package/dist/chat/ai-view.d.ts +60 -0
  46. package/dist/chat/ai-view.js +121 -0
  47. package/dist/chat/chat-controller.svelte.d.ts +82 -0
  48. package/dist/chat/chat-controller.svelte.js +1926 -0
  49. package/dist/chat/chat-items.d.ts +88 -0
  50. package/dist/chat/chat-items.js +9 -0
  51. package/dist/chat/chat-mentions.d.ts +15 -0
  52. package/dist/chat/chat-mentions.js +77 -0
  53. package/dist/chat/chat-result-views.d.ts +5 -0
  54. package/dist/chat/chat-result-views.js +15 -0
  55. package/dist/chat/chat-session.d.ts +28 -0
  56. package/dist/chat/chat-session.js +50 -0
  57. package/dist/chat/chat-status.d.ts +1 -0
  58. package/dist/chat/chat-status.js +3 -0
  59. package/dist/chat/chat-time.d.ts +18 -0
  60. package/dist/chat/chat-time.js +90 -0
  61. package/dist/chat/chat-tool-display.d.ts +17 -0
  62. package/dist/chat/chat-tool-display.js +213 -0
  63. package/dist/chat/chat-tool-identity.d.ts +4 -0
  64. package/dist/chat/chat-tool-identity.js +42 -0
  65. package/dist/chat/chat-trace.d.ts +6 -0
  66. package/dist/chat/chat-trace.js +256 -0
  67. package/dist/chat/live-runtime-unavailable.d.ts +1 -0
  68. package/dist/chat/live-runtime-unavailable.js +1 -0
  69. package/dist/commands/agent.d.ts +8 -0
  70. package/dist/commands/agent.js +38 -0
  71. package/dist/commands/catalog.d.ts +18 -0
  72. package/dist/commands/catalog.js +115 -0
  73. package/dist/commands/discovery.d.ts +36 -0
  74. package/dist/commands/discovery.js +151 -0
  75. package/dist/commands/groups.d.ts +16 -0
  76. package/dist/commands/groups.js +121 -0
  77. package/dist/commands/inspect.d.ts +18 -0
  78. package/dist/commands/inspect.js +29 -0
  79. package/dist/commands/markdown.d.ts +21 -0
  80. package/dist/commands/markdown.js +117 -0
  81. package/dist/commands/parser.d.ts +4 -0
  82. package/dist/commands/parser.js +24 -0
  83. package/dist/commands/reserved.d.ts +4 -0
  84. package/dist/commands/reserved.js +107 -0
  85. package/dist/commands/router.d.ts +17 -0
  86. package/dist/commands/router.js +170 -0
  87. package/dist/commands/seed.d.ts +4 -0
  88. package/dist/commands/seed.js +8 -0
  89. package/dist/commands/types.d.ts +54 -0
  90. package/dist/commands/types.js +1 -0
  91. package/dist/commands/user-agents-node.d.ts +3 -0
  92. package/dist/commands/user-agents-node.js +52 -0
  93. package/dist/commands/user-agents.d.ts +22 -0
  94. package/dist/commands/user-agents.js +40 -0
  95. package/dist/conversations/approval-grants.d.ts +20 -0
  96. package/dist/conversations/approval-grants.js +75 -0
  97. package/dist/conversations/binding-state.d.ts +6 -0
  98. package/dist/conversations/binding-state.js +35 -0
  99. package/dist/conversations/context-handoff.d.ts +25 -0
  100. package/dist/conversations/context-handoff.js +207 -0
  101. package/dist/conversations/conversation-index-coordinator.d.ts +18 -0
  102. package/dist/conversations/conversation-index-coordinator.js +81 -0
  103. package/dist/conversations/conversation-index.d.ts +16 -0
  104. package/dist/conversations/conversation-index.js +125 -0
  105. package/dist/conversations/conversation-locator.d.ts +2 -0
  106. package/dist/conversations/conversation-locator.js +20 -0
  107. package/dist/conversations/conversation-palette.d.ts +18 -0
  108. package/dist/conversations/conversation-palette.js +29 -0
  109. package/dist/conversations/conversation-repository.d.ts +39 -0
  110. package/dist/conversations/conversation-repository.js +213 -0
  111. package/dist/conversations/handoff-summary.d.ts +48 -0
  112. package/dist/conversations/handoff-summary.js +269 -0
  113. package/dist/conversations/hashes.d.ts +5 -0
  114. package/dist/conversations/hashes.js +40 -0
  115. package/dist/conversations/history-creation-scope.d.ts +12 -0
  116. package/dist/conversations/history-creation-scope.js +44 -0
  117. package/dist/conversations/jsonl.d.ts +10 -0
  118. package/dist/conversations/jsonl.js +41 -0
  119. package/dist/conversations/memory-transcript-store.d.ts +15 -0
  120. package/dist/conversations/memory-transcript-store.js +119 -0
  121. package/dist/conversations/paths.d.ts +14 -0
  122. package/dist/conversations/paths.js +92 -0
  123. package/dist/conversations/redaction.d.ts +13 -0
  124. package/dist/conversations/redaction.js +94 -0
  125. package/dist/conversations/reveal-scope.d.ts +3 -0
  126. package/dist/conversations/reveal-scope.js +8 -0
  127. package/dist/conversations/scope-resolver.d.ts +11 -0
  128. package/dist/conversations/scope-resolver.js +18 -0
  129. package/dist/conversations/scope-tree.d.ts +10 -0
  130. package/dist/conversations/scope-tree.js +71 -0
  131. package/dist/conversations/transcript-projection.d.ts +9 -0
  132. package/dist/conversations/transcript-projection.js +409 -0
  133. package/dist/conversations/transcript-store.d.ts +24 -0
  134. package/dist/conversations/transcript-store.js +27 -0
  135. package/dist/conversations/types.d.ts +224 -0
  136. package/dist/conversations/types.js +12 -0
  137. package/dist/conversations/validation.d.ts +4 -0
  138. package/dist/conversations/validation.js +383 -0
  139. package/dist/conversations/vault-transcript-store.d.ts +22 -0
  140. package/dist/conversations/vault-transcript-store.js +219 -0
  141. package/dist/core/event-queue.d.ts +6 -0
  142. package/dist/core/event-queue.js +39 -0
  143. package/dist/core/types.d.ts +241 -0
  144. package/dist/core/types.js +50 -0
  145. package/dist/history/ai-history-panel.svelte +937 -0
  146. package/dist/history/ai-history-panel.svelte.d.ts +17 -0
  147. package/dist/history/ai-history-view-type.d.ts +1 -0
  148. package/dist/history/ai-history-view-type.js +1 -0
  149. package/dist/history/ai-history-view.d.ts +26 -0
  150. package/dist/history/ai-history-view.js +51 -0
  151. package/dist/history/conversation-history-tree.d.ts +15 -0
  152. package/dist/history/conversation-history-tree.js +71 -0
  153. package/dist/host/agent-workspace.d.ts +6 -0
  154. package/dist/host/agent-workspace.js +16 -0
  155. package/dist/host/create-host-runtimes.d.ts +2 -0
  156. package/dist/host/create-host-runtimes.js +14 -0
  157. package/dist/host/desktop-process-host.d.ts +6 -0
  158. package/dist/host/desktop-process-host.js +74 -0
  159. package/dist/host/host-runtime-availability.d.ts +1 -0
  160. package/dist/host/host-runtime-availability.js +3 -0
  161. package/dist/host/process-host.d.ts +31 -0
  162. package/dist/host/process-host.js +6 -0
  163. package/dist/index.d.ts +69 -0
  164. package/dist/index.js +49 -0
  165. package/dist/jsonl/ai-jsonl-preview.d.ts +27 -0
  166. package/dist/jsonl/ai-jsonl-preview.js +68 -0
  167. package/dist/jsonl/ai-jsonl-view-type.d.ts +1 -0
  168. package/dist/jsonl/ai-jsonl-view-type.js +1 -0
  169. package/dist/jsonl/ai-jsonl-view.d.ts +16 -0
  170. package/dist/jsonl/ai-jsonl-view.js +57 -0
  171. package/dist/jsonl/ai-jsonl-view.svelte +260 -0
  172. package/dist/jsonl/ai-jsonl-view.svelte.d.ts +9 -0
  173. package/dist/memory/candidate-extractor.d.ts +25 -0
  174. package/dist/memory/candidate-extractor.js +191 -0
  175. package/dist/memory/forget-confirmation.d.ts +3 -0
  176. package/dist/memory/forget-confirmation.js +45 -0
  177. package/dist/memory/hashes.d.ts +5 -0
  178. package/dist/memory/hashes.js +37 -0
  179. package/dist/memory/memory-ingestion-coordinator.d.ts +19 -0
  180. package/dist/memory/memory-ingestion-coordinator.js +108 -0
  181. package/dist/memory/memory-record-store.d.ts +62 -0
  182. package/dist/memory/memory-record-store.js +369 -0
  183. package/dist/memory/memory-scheduler.d.ts +21 -0
  184. package/dist/memory/memory-scheduler.js +143 -0
  185. package/dist/memory/memory-tools.d.ts +61 -0
  186. package/dist/memory/memory-tools.js +99 -0
  187. package/dist/memory/native-memory-service.d.ts +72 -0
  188. package/dist/memory/native-memory-service.js +1256 -0
  189. package/dist/memory/paths.d.ts +13 -0
  190. package/dist/memory/paths.js +60 -0
  191. package/dist/memory/runtime-consolidation-provider.d.ts +18 -0
  192. package/dist/memory/runtime-consolidation-provider.js +154 -0
  193. package/dist/memory/types.d.ts +139 -0
  194. package/dist/memory/types.js +1 -0
  195. package/dist/providers/acp-model-provider.d.ts +11 -0
  196. package/dist/providers/acp-model-provider.js +99 -0
  197. package/dist/providers/codex-model-catalog.d.ts +7 -0
  198. package/dist/providers/codex-model-catalog.js +179 -0
  199. package/dist/providers/codex-model-provider.d.ts +12 -0
  200. package/dist/providers/codex-model-provider.js +42 -0
  201. package/dist/providers/model-provider.d.ts +26 -0
  202. package/dist/providers/model-provider.js +26 -0
  203. package/dist/public-components.d.ts +3 -0
  204. package/dist/public-components.js +3 -0
  205. package/dist/registry/runtime-registry.d.ts +11 -0
  206. package/dist/registry/runtime-registry.js +71 -0
  207. package/dist/registry/select-runtime.d.ts +9 -0
  208. package/dist/registry/select-runtime.js +31 -0
  209. package/dist/runtime-adapters.d.ts +16 -0
  210. package/dist/runtime-adapters.js +9 -0
  211. package/dist/runtimes/acp/acp-event-mapper.d.ts +56 -0
  212. package/dist/runtimes/acp/acp-event-mapper.js +237 -0
  213. package/dist/runtimes/acp/acp-runtime.d.ts +46 -0
  214. package/dist/runtimes/acp/acp-runtime.js +165 -0
  215. package/dist/runtimes/acp/desktop-acp-backend.d.ts +16 -0
  216. package/dist/runtimes/acp/desktop-acp-backend.js +243 -0
  217. package/dist/runtimes/codex/app-server-protocol.d.ts +28 -0
  218. package/dist/runtimes/codex/app-server-protocol.js +274 -0
  219. package/dist/runtimes/codex/codex-runtime.d.ts +24 -0
  220. package/dist/runtimes/codex/codex-runtime.js +318 -0
  221. package/dist/runtimes/fake/fake-runtime.d.ts +51 -0
  222. package/dist/runtimes/fake/fake-runtime.js +257 -0
  223. package/dist/sessions/plugin-data.d.ts +8 -0
  224. package/dist/sessions/plugin-data.js +29 -0
  225. package/dist/sessions/session-store.d.ts +47 -0
  226. package/dist/sessions/session-store.js +117 -0
  227. package/dist/settings/acp-agents.d.ts +8 -0
  228. package/dist/settings/acp-agents.js +11 -0
  229. package/dist/settings/ai-settings-tab.d.ts +8 -0
  230. package/dist/settings/ai-settings-tab.js +249 -0
  231. package/dist/settings/ai-settings.d.ts +43 -0
  232. package/dist/settings/ai-settings.js +147 -0
  233. package/dist/settings/app-tool-setting-rows.d.ts +16 -0
  234. package/dist/settings/app-tool-setting-rows.js +30 -0
  235. package/dist/settings/register-ai-settings.d.ts +3 -0
  236. package/dist/settings/register-ai-settings.js +393 -0
  237. package/dist/skills/activation.d.ts +2 -0
  238. package/dist/skills/activation.js +20 -0
  239. package/dist/skills/bundled/lapis-notes.d.ts +3 -0
  240. package/dist/skills/bundled/lapis-notes.js +52 -0
  241. package/dist/skills/bundled/research.d.ts +6 -0
  242. package/dist/skills/bundled/research.js +29 -0
  243. package/dist/skills/discovery.d.ts +21 -0
  244. package/dist/skills/discovery.js +227 -0
  245. package/dist/skills/manifest.d.ts +3 -0
  246. package/dist/skills/manifest.js +39 -0
  247. package/dist/skills/parser.d.ts +12 -0
  248. package/dist/skills/parser.js +124 -0
  249. package/dist/skills/registry.d.ts +21 -0
  250. package/dist/skills/registry.js +89 -0
  251. package/dist/skills/seed.d.ts +5 -0
  252. package/dist/skills/seed.js +18 -0
  253. package/dist/skills/skill-tools.d.ts +8 -0
  254. package/dist/skills/skill-tools.js +113 -0
  255. package/dist/skills/types.d.ts +67 -0
  256. package/dist/skills/types.js +1 -0
  257. package/dist/styles.css +514 -0
  258. package/dist/tools/app-tool-host.d.ts +47 -0
  259. package/dist/tools/app-tool-host.js +419 -0
  260. package/dist/tools/desktop-app-tool-bridge.d.ts +23 -0
  261. package/dist/tools/desktop-app-tool-bridge.js +223 -0
  262. package/dist/tools/mcp-server-registry.d.ts +7 -0
  263. package/dist/tools/mcp-server-registry.js +30 -0
  264. package/manifest.json +34 -0
  265. package/package.json +83 -0
  266. package/styles.css +1 -0
@@ -0,0 +1,742 @@
1
+ import { Notice, Plugin, createVaultFileAppTools, hasNativeDesktopCapability, } from "@lapis-notes/api";
2
+ import { getWorkspaceHostBinding } from "@lapis-notes/api/workspace-host";
3
+ import { AiView, AiViewType } from "./chat/ai-view";
4
+ import AiInventoryResult from "./chat/ai-inventory-result.svelte";
5
+ import { LIVE_RUNTIME_UNAVAILABLE_REASON } from "./chat/live-runtime-unavailable";
6
+ import { AiCatalogView, AiCatalogViewType } from "./catalog/ai-catalog-view";
7
+ import { collectAiCatalog } from "./catalog/inventory";
8
+ import { AiHistoryView, AiHistoryViewType } from "./history/ai-history-view";
9
+ import { AiJsonlView, AiJsonlViewType } from "./jsonl/ai-jsonl-view";
10
+ import { formatFileMention, searchVaultFiles } from "./chat/chat-mentions";
11
+ import { createHostAgentRuntimes } from "./host/create-host-runtimes";
12
+ import { createAgentProcessHost } from "./host/desktop-process-host";
13
+ import { resolveAgentWorkspace } from "./host/agent-workspace";
14
+ import { AcpModelProvider } from "./providers/acp-model-provider";
15
+ import { ModelProviderRegistry } from "./providers/model-provider";
16
+ import { selectAgentRuntime } from "./registry/select-runtime";
17
+ import { createAgentRuntimeRegistry, } from "./registry/runtime-registry";
18
+ import { FakeAgentRuntime } from "./runtimes/fake/fake-runtime";
19
+ import { equalAiPluginData, parseAiPluginData, serializeAiPluginData, } from "./sessions/plugin-data";
20
+ import { AI_CONVERSATION_PALETTE_PROVIDER_ID, AI_CONVERSATION_PALETTE_TAB, conversationPaletteItem, } from "./conversations/conversation-palette";
21
+ import { ConversationRepository } from "./conversations/conversation-repository";
22
+ import { AiConversationIndex } from "./conversations/conversation-index";
23
+ import { ConversationIndexCoordinator } from "./conversations/conversation-index-coordinator";
24
+ import { ConversationScopeResolver } from "./conversations/scope-resolver";
25
+ import { revealConversationScope } from "./conversations/reveal-scope";
26
+ import { hasHiddenApplicationSegment } from "./conversations/paths";
27
+ import { VaultTranscriptStore } from "./conversations/vault-transcript-store";
28
+ import { registerAiSettings } from "./settings/register-ai-settings";
29
+ import { AiSettingsTab } from "./settings/ai-settings-tab";
30
+ import { applyAppToolEnablement, DEFAULT_AI_SETTINGS, mergeAiSettings, } from "./settings/ai-settings";
31
+ import { contributingPluginLabel, registeredAppToolRefs, } from "./settings/app-tool-setting-rows";
32
+ import { createMcpServerContributionRegistry } from "./tools/mcp-server-registry";
33
+ import { AppToolHost } from "./tools/app-tool-host";
34
+ import { DesktopAppToolBridge } from "./tools/desktop-app-tool-bridge";
35
+ import { NativeMemoryService } from "./memory/native-memory-service";
36
+ import { MemoryIngestionCoordinator } from "./memory/memory-ingestion-coordinator";
37
+ import { createMemoryAppTools } from "./memory/memory-tools";
38
+ import { VaultMemoryRecordStore } from "./memory/memory-record-store";
39
+ import { MemoryMaintenanceScheduler } from "./memory/memory-scheduler";
40
+ import { RuntimeMemoryConsolidationProvider } from "./memory/runtime-consolidation-provider";
41
+ import { HandoffSummaryCoordinator, RuntimeHandoffSummaryProvider, } from "./conversations/handoff-summary";
42
+ import { confirmForgetDerivedMemory } from "./memory/forget-confirmation";
43
+ import { conversationMemoryScope } from "./memory/paths";
44
+ import { SkillRegistry, SkillSnapshotStore } from "./skills/registry";
45
+ import { BUNDLED_APP_SKILLS } from "./skills/bundled/research";
46
+ import { seedBundledSkills } from "./skills/seed";
47
+ import { createSkillAppTools } from "./skills/skill-tools";
48
+ import { SlashCommandCatalog } from "./commands/catalog";
49
+ import { CommandDiscovery } from "./commands/discovery";
50
+ import { SlashCommandRouter } from "./commands/router";
51
+ import { seedReservedCommands } from "./commands/seed";
52
+ import { tryCreateNodeUserAgentsStore, } from "./commands/user-agents";
53
+ import manifestSpec from "../../manifest.json";
54
+ export class AiPlugin extends Plugin {
55
+ data = {
56
+ settings: DEFAULT_AI_SETTINGS,
57
+ source: {},
58
+ };
59
+ processHost;
60
+ registry;
61
+ models;
62
+ mcpServers = createMcpServerContributionRegistry();
63
+ appToolHost;
64
+ appToolBridge;
65
+ skillRegistry;
66
+ skillSnapshots = new SkillSnapshotStore();
67
+ slashCatalog;
68
+ slashRouter;
69
+ userAgents;
70
+ #settingsListeners = new Set();
71
+ #conversationMoveListeners = new Set();
72
+ #lastFileScope;
73
+ fakeRuntime = new FakeAgentRuntime({
74
+ requireApproval: false,
75
+ trace: "rich",
76
+ });
77
+ scopeResolver = new ConversationScopeResolver();
78
+ conversations;
79
+ conversationIndex;
80
+ conversationIndexCoordinator;
81
+ memory;
82
+ memoryConsolidationProvider;
83
+ handoffSummaryProvider;
84
+ handoffSummaries;
85
+ memoryIngestionCoordinator;
86
+ memoryScheduler;
87
+ constructor(app, pluginManifest = manifestSpec, options = {}) {
88
+ super(app, pluginManifest);
89
+ this.userAgents = options.userAgents;
90
+ this.conversations = new ConversationRepository(new VaultTranscriptStore(app.vault));
91
+ this.conversationIndex = new AiConversationIndex(this.conversations, app.appDatabase);
92
+ this.conversationIndexCoordinator = new ConversationIndexCoordinator(this.conversationIndex, (operation, location, error) => this.app.logger.warn(`Unable to ${operation} the AI conversation index for ${location.conversationId}`, error));
93
+ this.appToolHost = new AppToolHost(app.agentTools, () => this.getSettings());
94
+ this.appToolBridge = new DesktopAppToolBridge(this.appToolHost);
95
+ this.skillRegistry = new SkillRegistry({
96
+ vault: app.vault,
97
+ appSkills: app.agentSkills,
98
+ bundled: [...BUNDLED_APP_SKILLS],
99
+ extensionRootFor: (pluginId) => this.app.plugins?.plugins.get(pluginId)?.manifest.dir,
100
+ });
101
+ this.slashCatalog = new SlashCommandCatalog(app.agentSlashCommands);
102
+ this.slashCatalog.setFileCommandLoader((scopeDir) => this.refreshFileCommands(scopeDir));
103
+ this.slashRouter = new SlashCommandRouter(this.slashCatalog, this.skillRegistry);
104
+ this.register(() => {
105
+ void this.appToolBridge.close().finally(() => this.appToolHost.close());
106
+ });
107
+ this.processHost = createAgentProcessHost();
108
+ const workspace = this.workspace;
109
+ this.models = new ModelProviderRegistry([
110
+ new AcpModelProvider("codex", { workspace }),
111
+ new AcpModelProvider("cursor", { workspace }),
112
+ ]);
113
+ this.registry = createAgentRuntimeRegistry([
114
+ this.fakeRuntime,
115
+ ...createHostAgentRuntimes(),
116
+ ]);
117
+ this.memoryConsolidationProvider = new RuntimeMemoryConsolidationProvider({
118
+ configuration: () => {
119
+ const settings = this.getSettings();
120
+ return {
121
+ runtimeId: settings.memoryConsolidationRuntime,
122
+ agent: settings.memoryConsolidationAgent,
123
+ model: settings.memoryConsolidationModel,
124
+ };
125
+ },
126
+ resolveRuntime: async (request) => {
127
+ const runtimeId = request.metadata?.runtime;
128
+ const runtime = typeof runtimeId === "string"
129
+ ? this.registry.get(runtimeId)
130
+ : undefined;
131
+ if (!runtime || !(await runtime.supports(request))) {
132
+ throw new Error(`Pinned memory runtime ${String(runtimeId)} is unavailable.`);
133
+ }
134
+ return runtime;
135
+ },
136
+ });
137
+ this.handoffSummaryProvider = new RuntimeHandoffSummaryProvider({
138
+ configuration: () => {
139
+ const settings = this.getSettings();
140
+ return {
141
+ runtime: settings.handoffSummaryRuntime,
142
+ agent: settings.handoffSummaryAgent,
143
+ model: settings.handoffSummaryModel,
144
+ };
145
+ },
146
+ resolveRuntime: async (request) => {
147
+ const runtimeId = request.metadata?.runtime;
148
+ const runtime = typeof runtimeId === "string"
149
+ ? this.registry.get(runtimeId)
150
+ : undefined;
151
+ if (!runtime || !(await runtime.supports(request))) {
152
+ throw new Error(`Pinned handoff-summary runtime ${String(runtimeId)} is unavailable.`);
153
+ }
154
+ return runtime;
155
+ },
156
+ });
157
+ this.handoffSummaries = new HandoffSummaryCoordinator(this.conversations, this.handoffSummaryProvider, () => {
158
+ const settings = this.getSettings();
159
+ return {
160
+ runtime: settings.handoffSummaryRuntime,
161
+ agent: settings.handoffSummaryAgent,
162
+ model: settings.handoffSummaryModel,
163
+ };
164
+ }, () => this.getSettings().handoffSummariesEnabled);
165
+ this.memory = new NativeMemoryService(this.conversations, app.appDatabase, {
166
+ recordStore: new VaultMemoryRecordStore(app.vault),
167
+ consolidationProvider: () => this.getSettings().memoryConsolidationEnabled
168
+ ? this.memoryConsolidationProvider
169
+ : undefined,
170
+ });
171
+ this.memoryIngestionCoordinator = new MemoryIngestionCoordinator(this.conversations, this.memory, (operation, location, error) => this.app.logger.warn(`Unable to ${operation} AI memory${location ? ` for ${location.conversationId}` : ""}`, error));
172
+ this.memoryScheduler = new MemoryMaintenanceScheduler(app.appDatabase, this.memory, {
173
+ onError: (_operation, scope, error) => this.app.logger.warn(`Unable to consolidate AI memory for ${scope.kind}`, error),
174
+ });
175
+ }
176
+ get skills() {
177
+ return this.skillRegistry;
178
+ }
179
+ skillContext = () => {
180
+ const scopeDir = this.createConversationInput().scopeDir;
181
+ return {
182
+ scopeDir,
183
+ availableToolNames: this.app.agentTools
184
+ .list()
185
+ .map((item) => item.tool.name),
186
+ enabledPluginIds: this.app.plugins?.enabledPlugins ?? [this.manifest.id],
187
+ };
188
+ };
189
+ getSettings() {
190
+ return {
191
+ ...this.data.settings,
192
+ defaultModels: { ...this.data.settings.defaultModels },
193
+ disabledAppToolNames: [...this.data.settings.disabledAppToolNames],
194
+ enabledAppToolNames: [...this.data.settings.enabledAppToolNames],
195
+ enabledCommunityToolPluginIds: [
196
+ ...this.data.settings.enabledCommunityToolPluginIds,
197
+ ],
198
+ };
199
+ }
200
+ async updateSettings(patch) {
201
+ const acpAgent = patch.acpAgent ?? this.data.settings.acpAgent;
202
+ const defaultModels = {
203
+ ...this.data.settings.defaultModels,
204
+ ...patch.defaultModels,
205
+ };
206
+ if (patch.defaultModel !== undefined) {
207
+ defaultModels[acpAgent] = patch.defaultModel.trim();
208
+ }
209
+ const nextData = {
210
+ ...this.data,
211
+ settings: mergeAiSettings({
212
+ ...this.data.settings,
213
+ ...patch,
214
+ acpAgent,
215
+ defaultModels,
216
+ }, registeredAppToolRefs(this.app)),
217
+ };
218
+ if (equalAiPluginData(this.data, nextData))
219
+ return;
220
+ this.data = nextData;
221
+ await this.saveData(serializeAiPluginData(this.data));
222
+ for (const listener of this.#settingsListeners)
223
+ listener(patch);
224
+ }
225
+ subscribeSettings(listener) {
226
+ this.#settingsListeners.add(listener);
227
+ return () => this.#settingsListeners.delete(listener);
228
+ }
229
+ subscribeConversationMoves(listener) {
230
+ this.#conversationMoveListeners.add(listener);
231
+ return () => this.#conversationMoveListeners.delete(listener);
232
+ }
233
+ refreshHostRuntimes() {
234
+ for (const runtime of createHostAgentRuntimes()) {
235
+ this.registry.register(runtime);
236
+ }
237
+ }
238
+ liveRuntimeUnavailableReason() {
239
+ if (hasNativeDesktopCapability("agent-runtime"))
240
+ return null;
241
+ return LIVE_RUNTIME_UNAVAILABLE_REASON;
242
+ }
243
+ get workspace() {
244
+ return resolveAgentWorkspace(this.app.vault.adapter);
245
+ }
246
+ createConversationInput(explicitFolder) {
247
+ const activeFile = this.app.workspace.getActiveFile();
248
+ const resolved = this.scopeResolver.resolve({
249
+ explicitFolder,
250
+ activeFile,
251
+ });
252
+ const launchNotePath = activeFile &&
253
+ (!resolved.scopeDir ||
254
+ activeFile.path.startsWith(`${resolved.scopeDir}/`))
255
+ ? activeFile.path
256
+ : undefined;
257
+ return {
258
+ scopeDir: resolved.scopeDir,
259
+ launchNotePath,
260
+ };
261
+ }
262
+ listConversationFolders() {
263
+ const folders = this.app.vault
264
+ .getAllFolders()
265
+ .map((folder) => folder.path.replace(/^\/+|\/+$/gu, ""))
266
+ .filter((path) => !hasHiddenApplicationSegment(path));
267
+ return [...new Set(["", ...folders])].sort((left, right) => left.localeCompare(right));
268
+ }
269
+ currentConversationScope() {
270
+ this.#rememberFileScope();
271
+ return (this.#lastFileScope ??
272
+ this.scopeResolver.resolve({
273
+ activeFile: this.app.workspace.getActiveFile(),
274
+ }).scopeDir);
275
+ }
276
+ #rememberFileScope(leaf) {
277
+ if (leaf?.view.getViewType() === AiViewType)
278
+ return;
279
+ const file = this.app.workspace.getActiveFile();
280
+ if (!file)
281
+ return;
282
+ this.#lastFileScope = this.scopeResolver.resolve({
283
+ activeFile: file,
284
+ }).scopeDir;
285
+ }
286
+ currentAiConversation() {
287
+ const active = this.app.workspace.activeLeaf;
288
+ if (active?.view.getViewType() === AiViewType) {
289
+ const location = conversationLocationFromLeaf(active);
290
+ if (location)
291
+ return location;
292
+ }
293
+ for (const leaf of this.app.workspace.getLeavesOfType(AiViewType)) {
294
+ const location = conversationLocationFromLeaf(leaf);
295
+ if (location)
296
+ return location;
297
+ }
298
+ return null;
299
+ }
300
+ searchAiConversations(query) {
301
+ return this.conversationIndex.search(query);
302
+ }
303
+ searchVaultFiles = async (query, signal) => {
304
+ if (signal.aborted)
305
+ return [];
306
+ const files = this.app.vault.getFiles().map((file) => ({
307
+ path: file.path,
308
+ name: file.basename,
309
+ }));
310
+ return searchVaultFiles(files, query).map((file) => ({
311
+ id: file.path,
312
+ label: file.name,
313
+ value: formatFileMention(file.path),
314
+ description: file.path,
315
+ }));
316
+ };
317
+ fallbackRuntime() {
318
+ return this.fakeRuntime;
319
+ }
320
+ async selectRuntime(request) {
321
+ const requestedRuntime = request.metadata?.runtime;
322
+ if (typeof requestedRuntime === "string") {
323
+ const explicit = requestedRuntime === "fake"
324
+ ? this.fakeRuntime
325
+ : this.registry.get(requestedRuntime);
326
+ if (explicit && (await explicit.supports(request)))
327
+ return explicit;
328
+ throw new Error(`Selected runtime ${requestedRuntime} is unavailable.`);
329
+ }
330
+ return selectAgentRuntime({
331
+ registry: this.registry,
332
+ settings: this.data.settings,
333
+ fake: this.fakeRuntime,
334
+ request: {
335
+ ...request,
336
+ mcpServers: [...(request.mcpServers ?? []), ...this.mcpServers.list()],
337
+ },
338
+ });
339
+ }
340
+ async refreshFileCommands(scopeDir = this.createConversationInput().scopeDir) {
341
+ const discovered = await new CommandDiscovery({
342
+ vault: this.app.vault,
343
+ userAgents: this.userAgents,
344
+ }).discover(scopeDir);
345
+ this.slashCatalog.replaceFileCommands(discovered.commands, discovered.overlays);
346
+ }
347
+ async updateBundledSkills() {
348
+ await seedBundledSkills(this.app.vault, { overwrite: true });
349
+ this.skillRegistry.invalidate();
350
+ }
351
+ async updateReservedCommands() {
352
+ if (!this.userAgents)
353
+ return;
354
+ await seedReservedCommands(this.userAgents, { overwrite: true });
355
+ await this.refreshFileCommands();
356
+ }
357
+ async onload() {
358
+ this.data = parseAiPluginData(await this.loadData());
359
+ if (!this.userAgents && shouldUseHomeUserAgents()) {
360
+ this.userAgents = await tryCreateNodeUserAgentsStore();
361
+ }
362
+ await seedBundledSkills(this.app.vault).catch((error) => this.app.logger.warn("Unable to seed bundled AI skills", error));
363
+ if (this.userAgents) {
364
+ await seedReservedCommands(this.userAgents).catch((error) => this.app.logger.warn("Unable to seed reserved AI commands", error));
365
+ }
366
+ await this.refreshFileCommands();
367
+ this.addSettingTab(new AiSettingsTab(this.app, this));
368
+ registerAiSettings(this);
369
+ for (const tool of createVaultFileAppTools(this.app.vault)) {
370
+ this.registerAgentTool(tool);
371
+ }
372
+ for (const tool of createSkillAppTools({
373
+ registry: this.skillRegistry,
374
+ snapshots: this.skillSnapshots,
375
+ vault: this.app.vault,
376
+ })) {
377
+ this.registerAgentTool(tool);
378
+ }
379
+ for (const tool of createMemoryAppTools(this.memory)) {
380
+ this.registerAgentTool(tool);
381
+ }
382
+ this.registerAgentResultView({
383
+ command: "skills",
384
+ component: AiInventoryResult,
385
+ });
386
+ this.registerAgentResultView({
387
+ command: "tools",
388
+ component: AiInventoryResult,
389
+ });
390
+ this.registerEvent(this.app.vault.on("rename", (file, oldPath) => {
391
+ for (const listener of this.#conversationMoveListeners) {
392
+ listener(oldPath, file.path);
393
+ }
394
+ }));
395
+ this.registerEvent(this.app.workspace.on("active-leaf-change", (leaf) => {
396
+ this.#rememberFileScope(leaf);
397
+ }));
398
+ const scheduleConversationIndexUpdate = (file, oldPath) => {
399
+ this.conversationIndexCoordinator.handleVaultChange(file.path, oldPath);
400
+ };
401
+ const scheduleMemoryIngestion = (file, oldPath) => {
402
+ this.memoryIngestionCoordinator.handleVaultChange(file.path, oldPath);
403
+ };
404
+ const invalidateAgents = (file, oldPath) => {
405
+ if (isAgentsPath(file.path) || (oldPath && isAgentsPath(oldPath))) {
406
+ this.skillRegistry.invalidate();
407
+ void this.refreshFileCommands();
408
+ }
409
+ };
410
+ if (this.userAgents?.subscribe) {
411
+ this.register(this.userAgents.subscribe(() => void this.refreshFileCommands()));
412
+ }
413
+ this.addCommand({
414
+ id: "update-bundled-skills",
415
+ name: "Update bundled skills",
416
+ callback: () => void this.updateBundledSkills(),
417
+ });
418
+ this.addCommand({
419
+ id: "update-reserved-commands",
420
+ name: "Update reserved commands",
421
+ callback: () => void this.updateReservedCommands(),
422
+ });
423
+ this.addCommand({
424
+ id: "rebuild-memory-index",
425
+ name: "Rebuild memory index",
426
+ callback: async () => {
427
+ const result = await this.memory.rebuild();
428
+ new Notice(`Memory index rebuilt (${result.conversations} conversations, ${result.episodes} episodes)`);
429
+ },
430
+ });
431
+ this.addCommand({
432
+ id: "preview-memory-consolidation",
433
+ name: "Preview memory consolidation",
434
+ callback: async () => {
435
+ const preview = await this.memory.previewConsolidation(conversationMemoryScope(this.currentConversationScope()));
436
+ new Notice(`${preview.proposals} memory proposal${preview.proposals === 1 ? "" : "s"} ready from ${preview.candidateIds.length} candidate${preview.candidateIds.length === 1 ? "" : "s"}`);
437
+ },
438
+ });
439
+ this.addCommand({
440
+ id: "run-memory-consolidation",
441
+ name: "Run memory consolidation",
442
+ callback: async () => {
443
+ const result = await this.memory.consolidate(conversationMemoryScope(this.currentConversationScope()));
444
+ new Notice(`Memory consolidation wrote ${result.written} revision${result.written === 1 ? "" : "s"}; ${result.needsReview} need review`);
445
+ },
446
+ });
447
+ this.addCommand({
448
+ id: "show-memory-status",
449
+ name: "Show memory status",
450
+ callback: async () => {
451
+ const [sources, candidates, jobs] = await Promise.all([
452
+ this.app.appDatabase.listMemorySourceStates(),
453
+ this.app.appDatabase.queryMemoryCandidates({ limit: 10_000 }),
454
+ this.app.appDatabase.listMemoryJobs(),
455
+ ]);
456
+ new Notice(`Memory: ${sources.length} conversation source${sources.length === 1 ? "" : "s"}, ${candidates.length} candidate${candidates.length === 1 ? "" : "s"}, ${jobs.filter((job) => job.status === "running").length} active job${jobs.filter((job) => job.status === "running").length === 1 ? "" : "s"}`);
457
+ },
458
+ });
459
+ this.addCommand({
460
+ id: "open-latest-memory-record",
461
+ name: "Open latest memory record",
462
+ callback: async () => {
463
+ const files = new Map([
464
+ ...this.app.vault.getFilesByGlob(".lapis/agents/memory/user/records/*.md"),
465
+ ...this.app.vault.getFilesByGlob(".lapis/agents/memory/workspace/records/*.md"),
466
+ ...this.app.vault.getFilesByGlob("**/.lapis/agents/memory/project/records/*.md"),
467
+ ].map((candidate) => [candidate.path, candidate]));
468
+ const file = [...files.values()].sort((left, right) => right.stat.mtime - left.stat.mtime)[0];
469
+ if (!file) {
470
+ new Notice("No curated memory records yet");
471
+ return;
472
+ }
473
+ await this.app.workspace.openLinkText(file.path, "");
474
+ },
475
+ });
476
+ this.addCommand({
477
+ id: "open-latest-memory-review",
478
+ name: "Open latest memory review",
479
+ callback: async () => {
480
+ const files = new Map([
481
+ ...this.app.vault.getFilesByGlob(".lapis/agents/memory/reviews/*.md"),
482
+ ...this.app.vault.getFilesByGlob("**/.lapis/agents/memory/reviews/*.md"),
483
+ ].map((candidate) => [candidate.path, candidate]));
484
+ const file = [...files.values()].sort((left, right) => right.stat.mtime - left.stat.mtime)[0];
485
+ if (!file) {
486
+ new Notice("No memory review reports yet");
487
+ return;
488
+ }
489
+ await this.app.workspace.openLinkText(file.path, "");
490
+ },
491
+ });
492
+ this.addCommand({
493
+ id: "forget-current-conversation-memory",
494
+ name: "Forget derived memory from current conversation",
495
+ callback: async () => {
496
+ const location = this.currentAiConversation();
497
+ if (!location) {
498
+ new Notice("Open an AI conversation before forgetting its memory");
499
+ return;
500
+ }
501
+ const preview = await this.memory.previewForgetConversation(location);
502
+ if (preview.episodeRefs.length === 0 &&
503
+ preview.candidateIds.length === 0 &&
504
+ preview.memoryIds.length === 0) {
505
+ new Notice("This conversation has no derived memory to forget");
506
+ return;
507
+ }
508
+ if (!(await confirmForgetDerivedMemory(this.app, preview)))
509
+ return;
510
+ const result = await this.memory.forgetConversation(location);
511
+ new Notice(`Forgot derived conversation memory and retracted ${result.retracted} record${result.retracted === 1 ? "" : "s"}; the transcript was preserved`);
512
+ },
513
+ });
514
+ this.registerEvent(this.app.agentSkills.on("changed", () => this.skillRegistry.invalidate()));
515
+ this.registerEvent(this.app.vault.on("create", (file) => invalidateAgents(file)));
516
+ this.registerEvent(this.app.vault.on("modify", (file) => invalidateAgents(file)));
517
+ this.registerEvent(this.app.vault.on("delete", (file) => invalidateAgents(file)));
518
+ this.registerEvent(this.app.vault.on("create", scheduleConversationIndexUpdate));
519
+ this.registerEvent(this.app.vault.on("create", scheduleMemoryIngestion));
520
+ this.registerEvent(this.app.vault.on("modify", scheduleConversationIndexUpdate));
521
+ this.registerEvent(this.app.vault.on("modify", scheduleMemoryIngestion));
522
+ this.registerEvent(this.app.vault.on("delete", scheduleConversationIndexUpdate));
523
+ this.registerEvent(this.app.vault.on("delete", scheduleMemoryIngestion));
524
+ this.registerEvent(this.app.vault.on("rename", (file, oldPath) => {
525
+ invalidateAgents(file, oldPath);
526
+ scheduleConversationIndexUpdate(file, oldPath);
527
+ scheduleMemoryIngestion(file, oldPath);
528
+ }));
529
+ this.register(() => this.conversationIndexCoordinator.dispose());
530
+ this.register(() => this.memoryIngestionCoordinator.dispose());
531
+ this.register(this.conversations.subscribe((change) => {
532
+ if (change.type === "upsert") {
533
+ this.memoryScheduler.noteActivity(conversationMemoryScope(change.location.scopeDir));
534
+ }
535
+ }));
536
+ this.register(() => this.memoryScheduler.dispose());
537
+ this.memoryIngestionCoordinator.startCatchUp();
538
+ this.memoryScheduler.start();
539
+ this.registerView(AiJsonlViewType, (leaf) => new AiJsonlView(leaf), { kind: "file" });
540
+ this.registerEditorView({
541
+ id: AiJsonlViewType,
542
+ viewType: AiJsonlViewType,
543
+ label: "AI JSONL",
544
+ description: "Read-only chat and event preview for JSON Lines files.",
545
+ filenamePatterns: [".jsonl", "*.jsonl"],
546
+ priority: "default",
547
+ });
548
+ this.registerExtensions(["jsonl"], AiJsonlViewType);
549
+ this.registerSidebarView(AiViewType, (leaf) => new AiView(leaf, this), {
550
+ side: "right",
551
+ title: "AI",
552
+ icon: "sparkles",
553
+ }, {
554
+ kind: "command",
555
+ command: {
556
+ id: "open-chat",
557
+ name: "Open Chat",
558
+ callback: () => void this.openAiChat(),
559
+ },
560
+ });
561
+ this.addRibbonIcon("sparkles", "Open Chat", () => {
562
+ void this.openAiChat();
563
+ });
564
+ this.registerSidebarView(AiHistoryViewType, (leaf) => new AiHistoryView(leaf, this), {
565
+ side: "right",
566
+ title: "AI conversations",
567
+ icon: "history",
568
+ }, {
569
+ kind: "command",
570
+ command: {
571
+ id: "open-history",
572
+ name: "Open History",
573
+ callback: () => void this.revealConversationHistory(),
574
+ },
575
+ });
576
+ this.registerSidebarView(AiCatalogViewType, (leaf) => new AiCatalogView(leaf, this), {
577
+ side: "left",
578
+ title: "Catalog",
579
+ icon: "library",
580
+ }, {
581
+ kind: "command",
582
+ command: {
583
+ id: "open-catalog",
584
+ name: "Open Catalog",
585
+ callback: () => void this.revealAiCatalog(),
586
+ },
587
+ });
588
+ const { controller } = getWorkspaceHostBinding(this.app.workspace);
589
+ this.register(controller.commands.registerPaletteProvider({
590
+ id: AI_CONVERSATION_PALETTE_PROVIDER_ID,
591
+ tab: AI_CONVERSATION_PALETTE_TAB,
592
+ emptyQueryLimit: 5,
593
+ search: async (query) => {
594
+ const entries = await this.searchAiConversations(query);
595
+ return entries.map((entry) => ({
596
+ ...conversationPaletteItem(entry),
597
+ run: () => void this.openAiConversation(entry.location),
598
+ }));
599
+ },
600
+ }));
601
+ }
602
+ async openAiChat() {
603
+ await this.openAiConversation();
604
+ }
605
+ async openAiConversation(location) {
606
+ const state = location
607
+ ? {
608
+ scopeDir: location.scopeDir,
609
+ conversationId: location.conversationId,
610
+ }
611
+ : {};
612
+ if (location) {
613
+ const existing = this.findMainConversationLeaf(location);
614
+ const target = existing ??
615
+ this.findUnboundMainAiLeaf() ??
616
+ this.app.workspace.getLeaf("tab");
617
+ if (!existing) {
618
+ await target.setViewState({ type: AiViewType, state });
619
+ }
620
+ this.app.workspace.activateLeaf(target, {
621
+ focusRootHost: false,
622
+ source: "api",
623
+ operation: "open-conversation",
624
+ });
625
+ await this.app.workspace.revealLeaf(target);
626
+ revealConversationScope(this.app, location.scopeDir);
627
+ return;
628
+ }
629
+ const existing = this.app.workspace.getLeavesOfType(AiViewType)[0];
630
+ const target = existing ?? this.app.workspace.ensureSideLeaf(AiViewType, "right");
631
+ if (!existing)
632
+ await target.setViewState({ type: AiViewType, state });
633
+ this.app.workspace.activateLeaf(target, {
634
+ focusRootHost: false,
635
+ source: "api",
636
+ operation: "open-ai-chat",
637
+ });
638
+ await this.app.workspace.revealLeaf(target);
639
+ }
640
+ async createAiConversation(scopeDir) {
641
+ const created = await this.conversations.create(this.createConversationInput(scopeDir));
642
+ await this.openAiConversation(created.location);
643
+ }
644
+ async loadAiCatalog() {
645
+ return collectAiCatalog({
646
+ tools: this.app.agentTools.list(),
647
+ commands: this.app.agentSlashCommands.list(),
648
+ registeredSkills: this.app.agentSkills.list(),
649
+ vault: this.app.vault,
650
+ bundled: BUNDLED_APP_SKILLS,
651
+ settings: this.getSettings(),
652
+ pluginLabel: (pluginId) => contributingPluginLabel(this.app, pluginId),
653
+ userAgents: this.userAgents,
654
+ scopeDir: this.createConversationInput().scopeDir,
655
+ });
656
+ }
657
+ async setCatalogToolEnabled(tool, enabled) {
658
+ await this.updateSettings(applyAppToolEnablement(this.getSettings(), { name: tool.name, owner: tool.owner }, enabled, registeredAppToolRefs(this.app)));
659
+ }
660
+ async openCatalogSkill(path) {
661
+ await this.app.workspace.openLinkText(path, "");
662
+ }
663
+ async revealAiCatalog() {
664
+ const existing = this.app.workspace.getLeavesOfType(AiCatalogViewType)[0];
665
+ const target = existing ?? this.app.workspace.ensureSideLeaf(AiCatalogViewType, "left");
666
+ if (!existing) {
667
+ await target.setViewState({ type: AiCatalogViewType, state: {} });
668
+ }
669
+ this.app.workspace.activateLeaf(target, {
670
+ focusRootHost: false,
671
+ source: "api",
672
+ operation: "reveal-ai-catalog",
673
+ });
674
+ await this.app.workspace.revealLeaf(target);
675
+ }
676
+ async revealConversationHistory() {
677
+ const existing = this.app.workspace.getLeavesOfType(AiHistoryViewType)[0];
678
+ const target = existing ?? this.app.workspace.ensureSideLeaf(AiHistoryViewType, "right");
679
+ if (!existing) {
680
+ await target.setViewState({ type: AiHistoryViewType, state: {} });
681
+ }
682
+ this.app.workspace.activateLeaf(target, {
683
+ focusRootHost: false,
684
+ source: "api",
685
+ operation: "reveal-conversation-history",
686
+ });
687
+ await this.app.workspace.revealLeaf(target);
688
+ }
689
+ findMainConversationLeaf(location) {
690
+ let match = null;
691
+ this.app.workspace.iterateRootLeaves((leaf) => {
692
+ if (!match &&
693
+ leaf.view.getViewType() === AiViewType &&
694
+ sameConversationLocation(conversationLocationFromLeaf(leaf), location)) {
695
+ match = leaf;
696
+ }
697
+ });
698
+ return match;
699
+ }
700
+ findUnboundMainAiLeaf() {
701
+ let match = null;
702
+ this.app.workspace.iterateRootLeaves((leaf) => {
703
+ if (!match &&
704
+ leaf.view.getViewType() === AiViewType &&
705
+ conversationLocationFromLeaf(leaf) === null) {
706
+ match = leaf;
707
+ }
708
+ });
709
+ return match;
710
+ }
711
+ }
712
+ export default AiPlugin;
713
+ function shouldUseHomeUserAgents() {
714
+ if (typeof process !== "undefined") {
715
+ if (process.env.VITEST || process.env.STORYBOOK)
716
+ return false;
717
+ }
718
+ return hasNativeDesktopCapability("agent-runtime");
719
+ }
720
+ function isAgentsPath(path) {
721
+ return (path.startsWith(".agents/") ||
722
+ path.includes("/.agents/skills/") ||
723
+ path.includes("/.agents/user/skills/") ||
724
+ path.includes("/.agents/commands/") ||
725
+ path.endsWith("/.agents/skills") ||
726
+ path.endsWith("/.agents/commands") ||
727
+ path.endsWith("/.agents/user/skills"));
728
+ }
729
+ function conversationLocationFromLeaf(leaf) {
730
+ const state = leaf.getViewState().state;
731
+ return typeof state?.scopeDir === "string" &&
732
+ typeof state.conversationId === "string"
733
+ ? {
734
+ scopeDir: state.scopeDir,
735
+ conversationId: state.conversationId,
736
+ }
737
+ : null;
738
+ }
739
+ function sameConversationLocation(left, right) {
740
+ return (left?.scopeDir === right.scopeDir &&
741
+ left.conversationId === right.conversationId);
742
+ }