@ponraaj/dimple-sdk 0.0.0-alpha.1 → 0.0.0-alpha.10

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 (43) hide show
  1. package/README.md +98 -0
  2. package/dist/dimple.d.ts +113 -5
  3. package/dist/errors.d.ts +24 -2
  4. package/dist/index.d.ts +3 -2
  5. package/dist/index.js +3055 -1524
  6. package/dist/indexer.d.ts +9 -0
  7. package/dist/internal/config/schema.d.ts +87 -0
  8. package/dist/internal/core/hosted-embedding.d.ts +33 -0
  9. package/dist/internal/embedder/auto-install.d.ts +10 -0
  10. package/dist/internal/embedder/index.d.ts +1 -2
  11. package/dist/internal/embedder/transformers.d.ts +40 -2
  12. package/dist/internal/extractor/models/extraction.d.ts +14 -0
  13. package/dist/internal/installer/index.d.ts +26 -0
  14. package/dist/internal/logger/index.d.ts +1 -1
  15. package/dist/internal/logger/service.d.ts +31 -12
  16. package/dist/internal/logger/types.d.ts +15 -3
  17. package/dist/internal/store/audit.d.ts +7 -1
  18. package/dist/internal/store/db-backend.d.ts +46 -8
  19. package/dist/internal/store/graph/candidates.d.ts +3 -1
  20. package/dist/internal/store/graph/concepts.d.ts +14 -5
  21. package/dist/internal/store/graph/dream.d.ts +7 -1
  22. package/dist/internal/store/graph/repair.d.ts +7 -1
  23. package/dist/internal/store/graph/traversal.d.ts +1 -1
  24. package/dist/internal/store/index.d.ts +1 -0
  25. package/dist/internal/store/models.d.ts +4 -3
  26. package/dist/internal/store/schema/graph.d.ts +7 -7
  27. package/dist/internal/store/schema/libsql.d.ts +4 -4
  28. package/dist/internal/store/schema/metadata.d.ts +4 -1
  29. package/dist/internal/store/service.d.ts +83 -4
  30. package/dist/internal/store/topics/jobs.d.ts +7 -1
  31. package/dist/internal/store/topics/lifecycle.d.ts +7 -1
  32. package/dist/internal/store/topics/maintenance.d.ts +8 -2
  33. package/dist/internal/store/topics/routing.d.ts +33 -0
  34. package/dist/internal/store/topics/topic-vectors.d.ts +10 -3
  35. package/dist/internal/store/topics/tree.d.ts +15 -9
  36. package/dist/internal/workflow/executor.d.ts +1 -1
  37. package/dist/internal/workflow/persistence.d.ts +1 -1
  38. package/dist/internal/workflow/queue.d.ts +6 -3
  39. package/dist/internal/workflow/registry.d.ts +1 -1
  40. package/dist/internal/workflow/signals.d.ts +21 -0
  41. package/dist/make.d.ts +27 -0
  42. package/package.json +12 -4
  43. package/dist/internal/embedder/openai.d.ts +0 -8
package/README.md ADDED
@@ -0,0 +1,98 @@
1
+ # @ponraaj/dimple-sdk
2
+
3
+ A local-first memory system for AI agents: store text memories and whole
4
+ codebases, retrieve them with hybrid semantic + lexical search, and let a
5
+ self-organizing **topic tree + artifact graph + concepts** keep everything
6
+ structured as it grows. Everything runs locally — ONNX embeddings on your
7
+ CPU, SQLite files on disk.
8
+
9
+ > **Documentation**: [dimple.ponraaj.me](https://dimple.ponraaj.me) —
10
+ > quickstart, architecture, config reference, changelog ·
11
+ > **Package**: [npmx.dev/package/@ponraaj/dimple](https://npmx.dev/package/@ponraaj/dimple) ·
12
+ > **Status**: alpha (`0.0.0-alpha.n`) — the API is stabilizing.
13
+
14
+ This is the programmatic SDK. The [`@ponraaj/dimple`](https://npmx.dev/package/@ponraaj/dimple)
15
+ CLI is a thin facade over it.
16
+
17
+ ## Install
18
+
19
+ ```bash
20
+ npm install @ponraaj/dimple-sdk
21
+ ```
22
+
23
+ Runtime deps only (Effect, libSQL, transformers) — workspace internals are
24
+ bundled, types are self-contained, and the default install ships **zero
25
+ postinstall scripts** (the local ONNX embedder is an optional peer,
26
+ auto-installed on first use).
27
+
28
+ ## Quickstart
29
+
30
+ ```ts
31
+ import { makeDimple } from "@ponraaj/dimple-sdk"; // ← makeDimple, not dimple
32
+
33
+ const dimple = await makeDimple({ config: "./dimple.jsonc" });
34
+
35
+ // write a memory (embeds + topic-routes it)
36
+ const mem = await dimple.write({
37
+ logicalKey: "deploy-1",
38
+ content: "the deploy pipeline runs on every push",
39
+ });
40
+
41
+ // hybrid semantic + FTS search
42
+ const hits = await dimple.query("how does the pipeline deploy", { limit: 3 });
43
+
44
+ // index a codebase (tree-sitter: one unit per file + per definition)
45
+ await dimple.index({ paths: ["./src"] });
46
+
47
+ await dimple.dispose(); // required before process.exit — the durable worker
48
+ ```
49
+
50
+ Calling conventions: **plain arguments** (`query(text, opts)`,
51
+ `write(input, opts)`, `index({ paths })`); every failure is a rejected
52
+ promise with a closed `_tag` (`"Sdk.NotFound"`, `"Sdk.InputError"`, …);
53
+ `dispose()` is idempotent.
54
+
55
+ ## API surface
56
+
57
+ | Method | What it does |
58
+ | --------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
59
+ | `write(input, { embed })` | Store a memory (idempotent per `logicalKey`) |
60
+ | `writeMany(units, { embed })` | Bulk ingest: batch insert + batch embed + routing in one pass (skips the per-write candidate scan — quadratic under bulk; run the dream job afterwards for graph edges) |
61
+ | `get(id)` / `forget(id)` | Fetch / remove by id or logical key |
62
+ | `query(text, options)` | Hybrid search — profiles, budgets, content-type filter |
63
+ | `updateEmbedding(id, vec, modelKey?)` | Attach an external embedding |
64
+ | `index({ paths })` | Codebase ingestion (idempotent re-index) |
65
+ | `graph.addEdge/confirm/reject/expire/candidates/coverage` | Memory relationships: supports / supersedes / contradicts |
66
+ | `explain({ kind, id }, options)` | Bounded graph neighborhood |
67
+ | `dream(modelKey?)` / `repair(modelKey?)` | Consolidation + maintenance jobs |
68
+ | `health(modelKey?)` | Topic-tree invariant health |
69
+ | `reload(input?)` | Blue-green config reload |
70
+
71
+ Errors are a closed hierarchy (`InputError`, `NotFound`, `DuplicateKey`,
72
+ `JobFailed`, `LLMNotConfigured`, `StoreFailure`) — see the docs site.
73
+
74
+ ## Configuration
75
+
76
+ `makeDimple({ config: "./dimple.jsonc" })` — every section is optional
77
+ except `embedding`. `dimple init` (CLI) writes the full annotated schema;
78
+ `${ENV_VAR}` placeholders keep tokens out of files. The complete reference
79
+ (store / jobs / embeddings / topics / graph / llm / logging / Turso) is on
80
+ the docs site: [Configuration reference](https://dimple.ponraaj.me/reference/config/).
81
+
82
+ ## MCP server
83
+
84
+ `dimple mcp` (from the CLI package) exposes dimple to any MCP client over
85
+ the 2026-07-28 protocol — API discovery plus sandboxed code execution with
86
+ the whole API as a `dimple` namespace. Guide:
87
+ [MCP server & code mode](https://dimple.ponraaj.me/guides/mcp/).
88
+
89
+ ## Agent integration patterns
90
+
91
+ Session-start injection, the supersedes recipe, and namespaces as the
92
+ code/message partition are covered in the Architecture section of the
93
+ docs site.
94
+
95
+ ## Changelog
96
+
97
+ [Release history](https://dimple.ponraaj.me/changelog/sdk/) · repository
98
+ [`CHANGELOG.md`](./CHANGELOG.md)
package/dist/dimple.d.ts CHANGED
@@ -1,9 +1,11 @@
1
- import { ManagedRuntime } from "effect";
1
+ import { Effect } from "effect";
2
2
  import type { QueryProfile } from "./internal/retriever/index.js";
3
3
  import type { CoreInterface } from "./internal/core/index.js";
4
4
  import type { CodeExtractor } from "./internal/extractor/index.js";
5
5
  import type { CodeParser } from "./internal/parser/index.js";
6
- import type { AddEdgeInput, AugmentedMemory, ExplainResult, GraphCandidatesResult, GraphCoverage, MemoryUnit, TopicHealth, WriteMemoryInput } from "./internal/store/index.js";
6
+ import type { DimpleConfig } from "./internal/config/index.js";
7
+ import type { AddEdgeInput, ArtifactEdge, AugmentedMemory, ExplainResult, GraphCandidatesResult, GraphCoverage, MemoryUnit, TopicHealth, WriteMemoryInput } from "./internal/store/index.js";
8
+ import type { ConfigInput } from "./config.ts";
7
9
  import { type DimpleError } from "./errors.ts";
8
10
  /** Options for a `query` call — mirrors the hybrid retriever's options. */
9
11
  export interface QueryOptions {
@@ -16,6 +18,23 @@ export interface QueryOptions {
16
18
  readonly topics?: {
17
19
  readonly topicKeys?: ReadonlyArray<string>;
18
20
  };
21
+ /** Content-type filter: one kind or a list (e.g. `"text/x-typescript"`
22
+ * or `["text/plain", "text/markdown"]`) — the code-vs-message
23
+ * separation lever at query time. */
24
+ readonly contentType?: string | readonly string[];
25
+ /** Include the 384-float embedding on result memories (default false —
26
+ * search results never need vectors; the opt-in exists for callers that
27
+ * do post-processing with them). */
28
+ readonly includeEmbedding?: boolean;
29
+ /** Retrieval context budget (LLM-facing guardrail): `maxUnits` caps the
30
+ * row count, `maxChars` truncates result content to fit the total char
31
+ * budget, `maxMs` marks the result truncated when the query exceeds it.
32
+ * Truncation is surfaced as `results.truncated` on the returned array. */
33
+ readonly budget?: {
34
+ readonly maxUnits?: number;
35
+ readonly maxChars?: number;
36
+ readonly maxMs?: number;
37
+ };
19
38
  }
20
39
  /** Options for a `write` call. */
21
40
  export interface WriteOptions {
@@ -49,23 +68,65 @@ export interface IndexResult {
49
68
  readonly files: number;
50
69
  /** Memory units written (file unit + extracted chunks). */
51
70
  readonly indexed: number;
52
- /** Units skipped as already-indexed (duplicate logical keys). */
71
+ /** Units whose active copy changed content — the old unit was
72
+ * superseded (confirmed `memory_supersedes` edge) and the new unit
73
+ * written under the same key. */
74
+ readonly updated: number;
75
+ /** Units whose source vanished from disk (deleted/moved file or
76
+ * definition) — demoted to superseded (`source_removed`); they no
77
+ * longer match queries. */
78
+ readonly reconciled: number;
79
+ /** The repo HEAD at index time (null outside a git tree) — stamped into
80
+ * every file/chunk unit's metadata as `codeVersion`. */
81
+ /** Units skipped as already-indexed (unchanged content under the same
82
+ * logical key). */
53
83
  readonly skipped: number;
54
84
  /** Files skipped because the extension is not indexable. */
55
85
  readonly unsupported: number;
86
+ readonly commit: string | null;
56
87
  /** Files that could not be walked/read/parsed/extracted/written. */
57
88
  readonly failed: readonly {
58
89
  readonly filePath: string;
59
90
  readonly message: string;
60
91
  }[];
61
92
  }
93
+ /** What a `reload` actually changed — so callers can react (alert, log,
94
+ * refuse) instead of guessing. */
95
+ export interface ReloadChanges {
96
+ /** The store database URL changed — the new db was bootstrapped (empty
97
+ * schema); the old db file is preserved on disk but no longer served.
98
+ * Nothing is migrated or merged. */
99
+ readonly storeUrl: boolean;
100
+ /** The jobs database URL changed — pending jobs stay durable in the
101
+ * old db (re-claimable by switching back or draining it externally). */
102
+ readonly jobsUrl: boolean;
103
+ /** Any other section changed (models, topics, graph, logging, …). */
104
+ readonly rest: boolean;
105
+ }
106
+ /** Result of a `reload`. */
107
+ export interface ReloadResult {
108
+ readonly config: DimpleConfig;
109
+ readonly changed: ReloadChanges;
110
+ /** `false` when the resolved config was identical to the live one —
111
+ * nothing was paused, booted, or restarted (safe for watchers). */
112
+ readonly reloaded: boolean;
113
+ }
62
114
  /**
63
115
  * The promise-based SDK facade — the ONLY surface app code touches.
64
116
  * Every method runs the underlying Effect at the boundary, remaps errors
65
117
  * onto the closed `DimpleError` hierarchy, and never leaks Effect types.
66
118
  */
67
119
  export interface Dimple {
120
+ /** The config-default embedding model's key — what `dream`/`repair`/
121
+ * `stats` use when no model is passed. */
122
+ readonly defaultModelId: string;
68
123
  readonly write: (input: WriteMemoryInput, options?: WriteOptions) => Promise<MemoryUnit>;
124
+ /** Bulk write: batch insert + batch embed + topic routing in ONE pass.
125
+ * Skips the per-write graph candidate scan (O(leaf size) per write —
126
+ * quadratic under bulk ingest); callers that need near-duplicate/
127
+ * conflict edges on bulk content should run the dream job afterwards.
128
+ * All-or-nothing: a duplicate logical key rejects the whole batch. */
129
+ readonly writeMany: (units: readonly WriteMemoryInput[], options?: WriteOptions) => Promise<readonly MemoryUnit[]>;
69
130
  readonly get: (id: string) => Promise<MemoryUnit>;
70
131
  readonly query: (text: string, options?: QueryOptions) => Promise<AugmentedMemory[]>;
71
132
  readonly forget: (id: string) => Promise<void>;
@@ -83,19 +144,66 @@ export interface Dimple {
83
144
  readonly embed: (text: string) => Promise<number[]>;
84
145
  readonly dream: (modelKey: string) => Promise<void>;
85
146
  readonly repair: (modelKey: string) => Promise<void>;
147
+ /** The store's tables + columns (snake_case DB names — the SDK exposes
148
+ * camelCase domain names; `dimple db-schema` prints this map). */
149
+ readonly dbSchema: () => Promise<ReadonlyArray<{
150
+ readonly table: string;
151
+ readonly columns: ReadonlyArray<{
152
+ readonly name: string;
153
+ readonly type: string;
154
+ }>;
155
+ }>>;
156
+ /** Options for `explain` — pass `edgeKinds` for a scoped answer (the
157
+ * common ask is memory-only navigation: the three `memory_*` kinds keep
158
+ * the topic/concept legs out). */
86
159
  readonly explain: (input: {
87
160
  readonly kind: "memory" | "topic" | "concept";
88
161
  readonly id: string;
162
+ }, options?: {
163
+ readonly edgeKinds?: readonly string[];
164
+ readonly maxDepth?: number;
165
+ readonly maxNeighbors?: number;
166
+ readonly maxTotal?: number;
167
+ readonly includePending?: boolean;
89
168
  }) => Promise<ExplainResult>;
90
169
  readonly health: (modelKey: string) => Promise<TopicHealth>;
91
170
  readonly graph: {
92
- readonly addEdge: (input: AddEdgeInput) => Promise<unknown>;
171
+ readonly addEdge: (input: AddEdgeInput) => Promise<ArtifactEdge>;
93
172
  readonly candidates: () => Promise<GraphCandidatesResult>;
94
173
  readonly coverage: (modelKey: string) => Promise<GraphCoverage>;
174
+ /** Promote a pending edge to confirmed (for `memory_supersedes` the
175
+ * old endpoint flips to superseded in the same transaction). */
176
+ readonly confirm: (id: string) => Promise<void>;
177
+ /** Reject a pending edge (removed from the pending review set). */
178
+ readonly reject: (id: string) => Promise<void>;
179
+ /** Soft-delete an edge (`expired_at` set; excluded from traversal). */
180
+ readonly expire: (id: string) => Promise<void>;
95
181
  };
182
+ /**
183
+ * Apply a config change: pause (new calls wait, in-flight calls settle),
184
+ * boot a fresh stack with the re-resolved config, and swap it in.
185
+ *
186
+ * With no argument the ORIGINAL config source is re-resolved — a
187
+ * `dimple.jsonc` FILE PATH is re-read from disk, an inline object is
188
+ * re-validated. A config that fails validation or boot rejects the
189
+ * reload and leaves the current system untouched. An identical config
190
+ * resolves as `{ reloaded: false }` — no pause, no restart.
191
+ */
192
+ readonly reload: (input?: ConfigInput) => Promise<ReloadResult>;
96
193
  /** Stops the worker, closes the sinks and the store — idempotent. */
97
194
  readonly dispose: () => Promise<void>;
98
195
  }
196
+ /**
197
+ * The live handles the facade reads at call time. `makeDimple` swaps the
198
+ * stack under this state on `reload`, so methods always hit the stack that
199
+ * is current when they run.
200
+ */
201
+ export interface FacadeState {
202
+ readonly run: <A, E>(effect: Effect.Effect<A, E>) => Promise<A>;
203
+ readonly core: () => CoreInterface;
204
+ readonly parser: () => CodeParser["Service"];
205
+ readonly extractor: () => CodeExtractor["Service"];
206
+ }
99
207
  /** Build the promise facade over the booted core + runtime. */
100
- export declare const makeFacade: <ER>(runtime: ManagedRuntime.ManagedRuntime<never, ER>, core: CoreInterface, parser: CodeParser["Service"], extractor: CodeExtractor["Service"], dispose: () => Promise<void>) => Dimple;
208
+ export declare const makeFacade: (state: FacadeState, reload: (input?: ConfigInput) => Promise<ReloadResult>, dispose: () => Promise<void>) => Dimple;
101
209
  export type { DimpleError };
package/dist/errors.d.ts CHANGED
@@ -45,19 +45,41 @@ declare const DuplicateEdgeError_base: Schema.Class<DuplicateEdgeError, Schema.T
45
45
  /** A duplicate memory↔memory edge (same from/to/kind already exists). */
46
46
  export declare class DuplicateEdgeError extends DuplicateEdgeError_base {
47
47
  }
48
+ declare const EdgeNotFoundError_base: Schema.Class<EdgeNotFoundError, Schema.TaggedStruct<"Sdk.EdgeNotFound", {
49
+ readonly id: Schema.optional<Schema.String>;
50
+ readonly message: Schema.String;
51
+ }>, import("effect/Cause").YieldableError>;
52
+ /** The edge does not exist (confirm/reject/expire on a stale id). */
53
+ export declare class EdgeNotFoundError extends EdgeNotFoundError_base {
54
+ }
48
55
  declare const StoreFailure_base: Schema.Class<StoreFailure, Schema.TaggedStruct<"Sdk.StoreFailure", {
49
56
  readonly message: Schema.String;
50
57
  }>, import("effect/Cause").YieldableError>;
51
58
  /** Anything else — the typed fallback that keeps the union closed. */
52
59
  export declare class StoreFailure extends StoreFailure_base {
53
60
  }
61
+ declare const ReloadError_base: Schema.Class<ReloadError, Schema.TaggedStruct<"Sdk.Reload", {
62
+ readonly message: Schema.String;
63
+ }>, import("effect/Cause").YieldableError>;
64
+ /** `reload` was unavailable (no config source, disposed) or failed to
65
+ * drain in-flight calls before the swap. */
66
+ export declare class ReloadError extends ReloadError_base {
67
+ }
68
+ declare const EmbeddingFailure_base: Schema.Class<EmbeddingFailure, Schema.TaggedStruct<"Sdk.Embedding", {
69
+ readonly message: Schema.String;
70
+ }>, import("effect/Cause").YieldableError>;
71
+ /** Embedding pipeline failure — the `@huggingface/transformers` package is
72
+ * missing (local embeddings), the model failed to load, or the output
73
+ * dimensions mismatch the config. */
74
+ export declare class EmbeddingFailure extends EmbeddingFailure_base {
75
+ }
54
76
  declare const InputError_base: Schema.Class<InputError, Schema.TaggedStruct<"Sdk.InputError", {
55
77
  readonly message: Schema.String;
56
78
  }>, import("effect/Cause").YieldableError>;
57
79
  /** Invalid SDK call input (bad `limit`, `k`, profile shape, …). */
58
80
  export declare class InputError extends InputError_base {
59
81
  }
60
- export type DimpleError = ConfigError | NotFoundError | DuplicateKeyError | DuplicateEdgeError | LLMNotConfiguredError | JobFailedError | StoreFailure | InputError;
82
+ export type DimpleError = ConfigError | NotFoundError | DuplicateKeyError | DuplicateEdgeError | EdgeNotFoundError | LLMNotConfiguredError | EmbeddingFailure | JobFailedError | StoreFailure | ReloadError | InputError;
61
83
  /** Map an underlying failure onto the closed SDK hierarchy. */
62
- export declare const remapError: (error: unknown) => DimpleError;
84
+ export declare const remapError: (cause: unknown) => DimpleError;
63
85
  export {};
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export { makeDimple, type MakeDimpleOptions } from "./make.ts";
2
2
  export { type ConfigInput } from "./config.ts";
3
- export { type Dimple, type QueryOptions, type IndexOptions, type IndexResult } from "./dimple.ts";
4
- export { ConfigError, NotFoundError, DuplicateKeyError, DuplicateEdgeError, LLMNotConfiguredError, JobFailedError, StoreFailure, InputError, remapError, type DimpleError, } from "./errors.ts";
3
+ export type { DimpleConfig } from "./internal/config/index.js";
4
+ export { type Dimple, type QueryOptions, type IndexOptions, type IndexResult, type ReloadChanges, type ReloadResult, } from "./dimple.ts";
5
+ export { ConfigError, NotFoundError, DuplicateKeyError, DuplicateEdgeError, EdgeNotFoundError, LLMNotConfiguredError, JobFailedError, StoreFailure, ReloadError, EmbeddingFailure, InputError, remapError, type DimpleError, } from "./errors.ts";