@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,13 @@
1
+ import { type App } from "@lapis-notes/api";
2
+ import { type Component } from "svelte";
3
+ import type { CatalogGroup, CatalogToolRow } from "./types";
4
+ type $$ComponentProps = {
5
+ app: App;
6
+ loadCatalog: () => Promise<CatalogGroup[]>;
7
+ onToggleTool: (tool: CatalogToolRow, enabled: boolean) => Promise<void>;
8
+ onOpenSkill: (path: string) => Promise<void>;
9
+ subscribeSettings?: (listener: () => void) => () => void;
10
+ };
11
+ declare const AiCatalogPanel: Component<$$ComponentProps, {}, "">;
12
+ type AiCatalogPanel = ReturnType<typeof AiCatalogPanel>;
13
+ export default AiCatalogPanel;
@@ -0,0 +1 @@
1
+ export declare const AiCatalogViewType = "ai-catalog";
@@ -0,0 +1 @@
1
+ export const AiCatalogViewType = "ai-catalog";
@@ -0,0 +1,22 @@
1
+ import { View, type WorkspaceLeaf } from "@lapis-notes/api";
2
+ import type { AiPluginSettings } from "../settings/ai-settings";
3
+ import type { CatalogGroup, CatalogToolRow } from "./types";
4
+ export type AiCatalogViewHost = {
5
+ loadAiCatalog(): Promise<CatalogGroup[]>;
6
+ setCatalogToolEnabled(tool: CatalogToolRow, enabled: boolean): Promise<void>;
7
+ openCatalogSkill(path: string): Promise<void>;
8
+ subscribeSettings(listener: (patch: Partial<AiPluginSettings>) => void): () => void;
9
+ };
10
+ export declare class AiCatalogView extends View {
11
+ private readonly host;
12
+ private component;
13
+ constructor(leaf: WorkspaceLeaf, host: AiCatalogViewHost);
14
+ getViewType(): string;
15
+ getDisplayText(): string;
16
+ getIcon(): string;
17
+ protected onOpen(): Promise<void>;
18
+ protected onClose(): Promise<void>;
19
+ load(): void;
20
+ unload(): void;
21
+ }
22
+ export { AiCatalogViewType } from "./ai-catalog-view-type";
@@ -0,0 +1,48 @@
1
+ import { View } from "@lapis-notes/api";
2
+ import { mount, unmount } from "svelte";
3
+ import AiCatalogPanel from "./ai-catalog-panel.svelte";
4
+ import { AiCatalogViewType } from "./ai-catalog-view-type";
5
+ export class AiCatalogView extends View {
6
+ host;
7
+ component = null;
8
+ constructor(leaf, host) {
9
+ super(leaf);
10
+ this.host = host;
11
+ }
12
+ getViewType() {
13
+ return AiCatalogViewType;
14
+ }
15
+ getDisplayText() {
16
+ return "Catalog";
17
+ }
18
+ getIcon() {
19
+ return "library";
20
+ }
21
+ onOpen() {
22
+ return Promise.resolve();
23
+ }
24
+ onClose() {
25
+ return Promise.resolve();
26
+ }
27
+ load() {
28
+ this.unload();
29
+ this.containerEl.replaceChildren();
30
+ this.containerEl.classList.add("ai-catalog-view");
31
+ this.component = mount(AiCatalogPanel, {
32
+ target: this.containerEl,
33
+ props: {
34
+ app: this.app,
35
+ loadCatalog: () => this.host.loadAiCatalog(),
36
+ onToggleTool: (tool, enabled) => this.host.setCatalogToolEnabled(tool, enabled),
37
+ onOpenSkill: (path) => this.host.openCatalogSkill(path),
38
+ subscribeSettings: (listener) => this.host.subscribeSettings(() => listener()),
39
+ },
40
+ });
41
+ }
42
+ unload() {
43
+ if (this.component)
44
+ void unmount(this.component);
45
+ this.component = null;
46
+ }
47
+ }
48
+ export { AiCatalogViewType } from "./ai-catalog-view-type";
@@ -0,0 +1,3 @@
1
+ import type { CatalogGroup } from "./types";
2
+ export declare function catalogQueryMatches(query: string, ...fields: readonly (string | undefined)[]): boolean;
3
+ export declare function filterCatalogGroups(groups: readonly CatalogGroup[], query: string): CatalogGroup[];
@@ -0,0 +1,24 @@
1
+ export function catalogQueryMatches(query, ...fields) {
2
+ const needle = query.trim().toLowerCase();
3
+ if (!needle)
4
+ return true;
5
+ return fields.some((field) => field?.toLowerCase().includes(needle));
6
+ }
7
+ export function filterCatalogGroups(groups, query) {
8
+ if (!query.trim())
9
+ return [...groups];
10
+ return groups
11
+ .map((group) => {
12
+ const tools = group.tools.filter((tool) => catalogQueryMatches(query, tool.name, tool.description, tool.effect));
13
+ const commands = group.commands.filter((command) => catalogQueryMatches(query, command.name, `/${command.name}`, command.description));
14
+ const skills = group.skills.filter((skill) => catalogQueryMatches(query, skill.name, skill.description));
15
+ const diagnostics = group.diagnostics.filter((diagnostic) => catalogQueryMatches(query, diagnostic.message, diagnostic.path));
16
+ return { ...group, tools, commands, skills, diagnostics };
17
+ })
18
+ .filter((group) => catalogQueryMatches(query, group.label) ||
19
+ group.tools.length +
20
+ group.commands.length +
21
+ group.skills.length +
22
+ group.diagnostics.length >
23
+ 0);
24
+ }
@@ -0,0 +1,21 @@
1
+ import type { Vault } from "@lapis-notes/api";
2
+ import type { RegisteredAppSkillSource, RegisteredAppSlashCommand, SkillSourceKind } from "@lapis-notes/api/agent-skills";
3
+ import type { RegisteredAppTool } from "@lapis-notes/api/agent-tools";
4
+ import type { UserAgentsCommandStore } from "../commands/user-agents";
5
+ import { type AiPluginSettings } from "../settings/ai-settings";
6
+ import type { LoadedAppSkill } from "../skills/types";
7
+ import type { CatalogGroup, CatalogToolRow } from "./types";
8
+ export interface CollectAiCatalogInput {
9
+ tools: readonly RegisteredAppTool[];
10
+ commands: readonly RegisteredAppSlashCommand[];
11
+ registeredSkills?: readonly RegisteredAppSkillSource[];
12
+ vault: Vault;
13
+ bundled: readonly LoadedAppSkill[];
14
+ settings: AiPluginSettings;
15
+ pluginLabel: (pluginId: string) => string;
16
+ userAgents?: UserAgentsCommandStore;
17
+ scopeDir?: string;
18
+ }
19
+ export declare function collectAiCatalog(input: CollectAiCatalogInput): Promise<CatalogGroup[]>;
20
+ export declare function skillSourceForPath(path: string): SkillSourceKind;
21
+ export declare function catalogToolRows(groups: readonly CatalogGroup[]): CatalogToolRow[];
@@ -0,0 +1,255 @@
1
+ import { SlashCommandCatalog } from "../commands/catalog";
2
+ import { CommandDiscovery } from "../commands/discovery";
3
+ import { isAppToolEnabled, } from "../settings/ai-settings";
4
+ import { BUNDLED_SKILL_NAMES } from "../skills/bundled/research";
5
+ import { parseSkillMarkdown, SkillParseError } from "../skills/parser";
6
+ const SOURCE_RANK = {
7
+ folder: 5,
8
+ vault: 4,
9
+ user: 3,
10
+ extension: 2,
11
+ programmatic: 2,
12
+ bundled: 1,
13
+ };
14
+ export async function collectAiCatalog(input) {
15
+ const groups = new Map();
16
+ const pluginGroup = (pluginId) => {
17
+ const existing = groups.get(pluginId);
18
+ if (existing)
19
+ return existing;
20
+ const created = {
21
+ id: pluginId,
22
+ label: input.pluginLabel(pluginId),
23
+ kind: "plugin",
24
+ tools: [],
25
+ commands: [],
26
+ skills: [],
27
+ diagnostics: [],
28
+ };
29
+ groups.set(pluginId, created);
30
+ return created;
31
+ };
32
+ for (const registered of input.tools) {
33
+ pluginGroup(registered.owner.pluginId).tools.push({
34
+ kind: "tool",
35
+ name: registered.tool.name,
36
+ description: registered.tool.description,
37
+ effect: registered.tool.effect,
38
+ pluginId: registered.owner.pluginId,
39
+ enabled: isAppToolEnabled({ name: registered.tool.name, owner: registered.owner }, input.settings),
40
+ owner: registered.owner,
41
+ });
42
+ }
43
+ const discoveredCommands = await new CommandDiscovery({
44
+ vault: input.vault,
45
+ userAgents: input.userAgents,
46
+ }).discover(input.scopeDir ?? "");
47
+ const catalog = new SlashCommandCatalog();
48
+ catalog.replaceFileCommands(discoveredCommands.commands, discoveredCommands.overlays);
49
+ const reserved = catalog.list();
50
+ const overlayByName = new Map(discoveredCommands.overlays.map((command) => [command.name, command]));
51
+ for (const command of reserved) {
52
+ const overlay = overlayByName.get(command.name);
53
+ pluginGroup("ai").commands.push({
54
+ kind: "command",
55
+ name: command.name,
56
+ description: command.description,
57
+ source: "app",
58
+ path: overlay?.path,
59
+ });
60
+ }
61
+ const reservedNames = new Set(reserved.map((command) => command.name));
62
+ for (const registered of input.commands) {
63
+ if (reservedNames.has(registered.command.name))
64
+ continue;
65
+ pluginGroup(registered.ownerPluginId).commands.push({
66
+ kind: "command",
67
+ name: registered.command.name,
68
+ description: registered.command.description,
69
+ source: "extension",
70
+ });
71
+ }
72
+ for (const command of discoveredCommands.commands) {
73
+ const row = {
74
+ kind: "command",
75
+ name: command.name,
76
+ description: command.description,
77
+ source: command.source,
78
+ path: command.path,
79
+ };
80
+ if (command.source === "user") {
81
+ ensureNamedGroup(groups, "user", "User", "user").commands.push(row);
82
+ }
83
+ else {
84
+ ensureNamedGroup(groups, "folders", "Folders", "folders").commands.push(row);
85
+ }
86
+ }
87
+ const { skills, diagnostics } = await listInventorySkills(input.vault, input.bundled, input.registeredSkills ?? []);
88
+ const winners = new Map();
89
+ for (const skill of skills) {
90
+ const current = winners.get(skill.name);
91
+ if (!current || SOURCE_RANK[skill.source] > SOURCE_RANK[current.source]) {
92
+ winners.set(skill.name, skill);
93
+ }
94
+ }
95
+ for (const skill of skills) {
96
+ const row = {
97
+ ...skill,
98
+ shadowed: winners.get(skill.name) !== skill,
99
+ };
100
+ if (skill.source === "folder" || skill.source === "vault") {
101
+ ensureNamedGroup(groups, "folders", "Folders", "folders").skills.push(row);
102
+ }
103
+ else if (skill.source === "user") {
104
+ ensureNamedGroup(groups, "user", "User", "user").skills.push(row);
105
+ }
106
+ else {
107
+ pluginGroup(skill.pluginId ?? "ai").skills.push(row);
108
+ }
109
+ }
110
+ const listed = [...groups.values()].filter((group) => group.tools.length +
111
+ group.commands.length +
112
+ group.skills.length +
113
+ group.diagnostics.length >
114
+ 0);
115
+ listed.sort((left, right) => {
116
+ const order = (kind) => kind === "plugin" ? 0 : kind === "folders" ? 1 : kind === "user" ? 2 : 3;
117
+ return order(left.kind) - order(right.kind) || left.label.localeCompare(right.label);
118
+ });
119
+ const allDiagnostics = [
120
+ ...diagnostics,
121
+ ...discoveredCommands.diagnostics,
122
+ ];
123
+ if (allDiagnostics.length > 0) {
124
+ listed.push({
125
+ id: "diagnostics",
126
+ label: "Diagnostics",
127
+ kind: "diagnostics",
128
+ tools: [],
129
+ commands: [],
130
+ skills: [],
131
+ diagnostics: allDiagnostics,
132
+ });
133
+ }
134
+ return listed;
135
+ }
136
+ function ensureNamedGroup(groups, id, label, kind) {
137
+ const existing = groups.get(id);
138
+ if (existing)
139
+ return existing;
140
+ const created = {
141
+ id,
142
+ label,
143
+ kind,
144
+ tools: [],
145
+ commands: [],
146
+ skills: [],
147
+ diagnostics: [],
148
+ };
149
+ groups.set(id, created);
150
+ return created;
151
+ }
152
+ async function listInventorySkills(vault, bundled, registeredSkills) {
153
+ const skills = [];
154
+ const diagnostics = [];
155
+ for (const file of vault.getFilesByGlob("**/.agents/skills/**/SKILL.md")) {
156
+ if (file.path.includes("/scripts/") || file.path.includes("/references/")) {
157
+ continue;
158
+ }
159
+ const source = skillSourceForPath(file.path);
160
+ try {
161
+ const loaded = parseSkillMarkdown(await vault.cachedRead(file), {
162
+ path: file.path,
163
+ source,
164
+ root: file.path.replace(/\/SKILL\.md$/u, ""),
165
+ });
166
+ skills.push({
167
+ kind: "skill",
168
+ name: loaded.name,
169
+ description: loaded.description,
170
+ source,
171
+ path: file.path,
172
+ pluginId: source === "bundled" ? "ai" : undefined,
173
+ shadowed: false,
174
+ userInvocable: loaded.userInvocable,
175
+ });
176
+ }
177
+ catch (error) {
178
+ diagnostics.push({
179
+ path: file.path,
180
+ message: error instanceof SkillParseError
181
+ ? error.message
182
+ : "Skill could not be parsed.",
183
+ });
184
+ }
185
+ }
186
+ for (const file of vault.getFilesByGlob(".agents/user/skills/**/SKILL.md")) {
187
+ if (file.path.includes("/scripts/") || file.path.includes("/references/")) {
188
+ continue;
189
+ }
190
+ try {
191
+ const loaded = parseSkillMarkdown(await vault.cachedRead(file), {
192
+ path: file.path,
193
+ source: "user",
194
+ root: file.path.replace(/\/SKILL\.md$/u, ""),
195
+ });
196
+ skills.push({
197
+ kind: "skill",
198
+ name: loaded.name,
199
+ description: loaded.description,
200
+ source: "user",
201
+ path: file.path,
202
+ shadowed: false,
203
+ userInvocable: loaded.userInvocable,
204
+ });
205
+ }
206
+ catch (error) {
207
+ diagnostics.push({
208
+ path: file.path,
209
+ message: error instanceof SkillParseError
210
+ ? error.message
211
+ : "Skill could not be parsed.",
212
+ });
213
+ }
214
+ }
215
+ for (const skill of bundled) {
216
+ if (skills.some((row) => row.name === skill.name && row.source === "bundled")) {
217
+ continue;
218
+ }
219
+ skills.push({
220
+ kind: "skill",
221
+ name: skill.name,
222
+ description: skill.description,
223
+ source: skill.source,
224
+ pluginId: "ai",
225
+ shadowed: false,
226
+ userInvocable: skill.userInvocable,
227
+ });
228
+ }
229
+ for (const registered of registeredSkills) {
230
+ if (registered.kind !== "programmatic" || !registered.skill)
231
+ continue;
232
+ skills.push({
233
+ kind: "skill",
234
+ name: registered.skill.name,
235
+ description: registered.skill.description,
236
+ source: "programmatic",
237
+ pluginId: registered.ownerPluginId,
238
+ shadowed: false,
239
+ userInvocable: registered.skill.userInvocable !== false,
240
+ });
241
+ }
242
+ return { skills, diagnostics };
243
+ }
244
+ export function skillSourceForPath(path) {
245
+ if (path.startsWith(".agents/user/skills/"))
246
+ return "user";
247
+ if (path.startsWith(".agents/skills/")) {
248
+ const name = path.split("/")[2] ?? "";
249
+ return BUNDLED_SKILL_NAMES.has(name) ? "bundled" : "vault";
250
+ }
251
+ return "folder";
252
+ }
253
+ export function catalogToolRows(groups) {
254
+ return groups.flatMap((group) => group.tools);
255
+ }
@@ -0,0 +1,12 @@
1
+ import type { CatalogGroup, CatalogSkillRow } from "./types";
2
+ export type CatalogKindKey = "tools" | "commands" | "skills" | "diagnostics";
3
+ export declare function catalogOwnerKey(groupId: string): string;
4
+ export declare function catalogKindKey(groupId: string, kind: CatalogKindKey): string;
5
+ export declare function catalogToolKey(name: string): string;
6
+ export declare function catalogCommandKey(name: string): string;
7
+ export declare function catalogSkillKey(source: CatalogSkillRow["source"], name: string): string;
8
+ export declare function catalogSkillExpands(_skill: CatalogSkillRow): boolean;
9
+ export declare function collectCatalogFolderKeys(groups: readonly CatalogGroup[]): string[];
10
+ export declare function collectCatalogLeafKeys(groups: readonly CatalogGroup[]): string[];
11
+ export declare function collectCatalogExpandableKeys(groups: readonly CatalogGroup[]): string[];
12
+ export declare function isCatalogFolderKey(key: string): boolean;
@@ -0,0 +1,60 @@
1
+ export function catalogOwnerKey(groupId) {
2
+ return `owner:${groupId}`;
3
+ }
4
+ export function catalogKindKey(groupId, kind) {
5
+ return `kind:${groupId}:${kind}`;
6
+ }
7
+ export function catalogToolKey(name) {
8
+ return `leaf:tool:${name}`;
9
+ }
10
+ export function catalogCommandKey(name) {
11
+ return `leaf:command:${name}`;
12
+ }
13
+ export function catalogSkillKey(source, name) {
14
+ return `leaf:skill:${source}:${name}`;
15
+ }
16
+ export function catalogSkillExpands(_skill) {
17
+ return true;
18
+ }
19
+ export function collectCatalogFolderKeys(groups) {
20
+ const keys = [];
21
+ for (const group of groups) {
22
+ keys.push(catalogOwnerKey(group.id));
23
+ if (group.tools.length > 0) {
24
+ keys.push(catalogKindKey(group.id, "tools"));
25
+ }
26
+ if (group.commands.length > 0) {
27
+ keys.push(catalogKindKey(group.id, "commands"));
28
+ }
29
+ if (group.skills.length > 0) {
30
+ keys.push(catalogKindKey(group.id, "skills"));
31
+ }
32
+ if (group.diagnostics.length > 0) {
33
+ keys.push(catalogKindKey(group.id, "diagnostics"));
34
+ }
35
+ }
36
+ return keys;
37
+ }
38
+ export function collectCatalogLeafKeys(groups) {
39
+ const keys = [];
40
+ for (const group of groups) {
41
+ for (const tool of group.tools) {
42
+ keys.push(catalogToolKey(tool.name));
43
+ }
44
+ for (const command of group.commands) {
45
+ keys.push(catalogCommandKey(command.name));
46
+ }
47
+ for (const skill of group.skills) {
48
+ if (catalogSkillExpands(skill)) {
49
+ keys.push(catalogSkillKey(skill.source, skill.name));
50
+ }
51
+ }
52
+ }
53
+ return keys;
54
+ }
55
+ export function collectCatalogExpandableKeys(groups) {
56
+ return [...collectCatalogFolderKeys(groups), ...collectCatalogLeafKeys(groups)];
57
+ }
58
+ export function isCatalogFolderKey(key) {
59
+ return key.startsWith("owner:") || key.startsWith("kind:");
60
+ }
@@ -0,0 +1,44 @@
1
+ import type { AppToolEffect } from "@lapis-notes/api/agent-tools";
2
+ import type { SkillSourceKind } from "@lapis-notes/api/agent-skills";
3
+ import type { AppToolEnablementOwner } from "../settings/ai-settings";
4
+ import type { SlashCommandSource } from "../commands/types";
5
+ export type CatalogGroupKind = "plugin" | "folders" | "user" | "diagnostics";
6
+ export interface CatalogToolRow {
7
+ kind: "tool";
8
+ name: string;
9
+ description: string;
10
+ effect: AppToolEffect;
11
+ pluginId: string;
12
+ enabled: boolean;
13
+ owner: AppToolEnablementOwner;
14
+ }
15
+ export interface CatalogCommandRow {
16
+ kind: "command";
17
+ name: string;
18
+ description: string;
19
+ source: SlashCommandSource;
20
+ path?: string;
21
+ }
22
+ export interface CatalogSkillRow {
23
+ kind: "skill";
24
+ name: string;
25
+ description: string;
26
+ source: SkillSourceKind;
27
+ path?: string;
28
+ pluginId?: string;
29
+ shadowed: boolean;
30
+ userInvocable: boolean;
31
+ }
32
+ export interface CatalogDiagnosticRow {
33
+ path: string;
34
+ message: string;
35
+ }
36
+ export interface CatalogGroup {
37
+ id: string;
38
+ label: string;
39
+ kind: CatalogGroupKind;
40
+ tools: CatalogToolRow[];
41
+ commands: CatalogCommandRow[];
42
+ skills: CatalogSkillRow[];
43
+ diagnostics: CatalogDiagnosticRow[];
44
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,54 @@
1
+ <script lang="ts">
2
+ import { Badge } from "@lapismd/design-core/shadcn/badge";
3
+ import type { ApprovalRequest } from "../core/types";
4
+
5
+ let {
6
+ request,
7
+ disabled = false,
8
+ onRespond,
9
+ }: {
10
+ request: ApprovalRequest;
11
+ disabled?: boolean;
12
+ onRespond(optionId: string): void;
13
+ } = $props();
14
+ </script>
15
+
16
+ <section
17
+ class="ai-agent-request"
18
+ data-ui-component="ai-agent-request"
19
+ data-kind="permission"
20
+ data-testid="ai-approval-card"
21
+ >
22
+ <div data-ui-part="request-heading">
23
+ <strong>{request.title}</strong>
24
+ {#if request.tool}
25
+ <span data-ui-part="tool">{request.tool.name}</span>
26
+ {/if}
27
+ </div>
28
+ {#if request.details?.description || request.details?.path || request.details?.diff}
29
+ <div data-ui-part="approval-details">
30
+ {#if request.details.description}
31
+ <p>{request.details.description}</p>
32
+ {/if}
33
+ {#if request.details.path}
34
+ <code>{request.details.path}</code>
35
+ {/if}
36
+ {#if request.details.diff}
37
+ <pre data-ui-part="approval-diff">{request.details.diff}</pre>
38
+ {/if}
39
+ </div>
40
+ {/if}
41
+ <div data-ui-part="options">
42
+ {#each request.options as option, index (option.id)}
43
+ <button
44
+ type="button"
45
+ data-ui-part="feedback-option"
46
+ disabled={disabled}
47
+ onclick={() => onRespond(option.id)}
48
+ >
49
+ <Badge variant="secondary">{String.fromCharCode(65 + index)}</Badge>
50
+ <span>{option.label}</span>
51
+ </button>
52
+ {/each}
53
+ </div>
54
+ </section>
@@ -0,0 +1,9 @@
1
+ import type { ApprovalRequest } from "../core/types";
2
+ type $$ComponentProps = {
3
+ request: ApprovalRequest;
4
+ disabled?: boolean;
5
+ onRespond(optionId: string): void;
6
+ };
7
+ declare const AiApprovalCard: import("svelte").Component<$$ComponentProps, {}, "">;
8
+ type AiApprovalCard = ReturnType<typeof AiApprovalCard>;
9
+ export default AiApprovalCard;