@gmickel/gno 1.43.0 → 1.45.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/assets/skill/SKILL.md +3 -0
- package/assets/skill/recipes/memory-file-decision.md +76 -0
- package/assets/skill/recipes/memory-scoped-recall.md +66 -0
- package/assets/skill/recipes/memory-supersede-fact.md +68 -0
- package/browser-extension/artifacts/{gno-browser-clipper-v1.43.0.zip → gno-browser-clipper-v1.45.0.zip} +0 -0
- package/browser-extension/artifacts/gno-browser-clipper-v1.45.0.zip.sha256 +1 -0
- package/browser-extension/dist/manifest.json +1 -1
- package/package.json +1 -1
- package/spec/cli.md +89 -8
- package/spec/mcp.md +12 -0
- package/spec/output-schemas/changes-follow-event.schema.json +35 -0
- package/spec/output-schemas/index-receipt.schema.json +135 -0
- package/spec/output-schemas/process-status.schema.json +76 -0
- package/src/cli/commands/agents/block.ts +9 -8
- package/src/cli/commands/changes-follow.ts +167 -0
- package/src/cli/commands/changes.ts +63 -0
- package/src/cli/commands/daemon.ts +35 -0
- package/src/cli/commands/doctor.ts +71 -0
- package/src/cli/commands/embed.ts +236 -178
- package/src/cli/commands/index-cmd.ts +238 -57
- package/src/cli/program.ts +94 -4
- package/src/config/types.ts +48 -0
- package/src/core/capture-sync.ts +144 -0
- package/src/core/capture.ts +10 -0
- package/src/core/findings-records.ts +381 -0
- package/src/core/findings-run-state.ts +282 -0
- package/src/embed/stage-state.ts +199 -0
- package/src/mcp/tools/capture.ts +91 -136
- package/src/serve/capture-service.ts +227 -53
- package/src/serve/findings-pass.ts +335 -0
- package/src/serve/resident-runtime.ts +42 -0
- package/src/serve/routes/api.ts +14 -14
- package/browser-extension/artifacts/gno-browser-clipper-v1.43.0.zip.sha256 +0 -1
package/assets/skill/SKILL.md
CHANGED
|
@@ -62,6 +62,9 @@ the matching recipe, then run the commands it names.
|
|
|
62
62
|
| Summarize a source | `recipes/source-summary.md` | Source-summary note with provenance verified |
|
|
63
63
|
| Preserve an idea | `recipes/idea-capture.md` | Original phrasing captured and findable |
|
|
64
64
|
| Verify claims and citations | `recipes/citation-and-provenance.md` | Claims labeled with evidence or explicit gaps |
|
|
65
|
+
| File a fact that may change | `recipes/memory-file-decision.md` | Fact stored (add) or proposal resolved, cited |
|
|
66
|
+
| Replace a stale recalled fact | `recipes/memory-supersede-fact.md` | Successor written, predecessor superseded |
|
|
67
|
+
| What do we know/believe about X | `recipes/memory-scoped-recall.md` | Current facts recalled under budget, cited |
|
|
65
68
|
|
|
66
69
|
Recipe rules:
|
|
67
70
|
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Memory: File A Decision
|
|
2
|
+
|
|
3
|
+
Use this recipe when a conversation settles one fact that may later change (a
|
|
4
|
+
decision, a preference, a standing rule) and the agent should be able to
|
|
5
|
+
recall it next session. Documents and long notes go through
|
|
6
|
+
`recipes/capture-and-file.md`; this recipe stores one fact.
|
|
7
|
+
|
|
8
|
+
## Inputs
|
|
9
|
+
|
|
10
|
+
- The fact, in one or two sentences, as it should be recalled later.
|
|
11
|
+
- One to eight explicit scopes (`project:gno`, `family`, `client/acme`).
|
|
12
|
+
There is no implicit global scope; every call names its scopes.
|
|
13
|
+
- Source evidence when known (a meeting, a message, a URL — never a `gno://`
|
|
14
|
+
URI, which the fence rejects as GNO-derived).
|
|
15
|
+
- The memory-managed collection when more than one is configured.
|
|
16
|
+
|
|
17
|
+
## Workflow
|
|
18
|
+
|
|
19
|
+
1. Recall first so a fact that already exists is not filed twice.
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
gno recall "<the topic>" --scope <scope> --json > /tmp/recall.json
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
2. Propose the fact. Without a decision `remember` writes nothing and returns
|
|
26
|
+
`outcome: "candidates"` with likely and weak matches from the same scopes.
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
gno remember "<fact>" --scope <scope> --json
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
3. Decide from the candidates. GNO never adjudicates a likely match; the
|
|
33
|
+
caller does.
|
|
34
|
+
- No match, or the match is a different fact: add.
|
|
35
|
+
- A match says the same thing: stop; `outcome: "existing"` means nothing
|
|
36
|
+
is written and the record is already current.
|
|
37
|
+
- A match is the same fact with stale content: switch to
|
|
38
|
+
`recipes/memory-supersede-fact.md`.
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
gno remember "<fact>" --scope <scope> --add \
|
|
42
|
+
--source "<where this came from>" --receipt /tmp/recall.json --json
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
4. Read the result. `outcome: "added"` plus `sync.status: "completed"` means
|
|
46
|
+
the fact file exists and is retrievable now; a `failed` sync means the
|
|
47
|
+
file exists and the index lags (`gno update <collection>`).
|
|
48
|
+
|
|
49
|
+
5. Verify by recalling it back and cite the returned `uri`.
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
gno recall "<distinctive phrase>" --scope <scope>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Guardrails
|
|
56
|
+
|
|
57
|
+
- Store what the user said or decided, not GNO's own recall output. Pass the
|
|
58
|
+
recall receipt (`--receipt`) so a recalled span cannot be re-filed as new;
|
|
59
|
+
a paraphrase without lineage cannot be fenced, so do not paraphrase
|
|
60
|
+
recalled facts into new ones.
|
|
61
|
+
- Never store a fact without an explicit `--add`; a question alone is
|
|
62
|
+
read-only, and `remember` without a decision is a proposal.
|
|
63
|
+
- Scopes are visibility, not access control. Pick the scope the fact belongs
|
|
64
|
+
to; use a shared scope name only when several callers agree on it.
|
|
65
|
+
- `remember` works only on a collection with `memoryManaged: true`; other
|
|
66
|
+
collections fail with `MEMORY_COLLECTION_UNMANAGED`. Do not fall back to
|
|
67
|
+
`gno capture` for a fact that may change.
|
|
68
|
+
- Keep the text self-contained; recall returns the fact without the
|
|
69
|
+
conversation that produced it.
|
|
70
|
+
|
|
71
|
+
## Done
|
|
72
|
+
|
|
73
|
+
- `outcome: "added"` with a `gno://` URI, or `existing` with the current
|
|
74
|
+
record.
|
|
75
|
+
- Recall in the same scope returns the fact.
|
|
76
|
+
- The user's wording, scopes, and source are preserved.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Memory: Scoped Recall
|
|
2
|
+
|
|
3
|
+
Use this recipe for "what do we know / what did we decide / what does the
|
|
4
|
+
user believe about X" questions, before document search and before answering
|
|
5
|
+
from general knowledge. Recall returns only current facts, under a budget,
|
|
6
|
+
with `gno://` cites.
|
|
7
|
+
|
|
8
|
+
## Inputs
|
|
9
|
+
|
|
10
|
+
- The question, as a short query.
|
|
11
|
+
- The scopes the answer may draw from (`project:gno`, `family`,
|
|
12
|
+
`client/acme`). Every call names its scopes; there is no implicit global
|
|
13
|
+
scope.
|
|
14
|
+
- Budget when the default (8 facts, 512 tokens) is too much or too little.
|
|
15
|
+
- The memory-managed collection when more than one is configured.
|
|
16
|
+
|
|
17
|
+
## Workflow
|
|
18
|
+
|
|
19
|
+
1. Recall in the narrowest scope that should hold the answer.
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
gno recall "<question>" --scope <scope> --json
|
|
23
|
+
gno recall "<question>" --scope <scope-a> --scope <scope-b> --max-facts 3 --max-tokens 256 --json
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Visibility is any-intersection: a fact is returned when at least one of
|
|
27
|
+
the call's scopes appears on it. Widen by adding scopes, not by dropping
|
|
28
|
+
the flag.
|
|
29
|
+
|
|
30
|
+
2. Read the response.
|
|
31
|
+
- `facts[]`: `uri`, `text`, `scopes`, `contentHash`, `supersedes`, `score`.
|
|
32
|
+
Superseded records never appear.
|
|
33
|
+
- `budget.omitted` > 0: facts matched but did not fit. Narrow the query
|
|
34
|
+
or raise the budget.
|
|
35
|
+
- Empty `facts` plus a `hint`: nothing is stored in scope yet. Say so;
|
|
36
|
+
the hint names `gno remember` for when the user wants to store one.
|
|
37
|
+
- `retrieval.mode: "lexical"`: the collection has no cached embeddings, so
|
|
38
|
+
the query matched every term. Rephrase to the fact's own words, or embed
|
|
39
|
+
the collection (`gno embed <collection>`) for question-shaped queries.
|
|
40
|
+
|
|
41
|
+
3. Answer from the facts and cite each by its `gno://` URI. When memory is
|
|
42
|
+
silent or stale, fall through to `gno search` / `gno query` on the
|
|
43
|
+
documents; memory answers "what we believe", documents answer "what the
|
|
44
|
+
sources say".
|
|
45
|
+
|
|
46
|
+
4. Keep the JSON if a write may follow. Its `receipt` is what `gno remember
|
|
47
|
+
--receipt` fences against, and its `contentHash` is what a supersede
|
|
48
|
+
requires (`recipes/memory-supersede-fact.md`).
|
|
49
|
+
|
|
50
|
+
## Guardrails
|
|
51
|
+
|
|
52
|
+
- Recalled spans are context, not new facts. Never feed recall output back
|
|
53
|
+
into `gno remember`; the fence catches exact replays with a receipt, not
|
|
54
|
+
paraphrases.
|
|
55
|
+
- Do not widen to every scope by habit. Scopes partition visibility; a recall
|
|
56
|
+
scoped to `project:other` should not surface family facts.
|
|
57
|
+
- `recall` reads memory-managed collections only; ordinary notes are not
|
|
58
|
+
facts. Use the document ladder for them.
|
|
59
|
+
- Respect the response's `egressLineage`; derived output inherits the
|
|
60
|
+
strictest policy across the returned facts.
|
|
61
|
+
|
|
62
|
+
## Done
|
|
63
|
+
|
|
64
|
+
- Facts cited by `gno://` URI, or an explicit "nothing stored in scope".
|
|
65
|
+
- Omitted facts acknowledged when `budget.omitted` is non-zero.
|
|
66
|
+
- Recall JSON kept when a remember or supersede follows.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Memory: Supersede A Stale Fact
|
|
2
|
+
|
|
3
|
+
Use this recipe when a recalled fact is no longer true and a newer statement
|
|
4
|
+
replaces it. Facts are replaced, never edited in place and never deleted by
|
|
5
|
+
the memory contract.
|
|
6
|
+
|
|
7
|
+
## Inputs
|
|
8
|
+
|
|
9
|
+
- The stale fact's `uri` and `contentHash`, taken from a recall.
|
|
10
|
+
- The replacement text.
|
|
11
|
+
- The same scopes the stale fact is visible in.
|
|
12
|
+
- Source evidence for the change when known.
|
|
13
|
+
|
|
14
|
+
## Workflow
|
|
15
|
+
|
|
16
|
+
1. Recall the current fact and keep the JSON; it carries the predecessor's
|
|
17
|
+
`uri`, `contentHash`, and the receipt.
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
gno recall "<the topic>" --scope <scope> --json > /tmp/recall.json
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
2. Confirm the match is the same fact with stale content, not a different
|
|
24
|
+
fact. Two facts that both hold get an add, not a supersede.
|
|
25
|
+
|
|
26
|
+
3. Supersede, naming the predecessor and its hash.
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
gno remember "<replacement text>" --scope <scope> \
|
|
30
|
+
--supersede <uri> --predecessor-hash <contentHash> \
|
|
31
|
+
--source "<what changed and where that is recorded>" \
|
|
32
|
+
--receipt /tmp/recall.json --json
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The scriptable spelling `--decision supersede --predecessor <uri>` means
|
|
36
|
+
the same thing.
|
|
37
|
+
|
|
38
|
+
4. Read the result. `outcome: "superseded"` returns the successor record with
|
|
39
|
+
`supersedes: [<uri>]`.
|
|
40
|
+
- `MEMORY_PREDECESSOR_HASH_MISMATCH`: the fact changed since the recall.
|
|
41
|
+
Recall again and decide against the current text.
|
|
42
|
+
- `MEMORY_SUPERSEDE_CONFLICT` (exit 4): another writer superseded it
|
|
43
|
+
first. Recall again; the successor may already say what you meant.
|
|
44
|
+
|
|
45
|
+
5. Verify: recall returns the successor and not the predecessor.
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
gno recall "<distinctive phrase>" --scope <scope>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Guardrails
|
|
52
|
+
|
|
53
|
+
- Never supersede without the `contentHash` from a recall; the hash is what
|
|
54
|
+
proves the replacement targets the fact the agent actually read.
|
|
55
|
+
- The replacement must be a new statement. Re-storing the recalled text is
|
|
56
|
+
fenced (`MEMORY_FENCED_REPLAY`) when the receipt is presented; a
|
|
57
|
+
paraphrase without lineage is not, so do not rephrase the old fact as a
|
|
58
|
+
"new" one.
|
|
59
|
+
- Superseded facts stay on disk and in ordinary `gno search`; only `recall`
|
|
60
|
+
excludes them. To remove a file, the user deletes it and runs
|
|
61
|
+
`gno update`; the contract has no delete.
|
|
62
|
+
- Do not chain supersedes speculatively; one recalled fact, one decision.
|
|
63
|
+
|
|
64
|
+
## Done
|
|
65
|
+
|
|
66
|
+
- `outcome: "superseded"` with a successor URI carrying `supersedes`.
|
|
67
|
+
- Recall in scope returns the successor only.
|
|
68
|
+
- A conflict or hash mismatch ended in a fresh recall, not a retry loop.
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ea5867ff2927a15524f4d5167c7ee9ee8a530b3604fefad886ec0327af7185d8 gno-browser-clipper-v1.45.0.zip
|
package/package.json
CHANGED
package/spec/cli.md
CHANGED
|
@@ -1025,24 +1025,51 @@ gno index [collection] [--no-embed] [--models-pull] [--git-pull] [--json] [--yes
|
|
|
1025
1025
|
|
|
1026
1026
|
**Behavior:**
|
|
1027
1027
|
|
|
1028
|
-
- Runs `update` then `embed`
|
|
1029
|
-
- With `--no-embed`, runs `
|
|
1028
|
+
- Runs two separable stages: `lexical` (`update`) then `embed`
|
|
1029
|
+
- With `--no-embed`, runs the `lexical` stage only (embed stage `skipped`)
|
|
1030
1030
|
- Waits by default for the shared write lease; `--no-wait` fails immediately with exit 4
|
|
1031
1031
|
|
|
1032
|
-
**
|
|
1032
|
+
**Staged, resumable contract:** each stage persists its own progress inside
|
|
1033
|
+
the index database (documents and chunks for `lexical`; vectors per batch for
|
|
1034
|
+
`embed`) plus a per-stage lifecycle marker (`schema_meta.index_stage_state`).
|
|
1035
|
+
A stage that fails never invalidates a completed earlier stage: the lexical
|
|
1036
|
+
index stays searchable when embedding fails or the process dies. A process
|
|
1037
|
+
killed mid-stage (SIGKILL, native crash, power loss) emits nothing; the next
|
|
1038
|
+
`gno index` or `gno embed` run reads the marker, reports the interrupted stage
|
|
1039
|
+
in its resume preamble (stderr in human mode, `resumedFrom` in JSON), and
|
|
1040
|
+
continues from persisted progress - unchanged files are skipped and already
|
|
1041
|
+
stored chunks are never re-embedded. A `gno index --no-embed` run that
|
|
1042
|
+
surfaces an interrupted embed stage settles that marker (the embed progress
|
|
1043
|
+
itself stays on disk), so later runs do not repeat the preamble.
|
|
1044
|
+
|
|
1045
|
+
**JSON output:** conforms to
|
|
1046
|
+
[`index-receipt@1.0`](./output-schemas/index-receipt.schema.json):
|
|
1047
|
+
`{ success, error?, stages: { lexical, embed }, resumedFrom, syncResult?, embedSkipped, embedResult? }`.
|
|
1048
|
+
Each stage reports `state` (`completed` | `failed` | `skipped` |
|
|
1049
|
+
`interrupted`) with counts (`filesProcessed`/`filesAdded`/`filesUpdated`/
|
|
1050
|
+
`filesErrored`/`filesSkipped`/`durationMs` for lexical;
|
|
1051
|
+
`embedded`/`errors`/`contentionErrors`/`durationMs` for embed), a `reason`
|
|
1052
|
+
when skipped, and an `error` when failed. The embed stage is `completed` only
|
|
1053
|
+
when every attempted chunk was stored: any `errors > 0` or a vector-sync error
|
|
1054
|
+
makes it `failed`. `resumedFrom` is `null` on a clean start or
|
|
1055
|
+
`{ stage, state: "interrupted", startedAt, pid, collection? }`.
|
|
1033
1056
|
`syncResult.collections[].files[].recordImport`, when present, conforms to
|
|
1034
1057
|
[`record-import@1.0`](./output-schemas/record-import.schema.json) with the same
|
|
1035
1058
|
deterministic ordering, bounds, truncation disclosure, and partial-snapshot
|
|
1036
1059
|
warnings as `gno update --json`. Human progress and diagnostics remain on
|
|
1037
|
-
stderr.
|
|
1038
|
-
and the
|
|
1060
|
+
stderr. A failed stage still emits the partial receipt on stdout (with
|
|
1061
|
+
`success: false` and `error`) before the non-zero exit. On lease timeout,
|
|
1062
|
+
stdout is one object `{ success: false, error, contention }` and the process
|
|
1063
|
+
exits 4.
|
|
1039
1064
|
|
|
1040
1065
|
**Exit Codes:**
|
|
1041
1066
|
|
|
1042
|
-
- 0:
|
|
1067
|
+
- 0: Every attempted stage completed
|
|
1043
1068
|
- 1: Invalid collection name or invalid `--lock-wait`
|
|
1044
|
-
- 2: DB or model failure
|
|
1045
|
-
|
|
1069
|
+
- 2: DB or model failure, or any stage `failed` (including chunk-level embed
|
|
1070
|
+
failures; the partial receipt is still emitted)
|
|
1071
|
+
- 4: Write lease busy (contention, not corruption), or chunks deferred by
|
|
1072
|
+
index contention after an otherwise completed embed stage
|
|
1046
1073
|
|
|
1047
1074
|
**Examples:**
|
|
1048
1075
|
|
|
@@ -2372,11 +2399,21 @@ gno doctor [--json|--md]
|
|
|
2372
2399
|
}
|
|
2373
2400
|
]
|
|
2374
2401
|
}
|
|
2402
|
+
},
|
|
2403
|
+
{
|
|
2404
|
+
"name": "findings-pass",
|
|
2405
|
+
"status": "ok",
|
|
2406
|
+
"message": "disabled (opt-in via findings.enabled)"
|
|
2375
2407
|
}
|
|
2376
2408
|
]
|
|
2377
2409
|
}
|
|
2378
2410
|
```
|
|
2379
2411
|
|
|
2412
|
+
The `findings-pass` check reports the daemon's scheduled findings pass from
|
|
2413
|
+
its persisted run state: `ok` when disabled or the last run succeeded, `warn`
|
|
2414
|
+
on `skipped_lease` / `overdue` / no recorded run, `error` on `failed` or a
|
|
2415
|
+
misconfigured `findings` block (see [Daemon Mode](../docs/DAEMON.md#scheduled-findings-pass)).
|
|
2416
|
+
|
|
2380
2417
|
The `embedding-fingerprint` check is additive doctor-only diagnostics. It uses
|
|
2381
2418
|
the active embed model and stored vector dimensions to report the current
|
|
2382
2419
|
freshness fingerprint, pending/stale chunks, legacy empty-fingerprint vectors,
|
|
@@ -3595,6 +3632,7 @@ List retained, metadata-only document lifecycle changes.
|
|
|
3595
3632
|
|
|
3596
3633
|
```bash
|
|
3597
3634
|
gno changes [--since <ISO-8601|cursor>] [--collection <name>] [--limit <n>] [--json]
|
|
3635
|
+
gno changes --follow --jsonl [--cursor <cursor>] [--collection <name>]
|
|
3598
3636
|
```
|
|
3599
3637
|
|
|
3600
3638
|
- `--since` accepts an ISO-8601 time or an opaque cursor returned by an earlier
|
|
@@ -3605,6 +3643,42 @@ gno changes [--since <ISO-8601|cursor>] [--collection <name>] [--limit <n>] [--j
|
|
|
3605
3643
|
cursor-expiry, and retention-truncation disclosure.
|
|
3606
3644
|
- The journal never returns source bodies.
|
|
3607
3645
|
|
|
3646
|
+
**Follow mode (`--follow --jsonl`)** streams journal events as they land and is
|
|
3647
|
+
the durable automation input for consumers that resume across restarts.
|
|
3648
|
+
|
|
3649
|
+
- `--follow` and `--jsonl` are one mode and must be given together; `--cursor`
|
|
3650
|
+
requires both. The mode excludes `--since`, `--limit`, and `--json` (exit 1).
|
|
3651
|
+
`--collection` filters the stream.
|
|
3652
|
+
- Wire contract: one JSON object per stdout line, validated by
|
|
3653
|
+
`changes-follow-event.schema.json`. An event line is
|
|
3654
|
+
`{"event": <change>, "postCursor": "<cursor>"}` where `event` is one
|
|
3655
|
+
`changes.schema.json` change and `postCursor` is the journal cursor after
|
|
3656
|
+
that event was applied. Lines are emitted in journal order.
|
|
3657
|
+
- Checkpoint rule: a consumer persists `postCursor` after it has durably
|
|
3658
|
+
handled the line and restarts with `--cursor <postCursor>`; nothing at or
|
|
3659
|
+
before that cursor is replayed. Delivery is at-least-once: a line the
|
|
3660
|
+
consumer received but did not checkpoint is redelivered on resume, so
|
|
3661
|
+
handlers must be idempotent by `event.id` (each event id is unique and
|
|
3662
|
+
equals its own `postCursor`).
|
|
3663
|
+
- Start position: without `--cursor` the stream starts at the journal's
|
|
3664
|
+
current `latestCursor` (tail semantics, no backfill). `--cursor` must be an
|
|
3665
|
+
opaque cursor from an earlier response (exit 1 when malformed or ahead of
|
|
3666
|
+
the journal).
|
|
3667
|
+
- Quiet periods emit nothing. There is no keepalive line in v1; consumers
|
|
3668
|
+
detect liveness from the process, not the stream.
|
|
3669
|
+
- Cursor expiry: when the resume cursor falls below the retention floor the
|
|
3670
|
+
stream writes exactly one terminal line,
|
|
3671
|
+
`{"error": "cursor_expired", "earliestCursor": "<cursor>", "latestCursor": "<cursor>"}`,
|
|
3672
|
+
then exits 2 with nothing on stderr. `earliestCursor` is the journal's
|
|
3673
|
+
documented resume floor (`gno changes --json` reports the same value);
|
|
3674
|
+
`latestCursor` is the current tail. The consumer chooses whether to backfill
|
|
3675
|
+
from `earliestCursor` or resume from `latestCursor` and accept the gap;
|
|
3676
|
+
resuming from `latestCursor` skips every retained event.
|
|
3677
|
+
- Signals: SIGINT or SIGTERM ends the stream after the line in progress and
|
|
3678
|
+
exits 0. No partial line is ever written.
|
|
3679
|
+
- The reader never takes the write lease; `gno index`, `gno update`, capture,
|
|
3680
|
+
and the daemon are never blocked by a follower.
|
|
3681
|
+
|
|
3608
3682
|
### gno diff
|
|
3609
3683
|
|
|
3610
3684
|
Show the latest retained structural delta for one document, or select an exact
|
|
@@ -3851,6 +3925,13 @@ is blocked.
|
|
|
3851
3925
|
watcher behavior.
|
|
3852
3926
|
- Runs an initial sync by default
|
|
3853
3927
|
- Triggers embedding after initial sync completes
|
|
3928
|
+
- With `findings.enabled`, runs the scheduled findings pass on its cadence:
|
|
3929
|
+
a read-only audit of every collection except the findings one, written as
|
|
3930
|
+
deterministic Markdown records into `findings.collection`. The audit runs
|
|
3931
|
+
without the write lease; only the record write takes it (no wait; a busy
|
|
3932
|
+
lease is recorded as `skipped_lease`). Every attempt persists to
|
|
3933
|
+
`{data}/index-<name>.findings-run.json`, surfaced by `--status` (`findings`)
|
|
3934
|
+
and the `findings-pass` doctor check. See [Daemon Mode](../docs/DAEMON.md#scheduled-findings-pass)
|
|
3854
3935
|
- Runs in the foreground until `SIGINT` / `SIGTERM`
|
|
3855
3936
|
- Starts a headless `/mcp` Streamable HTTP listener; it does not serve the Web UI
|
|
3856
3937
|
- Exposes the same safe REST lifecycle snapshot at `/api/resident/status`;
|
package/spec/mcp.md
CHANGED
|
@@ -1537,6 +1537,17 @@ Create a new document in a collection (write-enabled).
|
|
|
1537
1537
|
- For non-Markdown files, tags are stored as user-source in the database
|
|
1538
1538
|
- Receipts distinguish write result from sync and embedding state; capture does
|
|
1539
1539
|
not imply embedding unless `embed.status` is `completed`
|
|
1540
|
+
- Success is retrievability: the write and its lexical sync complete under the
|
|
1541
|
+
shared write lease before the tool returns, so a successful result always
|
|
1542
|
+
carries `sync.status: "completed"` and the note is an immediate `gno_search`
|
|
1543
|
+
hit. A written file whose sync fails is a tool error `CAPTURE_SYNC_FAILED`
|
|
1544
|
+
(message names the written path; run `gno update` to retry), never a success
|
|
1545
|
+
with `sync.status: "failed"`
|
|
1546
|
+
- `open_existing` on a file that is on disk but not indexed yet syncs it before
|
|
1547
|
+
returning `collisionPolicyResult: "opened_existing"`
|
|
1548
|
+
- The lease wait follows the v1.38 contention contract: the tool waits up to
|
|
1549
|
+
120s for a concurrent CLI/MCP/REST writer, then returns `LOCKED` without
|
|
1550
|
+
writing
|
|
1540
1551
|
- Writes run under the MCP write lock and are only registered when the server
|
|
1541
1552
|
starts with `--enable-write` or `GNO_MCP_ENABLE_WRITE=1`
|
|
1542
1553
|
|
|
@@ -2742,6 +2753,7 @@ Resource errors use standard MCP error responses.
|
|
|
2742
2753
|
- `PATH_NOT_FOUND` — Path does not exist
|
|
2743
2754
|
- `JOB_CONFLICT` — Another job is already running
|
|
2744
2755
|
- `LOCKED` — Another MCP process holds the write lock
|
|
2756
|
+
- `CAPTURE_SYNC_FAILED` — `gno_capture` wrote the file but lexical sync failed
|
|
2745
2757
|
- `WRITE_DISABLED` — Write tool dispatched while writes are disabled
|
|
2746
2758
|
- `MEMORY_*` — Memory contract errors from `gno_recall` / `gno_remember`;
|
|
2747
2759
|
the stable code set is `MemoryErrorCode` in `src/core/memory.ts` and each
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "gno://schemas/changes-follow-event@1.0",
|
|
4
|
+
"title": "GNO Knowledge Changes Follow Line",
|
|
5
|
+
"description": "One stdout line of `gno changes --follow --jsonl`: either a journal event with the cursor after it was applied, or the single terminal cursor-expiry record.",
|
|
6
|
+
"oneOf": [
|
|
7
|
+
{ "$ref": "#/definitions/eventLine" },
|
|
8
|
+
{ "$ref": "#/definitions/expiredLine" }
|
|
9
|
+
],
|
|
10
|
+
"definitions": {
|
|
11
|
+
"eventLine": {
|
|
12
|
+
"type": "object",
|
|
13
|
+
"required": ["event", "postCursor"],
|
|
14
|
+
"properties": {
|
|
15
|
+
"event": { "$ref": "gno://schemas/changes@1.0#/definitions/change" },
|
|
16
|
+
"postCursor": { "type": "string", "minLength": 1, "maxLength": 512 }
|
|
17
|
+
},
|
|
18
|
+
"additionalProperties": false
|
|
19
|
+
},
|
|
20
|
+
"expiredLine": {
|
|
21
|
+
"type": "object",
|
|
22
|
+
"required": ["error", "earliestCursor", "latestCursor"],
|
|
23
|
+
"properties": {
|
|
24
|
+
"error": { "type": "string", "const": "cursor_expired" },
|
|
25
|
+
"earliestCursor": {
|
|
26
|
+
"type": "string",
|
|
27
|
+
"minLength": 1,
|
|
28
|
+
"maxLength": 512
|
|
29
|
+
},
|
|
30
|
+
"latestCursor": { "type": "string", "minLength": 1, "maxLength": 512 }
|
|
31
|
+
},
|
|
32
|
+
"additionalProperties": false
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "gno://schemas/index-receipt@1.0",
|
|
4
|
+
"title": "GNO Index Receipt",
|
|
5
|
+
"description": "Per-stage receipt emitted by `gno index --json`. The lexical (sync) and embed stages are separable and resumable; the run succeeds only when every attempted stage completed. A run interrupted by a killed process emits nothing - the next run reports the interrupted stage under `resumedFrom`.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"required": ["success", "stages", "resumedFrom", "embedSkipped"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"success": {
|
|
11
|
+
"type": "boolean",
|
|
12
|
+
"description": "True only when every attempted stage completed."
|
|
13
|
+
},
|
|
14
|
+
"error": {
|
|
15
|
+
"type": "string",
|
|
16
|
+
"description": "Present when success is false: the failed stage's error."
|
|
17
|
+
},
|
|
18
|
+
"stages": {
|
|
19
|
+
"type": "object",
|
|
20
|
+
"additionalProperties": false,
|
|
21
|
+
"required": ["lexical", "embed"],
|
|
22
|
+
"properties": {
|
|
23
|
+
"lexical": { "$ref": "#/definitions/lexicalStage" },
|
|
24
|
+
"embed": { "$ref": "#/definitions/embedStage" }
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"resumedFrom": {
|
|
28
|
+
"oneOf": [
|
|
29
|
+
{ "$ref": "#/definitions/interruptedStage" },
|
|
30
|
+
{ "type": "null" }
|
|
31
|
+
],
|
|
32
|
+
"description": "Stage a previous run left running (process died mid-stage); null when this run started clean."
|
|
33
|
+
},
|
|
34
|
+
"syncResult": {
|
|
35
|
+
"type": "object",
|
|
36
|
+
"description": "Complete deterministic sync result (same shape as `gno update --json`); absent when the lexical stage failed before producing one."
|
|
37
|
+
},
|
|
38
|
+
"embedSkipped": {
|
|
39
|
+
"type": "boolean",
|
|
40
|
+
"description": "True when `--no-embed` was passed."
|
|
41
|
+
},
|
|
42
|
+
"embedResult": {
|
|
43
|
+
"type": "object",
|
|
44
|
+
"additionalProperties": false,
|
|
45
|
+
"required": ["embedded", "errors", "contentionErrors", "duration"],
|
|
46
|
+
"description": "Embedding outcome when the embed stage ran to a result (present for completed and for partially failed passes; absent when the stage failed before embedding).",
|
|
47
|
+
"properties": {
|
|
48
|
+
"embedded": { "type": "integer", "minimum": 0 },
|
|
49
|
+
"errors": { "type": "integer", "minimum": 0 },
|
|
50
|
+
"contentionErrors": { "type": "integer", "minimum": 0 },
|
|
51
|
+
"duration": {
|
|
52
|
+
"type": "number",
|
|
53
|
+
"minimum": 0,
|
|
54
|
+
"description": "Seconds."
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"definitions": {
|
|
60
|
+
"stageState": {
|
|
61
|
+
"type": "string",
|
|
62
|
+
"enum": ["completed", "failed", "skipped", "interrupted"]
|
|
63
|
+
},
|
|
64
|
+
"lexicalStage": {
|
|
65
|
+
"type": "object",
|
|
66
|
+
"additionalProperties": false,
|
|
67
|
+
"required": [
|
|
68
|
+
"state",
|
|
69
|
+
"filesProcessed",
|
|
70
|
+
"filesAdded",
|
|
71
|
+
"filesUpdated",
|
|
72
|
+
"filesErrored",
|
|
73
|
+
"filesSkipped",
|
|
74
|
+
"durationMs"
|
|
75
|
+
],
|
|
76
|
+
"properties": {
|
|
77
|
+
"state": { "$ref": "#/definitions/stageState" },
|
|
78
|
+
"filesProcessed": { "type": "integer", "minimum": 0 },
|
|
79
|
+
"filesAdded": { "type": "integer", "minimum": 0 },
|
|
80
|
+
"filesUpdated": { "type": "integer", "minimum": 0 },
|
|
81
|
+
"filesErrored": {
|
|
82
|
+
"type": "integer",
|
|
83
|
+
"minimum": 0,
|
|
84
|
+
"description": "Per-file errors are counted, not fatal; the stage still completes."
|
|
85
|
+
},
|
|
86
|
+
"filesSkipped": { "type": "integer", "minimum": 0 },
|
|
87
|
+
"durationMs": { "type": "integer", "minimum": 0 },
|
|
88
|
+
"error": { "type": "string" }
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
"embedStage": {
|
|
92
|
+
"type": "object",
|
|
93
|
+
"additionalProperties": false,
|
|
94
|
+
"required": [
|
|
95
|
+
"state",
|
|
96
|
+
"embedded",
|
|
97
|
+
"errors",
|
|
98
|
+
"contentionErrors",
|
|
99
|
+
"durationMs"
|
|
100
|
+
],
|
|
101
|
+
"properties": {
|
|
102
|
+
"state": { "$ref": "#/definitions/stageState" },
|
|
103
|
+
"embedded": { "type": "integer", "minimum": 0 },
|
|
104
|
+
"errors": {
|
|
105
|
+
"type": "integer",
|
|
106
|
+
"minimum": 0,
|
|
107
|
+
"description": "Chunks that failed to embed after same-run retries; any non-zero value makes the stage `failed`."
|
|
108
|
+
},
|
|
109
|
+
"contentionErrors": {
|
|
110
|
+
"type": "integer",
|
|
111
|
+
"minimum": 0,
|
|
112
|
+
"description": "Chunks deferred by SQLITE_BUSY/LOCKED - not embedding failures."
|
|
113
|
+
},
|
|
114
|
+
"durationMs": { "type": "integer", "minimum": 0 },
|
|
115
|
+
"reason": {
|
|
116
|
+
"type": "string",
|
|
117
|
+
"description": "Why the stage was skipped (`--no-embed`, `lexical stage failed`)."
|
|
118
|
+
},
|
|
119
|
+
"error": { "type": "string" }
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
"interruptedStage": {
|
|
123
|
+
"type": "object",
|
|
124
|
+
"additionalProperties": false,
|
|
125
|
+
"required": ["stage", "state", "startedAt", "pid"],
|
|
126
|
+
"properties": {
|
|
127
|
+
"stage": { "type": "string", "enum": ["lexical", "embed"] },
|
|
128
|
+
"state": { "const": "interrupted" },
|
|
129
|
+
"startedAt": { "type": "string", "format": "date-time" },
|
|
130
|
+
"pid": { "type": "integer", "minimum": 1 },
|
|
131
|
+
"collection": { "type": "string" }
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|