obsidian-mcp-server 3.7.2 → 3.9.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 (110) hide show
  1. package/AGENTS.md +20 -15
  2. package/CLAUDE.md +20 -15
  3. package/README.md +31 -19
  4. package/changelog/3.8.x/3.8.0.md +38 -0
  5. package/changelog/3.9.x/3.9.0.md +43 -0
  6. package/changelog/template.md +10 -3
  7. package/dist/config/server-config.d.ts +1 -0
  8. package/dist/config/server-config.d.ts.map +1 -1
  9. package/dist/config/server-config.js +30 -19
  10. package/dist/config/server-config.js.map +1 -1
  11. package/dist/index.d.ts +3 -3
  12. package/dist/index.js +27 -15
  13. package/dist/index.js.map +1 -1
  14. package/dist/instructions.d.ts +4 -3
  15. package/dist/instructions.d.ts.map +1 -1
  16. package/dist/instructions.js +23 -12
  17. package/dist/instructions.js.map +1 -1
  18. package/dist/mcp-server/resources/definitions/index.d.ts +2 -2
  19. package/dist/mcp-server/resources/definitions/obsidian-tags.resource.d.ts +3 -2
  20. package/dist/mcp-server/resources/definitions/obsidian-tags.resource.d.ts.map +1 -1
  21. package/dist/mcp-server/resources/definitions/obsidian-tags.resource.js +6 -5
  22. package/dist/mcp-server/resources/definitions/obsidian-tags.resource.js.map +1 -1
  23. package/dist/mcp-server/resources/definitions/obsidian-vault-note.resource.d.ts +2 -2
  24. package/dist/mcp-server/resources/definitions/obsidian-vault-note.resource.js +2 -2
  25. package/dist/mcp-server/resources/definitions/obsidian-vault-note.resource.js.map +1 -1
  26. package/dist/mcp-server/tools/definitions/_shared/suggest-paths.d.ts +15 -6
  27. package/dist/mcp-server/tools/definitions/_shared/suggest-paths.d.ts.map +1 -1
  28. package/dist/mcp-server/tools/definitions/_shared/suggest-paths.js +24 -12
  29. package/dist/mcp-server/tools/definitions/_shared/suggest-paths.js.map +1 -1
  30. package/dist/mcp-server/tools/definitions/index.d.ts +250 -230
  31. package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -1
  32. package/dist/mcp-server/tools/definitions/index.js +6 -4
  33. package/dist/mcp-server/tools/definitions/index.js.map +1 -1
  34. package/dist/mcp-server/tools/definitions/obsidian-append-to-note.tool.d.ts +8 -2
  35. package/dist/mcp-server/tools/definitions/obsidian-append-to-note.tool.d.ts.map +1 -1
  36. package/dist/mcp-server/tools/definitions/obsidian-append-to-note.tool.js +10 -3
  37. package/dist/mcp-server/tools/definitions/obsidian-append-to-note.tool.js.map +1 -1
  38. package/dist/mcp-server/tools/definitions/obsidian-delete-note.tool.d.ts +7 -6
  39. package/dist/mcp-server/tools/definitions/obsidian-delete-note.tool.d.ts.map +1 -1
  40. package/dist/mcp-server/tools/definitions/obsidian-delete-note.tool.js +7 -7
  41. package/dist/mcp-server/tools/definitions/obsidian-delete-note.tool.js.map +1 -1
  42. package/dist/mcp-server/tools/definitions/obsidian-get-note.tool.d.ts +2 -2
  43. package/dist/mcp-server/tools/definitions/obsidian-get-note.tool.d.ts.map +1 -1
  44. package/dist/mcp-server/tools/definitions/obsidian-get-note.tool.js +8 -5
  45. package/dist/mcp-server/tools/definitions/obsidian-get-note.tool.js.map +1 -1
  46. package/dist/mcp-server/tools/definitions/obsidian-list-notes.tool.d.ts +6 -6
  47. package/dist/mcp-server/tools/definitions/obsidian-list-notes.tool.d.ts.map +1 -1
  48. package/dist/mcp-server/tools/definitions/obsidian-list-notes.tool.js +8 -8
  49. package/dist/mcp-server/tools/definitions/obsidian-list-notes.tool.js.map +1 -1
  50. package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.d.ts +4 -4
  51. package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.js +7 -7
  52. package/dist/mcp-server/tools/definitions/obsidian-list-tags.tool.js.map +1 -1
  53. package/dist/mcp-server/tools/definitions/obsidian-manage-frontmatter.tool.d.ts +2 -2
  54. package/dist/mcp-server/tools/definitions/obsidian-manage-frontmatter.tool.d.ts.map +1 -1
  55. package/dist/mcp-server/tools/definitions/obsidian-manage-frontmatter.tool.js +2 -2
  56. package/dist/mcp-server/tools/definitions/obsidian-manage-frontmatter.tool.js.map +1 -1
  57. package/dist/mcp-server/tools/definitions/obsidian-manage-tags.tool.d.ts +2 -2
  58. package/dist/mcp-server/tools/definitions/obsidian-manage-tags.tool.d.ts.map +1 -1
  59. package/dist/mcp-server/tools/definitions/obsidian-manage-tags.tool.js +2 -2
  60. package/dist/mcp-server/tools/definitions/obsidian-manage-tags.tool.js.map +1 -1
  61. package/dist/mcp-server/tools/definitions/obsidian-open-in-ui.tool.d.ts +2 -2
  62. package/dist/mcp-server/tools/definitions/obsidian-open-in-ui.tool.js +3 -3
  63. package/dist/mcp-server/tools/definitions/obsidian-open-in-ui.tool.js.map +1 -1
  64. package/dist/mcp-server/tools/definitions/obsidian-patch-note.tool.d.ts +8 -2
  65. package/dist/mcp-server/tools/definitions/obsidian-patch-note.tool.d.ts.map +1 -1
  66. package/dist/mcp-server/tools/definitions/obsidian-patch-note.tool.js +10 -3
  67. package/dist/mcp-server/tools/definitions/obsidian-patch-note.tool.js.map +1 -1
  68. package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.d.ts +2 -2
  69. package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.js +2 -2
  70. package/dist/mcp-server/tools/definitions/obsidian-replace-in-note.tool.js.map +1 -1
  71. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.d.ts +185 -35
  72. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.d.ts.map +1 -1
  73. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.js +145 -82
  74. package/dist/mcp-server/tools/definitions/obsidian-search-notes.tool.js.map +1 -1
  75. package/dist/mcp-server/tools/definitions/obsidian-write-note.tool.d.ts +8 -2
  76. package/dist/mcp-server/tools/definitions/obsidian-write-note.tool.d.ts.map +1 -1
  77. package/dist/mcp-server/tools/definitions/obsidian-write-note.tool.js +12 -5
  78. package/dist/mcp-server/tools/definitions/obsidian-write-note.tool.js.map +1 -1
  79. package/dist/services/obsidian/jsonlogic-evaluator.d.ts +33 -8
  80. package/dist/services/obsidian/jsonlogic-evaluator.d.ts.map +1 -1
  81. package/dist/services/obsidian/jsonlogic-evaluator.js +171 -32
  82. package/dist/services/obsidian/jsonlogic-evaluator.js.map +1 -1
  83. package/dist/services/obsidian/jsonlogic-worker.d.ts +6 -5
  84. package/dist/services/obsidian/jsonlogic-worker.d.ts.map +1 -1
  85. package/dist/services/obsidian/jsonlogic-worker.js +7 -5
  86. package/dist/services/obsidian/jsonlogic-worker.js.map +1 -1
  87. package/dist/services/obsidian/obsidian-service.d.ts +90 -36
  88. package/dist/services/obsidian/obsidian-service.d.ts.map +1 -1
  89. package/dist/services/obsidian/obsidian-service.js +748 -248
  90. package/dist/services/obsidian/obsidian-service.js.map +1 -1
  91. package/dist/services/obsidian/patch-instruction.d.ts +4 -1
  92. package/dist/services/obsidian/patch-instruction.d.ts.map +1 -1
  93. package/dist/services/obsidian/patch-instruction.js +5 -2
  94. package/dist/services/obsidian/patch-instruction.js.map +1 -1
  95. package/dist/services/obsidian/path-policy.d.ts +67 -23
  96. package/dist/services/obsidian/path-policy.d.ts.map +1 -1
  97. package/dist/services/obsidian/path-policy.js +183 -80
  98. package/dist/services/obsidian/path-policy.js.map +1 -1
  99. package/dist/services/obsidian/section-extractor.d.ts +62 -1
  100. package/dist/services/obsidian/section-extractor.d.ts.map +1 -1
  101. package/dist/services/obsidian/section-extractor.js +387 -51
  102. package/dist/services/obsidian/section-extractor.js.map +1 -1
  103. package/dist/services/obsidian/simple-search.d.ts +62 -0
  104. package/dist/services/obsidian/simple-search.d.ts.map +1 -0
  105. package/dist/services/obsidian/simple-search.js +264 -0
  106. package/dist/services/obsidian/simple-search.js.map +1 -0
  107. package/manifest.json +12 -4
  108. package/package.json +9 -9
  109. package/server.json +23 -11
  110. package/skills/obsidian-guide/SKILL.md +61 -0
@@ -1,23 +1,39 @@
1
1
  /**
2
2
  * @fileoverview obsidian_search_notes — text/jsonlogic/omnisearch search with
3
- * MCP-spec cursor pagination. The `omnisearch` mode is added conditionally by
4
- * the entry point only when the Omnisearch plugin's HTTP server is reachable
5
- * at startup. Text-mode hits carry match locations (the service merges a
6
- * multi-token query's per-token spans) and additionally clip per file via
7
- * `maxMatchesPerHit` so a single match-heavy note can't blow the response
8
- * budget — clipped hits carry `truncated: true` and `totalMatches`.
3
+ * MCP-spec cursor pagination. The `omnisearch` mode is offered only with reads
4
+ * unscoped and the Omnisearch plugin's HTTP server answering at startup
5
+ * (`omnisearchAvailability`). Text-mode hits carry match locations (the
6
+ * service merges a multi-token query's per-token spans) and additionally clip
7
+ * per file via `maxMatchesPerHit` so a single match-heavy note can't blow the
8
+ * response budget — clipped hits carry `truncated: true` and `totalMatches`.
9
9
  * @module mcp-server/tools/definitions/obsidian-search-notes.tool
10
10
  */
11
11
  import { z } from '@cyanheads/mcp-ts-core';
12
12
  import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
13
+ import { type ObsidianService } from '../../../services/obsidian/obsidian-service.js';
14
+ /**
15
+ * Whether `obsidian_search_notes` offers `omnisearch` mode: `offered` when
16
+ * reads are unscoped and the plugin answered the startup probe,
17
+ * `unreachable` when it did not answer, and `withheld` under
18
+ * OBSIDIAN_READ_PATHS or OBSIDIAN_DENY_PATHS, where the plugin is never
19
+ * called. Omnisearch ranks and selects its results over the whole vault, so
20
+ * every one of them depends on notes outside a read scope.
21
+ */
22
+ export type OmnisearchAvailability = 'offered' | 'unreachable' | 'withheld';
23
+ /**
24
+ * Decide {@link OmnisearchAvailability} once, at startup. Under a read scope
25
+ * it is `withheld` with no request, the probe included; otherwise the probe
26
+ * decides.
27
+ */
28
+ export declare function omnisearchAvailability(svc: ObsidianService): Promise<OmnisearchAvailability>;
13
29
  /**
14
30
  * Build the `obsidian_search_notes` tool. The `omnisearch` mode is included
15
- * in the input/output schemas only when `omnisearchReachable` is true so the
16
- * LLM never sees it as an option on a deployment where it can't run. Re-probe
17
- * requires a server restart.
31
+ * in the input/output schemas and the description only when `omnisearch` is
32
+ * `offered`, so the LLM never sees it as an option on a deployment where it
33
+ * can't run or is withheld. Re-probe requires a server restart.
18
34
  */
19
- export declare function buildSearchNotesTool({ omnisearchReachable }: {
20
- omnisearchReachable: boolean;
35
+ export declare function buildSearchNotesTool({ omnisearch }: {
36
+ omnisearch: OmnisearchAvailability;
21
37
  }): import("@cyanheads/mcp-ts-core").ToolDefinition<z.ZodObject<{
22
38
  mode: z.ZodEnum<{
23
39
  jsonlogic: "jsonlogic";
@@ -99,6 +115,10 @@ export declare function buildSearchNotesTool({ omnisearchReachable }: {
99
115
  totalCount: z.ZodNumber;
100
116
  nextCursor: z.ZodOptional<z.ZodString>;
101
117
  truncated: z.ZodBoolean;
118
+ truncatedReason: z.ZodOptional<z.ZodEnum<{
119
+ cap_reached: "cap_reached";
120
+ filtered_after_cap: "filtered_after_cap";
121
+ }>>;
102
122
  }, z.core.$strip>], "mode">;
103
123
  }, z.core.$strip>, readonly [{
104
124
  readonly reason: 'path_prefix_invalid_mode';
@@ -108,14 +128,14 @@ export declare function buildSearchNotesTool({ omnisearchReachable }: {
108
128
  }, {
109
129
  readonly reason: 'query_required';
110
130
  readonly code: JsonRpcErrorCode.ValidationError;
111
- readonly when: '`query` is missing for `text` or `omnisearch` mode (required for both).';
112
- readonly recovery: 'Pass `query` — whitespace-separated tokens, all required, for text mode, or BM25 query syntax (quoted phrases, `-exclusion`, `path:` / `ext:` filters) for omnisearch.';
131
+ readonly when: '`query` is missing in a mode that requires it: every mode but `jsonlogic`.';
132
+ readonly recovery: "Pass `query` as space-separated tokens, all of which a note must contain." | "Pass `query` — space-separated tokens, all required, for text mode, or BM25 query syntax (quoted phrases, `-exclusion`, `path:` / `ext:` filters) for omnisearch.";
113
133
  }, {
114
134
  readonly reason: 'context_length_too_large';
115
135
  readonly thrownBy: 'service';
116
136
  readonly code: JsonRpcErrorCode.ValidationError;
117
- readonly when: 'The Local REST API exhausted its string capacity building one context window per match, so the whole text search failed.';
118
- readonly recovery: 'Lower `contextLength`, or narrow the query so fewer notes match. The ceiling is the product of the two, so a broad query fails at a much smaller window than a narrow one does.';
137
+ readonly when: "The matches would make a response longer than one can be, so the whole text search failed: the Local REST API runs out of string capacity serializing them, or, under OBSIDIAN_READ_PATHS or OBSIDIAN_DENY_PATHS, the readable notes' matches alone would pass the same ceiling. Each match costs its context window plus about 150 characters of offsets and framing.";
138
+ readonly recovery: 'Narrow the query so fewer notes match, and drop very common tokens: every occurrence of each token in a matching note is a match costing about 150 characters beside its window, so a token like `the` can fail even at `contextLength` 0. Lowering `contextLength` helps only while the windows, about twice `contextLength` each, dominate that cost.';
119
139
  }, {
120
140
  readonly reason: 'logic_required';
121
141
  readonly code: JsonRpcErrorCode.ValidationError;
@@ -131,32 +151,95 @@ export declare function buildSearchNotesTool({ omnisearchReachable }: {
131
151
  readonly reason: 'logic_too_costly';
132
152
  readonly thrownBy: 'service';
133
153
  readonly code: JsonRpcErrorCode.ValidationError;
134
- readonly when: "With OBSIDIAN_READ_PATHS set, the server evaluates the JSONLogic tree itself, and the tree passed a bound: nesting deeper than 1,000 levels, more than a work budget, or more than 10 s of evaluation. One work budget is per note — the size of values built by `merge`, `cat`, `map`, and array literals while evaluating that note, up to the note's own size plus 10,000,000 units — and one is per search: 10,000,000 units across every note for returned results, where a result whose JSON is at most 1,024 characters is free and a larger one pays for what it holds beyond its own note.";
154
+ readonly when: "With OBSIDIAN_READ_PATHS or OBSIDIAN_DENY_PATHS set, the server evaluates the JSONLogic tree itself, and the tree passed a bound: nesting deeper than 1,000 levels, more than a work budget, more than 10 s of evaluation, or more than 45 s for the whole search, reading the readable notes included. One work budget is per note — the size of values built by `merge`, `cat`, `map`, and array literals while evaluating that note, up to the note's own size plus 10,000,000 units — and one is per search: 10,000,000 units across every note for returned results, where a result whose JSON is at most 1,024 characters is free and a larger one pays for what it holds beyond its own note.";
135
155
  readonly recovery: "Simplify the tree: nest fewer levels, avoid building arrays or strings many times a note's size with `merge`, `cat`, `map`, or `reduce`, return values drawn from the note rather than large built values or constants, and prefer a simpler `regexp` pattern.";
156
+ }, {
157
+ readonly reason: 'text_search_too_costly';
158
+ readonly thrownBy: 'service';
159
+ readonly code: JsonRpcErrorCode.ValidationError;
160
+ readonly when: 'With OBSIDIAN_READ_PATHS or OBSIDIAN_DENY_PATHS set, the server runs text mode itself, reading every readable note whose path or body holds each token, and reading and matching them took more than 45 s.';
161
+ readonly recovery: 'Add rarer tokens, which every candidate note must contain, so fewer readable notes are read, or ask the operator to narrow OBSIDIAN_READ_PATHS or extend OBSIDIAN_DENY_PATHS.';
162
+ }, {
163
+ readonly reason: 'link_fields_unavailable';
164
+ readonly thrownBy: 'service';
165
+ readonly code: JsonRpcErrorCode.ValidationError;
166
+ readonly when: 'With OBSIDIAN_READ_PATHS or OBSIDIAN_DENY_PATHS set, the JSONLogic tree names `links`, `backlinks`, or `unresolvedLinks` by a fixed `var`, `missing`, or `missing_some` key. Scoped searches leave these fields out, since Obsidian resolves each link across the whole vault, notes outside the scope included; a computed key reads them as null.';
167
+ readonly recovery: 'Find backlinks by body text: `{"regexp": ["\\\\[\\\\[Target Note(\\\\\\\\?\\\\||#|\\\\]\\\\])", {"var": "content"}]}` matches every readable note that wikilinks or embeds `Target Note`. For a note\'s outgoing links, call `obsidian_get_note` with `includeLinks: true`.';
136
168
  }, {
137
169
  readonly reason: 'note_too_deep';
138
170
  readonly thrownBy: 'service';
139
171
  readonly code: JsonRpcErrorCode.SerializationError;
140
- readonly when: 'With OBSIDIAN_READ_PATHS set, a readable note holds data, usually a frontmatter value, nested deeper than the server can hand to its evaluator (about 3,500 levels under Node, more under Bun).';
141
- readonly recovery: 'Flatten the deeply nested value, usually a frontmatter field, in the note the message names, or ask the operator to leave that note out of OBSIDIAN_READ_PATHS; no scoped jsonlogic search runs while it is readable.';
172
+ readonly when: 'With OBSIDIAN_READ_PATHS or OBSIDIAN_DENY_PATHS set, a readable note holds data, usually a frontmatter value, nested deeper than the server can hand to its evaluator (about 3,500 levels under Node, more under Bun).';
173
+ readonly recovery: 'Flatten the deeply nested value, usually a frontmatter field, in the note the message names, or ask the operator to leave that note out of OBSIDIAN_READ_PATHS or add it to OBSIDIAN_DENY_PATHS; no scoped jsonlogic search runs while it is readable.';
142
174
  }, {
143
175
  readonly reason: 'omnisearch_unreachable';
144
176
  readonly thrownBy: 'service';
145
177
  readonly code: JsonRpcErrorCode.ServiceUnavailable;
146
- readonly when: 'Omnisearch was reachable at startup but is now unreachable (Obsidian quit, plugin disabled, or mobile session).';
178
+ readonly when: 'Omnisearch was reachable at startup but did not answer: it is unreachable (Obsidian quit, plugin disabled, or mobile session), answered with a non-2xx status, or took longer than OBSIDIAN_REQUEST_TIMEOUT_MS. One attempt, never retried.';
147
179
  readonly retryable: true;
148
- readonly recovery: 'Restart Obsidian with the Omnisearch plugin enabled, then restart this MCP server so it re-probes the plugin URL.';
149
- }], {
180
+ readonly recovery: 'Confirm Obsidian is running with the Omnisearch plugin enabled and retry, or narrow the query if it was slow. If Omnisearch stays down, restart Obsidian, then restart this MCP server so it re-probes the plugin URL.';
181
+ }] | readonly [{
182
+ readonly reason: 'path_prefix_invalid_mode';
183
+ readonly code: JsonRpcErrorCode.ValidationError;
184
+ readonly when: '`pathPrefix` was provided in a non-text mode (only `text` supports prefix filtering).';
185
+ readonly recovery: 'Drop pathPrefix or switch mode to text for prefix filtering.';
186
+ }, {
187
+ readonly reason: 'query_required';
188
+ readonly code: JsonRpcErrorCode.ValidationError;
189
+ readonly when: '`query` is missing in a mode that requires it: every mode but `jsonlogic`.';
190
+ readonly recovery: "Pass `query` as space-separated tokens, all of which a note must contain." | "Pass `query` — space-separated tokens, all required, for text mode, or BM25 query syntax (quoted phrases, `-exclusion`, `path:` / `ext:` filters) for omnisearch.";
191
+ }, {
192
+ readonly reason: 'context_length_too_large';
193
+ readonly thrownBy: 'service';
194
+ readonly code: JsonRpcErrorCode.ValidationError;
195
+ readonly when: "The matches would make a response longer than one can be, so the whole text search failed: the Local REST API runs out of string capacity serializing them, or, under OBSIDIAN_READ_PATHS or OBSIDIAN_DENY_PATHS, the readable notes' matches alone would pass the same ceiling. Each match costs its context window plus about 150 characters of offsets and framing.";
196
+ readonly recovery: 'Narrow the query so fewer notes match, and drop very common tokens: every occurrence of each token in a matching note is a match costing about 150 characters beside its window, so a token like `the` can fail even at `contextLength` 0. Lowering `contextLength` helps only while the windows, about twice `contextLength` each, dominate that cost.';
197
+ }, {
198
+ readonly reason: 'logic_required';
199
+ readonly code: JsonRpcErrorCode.ValidationError;
200
+ readonly when: '`logic` is missing for `jsonlogic` mode.';
201
+ readonly recovery: 'Pass a JSONLogic tree as `logic`. `glob` and `regexp` take `[PATTERN, VALUE]` — pattern first, e.g. `{"glob": ["Projects/*.md", {"var": "path"}]}`.';
202
+ }, {
203
+ readonly reason: 'logic_invalid';
204
+ readonly thrownBy: 'service';
205
+ readonly code: JsonRpcErrorCode.ValidationError;
206
+ readonly when: 'The JSONLogic tree failed to evaluate against a note — an unrecognized operator, or an operand that could not be evaluated (an uncompilable `regexp` pattern). A mis-arity operator is not rejected: it evaluates to false and the search returns zero hits.';
207
+ readonly recovery: 'Check the operator names and arity. `glob` and `regexp` take `[PATTERN, VALUE]` — pattern first, e.g. `{"regexp": ["^Inbox/", {"var": "path"}]}`; the reverse order compiles the note field as the pattern.';
208
+ }, {
209
+ readonly reason: 'logic_too_costly';
210
+ readonly thrownBy: 'service';
211
+ readonly code: JsonRpcErrorCode.ValidationError;
212
+ readonly when: "With OBSIDIAN_READ_PATHS or OBSIDIAN_DENY_PATHS set, the server evaluates the JSONLogic tree itself, and the tree passed a bound: nesting deeper than 1,000 levels, more than a work budget, more than 10 s of evaluation, or more than 45 s for the whole search, reading the readable notes included. One work budget is per note — the size of values built by `merge`, `cat`, `map`, and array literals while evaluating that note, up to the note's own size plus 10,000,000 units — and one is per search: 10,000,000 units across every note for returned results, where a result whose JSON is at most 1,024 characters is free and a larger one pays for what it holds beyond its own note.";
213
+ readonly recovery: "Simplify the tree: nest fewer levels, avoid building arrays or strings many times a note's size with `merge`, `cat`, `map`, or `reduce`, return values drawn from the note rather than large built values or constants, and prefer a simpler `regexp` pattern.";
214
+ }, {
215
+ readonly reason: 'text_search_too_costly';
216
+ readonly thrownBy: 'service';
217
+ readonly code: JsonRpcErrorCode.ValidationError;
218
+ readonly when: 'With OBSIDIAN_READ_PATHS or OBSIDIAN_DENY_PATHS set, the server runs text mode itself, reading every readable note whose path or body holds each token, and reading and matching them took more than 45 s.';
219
+ readonly recovery: 'Add rarer tokens, which every candidate note must contain, so fewer readable notes are read, or ask the operator to narrow OBSIDIAN_READ_PATHS or extend OBSIDIAN_DENY_PATHS.';
220
+ }, {
221
+ readonly reason: 'link_fields_unavailable';
222
+ readonly thrownBy: 'service';
223
+ readonly code: JsonRpcErrorCode.ValidationError;
224
+ readonly when: 'With OBSIDIAN_READ_PATHS or OBSIDIAN_DENY_PATHS set, the JSONLogic tree names `links`, `backlinks`, or `unresolvedLinks` by a fixed `var`, `missing`, or `missing_some` key. Scoped searches leave these fields out, since Obsidian resolves each link across the whole vault, notes outside the scope included; a computed key reads them as null.';
225
+ readonly recovery: 'Find backlinks by body text: `{"regexp": ["\\\\[\\\\[Target Note(\\\\\\\\?\\\\||#|\\\\]\\\\])", {"var": "content"}]}` matches every readable note that wikilinks or embeds `Target Note`. For a note\'s outgoing links, call `obsidian_get_note` with `includeLinks: true`.';
226
+ }, {
227
+ readonly reason: 'note_too_deep';
228
+ readonly thrownBy: 'service';
229
+ readonly code: JsonRpcErrorCode.SerializationError;
230
+ readonly when: 'With OBSIDIAN_READ_PATHS or OBSIDIAN_DENY_PATHS set, a readable note holds data, usually a frontmatter value, nested deeper than the server can hand to its evaluator (about 3,500 levels under Node, more under Bun).';
231
+ readonly recovery: 'Flatten the deeply nested value, usually a frontmatter field, in the note the message names, or ask the operator to leave that note out of OBSIDIAN_READ_PATHS or add it to OBSIDIAN_DENY_PATHS; no scoped jsonlogic search runs while it is readable.';
232
+ }, ...never[]], {
150
233
  readonly effectiveQuery: z.ZodOptional<z.ZodString>;
151
234
  readonly notice: z.ZodOptional<z.ZodString>;
152
235
  }>;
153
236
  /**
154
237
  * Static specimen for the MCP definition linter (which duck-types tool
155
238
  * exports out of each `.tool.ts` file) and for existing tests that import
156
- * the tool directly. Defaults to `omnisearchReachable: false` — the safe
157
- * baseline that doesn't assume the optional plugin is installed. The entry
158
- * point (`src/index.ts`) builds the live tool via `buildSearchNotesTool`
159
- * with the actual probe result; this export is not the registered tool.
239
+ * the tool directly. Built without the `omnisearch` mode — the safe baseline
240
+ * that doesn't assume the optional plugin is installed. The entry point
241
+ * (`src/index.ts`) builds the live tool via `buildSearchNotesTool` with the
242
+ * startup `omnisearchAvailability`; this export is not the registered tool.
160
243
  * The omnisearch-enabled variant is exercised by tests rather than the
161
244
  * linter (two exports under the same tool name would collide on
162
245
  * `name-unique`).
@@ -242,6 +325,10 @@ export declare const obsidianSearchNotes: import("@cyanheads/mcp-ts-core").ToolD
242
325
  totalCount: z.ZodNumber;
243
326
  nextCursor: z.ZodOptional<z.ZodString>;
244
327
  truncated: z.ZodBoolean;
328
+ truncatedReason: z.ZodOptional<z.ZodEnum<{
329
+ cap_reached: "cap_reached";
330
+ filtered_after_cap: "filtered_after_cap";
331
+ }>>;
245
332
  }, z.core.$strip>], "mode">;
246
333
  }, z.core.$strip>, readonly [{
247
334
  readonly reason: 'path_prefix_invalid_mode';
@@ -251,14 +338,14 @@ export declare const obsidianSearchNotes: import("@cyanheads/mcp-ts-core").ToolD
251
338
  }, {
252
339
  readonly reason: 'query_required';
253
340
  readonly code: JsonRpcErrorCode.ValidationError;
254
- readonly when: '`query` is missing for `text` or `omnisearch` mode (required for both).';
255
- readonly recovery: 'Pass `query` — whitespace-separated tokens, all required, for text mode, or BM25 query syntax (quoted phrases, `-exclusion`, `path:` / `ext:` filters) for omnisearch.';
341
+ readonly when: '`query` is missing in a mode that requires it: every mode but `jsonlogic`.';
342
+ readonly recovery: "Pass `query` as space-separated tokens, all of which a note must contain." | "Pass `query` — space-separated tokens, all required, for text mode, or BM25 query syntax (quoted phrases, `-exclusion`, `path:` / `ext:` filters) for omnisearch.";
256
343
  }, {
257
344
  readonly reason: 'context_length_too_large';
258
345
  readonly thrownBy: 'service';
259
346
  readonly code: JsonRpcErrorCode.ValidationError;
260
- readonly when: 'The Local REST API exhausted its string capacity building one context window per match, so the whole text search failed.';
261
- readonly recovery: 'Lower `contextLength`, or narrow the query so fewer notes match. The ceiling is the product of the two, so a broad query fails at a much smaller window than a narrow one does.';
347
+ readonly when: "The matches would make a response longer than one can be, so the whole text search failed: the Local REST API runs out of string capacity serializing them, or, under OBSIDIAN_READ_PATHS or OBSIDIAN_DENY_PATHS, the readable notes' matches alone would pass the same ceiling. Each match costs its context window plus about 150 characters of offsets and framing.";
348
+ readonly recovery: 'Narrow the query so fewer notes match, and drop very common tokens: every occurrence of each token in a matching note is a match costing about 150 characters beside its window, so a token like `the` can fail even at `contextLength` 0. Lowering `contextLength` helps only while the windows, about twice `contextLength` each, dominate that cost.';
262
349
  }, {
263
350
  readonly reason: 'logic_required';
264
351
  readonly code: JsonRpcErrorCode.ValidationError;
@@ -274,22 +361,85 @@ export declare const obsidianSearchNotes: import("@cyanheads/mcp-ts-core").ToolD
274
361
  readonly reason: 'logic_too_costly';
275
362
  readonly thrownBy: 'service';
276
363
  readonly code: JsonRpcErrorCode.ValidationError;
277
- readonly when: "With OBSIDIAN_READ_PATHS set, the server evaluates the JSONLogic tree itself, and the tree passed a bound: nesting deeper than 1,000 levels, more than a work budget, or more than 10 s of evaluation. One work budget is per note — the size of values built by `merge`, `cat`, `map`, and array literals while evaluating that note, up to the note's own size plus 10,000,000 units — and one is per search: 10,000,000 units across every note for returned results, where a result whose JSON is at most 1,024 characters is free and a larger one pays for what it holds beyond its own note.";
364
+ readonly when: "With OBSIDIAN_READ_PATHS or OBSIDIAN_DENY_PATHS set, the server evaluates the JSONLogic tree itself, and the tree passed a bound: nesting deeper than 1,000 levels, more than a work budget, more than 10 s of evaluation, or more than 45 s for the whole search, reading the readable notes included. One work budget is per note — the size of values built by `merge`, `cat`, `map`, and array literals while evaluating that note, up to the note's own size plus 10,000,000 units — and one is per search: 10,000,000 units across every note for returned results, where a result whose JSON is at most 1,024 characters is free and a larger one pays for what it holds beyond its own note.";
278
365
  readonly recovery: "Simplify the tree: nest fewer levels, avoid building arrays or strings many times a note's size with `merge`, `cat`, `map`, or `reduce`, return values drawn from the note rather than large built values or constants, and prefer a simpler `regexp` pattern.";
366
+ }, {
367
+ readonly reason: 'text_search_too_costly';
368
+ readonly thrownBy: 'service';
369
+ readonly code: JsonRpcErrorCode.ValidationError;
370
+ readonly when: 'With OBSIDIAN_READ_PATHS or OBSIDIAN_DENY_PATHS set, the server runs text mode itself, reading every readable note whose path or body holds each token, and reading and matching them took more than 45 s.';
371
+ readonly recovery: 'Add rarer tokens, which every candidate note must contain, so fewer readable notes are read, or ask the operator to narrow OBSIDIAN_READ_PATHS or extend OBSIDIAN_DENY_PATHS.';
372
+ }, {
373
+ readonly reason: 'link_fields_unavailable';
374
+ readonly thrownBy: 'service';
375
+ readonly code: JsonRpcErrorCode.ValidationError;
376
+ readonly when: 'With OBSIDIAN_READ_PATHS or OBSIDIAN_DENY_PATHS set, the JSONLogic tree names `links`, `backlinks`, or `unresolvedLinks` by a fixed `var`, `missing`, or `missing_some` key. Scoped searches leave these fields out, since Obsidian resolves each link across the whole vault, notes outside the scope included; a computed key reads them as null.';
377
+ readonly recovery: 'Find backlinks by body text: `{"regexp": ["\\\\[\\\\[Target Note(\\\\\\\\?\\\\||#|\\\\]\\\\])", {"var": "content"}]}` matches every readable note that wikilinks or embeds `Target Note`. For a note\'s outgoing links, call `obsidian_get_note` with `includeLinks: true`.';
279
378
  }, {
280
379
  readonly reason: 'note_too_deep';
281
380
  readonly thrownBy: 'service';
282
381
  readonly code: JsonRpcErrorCode.SerializationError;
283
- readonly when: 'With OBSIDIAN_READ_PATHS set, a readable note holds data, usually a frontmatter value, nested deeper than the server can hand to its evaluator (about 3,500 levels under Node, more under Bun).';
284
- readonly recovery: 'Flatten the deeply nested value, usually a frontmatter field, in the note the message names, or ask the operator to leave that note out of OBSIDIAN_READ_PATHS; no scoped jsonlogic search runs while it is readable.';
382
+ readonly when: 'With OBSIDIAN_READ_PATHS or OBSIDIAN_DENY_PATHS set, a readable note holds data, usually a frontmatter value, nested deeper than the server can hand to its evaluator (about 3,500 levels under Node, more under Bun).';
383
+ readonly recovery: 'Flatten the deeply nested value, usually a frontmatter field, in the note the message names, or ask the operator to leave that note out of OBSIDIAN_READ_PATHS or add it to OBSIDIAN_DENY_PATHS; no scoped jsonlogic search runs while it is readable.';
285
384
  }, {
286
385
  readonly reason: 'omnisearch_unreachable';
287
386
  readonly thrownBy: 'service';
288
387
  readonly code: JsonRpcErrorCode.ServiceUnavailable;
289
- readonly when: 'Omnisearch was reachable at startup but is now unreachable (Obsidian quit, plugin disabled, or mobile session).';
388
+ readonly when: 'Omnisearch was reachable at startup but did not answer: it is unreachable (Obsidian quit, plugin disabled, or mobile session), answered with a non-2xx status, or took longer than OBSIDIAN_REQUEST_TIMEOUT_MS. One attempt, never retried.';
290
389
  readonly retryable: true;
291
- readonly recovery: 'Restart Obsidian with the Omnisearch plugin enabled, then restart this MCP server so it re-probes the plugin URL.';
292
- }], {
390
+ readonly recovery: 'Confirm Obsidian is running with the Omnisearch plugin enabled and retry, or narrow the query if it was slow. If Omnisearch stays down, restart Obsidian, then restart this MCP server so it re-probes the plugin URL.';
391
+ }] | readonly [{
392
+ readonly reason: 'path_prefix_invalid_mode';
393
+ readonly code: JsonRpcErrorCode.ValidationError;
394
+ readonly when: '`pathPrefix` was provided in a non-text mode (only `text` supports prefix filtering).';
395
+ readonly recovery: 'Drop pathPrefix or switch mode to text for prefix filtering.';
396
+ }, {
397
+ readonly reason: 'query_required';
398
+ readonly code: JsonRpcErrorCode.ValidationError;
399
+ readonly when: '`query` is missing in a mode that requires it: every mode but `jsonlogic`.';
400
+ readonly recovery: "Pass `query` as space-separated tokens, all of which a note must contain." | "Pass `query` — space-separated tokens, all required, for text mode, or BM25 query syntax (quoted phrases, `-exclusion`, `path:` / `ext:` filters) for omnisearch.";
401
+ }, {
402
+ readonly reason: 'context_length_too_large';
403
+ readonly thrownBy: 'service';
404
+ readonly code: JsonRpcErrorCode.ValidationError;
405
+ readonly when: "The matches would make a response longer than one can be, so the whole text search failed: the Local REST API runs out of string capacity serializing them, or, under OBSIDIAN_READ_PATHS or OBSIDIAN_DENY_PATHS, the readable notes' matches alone would pass the same ceiling. Each match costs its context window plus about 150 characters of offsets and framing.";
406
+ readonly recovery: 'Narrow the query so fewer notes match, and drop very common tokens: every occurrence of each token in a matching note is a match costing about 150 characters beside its window, so a token like `the` can fail even at `contextLength` 0. Lowering `contextLength` helps only while the windows, about twice `contextLength` each, dominate that cost.';
407
+ }, {
408
+ readonly reason: 'logic_required';
409
+ readonly code: JsonRpcErrorCode.ValidationError;
410
+ readonly when: '`logic` is missing for `jsonlogic` mode.';
411
+ readonly recovery: 'Pass a JSONLogic tree as `logic`. `glob` and `regexp` take `[PATTERN, VALUE]` — pattern first, e.g. `{"glob": ["Projects/*.md", {"var": "path"}]}`.';
412
+ }, {
413
+ readonly reason: 'logic_invalid';
414
+ readonly thrownBy: 'service';
415
+ readonly code: JsonRpcErrorCode.ValidationError;
416
+ readonly when: 'The JSONLogic tree failed to evaluate against a note — an unrecognized operator, or an operand that could not be evaluated (an uncompilable `regexp` pattern). A mis-arity operator is not rejected: it evaluates to false and the search returns zero hits.';
417
+ readonly recovery: 'Check the operator names and arity. `glob` and `regexp` take `[PATTERN, VALUE]` — pattern first, e.g. `{"regexp": ["^Inbox/", {"var": "path"}]}`; the reverse order compiles the note field as the pattern.';
418
+ }, {
419
+ readonly reason: 'logic_too_costly';
420
+ readonly thrownBy: 'service';
421
+ readonly code: JsonRpcErrorCode.ValidationError;
422
+ readonly when: "With OBSIDIAN_READ_PATHS or OBSIDIAN_DENY_PATHS set, the server evaluates the JSONLogic tree itself, and the tree passed a bound: nesting deeper than 1,000 levels, more than a work budget, more than 10 s of evaluation, or more than 45 s for the whole search, reading the readable notes included. One work budget is per note — the size of values built by `merge`, `cat`, `map`, and array literals while evaluating that note, up to the note's own size plus 10,000,000 units — and one is per search: 10,000,000 units across every note for returned results, where a result whose JSON is at most 1,024 characters is free and a larger one pays for what it holds beyond its own note.";
423
+ readonly recovery: "Simplify the tree: nest fewer levels, avoid building arrays or strings many times a note's size with `merge`, `cat`, `map`, or `reduce`, return values drawn from the note rather than large built values or constants, and prefer a simpler `regexp` pattern.";
424
+ }, {
425
+ readonly reason: 'text_search_too_costly';
426
+ readonly thrownBy: 'service';
427
+ readonly code: JsonRpcErrorCode.ValidationError;
428
+ readonly when: 'With OBSIDIAN_READ_PATHS or OBSIDIAN_DENY_PATHS set, the server runs text mode itself, reading every readable note whose path or body holds each token, and reading and matching them took more than 45 s.';
429
+ readonly recovery: 'Add rarer tokens, which every candidate note must contain, so fewer readable notes are read, or ask the operator to narrow OBSIDIAN_READ_PATHS or extend OBSIDIAN_DENY_PATHS.';
430
+ }, {
431
+ readonly reason: 'link_fields_unavailable';
432
+ readonly thrownBy: 'service';
433
+ readonly code: JsonRpcErrorCode.ValidationError;
434
+ readonly when: 'With OBSIDIAN_READ_PATHS or OBSIDIAN_DENY_PATHS set, the JSONLogic tree names `links`, `backlinks`, or `unresolvedLinks` by a fixed `var`, `missing`, or `missing_some` key. Scoped searches leave these fields out, since Obsidian resolves each link across the whole vault, notes outside the scope included; a computed key reads them as null.';
435
+ readonly recovery: 'Find backlinks by body text: `{"regexp": ["\\\\[\\\\[Target Note(\\\\\\\\?\\\\||#|\\\\]\\\\])", {"var": "content"}]}` matches every readable note that wikilinks or embeds `Target Note`. For a note\'s outgoing links, call `obsidian_get_note` with `includeLinks: true`.';
436
+ }, {
437
+ readonly reason: 'note_too_deep';
438
+ readonly thrownBy: 'service';
439
+ readonly code: JsonRpcErrorCode.SerializationError;
440
+ readonly when: 'With OBSIDIAN_READ_PATHS or OBSIDIAN_DENY_PATHS set, a readable note holds data, usually a frontmatter value, nested deeper than the server can hand to its evaluator (about 3,500 levels under Node, more under Bun).';
441
+ readonly recovery: 'Flatten the deeply nested value, usually a frontmatter field, in the note the message names, or ask the operator to leave that note out of OBSIDIAN_READ_PATHS or add it to OBSIDIAN_DENY_PATHS; no scoped jsonlogic search runs while it is readable.';
442
+ }, ...never[]], {
293
443
  readonly effectiveQuery: z.ZodOptional<z.ZodString>;
294
444
  readonly notice: z.ZodOptional<z.ZodString>;
295
445
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"obsidian-search-notes.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/obsidian-search-notes.tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAsB,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AA+GjE;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,mBAAmB,EAAE,EAAE;IAAE,mBAAmB,EAAE,OAAO,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAwIhF,0BAA0B;;mBAE5B,uFAAuF;uBACnF,8DAA8D;;qBAGhE,gBAAgB;;mBAElB,yEAAyE;uBAE7E,wKAAwK;;qBAGlK,0BAA0B;uBACxB,SAAS;;mBAEb,0HAA0H;uBAE9H,iLAAiL;;qBAG3K,gBAAgB;;mBAElB,0CAA0C;uBAE9C,qJAAqJ;;qBAG/I,eAAe;uBACb,SAAS;;mBAEb,8PAA8P;uBAElQ,6MAA6M;;qBAGvM,kBAAkB;uBAChB,SAAS;;mBAEb,qkBAAqkB;uBAEzkB,gQAAgQ;;qBAG1P,eAAe;uBACb,SAAS;;mBAEb,iMAAiM;uBAErM,uNAAuN;;qBAGjN,wBAAwB;uBACtB,SAAS;;mBAEb,iHAAiH;;uBAGrH,mHAAmH;;;;GAqK1H;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA5OlB,0BAA0B;;mBAE5B,uFAAuF;uBACnF,8DAA8D;;qBAGhE,gBAAgB;;mBAElB,yEAAyE;uBAE7E,wKAAwK;;qBAGlK,0BAA0B;uBACxB,SAAS;;mBAEb,0HAA0H;uBAE9H,iLAAiL;;qBAG3K,gBAAgB;;mBAElB,0CAA0C;uBAE9C,qJAAqJ;;qBAG/I,eAAe;uBACb,SAAS;;mBAEb,8PAA8P;uBAElQ,6MAA6M;;qBAGvM,kBAAkB;uBAChB,SAAS;;mBAEb,qkBAAqkB;uBAEzkB,gQAAgQ;;qBAG1P,eAAe;uBACb,SAAS;;mBAEb,iMAAiM;uBAErM,uNAAuN;;qBAGjN,wBAAwB;uBACtB,SAAS;;mBAEb,iHAAiH;;uBAGrH,mHAAmH;;;;EAkLpC,CAAC"}
1
+ {"version":3,"file":"obsidian-search-notes.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/obsidian-search-notes.tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAsB,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AASjE,OAAO,EAAsB,KAAK,eAAe,EAAE,MAAM,yCAAyC,CAAC;AAiBnG;;;;;;;GAOG;AACH,MAAM,MAAM,sBAAsB,GAAG,SAAS,GAAG,aAAa,GAAG,UAAU,CAAC;AAE5E;;;;GAIG;AACH,wBAAsB,sBAAsB,CAC1C,GAAG,EAAE,eAAe,GACnB,OAAO,CAAC,sBAAsB,CAAC,CAGjC;AAqGD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,UAAU,EAAE,EAAE;IAAE,UAAU,EAAE,sBAAsB,CAAA;CAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA4J7E,0BAA0B;;mBAE5B,uFAAuF;uBACnF,8DAA8D;;qBAGhE,gBAAgB;;mBAElB,4EAA4E;;;qBAM1E,0BAA0B;uBACxB,SAAS;;mBAEb,wWAAwW;uBAE5W,yVAAyV;;qBAGnV,gBAAgB;;mBAElB,0CAA0C;uBAE9C,qJAAqJ;;qBAG/I,eAAe;uBACb,SAAS;;mBAEb,8PAA8P;uBAElQ,6MAA6M;;qBAGvM,kBAAkB;uBAChB,SAAS;;mBAEb,sqBAAsqB;uBAE1qB,gQAAgQ;;qBAG1P,wBAAwB;uBACtB,SAAS;;mBAEb,4MAA4M;uBAEhN,+KAA+K;;qBAGzK,yBAAyB;uBACvB,SAAS;;mBAEb,qVAAqV;uBAEzV,6QAA6Q;;qBAGvQ,eAAe;uBACb,SAAS;;mBAEb,wNAAwN;uBAE5N,wPAAwP;;qBAnFlP,wBAAwB;uBACtB,SAAS;;mBAEb,6OAA6O;;uBAGjP,wNAAwN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6O/N;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA/OlB,0BAA0B;;mBAE5B,uFAAuF;uBACnF,8DAA8D;;qBAGhE,gBAAgB;;mBAElB,4EAA4E;;;qBAM1E,0BAA0B;uBACxB,SAAS;;mBAEb,wWAAwW;uBAE5W,yVAAyV;;qBAGnV,gBAAgB;;mBAElB,0CAA0C;uBAE9C,qJAAqJ;;qBAG/I,eAAe;uBACb,SAAS;;mBAEb,8PAA8P;uBAElQ,6MAA6M;;qBAGvM,kBAAkB;uBAChB,SAAS;;mBAEb,sqBAAsqB;uBAE1qB,gQAAgQ;;qBAG1P,wBAAwB;uBACtB,SAAS;;mBAEb,4MAA4M;uBAEhN,+KAA+K;;qBAGzK,yBAAyB;uBACvB,SAAS;;mBAEb,qVAAqV;uBAEzV,6QAA6Q;;qBAGvQ,eAAe;uBACb,SAAS;;mBAEb,wNAAwN;uBAE5N,wPAAwP;;qBAnFlP,wBAAwB;uBACtB,SAAS;;mBAEb,6OAA6O;;uBAGjP,wNAAwN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA0P1I,CAAC"}