@gmickel/gno 2.12.2 → 2.14.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 +1 -1
- package/assets/skill/SKILL.md +36 -5
- package/assets/skill/cli-reference.md +62 -11
- package/assets/skill/examples.md +30 -4
- package/assets/skill/mcp-reference.md +16 -0
- package/assets/spa-production.json.gz +0 -0
- package/browser-extension/artifacts/{gno-browser-clipper-v2.12.2.zip → gno-browser-clipper-v2.14.0.zip} +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v2.14.0.zip.sha256 +1 -0
- package/browser-extension/dist/manifest.json +1 -1
- package/package.json +1 -1
- package/spec/cli.md +139 -16
- package/spec/mcp.md +111 -3
- package/spec/output-schemas/collection-list.schema.json +28 -0
- package/spec/output-schemas/convert.schema.json +97 -0
- package/spec/output-schemas/ls.schema.json +65 -0
- package/spec/output-schemas/mcp-job-status.schema.json +17 -1
- package/spec/output-schemas/mcp-sync-result.schema.json +9 -2
- package/spec/output-schemas/search-results.schema.json +7 -0
- package/src/cli/commands/index-cmd.ts +50 -12
- package/src/cli/commands/ls.ts +20 -3
- package/src/cli/commands/profile-apply.ts +2 -1
- package/src/cli/commands/query.ts +21 -8
- package/src/cli/commands/search.ts +11 -0
- package/src/cli/commands/vsearch.ts +17 -4
- package/src/cli/options.ts +19 -0
- package/src/cli/program.ts +90 -10
- package/src/config/loader.ts +11 -1
- package/src/config/types.ts +90 -1
- package/src/core/audit-collection-rules.ts +331 -0
- package/src/core/audit-links.ts +3 -1
- package/src/core/audit-workspace.ts +69 -5
- package/src/core/collection-egress-policy-service.ts +4 -1
- package/src/core/collection-scope.ts +105 -0
- package/src/core/egress-enforcement.ts +20 -4
- package/src/core/egress-policy.ts +4 -0
- package/src/core/egress-provenance.ts +33 -11
- package/src/core/errors.ts +5 -0
- package/src/core/job-manager.ts +238 -19
- package/src/core/project-profile-apply-state.ts +6 -15
- package/src/core/project-profile-apply.ts +32 -1
- package/src/core/reindex-paths.ts +167 -0
- package/src/core/retrieval-trace-request.ts +1 -0
- package/src/ingestion/convert-file.ts +181 -0
- package/src/llm/registry.ts +20 -0
- package/src/mcp/http-egress.ts +21 -2
- package/src/mcp/tools/collection-scope.ts +25 -0
- package/src/mcp/tools/index-cmd.ts +66 -48
- package/src/mcp/tools/index.ts +74 -10
- package/src/mcp/tools/job-status.ts +7 -0
- package/src/mcp/tools/query.ts +28 -7
- package/src/mcp/tools/search.ts +4 -0
- package/src/mcp/tools/sync.ts +68 -60
- package/src/mcp/tools/vsearch.ts +9 -3
- package/src/pipeline/filters.ts +48 -5
- package/src/pipeline/graph-retrieval.ts +1 -0
- package/src/pipeline/hybrid.ts +15 -2
- package/src/pipeline/hydration.ts +7 -2
- package/src/pipeline/owner-fusion.ts +1 -0
- package/src/pipeline/search.ts +2 -0
- package/src/pipeline/types.ts +7 -0
- package/src/pipeline/vsearch.ts +10 -5
- package/src/sdk/client.ts +45 -12
- package/src/sdk/convert.ts +27 -0
- package/src/sdk/documents.ts +15 -2
- package/src/sdk/index.ts +2 -0
- package/src/sdk/types.ts +4 -1
- package/src/serve/jobs.ts +4 -1
- package/src/serve/public/components/IndexingProgress.tsx +25 -3
- package/src/serve/routes/api.ts +164 -24
- package/src/store/sqlite/adapter.ts +97 -27
- package/src/store/sqlite/eligibility.ts +4 -0
- package/src/store/types.ts +7 -0
- package/src/store/vector/sqlite-vec.ts +67 -15
- package/src/store/vector/variant-search.ts +41 -4
- package/browser-extension/artifacts/gno-browser-clipper-v2.12.2.zip.sha256 +0 -1
package/spec/mcp.md
CHANGED
|
@@ -230,6 +230,50 @@ All write tools acquire an OS-backed advisory lock at `.mcp-write.lock` under th
|
|
|
230
230
|
If another process holds the lock, tools return `LOCKED`.
|
|
231
231
|
For async jobs, the lock is held for the full job duration.
|
|
232
232
|
|
|
233
|
+
### Reindex Queue
|
|
234
|
+
|
|
235
|
+
`gno_sync` and `gno_index` (and REST `POST /api/sync`) never reject a request
|
|
236
|
+
because another job in the same server is running:
|
|
237
|
+
|
|
238
|
+
- With no job running or waiting, the request starts at once (`status:
|
|
239
|
+
"started"`), taking the write lock as above; another process holding it
|
|
240
|
+
returns `LOCKED`.
|
|
241
|
+
- Otherwise it is queued (`status: "queued"`) and starts when the jobs ahead
|
|
242
|
+
of it finish, taking the write lock then. A queued job that cannot get the
|
|
243
|
+
lock fails with `LOCKED` in its job status.
|
|
244
|
+
- A request joins a waiting job of the same tool and collection and returns
|
|
245
|
+
its `jobId`, so any number of requests cause at most one more pass:
|
|
246
|
+
- a request with `paths` joins any such job (its files are added to the
|
|
247
|
+
pass, or covered by a whole-collection pass);
|
|
248
|
+
- a whole-collection request joins a job that only has path requests
|
|
249
|
+
(widening it and setting its options) or a whole-collection job with the
|
|
250
|
+
same `gitPull` / `runUpdateCmd`. Whole-collection requests with different
|
|
251
|
+
options stay separate passes, and a path-only pass never runs `gitPull`
|
|
252
|
+
or an update command.
|
|
253
|
+
- a path-only job whose merged files pass 256 becomes a whole-collection
|
|
254
|
+
pass with no `gitPull` or update command.
|
|
255
|
+
- A queued pass uses the configuration of the latest request that joined it;
|
|
256
|
+
`gno_index` resolves its embedding model when the pass starts, so a model
|
|
257
|
+
or preset change while it waits is picked up.
|
|
258
|
+
- At most 64 distinct scopes wait at once; a new scope beyond that returns
|
|
259
|
+
`QUEUE_FULL`. Retry after the running job finishes.
|
|
260
|
+
- The queue lives in the server process. Jobs still waiting when it stops are
|
|
261
|
+
failed at shutdown and unknown after a restart (`NOT_FOUND` from
|
|
262
|
+
`gno_job_status`); the index stays consistent.
|
|
263
|
+
|
|
264
|
+
### Path-Level Reindex
|
|
265
|
+
|
|
266
|
+
`paths` on `gno_sync` / `gno_index` reindexes only the listed files of one
|
|
267
|
+
collection: each path is relative to the collection root or absolute inside
|
|
268
|
+
it, and only those files are re-read. A listed file that no longer exists is
|
|
269
|
+
marked inactive. `paths` requires `collection` and cannot be combined with
|
|
270
|
+
`gitPull` or `runUpdateCmd`; an empty list, more than 256 paths, a
|
|
271
|
+
directory, a path outside the root (including through a symlink) or a
|
|
272
|
+
non-string entry is rejected before anything is queued (`INVALID_INPUT` /
|
|
273
|
+
`INVALID_PATH`), and so is a path the collection's own `pattern`, `include`
|
|
274
|
+
or `exclude` rules leave out. To reindex a directory or more than 256 files,
|
|
275
|
+
reindex the whole collection.
|
|
276
|
+
|
|
233
277
|
`gno_remember` is the one write tool whose adapter takes no lock of its own:
|
|
234
278
|
the core memory service acquires the same `.mcp-write.lock` lease for every
|
|
235
279
|
memory write, so an MCP remember and a CLI writer serialise on one lease. A
|
|
@@ -294,6 +338,13 @@ compatible collection policy. Policy denial returns HTTP 403 with stable
|
|
|
294
338
|
`EGRESS_DENIED` data and a redacted evaluator audit. Write authorization remains
|
|
295
339
|
an independent additional requirement.
|
|
296
340
|
|
|
341
|
+
The check covers the request's collection scope: the collections it names, or
|
|
342
|
+
every configured collection when it names none. One decision covers at most 64
|
|
343
|
+
collections and one policy lineage at most 128. A scope over either bound is
|
|
344
|
+
denied with reason `COLLECTION_LIMIT_EXCEEDED` through the same 403 response,
|
|
345
|
+
whose audit names no collection; it is never an internal error. A request that
|
|
346
|
+
names a few collections is evaluated normally however many are configured.
|
|
347
|
+
|
|
297
348
|
The MCP tool and resource registry is paired with a callsite-level
|
|
298
349
|
network-boundary inventory. A TypeScript AST scan covers shipped TS, TSX, JS,
|
|
299
350
|
and JSX and recognizes direct, qualified, bracketed, imported, and aliased
|
|
@@ -367,7 +418,10 @@ Rules report `pass`, `fail`, `skip`, `unavailable`, or `inconclusive`; reports
|
|
|
367
418
|
are `complete`, `partial`, `changed_during_audit`, or `failed`. A passing rule
|
|
368
419
|
may carry `info` findings (`links.outside-index`: link targets that exist as
|
|
369
420
|
files in the link workspace but are not indexed); only `warning` and `error`
|
|
370
|
-
findings fail a rule. Link semantics match `gno audit` (spec/cli.md)
|
|
421
|
+
findings fail a rule. Link semantics match `gno audit` (spec/cli.md),
|
|
422
|
+
including the opt-in `links.collection-policy`, `links.external-url` and
|
|
423
|
+
`links.path-layout` rules read from collection `audit` config; they add no
|
|
424
|
+
tool inputs. Unavailable or
|
|
371
425
|
changing evidence never appears healthy. Stable finding IDs are derived from
|
|
372
426
|
rule, normalized subject/location, and evidence fingerprint. Responses are
|
|
373
427
|
canonically ordered and bounded while retaining exact pre-truncation totals.
|
|
@@ -603,6 +657,19 @@ opaque remote hints. The server never stats, realpaths, discovers repositories,
|
|
|
603
657
|
or infers its cwd from them; remote hints produce redacted zero-affinity
|
|
604
658
|
metadata and no ranking change.
|
|
605
659
|
|
|
660
|
+
`gno_search`, `gno_vsearch` and `gno_query` also accept an optional
|
|
661
|
+
`collections` allowlist. The filter applies before every candidate limit (BM25,
|
|
662
|
+
vector, fusion, graph expansion, hydration and rerank), so unlisted collections
|
|
663
|
+
never take result slots. Names are trimmed, lowercased, de-duplicated and
|
|
664
|
+
sorted; responses echo them as `meta.collections`, and `meta.collection` keeps
|
|
665
|
+
its single-collection meaning. Passing both `collection` and `collections`, an
|
|
666
|
+
empty list, a non-string member, or more than 256 names after normalization is
|
|
667
|
+
a `VALIDATION` error; unconfigured names give `Collection not found: <name>` /
|
|
668
|
+
`Collections not found: <a>, <b>`. Over HTTP the egress check covers exactly
|
|
669
|
+
the listed collections, so the most restrictive listed collection decides.
|
|
670
|
+
When the listed collections resolve different models for a role, that role uses
|
|
671
|
+
the unscoped default. `gno_query_diagnose` does not accept `collections`.
|
|
672
|
+
|
|
606
673
|
**Input Schema:**
|
|
607
674
|
|
|
608
675
|
```json
|
|
@@ -617,6 +684,11 @@ metadata and no ranking change.
|
|
|
617
684
|
"type": "string",
|
|
618
685
|
"description": "Optional collection name to filter results"
|
|
619
686
|
},
|
|
687
|
+
"collections": {
|
|
688
|
+
"type": "array",
|
|
689
|
+
"items": { "type": "string" },
|
|
690
|
+
"description": "Optional allowlist: filter to any of these collection names (1-256); use instead of collection"
|
|
691
|
+
},
|
|
620
692
|
"limit": {
|
|
621
693
|
"type": "integer",
|
|
622
694
|
"description": "Maximum number of results (1-100)",
|
|
@@ -738,6 +810,11 @@ Vector semantic search over indexed documents.
|
|
|
738
810
|
"type": "string",
|
|
739
811
|
"description": "Optional collection name to filter results"
|
|
740
812
|
},
|
|
813
|
+
"collections": {
|
|
814
|
+
"type": "array",
|
|
815
|
+
"items": { "type": "string" },
|
|
816
|
+
"description": "Optional allowlist: filter to any of these collection names (1-256); use instead of collection"
|
|
817
|
+
},
|
|
741
818
|
"limit": {
|
|
742
819
|
"type": "integer",
|
|
743
820
|
"description": "Maximum number of results (1-100)",
|
|
@@ -822,6 +899,11 @@ Hybrid search combining BM25 and vector retrieval with optional expansion and re
|
|
|
822
899
|
"type": "string",
|
|
823
900
|
"description": "Optional collection name to filter results"
|
|
824
901
|
},
|
|
902
|
+
"collections": {
|
|
903
|
+
"type": "array",
|
|
904
|
+
"items": { "type": "string" },
|
|
905
|
+
"description": "Optional allowlist: filter to any of these collection names (1-256); use instead of collection"
|
|
906
|
+
},
|
|
825
907
|
"limit": {
|
|
826
908
|
"type": "integer",
|
|
827
909
|
"description": "Maximum number of results (1-100)",
|
|
@@ -2719,6 +2801,12 @@ Reindex one or all collections (write-enabled).
|
|
|
2719
2801
|
"type": "boolean",
|
|
2720
2802
|
"description": "Run updateCmd before indexing (default: false for MCP)",
|
|
2721
2803
|
"default": false
|
|
2804
|
+
},
|
|
2805
|
+
"paths": {
|
|
2806
|
+
"type": "array",
|
|
2807
|
+
"items": { "type": "string" },
|
|
2808
|
+
"maxItems": 256,
|
|
2809
|
+
"description": "Reindex only these files of the collection (see Path-Level Reindex); requires collection"
|
|
2722
2810
|
}
|
|
2723
2811
|
}
|
|
2724
2812
|
}
|
|
@@ -2726,6 +2814,9 @@ Reindex one or all collections (write-enabled).
|
|
|
2726
2814
|
|
|
2727
2815
|
**Output Schema:** `gno://schemas/mcp-sync-result@1.0`
|
|
2728
2816
|
|
|
2817
|
+
`status` is `started` or `queued` (see [Reindex Queue](#reindex-queue));
|
|
2818
|
+
`paths` echoes the resolved collection-relative paths of a path-level sync.
|
|
2819
|
+
|
|
2729
2820
|
---
|
|
2730
2821
|
|
|
2731
2822
|
### gno_embed
|
|
@@ -2818,6 +2909,12 @@ Full index: sync files + generate embeddings (write-enabled). Runs as background
|
|
|
2818
2909
|
"type": "boolean",
|
|
2819
2910
|
"description": "Run git pull before sync",
|
|
2820
2911
|
"default": false
|
|
2912
|
+
},
|
|
2913
|
+
"paths": {
|
|
2914
|
+
"type": "array",
|
|
2915
|
+
"items": { "type": "string" },
|
|
2916
|
+
"maxItems": 256,
|
|
2917
|
+
"description": "Reindex only these files of the collection (see Path-Level Reindex); requires collection"
|
|
2821
2918
|
}
|
|
2822
2919
|
}
|
|
2823
2920
|
}
|
|
@@ -2852,6 +2949,7 @@ Full index: sync files + generate embeddings (write-enabled). Runs as background
|
|
|
2852
2949
|
|
|
2853
2950
|
- Requires `--enable-write` flag
|
|
2854
2951
|
- Runs sync phase first, then embed phase
|
|
2952
|
+
- `status` is `started` or `queued` (see [Reindex Queue](#reindex-queue)); a path-level index adds `paths`
|
|
2855
2953
|
- `runUpdateCmd` is always false for MCP (security)
|
|
2856
2954
|
- Fails fast if embedding model not cached
|
|
2857
2955
|
- Poll job status with `gno_job_status`
|
|
@@ -2902,6 +3000,11 @@ Get status of a background job.
|
|
|
2902
3000
|
|
|
2903
3001
|
**Output Schema:** `gno://schemas/mcp-job-status@1.0`
|
|
2904
3002
|
|
|
3003
|
+
`status` is `queued` while a reindex job waits behind another job, then
|
|
3004
|
+
`running`, `completed` or `failed`. Reindex jobs also report `scope`: the
|
|
3005
|
+
collection (`null` for all) and the merged `paths` (`null` for the whole
|
|
3006
|
+
collection).
|
|
3007
|
+
|
|
2905
3008
|
---
|
|
2906
3009
|
|
|
2907
3010
|
### gno_list_jobs
|
|
@@ -3062,8 +3165,9 @@ Resource errors use standard MCP error responses.
|
|
|
3062
3165
|
- `HAS_REFERENCES` — Collection referenced by contexts
|
|
3063
3166
|
- `INVALID_PATH` — Path violates safety rules
|
|
3064
3167
|
- `PATH_NOT_FOUND` — Path does not exist
|
|
3065
|
-
- `JOB_CONFLICT` — Another job is already running
|
|
3168
|
+
- `JOB_CONFLICT` — Another job is already running (not returned by `gno_sync` / `gno_index`, which queue instead)
|
|
3066
3169
|
- `LOCKED` — Another MCP process holds the write lock
|
|
3170
|
+
- `QUEUE_FULL` — Too many reindex scopes are already waiting; retry later
|
|
3067
3171
|
- `CAPTURE_SYNC_FAILED` — `gno_capture` wrote the file but lexical sync failed
|
|
3068
3172
|
- `WRITE_DISABLED` — Write tool dispatched while writes are disabled
|
|
3069
3173
|
- `MEMORY_*` — Memory contract errors from `gno_recall` / `gno_remember`;
|
|
@@ -3106,6 +3210,7 @@ Clients should check schema version for compatibility.
|
|
|
3106
3210
|
- No persistent state between tool calls
|
|
3107
3211
|
- Each tool call is independent
|
|
3108
3212
|
- Server handles concurrent tool calls sequentially; an accepted background job (`gno_sync`, `gno_embed`, `gno_index`) waits for the call in progress, then runs without holding that queue, so reads are not blocked while it runs
|
|
3213
|
+
- The retrieval tools (`gno_search`, `gno_vsearch`, `gno_query`, `gno_get`, `gno_multi_get`, `gno_status`, `gno_list_tags`, `gno_links`, `gno_backlinks`, `gno_similar`) read on a second connection, so they see only committed index data, never a sync batch still being written
|
|
3109
3214
|
|
|
3110
3215
|
---
|
|
3111
3216
|
|
|
@@ -3291,7 +3396,10 @@ Read tools:
|
|
|
3291
3396
|
caller authentication/authorization, content class, and partial mode. It
|
|
3292
3397
|
performs no action and returns the canonical decision/explanation contract.
|
|
3293
3398
|
An explicit scope is a non-empty, duplicate-free list of at most 64 canonical
|
|
3294
|
-
collection names; omitted scope means all configured collections.
|
|
3399
|
+
collection names; omitted scope means all configured collections. Omitted
|
|
3400
|
+
scope with more than 64 configured collections returns a denied decision
|
|
3401
|
+
with reason `COLLECTION_LIMIT_EXCEEDED`; with more than 128 it returns a
|
|
3402
|
+
`VALIDATION` error asking for named collections.
|
|
3295
3403
|
- `gno_egress_audit_list`, `gno_egress_audit_show`, and
|
|
3296
3404
|
`gno_egress_audit_status` expose only content-free local receipts.
|
|
3297
3405
|
|
|
@@ -57,6 +57,34 @@
|
|
|
57
57
|
"type": "string",
|
|
58
58
|
"enum": ["none", "detected", "configured", "disabled", "unavailable"],
|
|
59
59
|
"description": "CLI list only: how the link workspace was set"
|
|
60
|
+
},
|
|
61
|
+
"audit": {
|
|
62
|
+
"type": "object",
|
|
63
|
+
"description": "Opt-in report-only link and path rules for gno audit links. Absent when not configured.",
|
|
64
|
+
"additionalProperties": false,
|
|
65
|
+
"properties": {
|
|
66
|
+
"linkCollections": {
|
|
67
|
+
"type": "array",
|
|
68
|
+
"description": "Other collections this one may link to; its own is always allowed",
|
|
69
|
+
"maxItems": 256,
|
|
70
|
+
"items": {
|
|
71
|
+
"type": "string",
|
|
72
|
+
"pattern": "^[a-z0-9][a-z0-9_-]{0,63}$"
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
"externalUrls": {
|
|
76
|
+
"type": "string",
|
|
77
|
+
"enum": ["report", "ignore"],
|
|
78
|
+
"description": "report lists external URLs written in documents"
|
|
79
|
+
},
|
|
80
|
+
"paths": {
|
|
81
|
+
"type": "array",
|
|
82
|
+
"description": "Relative globs; each document path must match at least one",
|
|
83
|
+
"minItems": 1,
|
|
84
|
+
"maxItems": 64,
|
|
85
|
+
"items": { "type": "string", "maxLength": 1024 }
|
|
86
|
+
}
|
|
87
|
+
}
|
|
60
88
|
}
|
|
61
89
|
}
|
|
62
90
|
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "gno://schemas/convert@1.0",
|
|
4
|
+
"title": "GNO Convert Result",
|
|
5
|
+
"description": "Output of gno convert --json and SDK convertFile: the Markdown GNO would index for one file",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": [
|
|
8
|
+
"schemaVersion",
|
|
9
|
+
"source",
|
|
10
|
+
"converter",
|
|
11
|
+
"title",
|
|
12
|
+
"languageHint",
|
|
13
|
+
"markdown",
|
|
14
|
+
"mirrorHash",
|
|
15
|
+
"warnings"
|
|
16
|
+
],
|
|
17
|
+
"additionalProperties": false,
|
|
18
|
+
"properties": {
|
|
19
|
+
"schemaVersion": {
|
|
20
|
+
"const": "convert@1.0"
|
|
21
|
+
},
|
|
22
|
+
"source": {
|
|
23
|
+
"type": "object",
|
|
24
|
+
"required": ["path", "mime", "ext", "sizeBytes"],
|
|
25
|
+
"additionalProperties": false,
|
|
26
|
+
"properties": {
|
|
27
|
+
"path": {
|
|
28
|
+
"type": "string",
|
|
29
|
+
"minLength": 1,
|
|
30
|
+
"description": "Absolute path of the converted file"
|
|
31
|
+
},
|
|
32
|
+
"mime": {
|
|
33
|
+
"type": "string",
|
|
34
|
+
"minLength": 1,
|
|
35
|
+
"description": "Detected MIME type"
|
|
36
|
+
},
|
|
37
|
+
"ext": {
|
|
38
|
+
"type": "string",
|
|
39
|
+
"description": "File extension, including the dot"
|
|
40
|
+
},
|
|
41
|
+
"sizeBytes": {
|
|
42
|
+
"type": "integer",
|
|
43
|
+
"minimum": 0
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"converter": {
|
|
48
|
+
"type": "object",
|
|
49
|
+
"required": ["id", "version"],
|
|
50
|
+
"additionalProperties": false,
|
|
51
|
+
"properties": {
|
|
52
|
+
"id": {
|
|
53
|
+
"type": "string",
|
|
54
|
+
"minLength": 1
|
|
55
|
+
},
|
|
56
|
+
"version": {
|
|
57
|
+
"type": "string",
|
|
58
|
+
"minLength": 1
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
"title": {
|
|
63
|
+
"type": ["string", "null"],
|
|
64
|
+
"description": "Title from conversion, or null"
|
|
65
|
+
},
|
|
66
|
+
"languageHint": {
|
|
67
|
+
"type": ["string", "null"],
|
|
68
|
+
"description": "BCP-47 language hint from conversion, or null"
|
|
69
|
+
},
|
|
70
|
+
"markdown": {
|
|
71
|
+
"type": "string",
|
|
72
|
+
"description": "Canonical Markdown, identical to the mirror indexing stores"
|
|
73
|
+
},
|
|
74
|
+
"mirrorHash": {
|
|
75
|
+
"type": "string",
|
|
76
|
+
"pattern": "^[a-f0-9]{64}$",
|
|
77
|
+
"description": "SHA-256 hex of the canonical Markdown, as stored by indexing"
|
|
78
|
+
},
|
|
79
|
+
"warnings": {
|
|
80
|
+
"type": "array",
|
|
81
|
+
"items": {
|
|
82
|
+
"type": "object",
|
|
83
|
+
"required": ["code", "message"],
|
|
84
|
+
"additionalProperties": false,
|
|
85
|
+
"properties": {
|
|
86
|
+
"code": {
|
|
87
|
+
"type": "string",
|
|
88
|
+
"minLength": 1
|
|
89
|
+
},
|
|
90
|
+
"message": {
|
|
91
|
+
"type": "string"
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "gno://schemas/ls@1.0",
|
|
4
|
+
"title": "GNO Document Listing",
|
|
5
|
+
"description": "Output of gno ls --json and SDK list(): one page of active documents in URI order",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": ["documents", "meta"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"documents": {
|
|
11
|
+
"type": "array",
|
|
12
|
+
"items": {
|
|
13
|
+
"type": "object",
|
|
14
|
+
"additionalProperties": false,
|
|
15
|
+
"required": ["docid", "uri", "source"],
|
|
16
|
+
"properties": {
|
|
17
|
+
"docid": { "type": "string", "pattern": "^#[a-f0-9]+$" },
|
|
18
|
+
"uri": { "type": "string", "pattern": "^gno://" },
|
|
19
|
+
"title": { "type": "string" },
|
|
20
|
+
"source": {
|
|
21
|
+
"type": "object",
|
|
22
|
+
"additionalProperties": false,
|
|
23
|
+
"required": ["relPath", "mime", "ext"],
|
|
24
|
+
"properties": {
|
|
25
|
+
"relPath": { "type": "string" },
|
|
26
|
+
"mime": { "type": "string" },
|
|
27
|
+
"ext": { "type": "string" }
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"meta": {
|
|
34
|
+
"type": "object",
|
|
35
|
+
"additionalProperties": false,
|
|
36
|
+
"required": ["total", "returned", "offset"],
|
|
37
|
+
"properties": {
|
|
38
|
+
"total": {
|
|
39
|
+
"type": "integer",
|
|
40
|
+
"minimum": 0,
|
|
41
|
+
"description": "Documents in scope that match the filter, before pagination"
|
|
42
|
+
},
|
|
43
|
+
"returned": { "type": "integer", "minimum": 0 },
|
|
44
|
+
"offset": { "type": "integer", "minimum": 0 },
|
|
45
|
+
"warnings": {
|
|
46
|
+
"type": "array",
|
|
47
|
+
"description": "Present only with a typed metadata filter when some documents could not be judged",
|
|
48
|
+
"minItems": 1,
|
|
49
|
+
"items": {
|
|
50
|
+
"type": "object",
|
|
51
|
+
"additionalProperties": false,
|
|
52
|
+
"required": ["code", "message"],
|
|
53
|
+
"properties": {
|
|
54
|
+
"code": {
|
|
55
|
+
"type": "string",
|
|
56
|
+
"enum": ["METADATA_COVERAGE_INCOMPLETE"]
|
|
57
|
+
},
|
|
58
|
+
"message": { "type": "string" }
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -223,7 +223,7 @@
|
|
|
223
223
|
"status": {
|
|
224
224
|
"type": "string",
|
|
225
225
|
"description": "Job status",
|
|
226
|
-
"enum": ["running", "completed", "failed"]
|
|
226
|
+
"enum": ["queued", "running", "completed", "failed"]
|
|
227
227
|
},
|
|
228
228
|
"startedAt": {
|
|
229
229
|
"type": "string",
|
|
@@ -247,6 +247,22 @@
|
|
|
247
247
|
"type": "string",
|
|
248
248
|
"description": "Error message if failed"
|
|
249
249
|
},
|
|
250
|
+
"scope": {
|
|
251
|
+
"type": "object",
|
|
252
|
+
"description": "Reindex jobs: what the job covers after merging requests",
|
|
253
|
+
"required": ["collection", "paths"],
|
|
254
|
+
"properties": {
|
|
255
|
+
"collection": {
|
|
256
|
+
"type": ["string", "null"],
|
|
257
|
+
"description": "Collection name, or null for all collections"
|
|
258
|
+
},
|
|
259
|
+
"paths": {
|
|
260
|
+
"type": ["array", "null"],
|
|
261
|
+
"description": "Collection-relative files, or null for the whole collection",
|
|
262
|
+
"items": { "type": "string" }
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
},
|
|
250
266
|
"serverInstanceId": {
|
|
251
267
|
"type": "string",
|
|
252
268
|
"description": "Server instance UUID",
|
|
@@ -19,8 +19,15 @@
|
|
|
19
19
|
},
|
|
20
20
|
"status": {
|
|
21
21
|
"type": "string",
|
|
22
|
-
"description": "
|
|
23
|
-
"enum": ["started"]
|
|
22
|
+
"description": "started: the job is running; queued: it waits behind another write job (requests for the same scope share one queued job)",
|
|
23
|
+
"enum": ["started", "queued"]
|
|
24
|
+
},
|
|
25
|
+
"paths": {
|
|
26
|
+
"type": "array",
|
|
27
|
+
"description": "Collection-relative files this sync reindexes; absent for a whole-collection sync",
|
|
28
|
+
"items": {
|
|
29
|
+
"type": "string"
|
|
30
|
+
}
|
|
24
31
|
},
|
|
25
32
|
"options": {
|
|
26
33
|
"type": "object",
|
|
@@ -454,6 +454,13 @@
|
|
|
454
454
|
"type": "string",
|
|
455
455
|
"description": "Collection filter if applied"
|
|
456
456
|
},
|
|
457
|
+
"collections": {
|
|
458
|
+
"type": "array",
|
|
459
|
+
"items": { "type": "string" },
|
|
460
|
+
"minItems": 1,
|
|
461
|
+
"maxItems": 256,
|
|
462
|
+
"description": "Normalized collection allowlist if applied (sorted, lowercase)"
|
|
463
|
+
},
|
|
457
464
|
"intent": {
|
|
458
465
|
"type": "string",
|
|
459
466
|
"description": "Disambiguating context used to steer retrieval without being searched directly"
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* @module src/cli/commands/indexCmd
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
import { resolveReindexScope } from "../../core/reindex-paths";
|
|
10
11
|
import {
|
|
11
12
|
type CliWriteLeaseOptions,
|
|
12
13
|
type WriteLeaseContention,
|
|
@@ -27,6 +28,7 @@ import {
|
|
|
27
28
|
type SyncResult,
|
|
28
29
|
withContentTypeRules,
|
|
29
30
|
} from "../../ingestion";
|
|
31
|
+
import { CliError } from "../errors";
|
|
30
32
|
import { type EmbedResult, embedStageOutcome } from "./embed";
|
|
31
33
|
import {
|
|
32
34
|
formatSyncResultLines,
|
|
@@ -44,6 +46,8 @@ export interface IndexOptions extends CliWriteLeaseOptions {
|
|
|
44
46
|
indexName?: string;
|
|
45
47
|
/** Scope to single collection */
|
|
46
48
|
collection?: string;
|
|
49
|
+
/** Reindex only these files of `collection` */
|
|
50
|
+
paths?: string[];
|
|
47
51
|
/** Run ingestion only, skip embedding */
|
|
48
52
|
noEmbed?: boolean;
|
|
49
53
|
/** Download models if missing */
|
|
@@ -186,6 +190,18 @@ export async function index(options: IndexOptions = {}): Promise<IndexResult> {
|
|
|
186
190
|
}
|
|
187
191
|
|
|
188
192
|
const { store, collections, config } = initResult;
|
|
193
|
+
let paths: string[] | null;
|
|
194
|
+
try {
|
|
195
|
+
paths = await resolveReindexScope(
|
|
196
|
+
options.collection ? (collections[0] ?? null) : null,
|
|
197
|
+
options.paths,
|
|
198
|
+
{ gitPull: options.gitPull }
|
|
199
|
+
);
|
|
200
|
+
} catch (e) {
|
|
201
|
+
await store.close();
|
|
202
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
203
|
+
throw new CliError("VALIDATION", message.replace(/^[A-Z_]+: /, ""));
|
|
204
|
+
}
|
|
189
205
|
const db = store.getRawDb();
|
|
190
206
|
const embedSkipped = options.noEmbed ?? false;
|
|
191
207
|
|
|
@@ -202,18 +218,40 @@ export async function index(options: IndexOptions = {}): Promise<IndexResult> {
|
|
|
202
218
|
markIndexStageRunning(db, "lexical", { collection: options.collection });
|
|
203
219
|
let syncResult: SyncResult;
|
|
204
220
|
try {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
onSlowConversion: reportSlowConversion,
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
)
|
|
216
|
-
|
|
221
|
+
const collection = collections[0];
|
|
222
|
+
if (paths && collection) {
|
|
223
|
+
const pathResult = await defaultSyncService.syncPaths(
|
|
224
|
+
collection,
|
|
225
|
+
store,
|
|
226
|
+
paths,
|
|
227
|
+
withContentTypeRules(
|
|
228
|
+
{ onSlowConversion: reportSlowConversion },
|
|
229
|
+
config
|
|
230
|
+
)
|
|
231
|
+
);
|
|
232
|
+
syncResult = {
|
|
233
|
+
collections: [pathResult],
|
|
234
|
+
totalDurationMs: pathResult.durationMs,
|
|
235
|
+
totalFilesProcessed: pathResult.filesProcessed,
|
|
236
|
+
totalFilesAdded: pathResult.filesAdded,
|
|
237
|
+
totalFilesUpdated: pathResult.filesUpdated,
|
|
238
|
+
totalFilesErrored: pathResult.filesErrored,
|
|
239
|
+
totalFilesSkipped: pathResult.filesSkipped,
|
|
240
|
+
};
|
|
241
|
+
} else {
|
|
242
|
+
syncResult = await defaultSyncService.syncAll(
|
|
243
|
+
collections,
|
|
244
|
+
store,
|
|
245
|
+
withContentTypeRules(
|
|
246
|
+
{
|
|
247
|
+
gitPull: options.gitPull,
|
|
248
|
+
runUpdateCmd: true,
|
|
249
|
+
onSlowConversion: reportSlowConversion,
|
|
250
|
+
},
|
|
251
|
+
config
|
|
252
|
+
)
|
|
253
|
+
);
|
|
254
|
+
}
|
|
217
255
|
} catch (e) {
|
|
218
256
|
const message = e instanceof Error ? e.message : String(e);
|
|
219
257
|
markIndexStageFinished(db, "lexical", "failed");
|
package/src/cli/commands/ls.ts
CHANGED
|
@@ -5,9 +5,14 @@
|
|
|
5
5
|
* @module src/cli/commands/ls
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import type { MetadataPredicate } from "../../core/typed-metadata";
|
|
8
9
|
import type { DocumentRow, StorePort, StoreResult } from "../../store/types";
|
|
9
10
|
|
|
10
11
|
import { decorateUriForIndex } from "../../app/constants";
|
|
12
|
+
import {
|
|
13
|
+
filterDocumentsByMetadata,
|
|
14
|
+
metadataCoverageWarnings,
|
|
15
|
+
} from "../../pipeline/filters";
|
|
11
16
|
import { initStore } from "./shared";
|
|
12
17
|
|
|
13
18
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -23,6 +28,8 @@ export interface LsCommandOptions {
|
|
|
23
28
|
limit?: number;
|
|
24
29
|
/** Skip first N results */
|
|
25
30
|
offset?: number;
|
|
31
|
+
/** Typed metadata predicate (same semantics as search --filter) */
|
|
32
|
+
filter?: MetadataPredicate;
|
|
26
33
|
/** JSON output */
|
|
27
34
|
json?: boolean;
|
|
28
35
|
/** File protocol output */
|
|
@@ -48,6 +55,8 @@ export interface LsResponse {
|
|
|
48
55
|
total: number;
|
|
49
56
|
returned: number;
|
|
50
57
|
offset: number;
|
|
58
|
+
/** Only with a filter, when documents could not be judged. */
|
|
59
|
+
warnings?: { code: string; message: string }[];
|
|
51
60
|
};
|
|
52
61
|
}
|
|
53
62
|
|
|
@@ -128,9 +137,16 @@ export async function ls(
|
|
|
128
137
|
return { success: false, error: docs.error.message };
|
|
129
138
|
}
|
|
130
139
|
|
|
131
|
-
|
|
132
|
-
const
|
|
133
|
-
|
|
140
|
+
const active = docs.value.filter((d) => d.active);
|
|
141
|
+
const filtered = options.filter
|
|
142
|
+
? filterDocumentsByMetadata(active, options.filter)
|
|
143
|
+
: undefined;
|
|
144
|
+
const warnings = filtered
|
|
145
|
+
? metadataCoverageWarnings(filtered, "listing")
|
|
146
|
+
: undefined;
|
|
147
|
+
|
|
148
|
+
// Sort by URI
|
|
149
|
+
const allActive = (filtered?.matches ?? active)
|
|
134
150
|
.map((d) => ({
|
|
135
151
|
docid: d.docid,
|
|
136
152
|
uri: d.uri,
|
|
@@ -160,6 +176,7 @@ export async function ls(
|
|
|
160
176
|
total: allActive.length,
|
|
161
177
|
returned: paged.length,
|
|
162
178
|
offset,
|
|
179
|
+
...(warnings ? { warnings } : {}),
|
|
163
180
|
},
|
|
164
181
|
},
|
|
165
182
|
};
|
|
@@ -267,7 +267,8 @@ export async function runProjectProfileApplyCommand(
|
|
|
267
267
|
];
|
|
268
268
|
const validationFailure =
|
|
269
269
|
applied.error.code === "PROFILE_INVALID" ||
|
|
270
|
-
applied.error.code === "RUNTIME_PATH_OVERLAP"
|
|
270
|
+
applied.error.code === "RUNTIME_PATH_OVERLAP" ||
|
|
271
|
+
applied.error.code === "WORKSPACE_ROOT_CONFLICT";
|
|
271
272
|
return {
|
|
272
273
|
result: failedApplyResult(
|
|
273
274
|
validationFailure ? "invalid" : "failed",
|