@avantf/dsh-mem 0.3.1 → 0.4.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.
Files changed (144) hide show
  1. package/README.md +89 -28
  2. package/cordis.patch.yml +17 -0
  3. package/lib/client.js +155 -14
  4. package/lib/engine/mem/config/config_files.d.ts +26 -0
  5. package/lib/engine/mem/config/domains.d.ts +20 -0
  6. package/lib/engine/mem/config/loader.d.ts +35 -0
  7. package/lib/engine/mem/config/paths.d.ts +53 -0
  8. package/lib/engine/mem/db/chunk.d.ts +26 -0
  9. package/lib/engine/mem/db/conn.d.ts +13 -0
  10. package/lib/engine/mem/db/dao/chunks.d.ts +150 -0
  11. package/lib/engine/mem/db/dao/contradictions.d.ts +98 -0
  12. package/lib/engine/mem/db/dao/documents.d.ts +51 -0
  13. package/lib/engine/mem/db/dao/entities.d.ts +67 -0
  14. package/lib/engine/mem/db/dao/facts.d.ts +472 -0
  15. package/lib/engine/mem/db/dao/stats.d.ts +14 -0
  16. package/lib/engine/mem/db/dao/triples.d.ts +80 -0
  17. package/lib/engine/mem/db/hash.d.ts +2 -0
  18. package/lib/engine/mem/db/knowledge.d.ts +17 -0
  19. package/lib/engine/mem/db/migrations.d.ts +71 -0
  20. package/lib/engine/mem/db/port.d.ts +57 -0
  21. package/lib/engine/mem/db/schema.d.ts +26 -0
  22. package/lib/engine/mem/db/sqlite.d.ts +89 -0
  23. package/lib/engine/mem/db/store.d.ts +35 -0
  24. package/lib/engine/mem/db/tokenizer.d.ts +61 -0
  25. package/lib/engine/mem/db/vectors.d.ts +50 -0
  26. package/lib/engine/mem/dispatch.d.ts +51 -0
  27. package/lib/engine/mem/entities/extract.d.ts +84 -0
  28. package/lib/engine/mem/eval/loader.d.ts +19 -0
  29. package/lib/engine/mem/eval/metrics.d.ts +25 -0
  30. package/lib/engine/mem/eval/runner.d.ts +10 -0
  31. package/lib/engine/mem/eval/write_metrics.d.ts +88 -0
  32. package/lib/engine/mem/git.d.ts +73 -0
  33. package/lib/engine/mem/hrr/algebra.d.ts +30 -0
  34. package/lib/engine/mem/hrr/atoms.d.ts +22 -0
  35. package/lib/engine/mem/hrr/encode.d.ts +32 -0
  36. package/lib/engine/mem/hrr/index.d.ts +3 -0
  37. package/lib/engine/mem/index.d.ts +27 -0
  38. package/lib/engine/mem/lifecycle/contradiction.d.ts +156 -0
  39. package/lib/engine/mem/lifecycle/index.d.ts +5 -0
  40. package/lib/engine/mem/lifecycle/maintenance.d.ts +48 -0
  41. package/lib/engine/mem/lifecycle/presence.d.ts +29 -0
  42. package/lib/engine/mem/lifecycle/tick.d.ts +43 -0
  43. package/lib/engine/mem/lifecycle/trust.d.ts +90 -0
  44. package/lib/engine/mem/modelBootstrap.d.ts +207 -0
  45. package/lib/engine/mem/router.d.ts +51 -0
  46. package/lib/engine/mem/runtime.d.ts +232 -0
  47. package/lib/engine/mem/store/common.d.ts +82 -0
  48. package/lib/engine/mem/store/doc_files.d.ts +125 -0
  49. package/lib/engine/mem/store/document_text.d.ts +47 -0
  50. package/lib/engine/mem/store/floors.d.ts +191 -0
  51. package/lib/engine/mem/store/hybrid.d.ts +232 -0
  52. package/lib/engine/mem/store/ingest_guard.d.ts +25 -0
  53. package/lib/engine/mem/store/knowledge.d.ts +483 -0
  54. package/lib/engine/mem/store/lexical.d.ts +67 -0
  55. package/lib/engine/mem/store/memory.d.ts +543 -0
  56. package/lib/engine/mem/store/source_picker.d.ts +43 -0
  57. package/lib/engine/mem-contract/config.d.ts +129 -0
  58. package/lib/engine/mem-contract/env.d.ts +31 -0
  59. package/lib/engine/mem-contract/family.d.ts +25 -0
  60. package/lib/engine/mem-contract/index.d.ts +8 -0
  61. package/lib/engine/mem-contract/log.d.ts +29 -0
  62. package/lib/engine/mem-contract/remote.d.ts +80 -0
  63. package/lib/engine/mem-contract/text.d.ts +92 -0
  64. package/lib/engine/mem-contract/tools.d.ts +284 -0
  65. package/lib/engine/mem-contract/types.d.ts +615 -0
  66. package/lib/engine/mem-retrieval/adapters/auto_vstore.d.ts +47 -0
  67. package/lib/engine/mem-retrieval/adapters/hnswlib.d.ts +174 -0
  68. package/lib/engine/mem-retrieval/adapters/local_bge.d.ts +121 -0
  69. package/lib/engine/mem-retrieval/adapters/local_numpy.d.ts +28 -0
  70. package/lib/engine/mem-retrieval/adapters/local_reranker.d.ts +52 -0
  71. package/lib/engine/mem-retrieval/adapters/none_reranker.d.ts +10 -0
  72. package/lib/engine/mem-retrieval/adapters/warm_gate.d.ts +46 -0
  73. package/lib/engine/mem-retrieval/budget.d.ts +30 -0
  74. package/lib/engine/mem-retrieval/fusion.d.ts +53 -0
  75. package/lib/engine/mem-retrieval/index.d.ts +14 -0
  76. package/lib/engine/mem-retrieval/interfaces.d.ts +82 -0
  77. package/lib/engine/mem-retrieval/log.d.ts +11 -0
  78. package/lib/engine/mem-retrieval/registry.d.ts +23 -0
  79. package/lib/engine/mem-retrieval/rerank.d.ts +13 -0
  80. package/lib/engine/mem-retrieval/stats.d.ts +64 -0
  81. package/lib/engine/mem-retrieval/text_budget.d.ts +52 -0
  82. package/lib/index.js +1773 -473
  83. package/lib/interface-version.json +2 -2
  84. package/lib/types/client/domains.d.ts +5 -4
  85. package/lib/types/client/domains.d.ts.map +1 -1
  86. package/lib/types/client/index.d.ts.map +1 -1
  87. package/lib/types/client/ingest.d.ts +1 -1
  88. package/lib/types/client/wire.d.ts +36 -0
  89. package/lib/types/client/wire.d.ts.map +1 -0
  90. package/lib/types/envinit-bootstrap.d.ts +3 -2
  91. package/lib/types/envinit.d.ts +2 -19
  92. package/lib/types/envinit.d.ts.map +1 -1
  93. package/lib/types/hints.d.ts +1 -1
  94. package/lib/types/index.d.ts +8 -3
  95. package/lib/types/index.d.ts.map +1 -1
  96. package/lib/types/open.d.ts +61 -11
  97. package/lib/types/open.d.ts.map +1 -1
  98. package/lib/types/prompt.d.ts +19 -1
  99. package/lib/types/prompt.d.ts.map +1 -1
  100. package/lib/types/provision.d.ts +1 -1
  101. package/lib/types/provision.d.ts.map +1 -1
  102. package/lib/types/reconcile.d.ts +64 -0
  103. package/lib/types/reconcile.d.ts.map +1 -0
  104. package/lib/types/remote.d.ts +53 -0
  105. package/lib/types/remote.d.ts.map +1 -1
  106. package/lib/types/render.d.ts +35 -0
  107. package/lib/types/render.d.ts.map +1 -0
  108. package/lib/types/tool_schema.d.ts +3 -13
  109. package/lib/types/tool_schema.d.ts.map +1 -1
  110. package/package.json +24 -15
  111. package/lib/client.js.map +0 -1
  112. package/lib/types/client/domains.js +0 -25
  113. package/lib/types/client/domains.js.map +0 -1
  114. package/lib/types/client/index.js +0 -1371
  115. package/lib/types/client/index.js.map +0 -1
  116. package/lib/types/client/ingest.js +0 -30
  117. package/lib/types/client/ingest.js.map +0 -1
  118. package/lib/types/client/paging.js +0 -36
  119. package/lib/types/client/paging.js.map +0 -1
  120. package/lib/types/client/summarize.js +0 -79
  121. package/lib/types/client/summarize.js.map +0 -1
  122. package/lib/types/data_home.js +0 -26
  123. package/lib/types/data_home.js.map +0 -1
  124. package/lib/types/envinit-bootstrap.js +0 -333
  125. package/lib/types/envinit.js +0 -402
  126. package/lib/types/envinit.js.map +0 -1
  127. package/lib/types/hints.js +0 -53
  128. package/lib/types/hints.js.map +0 -1
  129. package/lib/types/index.js +0 -755
  130. package/lib/types/index.js.map +0 -1
  131. package/lib/types/inject.js +0 -14
  132. package/lib/types/inject.js.map +0 -1
  133. package/lib/types/interface_gate.js +0 -84
  134. package/lib/types/interface_gate.js.map +0 -1
  135. package/lib/types/open.js +0 -133
  136. package/lib/types/open.js.map +0 -1
  137. package/lib/types/prompt.js +0 -148
  138. package/lib/types/prompt.js.map +0 -1
  139. package/lib/types/provision.js +0 -177
  140. package/lib/types/provision.js.map +0 -1
  141. package/lib/types/remote.js +0 -247
  142. package/lib/types/remote.js.map +0 -1
  143. package/lib/types/tool_schema.js +0 -149
  144. package/lib/types/tool_schema.js.map +0 -1
@@ -0,0 +1,129 @@
1
+ import { z } from 'zod';
2
+ /**
3
+ * Input window of the SHIPPED models: `Xenova/bge-small-zh-v1.5` (embedder) and
4
+ * `Xenova/bge-reranker-base` (reranker) both read 512 tokens.
5
+ *
6
+ * Exported because more than one default derives from it: the embedder's fallback window, the
7
+ * reranker's pair budget (retrieval-core), and `knowledge.chunk_size` below. transformers.js
8
+ * truncates past the window SILENTLY, so every derivation has to agree on the number.
9
+ */
10
+ export declare const DEFAULT_MODEL_WINDOW_TOKENS = 512;
11
+ /** The merged runtime config shared by memory and knowledge stores. */
12
+ export declare const ConfigSchema: z.ZodObject<{
13
+ dataHome: z.ZodDefault<z.ZodString>;
14
+ semantic: z.ZodPrefault<z.ZodObject<{
15
+ backend: z.ZodDefault<z.ZodString>;
16
+ local_model: z.ZodDefault<z.ZodString>;
17
+ dim: z.ZodDefault<z.ZodNumber>;
18
+ max_input_tokens: z.ZodDefault<z.ZodNumber>;
19
+ mirror: z.ZodDefault<z.ZodString>;
20
+ cache_dir: z.ZodDefault<z.ZodString>;
21
+ auto_download: z.ZodDefault<z.ZodBoolean>;
22
+ }, z.core.$strip>>;
23
+ rerank: z.ZodPrefault<z.ZodObject<{
24
+ backend: z.ZodDefault<z.ZodString>;
25
+ local_model: z.ZodDefault<z.ZodString>;
26
+ max_input_tokens: z.ZodDefault<z.ZodNumber>;
27
+ mirror: z.ZodDefault<z.ZodString>;
28
+ cache_dir: z.ZodDefault<z.ZodString>;
29
+ auto_download: z.ZodDefault<z.ZodBoolean>;
30
+ }, z.core.$strip>>;
31
+ vectorStore: z.ZodPrefault<z.ZodObject<{
32
+ backend: z.ZodDefault<z.ZodString>;
33
+ auto_thresholds: z.ZodDefault<z.ZodObject<{
34
+ hnswlib: z.ZodDefault<z.ZodNumber>;
35
+ }, z.core.$strip>>;
36
+ hnswlib_ef_search: z.ZodDefault<z.ZodNumber>;
37
+ }, z.core.$strip>>;
38
+ retriever: z.ZodPrefault<z.ZodObject<{
39
+ weight_semantic: z.ZodDefault<z.ZodNumber>;
40
+ weight_fts: z.ZodDefault<z.ZodNumber>;
41
+ weight_jaccard: z.ZodDefault<z.ZodNumber>;
42
+ max_output_tokens: z.ZodDefault<z.ZodNumber>;
43
+ over_fetch_factor: z.ZodDefault<z.ZodNumber>;
44
+ min_semantic_similarity: z.ZodDefault<z.ZodNumber>;
45
+ min_fts_terms: z.ZodDefault<z.ZodNumber>;
46
+ min_jaccard: z.ZodDefault<z.ZodNumber>;
47
+ leg_cap: z.ZodDefault<z.ZodNumber>;
48
+ }, z.core.$strip>>;
49
+ lifecycle: z.ZodPrefault<z.ZodObject<{
50
+ purge_after_archived_days: z.ZodDefault<z.ZodNumber>;
51
+ contradiction_threshold: z.ZodDefault<z.ZodNumber>;
52
+ }, z.core.$strip>>;
53
+ trust: z.ZodPrefault<z.ZodObject<{
54
+ enabled: z.ZodDefault<z.ZodBoolean>;
55
+ start: z.ZodDefault<z.ZodNumber>;
56
+ decay_per_day: z.ZodDefault<z.ZodNumber>;
57
+ forget_threshold: z.ZodDefault<z.ZodNumber>;
58
+ permanent_threshold: z.ZodDefault<z.ZodNumber>;
59
+ recall_floor: z.ZodDefault<z.ZodNumber>;
60
+ recall_delta: z.ZodDefault<z.ZodNumber>;
61
+ recall_daily_cap: z.ZodDefault<z.ZodNumber>;
62
+ recall_marginal_decay: z.ZodDefault<z.ZodNumber>;
63
+ recall_ceiling: z.ZodDefault<z.ZodNumber>;
64
+ feedback_delta: z.ZodDefault<z.ZodNumber>;
65
+ feedback_daily_cap: z.ZodDefault<z.ZodNumber>;
66
+ inherit_trust_on_update: z.ZodDefault<z.ZodBoolean>;
67
+ purge_skips_pinned: z.ZodDefault<z.ZodBoolean>;
68
+ idle_calendar_days: z.ZodDefault<z.ZodNumber>;
69
+ tick_max_facts: z.ZodDefault<z.ZodNumber>;
70
+ presence: z.ZodPrefault<z.ZodObject<{
71
+ mode: z.ZodDefault<z.ZodEnum<{
72
+ process: "process";
73
+ }>>;
74
+ gap_cap_days: z.ZodDefault<z.ZodNumber>;
75
+ heartbeat_minutes: z.ZodDefault<z.ZodNumber>;
76
+ }, z.core.$strip>>;
77
+ }, z.core.$strip>>;
78
+ tools: z.ZodPrefault<z.ZodObject<{
79
+ dir: z.ZodDefault<z.ZodString>;
80
+ mirror: z.ZodDefault<z.ZodArray<z.ZodString>>;
81
+ auto_install: z.ZodDefault<z.ZodBoolean>;
82
+ }, z.core.$strip>>;
83
+ }, z.core.$strip>;
84
+ export type Config = z.infer<typeof ConfigSchema>;
85
+ /** Built-in defaults — the lowest precedence layer. */
86
+ export declare const defaultConfig: Config;
87
+ /**
88
+ * Memory store-specific config. Overrides on top of the common Config.
89
+ * Note: `db.path` is the single authoritative path for the memory DB.
90
+ */
91
+ export declare const MemoryConfigSchema: z.ZodObject<{
92
+ db: z.ZodPrefault<z.ZodObject<{
93
+ path: z.ZodDefault<z.ZodString>;
94
+ }, z.core.$strip>>;
95
+ }, z.core.$strip>;
96
+ export type MemoryConfig = z.infer<typeof MemoryConfigSchema>;
97
+ /** Knowledge store-specific config. */
98
+ export declare const KnowledgeConfigSchema: z.ZodObject<{
99
+ db: z.ZodPrefault<z.ZodObject<{
100
+ path: z.ZodDefault<z.ZodString>;
101
+ }, z.core.$strip>>;
102
+ docs: z.ZodPrefault<z.ZodObject<{
103
+ dir: z.ZodDefault<z.ZodString>;
104
+ }, z.core.$strip>>;
105
+ git: z.ZodPrefault<z.ZodObject<{
106
+ mode: z.ZodDefault<z.ZodEnum<{
107
+ auto: "auto";
108
+ off: "off";
109
+ }>>;
110
+ root: z.ZodDefault<z.ZodString>;
111
+ ignore: z.ZodDefault<z.ZodArray<z.ZodString>>;
112
+ }, z.core.$strip>>;
113
+ open: z.ZodPrefault<z.ZodObject<{
114
+ editor: z.ZodDefault<z.ZodString>;
115
+ }, z.core.$strip>>;
116
+ domains: z.ZodDefault<z.ZodArray<z.ZodString>>;
117
+ chunk_size: z.ZodDefault<z.ZodNumber>;
118
+ chunk_overlap: z.ZodDefault<z.ZodNumber>;
119
+ source_priority: z.ZodDefault<z.ZodEnum<{
120
+ none: "none";
121
+ workspace: "workspace";
122
+ }>>;
123
+ ingest: z.ZodPrefault<z.ZodObject<{
124
+ local_roots: z.ZodDefault<z.ZodArray<z.ZodString>>;
125
+ allow_outside_workspace: z.ZodDefault<z.ZodBoolean>;
126
+ allow_private_network: z.ZodDefault<z.ZodBoolean>;
127
+ }, z.core.$strip>>;
128
+ }, z.core.$strip>;
129
+ export type KnowledgeConfig = z.infer<typeof KnowledgeConfigSchema>;
@@ -0,0 +1,31 @@
1
+ /** Expand `~/…` (and a BARE `~`) against the USER home directory.
2
+ *
3
+ * The bare form matters: `AVANTF_HOME=~` used to come back verbatim, i.e. as the RELATIVE path `~`,
4
+ * and everything built on it was written into the current working directory. The base kit's own
5
+ * `expandHome` always expanded it, so the two copies disagreed on exactly the input a shell makes
6
+ * easy to type. */
7
+ export declare function expandHome(p: string): string;
8
+ /** Parse a boolean env var: `0`/`false` → false, unset/empty → undefined, else true. */
9
+ export declare function envFlag(name: string): boolean | undefined;
10
+ /**
11
+ * The global model-download kill switch.
12
+ *
13
+ * TWO switches, either of which turns downloads off:
14
+ *
15
+ * - `AVANTF_MEM_AUTO_DOWNLOAD` — this project's switch (CLI, MCP server, tests);
16
+ * - `AVANTF_ENVINIT_AUTO_DOWNLOAD` — the family framework's switch, a MASTER gate: the operator
17
+ * turns the whole family's provisioning off in one place, so the engine must stop fetching too
18
+ * (otherwise the framework skips its item while the runtime silently downloads the same model).
19
+ *
20
+ * Deliberately honored in the config loader (env layer ④, so `rt.config` reflects reality) and in
21
+ * the model adapters themselves, so even a directly constructed backend (tests, third-party
22
+ * embedders) can never reach the network. As an ops/test kill switch it intentionally overrides the
23
+ * configured/passed `autoDownload`.
24
+ *
25
+ * Three-valued on purpose: either switch `0`/`false` → `false`; the project switch `1`/`true` →
26
+ * `true`; otherwise (including the family switch merely being `1`, which only means "the family did
27
+ * not disable anything") → `undefined`, so the configured value stands. The family switch is a
28
+ * master GATE, not a force-on: it must be able to stop the runtime, never to override
29
+ * `semantic.auto_download: false`.
30
+ */
31
+ export declare function envAutoDownload(): boolean | undefined;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * The family root and the two managed directories under it — ONE definition of a convention that
3
+ * four packages would otherwise each spell out.
4
+ *
5
+ * `@avantf/dsh-plugin-base` (the family's environment framework) installs everything it manages under a
6
+ * single root: `$AVANTF_HOME` when set, else `~/.avantf/env`. `tools` holds external binaries
7
+ * (pandoc), `models` the downloaded embedding/rerank weights in the flat layout the transformers.js
8
+ * cache reads. The engine's built-in defaults point HERE, not at the pre-framework
9
+ * `~/.avantf/{tools,models}`: those legacy directories are no longer a fallback anywhere, so a
10
+ * machine that never creates them loses nothing, and no process resolves a path that only missions
11
+ * because somebody left a compatibility symlink behind.
12
+ *
13
+ * `provision` mirrors {@link familyHome} (it is deliberately dependency-free, so it cannot import
14
+ * this module); `packages/core/test/family_paths.spec.ts` pins the two copies together so the
15
+ * convention cannot drift.
16
+ *
17
+ * The `~/` expansion is NOT a private copy any more: this module and `env.ts` used to carry two
18
+ * literally identical `expandTilde`/`expandHome` bodies in the same package, and only the exported
19
+ * one was pinned — so the un-pinned copy could drift silently. It now calls {@link expandHome}.
20
+ */
21
+ export declare function familyHome(env?: Record<string, string | undefined>): string;
22
+ /** The managed external-binary root (`<family root>/tools`). */
23
+ export declare function familyToolsDir(env?: Record<string, string | undefined>): string;
24
+ /** The managed model-cache root (`<family root>/models`). */
25
+ export declare function familyModelsDir(env?: Record<string, string | undefined>): string;
@@ -0,0 +1,8 @@
1
+ export * from './types.js';
2
+ export * from './config.js';
3
+ export * from './family.js';
4
+ export * from './tools.js';
5
+ export * from './remote.js';
6
+ export * from './log.js';
7
+ export * from './env.js';
8
+ export * from './text.js';
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Minimal leveled logger shared by the engine, the retrieval core, and the DSH
3
+ * plugin. The plugin injects the host `ctx.logger` facade so every line lands in
4
+ * the DSH host output; standalone runs (CLI / MCP / tests) fall back to console.
5
+ *
6
+ * The console fallback writes to STDERR on purpose: the CLI and the MCP server
7
+ * own stdout for JSON / JSON-RPC, so logs must never share that stream.
8
+ */
9
+ /** One leveled log sink. */
10
+ export interface AvantfLogger {
11
+ info(message: string): void;
12
+ warn(message: string): void;
13
+ error(message: string): void;
14
+ }
15
+ /** Build a stderr-backed logger with a stable `[avantf-mem]` prefix. */
16
+ export declare function createConsoleLogger(prefix?: string): AvantfLogger;
17
+ /** The default console logger used whenever no host logger is supplied. */
18
+ export declare const defaultLogger: AvantfLogger;
19
+ /**
20
+ * Flatten an error and its `cause` chain into one log-safe line.
21
+ *
22
+ * Node's `fetch` (undici) reports any failed request as a bare
23
+ * `TypeError: fetch failed` and puts the actionable detail — DNS failure,
24
+ * connect timeout, TLS error — plus the `UND_ERR_*` code on `error.cause`.
25
+ * Logging `message` alone therefore hides *why* a model download failed: a
26
+ * poisoned DNS entry and a dead mirror both read as "fetch failed". Every
27
+ * adapter / bootstrap log goes through this helper so the cause survives.
28
+ */
29
+ export declare function describeError(error: unknown): string;
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Transport-shape helpers shared by the DSH Remote host gateway (@avantf/dsh-mem)
3
+ * and its client pages.
4
+ *
5
+ * There are TWO nested envelopes on the client↔host Remote path:
6
+ *
7
+ * 1. the **transport** envelope, added by DSH itself: every `@Remote` method call
8
+ * resolves to `{ok:true, value:<host method return>}` (or `{ok:false, error}`
9
+ * on a carrier/host failure) — see the harness Typert client
10
+ * (`packages/api/gateway/src/client/index.ts`). The host method must NOT add
11
+ * this layer itself.
12
+ * 2. the **application** envelope this plugin's gateway returns deliberately, so
13
+ * the settings pages can show contract-validation violations instead of a raw
14
+ * exception: `{ok:true, value}` / `{ok:false, error, violations}`.
15
+ *
16
+ * `unwrapRemoteEnvelope` peels both, in order, and also tolerates a bare payload
17
+ * (a gateway that returns raw values, or a future protocol change), so the pages
18
+ * never render an envelope as if it were data.
19
+ *
20
+ * The application envelope also carries the **wire revision** (`wire`, optional): the host stamps
21
+ * the revision of the Remote FACE it publishes onto every answer (see `@avantf/dsh-mem`'s
22
+ * `remote.ts` `WIRE_VERSION`), and the client half reads it back to tell a rebuilt browser bundle
23
+ * from the host process that `dsh web` loaded before it. It rides the envelope rather than one
24
+ * method's payload because this plugin has no single entry point — each tab makes its own first
25
+ * call — while the envelope is the one object every answer shares. Absent means "a host older
26
+ * than the marker": still readable, but the client may not assume a method it knows about exists.
27
+ */
28
+ /** Successful application result. */
29
+ export interface RemoteOk<T> {
30
+ ok: true;
31
+ value: T;
32
+ /** The publisher's wire revision, when it reports one (see the module doc). */
33
+ wire?: number;
34
+ }
35
+ /** Failed application result (validation violations are optional). */
36
+ export interface RemoteErr {
37
+ ok: false;
38
+ error: string;
39
+ violations?: string[];
40
+ /** The publisher's wire revision, when it reports one (see the module doc). */
41
+ wire?: number;
42
+ }
43
+ export type RemoteEnvelope<T> = RemoteOk<T> | RemoteErr;
44
+ /** Best-effort human-readable text for any error carrier (string, Error, object). */
45
+ export declare function remoteErrorText(error: unknown): string;
46
+ /**
47
+ * Decode one Remote call result into the application envelope.
48
+ *
49
+ * @param result - whatever the client transport resolved with.
50
+ * @returns the application payload, or the application error + violations.
51
+ */
52
+ export declare function unwrapRemoteEnvelope<T>(result: unknown): RemoteEnvelope<T>;
53
+ /** Render a violation list for display (used by the settings pages). */
54
+ export declare function formatViolations(violations: string[] | undefined): string;
55
+ /**
56
+ * The envelope every AGENT-facing tool result uses, on BOTH surfaces: the DSH
57
+ * `defineTool` tools (`@avantf/dsh-mem`) and the standalone MCP server
58
+ * (`@avantf/mem-mcp`). Keeping one shape means a model/consumer sees the same
59
+ * response whether it talks to the plugin or to the MCP process.
60
+ *
61
+ * Note the deliberate difference from {@link RemoteEnvelope}: the payload key is
62
+ * `result` (tools) vs `value` (settings-page Remote calls).
63
+ */
64
+ export type ToolEnvelope<T> = {
65
+ ok: true;
66
+ result: T;
67
+ } | {
68
+ ok: false;
69
+ error: string;
70
+ violations?: string[];
71
+ };
72
+ /** Wrap a successful tool payload (a null/undefined payload becomes explicit null). */
73
+ export declare function toolOk<T>(result: T): ToolEnvelope<T | null>;
74
+ /** Wrap a failed tool call (message + optional contract violations). */
75
+ export declare function toolErr(error: unknown, violations?: string[]): ToolEnvelope<never>;
76
+ /** Contract-validation failure message shared by both tool surfaces. */
77
+ export declare function validationError(toolName: string, issues: readonly {
78
+ path: PropertyKey[];
79
+ message: string;
80
+ }[]): ToolEnvelope<never>;
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Well-formedness of every string mem stores or shows a model — the mem-side MIRROR.
3
+ *
4
+ * The defect this module exists for is ONE shape: a lone surrogate — a UTF-16 code unit in the
5
+ * `D800–DFFF` range with no partner. A string carrying one is not a valid Unicode scalar sequence,
6
+ * and `JSON.stringify` happily emits it as the escape `"\ud800"`: JavaScript's own `JSON.parse`
7
+ * accepts that, so the defect passes every check inside this repository, while a strict parser
8
+ * (Rust's `serde_json`, JSON Schema validators, most non-JS consumers) rejects the whole document.
9
+ * The same half-code-unit also poisons FTS, embeddings and the UI. `String.prototype.toWellFormed`
10
+ * (Node ≥20, present in this repo's Node ≥22.15) replaces each lone surrogate with U+FFFD, which is
11
+ * exactly the repair wanted.
12
+ *
13
+ * ── THE ORIGINAL IS THE BASE KIT ──────────────────────────────────────────────────────────────
14
+ *
15
+ * `base/plugin-base/src/kit/wellformed.ts` owns `wellFormedText` / `wellFormedDeep` (interface v2)
16
+ * and is the copy ONE base release fixes for the whole family. This module is its **deliberate
17
+ * mirror**, in the same sense as `./family.ts` (whose original is the base's `kit/family.ts`): the
18
+ * engine (`@avantf/mem`) and the CLI / MCP faces have **no DSH host and never load the base**
19
+ * (`AGENTS.md`), so they cannot reach the original and keep a dependency-free copy as their
20
+ * documented degradation path. The cross-tree test
21
+ * `mem/packages/plugin/test/wellformed_pin.spec.ts` takes the REAL linked base and compares it with
22
+ * this mirror on one set of samples (the precedent is `family_pin.spec.ts`); **do not change one
23
+ * side without the other**.
24
+ *
25
+ * ── WHO RUNS: the base when a host installed it, the mirror otherwise ─────────────────────────
26
+ *
27
+ * This module is also the ONE place the DSH plugin can hand the base's implementation in:
28
+ * {@link adoptWellFormed} takes the module the bootstrap loaded and swaps the two functions for the
29
+ * base's, falling back per member when it does not carry them. The switch is deliberately
30
+ * **"does the loaded module HAVE the function"** (a `typeof` read of each member, guarded against a
31
+ * hostile getter) — never an interface-generation check, so a base that predates the v2 helpers
32
+ * (generation v1) simply keeps the mirror and the plugin still mounts completely. Nothing here can
33
+ * throw or refuse a mount.
34
+ *
35
+ * Two directions, two functions, deliberately NOT one:
36
+ *
37
+ * - {@link toWellFormedText} is the WRITE side. It additionally applies `normalize('NFC')`, because
38
+ * Unicode equivalence is a persistence concern: two spellings of the same text must not become
39
+ * two rows, two FTS terms or two entities. Every store write and every derived string (entity
40
+ * names, SPO slots) goes through it BEFORE it is persisted. **NFC is mem's policy, not the
41
+ * well-formed layer's**: the base's `wellFormedText` does NOT normalize, and when it is adopted
42
+ * the write wrapper here is exactly `base.wellFormedText(value).normalize('NFC')`.
43
+ * - {@link toWellFormedDeep} is the READ side. It never changes anything except lone surrogates,
44
+ * and it walks the result value so that data this process did not just write — a row written by
45
+ * an older build or a foreign driver, a string the tokenizer derived — still serializes to JSON
46
+ * every strict parser accepts. Applying NFC here would silently rewrite history for display, so
47
+ * it does not.
48
+ *
49
+ * @module contract/text
50
+ */
51
+ /**
52
+ * The ONE write-side normalization: well-formed, and NFC.
53
+ *
54
+ * Called at the store write entries (never at each individual string field), so a fix here lands
55
+ * everywhere at once.
56
+ */
57
+ export declare function toWellFormedText(value: string): string;
58
+ /** {@link toWellFormedText} over a batch (entity names, caller paths, …). */
59
+ export declare function toWellFormedTexts(values: readonly string[]): string[];
60
+ /**
61
+ * The read-side twin: a structurally identical value in which every string is well-formed.
62
+ *
63
+ * Delegates to {@link repairDeep}: the local {@link mirrorDeep} until a host installs the base's
64
+ * `wellFormedDeep` through {@link adoptWellFormed}, which is the same walk (see the module note).
65
+ */
66
+ export declare function toWellFormedDeep<T>(value: T): T;
67
+ /** The slice of a loaded base {@link adoptWellFormed} reads; both members are optional. */
68
+ export interface WellFormedKit {
69
+ readonly wellFormedText?: unknown;
70
+ readonly wellFormedDeep?: unknown;
71
+ }
72
+ /** Which of the two repairs came from the kit (`false` = the mirror is in force for it). */
73
+ export interface WellFormedSource {
74
+ readonly text: boolean;
75
+ readonly deep: boolean;
76
+ }
77
+ /**
78
+ * Prefer the loaded base's well-formed helpers; fall back to this mirror for whatever it lacks.
79
+ *
80
+ * The plugin calls this ONCE at mount with the module the bootstrap loaded (`env?.kit`). The
81
+ * decision per member is a `typeof` check — the v2 members are an OPTIONAL capability, and a base
82
+ * that predates them (interface v1) or a module with none of them leaves both repairs on the mirror.
83
+ * It is total: a hostile module reads as "reports none", nothing throws, and a mount is never
84
+ * refused or changed by the outcome.
85
+ *
86
+ * Calling it AGAIN replaces whatever was installed before, so passing `undefined` restores the
87
+ * mirror (the CLI / MCP faces never call it at all and keep the mirror for their whole life).
88
+ *
89
+ * @param kit - the loaded base module (or anything else; only the two members are read).
90
+ * @returns which repair each side came from, for the caller's log line.
91
+ */
92
+ export declare function adoptWellFormed(kit: unknown): WellFormedSource;