@remnic/core 9.3.624 → 9.3.625

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 (261) hide show
  1. package/dist/access-cli.js +18 -16
  2. package/dist/access-cli.js.map +1 -1
  3. package/dist/access-http.d.ts +12 -5
  4. package/dist/access-http.js +10 -9
  5. package/dist/access-mcp.d.ts +5 -5
  6. package/dist/access-mcp.js +8 -8
  7. package/dist/access-schema.d.ts +5 -5
  8. package/dist/{access-service-CBNEKjzN.d.ts → access-service-C_sfOHsX.d.ts} +26 -3
  9. package/dist/access-service.d.ts +5 -5
  10. package/dist/access-service.js +7 -7
  11. package/dist/action-confidence.d.ts +1 -1
  12. package/dist/active-memory-bridge.d.ts +1 -1
  13. package/dist/active-recall.d.ts +1 -1
  14. package/dist/active-recall.js +2 -1
  15. package/dist/active-recall.js.map +1 -1
  16. package/dist/behavior-learner.d.ts +1 -1
  17. package/dist/behavior-signals.d.ts +1 -1
  18. package/dist/bootstrap.d.ts +4 -4
  19. package/dist/briefing.d.ts +1 -1
  20. package/dist/briefing.js +3 -3
  21. package/dist/buffer-surprise-report.d.ts +1 -1
  22. package/dist/buffer.d.ts +1 -1
  23. package/dist/calibration.d.ts +1 -1
  24. package/dist/causal-behavior.d.ts +1 -1
  25. package/dist/causal-consolidation.d.ts +1 -1
  26. package/dist/causal-consolidation.js +4 -4
  27. package/dist/{chunk-7TPH6UZL.js → chunk-2RHI3FGV.js} +540 -17
  28. package/dist/chunk-2RHI3FGV.js.map +1 -0
  29. package/dist/{chunk-GYTVOLNX.js → chunk-3MNBW7R7.js} +2 -2
  30. package/dist/{chunk-QFQQFX2H.js → chunk-3R2UZV3U.js} +2 -2
  31. package/dist/{chunk-O4UNM6OR.js → chunk-532VCWYW.js} +2 -2
  32. package/dist/{chunk-2UFQYU5F.js → chunk-57QXN2CS.js} +2 -2
  33. package/dist/chunk-7WV3F5DQ.js +22 -0
  34. package/dist/chunk-7WV3F5DQ.js.map +1 -0
  35. package/dist/{chunk-RKW6QR7W.js → chunk-AZ4RI3QD.js} +1461 -78
  36. package/dist/chunk-AZ4RI3QD.js.map +1 -0
  37. package/dist/{chunk-KQFQ3IS5.js → chunk-F3FY3D3S.js} +43 -7
  38. package/dist/chunk-F3FY3D3S.js.map +1 -0
  39. package/dist/{chunk-4R4KTDIE.js → chunk-FPNQF475.js} +1 -1
  40. package/dist/chunk-FPNQF475.js.map +1 -0
  41. package/dist/{chunk-UGEBPVNI.js → chunk-GE7Q7KXP.js} +2 -2
  42. package/dist/{chunk-GLWW3EJQ.js → chunk-KB4MFBF5.js} +3 -3
  43. package/dist/{chunk-5GOMXHLC.js → chunk-KKTXCFD7.js} +255 -1
  44. package/dist/chunk-KKTXCFD7.js.map +1 -0
  45. package/dist/{chunk-FH3PPO42.js → chunk-KVFYTRMV.js} +2 -2
  46. package/dist/{chunk-BNW5NJJH.js → chunk-LQYTQCXM.js} +2 -2
  47. package/dist/{chunk-AYHXQR53.js → chunk-MVQN73GT.js} +2 -2
  48. package/dist/{chunk-ZZPIJPPD.js → chunk-N5RGXWLQ.js} +2 -2
  49. package/dist/chunk-NDAH7BJ5.js +213 -0
  50. package/dist/chunk-NDAH7BJ5.js.map +1 -0
  51. package/dist/{chunk-R3OQGYOU.js → chunk-P2D2MM47.js} +2 -2
  52. package/dist/{chunk-PSUB67YB.js → chunk-PW6GURU3.js} +2 -2
  53. package/dist/{chunk-W3BKVM64.js → chunk-QDV6VAD4.js} +2 -2
  54. package/dist/{chunk-3QSU4NFF.js → chunk-QHXW3LZV.js} +3 -3
  55. package/dist/{chunk-I6UCUHLK.js → chunk-SHV5Y2WU.js} +182 -3
  56. package/dist/chunk-SHV5Y2WU.js.map +1 -0
  57. package/dist/{chunk-OZXVGYGZ.js → chunk-STDAAGH7.js} +2 -2
  58. package/dist/{chunk-FMGWXIES.js → chunk-TZDSNIRO.js} +5 -5
  59. package/dist/{chunk-2L54V4ZO.js → chunk-UELS6WWF.js} +2 -2
  60. package/dist/{chunk-PJGB7XRR.js → chunk-UGHUNQ74.js} +502 -134
  61. package/dist/chunk-UGHUNQ74.js.map +1 -0
  62. package/dist/{chunk-FG76RDVI.js → chunk-Y3TMFC6I.js} +136 -4
  63. package/dist/chunk-Y3TMFC6I.js.map +1 -0
  64. package/dist/{chunk-BPSGLMQ4.js → chunk-YQNADJCT.js} +2 -2
  65. package/dist/{cli-Cw729yLf.d.ts → cli-EZv6YE6_.d.ts} +3 -3
  66. package/dist/cli.d.ts +6 -6
  67. package/dist/cli.js +23 -21
  68. package/dist/compounding/engine.d.ts +1 -1
  69. package/dist/compounding/engine.js +3 -3
  70. package/dist/compounding/preference-consolidator.d.ts +1 -1
  71. package/dist/compression-optimizer.d.ts +1 -1
  72. package/dist/config.d.ts +1 -1
  73. package/dist/config.js +2 -1
  74. package/dist/connectors/codex-materialize-runner.d.ts +1 -1
  75. package/dist/connectors/codex-materialize-runner.js +3 -3
  76. package/dist/connectors/codex-materialize.d.ts +1 -1
  77. package/dist/connectors/index.d.ts +1 -1
  78. package/dist/connectors/index.js +3 -3
  79. package/dist/consolidation-provenance-check.d.ts +1 -1
  80. package/dist/consolidation-undo.d.ts +1 -1
  81. package/dist/contradiction/index.d.ts +2 -2
  82. package/dist/conversation-index/backend.d.ts +1 -1
  83. package/dist/conversation-index/chunker.d.ts +1 -1
  84. package/dist/conversation-index/faiss-adapter.d.ts +1 -1
  85. package/dist/conversation-index/indexer.d.ts +1 -1
  86. package/dist/conversation-index/search.d.ts +1 -1
  87. package/dist/day-summary.d.ts +1 -1
  88. package/dist/delinearize.d.ts +1 -1
  89. package/dist/direct-answer-wiring.d.ts +1 -1
  90. package/dist/direct-answer.d.ts +1 -1
  91. package/dist/embedding-fallback.d.ts +1 -1
  92. package/dist/enrichment/index.d.ts +1 -1
  93. package/dist/entity-retrieval.d.ts +1 -1
  94. package/dist/entity-retrieval.js +3 -3
  95. package/dist/entity-schema.d.ts +1 -1
  96. package/dist/explicit-capture.d.ts +4 -4
  97. package/dist/extraction-judge-telemetry.d.ts +1 -1
  98. package/dist/extraction-judge-training.d.ts +1 -1
  99. package/dist/extraction-judge.d.ts +1 -1
  100. package/dist/extraction.d.ts +1 -1
  101. package/dist/fallback-llm.d.ts +1 -1
  102. package/dist/identity-continuity.d.ts +1 -1
  103. package/dist/importance.d.ts +1 -1
  104. package/dist/index.d.ts +307 -9
  105. package/dist/index.js +155 -29
  106. package/dist/index.js.map +1 -1
  107. package/dist/intent.d.ts +1 -1
  108. package/dist/lcm/engine.d.ts +1 -1
  109. package/dist/lcm/index.d.ts +1 -1
  110. package/dist/lcm/tools.d.ts +1 -1
  111. package/dist/lifecycle.d.ts +1 -1
  112. package/dist/live-connectors-runner.d.ts +1 -1
  113. package/dist/local-llm.d.ts +1 -1
  114. package/dist/maintenance/memory-governance.d.ts +1 -1
  115. package/dist/maintenance/memory-governance.js +3 -3
  116. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
  117. package/dist/maintenance/rebuild-memory-projection.js +4 -4
  118. package/dist/mcp-memory-inspector-app.d.ts +5 -5
  119. package/dist/memory-action-policy.d.ts +1 -1
  120. package/dist/memory-cache.d.ts +1 -1
  121. package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
  122. package/dist/memory-projection-store.d.ts +1 -1
  123. package/dist/memory-provenance.d.ts +1 -1
  124. package/dist/memory-worth-outcomes.d.ts +1 -1
  125. package/dist/models-json.d.ts +1 -1
  126. package/dist/namespaces/migrate.d.ts +1 -1
  127. package/dist/namespaces/migrate.js +4 -4
  128. package/dist/namespaces/principal.d.ts +1 -1
  129. package/dist/namespaces/search.d.ts +1 -1
  130. package/dist/namespaces/storage.d.ts +1 -1
  131. package/dist/namespaces/storage.js +3 -3
  132. package/dist/native-knowledge.d.ts +1 -1
  133. package/dist/operator-toolkit.d.ts +1 -1
  134. package/dist/operator-toolkit.js +8 -7
  135. package/dist/{orchestrator-CqWOjfgl.d.ts → orchestrator-CEycaY3M.d.ts} +361 -4
  136. package/dist/orchestrator.d.ts +4 -4
  137. package/dist/orchestrator.js +13 -11
  138. package/dist/patterns-cli.d.ts +1 -1
  139. package/dist/policy-runtime.d.ts +1 -1
  140. package/dist/qmd-recall-cache.d.ts +1 -1
  141. package/dist/qmd.d.ts +1 -1
  142. package/dist/recall-disclosure-escalation.d.ts +1 -1
  143. package/dist/recall-explain-renderer.d.ts +1 -1
  144. package/dist/recall-explain-renderer.js +3 -3
  145. package/dist/recall-planner-llm.d.ts +1 -1
  146. package/dist/recall-state.d.ts +1 -1
  147. package/dist/recall-tag-filter.d.ts +1 -1
  148. package/dist/recall-xray-cli.d.ts +1 -1
  149. package/dist/recall-xray-cli.js +4 -4
  150. package/dist/recall-xray-renderer.d.ts +1 -1
  151. package/dist/recall-xray-renderer.js +3 -3
  152. package/dist/recall-xray.d.ts +1 -1
  153. package/dist/recall-xray.js +2 -2
  154. package/dist/resolve-auth-token.d.ts +1 -1
  155. package/dist/resume-bundles.js +3 -2
  156. package/dist/retrieval-agents.d.ts +1 -1
  157. package/dist/retrieval-tiers.d.ts +1 -1
  158. package/dist/routing/engine.d.ts +1 -1
  159. package/dist/routing/store.d.ts +1 -1
  160. package/dist/schemas.d.ts +10 -10
  161. package/dist/search/embed-helper.d.ts +1 -1
  162. package/dist/search/factory.d.ts +1 -1
  163. package/dist/search/index.d.ts +1 -1
  164. package/dist/search/lancedb-backend.d.ts +1 -1
  165. package/dist/search/meilisearch-backend.d.ts +1 -1
  166. package/dist/search/noop-backend.d.ts +1 -1
  167. package/dist/search/orama-backend.d.ts +1 -1
  168. package/dist/search/port.d.ts +1 -1
  169. package/dist/search/remote-backend.d.ts +1 -1
  170. package/dist/{semantic-SLAa_prH.d.ts → semantic-DJR8_DMQ.d.ts} +1 -1
  171. package/dist/{semantic-consolidation-4HkHWgeI.d.ts → semantic-consolidation-FbhPeJjB.d.ts} +1 -1
  172. package/dist/semantic-consolidation.d.ts +2 -2
  173. package/dist/semantic-consolidation.js +4 -4
  174. package/dist/semantic-rule-promotion.js +3 -3
  175. package/dist/semantic-rule-verifier.d.ts +1 -1
  176. package/dist/semantic-rule-verifier.js +3 -3
  177. package/dist/session-observer-bands.d.ts +1 -1
  178. package/dist/session-observer-state.d.ts +1 -1
  179. package/dist/shared-context/manager.d.ts +5 -5
  180. package/dist/signal.d.ts +1 -1
  181. package/dist/storage.d.ts +19 -1
  182. package/dist/storage.js +2 -2
  183. package/dist/summarizer.d.ts +1 -1
  184. package/dist/summary-snapshot.d.ts +1 -1
  185. package/dist/temporal-supersession.d.ts +1 -1
  186. package/dist/temporal-validity.d.ts +1 -1
  187. package/dist/threading.d.ts +1 -1
  188. package/dist/tier-migration.d.ts +1 -1
  189. package/dist/tier-routing.d.ts +1 -1
  190. package/dist/topics.d.ts +1 -1
  191. package/dist/transcript.d.ts +1 -1
  192. package/dist/types-D5VRAI04.d.ts +3134 -0
  193. package/dist/types.d.ts +3 -2862
  194. package/dist/types.js +1 -1
  195. package/dist/utility-runtime.d.ts +1 -1
  196. package/dist/verified-recall.js +3 -3
  197. package/package.json +1 -1
  198. package/src/access-http.ts +167 -0
  199. package/src/access-mcp.ts +198 -0
  200. package/src/access-service.ts +65 -0
  201. package/src/cli.ts +187 -0
  202. package/src/config.ts +7 -0
  203. package/src/index.ts +7 -0
  204. package/src/orchestrator.ts +42 -0
  205. package/src/storage.ts +106 -0
  206. package/src/types.ts +5 -0
  207. package/src/wearables/cleanup.test.ts +134 -0
  208. package/src/wearables/cleanup.ts +188 -0
  209. package/src/wearables/cli.test.ts +170 -0
  210. package/src/wearables/cli.ts +441 -0
  211. package/src/wearables/config.test.ts +143 -0
  212. package/src/wearables/config.ts +332 -0
  213. package/src/wearables/corrections.test.ts +118 -0
  214. package/src/wearables/corrections.ts +211 -0
  215. package/src/wearables/day-store.test.ts +143 -0
  216. package/src/wearables/day-store.ts +238 -0
  217. package/src/wearables/errors.test.ts +32 -0
  218. package/src/wearables/errors.ts +29 -0
  219. package/src/wearables/index.ts +114 -0
  220. package/src/wearables/memory-gen.test.ts +342 -0
  221. package/src/wearables/memory-gen.ts +413 -0
  222. package/src/wearables/pipeline.test.ts +608 -0
  223. package/src/wearables/pipeline.ts +519 -0
  224. package/src/wearables/redaction.test.ts +94 -0
  225. package/src/wearables/redaction.ts +156 -0
  226. package/src/wearables/registry.test.ts +62 -0
  227. package/src/wearables/registry.ts +133 -0
  228. package/src/wearables/service.test.ts +425 -0
  229. package/src/wearables/service.ts +691 -0
  230. package/src/wearables/speakers.test.ts +110 -0
  231. package/src/wearables/speakers.ts +174 -0
  232. package/src/wearables/storage-io.test.ts +105 -0
  233. package/src/wearables/sync-state.test.ts +134 -0
  234. package/src/wearables/sync-state.ts +186 -0
  235. package/src/wearables/types.ts +285 -0
  236. package/dist/chunk-4R4KTDIE.js.map +0 -1
  237. package/dist/chunk-5GOMXHLC.js.map +0 -1
  238. package/dist/chunk-7TPH6UZL.js.map +0 -1
  239. package/dist/chunk-FG76RDVI.js.map +0 -1
  240. package/dist/chunk-I6UCUHLK.js.map +0 -1
  241. package/dist/chunk-KQFQ3IS5.js.map +0 -1
  242. package/dist/chunk-PJGB7XRR.js.map +0 -1
  243. package/dist/chunk-RKW6QR7W.js.map +0 -1
  244. /package/dist/{chunk-GYTVOLNX.js.map → chunk-3MNBW7R7.js.map} +0 -0
  245. /package/dist/{chunk-QFQQFX2H.js.map → chunk-3R2UZV3U.js.map} +0 -0
  246. /package/dist/{chunk-O4UNM6OR.js.map → chunk-532VCWYW.js.map} +0 -0
  247. /package/dist/{chunk-2UFQYU5F.js.map → chunk-57QXN2CS.js.map} +0 -0
  248. /package/dist/{chunk-UGEBPVNI.js.map → chunk-GE7Q7KXP.js.map} +0 -0
  249. /package/dist/{chunk-GLWW3EJQ.js.map → chunk-KB4MFBF5.js.map} +0 -0
  250. /package/dist/{chunk-FH3PPO42.js.map → chunk-KVFYTRMV.js.map} +0 -0
  251. /package/dist/{chunk-BNW5NJJH.js.map → chunk-LQYTQCXM.js.map} +0 -0
  252. /package/dist/{chunk-AYHXQR53.js.map → chunk-MVQN73GT.js.map} +0 -0
  253. /package/dist/{chunk-ZZPIJPPD.js.map → chunk-N5RGXWLQ.js.map} +0 -0
  254. /package/dist/{chunk-R3OQGYOU.js.map → chunk-P2D2MM47.js.map} +0 -0
  255. /package/dist/{chunk-PSUB67YB.js.map → chunk-PW6GURU3.js.map} +0 -0
  256. /package/dist/{chunk-W3BKVM64.js.map → chunk-QDV6VAD4.js.map} +0 -0
  257. /package/dist/{chunk-3QSU4NFF.js.map → chunk-QHXW3LZV.js.map} +0 -0
  258. /package/dist/{chunk-OZXVGYGZ.js.map → chunk-STDAAGH7.js.map} +0 -0
  259. /package/dist/{chunk-FMGWXIES.js.map → chunk-TZDSNIRO.js.map} +0 -0
  260. /package/dist/{chunk-2L54V4ZO.js.map → chunk-UELS6WWF.js.map} +0 -0
  261. /package/dist/{chunk-BPSGLMQ4.js.map → chunk-YQNADJCT.js.map} +0 -0
package/dist/types.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  SPECULATIVE_TTL_DAYS,
5
5
  confidenceTier,
6
6
  isRecallDisclosure
7
- } from "./chunk-4R4KTDIE.js";
7
+ } from "./chunk-FPNQF475.js";
8
8
  import "./chunk-PZ5AY32C.js";
9
9
  export {
10
10
  DEFAULT_RECALL_DISCLOSURE,
@@ -1,5 +1,5 @@
1
1
  import { TierRoutingPolicy } from './tier-routing.js';
2
- import './types.js';
2
+ import './types-D5VRAI04.js';
3
3
  import './types-BliCnURB.js';
4
4
  import './index-DJ9QWMw-.js';
5
5
  import './lifecycle.js';
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  searchVerifiedEpisodes
3
- } from "./chunk-R3OQGYOU.js";
3
+ } from "./chunk-P2D2MM47.js";
4
4
  import "./chunk-HQ6NIBL6.js";
5
- import "./chunk-PJGB7XRR.js";
5
+ import "./chunk-UGHUNQ74.js";
6
6
  import "./chunk-5UZXUTVO.js";
7
7
  import "./chunk-J6A3CX5N.js";
8
- import "./chunk-4R4KTDIE.js";
8
+ import "./chunk-FPNQF475.js";
9
9
  import "./chunk-RULE4VG5.js";
10
10
  import "./chunk-SCU65EZI.js";
11
11
  import "./chunk-MB5RSUW6.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remnic/core",
3
- "version": "9.3.624",
3
+ "version": "9.3.625",
4
4
  "description": "Framework-agnostic Remnic memory engine — orchestrator, storage, extraction, search, trust zones",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -8,6 +8,7 @@ import { fileURLToPath, URL } from "node:url";
8
8
  import { gunzipSync } from "node:zlib";
9
9
  import { log } from "./logger.js";
10
10
  import { EngramAccessInputError, type EngramAccessService } from "./access-service.js";
11
+ import { WearablesInputError } from "./wearables/errors.js";
11
12
  import { EngramMcpServer } from "./access-mcp.js";
12
13
  import { validateRequest, type SchemaName, type SchemaTypeFor } from "./access-schema.js";
13
14
  import {
@@ -1005,6 +1006,128 @@ export class EngramAccessHttpServer {
1005
1006
  return;
1006
1007
  }
1007
1008
 
1009
+ // -- Wearables (Limitless / Bee / Omi transcript ingestion). All
1010
+ // behavior + validation lives in WearablesService; these routes
1011
+ // translate transport shape only. Service validation errors map
1012
+ // to 400 via respondWearablesError; backend faults bubble to the
1013
+ // global 500 handler.
1014
+ if (
1015
+ req.method === "GET" &&
1016
+ (pathname === "/engram/v1/wearables/status" || pathname === "/remnic/v1/wearables/status")
1017
+ ) {
1018
+ this.respondJson(res, 200, await this.service.wearablesStatus());
1019
+ return;
1020
+ }
1021
+
1022
+ if (
1023
+ req.method === "POST" &&
1024
+ (pathname === "/engram/v1/wearables/sync" || pathname === "/remnic/v1/wearables/sync")
1025
+ ) {
1026
+ const body = (await this.readJsonBody(req)) as Record<string, unknown>;
1027
+ const source = optionalQueryString(body.source, "source");
1028
+ const date = optionalQueryString(body.date, "date");
1029
+ let days: number | undefined;
1030
+ if (body.days !== undefined && body.days !== null) {
1031
+ if (
1032
+ typeof body.days !== "number" ||
1033
+ !Number.isInteger(body.days) ||
1034
+ body.days < 1
1035
+ ) {
1036
+ throw new EngramAccessInputError(
1037
+ `days must be a positive integer (got ${JSON.stringify(body.days)})`,
1038
+ );
1039
+ }
1040
+ days = body.days;
1041
+ }
1042
+ if (body.forceMemories !== undefined && typeof body.forceMemories !== "boolean") {
1043
+ throw new EngramAccessInputError(
1044
+ `forceMemories must be a boolean (got ${JSON.stringify(body.forceMemories)})`,
1045
+ );
1046
+ }
1047
+ try {
1048
+ const summaries = await this.service.wearablesSync({
1049
+ source,
1050
+ date,
1051
+ days,
1052
+ forceMemories: body.forceMemories === true,
1053
+ });
1054
+ this.respondJson(res, 200, { summaries });
1055
+ } catch (err) {
1056
+ if (this.respondWearablesError(res, err)) return;
1057
+ throw err;
1058
+ }
1059
+ return;
1060
+ }
1061
+
1062
+ if (
1063
+ req.method === "GET" &&
1064
+ (pathname === "/engram/v1/wearables/transcript" || pathname === "/remnic/v1/wearables/transcript")
1065
+ ) {
1066
+ const date = parsed.searchParams.get("date");
1067
+ if (!date || date.trim().length === 0) {
1068
+ throw new EngramAccessInputError(
1069
+ "date query parameter is required (YYYY-MM-DD)",
1070
+ );
1071
+ }
1072
+ const sourceParam = parsed.searchParams.get("source");
1073
+ try {
1074
+ const transcripts = await this.service.wearablesTranscriptDay({
1075
+ date,
1076
+ source: sourceParam && sourceParam.length > 0 ? sourceParam : undefined,
1077
+ });
1078
+ this.respondJson(res, 200, { transcripts });
1079
+ } catch (err) {
1080
+ if (this.respondWearablesError(res, err)) return;
1081
+ throw err;
1082
+ }
1083
+ return;
1084
+ }
1085
+
1086
+ if (
1087
+ req.method === "GET" &&
1088
+ (pathname === "/engram/v1/wearables/transcripts/search" ||
1089
+ pathname === "/remnic/v1/wearables/transcripts/search")
1090
+ ) {
1091
+ const queryParam = parsed.searchParams.get("q");
1092
+ if (!queryParam || queryParam.trim().length === 0) {
1093
+ throw new EngramAccessInputError(
1094
+ "q query parameter is required and must be non-empty",
1095
+ );
1096
+ }
1097
+ try {
1098
+ const results = await this.service.wearablesTranscriptSearch({
1099
+ query: queryParam,
1100
+ source: nonEmptyQueryParam(parsed.searchParams.get("source")),
1101
+ from: nonEmptyQueryParam(parsed.searchParams.get("from")),
1102
+ to: nonEmptyQueryParam(parsed.searchParams.get("to")),
1103
+ limit: positiveIntQueryParam(parsed.searchParams.get("limit"), "limit"),
1104
+ });
1105
+ this.respondJson(res, 200, { results });
1106
+ } catch (err) {
1107
+ if (this.respondWearablesError(res, err)) return;
1108
+ throw err;
1109
+ }
1110
+ return;
1111
+ }
1112
+
1113
+ if (
1114
+ req.method === "GET" &&
1115
+ (pathname === "/engram/v1/wearables/memories" || pathname === "/remnic/v1/wearables/memories")
1116
+ ) {
1117
+ try {
1118
+ const memories = await this.service.wearablesTranscriptMemories({
1119
+ source: nonEmptyQueryParam(parsed.searchParams.get("source")),
1120
+ date: nonEmptyQueryParam(parsed.searchParams.get("date")),
1121
+ limit: positiveIntQueryParam(parsed.searchParams.get("limit"), "limit"),
1122
+ });
1123
+ this.respondJson(res, 200, { memories });
1124
+ } catch (err) {
1125
+ if (this.respondWearablesError(res, err)) return;
1126
+ throw err;
1127
+ }
1128
+ return;
1129
+ }
1130
+
1008
1131
  if (req.method === "POST" && pathname === "/engram/v1/observe") {
1009
1132
  const body = await this.readValidatedBody(req, "observe");
1010
1133
  this.ensureWriteRateLimitAvailable();
@@ -2372,4 +2495,48 @@ export class EngramAccessHttpServer {
2372
2495
  private shouldCountWriteRateLimit(response: { dryRun?: boolean; idempotencyReplay?: boolean }): boolean {
2373
2496
  return response.dryRun !== true && response.idempotencyReplay !== true;
2374
2497
  }
2498
+
2499
+ /**
2500
+ * Map wearables validation errors (WearablesInputError — invalid
2501
+ * params, unknown/disabled sources, missing connector packages) to a
2502
+ * 400 response. Returns false for everything else so backend faults
2503
+ * keep flowing to the global 500 handler.
2504
+ */
2505
+ private respondWearablesError(res: ServerResponse, err: unknown): boolean {
2506
+ if (err instanceof WearablesInputError) {
2507
+ this.respondJson(res, 400, {
2508
+ error: "invalid_request",
2509
+ code: "invalid_request",
2510
+ message: err.message,
2511
+ });
2512
+ return true;
2513
+ }
2514
+ return false;
2515
+ }
2516
+ }
2517
+
2518
+ /** Optional string field from a JSON body: absent/null/"" → undefined. */
2519
+ function optionalQueryString(value: unknown, label: string): string | undefined {
2520
+ if (value === undefined || value === null || value === "") return undefined;
2521
+ if (typeof value !== "string") {
2522
+ throw new EngramAccessInputError(
2523
+ `${label} must be a string (got ${JSON.stringify(value)})`,
2524
+ );
2525
+ }
2526
+ return value;
2527
+ }
2528
+
2529
+ /** Optional non-empty query param: null/"" → undefined. */
2530
+ function nonEmptyQueryParam(value: string | null): string | undefined {
2531
+ return value !== null && value.length > 0 ? value : undefined;
2532
+ }
2533
+
2534
+ /** Optional positive-integer query param; rejects invalid values. */
2535
+ function positiveIntQueryParam(value: string | null, label: string): number | undefined {
2536
+ if (value === null || value.length === 0) return undefined;
2537
+ const parsed = Number(value);
2538
+ if (!Number.isFinite(parsed) || parsed <= 0 || !Number.isInteger(parsed)) {
2539
+ throw new EngramAccessInputError(`${label} expects a positive integer`);
2540
+ }
2541
+ return parsed;
2375
2542
  }
package/src/access-mcp.ts CHANGED
@@ -204,6 +204,36 @@ function parseMcpRequest<N extends SchemaName>(
204
204
  );
205
205
  }
206
206
 
207
+ /**
208
+ * Strict optional-string MCP argument: absent/null/"" → undefined,
209
+ * non-string → loud error (CLAUDE.md rule 51 — no silent coercion).
210
+ */
211
+ function optionalNonEmptyString(value: unknown, label: string): string | undefined {
212
+ if (value === undefined || value === null || value === "") return undefined;
213
+ if (typeof value !== "string") {
214
+ throw new Error(`${label} expects a string; got ${JSON.stringify(value)}`);
215
+ }
216
+ return value;
217
+ }
218
+
219
+ /**
220
+ * Strict optional positive-integer MCP argument. Accepts JSON numbers
221
+ * and numeric strings (loosely-typed MCP clients send both); rejects
222
+ * everything else including booleans, which `Number()` would silently
223
+ * coerce.
224
+ */
225
+ function optionalPositiveInteger(value: unknown, label: string): number | undefined {
226
+ if (value === undefined || value === null || value === "") return undefined;
227
+ if (typeof value !== "number" && typeof value !== "string") {
228
+ throw new Error(`${label} expects a positive integer; got ${JSON.stringify(value)}`);
229
+ }
230
+ const parsed = typeof value === "number" ? value : Number(value);
231
+ if (!Number.isFinite(parsed) || parsed <= 0 || !Number.isInteger(parsed)) {
232
+ throw new Error(`${label} expects a positive integer; got ${JSON.stringify(value)}`);
233
+ }
234
+ return parsed;
235
+ }
236
+
207
237
  function getObjectProperties(value: unknown): Record<string, unknown> | undefined {
208
238
  return value && typeof value === "object" && !Array.isArray(value)
209
239
  ? (value as Record<string, unknown>)
@@ -452,6 +482,124 @@ export class EngramMcpServer {
452
482
  additionalProperties: false,
453
483
  },
454
484
  },
485
+ {
486
+ name: "engram.wearables_status",
487
+ description:
488
+ "Status of wearable transcript sources (Limitless / Bee / Omi): configured sources, connector availability, last sync, stored transcript days.",
489
+ inputSchema: {
490
+ type: "object",
491
+ properties: {},
492
+ additionalProperties: false,
493
+ },
494
+ },
495
+ {
496
+ name: "engram.wearables_sync",
497
+ description:
498
+ "Pull, clean, and store wearable transcripts for one source or all enabled sources; optionally creates trust-gated memories per the source's memoryMode.",
499
+ inputSchema: {
500
+ type: "object",
501
+ properties: {
502
+ source: {
503
+ type: "string",
504
+ description: "Source id (e.g. limitless, bee, omi). Omit to sync every enabled source.",
505
+ },
506
+ date: {
507
+ type: "string",
508
+ description: "Sync exactly this day (YYYY-MM-DD). Overrides days.",
509
+ },
510
+ days: {
511
+ type: "integer",
512
+ minimum: 1,
513
+ maximum: 90,
514
+ description: "Lookback window in days ending today (default 2).",
515
+ },
516
+ forceMemories: {
517
+ type: "boolean",
518
+ description: "Re-run memory extraction even for unchanged days.",
519
+ },
520
+ },
521
+ additionalProperties: false,
522
+ },
523
+ },
524
+ {
525
+ name: "engram.transcript_day",
526
+ description:
527
+ "Return the full stored wearable transcript(s) for a day, across all sources or one source, with cross-source overlap hints.",
528
+ inputSchema: {
529
+ type: "object",
530
+ properties: {
531
+ date: {
532
+ type: "string",
533
+ description: "Day to read (YYYY-MM-DD). Required.",
534
+ },
535
+ source: {
536
+ type: "string",
537
+ description: "Optional source id to scope to (e.g. limitless).",
538
+ },
539
+ },
540
+ required: ["date"],
541
+ additionalProperties: false,
542
+ },
543
+ },
544
+ {
545
+ name: "engram.transcript_search",
546
+ description:
547
+ "Search stored wearable transcripts. Results carry source + date so callers can pull the full day via engram.transcript_day.",
548
+ inputSchema: {
549
+ type: "object",
550
+ properties: {
551
+ query: {
552
+ type: "string",
553
+ description: "Search query. Required; non-empty.",
554
+ },
555
+ source: {
556
+ type: "string",
557
+ description: "Optional source id filter.",
558
+ },
559
+ from: {
560
+ type: "string",
561
+ description: "Optional inclusive start date (YYYY-MM-DD).",
562
+ },
563
+ to: {
564
+ type: "string",
565
+ description: "Optional inclusive end date (YYYY-MM-DD).",
566
+ },
567
+ limit: {
568
+ type: "integer",
569
+ minimum: 1,
570
+ maximum: 50,
571
+ description: "Maximum results (default 10).",
572
+ },
573
+ },
574
+ required: ["query"],
575
+ additionalProperties: false,
576
+ },
577
+ },
578
+ {
579
+ name: "engram.transcript_memories",
580
+ description:
581
+ "List memories created from wearable transcripts, filterable by source and/or day. Includes pending_review candidates awaiting approval.",
582
+ inputSchema: {
583
+ type: "object",
584
+ properties: {
585
+ source: {
586
+ type: "string",
587
+ description: "Optional source id filter (e.g. limitless).",
588
+ },
589
+ date: {
590
+ type: "string",
591
+ description: "Optional transcript day filter (YYYY-MM-DD).",
592
+ },
593
+ limit: {
594
+ type: "integer",
595
+ minimum: 1,
596
+ maximum: 200,
597
+ description: "Maximum results (default 50).",
598
+ },
599
+ },
600
+ additionalProperties: false,
601
+ },
602
+ },
455
603
  {
456
604
  name: "engram.action_confidence",
457
605
  description:
@@ -2348,6 +2496,56 @@ export class EngramMcpServer {
2348
2496
  : {}),
2349
2497
  });
2350
2498
  }
2499
+ case "engram.wearables_status":
2500
+ return this.service.wearablesStatus();
2501
+ case "engram.wearables_sync": {
2502
+ const source = optionalNonEmptyString(args.source, "engram.wearables_sync: source");
2503
+ const date = optionalNonEmptyString(args.date, "engram.wearables_sync: date");
2504
+ const days = optionalPositiveInteger(args.days, "engram.wearables_sync: days");
2505
+ let forceMemories: boolean | undefined;
2506
+ if (args.forceMemories !== undefined && args.forceMemories !== null) {
2507
+ if (typeof args.forceMemories !== "boolean") {
2508
+ throw new Error(
2509
+ `engram.wearables_sync: forceMemories expects a boolean; got ${JSON.stringify(args.forceMemories)}`,
2510
+ );
2511
+ }
2512
+ forceMemories = args.forceMemories;
2513
+ }
2514
+ // Date/days/source validation beyond shape lives in the shared
2515
+ // WearablesService so CLI/HTTP/MCP reject identically.
2516
+ return this.service.wearablesSync({ source, date, days, forceMemories });
2517
+ }
2518
+ case "engram.transcript_day": {
2519
+ const date = typeof args.date === "string" ? args.date : "";
2520
+ if (date.trim().length === 0) {
2521
+ throw new Error(
2522
+ "engram.transcript_day: date is required and must be YYYY-MM-DD",
2523
+ );
2524
+ }
2525
+ const source = optionalNonEmptyString(args.source, "engram.transcript_day: source");
2526
+ return this.service.wearablesTranscriptDay({ date, source });
2527
+ }
2528
+ case "engram.transcript_search": {
2529
+ const query = typeof args.query === "string" ? args.query : "";
2530
+ if (query.trim().length === 0) {
2531
+ throw new Error(
2532
+ "engram.transcript_search: query is required and must be non-empty",
2533
+ );
2534
+ }
2535
+ return this.service.wearablesTranscriptSearch({
2536
+ query,
2537
+ source: optionalNonEmptyString(args.source, "engram.transcript_search: source"),
2538
+ from: optionalNonEmptyString(args.from, "engram.transcript_search: from"),
2539
+ to: optionalNonEmptyString(args.to, "engram.transcript_search: to"),
2540
+ limit: optionalPositiveInteger(args.limit, "engram.transcript_search: limit"),
2541
+ });
2542
+ }
2543
+ case "engram.transcript_memories":
2544
+ return this.service.wearablesTranscriptMemories({
2545
+ source: optionalNonEmptyString(args.source, "engram.transcript_memories: source"),
2546
+ date: optionalNonEmptyString(args.date, "engram.transcript_memories: date"),
2547
+ limit: optionalPositiveInteger(args.limit, "engram.transcript_memories: limit"),
2548
+ });
2351
2549
  case "engram.action_confidence": {
2352
2550
  const body: ActionConfidenceRequest = parseMcpRequest("actionConfidence", args);
2353
2551
  return this.service.actionConfidence(body);
@@ -39,6 +39,7 @@ import {
39
39
  import { runProcedureMining } from "./procedural/procedure-miner.js";
40
40
  import type { PatternReinforcementResult } from "./maintenance/pattern-reinforcement.js";
41
41
  import type { LiveConnectorsRunSummary } from "./live-connectors-runner.js";
42
+ import type { WearablesService } from "./wearables/service.js";
42
43
  import {
43
44
  computeProcedureStats,
44
45
  type ProcedureStatsReport,
@@ -6154,4 +6155,68 @@ export class EngramAccessService {
6154
6155
  notes: result.notes,
6155
6156
  };
6156
6157
  }
6158
+
6159
+ // ---------------------------------------------------------------------------
6160
+ // Wearables (Limitless / Bee / Omi transcript ingestion)
6161
+ //
6162
+ // Thin delegations to the orchestrator-owned WearablesService — the
6163
+ // same instance behind the CLI, so HTTP/MCP callers observe identical
6164
+ // behavior and validation (renderer-sharing rule).
6165
+ // ---------------------------------------------------------------------------
6166
+
6167
+ async wearablesStatus(): Promise<
6168
+ Awaited<ReturnType<WearablesService["status"]>>
6169
+ > {
6170
+ return this.orchestrator.getWearablesService().status();
6171
+ }
6172
+
6173
+ async wearablesSync(request: {
6174
+ source?: string;
6175
+ date?: string;
6176
+ days?: number;
6177
+ forceMemories?: boolean;
6178
+ }): Promise<Awaited<ReturnType<WearablesService["sync"]>>> {
6179
+ return this.orchestrator.getWearablesService().sync({
6180
+ source: request.source,
6181
+ date: request.date,
6182
+ days: request.days,
6183
+ forceMemories: request.forceMemories,
6184
+ });
6185
+ }
6186
+
6187
+ async wearablesTranscriptDay(request: {
6188
+ date: string;
6189
+ source?: string;
6190
+ }): Promise<Awaited<ReturnType<WearablesService["dayTranscript"]>>> {
6191
+ return this.orchestrator
6192
+ .getWearablesService()
6193
+ .dayTranscript(request.date, request.source);
6194
+ }
6195
+
6196
+ async wearablesTranscriptSearch(request: {
6197
+ query: string;
6198
+ source?: string;
6199
+ from?: string;
6200
+ to?: string;
6201
+ limit?: number;
6202
+ }): Promise<Awaited<ReturnType<WearablesService["searchTranscripts"]>>> {
6203
+ return this.orchestrator.getWearablesService().searchTranscripts(request.query, {
6204
+ source: request.source,
6205
+ from: request.from,
6206
+ to: request.to,
6207
+ limit: request.limit,
6208
+ });
6209
+ }
6210
+
6211
+ async wearablesTranscriptMemories(request: {
6212
+ source?: string;
6213
+ date?: string;
6214
+ limit?: number;
6215
+ }): Promise<Awaited<ReturnType<WearablesService["transcriptMemories"]>>> {
6216
+ return this.orchestrator.getWearablesService().transcriptMemories({
6217
+ source: request.source,
6218
+ date: request.date,
6219
+ limit: request.limit,
6220
+ });
6221
+ }
6157
6222
  }