@gmickel/gno 2.10.1 → 2.12.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 +11 -11
- package/assets/skill/SKILL.md +27 -15
- package/assets/skill/cli-reference.md +6 -5
- package/assets/skill/examples.md +16 -12
- package/assets/skill/mcp-reference.md +2 -1
- package/assets/spa-production.json.gz +0 -0
- package/browser-extension/artifacts/{gno-browser-clipper-v2.10.1.zip → gno-browser-clipper-v2.12.0.zip} +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v2.12.0.zip.sha256 +1 -0
- package/browser-extension/dist/manifest.json +1 -1
- package/package.json +10 -5
- package/spec/cli.md +127 -35
- package/spec/evals-agentic.md +3 -1
- package/spec/mcp.md +36 -6
- package/spec/output-schemas/ask.schema.json +8 -0
- package/spec/output-schemas/claim-verification.schema.json +8 -2
- package/spec/output-schemas/context-capsule-v1.schema.json +6 -1
- package/spec/output-schemas/context-capsule-verification.schema.json +4 -2
- package/spec/output-schemas/get.schema.json +4 -0
- package/spec/output-schemas/metadata-summary.schema.json +60 -0
- package/spec/output-schemas/multi-get.schema.json +4 -0
- package/spec/output-schemas/search-result.schema.json +4 -0
- package/spec/output-schemas/search-results.schema.json +4 -0
- package/spec/output-schemas/status.schema.json +28 -0
- package/src/app/constants.ts +16 -0
- package/src/app/context-agent-projection.ts +10 -1
- package/src/app/context-format.ts +1 -0
- package/src/app/verified-ask.ts +2 -0
- package/src/cli/commands/agents/block.ts +10 -9
- package/src/cli/commands/agents/commands.ts +6 -5
- package/src/cli/commands/agents/engine.ts +15 -2
- package/src/cli/commands/agents/harnesses.ts +21 -14
- package/src/cli/commands/ask-format.ts +18 -1
- package/src/cli/commands/ask.ts +4 -5
- package/src/cli/commands/cleanup.ts +46 -6
- package/src/cli/commands/collection/remove.ts +1 -0
- package/src/cli/commands/collection/rename.ts +1 -0
- package/src/cli/commands/daemon.ts +5 -1
- package/src/cli/commands/doctor.ts +37 -0
- package/src/cli/commands/get.ts +11 -1
- package/src/cli/commands/mcp/paths.ts +2 -1
- package/src/cli/commands/metadata.ts +79 -0
- package/src/cli/commands/multi-get.ts +13 -0
- package/src/cli/commands/setup-semantic.ts +6 -1
- package/src/cli/commands/shared.ts +35 -8
- package/src/cli/commands/skill/paths.ts +20 -2
- package/src/cli/commands/status.ts +89 -15
- package/src/cli/format/search-results.ts +11 -0
- package/src/cli/options.ts +2 -0
- package/src/cli/program.ts +64 -3
- package/src/core/activation-probe-plan.ts +0 -1
- package/src/core/config-mutation.ts +72 -55
- package/src/core/context-capsule-schema.ts +2 -0
- package/src/core/context-capsule-verification.ts +2 -0
- package/src/core/context-compiler.ts +2 -5
- package/src/core/context-evidence.ts +1 -0
- package/src/core/context-verifier.ts +14 -1
- package/src/core/memory-remember.ts +0 -1
- package/src/core/metadata-discovery.ts +169 -0
- package/src/core/module-path.ts +33 -0
- package/src/core/runtime-entrypoint.ts +3 -1
- package/src/ingestion/file-processor.ts +6 -3
- package/src/ingestion/prepare-file.ts +14 -4
- package/src/ingestion/source-availability/root.ts +138 -0
- package/src/ingestion/sync.ts +35 -1
- package/src/ingestion/walker.ts +11 -3
- package/src/llm/native-worker/client.ts +8 -4
- package/src/llm/native-worker/errors.ts +26 -3
- package/src/mcp/http-egress.ts +1 -0
- package/src/mcp/http-transport.ts +7 -2
- package/src/mcp/server.ts +3 -0
- package/src/mcp/tool-descriptions-core.ts +3 -3
- package/src/mcp/tool-profile.ts +16 -1
- package/src/mcp/tools/get.ts +10 -0
- package/src/mcp/tools/index.ts +68 -4
- package/src/mcp/tools/multi-get.ts +15 -0
- package/src/mcp/tools/query.ts +5 -3
- package/src/mcp/tools/search.ts +5 -3
- package/src/mcp/tools/status.ts +17 -2
- package/src/mcp/tools/vsearch.ts +5 -3
- package/src/mcp/tools/workspace-write.ts +42 -34
- package/src/pipeline/answer-prompt.ts +15 -2
- package/src/pipeline/answer.ts +3 -0
- package/src/pipeline/claim-verification-schema.ts +6 -1
- package/src/pipeline/claim-verification.ts +54 -1
- package/src/pipeline/explain.ts +1 -1
- package/src/pipeline/fusion.ts +24 -4
- package/src/pipeline/hybrid.ts +5 -1
- package/src/pipeline/query-snippet.ts +266 -0
- package/src/pipeline/result-context.ts +29 -0
- package/src/pipeline/search.ts +154 -20
- package/src/pipeline/types.ts +4 -0
- package/src/pipeline/vsearch.ts +5 -1
- package/src/sdk/client.ts +46 -6
- package/src/sdk/documents.ts +5 -0
- package/src/sdk/types.ts +11 -1
- package/src/serve/public/components/ThoroughnessSelector.tsx +1 -1
- package/src/serve/public/globals.built.css +1 -1
- package/src/serve/public/pages/Collections.tsx +8 -0
- package/src/serve/public/pages/Search.tsx +9 -1
- package/src/serve/resident-request.ts +8 -0
- package/src/serve/resident-runtime.ts +25 -3
- package/src/serve/routes/api.ts +29 -1
- package/src/serve/server.ts +12 -0
- package/src/serve/spa-production-build.ts +7 -3
- package/src/serve/status-model.ts +2 -0
- package/src/serve/status.ts +29 -0
- package/src/sessions/config-refresh.ts +6 -0
- package/src/sessions/import-child.ts +4 -1
- package/src/store/sqlite/adapter.ts +241 -20
- package/src/store/types.ts +61 -7
- package/src/store/vector/variant-search.ts +112 -74
- package/browser-extension/artifacts/gno-browser-clipper-v2.10.1.zip.sha256 +0 -1
package/spec/mcp.md
CHANGED
|
@@ -7,7 +7,10 @@
|
|
|
7
7
|
**Transport:** JSON-RPC 2.0 over stdio or resident Streamable HTTP
|
|
8
8
|
**SDK:** `@modelcontextprotocol/server` 2.x (tool `inputSchema` /
|
|
9
9
|
`outputSchema` carry the JSON Schema 2020-12 `$schema` stamp; an unknown tool
|
|
10
|
-
name answers JSON-RPC `-32602`)
|
|
10
|
+
name answers JSON-RPC `-32602`). Tool inputs are closed objects: an argument
|
|
11
|
+
key a tool does not declare fails validation with an error naming the key, and
|
|
12
|
+
the tool does not run. Each `inputSchema` advertises `additionalProperties:
|
|
13
|
+
false` (per `oneOf` member for the discriminated-union inputs).
|
|
11
14
|
|
|
12
15
|
This document specifies the MCP server interface for GNO.
|
|
13
16
|
|
|
@@ -153,7 +156,7 @@ the resident gateway applies one profile to every connected client.
|
|
|
153
156
|
|
|
154
157
|
| Profile | Without `--enable-write` | With `--enable-write` |
|
|
155
158
|
| ---------------- | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------- |
|
|
156
|
-
| `full` (default) | Every read tool below (
|
|
159
|
+
| `full` (default) | Every read tool below (38) | Every read tool plus every write tool (60) |
|
|
157
160
|
| `core` | `gno_query`, `gno_search`, `gno_get`, `gno_multi_get`, `gno_context`, `gno_changes`, `gno_recall` (7) | The 7 read tools plus `gno_capture`, `gno_remember` (9) |
|
|
158
161
|
|
|
159
162
|
Both lists are exact: `core` advertises nothing else, and `full` is byte-for-byte
|
|
@@ -525,7 +528,7 @@ non-reflection contract as all MCP retrieval tools.
|
|
|
525
528
|
|
|
526
529
|
`structuredContent` is the complete canonical Context Capsule object for
|
|
527
530
|
application clients. Model-visible text is always one deterministic
|
|
528
|
-
`gno-context-agent-
|
|
531
|
+
`gno-context-agent-v2` JSON projection, even when the compatibility `format`
|
|
529
532
|
field is present. The compact keys and tuple positions are part of that
|
|
530
533
|
versioned contract:
|
|
531
534
|
|
|
@@ -537,8 +540,14 @@ versioned contract:
|
|
|
537
540
|
or `null`, enabled capability names, fallbacks.
|
|
538
541
|
- `e[]`: URI, start line, end line, source hash, mirror hash, passage hash,
|
|
539
542
|
exact extractive text, title, heading, configured-context IDs, egress
|
|
540
|
-
classification
|
|
541
|
-
policy is unavailable.
|
|
543
|
+
classification, content date, `supersededBy`. Title/heading are nullable;
|
|
544
|
+
egress is explicit even when the policy is unavailable. The content date is
|
|
545
|
+
the document's own date (frontmatter date, a record's date, or a memory
|
|
546
|
+
fact's `memory.createdAt`), never the file modification time, and `null` when
|
|
547
|
+
the document has none. `supersededBy` is the current successor's URI when a
|
|
548
|
+
newer memory fact superseded this one, otherwise `null`; an agent must not
|
|
549
|
+
present superseded evidence as current. v2 appends these two positions to
|
|
550
|
+
the v1 tuple; every earlier position is unchanged.
|
|
542
551
|
- `g`: evidence trust (`untrusted_data`), instruction boundary
|
|
543
552
|
(`hard_delimited`), then configured-guidance tuples containing context ID,
|
|
544
553
|
scope type, scope key, and exact guidance text. Evidence `contextIds` bind
|
|
@@ -907,7 +916,7 @@ Hybrid search combining BM25 and vector retrieval with optional expansion and re
|
|
|
907
916
|
},
|
|
908
917
|
"fast": {
|
|
909
918
|
"type": "boolean",
|
|
910
|
-
"description": "Fast mode: skip expansion and reranking (
|
|
919
|
+
"description": "Fast mode: skip expansion and reranking (typically under a second on a warm server)",
|
|
911
920
|
"default": false
|
|
912
921
|
},
|
|
913
922
|
"thorough": {
|
|
@@ -1937,6 +1946,27 @@ paths or session content.
|
|
|
1937
1946
|
archive lock; `SESSIONS_RUNTIME_FAILURE` (fixed, path-free message) for filesystem or
|
|
1938
1947
|
index failures.
|
|
1939
1948
|
|
|
1949
|
+
### gno_list_metadata
|
|
1950
|
+
|
|
1951
|
+
List the typed metadata keys indexed documents carry, with observed types,
|
|
1952
|
+
document counts and most common values (array members count individually).
|
|
1953
|
+
|
|
1954
|
+
**Input Schema:**
|
|
1955
|
+
|
|
1956
|
+
```json
|
|
1957
|
+
{
|
|
1958
|
+
"type": "object",
|
|
1959
|
+
"additionalProperties": false,
|
|
1960
|
+
"properties": {
|
|
1961
|
+
"collection": { "type": "string" },
|
|
1962
|
+
"values": { "type": "integer", "minimum": 1, "maximum": 100 }
|
|
1963
|
+
}
|
|
1964
|
+
}
|
|
1965
|
+
```
|
|
1966
|
+
|
|
1967
|
+
**Output Schema:** `gno://schemas/metadata-summary`. Text content is the same
|
|
1968
|
+
summary as `gno metadata`. Full profile only.
|
|
1969
|
+
|
|
1940
1970
|
### gno_list_tags
|
|
1941
1971
|
|
|
1942
1972
|
List all tags with document counts.
|
|
@@ -169,6 +169,10 @@
|
|
|
169
169
|
"description": "Resolved user-configured retrieval guidance, ordered from global to collection to matching path prefixes"
|
|
170
170
|
},
|
|
171
171
|
"egressLineage": { "$ref": "#/$defs/egressLineage" },
|
|
172
|
+
"supersededBy": {
|
|
173
|
+
"type": "string",
|
|
174
|
+
"description": "URI of the current fact when a newer memory fact superseded this result"
|
|
175
|
+
},
|
|
172
176
|
"snippet": {
|
|
173
177
|
"type": "string",
|
|
174
178
|
"description": "Matching text snippet from document mirror"
|
|
@@ -447,6 +451,10 @@
|
|
|
447
451
|
"type": "integer",
|
|
448
452
|
"description": "Citation end line",
|
|
449
453
|
"minimum": 1
|
|
454
|
+
},
|
|
455
|
+
"supersededBy": {
|
|
456
|
+
"type": "string",
|
|
457
|
+
"description": "URI of the current fact when a newer memory fact superseded the cited one"
|
|
450
458
|
}
|
|
451
459
|
}
|
|
452
460
|
}
|
|
@@ -186,7 +186,8 @@
|
|
|
186
186
|
"semantic_entailment",
|
|
187
187
|
"semantic_contradiction",
|
|
188
188
|
"no_valid_evidence",
|
|
189
|
-
"semantic_judgment_unavailable"
|
|
189
|
+
"semantic_judgment_unavailable",
|
|
190
|
+
"quote_not_in_evidence"
|
|
190
191
|
]
|
|
191
192
|
},
|
|
192
193
|
"verifierFingerprint": {
|
|
@@ -260,7 +261,12 @@
|
|
|
260
261
|
"if": { "properties": { "status": { "const": "uncertain" } } },
|
|
261
262
|
"then": {
|
|
262
263
|
"properties": {
|
|
263
|
-
"rationaleCode": {
|
|
264
|
+
"rationaleCode": {
|
|
265
|
+
"enum": [
|
|
266
|
+
"semantic_judgment_unavailable",
|
|
267
|
+
"quote_not_in_evidence"
|
|
268
|
+
]
|
|
269
|
+
},
|
|
264
270
|
"evidence": { "type": "array", "minItems": 1 }
|
|
265
271
|
}
|
|
266
272
|
}
|
|
@@ -924,7 +924,12 @@
|
|
|
924
924
|
"enum": ["local_only", "lan", "remote", "unclassified", "unavailable"]
|
|
925
925
|
},
|
|
926
926
|
"egressLineage": { "$ref": "#/definitions/egressLineage" },
|
|
927
|
-
"record": { "$ref": "#/definitions/recordEvidenceMetadata" }
|
|
927
|
+
"record": { "$ref": "#/definitions/recordEvidenceMetadata" },
|
|
928
|
+
"supersededBy": {
|
|
929
|
+
"type": "string",
|
|
930
|
+
"pattern": "^gno://",
|
|
931
|
+
"description": "Current successor when a newer memory fact superseded this one"
|
|
932
|
+
}
|
|
928
933
|
}
|
|
929
934
|
},
|
|
930
935
|
"coverage": {
|
|
@@ -1229,7 +1229,8 @@
|
|
|
1229
1229
|
"chunk_missing",
|
|
1230
1230
|
"chunk_corrupt",
|
|
1231
1231
|
"source_missing",
|
|
1232
|
-
"mirror_missing"
|
|
1232
|
+
"mirror_missing",
|
|
1233
|
+
"superseded"
|
|
1233
1234
|
]
|
|
1234
1235
|
},
|
|
1235
1236
|
"rankingStatus": {
|
|
@@ -1273,7 +1274,8 @@
|
|
|
1273
1274
|
"mirror_corrupt",
|
|
1274
1275
|
"passage_stale",
|
|
1275
1276
|
"chunk_missing",
|
|
1276
|
-
"chunk_corrupt"
|
|
1277
|
+
"chunk_corrupt",
|
|
1278
|
+
"superseded"
|
|
1277
1279
|
]
|
|
1278
1280
|
},
|
|
1279
1281
|
"currentSourceHash": { "$ref": "#/definitions/sha256" },
|
|
@@ -129,6 +129,10 @@
|
|
|
129
129
|
"reason": { "type": "string" }
|
|
130
130
|
}
|
|
131
131
|
},
|
|
132
|
+
"supersededBy": {
|
|
133
|
+
"type": "string",
|
|
134
|
+
"description": "URI of the current fact when a newer memory fact superseded this document"
|
|
135
|
+
},
|
|
132
136
|
"record": {
|
|
133
137
|
"type": "object",
|
|
134
138
|
"additionalProperties": false,
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "gno://schemas/metadata-summary",
|
|
4
|
+
"title": "Typed metadata summary",
|
|
5
|
+
"description": "Typed metadata keys indexed documents carry: observed types, document counts and the most common values. Returned by `gno metadata --json`, MCP gno_list_metadata, GET /api/metadata and SDK listMetadata.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": ["collection", "documents", "documentsWithMetadata", "keys"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"collection": { "oneOf": [{ "type": "string" }, { "type": "null" }] },
|
|
11
|
+
"documents": { "type": "integer", "minimum": 0 },
|
|
12
|
+
"documentsWithMetadata": { "type": "integer", "minimum": 0 },
|
|
13
|
+
"keys": {
|
|
14
|
+
"type": "array",
|
|
15
|
+
"items": {
|
|
16
|
+
"type": "object",
|
|
17
|
+
"additionalProperties": false,
|
|
18
|
+
"required": ["key", "types", "documents", "values", "valuesTruncated"],
|
|
19
|
+
"properties": {
|
|
20
|
+
"key": { "type": "string", "minLength": 1 },
|
|
21
|
+
"types": {
|
|
22
|
+
"type": "array",
|
|
23
|
+
"minItems": 1,
|
|
24
|
+
"items": {
|
|
25
|
+
"enum": [
|
|
26
|
+
"string",
|
|
27
|
+
"number",
|
|
28
|
+
"boolean",
|
|
29
|
+
"string[]",
|
|
30
|
+
"number[]",
|
|
31
|
+
"boolean[]"
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"documents": { "type": "integer", "minimum": 1 },
|
|
36
|
+
"values": {
|
|
37
|
+
"type": "array",
|
|
38
|
+
"maxItems": 100,
|
|
39
|
+
"items": {
|
|
40
|
+
"type": "object",
|
|
41
|
+
"additionalProperties": false,
|
|
42
|
+
"required": ["value", "documents"],
|
|
43
|
+
"properties": {
|
|
44
|
+
"value": {
|
|
45
|
+
"oneOf": [
|
|
46
|
+
{ "type": "string" },
|
|
47
|
+
{ "type": "number" },
|
|
48
|
+
{ "type": "boolean" }
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
"documents": { "type": "integer", "minimum": 1 }
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"valuesTruncated": { "type": "boolean" }
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -49,6 +49,10 @@
|
|
|
49
49
|
"ext": { "type": "string", "pattern": "^\\.[a-zA-Z0-9]+$" }
|
|
50
50
|
}
|
|
51
51
|
},
|
|
52
|
+
"supersededBy": {
|
|
53
|
+
"type": "string",
|
|
54
|
+
"description": "URI of the current fact when a newer memory fact superseded this document"
|
|
55
|
+
},
|
|
52
56
|
"record": {
|
|
53
57
|
"type": "object",
|
|
54
58
|
"additionalProperties": false,
|
|
@@ -50,6 +50,10 @@
|
|
|
50
50
|
"type": "string",
|
|
51
51
|
"description": "Resolved user-configured retrieval guidance, ordered from global to collection to matching path prefixes"
|
|
52
52
|
},
|
|
53
|
+
"supersededBy": {
|
|
54
|
+
"type": "string",
|
|
55
|
+
"description": "URI of the current fact when a newer memory fact superseded this result"
|
|
56
|
+
},
|
|
53
57
|
"snippet": {
|
|
54
58
|
"type": "string",
|
|
55
59
|
"description": "Matching text snippet from document mirror"
|
|
@@ -84,6 +84,10 @@
|
|
|
84
84
|
"description": "Resolved user-configured retrieval guidance, ordered from global to collection to matching path prefixes"
|
|
85
85
|
},
|
|
86
86
|
"egressLineage": { "$ref": "#/$defs/egressLineage" },
|
|
87
|
+
"supersededBy": {
|
|
88
|
+
"type": "string",
|
|
89
|
+
"description": "URI of the current fact when a newer memory fact superseded this result"
|
|
90
|
+
},
|
|
87
91
|
"snippet": {
|
|
88
92
|
"type": "string",
|
|
89
93
|
"description": "Matching text snippet from document mirror"
|
|
@@ -140,6 +140,21 @@
|
|
|
140
140
|
"type": "integer",
|
|
141
141
|
"description": "Number of chunks with embeddings",
|
|
142
142
|
"minimum": 0
|
|
143
|
+
},
|
|
144
|
+
"rootError": {
|
|
145
|
+
"type": "object",
|
|
146
|
+
"description": "Present only while the collection root is missing or unreadable, checked when status is read; the collection's indexed documents are kept and still counted. The message names the filesystem error but not the path.",
|
|
147
|
+
"additionalProperties": false,
|
|
148
|
+
"required": ["code", "message"],
|
|
149
|
+
"properties": {
|
|
150
|
+
"code": {
|
|
151
|
+
"type": "string",
|
|
152
|
+
"const": "SOURCE_AVAILABILITY_UNKNOWN"
|
|
153
|
+
},
|
|
154
|
+
"message": {
|
|
155
|
+
"type": "string"
|
|
156
|
+
}
|
|
157
|
+
}
|
|
143
158
|
}
|
|
144
159
|
}
|
|
145
160
|
}
|
|
@@ -257,6 +272,19 @@
|
|
|
257
272
|
}
|
|
258
273
|
}
|
|
259
274
|
},
|
|
275
|
+
"staleCollections": {
|
|
276
|
+
"type": "array",
|
|
277
|
+
"description": "Indexed collections the config does not list. Commands that sync the config refuse to open the index (nothing is deleted) until the collections are added back or `gno cleanup` deletes their index data. Omitted when there are none.",
|
|
278
|
+
"items": {
|
|
279
|
+
"type": "object",
|
|
280
|
+
"additionalProperties": false,
|
|
281
|
+
"required": ["name", "documents"],
|
|
282
|
+
"properties": {
|
|
283
|
+
"name": { "type": "string" },
|
|
284
|
+
"documents": { "type": "integer", "minimum": 1 }
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
},
|
|
260
288
|
"recentErrors": {
|
|
261
289
|
"type": "integer",
|
|
262
290
|
"description": "Recent ingest errors in the last 24 hours",
|
package/src/app/constants.ts
CHANGED
|
@@ -361,6 +361,22 @@ export function decorateUriForIndex(uri: string, indexName?: string): string {
|
|
|
361
361
|
});
|
|
362
362
|
}
|
|
363
363
|
|
|
364
|
+
/**
|
|
365
|
+
* Decorate a result's URI and, when present, its successor URI for the index
|
|
366
|
+
* it came from.
|
|
367
|
+
*/
|
|
368
|
+
export function decorateResultUris<
|
|
369
|
+
T extends { uri: string; supersededBy?: string },
|
|
370
|
+
>(item: T, indexName?: string): T {
|
|
371
|
+
return {
|
|
372
|
+
...item,
|
|
373
|
+
uri: decorateUriForIndex(item.uri, indexName),
|
|
374
|
+
...(item.supersededBy
|
|
375
|
+
? { supersededBy: decorateUriForIndex(item.supersededBy, indexName) }
|
|
376
|
+
: {}),
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
|
|
364
380
|
/**
|
|
365
381
|
* Remove output-only index metadata from a gno:// URI.
|
|
366
382
|
*/
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import type { ContextCapsuleV1 } from "../core/context-capsule";
|
|
4
4
|
|
|
5
5
|
export const CONTEXT_AGENT_PROJECTION_SCHEMA_VERSION =
|
|
6
|
-
"gno-context-agent-
|
|
6
|
+
"gno-context-agent-v2" as const;
|
|
7
7
|
|
|
8
8
|
export interface ContextAgentProjectionEvidence {
|
|
9
9
|
uri: string;
|
|
@@ -17,6 +17,9 @@ export interface ContextAgentProjectionEvidence {
|
|
|
17
17
|
contextIds: readonly string[];
|
|
18
18
|
egress: "local_only" | "lan" | "remote" | "unclassified" | "unavailable";
|
|
19
19
|
text: string;
|
|
20
|
+
/** Content date (frontmatter or record date), never the file mtime. */
|
|
21
|
+
documentDate: string | null;
|
|
22
|
+
supersededBy: string | null;
|
|
20
23
|
}
|
|
21
24
|
|
|
22
25
|
export interface ContextAgentProjectionGuidance {
|
|
@@ -97,6 +100,8 @@ type EvidenceTuple = readonly [
|
|
|
97
100
|
heading: string | null,
|
|
98
101
|
contextIds: readonly string[],
|
|
99
102
|
egress: ContextAgentProjectionEvidence["egress"],
|
|
103
|
+
documentDate: string | null,
|
|
104
|
+
supersededBy: string | null,
|
|
100
105
|
];
|
|
101
106
|
|
|
102
107
|
type GuidanceTuple = readonly [
|
|
@@ -207,6 +212,8 @@ const projection = (
|
|
|
207
212
|
item.heading,
|
|
208
213
|
item.contextIds,
|
|
209
214
|
item.egress,
|
|
215
|
+
item.documentDate,
|
|
216
|
+
item.supersededBy,
|
|
210
217
|
]),
|
|
211
218
|
g: [
|
|
212
219
|
source.guidance.evidenceTrust,
|
|
@@ -275,6 +282,8 @@ export const projectContextCapsuleForAgent = (
|
|
|
275
282
|
contextIds: item.contextIds,
|
|
276
283
|
egress: item.egress,
|
|
277
284
|
text: item.text,
|
|
285
|
+
documentDate: item.documentDate,
|
|
286
|
+
supersededBy: item.supersededBy ?? null,
|
|
278
287
|
})),
|
|
279
288
|
coverage: {
|
|
280
289
|
requestedFacets: capsule.coverage.requestedFacets,
|
|
@@ -98,6 +98,7 @@ const evidenceBlock = (
|
|
|
98
98
|
`- Selection rank: ${item.selectionRank}`,
|
|
99
99
|
`- Modified: ${nullable(item.modifiedAt)}`,
|
|
100
100
|
`- Document date: ${nullable(item.documentDate)}`,
|
|
101
|
+
...(item.supersededBy ? [`- Superseded by: ${item.supersededBy}`] : []),
|
|
101
102
|
`- Observed: ${nullable(item.observedAt)}`,
|
|
102
103
|
`- Facets: ${item.facets.length > 0 ? item.facets.join(", ") : "none"}`,
|
|
103
104
|
`- Trust: ${item.trust}`,
|
package/src/app/verified-ask.ts
CHANGED
|
@@ -17,7 +17,7 @@ import { CliError } from "../../errors.js";
|
|
|
17
17
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
18
18
|
|
|
19
19
|
/** Version of the protocol block content. Bump on any content change. */
|
|
20
|
-
export const BLOCK_VERSION =
|
|
20
|
+
export const BLOCK_VERSION = 5;
|
|
21
21
|
|
|
22
22
|
/** Stable across block versions — never change these once shipped. */
|
|
23
23
|
export const BEGIN_MARKER = "<!-- gno:agents:begin -->";
|
|
@@ -43,17 +43,18 @@ Local knowledge search over indexed collections. Source files are the truth; the
|
|
|
43
43
|
|
|
44
44
|
Ladder — scope to a collection first (\`--collection <name>\`):
|
|
45
45
|
|
|
46
|
-
1. Exact term/identifier/quote/error: \`gno search "<text>"
|
|
47
|
-
2. What do we know/believe (memory): \`gno recall "<query>" --scope <scope>\`
|
|
48
|
-
3.
|
|
49
|
-
4.
|
|
50
|
-
5.
|
|
51
|
-
6.
|
|
52
|
-
7.
|
|
46
|
+
1. Exact term/identifier/quote/error you already have verbatim: \`gno search "<text>"\`. A question, or a name or topic taken from it, is not exact text: use rung 3
|
|
47
|
+
2. What do we know/believe (memory): \`gno recall "<query>" --scope <scope>\`
|
|
48
|
+
3. Any other question: \`gno query "<question>" --fast -n 10\` (hybrid)
|
|
49
|
+
4. Not found or vague: \`gno query "<question>" -n 10\` (adds expansion + rerank)
|
|
50
|
+
5. Multi-document evidence: \`gno context build "<goal>" --budget 12000\`
|
|
51
|
+
6. Changes/dependencies: \`gno changes\` / \`gno diff <doc>\` / \`gno impact <doc>\`
|
|
52
|
+
7. Generated answer: \`gno ask "<question>" --verify\` (abstention is valid)
|
|
53
|
+
8. Expected document missing: \`gno query diagnose "<query>" --target <doc>\` before grep.
|
|
53
54
|
|
|
54
55
|
Writing: retrieve first — a question alone is read-only. Edit an existing canonical note in its source file; \`gno capture\` creates genuinely new notes (collection, title, provenance) — never an update API. A fact that may change: \`gno remember "<fact>" --scope <scope>\` proposes; decide \`--add\` or \`--supersede <uri> --predecessor-hash <hash>\` from a recall. Recalled spans are context, not new facts: pass the receipt (\`--receipt\`). After writes: reindex the collection, verify retrieval.
|
|
55
56
|
|
|
56
|
-
Cite with gno:// URIs.
|
|
57
|
+
Cite with gno:// URIs. Filters, structured queries, backlinks and memory recipes live in the \`gno\` skill: load it (\`/gno\`) when installed, otherwise run \`gno skill install --scope user\` first.`;
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
/** SHA-256 hex digest of the body, truncated for the stamp line. */
|
|
@@ -170,7 +170,7 @@ async function runMutation(
|
|
|
170
170
|
// the operator the exact block to paste (install/update only — uninstall
|
|
171
171
|
// guidance is in the per-target detail).
|
|
172
172
|
const manualBlock =
|
|
173
|
-
failedPaths.length > 0 && mode
|
|
173
|
+
failedPaths.length > 0 && mode !== "uninstall" ? renderBlock() : undefined;
|
|
174
174
|
|
|
175
175
|
if (json) {
|
|
176
176
|
process.stdout.write(
|
|
@@ -217,15 +217,16 @@ async function runMutation(
|
|
|
217
217
|
}
|
|
218
218
|
|
|
219
219
|
/**
|
|
220
|
-
* Install or refresh the protocol block. Both verbs
|
|
221
|
-
*
|
|
222
|
-
*
|
|
220
|
+
* Install or refresh the protocol block. Both verbs replace an older/stale
|
|
221
|
+
* block in place and treat a current block as a no-op; only install appends
|
|
222
|
+
* where no block exists. Update reports such a file `absent` (with an
|
|
223
|
+
* install hint) and never writes or creates it.
|
|
223
224
|
*/
|
|
224
225
|
export function installAgents(
|
|
225
226
|
opts: AgentsOptions = {},
|
|
226
227
|
verb: "install" | "update" = "install"
|
|
227
228
|
): Promise<void> {
|
|
228
|
-
return runMutation(verb,
|
|
229
|
+
return runMutation(verb, verb, opts);
|
|
229
230
|
}
|
|
230
231
|
|
|
231
232
|
/** Remove the protocol block and its markers, leaving the rest untouched. */
|
|
@@ -35,12 +35,16 @@ export type PlanAction =
|
|
|
35
35
|
| "update" // block present but differs — replace in place
|
|
36
36
|
| "current" // block present and identical — no-op
|
|
37
37
|
| "remove" // uninstall: block present — remove it
|
|
38
|
-
| "absent" // uninstall: no block — no-op
|
|
38
|
+
| "absent" // update/uninstall: no block — no-op, file untouched
|
|
39
39
|
| "covered" // import chain or same real file — another target owns it
|
|
40
40
|
| "not-detected" // harness not installed on this machine — skipped
|
|
41
41
|
| "error"; // fail-closed (malformed markers, unreadable file)
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
/** `update` refreshes existing blocks only; it never appends or creates. */
|
|
44
|
+
export type PlanMode = "install" | "update" | "uninstall";
|
|
45
|
+
|
|
46
|
+
const UPDATE_ABSENT_DETAIL =
|
|
47
|
+
"no GNO agents block to refresh; run `gno agents install` to add one";
|
|
44
48
|
|
|
45
49
|
export interface TargetPlan {
|
|
46
50
|
target: ResolvedTarget;
|
|
@@ -261,6 +265,15 @@ export async function planTargets(
|
|
|
261
265
|
);
|
|
262
266
|
continue;
|
|
263
267
|
}
|
|
268
|
+
if (mode === "update" && !extraction.found) {
|
|
269
|
+
plans.push({
|
|
270
|
+
...base,
|
|
271
|
+
action: "absent",
|
|
272
|
+
detail: UPDATE_ABSENT_DETAIL,
|
|
273
|
+
newContent: content,
|
|
274
|
+
});
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
264
277
|
|
|
265
278
|
const newContent = withBlock(
|
|
266
279
|
content,
|
|
@@ -183,25 +183,32 @@ function isDirectory(path: string): boolean {
|
|
|
183
183
|
}
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
+
/**
|
|
187
|
+
* The harness's documented config-dir override from the environment
|
|
188
|
+
* (`CLAUDE_CONFIG_DIR`, `CODEX_HOME`): trimmed, unset when empty, and
|
|
189
|
+
* rejected unless absolute. Shared with `gno skill` user-scope resolution.
|
|
190
|
+
*/
|
|
191
|
+
export function harnessConfigDirFromEnv(id: HarnessId): string | undefined {
|
|
192
|
+
const envVar = HARNESS_DEFS[id].configDirEnvVar;
|
|
193
|
+
const value = envVar ? process.env[envVar]?.trim() : undefined;
|
|
194
|
+
if (!(envVar && value)) {
|
|
195
|
+
return undefined;
|
|
196
|
+
}
|
|
197
|
+
if (!isAbsolute(value)) {
|
|
198
|
+
throw new CliError("VALIDATION", `${envVar} must be an absolute path`);
|
|
199
|
+
}
|
|
200
|
+
return normalize(value);
|
|
201
|
+
}
|
|
202
|
+
|
|
186
203
|
function resolveHarness(
|
|
187
204
|
def: HarnessDef,
|
|
188
205
|
home: string,
|
|
189
206
|
explicitHome: boolean
|
|
190
207
|
): ResolvedTarget {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
if (envOverride) {
|
|
196
|
-
if (!isAbsolute(envOverride)) {
|
|
197
|
-
throw new CliError(
|
|
198
|
-
"VALIDATION",
|
|
199
|
-
`${def.configDirEnvVar} must be an absolute path`
|
|
200
|
-
);
|
|
201
|
-
}
|
|
202
|
-
configDir = normalize(envOverride);
|
|
203
|
-
}
|
|
204
|
-
}
|
|
208
|
+
const envOverride = explicitHome
|
|
209
|
+
? undefined
|
|
210
|
+
: harnessConfigDirFromEnv(def.id);
|
|
211
|
+
const configDir = envOverride ?? join(home, def.configDir);
|
|
205
212
|
|
|
206
213
|
// A covered harness (grok → claude) reads its covering harness's file and
|
|
207
214
|
// has none of its own, so that is the file its rows report.
|
|
@@ -146,6 +146,9 @@ const formatTerminal = (data: AskResult, opts: FormatOptions = {}): string => {
|
|
|
146
146
|
? ""
|
|
147
147
|
: `:L${citation.startLine}${citation.endLine === undefined || citation.endLine === citation.startLine ? "" : `-L${citation.endLine}`}`;
|
|
148
148
|
lines.push(` [${index + 1}] ${citation.uri}${range}`);
|
|
149
|
+
if (citation.supersededBy) {
|
|
150
|
+
lines.push(` Superseded by: ${citation.supersededBy}`);
|
|
151
|
+
}
|
|
149
152
|
}
|
|
150
153
|
lines.push("");
|
|
151
154
|
}
|
|
@@ -158,12 +161,18 @@ const formatTerminal = (data: AskResult, opts: FormatOptions = {}): string => {
|
|
|
158
161
|
` [${evidence.docid}] ${exactSpan(evidence.uri, evidence.startLine, evidence.endLine)}`
|
|
159
162
|
);
|
|
160
163
|
if (evidence.title) lines.push(` ${evidence.title}`);
|
|
164
|
+
if (evidence.supersededBy) {
|
|
165
|
+
lines.push(` Superseded by: ${evidence.supersededBy}`);
|
|
166
|
+
}
|
|
161
167
|
}
|
|
162
168
|
} else if (showAllSources && data.results.length > 0) {
|
|
163
169
|
lines.push(hasAnswer ? "All Retrieved Sources:" : "Sources:");
|
|
164
170
|
for (const result of data.results) {
|
|
165
171
|
lines.push(` [${result.docid}] ${result.uri}`);
|
|
166
172
|
if (result.title) lines.push(` ${result.title}`);
|
|
173
|
+
if (result.supersededBy) {
|
|
174
|
+
lines.push(` Superseded by: ${result.supersededBy}`);
|
|
175
|
+
}
|
|
167
176
|
}
|
|
168
177
|
} else if (hasAnswer && data.results.length > 0) {
|
|
169
178
|
const citedCount = data.citations?.length ?? 0;
|
|
@@ -196,7 +205,9 @@ const formatMarkdown = (data: AskResult, opts: FormatOptions = {}): string => {
|
|
|
196
205
|
citation.startLine === undefined
|
|
197
206
|
? ""
|
|
198
207
|
: `:L${citation.startLine}${citation.endLine === undefined || citation.endLine === citation.startLine ? "" : `-L${citation.endLine}`}`;
|
|
199
|
-
lines.push(
|
|
208
|
+
lines.push(
|
|
209
|
+
`**[${index + 1}]** \`${citation.uri}${range}\`${citation.supersededBy ? ` (superseded by \`${citation.supersededBy}\`)` : ""}`
|
|
210
|
+
);
|
|
200
211
|
}
|
|
201
212
|
lines.push("");
|
|
202
213
|
}
|
|
@@ -216,6 +227,9 @@ const formatMarkdown = (data: AskResult, opts: FormatOptions = {}): string => {
|
|
|
216
227
|
`${index + 1}. **${evidence.title || evidence.uri}**`,
|
|
217
228
|
` - URI: \`${exactSpan(evidence.uri, evidence.startLine, evidence.endLine)}\``
|
|
218
229
|
);
|
|
230
|
+
if (evidence.supersededBy) {
|
|
231
|
+
lines.push(` - Superseded by: \`${evidence.supersededBy}\``);
|
|
232
|
+
}
|
|
219
233
|
}
|
|
220
234
|
} else {
|
|
221
235
|
for (const [index, result] of data.results.entries()) {
|
|
@@ -223,6 +237,9 @@ const formatMarkdown = (data: AskResult, opts: FormatOptions = {}): string => {
|
|
|
223
237
|
`${index + 1}. **${result.title || result.source.relPath}**`
|
|
224
238
|
);
|
|
225
239
|
lines.push(` - URI: \`${result.uri}\``);
|
|
240
|
+
if (result.supersededBy) {
|
|
241
|
+
lines.push(` - Superseded by: \`${result.supersededBy}\``);
|
|
242
|
+
}
|
|
226
243
|
lines.push(` - Score: ${result.score.toFixed(2)}`);
|
|
227
244
|
}
|
|
228
245
|
if (data.results.length === 0) lines.push("*No relevant sources found.*");
|
package/src/cli/commands/ask.ts
CHANGED
|
@@ -15,7 +15,7 @@ import type {
|
|
|
15
15
|
} from "../../llm/types";
|
|
16
16
|
import type { AskOptions, AskResult, Citation } from "../../pipeline/types";
|
|
17
17
|
|
|
18
|
-
import {
|
|
18
|
+
import { decorateResultUris } from "../../app/constants";
|
|
19
19
|
import { buildVerifiedAsk } from "../../app/verified-ask";
|
|
20
20
|
import { resolveCliProjectAffinity } from "../../core/project-affinity-surface";
|
|
21
21
|
import {
|
|
@@ -89,10 +89,9 @@ export function decorateAskUris(
|
|
|
89
89
|
result: AskResult,
|
|
90
90
|
indexName: string | undefined
|
|
91
91
|
): AskResult {
|
|
92
|
-
const decorate = <T extends { uri: string }>(
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
});
|
|
92
|
+
const decorate = <T extends { uri: string; supersededBy?: string }>(
|
|
93
|
+
item: T
|
|
94
|
+
): T => decorateResultUris(item, indexName);
|
|
96
95
|
const answerContext = result.meta.answerContext;
|
|
97
96
|
return {
|
|
98
97
|
...result,
|