@gmickel/gno 2.13.0 → 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 +35 -4
- package/assets/skill/cli-reference.md +39 -1
- package/assets/skill/examples.md +30 -4
- package/assets/skill/mcp-reference.md +14 -0
- package/browser-extension/artifacts/{gno-browser-clipper-v2.13.0.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 +73 -11
- package/spec/mcp.md +15 -2
- package/spec/output-schemas/collection-list.schema.json +28 -0
- package/spec/output-schemas/ls.schema.json +65 -0
- package/src/cli/commands/ls.ts +20 -3
- package/src/cli/commands/profile-apply.ts +2 -1
- package/src/cli/program.ts +11 -0
- 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/egress-enforcement.ts +20 -4
- package/src/core/egress-policy.ts +4 -0
- package/src/core/egress-provenance.ts +33 -11
- package/src/core/project-profile-apply-state.ts +6 -15
- package/src/core/project-profile-apply.ts +32 -1
- package/src/pipeline/filters.ts +30 -2
- package/src/sdk/client.ts +6 -1
- package/src/sdk/documents.ts +15 -2
- package/src/sdk/types.ts +3 -0
- package/browser-extension/artifacts/gno-browser-clipper-v2.13.0.zip.sha256 +0 -1
package/README.md
CHANGED
|
@@ -139,7 +139,7 @@ See the [guide](docs/COMPILED-CONTEXT.md).
|
|
|
139
139
|
|
|
140
140
|
<!-- public-truth:current-version -->
|
|
141
141
|
|
|
142
|
-
> Current source version: **v2.
|
|
142
|
+
> Current source version: **v2.14.0**. See [CHANGELOG.md](./CHANGELOG.md).
|
|
143
143
|
|
|
144
144
|
<!-- /public-truth -->
|
|
145
145
|
|
package/assets/skill/SKILL.md
CHANGED
|
@@ -84,7 +84,7 @@ Recipe rules:
|
|
|
84
84
|
| ------------ | ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
|
|
85
85
|
| **Search** | `search`, `vsearch`, `query`, `ask` | Find documents by keywords, meaning, or get AI answers |
|
|
86
86
|
| **Links** | `links`, `backlinks`, `similar`, `graph`, `graph query` | Navigate document relationships and typed connections |
|
|
87
|
-
| **Retrieve** | `get`, `multi-get`, `ls`
|
|
87
|
+
| **Retrieve** | `get`, `multi-get`, `ls`, `ls --filter` | Fetch document content by URI or ID; list documents by typed metadata |
|
|
88
88
|
| **Index** | `setup`, `profile check/show/diff/apply`, `init`, `collection add/list/remove`, `index`, `update`, `embed` | Reproduce profile intent, prove retrieval, then maintain the index |
|
|
89
89
|
| **Tags** | `tags`, `tags add`, `tags rm` | Organize and filter documents |
|
|
90
90
|
| **Context** | `context add/list/rm/check/build/verify/watch/watches/reverify/unwatch` | Configure guidance or compile, verify, and watch saved evidence Capsules |
|
|
@@ -154,7 +154,9 @@ machines are slower.
|
|
|
154
154
|
exact identifier/quote/error you already have verbatim → `gno search` (a
|
|
155
155
|
question, or a name or topic taken from it, is not exact text). No good results: run balanced
|
|
156
156
|
`gno query`, then rephrase, then `--thorough`. An expected document still
|
|
157
|
-
missing: `gno query diagnose` before falling back to grep.
|
|
157
|
+
missing: `gno query diagnose` before falling back to grep. When the user
|
|
158
|
+
explicitly asks for a semantic, vector or meaning-only search (their documents
|
|
159
|
+
use different wording), use `gno vsearch` instead.
|
|
158
160
|
|
|
159
161
|
## Common Flags (search/vsearch/query/ask)
|
|
160
162
|
|
|
@@ -345,7 +347,10 @@ confirmation and invalidates active sessions, streams, and queued work.
|
|
|
345
347
|
|
|
346
348
|
Bearer authentication, MCP write enablement, and collection policy are
|
|
347
349
|
independent gates. `EGRESS_DENIED` is not permission to retry through another
|
|
348
|
-
surface.
|
|
350
|
+
surface. The one exception is reason `COLLECTION_LIMIT_EXCEEDED`: the call
|
|
351
|
+
covered more than 64 collections (128 for lineage), so retry it scoped to the
|
|
352
|
+
collections the task needs (`collection`/`collections`, `-c`). It is not an
|
|
353
|
+
outage; never restart, raise a limit or relax policy for it. Audit output is local and content-free via
|
|
349
354
|
`gno egress-audit list|show|status`; deletion/purge must be explicit. A local
|
|
350
355
|
policy change cannot retract data already uploaded—tell the user to remove it
|
|
351
356
|
at the remote service. For gno.sh, supported private links can be revoked or
|
|
@@ -371,6 +376,29 @@ never from code spans, code blocks, or non-Markdown files.
|
|
|
371
376
|
Report `truncation.snapshotTruncated` as "totals cover the bounded snapshot,
|
|
372
377
|
not the whole index".
|
|
373
378
|
|
|
379
|
+
A collection can opt into three report-only link rules with an `audit` block in
|
|
380
|
+
its config: `linkCollections` (other collections it may link to; its own is
|
|
381
|
+
always allowed), `externalUrls: report`, and `paths` (globs every document path
|
|
382
|
+
must match). Their findings are `warning`s: `links.collection-policy`,
|
|
383
|
+
`links.external-url` and `links.path-layout`. Report them as structure and
|
|
384
|
+
publishing hygiene, not access control: `links.external-url` only reports a
|
|
385
|
+
URL written in a note; it sends and blocks nothing, so the remedy is editing
|
|
386
|
+
the note or setting `externalUrls: ignore`, never a collection policy change.
|
|
387
|
+
Show which URLs were found with
|
|
388
|
+
`gno audit links --json | jq -r '.findings[] | select(.ruleId == "links.external-url") | "\(.subject) \(.location) \(.evidence[0].summary)"'`.
|
|
389
|
+
Never add an `audit` block on your own initiative. When the user asks for a
|
|
390
|
+
rule, there is no CLI flag: always write out the exact `audit` block for that
|
|
391
|
+
collection's entry in the config file, then run the check. For "published may
|
|
392
|
+
link only to reference":
|
|
393
|
+
|
|
394
|
+
```bash
|
|
395
|
+
gno doctor # prints "Config loaded: <path>"
|
|
396
|
+
# In <path>, under the `published` collection entry, add:
|
|
397
|
+
# audit:
|
|
398
|
+
# linkCollections: [reference]
|
|
399
|
+
gno audit links -c published --json
|
|
400
|
+
```
|
|
401
|
+
|
|
374
402
|
Treat exit `4` as a complete report with findings. Exit `5` or report status
|
|
375
403
|
`partial`/`changed_during_audit` means evidence is unavailable, inconclusive,
|
|
376
404
|
cancelled, truncated, or repeatedly changed—never healthy. Preserve stable
|
|
@@ -753,7 +781,10 @@ fields must be indexed from nested YAML `gno.metadata`; arbitrary frontmatter
|
|
|
753
781
|
keys are not automatically custom fields. Run `gno metadata --collection <c>`
|
|
754
782
|
(MCP `gno_list_metadata`) first to see which keys, types and values exist.
|
|
755
783
|
CLI retrieval accepts `--filter` JSON; MCP/SDK/REST accept the same `filter`
|
|
756
|
-
object
|
|
784
|
+
object. To enumerate documents by metadata with no search term (every
|
|
785
|
+
`status: draft` note), use `gno ls [<collection>] --filter '<json>'`, not a
|
|
786
|
+
search with a placeholder query; `--json` returns `{documents, meta}`, so read
|
|
787
|
+
`.documents[]` and `meta.total`:
|
|
757
788
|
|
|
758
789
|
```json
|
|
759
790
|
{
|
|
@@ -510,9 +510,14 @@ gno multi-get <pattern> [--max-bytes <n>] [--line-numbers]
|
|
|
510
510
|
List documents.
|
|
511
511
|
|
|
512
512
|
```bash
|
|
513
|
-
gno ls [<scope>] [--json|--files|--md]
|
|
513
|
+
gno ls [<scope>] [--filter <json>] [-n <num>] [--offset <num>] [--json|--files|--md]
|
|
514
514
|
```
|
|
515
515
|
|
|
516
|
+
- `<scope>`: collection name or `gno://collection/prefix`
|
|
517
|
+
- `--filter <json>`: list only documents whose typed metadata (`gno.metadata`) matches; same predicate syntax and semantics as `gno search --filter`. Applies before pagination
|
|
518
|
+
- `--json` returns `{documents: [{docid, uri, title, source}], meta: {total, returned, offset}}`; `meta.total` counts all matches
|
|
519
|
+
- With `--filter`, `meta.warnings` (`METADATA_COVERAGE_INCOMPLETE`) appears when documents with invalid or pending metadata were skipped; other formats print it on stderr
|
|
520
|
+
|
|
516
521
|
## Context Management
|
|
517
522
|
|
|
518
523
|
### gno context add
|
|
@@ -653,6 +658,9 @@ gno egress-audit purge
|
|
|
653
658
|
Denied egress is terminal for that route; do not retry through another network
|
|
654
659
|
surface. Relaxing policy requires the current revision; tightening to
|
|
655
660
|
`local_only` does not. Audit receipts are local and content-free.
|
|
661
|
+
`COLLECTION_LIMIT_EXCEEDED` is the one denial to retry: the request covered more
|
|
662
|
+
than 64 collections (128 for lineage), so name only the collections it needs
|
|
663
|
+
(`-c <name>`).
|
|
656
664
|
Deletion/purge must remain explicit.
|
|
657
665
|
|
|
658
666
|
## Note Linking
|
|
@@ -849,6 +857,36 @@ gno models path [--json]
|
|
|
849
857
|
|
|
850
858
|
## Maintenance
|
|
851
859
|
|
|
860
|
+
### gno audit
|
|
861
|
+
|
|
862
|
+
Read-only workspace integrity report. Exit 4 = complete with findings, 5 =
|
|
863
|
+
partial/inconclusive.
|
|
864
|
+
|
|
865
|
+
```bash
|
|
866
|
+
gno audit [links|provenance|freshness|all] [-c <collection>] [--json]
|
|
867
|
+
gno audit links -c published --json
|
|
868
|
+
```
|
|
869
|
+
|
|
870
|
+
Opt-in, report-only collection rules come from an `audit` block on a
|
|
871
|
+
collection in the config file (`gno doctor` shows its path); there are no CLI
|
|
872
|
+
flags for them:
|
|
873
|
+
|
|
874
|
+
```yaml
|
|
875
|
+
collections:
|
|
876
|
+
- name: published
|
|
877
|
+
path: ~/notes/published
|
|
878
|
+
audit:
|
|
879
|
+
linkCollections: [reference] # other collections it may link to
|
|
880
|
+
externalUrls: report # report | ignore (default ignore)
|
|
881
|
+
paths: ["20??/**/*.md"] # globs every document path must match
|
|
882
|
+
```
|
|
883
|
+
|
|
884
|
+
| Rule id | Reports |
|
|
885
|
+
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
|
|
886
|
+
| `links.collection-policy` | A link into a collection `linkCollections` does not list |
|
|
887
|
+
| `links.external-url` | A URL written in a document (outside frontmatter, code, comments), or `unchecked` when the text is unavailable. Not egress |
|
|
888
|
+
| `links.path-layout` | A document whose path matches none of the `paths` globs |
|
|
889
|
+
|
|
852
890
|
### gno peek
|
|
853
891
|
|
|
854
892
|
Cheap counts, backlog, recent files, and serve liveness. Same `peek@1.0`
|
package/assets/skill/examples.md
CHANGED
|
@@ -183,6 +183,17 @@ gno ls work
|
|
|
183
183
|
gno ls --json
|
|
184
184
|
```
|
|
185
185
|
|
|
186
|
+
### List by metadata
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
# Every draft note in work (no search term needed)
|
|
190
|
+
gno ls work --filter '{"op":"eq","key":"status","value":"draft"}'
|
|
191
|
+
|
|
192
|
+
# URIs of every note whose project list contains atlas
|
|
193
|
+
gno ls work --filter '{"op":"in","key":"project","values":["atlas"]}' -n 1000 --json \
|
|
194
|
+
| jq -r '.documents[].uri'
|
|
195
|
+
```
|
|
196
|
+
|
|
186
197
|
## Search & Retrieve Full Content
|
|
187
198
|
|
|
188
199
|
### Pipeline: Search then get
|
|
@@ -204,10 +215,10 @@ gno search "error handling" --json | jq -r '.results[].uri' | xargs gno multi-ge
|
|
|
204
215
|
|
|
205
216
|
```bash
|
|
206
217
|
# Get URIs of matches
|
|
207
|
-
gno search "api endpoint" --json | jq '.[] | .uri'
|
|
218
|
+
gno search "api endpoint" --json | jq '.results[] | .uri'
|
|
208
219
|
|
|
209
220
|
# Get snippets
|
|
210
|
-
gno search "config" --json | jq '.[] | {uri, snippet}'
|
|
221
|
+
gno search "config" --json | jq '.results[] | {uri, snippet}'
|
|
211
222
|
```
|
|
212
223
|
|
|
213
224
|
### Check index health
|
|
@@ -224,10 +235,10 @@ gno doctor --json
|
|
|
224
235
|
|
|
225
236
|
```bash
|
|
226
237
|
# Export all document IDs
|
|
227
|
-
gno ls --json | jq -r '.[].docid' > doc-ids.txt
|
|
238
|
+
gno ls --json -n 10000 | jq -r '.documents[].docid' > doc-ids.txt
|
|
228
239
|
|
|
229
240
|
# Search and process results
|
|
230
|
-
gno search "error" --json | jq -r '.[] | .uri' | while read uri; do
|
|
241
|
+
gno search "error" --json | jq -r '.results[] | .uri' | while read uri; do
|
|
231
242
|
echo "Processing: $uri"
|
|
232
243
|
gno get "$uri" > "output/$(basename $uri)"
|
|
233
244
|
done
|
|
@@ -235,6 +246,21 @@ done
|
|
|
235
246
|
|
|
236
247
|
## Maintenance
|
|
237
248
|
|
|
249
|
+
### Check a published collection's links
|
|
250
|
+
|
|
251
|
+
Let `published` link only to itself and `reference`: add this to the
|
|
252
|
+
`published` collection in the config file (`gno doctor` shows its path).
|
|
253
|
+
|
|
254
|
+
```yaml
|
|
255
|
+
audit:
|
|
256
|
+
linkCollections: [reference]
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
gno audit links -c published --json \
|
|
261
|
+
| jq -r '.findings[] | select(.ruleId == "links.collection-policy") | "\(.subject) \(.location): \(.message)"'
|
|
262
|
+
```
|
|
263
|
+
|
|
238
264
|
### Update index after changes
|
|
239
265
|
|
|
240
266
|
```bash
|
|
@@ -93,6 +93,14 @@ gno serve --status --json
|
|
|
93
93
|
gno daemon --status --json
|
|
94
94
|
```
|
|
95
95
|
|
|
96
|
+
Each HTTP request is checked against the egress policy of the collections it
|
|
97
|
+
covers: the ones it names, or every configured collection when it names none.
|
|
98
|
+
One check covers at most 64 collections (128 for a policy lineage; 64 names for
|
|
99
|
+
`gno_egress_check`). A 403 whose reason is `COLLECTION_LIMIT_EXCEEDED` means the
|
|
100
|
+
call covered too many collections: retry with `collection` or `collections` set
|
|
101
|
+
to just the ones the task needs. It is not an outage, so do not restart the
|
|
102
|
+
server, raise a limit, change policy, or retry through another surface.
|
|
103
|
+
|
|
96
104
|
## Retrieval Order
|
|
97
105
|
|
|
98
106
|
`gno mcp --tool-profile core` (or `gateway.toolProfile: core` for the resident
|
|
@@ -253,6 +261,12 @@ before calling.
|
|
|
253
261
|
`not_found`, so do not blindly resend an uncertain old write as new.
|
|
254
262
|
- Errors arrive as tool text `CODE: message` with `structuredContent.error`.
|
|
255
263
|
|
|
264
|
+
## Audits
|
|
265
|
+
|
|
266
|
+
`gno_audit` returns the same report as `gno audit`. Collection `audit` config
|
|
267
|
+
adds `links.collection-policy`, `links.external-url` and `links.path-layout`
|
|
268
|
+
findings with no new tool inputs; they report structure, not egress.
|
|
269
|
+
|
|
256
270
|
## Uninstall
|
|
257
271
|
|
|
258
272
|
```bash
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
aca4d00878cb85d4f57181425caf0bb2175ecec0a5bc4ea437e994b8fd42c9cc gno-browser-clipper-v2.14.0.zip
|
package/package.json
CHANGED
package/spec/cli.md
CHANGED
|
@@ -191,7 +191,11 @@ through a resumable operation. It can initialize a missing user config. Omitted
|
|
|
191
191
|
collection-scoped contexts, and content-type rules remain untouched; stale
|
|
192
192
|
same-path collections are reported as skipped and retained. A stale same-name
|
|
193
193
|
collection root is repaired in place without deleting its collection or index
|
|
194
|
-
identity.
|
|
194
|
+
identity. A re-applied collection keeps every setting the profile does not
|
|
195
|
+
own (for example `egressPolicy`, `egressPolicyRevision`, `sourceAvailability`,
|
|
196
|
+
`workspaceRoot`, `memoryManaged`, `audit` and `updateCmd`). When a repaired root
|
|
197
|
+
falls outside an explicit `workspaceRoot`, apply fails with
|
|
198
|
+
`WORKSPACE_ROOT_CONFLICT` (exit 1) before any config write. Apply also updates a timestamp-free `projectProfileBindings` record
|
|
195
199
|
in the local user config with the canonical absolute profile path, profile
|
|
196
200
|
fingerprint, and projected collection. The public `profile_binding` resource
|
|
197
201
|
receipt identifies only the collection and never exposes that local path.
|
|
@@ -893,6 +897,12 @@ List all configured collections.
|
|
|
893
897
|
gno collection list [--json|--md]
|
|
894
898
|
```
|
|
895
899
|
|
|
900
|
+
Each JSON item is the configured collection plus `effectiveWorkspaceRoot` and
|
|
901
|
+
`workspaceSource`. A collection with an `audit` block lists it unchanged
|
|
902
|
+
(`linkCollections`, `externalUrls`, `paths`); see
|
|
903
|
+
[gno audit](#gno-audit). Schema:
|
|
904
|
+
[`collection-list@1.0`](./output-schemas/collection-list.schema.json).
|
|
905
|
+
|
|
896
906
|
---
|
|
897
907
|
|
|
898
908
|
### gno collection clear-embeddings
|
|
@@ -1046,6 +1056,32 @@ target missing from the listing stays unresolved; an unreadable folder or the
|
|
|
1046
1056
|
file bound makes the listing incomplete, which the `links.outside-index` rule
|
|
1047
1057
|
message states once.
|
|
1048
1058
|
|
|
1059
|
+
**Opt-in collection rules.** A collection's optional `audit` config object
|
|
1060
|
+
adds three report-only `links` rules. Each is emitted only when an audited
|
|
1061
|
+
collection (the `--collection` filter, else every collection) configures it,
|
|
1062
|
+
so without `audit` the rule list, findings, fingerprints and exit codes are
|
|
1063
|
+
unchanged. The config fingerprint includes a collection's `audit` object only
|
|
1064
|
+
when present on an audited collection.
|
|
1065
|
+
|
|
1066
|
+
| Rule id | Enabled by | Reports |
|
|
1067
|
+
| ------------------------- | ---------------------------- | ---------------------------------------------------------------------------------------------------- |
|
|
1068
|
+
| `links.collection-policy` | `audit.linkCollections` | A link that resolves into a collection the list does not name |
|
|
1069
|
+
| `links.external-url` | `audit.externalUrls: report` | An external URL written in a document, or a document whose indexed text is unavailable (`unchecked`) |
|
|
1070
|
+
| `links.path-layout` | `audit.paths` | A document whose collection-relative path matches none of the globs |
|
|
1071
|
+
|
|
1072
|
+
Findings are `warning`s with location evidence: `collection-policy` (detail
|
|
1073
|
+
`sourceCollection`, `targetCollection`, `target`, `linkType`, `allowed`) at the
|
|
1074
|
+
link's line and column, `external-url` at the URL's line and column (or
|
|
1075
|
+
`external-url-unchecked` with no location), and `path-layout` (detail
|
|
1076
|
+
`paths`). Only links that resolve to exactly one document are policy findings.
|
|
1077
|
+
External URLs are `scheme://` URLs in the document's indexed text outside
|
|
1078
|
+
frontmatter, code and HTML comments; `gno://` and `file://` are local. Path
|
|
1079
|
+
globs use `pattern` syntax against `recordSourcePath ?? relPath`. A truncated
|
|
1080
|
+
snapshot makes all three `inconclusive`. Config validation: `linkCollections`
|
|
1081
|
+
members must name configured collections, `externalUrls` is `report` or
|
|
1082
|
+
`ignore`, and `paths` is 1-64 relative globs without `..` and with balanced
|
|
1083
|
+
`{}` / `[]`.
|
|
1084
|
+
|
|
1049
1085
|
The wiki link parser reads Obsidian's table-escaped alias `[[Note\|Alias]]`
|
|
1050
1086
|
as target `Note` with alias `Alias`. Markdown link text may contain balanced
|
|
1051
1087
|
square brackets (`[see [1]](note.md)`); a destination containing a square
|
|
@@ -2564,7 +2600,7 @@ List documents in a collection or prefix.
|
|
|
2564
2600
|
**Synopsis:**
|
|
2565
2601
|
|
|
2566
2602
|
```bash
|
|
2567
|
-
gno ls [<scope>] [--json|--files|--md]
|
|
2603
|
+
gno ls [<scope>] [--filter <json>] [-n <num>] [--offset <num>] [--json|--files|--md]
|
|
2568
2604
|
```
|
|
2569
2605
|
|
|
2570
2606
|
**Arguments:**
|
|
@@ -2572,23 +2608,49 @@ gno ls [<scope>] [--json|--files|--md]
|
|
|
2572
2608
|
|-----|------|-------------|
|
|
2573
2609
|
| `<scope>` | string | Collection name or `gno://collection/prefix` (default: all) |
|
|
2574
2610
|
|
|
2575
|
-
**
|
|
2611
|
+
**Options:**
|
|
2612
|
+
| Flag | Type | Description |
|
|
2613
|
+
|------|------|-------------|
|
|
2614
|
+
| `--filter` | JSON | Typed metadata predicate; same schema and semantics as `gno search --filter` |
|
|
2615
|
+
| `-n, --limit` | integer | Max documents (default 20) |
|
|
2616
|
+
| `--offset` | integer | Skip the first N documents |
|
|
2617
|
+
|
|
2618
|
+
Active documents are listed in URI order. With `--filter`, only documents whose
|
|
2619
|
+
typed metadata satisfies the predicate are listed; documents with invalid or
|
|
2620
|
+
not-yet-extracted metadata never match, including under negated predicates.
|
|
2621
|
+
The filter and the scope both apply, before pagination: `limit`, `offset` and
|
|
2622
|
+
`meta.total` count matching documents only. Without `--filter`, output is
|
|
2623
|
+
unchanged.
|
|
2624
|
+
|
|
2625
|
+
**Output (JSON):** [`ls@1.0`](output-schemas/ls.schema.json)
|
|
2576
2626
|
|
|
2577
2627
|
```json
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2628
|
+
{
|
|
2629
|
+
"documents": [
|
|
2630
|
+
{
|
|
2631
|
+
"docid": "#a1b2c3d4",
|
|
2632
|
+
"uri": "gno://work/doc.md",
|
|
2633
|
+
"title": "Document Title",
|
|
2634
|
+
"source": { "relPath": "doc.md", "mime": "text/markdown", "ext": ".md" }
|
|
2635
|
+
}
|
|
2636
|
+
],
|
|
2637
|
+
"meta": {
|
|
2638
|
+
"total": 12,
|
|
2639
|
+
"returned": 1,
|
|
2640
|
+
"offset": 0,
|
|
2641
|
+
"warnings": [{ "code": "METADATA_COVERAGE_INCOMPLETE", "message": "..." }]
|
|
2584
2642
|
}
|
|
2585
|
-
|
|
2643
|
+
}
|
|
2586
2644
|
```
|
|
2587
2645
|
|
|
2646
|
+
`meta.warnings` appears only with `--filter` when documents in scope were
|
|
2647
|
+
skipped because their metadata is invalid or pending re-ingestion. Terminal,
|
|
2648
|
+
`--files` and `--md` output print the warning on stderr.
|
|
2649
|
+
|
|
2588
2650
|
**Exit Codes:**
|
|
2589
2651
|
|
|
2590
2652
|
- 0: Success
|
|
2591
|
-
- 1: Invalid scope
|
|
2653
|
+
- 1: Invalid scope or invalid `--filter` (`VALIDATION`, same message as `gno search --filter`)
|
|
2592
2654
|
- 2: DB failure
|
|
2593
2655
|
|
|
2594
2656
|
---
|
package/spec/mcp.md
CHANGED
|
@@ -338,6 +338,13 @@ compatible collection policy. Policy denial returns HTTP 403 with stable
|
|
|
338
338
|
`EGRESS_DENIED` data and a redacted evaluator audit. Write authorization remains
|
|
339
339
|
an independent additional requirement.
|
|
340
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
|
+
|
|
341
348
|
The MCP tool and resource registry is paired with a callsite-level
|
|
342
349
|
network-boundary inventory. A TypeScript AST scan covers shipped TS, TSX, JS,
|
|
343
350
|
and JSX and recognizes direct, qualified, bracketed, imported, and aliased
|
|
@@ -411,7 +418,10 @@ Rules report `pass`, `fail`, `skip`, `unavailable`, or `inconclusive`; reports
|
|
|
411
418
|
are `complete`, `partial`, `changed_during_audit`, or `failed`. A passing rule
|
|
412
419
|
may carry `info` findings (`links.outside-index`: link targets that exist as
|
|
413
420
|
files in the link workspace but are not indexed); only `warning` and `error`
|
|
414
|
-
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
|
|
415
425
|
changing evidence never appears healthy. Stable finding IDs are derived from
|
|
416
426
|
rule, normalized subject/location, and evidence fingerprint. Responses are
|
|
417
427
|
canonically ordered and bounded while retaining exact pre-truncation totals.
|
|
@@ -3386,7 +3396,10 @@ Read tools:
|
|
|
3386
3396
|
caller authentication/authorization, content class, and partial mode. It
|
|
3387
3397
|
performs no action and returns the canonical decision/explanation contract.
|
|
3388
3398
|
An explicit scope is a non-empty, duplicate-free list of at most 64 canonical
|
|
3389
|
-
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.
|
|
3390
3403
|
- `gno_egress_audit_list`, `gno_egress_audit_show`, and
|
|
3391
3404
|
`gno_egress_audit_status` expose only content-free local receipts.
|
|
3392
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,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
|
+
}
|
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",
|
package/src/cli/program.ts
CHANGED
|
@@ -2625,6 +2625,7 @@ function wireRetrievalCommands(program: Command): void {
|
|
|
2625
2625
|
"Skip first N results",
|
|
2626
2626
|
parsePositiveInt.bind(null, "offset")
|
|
2627
2627
|
)
|
|
2628
|
+
.option("--filter <json>", "typed custom metadata predicate (JSON)")
|
|
2628
2629
|
.option("--json", "JSON output")
|
|
2629
2630
|
.option("--files", "File protocol output")
|
|
2630
2631
|
.option("--md", "Markdown output")
|
|
@@ -2633,6 +2634,7 @@ function wireRetrievalCommands(program: Command): void {
|
|
|
2633
2634
|
const format = getFormat(cmdOpts);
|
|
2634
2635
|
assertFormatSupported(CMD.ls, format);
|
|
2635
2636
|
const globals = getGlobals();
|
|
2637
|
+
const filter = parseCliMetadataFilter(cmdOpts.filter);
|
|
2636
2638
|
|
|
2637
2639
|
const { ls, formatLs } = await import("./commands/ls");
|
|
2638
2640
|
const result = await ls(scope, {
|
|
@@ -2640,6 +2642,7 @@ function wireRetrievalCommands(program: Command): void {
|
|
|
2640
2642
|
indexName: globals.index,
|
|
2641
2643
|
limit: cmdOpts.limit as number | undefined,
|
|
2642
2644
|
offset: cmdOpts.offset as number | undefined,
|
|
2645
|
+
filter,
|
|
2643
2646
|
json: format === "json",
|
|
2644
2647
|
files: format === "files",
|
|
2645
2648
|
md: format === "md",
|
|
@@ -2652,6 +2655,14 @@ function wireRetrievalCommands(program: Command): void {
|
|
|
2652
2655
|
);
|
|
2653
2656
|
}
|
|
2654
2657
|
|
|
2658
|
+
// JSON carries warnings in meta; other formats keep stdout clean.
|
|
2659
|
+
if (format !== "json") {
|
|
2660
|
+
for (const warning of result.data.meta.warnings ?? []) {
|
|
2661
|
+
process.stderr.write(
|
|
2662
|
+
`Warning: ${warning.code}: ${warning.message}\n`
|
|
2663
|
+
);
|
|
2664
|
+
}
|
|
2665
|
+
}
|
|
2655
2666
|
const output = formatLs(result, {
|
|
2656
2667
|
json: format === "json",
|
|
2657
2668
|
files: format === "files",
|