@sigrun/knowledge 0.0.0-stage → 0.1.1

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/CHANGELOG.md ADDED
@@ -0,0 +1,82 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ### Added
11
+
12
+ - Everything below, released as 0.1.0: the full knowledge extension —
13
+ store, atomic versioned apply/undo, tools, the curation target, the
14
+ research flag, recall mirroring and the idle pass.
15
+
16
+ ### Fixed (post-merge follow-ups)
17
+
18
+ - Idle pass: a kept child type's identity-key rows re-root by its
19
+ entities, not by the child's own type id — a child type's rows live at
20
+ its family root (the grandparent), so the old select missed them and a
21
+ later record for the same key minted a duplicate entity.
22
+ - Mirroring: a rejected `recall.index` call logs one line (the silent
23
+ skip hid every mirror failure — including the card-date format bug the
24
+ e2e later caught).
25
+
26
+ ## [0.1.1] - 2026-11-05
27
+
28
+ ### Fixed
29
+
30
+ - First registry release. 0.1.0 was consumed by the npm stage
31
+ bootstrap (the name-claiming placeholder) and never published; 0.1.1
32
+ is the identical tree.
33
+
34
+ ### Added
35
+
36
+ - Package scaffold: `createKnowledge(host, deps?)` factory returning
37
+ `defineExtension({ name: "@sigrun/knowledge" })`, arity 1, with lazily
38
+ opened per-user databases closed on `harnessShutdown`.
39
+ - `src/schema.ts`: the field-schema subset (`FieldType`, `FieldDef`,
40
+ `TypeDef`, `TypeDefSchema`, `validateValue`).
41
+ - `src/db.ts`: `KnowledgeDb` — types / entities / entity_keys / inquiries /
42
+ roles / versions / applied / maintenance tables plus
43
+ `transaction` (BEGIN IMMEDIATE / COMMIT / ROLLBACK) and `close`.
44
+ - `src/config.ts`: `resolveUserSettings` (researchTools glob list with
45
+ warn-once fallback) and `matchesGlob` (`*` only).
46
+ - `src/apply.ts` / `src/undo.ts` / `src/card.ts`: `applyRecord` (one
47
+ transaction, whole-record validation, entity de-duplication by
48
+ identity-key pairs within a type family, idempotent replay by call id),
49
+ `undoChange` (newest-first row-equality restores, versioned under
50
+ `undo:<changeId>`, create-archive and skip reporting), `retypeEntities`,
51
+ and `renderCard` (stale marks past `horizonDays`).
52
+ - `src/tools.ts`: `knowledge_record` (target tool, replay-safe, idempotent
53
+ by call id; inquiry records the reviewed parent conversation through the
54
+ fork-ancestry paging lookup) and `knowledge_find` (read tool — batched
55
+ type/field/inquiry/text queries; text via `recall.search` with LIKE
56
+ fallback; audience rule first; local-only entities never shown).
57
+ - `src/target.ts`: the `knowledge` curation target — guidance, undo
58
+ (revert + re-mirror), wantsReview/reviewed on the research flag,
59
+ `maintain` (the idle pass: re-index pending/stale entities, continue
60
+ unfinished re-typing, propose one generalization per pass — ≥3
61
+ overlapping siblings into a shared parent, folding field-less
62
+ children, ≤50 retypes per pass).
63
+ - `src/research.ts`: the `afterTool` research flag (`<user
64
+ state>/research.json`) with the 15-minute single-request window.
65
+ - `src/mirror.ts`: recall mirroring after apply/undo — `recall.index`
66
+ (kind `record`) or `recall.remove` for archived entities; failure
67
+ leaves `indexedAt` behind the last version for the idle pass.
68
+ - `src/audience.ts`: the audience rule (private copy of recall's).
69
+ - `src/prompts.ts`: the review guidance bullets.
70
+ - `src/maintain.ts`: the idle pass implementation (generalize sibling
71
+ types into a hierarchy with versioned key re-roots, declined-group
72
+ memory, collision-drop cleanup).
73
+
74
+ ### Dependencies
75
+
76
+ - `@sigrun/shared` peer accepts `0.5.0 || 0.6.0 || 0.6.1 || 0.7.0 ||
77
+ 0.8.0` (the runtime value imports landed on 0.5.0; recall made the
78
+ same widening).
79
+
80
+ <!-- TODO at release time: pin `@sigrun/sigrun` and `@sigrun/shared` to
81
+ the releases carrying published hooks and curation targets (core
82
+ 0.9.0 line, when cut). -->
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Michael MacLeod
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,84 @@
1
- # Temporary Holding Version
1
+ # @sigrun/knowledge
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Curated per-user knowledge extension for [sigrun](https://github.com/sigrun-ai/sigrun).
4
+
5
+ This package owns one SQLite store per directory user
6
+ (`<user data dir>/knowledge.db`) holding typed knowledge entities, identity
7
+ keys, inquiries, and the version history that makes every change undoable.
8
+
9
+ ## Tools
10
+
11
+ - **`knowledge_record`** (curation target tool, `replay: "safe"`,
12
+ idempotent by call id): one call carries the whole update from a review —
13
+ the inquiry (question, why, outcome), any new or extended types, and the
14
+ entities with identity keys, cited fields (`{value, source, observedAt}`
15
+ where `source` is a recall handle), and per-inquiry roles. Applied
16
+ atomically; validation errors roll everything back and are reported as
17
+ text with no `details.curation`. Success returns the one-line summary
18
+ (`recorded Biscuit's knee: 3 vet clinics`) as the output text and
19
+ `details.curation: { changeId, summary }` — the undo unit.
20
+
21
+ The user is the conversation's acting user (the review fork's owner).
22
+ The inquiry records the *reviewed parent* conversation, resolved by
23
+ paging the fork's entries newest-first until an entry stamped with a
24
+ different conversation id appears.
25
+
26
+ - **`knowledge_find`** (read tool, never a target tool): batched queries
27
+ (≤ 10) by `type` (child types included), by `field` comparison
28
+ (`eq`/`lt`/`gt`/`contains`; money compares amounts within one currency
29
+ only), by `inquiry` question text, or by free `text`. Text search goes
30
+ through the optional `recall.search` hook (keeping only knowledge's own
31
+ hits) and falls back to a `LIKE` scan when recall is absent or fails.
32
+ Entities with class `local-only` are never shown.
33
+
34
+ The audience rule (spec delta 7) runs first: in a shared conversation
35
+ the tool answers "Not available here." unless every reader may see the
36
+ user's knowledge — the user's own records are private to their
37
+ conversations.
38
+
39
+ ## The curation target
40
+
41
+ The factory result declares one target:
42
+ `{ name: "knowledge", tools: ["knowledge_record"], readTools: ["knowledge_find"] }`.
43
+
44
+ - `guidance` — the review prompt bullets (record the inquiry and its why;
45
+ find before creating; cite every field; give fields that go out of date a
46
+ `horizonDays` — prices ~30, opening hours ~180, addresses none; record
47
+ the user's verdicts, never the agent's guesses).
48
+ - `undo` — reverts a change (row-level equality: only rows still equal to
49
+ what the change wrote are restored) and re-mirrors every touched entity.
50
+ - `wantsReview` / `reviewed` — drive the research flag (below).
51
+ - `maintain` — the idle pass: re-indexes up to 50 pending or
52
+ horizon-stale entities (mirroring them into recall), continues an
53
+ unfinished re-typing before proposing anything new, and proposes at
54
+ most ONE generalization per pass — ≥ 3 sibling types whose field
55
+ names overlap (pairwise Jaccard ≥ 0.5) become children of a new shared
56
+ parent type; a child left with no distinct fields is folded (its
57
+ entities re-typed, ≤ 50 per pass, extra values preserved in
58
+ `attributes`); identity-key rows re-root (versioned) so records keep
59
+ merging; declined groups are remembered for 30 days. The digest-run
60
+ budget bounds the pass and its runs.
61
+
62
+ ## The research trigger
63
+
64
+ An `afterTool` hook watches non-internal conversations with an owner: when
65
+ a tool whose name matches the owner's `researchTools` globs (defaults to
66
+ web search/fetch/crawl tool names) runs, the conversation is flagged in
67
+ `<user state>/research.json`. The curator asks `wantsReview` at settle;
68
+ a flag with no request in the last 15 minutes answers true once (stamping
69
+ the request), `reviewed` clears it, and a review that never completes is
70
+ re-requested after the window. Errors are logged, never thrown, and the
71
+ hook never alters tool results.
72
+
73
+ The glob list is the per-user `researchTools` setting (`*` is the only
74
+ wildcard), e.g. `["searxng/search*", "web_fetch"]`.
75
+
76
+ ## Recall mirroring (optional dependency)
77
+
78
+ After each apply or undo, every touched entity is mirrored into recall
79
+ through the published `recall.index` hook (`kind: "record"`, id = entity
80
+ id, title/text/date/sources from the review card); archived entities are
81
+ removed through `recall.remove`. On `ok` the returned class and the index
82
+ instant are stored; on `absent` nothing happens (knowledge works fully
83
+ without recall); on `failed`/`rejected` the entity's `indexedAt` stays
84
+ behind its last version so the next idle pass retries.
@@ -0,0 +1,56 @@
1
+ import type { KnowledgeDb } from "./db.js";
2
+ import { type TypeDef } from "./schema.js";
3
+ declare const ENTITY_ROLES: readonly ["candidate", "shortlisted", "rejected", "chosen"];
4
+ export interface RecordInput {
5
+ inquiry?: {
6
+ id?: string;
7
+ question: string;
8
+ why?: string;
9
+ outcome?: {
10
+ status: "open" | "decided" | "abandoned";
11
+ what?: string;
12
+ };
13
+ };
14
+ types?: TypeDef[];
15
+ entities: {
16
+ id?: string;
17
+ type: string;
18
+ name: string;
19
+ keys: Record<string, string>;
20
+ fields: Record<string, {
21
+ value: unknown;
22
+ source: string;
23
+ observedAt: string;
24
+ }>;
25
+ attributes?: Record<string, unknown>;
26
+ role?: (typeof ENTITY_ROLES)[number];
27
+ reason?: string;
28
+ }[];
29
+ }
30
+ export interface ApplyResult {
31
+ changeId: string;
32
+ summary: string;
33
+ /** Entity ids created or updated. */
34
+ touched: string[];
35
+ errors: string[];
36
+ }
37
+ export interface ApplyContext {
38
+ conversationId?: number;
39
+ callId: string;
40
+ now: number;
41
+ }
42
+ /** Normalize an identity key value for matching within a type family. */
43
+ export declare function normalizeKey(key: string, value: string): string;
44
+ /**
45
+ * Apply one knowledge record atomically. Any validation error rolls the
46
+ * whole record back and is reported in `errors`. Replaying an already
47
+ * applied `callId` returns the stored result unchanged.
48
+ */
49
+ export declare function applyRecord(db: KnowledgeDb, input: RecordInput, ctx: ApplyContext): ApplyResult;
50
+ /**
51
+ * Move entities to a different type: field values the new type does not
52
+ * declare move into attributes, and identity keys re-root at the new
53
+ * type's family.
54
+ */
55
+ export declare function retypeEntities(db: KnowledgeDb, entityIds: readonly string[], toType: string, changeId: string, now: number): void;
56
+ export {};