@gmickel/gno 1.8.0 → 1.10.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.
- package/README.md +6 -2
- package/assets/skill/SKILL.md +41 -16
- package/assets/skill/cli-reference.md +39 -0
- package/assets/skill/examples.md +41 -0
- package/assets/skill/mcp-reference.md +13 -1
- package/package.json +1 -1
- package/src/cli/commands/capture.ts +9 -6
- package/src/cli/commands/graph.ts +89 -2
- package/src/cli/commands/index-cmd.ts +17 -6
- package/src/cli/commands/links.ts +237 -54
- package/src/cli/commands/query.ts +212 -0
- package/src/cli/commands/ref-parser.ts +8 -103
- package/src/cli/commands/shared.ts +17 -1
- package/src/cli/commands/update.ts +17 -6
- package/src/cli/options.ts +4 -0
- package/src/cli/program.ts +176 -9
- package/src/config/content-types.ts +154 -0
- package/src/config/defaults.ts +1 -0
- package/src/config/index.ts +14 -0
- package/src/config/loader.ts +11 -2
- package/src/config/types.ts +37 -1
- package/src/core/config-mutation.ts +14 -2
- package/src/core/graph-query.ts +137 -0
- package/src/core/graph-resolver.ts +117 -0
- package/src/core/note-presets.ts +61 -5
- package/src/core/ref-parser.ts +145 -0
- package/src/ingestion/frontmatter.ts +170 -2
- package/src/ingestion/index.ts +2 -0
- package/src/ingestion/sync-options.ts +29 -0
- package/src/ingestion/sync.ts +385 -17
- package/src/ingestion/types.ts +14 -0
- package/src/mcp/tools/add-collection.ts +8 -5
- package/src/mcp/tools/capture.ts +5 -2
- package/src/mcp/tools/get.ts +1 -1
- package/src/mcp/tools/index-cmd.ts +13 -7
- package/src/mcp/tools/index.ts +97 -10
- package/src/mcp/tools/links.ts +83 -1
- package/src/mcp/tools/multi-get.ts +1 -1
- package/src/mcp/tools/query.ts +207 -0
- package/src/mcp/tools/sync.ts +12 -6
- package/src/mcp/tools/workspace-write.ts +16 -10
- package/src/pipeline/diagnose.ts +302 -0
- package/src/pipeline/filters.ts +119 -0
- package/src/pipeline/hybrid.ts +92 -17
- package/src/pipeline/search.ts +2 -0
- package/src/pipeline/types.ts +34 -0
- package/src/pipeline/vsearch.ts +4 -0
- package/src/publish/export-service.ts +1 -1
- package/src/sdk/client.ts +51 -24
- package/src/sdk/documents.ts +2 -2
- package/src/serve/background-runtime.ts +18 -4
- package/src/serve/config-sync.ts +9 -2
- package/src/serve/routes/api.ts +244 -24
- package/src/serve/routes/graph.ts +173 -1
- package/src/serve/server.ts +24 -1
- package/src/serve/watch-service.ts +12 -2
- package/src/store/migrations/009-content-type-rule-fingerprint.ts +36 -0
- package/src/store/migrations/010-typed-edges.ts +67 -0
- package/src/store/migrations/011-doc-edge-traversal-indexes.ts +30 -0
- package/src/store/migrations/index.ts +16 -1
- package/src/store/sqlite/adapter.ts +853 -114
- package/src/store/types.ts +147 -0
|
@@ -117,6 +117,168 @@ function parseTagsValue(
|
|
|
117
117
|
return [];
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
+
function parseInlineArrayValue(value: string): string[] | undefined {
|
|
121
|
+
const inlineMatch = INLINE_ARRAY_REGEX.exec(value.trim());
|
|
122
|
+
if (!inlineMatch) {
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
const rawItems = inlineMatch[1];
|
|
126
|
+
if (rawItems === undefined) {
|
|
127
|
+
return [];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return rawItems
|
|
131
|
+
.split(",")
|
|
132
|
+
.map((item) => unquoteScalar(item.trim()))
|
|
133
|
+
.filter((item) => item.length > 0);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function unquoteScalar(value: string): string {
|
|
137
|
+
const trimmed = value.trim();
|
|
138
|
+
if (trimmed.length < 2) {
|
|
139
|
+
return trimmed;
|
|
140
|
+
}
|
|
141
|
+
const first = trimmed[0];
|
|
142
|
+
const last = trimmed.at(-1);
|
|
143
|
+
if ((first === '"' && last === '"') || (first === "'" && last === "'")) {
|
|
144
|
+
return trimmed.slice(1, -1).trim();
|
|
145
|
+
}
|
|
146
|
+
return trimmed;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function parseBlockArrayValue(lines: string[], startIdx: number): string[] {
|
|
150
|
+
const items: string[] = [];
|
|
151
|
+
for (let i = startIdx + 1; i < lines.length; i++) {
|
|
152
|
+
const line = lines[i];
|
|
153
|
+
if (line === undefined) break;
|
|
154
|
+
const itemMatch = YAML_ARRAY_ITEM_REGEX.exec(line);
|
|
155
|
+
if (itemMatch?.[1]) {
|
|
156
|
+
const item = unquoteScalar(itemMatch[1]);
|
|
157
|
+
if (item.length > 0) {
|
|
158
|
+
items.push(item);
|
|
159
|
+
}
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
if (
|
|
163
|
+
line.trim().length > 0 &&
|
|
164
|
+
!line.startsWith(" ") &&
|
|
165
|
+
!line.startsWith("\t")
|
|
166
|
+
) {
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
return items;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function countIndent(line: string): number {
|
|
174
|
+
let indent = 0;
|
|
175
|
+
for (const char of line) {
|
|
176
|
+
if (char === " ") {
|
|
177
|
+
indent += 1;
|
|
178
|
+
} else if (char === "\t") {
|
|
179
|
+
indent += 2;
|
|
180
|
+
} else {
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return indent;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function parseNestedMapValue(
|
|
188
|
+
lines: string[],
|
|
189
|
+
startIdx: number
|
|
190
|
+
): Record<string, string[]> {
|
|
191
|
+
const result: Record<string, string[]> = {};
|
|
192
|
+
|
|
193
|
+
for (let i = startIdx + 1; i < lines.length; i++) {
|
|
194
|
+
const line = lines[i];
|
|
195
|
+
if (line === undefined) break;
|
|
196
|
+
if (line.trim().length === 0) continue;
|
|
197
|
+
if (!line.startsWith(" ") && !line.startsWith("\t")) {
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
const keyIndent = countIndent(line);
|
|
202
|
+
const trimmed = line.trim();
|
|
203
|
+
const colonIdx = trimmed.indexOf(":");
|
|
204
|
+
if (colonIdx <= 0) {
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const key = trimmed.slice(0, colonIdx).trim();
|
|
209
|
+
const rawValue = trimmed.slice(colonIdx + 1).trim();
|
|
210
|
+
const values: string[] = [];
|
|
211
|
+
|
|
212
|
+
const inlineArray = parseInlineArrayValue(rawValue);
|
|
213
|
+
if (inlineArray) {
|
|
214
|
+
values.push(...inlineArray);
|
|
215
|
+
} else if (rawValue.length > 0) {
|
|
216
|
+
values.push(unquoteScalar(rawValue));
|
|
217
|
+
} else {
|
|
218
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
219
|
+
const childLine = lines[j];
|
|
220
|
+
if (childLine === undefined) break;
|
|
221
|
+
if (childLine.trim().length === 0) continue;
|
|
222
|
+
const childIndent = countIndent(childLine);
|
|
223
|
+
if (childIndent <= keyIndent) {
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
const itemMatch = YAML_ARRAY_ITEM_REGEX.exec(childLine);
|
|
227
|
+
if (itemMatch?.[1]) {
|
|
228
|
+
const item = unquoteScalar(itemMatch[1]);
|
|
229
|
+
if (item.length > 0) {
|
|
230
|
+
values.push(item);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (key.length > 0 && values.length > 0) {
|
|
237
|
+
result[key] = values;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return result;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function startsNestedMap(lines: string[], startIdx: number): boolean {
|
|
245
|
+
for (let i = startIdx + 1; i < lines.length; i++) {
|
|
246
|
+
const line = lines[i];
|
|
247
|
+
if (line === undefined) break;
|
|
248
|
+
if (line.trim().length === 0) continue;
|
|
249
|
+
if (!line.startsWith(" ") && !line.startsWith("\t")) {
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
return line.trim().indexOf(":") > 0;
|
|
253
|
+
}
|
|
254
|
+
return false;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function parseMetadataValue(
|
|
258
|
+
value: string,
|
|
259
|
+
lines: string[],
|
|
260
|
+
startIdx: number
|
|
261
|
+
): string | string[] | Record<string, string[]> | undefined {
|
|
262
|
+
const trimmed = value.trim();
|
|
263
|
+
const inlineArray = parseInlineArrayValue(trimmed);
|
|
264
|
+
if (inlineArray) {
|
|
265
|
+
return inlineArray;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (trimmed.length === 0) {
|
|
269
|
+
if (startsNestedMap(lines, startIdx)) {
|
|
270
|
+
const nestedMap = parseNestedMapValue(lines, startIdx);
|
|
271
|
+
return Object.keys(nestedMap).length > 0 ? nestedMap : undefined;
|
|
272
|
+
}
|
|
273
|
+
const blockArray = parseBlockArrayValue(lines, startIdx);
|
|
274
|
+
if (blockArray.length > 0) {
|
|
275
|
+
return blockArray;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return unquoteScalar(trimmed);
|
|
280
|
+
}
|
|
281
|
+
|
|
120
282
|
/**
|
|
121
283
|
* Parse frontmatter from markdown source.
|
|
122
284
|
* Returns extracted tags and metadata.
|
|
@@ -150,6 +312,9 @@ export function parseFrontmatter(source: string): FrontmatterResult {
|
|
|
150
312
|
for (let i = 0; i < lines.length; i++) {
|
|
151
313
|
const line = lines[i];
|
|
152
314
|
if (line === undefined) continue;
|
|
315
|
+
if (line.startsWith(" ") || line.startsWith("\t")) {
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
153
318
|
|
|
154
319
|
// Logseq format: tags:: value
|
|
155
320
|
const logseqMatch = LOGSEQ_TAGS_REGEX.exec(line);
|
|
@@ -170,8 +335,11 @@ export function parseFrontmatter(source: string): FrontmatterResult {
|
|
|
170
335
|
if (colonIdx > 0) {
|
|
171
336
|
const key = line.slice(0, colonIdx).trim();
|
|
172
337
|
const value = line.slice(colonIdx + 1).trim();
|
|
173
|
-
if (key !== "tags"
|
|
174
|
-
|
|
338
|
+
if (key !== "tags") {
|
|
339
|
+
const metadataValue = parseMetadataValue(value, lines, i);
|
|
340
|
+
if (metadataValue !== undefined) {
|
|
341
|
+
result.metadata[key] = metadataValue;
|
|
342
|
+
}
|
|
175
343
|
}
|
|
176
344
|
}
|
|
177
345
|
}
|
package/src/ingestion/index.ts
CHANGED
|
@@ -10,12 +10,14 @@ export { defaultChunker, MarkdownChunker } from "./chunker";
|
|
|
10
10
|
export { defaultLanguageDetector, SimpleLanguageDetector } from "./language";
|
|
11
11
|
// Sync service
|
|
12
12
|
export { defaultSyncService, SyncService } from "./sync";
|
|
13
|
+
export { resolveContentTypeRules, withContentTypeRules } from "./sync-options";
|
|
13
14
|
// Types
|
|
14
15
|
export type {
|
|
15
16
|
ChunkerPort,
|
|
16
17
|
ChunkOutput,
|
|
17
18
|
ChunkParams,
|
|
18
19
|
CollectionSyncResult,
|
|
20
|
+
ContentTypeSource,
|
|
19
21
|
FileSyncResult,
|
|
20
22
|
FileSyncStatus,
|
|
21
23
|
LanguageDetectorPort,
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sync option helpers.
|
|
3
|
+
*
|
|
4
|
+
* @module src/ingestion/sync-options
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { Config, NormalizedContentTypeRule } from "../config";
|
|
8
|
+
import type { SyncOptions } from "./types";
|
|
9
|
+
|
|
10
|
+
import { fingerprintContentTypeRules, normalizeContentTypes } from "../config";
|
|
11
|
+
|
|
12
|
+
export function resolveContentTypeRules(
|
|
13
|
+
config?: Pick<Config, "contentTypes">
|
|
14
|
+
): NormalizedContentTypeRule[] {
|
|
15
|
+
return normalizeContentTypes(config?.contentTypes ?? []).rules;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function withContentTypeRules(
|
|
19
|
+
options: SyncOptions = {},
|
|
20
|
+
config?: Pick<Config, "contentTypes">
|
|
21
|
+
): SyncOptions {
|
|
22
|
+
const rules = options.contentTypeRules ?? resolveContentTypeRules(config);
|
|
23
|
+
return {
|
|
24
|
+
...options,
|
|
25
|
+
contentTypeRules: rules,
|
|
26
|
+
contentTypeRulesFingerprint:
|
|
27
|
+
options.contentTypeRulesFingerprint ?? fingerprintContentTypeRules(rules),
|
|
28
|
+
};
|
|
29
|
+
}
|