@vaur94/agz-memory 0.4.0-beta.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.
Files changed (41) hide show
  1. package/ARCHITECTURE.md +173 -0
  2. package/CHANGELOG.md +18 -0
  3. package/LICENSE +21 -0
  4. package/README.md +237 -0
  5. package/README.tr.md +240 -0
  6. package/dist/admin.js +1494 -0
  7. package/dist/core.js +2434 -0
  8. package/dist/server.js +1790 -0
  9. package/dist/types/admin/doctor.d.ts +10 -0
  10. package/dist/types/admin/index.d.ts +2 -0
  11. package/dist/types/capture/contract.d.ts +102 -0
  12. package/dist/types/capture/identity.d.ts +25 -0
  13. package/dist/types/capture/policy.d.ts +9 -0
  14. package/dist/types/capture/projection.d.ts +17 -0
  15. package/dist/types/capture/redact.d.ts +12 -0
  16. package/dist/types/config.d.ts +4 -0
  17. package/dist/types/context.d.ts +1 -0
  18. package/dist/types/core.d.ts +30 -0
  19. package/dist/types/db/backup.d.ts +25 -0
  20. package/dist/types/db/health.d.ts +11 -0
  21. package/dist/types/db/migration-lock.d.ts +17 -0
  22. package/dist/types/db/migrations/v009.d.ts +3 -0
  23. package/dist/types/db/schema.d.ts +5 -0
  24. package/dist/types/db.d.ts +6 -0
  25. package/dist/types/identity.d.ts +1 -0
  26. package/dist/types/index.d.ts +2 -0
  27. package/dist/types/project.d.ts +4 -0
  28. package/dist/types/retrieval/backends/none.d.ts +9 -0
  29. package/dist/types/retrieval/contract.d.ts +42 -0
  30. package/dist/types/retrieval/derived.d.ts +11 -0
  31. package/dist/types/retrieval/formatter.d.ts +5 -0
  32. package/dist/types/retrieval/fusion.d.ts +8 -0
  33. package/dist/types/server.d.ts +5 -0
  34. package/dist/types/store/capture.d.ts +46 -0
  35. package/dist/types/store/outbox.d.ts +14 -0
  36. package/dist/types/store/retrieval.d.ts +18 -0
  37. package/dist/types/store.d.ts +95 -0
  38. package/dist/types/tools.d.ts +3 -0
  39. package/dist/types/types.d.ts +54 -0
  40. package/docs/backup-restore-runbook.md +73 -0
  41. package/package.json +63 -0
@@ -0,0 +1,10 @@
1
+ import type { Database } from "bun:sqlite";
2
+ import { inspectDatabase } from "../db/health";
3
+ export interface DoctorReport {
4
+ ok: boolean;
5
+ health: ReturnType<typeof inspectDatabase>;
6
+ warnings: string[];
7
+ failures: string[];
8
+ invariants: Record<string, number>;
9
+ }
10
+ export declare function doctorDatabase(db: Database): DoctorReport;
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env bun
2
+ export declare function runAdmin(argv?: string[]): Promise<unknown>;
@@ -0,0 +1,102 @@
1
+ import * as z from "zod/v4";
2
+ export declare const CAPTURE_SCHEMA: "opencode2-memory.capture/1";
3
+ export declare const SUPPORTED_OPENCODE_VERSION: "0.0.0-beta-18743";
4
+ export declare const CAPTURE_EVENT_MAX_BYTES: number;
5
+ export declare const CAPTURE_CONTENT_MAX_CHARACTERS = 4800;
6
+ export declare const CAPTURE_SUMMARY_MAX_CHARACTERS = 1200;
7
+ export declare const CAPTURE_SUBJECT_MAX_CHARACTERS = 240;
8
+ declare const candidateSchema: z.ZodObject<{
9
+ kind: z.ZodEnum<{
10
+ context: "context";
11
+ decision: "decision";
12
+ fact: "fact";
13
+ preference: "preference";
14
+ procedure: "procedure";
15
+ research: "research";
16
+ task: "task";
17
+ }>;
18
+ title: z.ZodString;
19
+ summary: z.ZodString;
20
+ content: z.ZodString;
21
+ subjectKey: z.ZodOptional<z.ZodString>;
22
+ intent: z.ZodEnum<{
23
+ create: "create";
24
+ ignore: "ignore";
25
+ review: "review";
26
+ supersede: "supersede";
27
+ }>;
28
+ targetNoteID: z.ZodOptional<z.ZodString>;
29
+ confidence: z.ZodNumber;
30
+ evidence: z.ZodEnum<{
31
+ "explicit-user": "explicit-user";
32
+ "session-summary": "session-summary";
33
+ "verified-outcome": "verified-outcome";
34
+ }>;
35
+ }, z.core.$strict>;
36
+ export declare const captureEventSchema: z.ZodObject<{
37
+ schema: z.ZodLiteral<"opencode2-memory.capture/1">;
38
+ idempotencyKey: z.ZodString;
39
+ projectID: z.ZodUUID;
40
+ bindingKey: z.ZodString;
41
+ kind: z.ZodEnum<{
42
+ "assistant-candidate": "assistant-candidate";
43
+ "session-summary": "session-summary";
44
+ "tool-signal": "tool-signal";
45
+ "user-candidate": "user-candidate";
46
+ }>;
47
+ source: z.ZodObject<{
48
+ system: z.ZodLiteral<"opencode-v2">;
49
+ opencodeVersion: z.ZodLiteral<"0.0.0-beta-18743">;
50
+ pluginVersion: z.ZodString;
51
+ sessionID: z.ZodString;
52
+ messageID: z.ZodOptional<z.ZodString>;
53
+ ordinal: z.ZodOptional<z.ZodNumber>;
54
+ toolCallID: z.ZodOptional<z.ZodString>;
55
+ observedAt: z.ZodNumber;
56
+ }, z.core.$strict>;
57
+ candidate: z.ZodOptional<z.ZodObject<{
58
+ kind: z.ZodEnum<{
59
+ context: "context";
60
+ decision: "decision";
61
+ fact: "fact";
62
+ preference: "preference";
63
+ procedure: "procedure";
64
+ research: "research";
65
+ task: "task";
66
+ }>;
67
+ title: z.ZodString;
68
+ summary: z.ZodString;
69
+ content: z.ZodString;
70
+ subjectKey: z.ZodOptional<z.ZodString>;
71
+ intent: z.ZodEnum<{
72
+ create: "create";
73
+ ignore: "ignore";
74
+ review: "review";
75
+ supersede: "supersede";
76
+ }>;
77
+ targetNoteID: z.ZodOptional<z.ZodString>;
78
+ confidence: z.ZodNumber;
79
+ evidence: z.ZodEnum<{
80
+ "explicit-user": "explicit-user";
81
+ "session-summary": "session-summary";
82
+ "verified-outcome": "verified-outcome";
83
+ }>;
84
+ }, z.core.$strict>>;
85
+ signal: z.ZodOptional<z.ZodObject<{
86
+ tool: z.ZodString;
87
+ status: z.ZodEnum<{
88
+ completed: "completed";
89
+ error: "error";
90
+ }>;
91
+ errorType: z.ZodOptional<z.ZodString>;
92
+ }, z.core.$strict>>;
93
+ redaction: z.ZodObject<{
94
+ policyVersion: z.ZodString;
95
+ replacements: z.ZodNumber;
96
+ truncated: z.ZodBoolean;
97
+ }, z.core.$strict>;
98
+ }, z.core.$strict>;
99
+ export type MemoryCandidateV1 = z.infer<typeof candidateSchema>;
100
+ export type CaptureEventV1 = z.infer<typeof captureEventSchema>;
101
+ export declare function parseCaptureEvent(value: unknown): CaptureEventV1;
102
+ export {};
@@ -0,0 +1,25 @@
1
+ export type CaptureIdentityInput = {
2
+ kind: "user";
3
+ bindingKey: string;
4
+ sessionID: string;
5
+ messageID: string;
6
+ } | {
7
+ kind: "assistant";
8
+ bindingKey: string;
9
+ sessionID: string;
10
+ assistantMessageID: string;
11
+ ordinal: number;
12
+ } | {
13
+ kind: "tool";
14
+ bindingKey: string;
15
+ sessionID: string;
16
+ assistantMessageID: string;
17
+ toolCallID: string;
18
+ terminalStatus: "completed" | "error";
19
+ } | {
20
+ kind: "summary";
21
+ bindingKey: string;
22
+ sessionID: string;
23
+ checkpointMessageID: string;
24
+ };
25
+ export declare function captureIdempotencyKey(input: CaptureIdentityInput): string;
@@ -0,0 +1,9 @@
1
+ import type { MemoryCandidateV1 } from "./contract";
2
+ export declare const CAPTURE_POLICY_VERSION = "capture-policy/1";
3
+ export declare const EXTRACTOR_VERSION = "deterministic-extractor/1";
4
+ export declare function extractExplicitUserCandidate(text: string): MemoryCandidateV1 | undefined;
5
+ export declare function canAutoWrite(candidate: MemoryCandidateV1, redaction: {
6
+ truncated: boolean;
7
+ quarantined: boolean;
8
+ }, allowedKinds?: readonly string[], minConfidence?: number): boolean;
9
+ export declare function normalizeSubjectKey(value: string): string;
@@ -0,0 +1,17 @@
1
+ export interface ProjectedText {
2
+ text: string;
3
+ truncated: boolean;
4
+ }
5
+ export declare function projectUserPrompt(prompt: {
6
+ text?: unknown;
7
+ }, maxCharacters?: number): ProjectedText;
8
+ export declare function projectAssistantParts(parts: readonly unknown[], maxCharacters?: number): ProjectedText;
9
+ export declare function projectSessionSummary(messages: readonly {
10
+ role: string;
11
+ parts: readonly unknown[];
12
+ }[], maxCharacters?: number): ProjectedText;
13
+ export declare function projectToolSignal(tool: string, status: "completed" | "error", error?: unknown): {
14
+ tool: string;
15
+ status: "completed" | "error";
16
+ errorType?: string;
17
+ };
@@ -0,0 +1,12 @@
1
+ export declare const REDACTION_POLICY_VERSION = "redaction/1";
2
+ export interface RedactionResult {
3
+ text: string;
4
+ replacements: number;
5
+ classes: Record<string, number>;
6
+ truncated: boolean;
7
+ quarantined: boolean;
8
+ }
9
+ export declare function redactText(value: string, options?: {
10
+ maxCharacters?: number;
11
+ denylist?: readonly string[];
12
+ }): RedactionResult;
@@ -0,0 +1,4 @@
1
+ export interface MemoryConfig {
2
+ databasePath: string;
3
+ }
4
+ export declare function resolveConfig(environment?: NodeJS.ProcessEnv): MemoryConfig;
@@ -0,0 +1 @@
1
+ export declare const MEMORY_GUIDANCE = "Use project-scoped memory for durable facts across sessions.\n- Start with project_list. Use the immutable projectID for stable references; projectName is a convenient unique lookup.\n- Create a project with project_create before storing its first note. Renaming a project never changes its ID.\n- Every memory_recall, memory_read, memory_update, memory_link, and memory_pin call must select exactly one project by projectID or projectName.\n- No notes are injected automatically; use memory_recall for relevant project history.\n- Read indexed note bodies and graph neighbors with memory_read.\n- Store only durable verified facts, decisions, procedures, research, preferences, or substantial completed work.\n- Use memory_pin to prioritize important matching notes inside their project. Pinning never moves notes between projects.\n- Never save transcripts, guesses, secrets, or routine progress.\n- project_delete permanently destroys the project and all of its memory. Call project_list first and provide the immutable ID, exact current name, and required confirmation phrase only when deletion is explicitly intended.";
@@ -0,0 +1,30 @@
1
+ import type { RetrievalBackend } from "./retrieval/contract";
2
+ import { type OpenedDB } from "./db";
3
+ import { CaptureStore } from "./store/capture";
4
+ import { MemoryStore } from "./store";
5
+ import { OutboxWorker } from "./store/outbox";
6
+ import { RetrievalStore } from "./store/retrieval";
7
+ export interface MemoryCoreOptions {
8
+ indexBackends?: readonly string[];
9
+ retrievalBackend?: RetrievalBackend;
10
+ outboxBackends?: ReadonlyMap<string, RetrievalBackend>;
11
+ }
12
+ export declare class MemoryCore {
13
+ private opened;
14
+ readonly memory: MemoryStore;
15
+ readonly capture: CaptureStore;
16
+ readonly retrieval: RetrievalStore;
17
+ readonly outbox?: OutboxWorker;
18
+ constructor(opened: OpenedDB, options?: MemoryCoreOptions);
19
+ close(): void;
20
+ }
21
+ export declare function openMemoryCore(databasePath: string, options?: MemoryCoreOptions): MemoryCore;
22
+ export * from "./capture/contract";
23
+ export * from "./capture/identity";
24
+ export * from "./capture/policy";
25
+ export * from "./capture/projection";
26
+ export * from "./capture/redact";
27
+ export * from "./retrieval/contract";
28
+ export * from "./retrieval/formatter";
29
+ export * from "./store/capture";
30
+ export * from "./types";
@@ -0,0 +1,25 @@
1
+ import { Database } from "bun:sqlite";
2
+ export declare const BACKUP_FORMAT: "opencode2-memory-backup/1";
3
+ export interface BackupManifest {
4
+ format: typeof BACKUP_FORMAT;
5
+ productVersion: string;
6
+ sourceSchema: number;
7
+ targetSchema: number;
8
+ createdAt: string;
9
+ sqliteVersion: string;
10
+ databaseFile: string;
11
+ sha256: string;
12
+ size: number;
13
+ counts: Record<string, number>;
14
+ integrity: "ok";
15
+ foreignKeyViolations: 0;
16
+ }
17
+ export interface VerifiedBackup {
18
+ databasePath: string;
19
+ manifestPath: string;
20
+ manifest: BackupManifest;
21
+ }
22
+ export declare function createVerifiedBackup(db: Database, databasePath: string, sourceSchema: number, targetSchema: number, productVersion: string): VerifiedBackup;
23
+ export declare function verifyBackupManifest(manifestPath: string): VerifiedBackup;
24
+ export declare function restoreVerifiedBackup(manifestPath: string, targetPath: string, confirmation: string): string;
25
+ export declare function inspectBackupDatabase(path: string): import("./health").DatabaseHealth;
@@ -0,0 +1,11 @@
1
+ import type { Database } from "bun:sqlite";
2
+ export interface DatabaseHealth {
3
+ integrity: string;
4
+ foreignKeyViolations: unknown[];
5
+ schemaVersion?: number;
6
+ counts: Record<string, number>;
7
+ }
8
+ export declare function inspectDatabase(db: Database): DatabaseHealth;
9
+ export declare function assertHealthyDatabase(db: Database): DatabaseHealth;
10
+ export declare function hasTable(db: Database, table: string): boolean;
11
+ export declare function hasColumn(db: Database, table: string, column: string): boolean;
@@ -0,0 +1,17 @@
1
+ export interface MigrationLockOwner {
2
+ ownerID: string;
3
+ pid: number;
4
+ processStartMarker: string;
5
+ hostname: string;
6
+ startedAt: number;
7
+ targetSchema: number;
8
+ }
9
+ export interface MigrationLock {
10
+ path: string;
11
+ owner: MigrationLockOwner;
12
+ release(): void;
13
+ }
14
+ export declare function migrationLockPath(databasePath: string): string;
15
+ export declare function acquireMigrationLock(databasePath: string, targetSchema: number, timeoutMs?: number): MigrationLock;
16
+ export declare function readMigrationLockOwner(path: string): MigrationLockOwner | undefined;
17
+ export declare function breakMigrationLock(databasePath: string, ownerID: string, confirmation: string): void;
@@ -0,0 +1,3 @@
1
+ import type { Database } from "bun:sqlite";
2
+ export declare function migrateV8ToV9(db: Database): void;
3
+ export declare function noteContentHash(kind: string, title: string, summary: string, content: string): string;
@@ -0,0 +1,5 @@
1
+ import type { Database } from "bun:sqlite";
2
+ export declare const SCHEMA_V9_TABLES = "\nCREATE TABLE IF NOT EXISTS projects (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n normalized_name TEXT NOT NULL UNIQUE,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL\n);\nCREATE TABLE IF NOT EXISTS notes (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n kind TEXT NOT NULL CHECK (kind IN ('decision','fact','procedure','context','research','preference','task')),\n title TEXT NOT NULL,\n summary TEXT NOT NULL,\n content TEXT NOT NULL,\n size_class TEXT NOT NULL CHECK (size_class IN ('inline','indexed')),\n pinned INTEGER NOT NULL DEFAULT 0 CHECK (pinned IN (0,1)),\n status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active','superseded','archived')),\n supersedes_id TEXT,\n current_revision INTEGER NOT NULL DEFAULT 1 CHECK (current_revision >= 1),\n subject_key TEXT,\n content_hash TEXT NOT NULL CHECK (length(content_hash) = 64),\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n UNIQUE(project_id, id)\n);\nCREATE INDEX IF NOT EXISTS notes_project_idx ON notes(project_id, status);\nCREATE UNIQUE INDEX IF NOT EXISTS notes_active_subject_idx\n ON notes(project_id, kind, subject_key)\n WHERE status = 'active' AND subject_key IS NOT NULL;\nCREATE TABLE IF NOT EXISTS note_edges (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n source_id TEXT NOT NULL,\n target_id TEXT NOT NULL,\n predicate TEXT NOT NULL CHECK (predicate IN ('SUPPORTS','DERIVED_FROM','PART_OF','ABOUT','PRECEDES','SUPERSEDES')),\n created_at INTEGER NOT NULL,\n UNIQUE(project_id, source_id, target_id, predicate),\n FOREIGN KEY (project_id, source_id) REFERENCES notes(project_id, id) ON DELETE CASCADE,\n FOREIGN KEY (project_id, target_id) REFERENCES notes(project_id, id) ON DELETE CASCADE\n);\nCREATE INDEX IF NOT EXISTS note_edges_source_idx ON note_edges(project_id, source_id);\nCREATE INDEX IF NOT EXISTS note_edges_target_idx ON note_edges(project_id, target_id);\nCREATE TABLE IF NOT EXISTS project_bindings (\n binding_key TEXT PRIMARY KEY,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n source TEXT NOT NULL CHECK (source = 'opencode-v2'),\n source_project_id TEXT NOT NULL,\n workspace_id TEXT NOT NULL,\n canonical_path_hash TEXT NOT NULL CHECK (length(canonical_path_hash) = 64),\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n UNIQUE(source, source_project_id, workspace_id)\n);\nCREATE TABLE IF NOT EXISTS capture_checkpoints (\n session_id TEXT PRIMARY KEY,\n binding_key TEXT NOT NULL REFERENCES project_bindings(binding_key) ON DELETE CASCADE,\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n state TEXT NOT NULL CHECK (state IN ('active','idle','unavailable','closed')),\n last_message_id TEXT,\n last_reconciled_at INTEGER,\n next_reconcile_at INTEGER NOT NULL,\n failure_count INTEGER NOT NULL DEFAULT 0 CHECK (failure_count >= 0),\n lease_owner TEXT,\n lease_expires_at INTEGER,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL\n);\nCREATE INDEX IF NOT EXISTS capture_checkpoints_due_idx\n ON capture_checkpoints(state, next_reconcile_at);\nCREATE TABLE IF NOT EXISTS capture_events (\n idempotency_key TEXT PRIMARY KEY,\n contract TEXT NOT NULL CHECK (contract = 'opencode2-memory.capture/1'),\n project_id TEXT NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n binding_key TEXT NOT NULL REFERENCES project_bindings(binding_key) ON DELETE CASCADE,\n event_kind TEXT NOT NULL CHECK (event_kind IN ('user-candidate','assistant-candidate','session-summary','tool-signal')),\n source_session_id TEXT NOT NULL,\n source_message_id TEXT,\n source_ordinal INTEGER CHECK (source_ordinal IS NULL OR source_ordinal >= 0),\n source_tool_call_id TEXT,\n payload_json TEXT CHECK (payload_json IS NULL OR json_valid(payload_json)),\n payload_hash TEXT,\n redaction_version TEXT NOT NULL,\n state TEXT NOT NULL CHECK (state IN ('pending','shadowed','review','materialized','duplicate','ignored','rejected','quarantined','failed','dead')),\n attempt_count INTEGER NOT NULL DEFAULT 0 CHECK (attempt_count >= 0),\n note_id TEXT,\n last_error_code TEXT,\n generation INTEGER NOT NULL DEFAULT 0 CHECK (generation >= 0),\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n processed_at INTEGER\n);\nCREATE INDEX IF NOT EXISTS capture_events_state_idx ON capture_events(state, updated_at);\nCREATE INDEX IF NOT EXISTS capture_events_session_idx ON capture_events(project_id, source_session_id);\nCREATE INDEX IF NOT EXISTS capture_events_note_idx ON capture_events(project_id, note_id);\nCREATE TABLE IF NOT EXISTS note_provenance (\n id TEXT PRIMARY KEY,\n project_id TEXT NOT NULL,\n note_id TEXT NOT NULL,\n source_type TEXT NOT NULL CHECK (source_type IN ('mcp-manual','opencode-capture','migration','legacy-import','admin')),\n capture_event_id TEXT,\n source_session_id TEXT,\n source_message_id TEXT,\n source_ordinal INTEGER,\n source_tool_call_id TEXT,\n redaction_version TEXT,\n extractor_version TEXT,\n confidence REAL CHECK (confidence IS NULL OR (confidence >= 0 AND confidence <= 1)),\n created_at INTEGER NOT NULL,\n UNIQUE(project_id, id),\n FOREIGN KEY (project_id, note_id) REFERENCES notes(project_id, id) ON DELETE CASCADE\n);\nCREATE TABLE IF NOT EXISTS note_revisions (\n project_id TEXT NOT NULL,\n note_id TEXT NOT NULL,\n revision INTEGER NOT NULL CHECK (revision >= 1),\n kind TEXT NOT NULL,\n title TEXT NOT NULL,\n summary TEXT NOT NULL,\n content TEXT NOT NULL,\n size_class TEXT NOT NULL,\n pinned INTEGER NOT NULL CHECK (pinned IN (0,1)),\n status TEXT NOT NULL CHECK (status IN ('active','superseded','archived')),\n supersedes_id TEXT,\n subject_key TEXT,\n content_hash TEXT NOT NULL,\n provenance_id TEXT NOT NULL,\n created_at INTEGER NOT NULL,\n PRIMARY KEY(project_id, note_id, revision),\n FOREIGN KEY (project_id, note_id) REFERENCES notes(project_id, id) ON DELETE CASCADE,\n FOREIGN KEY (project_id, provenance_id) REFERENCES note_provenance(project_id, id)\n);\nCREATE TABLE IF NOT EXISTS index_outbox (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n backend TEXT NOT NULL,\n operation TEXT NOT NULL CHECK (operation IN ('upsert-note','delete-note','purge-project')),\n project_id TEXT NOT NULL,\n note_id TEXT,\n revision INTEGER,\n content_hash TEXT,\n state TEXT NOT NULL DEFAULT 'pending' CHECK (state IN ('pending','leased','succeeded','dead')),\n attempt_count INTEGER NOT NULL DEFAULT 0 CHECK (attempt_count >= 0),\n available_at INTEGER NOT NULL,\n lease_owner TEXT,\n lease_expires_at INTEGER,\n last_error_code TEXT,\n created_at INTEGER NOT NULL,\n completed_at INTEGER,\n UNIQUE(backend, operation, project_id, note_id, revision)\n);\nCREATE INDEX IF NOT EXISTS index_outbox_due_idx\n ON index_outbox(backend, project_id, state, available_at, id);\nCREATE TABLE IF NOT EXISTS schema_state (version INTEGER PRIMARY KEY);\n";
3
+ export declare const FTS_V9 = "\nCREATE VIRTUAL TABLE IF NOT EXISTS notes_fts USING fts5(\n title, summary, content,\n content='notes', content_rowid='rowid',\n tokenize='unicode61'\n);\nCREATE TRIGGER IF NOT EXISTS notes_fts_ai AFTER INSERT ON notes BEGIN\n INSERT INTO notes_fts(rowid, title, summary, content)\n VALUES (new.rowid, new.title, new.summary, new.content);\nEND;\nCREATE TRIGGER IF NOT EXISTS notes_fts_ad AFTER DELETE ON notes BEGIN\n INSERT INTO notes_fts(notes_fts, rowid, title, summary, content)\n VALUES ('delete', old.rowid, old.title, old.summary, old.content);\nEND;\nCREATE TRIGGER IF NOT EXISTS notes_fts_au AFTER UPDATE OF title, summary, content ON notes BEGIN\n INSERT INTO notes_fts(notes_fts, rowid, title, summary, content)\n VALUES ('delete', old.rowid, old.title, old.summary, old.content);\n INSERT INTO notes_fts(rowid, title, summary, content)\n VALUES (new.rowid, new.title, new.summary, new.content);\nEND;\n";
4
+ export declare function createSchemaV9(db: Database): void;
5
+ export declare function rebuildFts(db: Database): void;
@@ -0,0 +1,6 @@
1
+ import { Database } from "bun:sqlite";
2
+ export interface OpenedDB {
3
+ db: Database;
4
+ close: () => void;
5
+ }
6
+ export declare function openMemoryDatabase(path: string): OpenedDB;
@@ -0,0 +1 @@
1
+ export declare function hashRoot(directory: string): string;
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env bun
2
+ export {};
@@ -0,0 +1,4 @@
1
+ export declare const MAX_PROJECT_NAME_LENGTH = 120;
2
+ export declare function cleanProjectName(value: string): string;
3
+ export declare function normalizeProjectName(value: string): string;
4
+ export declare function validateProjectName(value: string): string | undefined;
@@ -0,0 +1,9 @@
1
+ import type { BackendHealth, DerivedDocument, DerivedRef, RankedHit, RetrievalBackend } from "../contract";
2
+ export declare class NoneBackend implements RetrievalBackend {
3
+ readonly id = "none";
4
+ upsert(_document: DerivedDocument, _signal: AbortSignal): Promise<void>;
5
+ delete(_ref: DerivedRef, _signal: AbortSignal): Promise<void>;
6
+ purgeProject(_projectID: string, _signal: AbortSignal): Promise<void>;
7
+ query(_projectID: string, _query: string, _limit: number, _signal: AbortSignal): Promise<RankedHit[]>;
8
+ health(_signal: AbortSignal): Promise<BackendHealth>;
9
+ }
@@ -0,0 +1,42 @@
1
+ export interface RetrievalRequest {
2
+ projectID: string;
3
+ query: string;
4
+ limit: number;
5
+ deadlineAt: number;
6
+ semantic: "off" | "shadow" | "on";
7
+ }
8
+ export interface RankedHit {
9
+ noteID: string;
10
+ channel: "lexical" | "semantic" | "graph";
11
+ rank: number;
12
+ score?: number;
13
+ revision?: number;
14
+ contentHash?: string;
15
+ }
16
+ export interface DerivedDocument {
17
+ projectID: string;
18
+ noteID: string;
19
+ revision: number;
20
+ kind: string;
21
+ title: string;
22
+ summary: string;
23
+ content: string;
24
+ contentHash: string;
25
+ }
26
+ export interface DerivedRef {
27
+ projectID: string;
28
+ noteID: string;
29
+ }
30
+ export interface BackendHealth {
31
+ ok: boolean;
32
+ version?: string;
33
+ errorCode?: string;
34
+ }
35
+ export interface RetrievalBackend {
36
+ id: string;
37
+ upsert(document: DerivedDocument, signal: AbortSignal): Promise<void>;
38
+ delete(ref: DerivedRef, signal: AbortSignal): Promise<void>;
39
+ purgeProject(projectID: string, signal: AbortSignal): Promise<void>;
40
+ query(projectID: string, query: string, limit: number, signal: AbortSignal): Promise<RankedHit[]>;
41
+ health(signal: AbortSignal): Promise<BackendHealth>;
42
+ }
@@ -0,0 +1,11 @@
1
+ import type { DerivedDocument } from "./contract";
2
+ export interface CanonicalDocumentSource {
3
+ projectID: string;
4
+ noteID: string;
5
+ revision: number;
6
+ kind: string;
7
+ title: string;
8
+ summary: string;
9
+ content: string;
10
+ }
11
+ export declare function deriveDocument(source: CanonicalDocumentSource): DerivedDocument | undefined;
@@ -0,0 +1,5 @@
1
+ import type { RecallCard } from "../types";
2
+ export declare function formatUntrustedContext(projectID: string, cards: readonly RecallCard[], options?: {
3
+ maxCards?: number;
4
+ maxCharacters?: number;
5
+ }): string | undefined;
@@ -0,0 +1,8 @@
1
+ import type { RankedHit } from "./contract";
2
+ export interface FusedHit {
3
+ noteID: string;
4
+ score: number;
5
+ matchedCandidate: boolean;
6
+ channels: Set<RankedHit["channel"]>;
7
+ }
8
+ export declare function weightedReciprocalRankFusion(channels: readonly RankedHit[]): FusedHit[];
@@ -0,0 +1,5 @@
1
+ import { McpServer } from "@modelcontextprotocol/server";
2
+ import type { MemoryStore } from "./store";
3
+ export declare const SERVER_NAME = "agz-memory";
4
+ export declare const SERVER_VERSION = "0.4.0-beta.1";
5
+ export declare function createMemoryServer(store: MemoryStore): McpServer;
@@ -0,0 +1,46 @@
1
+ import type { Database } from "bun:sqlite";
2
+ export interface ProjectBindingInput {
3
+ memoryProjectID: string;
4
+ opencodeProjectID: string;
5
+ canonicalDirectory: string;
6
+ workspaceID?: string;
7
+ }
8
+ export type CaptureMode = "shadow" | "auto-write";
9
+ export interface CaptureIngestResult {
10
+ outcome: "shadowed" | "materialized" | "duplicate" | "ignored" | "review" | "rejected" | "quarantined";
11
+ idempotencyKey: string;
12
+ noteID?: string;
13
+ existing?: boolean;
14
+ }
15
+ export declare class CaptureStore {
16
+ private db;
17
+ private indexBackends;
18
+ constructor(db: Database, indexBackends?: readonly string[]);
19
+ bindProject(input: ProjectBindingInput): {
20
+ bindingKey: string;
21
+ projectID: string;
22
+ };
23
+ checkpoint(sessionID: string, bindingKey: string, projectID: string, messageID?: string, state?: "active" | "idle" | "unavailable" | "closed"): void;
24
+ markReconciled(sessionID: string, state: "active" | "idle" | "unavailable" | "closed", lastMessageID?: string, failed?: boolean): void;
25
+ getCheckpoint(sessionID: string): {
26
+ sessionID: string;
27
+ lastMessageID?: string;
28
+ state: "active" | "idle" | "unavailable" | "closed";
29
+ } | undefined;
30
+ ingest(input: unknown, mode: CaptureMode, options?: {
31
+ allowedKinds?: readonly string[];
32
+ minConfidence?: number;
33
+ denylist?: readonly string[];
34
+ }): CaptureIngestResult;
35
+ runRetention(now?: number, batchSize?: number): {
36
+ summarized: number;
37
+ deleted: number;
38
+ checkpoints: number;
39
+ };
40
+ private materialize;
41
+ private insertCapturedNote;
42
+ private recordRevision;
43
+ private enqueueOutbox;
44
+ private finishEvent;
45
+ private binding;
46
+ }
@@ -0,0 +1,14 @@
1
+ import type { Database } from "bun:sqlite";
2
+ import type { RetrievalBackend } from "../retrieval/contract";
3
+ export type OutboxOutcome = "idle" | "succeeded" | "stale" | "quarantined" | "retry" | "dead";
4
+ export declare class OutboxWorker {
5
+ private db;
6
+ private backends;
7
+ private now;
8
+ private random;
9
+ private readonly workerID;
10
+ constructor(db: Database, backends: ReadonlyMap<string, RetrievalBackend>, now?: () => number, random?: () => number);
11
+ processNext(): Promise<OutboxOutcome>;
12
+ private succeed;
13
+ private fail;
14
+ }
@@ -0,0 +1,18 @@
1
+ import type { Database } from "bun:sqlite";
2
+ import type { RetrievalBackend, RetrievalRequest } from "../retrieval/contract";
3
+ import type { RecallCard } from "../types";
4
+ export interface RetrievalResult {
5
+ cards: RecallCard[];
6
+ semanticFallback: boolean;
7
+ rejectedBackendHits: number;
8
+ }
9
+ export declare class RetrievalStore {
10
+ private db;
11
+ private backend?;
12
+ constructor(db: Database, backend?: RetrievalBackend | undefined);
13
+ retrieve(request: RetrievalRequest): Promise<RetrievalResult>;
14
+ private lexical;
15
+ private graph;
16
+ private graphPredicates;
17
+ private note;
18
+ }
@@ -0,0 +1,95 @@
1
+ import type { Database } from "bun:sqlite";
2
+ import type { Edge, Note, Project, ProjectSummary, RecallCard } from "./types";
3
+ export interface ProjectSelector {
4
+ projectID?: string;
5
+ projectName?: string;
6
+ }
7
+ export interface UpdateInput {
8
+ kind?: string;
9
+ title?: string;
10
+ summary?: string;
11
+ content?: string;
12
+ id?: string;
13
+ delete?: boolean;
14
+ }
15
+ export interface UpdateResult {
16
+ ok: boolean;
17
+ id?: string;
18
+ projectID?: string;
19
+ projectName?: string;
20
+ reason?: string;
21
+ sizeClass?: string;
22
+ deleted?: boolean;
23
+ }
24
+ export declare class MemoryStore {
25
+ private db;
26
+ private indexBackends;
27
+ constructor(db: Database, indexBackends?: readonly string[]);
28
+ resolveProject(selector: ProjectSelector): {
29
+ ok: boolean;
30
+ project?: Project;
31
+ reason?: string;
32
+ };
33
+ listProjects(): ProjectSummary[];
34
+ createProject(nameValue: string): {
35
+ ok: boolean;
36
+ project?: Project;
37
+ reason?: string;
38
+ };
39
+ updateProject(projectID: string, nameValue: string): {
40
+ ok: boolean;
41
+ project?: Project;
42
+ reason?: string;
43
+ };
44
+ deleteProject(projectID: string, confirmProjectName: string): {
45
+ ok: boolean;
46
+ deleted?: boolean;
47
+ projectID?: string;
48
+ projectName?: string;
49
+ deletedCounts?: {
50
+ notes: number;
51
+ edges: number;
52
+ pinned: number;
53
+ };
54
+ reason?: string;
55
+ };
56
+ update(projectID: string, input: UpdateInput): UpdateResult;
57
+ pin(projectID: string, id: string, pinned: boolean): {
58
+ ok: boolean;
59
+ reason: string;
60
+ id?: undefined;
61
+ projectID?: undefined;
62
+ projectName?: undefined;
63
+ pinned?: undefined;
64
+ } | {
65
+ reason?: undefined;
66
+ ok: boolean;
67
+ id: string;
68
+ projectID: string;
69
+ projectName: string;
70
+ pinned: boolean;
71
+ };
72
+ private insertNote;
73
+ read(projectID: string, id: string): {
74
+ note?: Note;
75
+ edges?: Edge[];
76
+ reason?: string;
77
+ };
78
+ link(projectID: string, sourceID: string, targetID: string, predicate: string): {
79
+ projectID?: undefined;
80
+ projectName?: undefined;
81
+ ok: boolean;
82
+ reason: string;
83
+ } | {
84
+ reason?: undefined;
85
+ ok: boolean;
86
+ projectID: string;
87
+ projectName: string;
88
+ };
89
+ recall(projectID: string, query: string, limit?: number): RecallCard[];
90
+ private getProjectRow;
91
+ private projectNameExists;
92
+ private getNoteRow;
93
+ private recordCurrentRevision;
94
+ private enqueueOutbox;
95
+ }
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/server";
2
+ import type { MemoryStore } from "./store";
3
+ export declare function registerTools(server: McpServer, store: MemoryStore): void;