@remnic/core 9.25.6 → 9.26.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 (220) hide show
  1. package/dist/access-admin-ops-surface.d.ts +2 -2
  2. package/dist/access-admin-ops-surface.js +41 -41
  3. package/dist/access-audit.js +2 -2
  4. package/dist/access-authorization-probe.d.ts +2 -2
  5. package/dist/access-authorization-probe.js +42 -42
  6. package/dist/access-boundary.d.ts +2 -2
  7. package/dist/access-boundary.js +41 -41
  8. package/dist/access-cli.js +98 -97
  9. package/dist/access-cli.js.map +1 -1
  10. package/dist/access-http-lcm-compaction.d.ts +130 -0
  11. package/dist/access-http-lcm-compaction.js +10 -0
  12. package/dist/access-http.d.ts +2 -2
  13. package/dist/access-http.js +53 -52
  14. package/dist/access-identity-continuity-surface.d.ts +1 -1
  15. package/dist/access-identity-continuity-surface.js +41 -41
  16. package/dist/access-lcm-surface.d.ts +2 -2
  17. package/dist/access-lcm-surface.js +41 -41
  18. package/dist/access-mcp.d.ts +2 -2
  19. package/dist/access-mcp.js +47 -47
  20. package/dist/access-namespace-preflight.js +41 -41
  21. package/dist/access-observe-write-surface.d.ts +2 -2
  22. package/dist/access-observe-write-surface.js +41 -41
  23. package/dist/access-operations-batch.js +43 -43
  24. package/dist/access-operations.d.ts +2 -2
  25. package/dist/access-operations.js +45 -45
  26. package/dist/access-recall-concurrency.d.ts +2 -2
  27. package/dist/access-recall-concurrency.js +41 -41
  28. package/dist/access-recall-response.d.ts +2 -2
  29. package/dist/access-recall-response.js +41 -41
  30. package/dist/access-recall-surface.d.ts +2 -2
  31. package/dist/access-recall-surface.js +41 -41
  32. package/dist/access-schema.d.ts +16 -1
  33. package/dist/access-schema.js +8 -8
  34. package/dist/{access-service-BJQ22URi.d.ts → access-service-DL8FJnTj.d.ts} +2 -2
  35. package/dist/access-service.d.ts +2 -2
  36. package/dist/access-service.js +41 -41
  37. package/dist/access-surface-catalog.d.ts +2 -2
  38. package/dist/adapters/index.js +7 -7
  39. package/dist/adapters/registry.js +3 -3
  40. package/dist/{auto-sync-5OE5QOZB.js → auto-sync-UPTUVE4X.js} +3 -3
  41. package/dist/bootstrap.d.ts +1 -1
  42. package/dist/briefing.js +5 -5
  43. package/dist/{capsule-crypto-7FJQINUR.js → capsule-crypto-YO5QJ6L3.js} +2 -2
  44. package/dist/capsule-crypto-YO5QJ6L3.js.map +1 -0
  45. package/dist/causal-behavior.js +2 -2
  46. package/dist/causal-chain.js +2 -2
  47. package/dist/causal-consolidation.js +11 -11
  48. package/dist/causal-retrieval.js +2 -2
  49. package/dist/causal-trajectory.js +1 -1
  50. package/dist/{chunk-JBPKEARU.js → chunk-2QSZNTDO.js} +7 -7
  51. package/dist/{chunk-BL4JHZSO.js → chunk-2XP3PWL3.js} +40 -40
  52. package/dist/{chunk-AQ2ZQYDI.js → chunk-4KKV7W62.js} +6 -6
  53. package/dist/chunk-4Z4XNEWZ.js +86 -0
  54. package/dist/chunk-4Z4XNEWZ.js.map +1 -0
  55. package/dist/{chunk-32XTXKIA.js → chunk-67DSDRUB.js} +22 -14
  56. package/dist/chunk-67DSDRUB.js.map +1 -0
  57. package/dist/{chunk-2PHX3I5C.js → chunk-6NNNURLK.js} +8 -8
  58. package/dist/{chunk-BLAKS3CP.js → chunk-77CNV7DY.js} +4 -4
  59. package/dist/{chunk-TVVEYCNW.js → chunk-7K5Q6COX.js} +4 -4
  60. package/dist/{chunk-227UFSEQ.js → chunk-7RZJWZ46.js} +5 -5
  61. package/dist/{chunk-WIGBTWXA.js → chunk-7XXCIO6X.js} +2 -2
  62. package/dist/{chunk-7CPOZH6Y.js → chunk-AJ7QCSIS.js} +2 -2
  63. package/dist/{chunk-2NLLXCJG.js → chunk-BXLOS5AJ.js} +2 -2
  64. package/dist/{chunk-X7Y7WX73.js → chunk-DQEMWVMT.js} +1 -1
  65. package/dist/{chunk-UMFLAACL.js → chunk-E6EAB4J6.js} +9 -9
  66. package/dist/{chunk-WSEA52RI.js → chunk-EXM2Q555.js} +2 -2
  67. package/dist/{chunk-G6MGAE36.js → chunk-F6LSNPPB.js} +5 -5
  68. package/dist/{chunk-7KXQ44PA.js → chunk-FE5FKTCI.js} +5 -5
  69. package/dist/{chunk-5J7HJ7RT.js → chunk-H2PBM562.js} +2 -2
  70. package/dist/{chunk-OIE242WM.js → chunk-HBVOJNV4.js} +3 -3
  71. package/dist/{chunk-PS5OG75R.js → chunk-IHMXPG4P.js} +2 -2
  72. package/dist/{chunk-3UOSVTFR.js → chunk-JCVQV6QX.js} +11 -11
  73. package/dist/{chunk-P25IPRXP.js → chunk-KGTD2KZJ.js} +28 -8
  74. package/dist/chunk-KGTD2KZJ.js.map +1 -0
  75. package/dist/{chunk-NY6W6CJW.js → chunk-KPWLZBXZ.js} +2 -2
  76. package/dist/{chunk-W33DEUKR.js → chunk-LIIQPDFN.js} +2 -2
  77. package/dist/{chunk-D7MAWMMK.js → chunk-M2KGXXTL.js} +2 -2
  78. package/dist/{chunk-UOURUMBN.js → chunk-MIFF37NN.js} +2 -2
  79. package/dist/{chunk-37VPMR4E.js → chunk-NKDVXEFU.js} +6 -6
  80. package/dist/{chunk-ZPUFQGUF.js → chunk-PQPSZICJ.js} +5 -5
  81. package/dist/{chunk-ES36HTSC.js → chunk-PTN6UAUA.js} +4 -4
  82. package/dist/{chunk-FR75B4UU.js → chunk-PX7VDW7R.js} +408 -721
  83. package/dist/chunk-PX7VDW7R.js.map +1 -0
  84. package/dist/{chunk-S2BBISHU.js → chunk-RYHWZ52A.js} +4 -4
  85. package/dist/{chunk-ZN4UZWMT.js → chunk-SK3EYPKC.js} +2 -2
  86. package/dist/{chunk-TPYZ727G.js → chunk-SN3ZESWQ.js} +6 -6
  87. package/dist/{chunk-BUK2FXOL.js → chunk-TKBDJTXG.js} +4 -4
  88. package/dist/{chunk-4B77XSG5.js → chunk-UV72DEZD.js} +5 -5
  89. package/dist/{chunk-K4DP5KZA.js → chunk-UZK7VVPD.js} +14 -14
  90. package/dist/{chunk-KQAFEZQX.js → chunk-VDX2J7OX.js} +2 -2
  91. package/dist/{chunk-SSYBI43M.js → chunk-VGEH3STZ.js} +6 -6
  92. package/dist/{chunk-NRV4Y3PM.js → chunk-W4FBGYGK.js} +1 -1
  93. package/dist/{chunk-IR4LGIH6.js → chunk-WMDRLTNA.js} +2 -2
  94. package/dist/{chunk-MU7ZHSZE.js → chunk-WZFAPHIK.js} +2 -2
  95. package/dist/{chunk-JA4HEXV7.js → chunk-XAAIUXJO.js} +2 -2
  96. package/dist/{chunk-VPSAVXHM.js → chunk-XNUBF6RF.js} +7 -7
  97. package/dist/{chunk-3CHQZVAL.js → chunk-Y6E37WRG.js} +5 -5
  98. package/dist/{chunk-E5A6C4A5.js → chunk-YN4AUGNF.js} +48 -48
  99. package/dist/{chunk-EZ25VE3G.js → chunk-YNDLCWXS.js} +4 -4
  100. package/dist/{chunk-7IGWPXVC.js → chunk-ZHP4SUPB.js} +2 -2
  101. package/dist/{cli-1W7cNjJJ.d.ts → cli-BoouX6LX.d.ts} +2 -2
  102. package/dist/cli.d.ts +3 -3
  103. package/dist/cli.js +75 -74
  104. package/dist/compounding/engine.js +5 -5
  105. package/dist/connectors/codex-materialize-runner.js +5 -5
  106. package/dist/connectors/index.js +5 -5
  107. package/dist/conversation-index/backend.js +2 -2
  108. package/dist/corpus-watermark.js +16 -16
  109. package/dist/dashboard-runtime.js +2 -2
  110. package/dist/entity-retrieval.js +5 -5
  111. package/dist/explicit-capture.d.ts +1 -1
  112. package/dist/extraction.js +3 -3
  113. package/dist/{first-start-migration-BKNGOFED.js → first-start-migration-LEXL3XYL.js} +4 -4
  114. package/dist/index.d.ts +4 -4
  115. package/dist/index.js +177 -176
  116. package/dist/lcm/engine.js +3 -3
  117. package/dist/lcm/index.js +9 -9
  118. package/dist/maintenance/memory-governance.js +6 -6
  119. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +5 -5
  120. package/dist/maintenance/rebuild-memory-projection.js +7 -7
  121. package/dist/mcp-memory-inspector-app.d.ts +2 -2
  122. package/dist/namespaces/migrate.js +15 -15
  123. package/dist/namespaces/search.js +9 -9
  124. package/dist/namespaces/storage.js +5 -5
  125. package/dist/operator-doctor-corpus.js +17 -17
  126. package/dist/operator-toolkit.js +28 -28
  127. package/dist/orchestration/maintenance.js +11 -11
  128. package/dist/{orchestrator-BtA1wC5K.d.ts → orchestrator-CFJ_TG6D.d.ts} +15 -10
  129. package/dist/orchestrator.d.ts +1 -1
  130. package/dist/orchestrator.js +98 -97
  131. package/dist/resume-bundles.js +1 -1
  132. package/dist/search/factory.js +8 -8
  133. package/dist/search/index.js +13 -13
  134. package/dist/search/lancedb-backend.js +2 -2
  135. package/dist/search/meilisearch-backend.js +2 -2
  136. package/dist/search/orama-backend.js +2 -2
  137. package/dist/semantic-consolidation.js +7 -7
  138. package/dist/semantic-rule-promotion.js +5 -5
  139. package/dist/semantic-rule-verifier.js +6 -6
  140. package/dist/session-namespace-bindings.d.ts +27 -0
  141. package/dist/session-namespace-bindings.js +243 -0
  142. package/dist/session-namespace-bindings.js.map +1 -0
  143. package/dist/storage.js +4 -4
  144. package/dist/testing/lifecycle-matrix.d.ts +100 -0
  145. package/dist/testing/lifecycle-matrix.js +149 -0
  146. package/dist/testing/lifecycle-matrix.js.map +1 -0
  147. package/dist/transfer/backup.js +4 -4
  148. package/dist/transfer/capsule-export.js +4 -4
  149. package/dist/transfer/capsule-import.js +3 -3
  150. package/dist/verified-recall.js +6 -6
  151. package/package.json +22 -2
  152. package/src/access-http-lcm-compaction.ts +116 -0
  153. package/src/access-http.test.ts +218 -0
  154. package/src/access-http.ts +8 -8
  155. package/src/access-schema-pi.test.ts +9 -0
  156. package/src/access-schema.ts +29 -4
  157. package/src/access-surface-catalog.test.ts +1 -0
  158. package/src/meetings/recall-exclusion.test.ts +4 -2
  159. package/src/orchestration/generic-recall-paths.ts +119 -0
  160. package/src/orchestration/namespace-read-fanout.ts +0 -12
  161. package/src/orchestration/orchestrator-helpers.ts +0 -35
  162. package/src/orchestration/recall-internal.ts +6 -6
  163. package/src/orchestration/recall-search-pipeline.test.ts +194 -28
  164. package/src/orchestration/recall-search-pipeline.ts +39 -89
  165. package/src/orchestrator.ts +5 -17
  166. package/src/recall-cold-deadline.test.ts +11 -13
  167. package/src/session-namespace-bindings.test.ts +358 -0
  168. package/src/session-namespace-bindings.ts +301 -0
  169. package/src/testing/lifecycle-matrix.ts +17 -7
  170. package/src/testing/subjects/generic-recall-paths.test.ts +157 -0
  171. package/dist/chunk-32XTXKIA.js.map +0 -1
  172. package/dist/chunk-FR75B4UU.js.map +0 -1
  173. package/dist/chunk-P25IPRXP.js.map +0 -1
  174. package/src/recall/archive-scoring.ts +0 -544
  175. /package/dist/{capsule-crypto-7FJQINUR.js.map → access-http-lcm-compaction.js.map} +0 -0
  176. /package/dist/{auto-sync-5OE5QOZB.js.map → auto-sync-UPTUVE4X.js.map} +0 -0
  177. /package/dist/{chunk-JBPKEARU.js.map → chunk-2QSZNTDO.js.map} +0 -0
  178. /package/dist/{chunk-BL4JHZSO.js.map → chunk-2XP3PWL3.js.map} +0 -0
  179. /package/dist/{chunk-AQ2ZQYDI.js.map → chunk-4KKV7W62.js.map} +0 -0
  180. /package/dist/{chunk-2PHX3I5C.js.map → chunk-6NNNURLK.js.map} +0 -0
  181. /package/dist/{chunk-BLAKS3CP.js.map → chunk-77CNV7DY.js.map} +0 -0
  182. /package/dist/{chunk-TVVEYCNW.js.map → chunk-7K5Q6COX.js.map} +0 -0
  183. /package/dist/{chunk-227UFSEQ.js.map → chunk-7RZJWZ46.js.map} +0 -0
  184. /package/dist/{chunk-WIGBTWXA.js.map → chunk-7XXCIO6X.js.map} +0 -0
  185. /package/dist/{chunk-7CPOZH6Y.js.map → chunk-AJ7QCSIS.js.map} +0 -0
  186. /package/dist/{chunk-2NLLXCJG.js.map → chunk-BXLOS5AJ.js.map} +0 -0
  187. /package/dist/{chunk-X7Y7WX73.js.map → chunk-DQEMWVMT.js.map} +0 -0
  188. /package/dist/{chunk-UMFLAACL.js.map → chunk-E6EAB4J6.js.map} +0 -0
  189. /package/dist/{chunk-WSEA52RI.js.map → chunk-EXM2Q555.js.map} +0 -0
  190. /package/dist/{chunk-G6MGAE36.js.map → chunk-F6LSNPPB.js.map} +0 -0
  191. /package/dist/{chunk-7KXQ44PA.js.map → chunk-FE5FKTCI.js.map} +0 -0
  192. /package/dist/{chunk-5J7HJ7RT.js.map → chunk-H2PBM562.js.map} +0 -0
  193. /package/dist/{chunk-OIE242WM.js.map → chunk-HBVOJNV4.js.map} +0 -0
  194. /package/dist/{chunk-PS5OG75R.js.map → chunk-IHMXPG4P.js.map} +0 -0
  195. /package/dist/{chunk-3UOSVTFR.js.map → chunk-JCVQV6QX.js.map} +0 -0
  196. /package/dist/{chunk-NY6W6CJW.js.map → chunk-KPWLZBXZ.js.map} +0 -0
  197. /package/dist/{chunk-W33DEUKR.js.map → chunk-LIIQPDFN.js.map} +0 -0
  198. /package/dist/{chunk-D7MAWMMK.js.map → chunk-M2KGXXTL.js.map} +0 -0
  199. /package/dist/{chunk-UOURUMBN.js.map → chunk-MIFF37NN.js.map} +0 -0
  200. /package/dist/{chunk-37VPMR4E.js.map → chunk-NKDVXEFU.js.map} +0 -0
  201. /package/dist/{chunk-ZPUFQGUF.js.map → chunk-PQPSZICJ.js.map} +0 -0
  202. /package/dist/{chunk-ES36HTSC.js.map → chunk-PTN6UAUA.js.map} +0 -0
  203. /package/dist/{chunk-S2BBISHU.js.map → chunk-RYHWZ52A.js.map} +0 -0
  204. /package/dist/{chunk-ZN4UZWMT.js.map → chunk-SK3EYPKC.js.map} +0 -0
  205. /package/dist/{chunk-TPYZ727G.js.map → chunk-SN3ZESWQ.js.map} +0 -0
  206. /package/dist/{chunk-BUK2FXOL.js.map → chunk-TKBDJTXG.js.map} +0 -0
  207. /package/dist/{chunk-4B77XSG5.js.map → chunk-UV72DEZD.js.map} +0 -0
  208. /package/dist/{chunk-K4DP5KZA.js.map → chunk-UZK7VVPD.js.map} +0 -0
  209. /package/dist/{chunk-KQAFEZQX.js.map → chunk-VDX2J7OX.js.map} +0 -0
  210. /package/dist/{chunk-SSYBI43M.js.map → chunk-VGEH3STZ.js.map} +0 -0
  211. /package/dist/{chunk-NRV4Y3PM.js.map → chunk-W4FBGYGK.js.map} +0 -0
  212. /package/dist/{chunk-IR4LGIH6.js.map → chunk-WMDRLTNA.js.map} +0 -0
  213. /package/dist/{chunk-MU7ZHSZE.js.map → chunk-WZFAPHIK.js.map} +0 -0
  214. /package/dist/{chunk-JA4HEXV7.js.map → chunk-XAAIUXJO.js.map} +0 -0
  215. /package/dist/{chunk-VPSAVXHM.js.map → chunk-XNUBF6RF.js.map} +0 -0
  216. /package/dist/{chunk-3CHQZVAL.js.map → chunk-Y6E37WRG.js.map} +0 -0
  217. /package/dist/{chunk-E5A6C4A5.js.map → chunk-YN4AUGNF.js.map} +0 -0
  218. /package/dist/{chunk-EZ25VE3G.js.map → chunk-YNDLCWXS.js.map} +0 -0
  219. /package/dist/{chunk-7IGWPXVC.js.map → chunk-ZHP4SUPB.js.map} +0 -0
  220. /package/dist/{first-start-migration-BKNGOFED.js.map → first-start-migration-LEXL3XYL.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/access-schema.ts"],"sourcesContent":["// Request/response schema validation for the Remnic HTTP API.\n// Uses zod for runtime validation — returns structured 400 errors with\n// field-level detail so consumers get clear feedback on malformed requests.\n\nimport { z } from \"zod\";\nimport {\n ACTION_CONFIDENCE_CONTEXT_READINESS,\n ACTION_CONFIDENCE_RISK_CATEGORIES,\n ACTION_CONFIDENCE_RULE_KINDS,\n} from \"./action-confidence.js\";\nimport { isValidCapsuleSince } from \"./transfer/capsule-export.js\";\nimport { validateArchiveRelativePath } from \"./transfer/fs-utils.js\";\nimport { CAPSULE_ID_PATTERN } from \"./transfer/types.js\";\nimport {\n OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES,\n OFFLINE_SYNC_MAX_MTIME_MS,\n} from \"./offline-sync.js\";\n\n// ---------------------------------------------------------------------------\n// Error formatting\n// ---------------------------------------------------------------------------\n\nexport interface SchemaValidationError {\n error: string;\n code: \"validation_error\";\n details: Array<{ field: string; message: string }>;\n}\n\nexport function formatZodError(error: z.ZodError): SchemaValidationError {\n return {\n error: \"request validation failed\",\n code: \"validation_error\",\n details: error.issues.map((issue) => ({\n field: issue.path.join(\".\") || \"(root)\",\n message: issue.message,\n })),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Shared fields\n// ---------------------------------------------------------------------------\n\nconst namespaceSchema = z.string().trim().max(256).optional();\nconst sessionKeySchema = z.string().trim().min(1).max(512).optional();\nconst idempotencyKeySchema = z.string().trim().min(1).max(256).optional();\nconst dryRunSchema = z.boolean().optional();\nconst schemaVersionSchema = z.number().int().optional();\nconst timeZoneSchema = z\n .string()\n .trim()\n .min(1)\n .max(128)\n .refine((value) => {\n try {\n Intl.DateTimeFormat(undefined, { timeZone: value });\n return true;\n } catch {\n return false;\n }\n }, \"must be a valid IANA timezone\");\n\n// ---------------------------------------------------------------------------\n// Recall\n// ---------------------------------------------------------------------------\n\n/**\n * Coding-agent context (issue #569). Optional payload that connectors may\n * ship with a recall request so the project/branch namespace overlay\n * applies to that recall. All fields are validated per CLAUDE.md #51 —\n * empty-string projectId / rootPath is rejected, not silently accepted.\n */\nexport const codingContextSchema = z\n .object({\n projectId: z.string().trim().min(1, \"codingContext.projectId is required\").max(128),\n branch: z.string().trim().max(256).nullable(),\n rootPath: z.string().trim().min(1, \"codingContext.rootPath is required\").max(1024),\n defaultBranch: z.string().trim().max(256).nullable(),\n })\n .nullable();\n\n/**\n * Recall disclosure depth (issue #677). Mirrors the `RecallDisclosure`\n * type in `types.ts` — keep these in sync. Default-application happens\n * inside `EngramAccessService.recall()`; the schema only accepts/rejects.\n * Invalid values throw a structured 400 instead of silently defaulting,\n * per CLAUDE.md rule 51.\n */\nexport const recallDisclosureSchema = z.enum([\"chunk\", \"section\", \"raw\"]);\n\n/**\n * Tag-match semantics (issue #689). `any` (default when `tags` is provided\n * and `tagMatch` is omitted) admits a result when it carries at least one\n * of the filter tags. `all` requires every filter tag to be present.\n * Schema rejects unknown values up front — never silently defaults\n * (CLAUDE.md rule 51).\n */\nexport const tagMatchSchema = z.enum([\"any\", \"all\"]);\n\nexport const recallRequestSchema = z.object({\n query: z.string().min(1, \"query is required\"),\n sessionKey: sessionKeySchema,\n namespace: namespaceSchema,\n topK: z.number().int().min(0).max(200).optional(),\n mode: z.enum([\"auto\", \"no_recall\", \"minimal\", \"full\", \"graph_mode\"]).optional(),\n includeDebug: z.boolean().optional(),\n idempotencyKey: idempotencyKeySchema,\n disclosure: recallDisclosureSchema.optional(),\n codingContext: codingContextSchema.optional(),\n /** Working directory for auto git-context resolution (issue #569). */\n cwd: z.string().trim().min(1, \"cwd must be non-empty when provided\").max(2048).optional(),\n /**\n * Arbitrary project tag for non-git-based project scoping (issue #569).\n * Creates a coding context with `projectId: \"tag:<projectTag>\"`.\n */\n projectTag: z.string().trim().min(1, \"projectTag must be non-empty when provided\").max(256).optional(),\n /**\n * Historical recall pin (issue #680). ISO 8601 timestamp. The\n * schema only enforces the basic shape; the access service runs\n * `Date.parse` and emits a structured 400 on malformed input\n * (CLAUDE.md rule 51).\n */\n asOf: z.string().trim().min(1, \"asOf must be a non-empty ISO 8601 timestamp\").max(64).optional(),\n /**\n * Free-form recall tag filter (issue #689). When provided, recall results\n * whose frontmatter `tags` do not match the filter are removed before the\n * response is returned. Comparison is case-sensitive exact match.\n */\n tags: z.array(z.string().trim().min(1).max(256)).max(50).optional(),\n /**\n * Match mode for `tags` (issue #689). Defaults to `\"any\"` when `tags` is\n * provided and `tagMatch` is omitted. Ignored when `tags` is absent.\n */\n tagMatch: tagMatchSchema.optional(),\n /**\n * Include graph edges below `graphTraversalConfidenceFloor` for diagnostic\n * recall traversal (issue #681). Defaults to false.\n */\n includeLowConfidence: z.boolean().optional(),\n});\n\nexport const recallExplainRequestSchema = z.object({\n sessionKey: sessionKeySchema,\n namespace: namespaceSchema,\n});\n\n/**\n * Standalone \"set coding context\" request. Used by the HTTP endpoint\n * `POST /engram/v1/coding-context` and the MCP `remnic.set_coding_context`\n * tool (PR 7). `codingContext: null` clears the attached context.\n */\nexport const setCodingContextRequestSchema = z\n .object({\n sessionKey: z.string().trim().min(1, \"sessionKey is required\").max(512),\n codingContext: codingContextSchema.optional(),\n /**\n * Project tag shorthand for non-git-based project scoping. When\n * `codingContext` is omitted, this becomes\n * `{ projectId: \"tag:<projectTag>\", branch: null, rootPath: \"tag:<projectTag>\", defaultBranch: null }`.\n */\n projectTag: z.string().trim().min(1, \"projectTag must be non-empty when provided\").max(256).optional(),\n })\n .superRefine((value, ctx) => {\n if (value.codingContext === undefined && value.projectTag === undefined) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: \"codingContext or projectTag is required\",\n path: [\"codingContext\"],\n });\n }\n });\n\n// ---------------------------------------------------------------------------\n// Observe\n// ---------------------------------------------------------------------------\n\nconst messageSchema = z.object({\n role: z.enum([\"user\", \"assistant\"]),\n content: z.string().min(1, \"message content must be non-empty\"),\n sourceFormat: z\n .enum([\"openai\", \"anthropic\", \"openclaw\", \"pi\", \"lossless-claw\", \"remnic\"])\n .nullable()\n .optional(),\n rawContent: z.unknown().nullable().optional(),\n parts: z\n .array(\n z.object({\n ordinal: z.number().int().min(0).nullable().optional(),\n kind: z.enum([\n \"text\",\n \"tool_call\",\n \"tool_result\",\n \"patch\",\n \"file_read\",\n \"file_write\",\n \"step_start\",\n \"step_finish\",\n \"snapshot\",\n \"retry\",\n ]),\n payload: z.record(z.string(), z.unknown()),\n toolName: z.string().nullable().optional(),\n tool_name: z.string().nullable().optional(),\n filePath: z.string().nullable().optional(),\n file_path: z.string().nullable().optional(),\n createdAt: z.string().nullable().optional(),\n created_at: z.string().nullable().optional(),\n }),\n )\n .nullable()\n .optional(),\n});\n\nexport const observeRequestSchema = z.object({\n sessionKey: z.string().trim().min(1, \"sessionKey is required\").max(512),\n messages: z.array(messageSchema).min(1, \"messages must be a non-empty array\"),\n namespace: namespaceSchema,\n skipExtraction: z.boolean().optional(),\n /**\n * Optional idempotency key for server-side dedup of retried observe POSTs\n * (issue #1649). A retry that reaches the daemon after the first attempt\n * already processed is replayed from cache instead of re-ingested. When the\n * key is reused with a DIFFERENT payload the request is rejected as a\n * conflict (same contract as memory_store/suggestion_submit).\n */\n idempotencyKey: idempotencyKeySchema,\n /** Working directory for auto git-context resolution (issue #569). */\n cwd: z.string().trim().min(1, \"cwd must be non-empty when provided\").max(2048).optional(),\n /**\n * Arbitrary project tag for non-git-based project scoping (issue #569).\n * Creates a coding context with `projectId: \"tag:<projectTag>\"`.\n */\n projectTag: z.string().trim().min(1, \"projectTag must be non-empty when provided\").max(256).optional(),\n});\n\n// ---------------------------------------------------------------------------\n// Memory store / suggestion submit\n// ---------------------------------------------------------------------------\n\nconst writeContentSchema = z.string().min(1, \"content is required\").max(50000);\nconst categorySchema = z\n .enum([\n \"fact\", \"preference\", \"correction\", \"entity\", \"decision\",\n \"relationship\", \"principle\", \"commitment\", \"moment\", \"skill\", \"rule\", \"procedure\",\n \"reasoning_trace\",\n ])\n .optional();\nconst confidenceSchema = z.number().min(0).max(1).optional();\nconst tagsSchema = z.array(z.string().max(256)).max(50).optional();\nconst entityRefSchema = z.string().trim().max(512).optional();\nconst ttlSchema = z.string().trim().max(128).optional();\nconst sourceReasonSchema = z.string().trim().max(2000).optional();\n\nexport const memoryStoreRequestSchema = z.object({\n schemaVersion: schemaVersionSchema,\n idempotencyKey: idempotencyKeySchema,\n dryRun: dryRunSchema,\n sessionKey: sessionKeySchema,\n content: writeContentSchema,\n category: categorySchema,\n confidence: confidenceSchema,\n namespace: namespaceSchema,\n tags: tagsSchema,\n entityRef: entityRefSchema,\n ttl: ttlSchema,\n sourceReason: sourceReasonSchema,\n // Git/project context for project-scoped writes (#1434). When no explicit\n // `namespace` is given, these route the write to the same project namespace\n // recall/observe resolve from `cwd`/`projectTag` (issue #569, rule 42). Also\n // lets MCP clients that auto-inject `cwd` (e.g. Pi MCPorter) call write tools.\n cwd: z.string().trim().min(1, \"cwd must be non-empty when provided\").max(2048).optional(),\n projectTag: z\n .string()\n .trim()\n .min(1, \"projectTag must be non-empty when provided\")\n .max(256)\n .optional(),\n});\n\nexport const suggestionSubmitRequestSchema = memoryStoreRequestSchema;\n\n// ---------------------------------------------------------------------------\n// Review disposition\n// ---------------------------------------------------------------------------\n\nexport const reviewDispositionRequestSchema = z.object({\n memoryId: z.string().trim().min(1, \"memoryId is required\"),\n status: z.enum([\n \"active\", \"pending_review\", \"quarantined\", \"rejected\", \"superseded\", \"archived\",\n ]),\n reasonCode: z.string().trim().min(1, \"reasonCode is required\"),\n namespace: namespaceSchema,\n});\n\n// ---------------------------------------------------------------------------\n// Trust-zone promote\n// ---------------------------------------------------------------------------\n\nexport const trustZonePromoteRequestSchema = z.object({\n recordId: z.string().trim().min(1, \"recordId is required\"),\n targetZone: z.enum([\"working\", \"trusted\"], {\n errorMap: () => ({ message: \"targetZone must be 'working' or 'trusted'\" }),\n }),\n promotionReason: z.string().trim().min(1, \"promotionReason is required\"),\n recordedAt: z.string().trim().optional(),\n summary: z.string().trim().max(5000).optional(),\n dryRun: dryRunSchema,\n namespace: namespaceSchema,\n});\n\n// ---------------------------------------------------------------------------\n// Trust-zone demo-seed\n// ---------------------------------------------------------------------------\n\nexport const trustZoneDemoSeedRequestSchema = z.object({\n scenario: z.string().trim().max(256).optional(),\n recordedAt: z.string().trim().optional(),\n dryRun: dryRunSchema,\n namespace: namespaceSchema,\n});\n\n// ---------------------------------------------------------------------------\n// LCM search\n// ---------------------------------------------------------------------------\n\nexport const lcmSearchRequestSchema = z.object({\n query: z.string().min(1, \"query is required\"),\n sessionKey: sessionKeySchema,\n sessionPrefix: z.string().trim().min(1).max(512).optional(),\n namespace: namespaceSchema,\n limit: z.number().int().min(1).max(100).optional(),\n});\n\nexport const lcmCompactionFlushRequestSchema = z.object({\n sessionKey: z.string().trim().min(1, \"sessionKey is required\").max(512),\n namespace: namespaceSchema,\n});\n\nexport const lcmCompactionRecordRequestSchema = z.object({\n sessionKey: z.string().trim().min(1, \"sessionKey is required\").max(512),\n namespace: namespaceSchema,\n tokensBefore: z.number().int().min(0, \"tokensBefore must be a non-negative integer\"),\n tokensAfter: z.number().int().min(0, \"tokensAfter must be a non-negative integer\"),\n});\n\n// ---------------------------------------------------------------------------\n// Day summary\n// ---------------------------------------------------------------------------\n\nexport const daySummaryRequestSchema = z.object({\n memories: z.string().max(100000).optional(),\n sessionKey: sessionKeySchema,\n namespace: namespaceSchema,\n timeZone: timeZoneSchema.optional(),\n});\n\n// ---------------------------------------------------------------------------\n// Capsule export\n// ---------------------------------------------------------------------------\n\nconst capsuleTopLevelSegmentSchema = z\n .string()\n .trim()\n .min(1)\n .max(128)\n .refine(\n (value) => !value.includes(\"/\") && !value.includes(\"\\\\\"),\n \"must be a top-level directory name without path separators\",\n );\n\nconst capsulePeerIdSchema = z\n .string()\n .trim()\n .min(1)\n .max(256)\n .refine(\n (value) => value !== \".\" && value !== \"..\" && !value.includes(\"/\") && !value.includes(\"\\\\\"),\n \"must be a plain peer id without path separators\",\n );\n\nconst capsuleIsoSinceSchema = z\n .string()\n .trim()\n .min(1, \"since must be a non-empty ISO 8601 timestamp\")\n .max(128)\n .refine(\n isValidCapsuleSince,\n \"since must be a valid ISO 8601 timestamp with no calendar overflow\",\n );\n\nexport const capsuleExportRequestSchema = z\n .object({\n name: z\n .string()\n .trim()\n .min(1, \"name is required\")\n .max(64, \"name must be 64 characters or fewer\")\n .regex(\n CAPSULE_ID_PATTERN,\n \"name must be alphanumeric with single dashes (no spaces, no leading/trailing dashes)\",\n ),\n namespace: namespaceSchema,\n since: capsuleIsoSinceSchema.optional(),\n includeKinds: z.array(capsuleTopLevelSegmentSchema).max(50).optional(),\n peerIds: z.array(capsulePeerIdSchema).max(100).optional(),\n includeTranscripts: z.boolean().optional(),\n encrypt: z.boolean().optional(),\n });\n\nexport const capsuleImportRequestSchema = z\n .object({\n archivePath: z.string().trim().min(1, \"archivePath is required\").max(4096),\n namespace: namespaceSchema,\n mode: z.enum([\"skip\", \"overwrite\", \"fork\"]).optional(),\n passphrase: z.string().min(1, \"passphrase must not be empty\").max(4096).optional(),\n });\n\nexport const capsuleListRequestSchema = z\n .object({\n namespace: namespaceSchema,\n sessionKey: sessionKeySchema,\n });\n\n// ---------------------------------------------------------------------------\n// Offline sync\n// ---------------------------------------------------------------------------\n\nfunction isValidOfflineSyncPath(value: string): boolean {\n try {\n validateArchiveRelativePath(value, \"path\");\n return true;\n } catch {\n return false;\n }\n}\n\nconst offlineSyncPathSchema = z\n .string()\n .trim()\n .min(1, \"path must be non-empty\")\n .max(4096)\n .refine(\n isValidOfflineSyncPath,\n \"path must be a POSIX relative path without unsafe segments\",\n );\n\nconst offlineSyncFileStateSchema = z.object({\n path: offlineSyncPathSchema,\n sha256: z.string().regex(/^[a-f0-9]{64}$/i, \"sha256 must be a 64-character hex digest\"),\n bytes: z.number().int().min(0),\n mtimeMs: z.number().finite().min(0).max(OFFLINE_SYNC_MAX_MTIME_MS),\n});\n\nconst offlineSyncBaseCapturedAtSchema = z\n .string()\n .trim()\n .min(1, \"baseCapturedAt must be non-empty when provided\")\n .max(64)\n .refine((value) => Number.isFinite(Date.parse(value)), {\n message: \"baseCapturedAt must be a valid ISO 8601 timestamp\",\n });\n\nexport const offlineSyncSnapshotRequestSchema = z.object({\n namespace: namespaceSchema,\n includeTranscripts: z.boolean().optional(),\n includeContent: z.boolean().optional(),\n baseCapturedAt: offlineSyncBaseCapturedAtSchema.optional(),\n baseFiles: z\n .array(offlineSyncFileStateSchema)\n .max(300_000, \"baseFiles must contain 300000 or fewer entries\")\n .optional(),\n});\n\nexport const offlineSyncApplyRequestSchema = z\n .object({\n namespace: namespaceSchema,\n changeset: z.unknown(),\n returnCurrentFiles: z.boolean().optional(),\n })\n .refine((value) => value.changeset !== undefined && value.changeset !== null, {\n message: \"changeset is required\",\n path: [\"changeset\"],\n });\n\nexport const offlineSyncFilesRequestSchema = z.object({\n namespace: namespaceSchema,\n includeTranscripts: z.boolean().optional(),\n paths: z\n .array(offlineSyncPathSchema)\n .max(5000, \"paths must contain 5000 or fewer entries\"),\n});\n\nexport const offlineSyncFileContentRequestSchema = z.object({\n namespace: namespaceSchema,\n includeTranscripts: z.boolean().optional(),\n path: offlineSyncPathSchema,\n offset: z.number().int().min(0).optional(),\n length: z.number().int().min(1).max(OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES).optional(),\n});\n\n// ---------------------------------------------------------------------------\n// Action confidence\n// ---------------------------------------------------------------------------\n\nconst nullableOptional = <T extends z.ZodTypeAny>(schema: T) =>\n schema.optional().nullable().transform((value) => value ?? undefined);\n\nconst actionConfidenceRuleSchema = z\n .object({\n kind: z.enum(ACTION_CONFIDENCE_RULE_KINDS),\n description: nullableOptional(z.string().trim().min(1).max(2000)),\n matched: nullableOptional(z.boolean()),\n })\n .strict();\n\nconst actionConfidenceMemorySchema = z\n .object({\n source: nullableOptional(z.string().trim().min(1).max(256)),\n created: nullableOptional(z.string().trim().min(1).max(128)),\n updated: nullableOptional(z.string().trim().min(1).max(128)),\n scope: nullableOptional(z.string().trim().min(1).max(512)),\n userContextScopes: nullableOptional(z.array(z.string().trim().min(1).max(128)).max(50)),\n retrievalReason: nullableOptional(z.string().trim().min(1).max(2000)),\n confidence: nullableOptional(z.number().min(0).max(1)),\n stale: nullableOptional(z.boolean()),\n corrected: nullableOptional(z.boolean()),\n correctionState: nullableOptional(z.enum([\"none\", \"correction\", \"superseded\", \"disputed\", \"forgotten\"])),\n safeToUse: nullableOptional(z.boolean()),\n safety: nullableOptional(z.enum([\"safe\", \"requires-review\", \"blocked\"])),\n safetyReasons: nullableOptional(z.array(z.string().trim().min(1).max(1000)).max(50)),\n })\n .strict();\n\nexport const actionConfidenceRequestSchema = z\n .object({\n intendedAction: nullableOptional(z.string().trim().min(1).max(1000)),\n confidence: nullableOptional(z.number().min(0).max(1)),\n risk: nullableOptional(z.enum(ACTION_CONFIDENCE_RISK_CATEGORIES)),\n contextReadiness: nullableOptional(z.enum(ACTION_CONFIDENCE_CONTEXT_READINESS)),\n currentContextScopes: nullableOptional(z.array(z.string().trim().min(1).max(128)).max(50)),\n userRules: nullableOptional(z.array(actionConfidenceRuleSchema).max(100)),\n retrievedMemories: nullableOptional(z.array(actionConfidenceMemorySchema).max(200)),\n })\n .strict();\n\n// ---------------------------------------------------------------------------\n// Inferred types\n// ---------------------------------------------------------------------------\n\nexport type RecallRequest = z.infer<typeof recallRequestSchema>;\nexport type RecallExplainRequest = z.infer<typeof recallExplainRequestSchema>;\nexport type SetCodingContextRequest = z.infer<typeof setCodingContextRequestSchema>;\nexport type ObserveRequest = z.infer<typeof observeRequestSchema>;\nexport type MemoryStoreRequest = z.infer<typeof memoryStoreRequestSchema>;\nexport type SuggestionSubmitRequest = z.infer<typeof suggestionSubmitRequestSchema>;\nexport type ReviewDispositionRequest = z.infer<typeof reviewDispositionRequestSchema>;\nexport type TrustZonePromoteRequest = z.infer<typeof trustZonePromoteRequestSchema>;\nexport type TrustZoneDemoSeedRequest = z.infer<typeof trustZoneDemoSeedRequestSchema>;\nexport type LcmSearchRequest = z.infer<typeof lcmSearchRequestSchema>;\nexport type LcmCompactionFlushRequest = z.infer<typeof lcmCompactionFlushRequestSchema>;\nexport type LcmCompactionRecordRequest = z.infer<typeof lcmCompactionRecordRequestSchema>;\nexport type DaySummaryRequest = z.infer<typeof daySummaryRequestSchema>;\nexport type CapsuleExportRequest = z.infer<typeof capsuleExportRequestSchema>;\nexport type CapsuleImportRequest = z.infer<typeof capsuleImportRequestSchema>;\nexport type CapsuleListRequest = z.infer<typeof capsuleListRequestSchema>;\nexport type OfflineSyncApplyRequest = z.infer<typeof offlineSyncApplyRequestSchema>;\nexport type OfflineSyncSnapshotRequest = z.infer<typeof offlineSyncSnapshotRequestSchema>;\nexport type OfflineSyncFilesRequest = z.infer<typeof offlineSyncFilesRequestSchema>;\nexport type OfflineSyncFileContentRequest = z.infer<typeof offlineSyncFileContentRequestSchema>;\nexport type ActionConfidenceRequest = z.infer<typeof actionConfidenceRequestSchema>;\n\n// ---------------------------------------------------------------------------\n// Validation helper\n// ---------------------------------------------------------------------------\n\nexport type SchemaName =\n | \"recall\"\n | \"recallExplain\"\n | \"setCodingContext\"\n | \"observe\"\n | \"memoryStore\"\n | \"suggestionSubmit\"\n | \"reviewDisposition\"\n | \"trustZonePromote\"\n | \"trustZoneDemoSeed\"\n | \"lcmSearch\"\n | \"lcmCompactionFlush\"\n | \"lcmCompactionRecord\"\n | \"daySummary\"\n | \"capsuleExport\"\n | \"capsuleImport\"\n | \"capsuleList\"\n | \"offlineSyncSnapshot\"\n | \"offlineSyncFiles\"\n | \"offlineSyncFileContent\"\n | \"offlineSyncApply\"\n | \"actionConfidence\";\n\nexport type SchemaTypeFor<N extends SchemaName> =\n N extends \"recall\" ? RecallRequest\n : N extends \"recallExplain\" ? RecallExplainRequest\n : N extends \"setCodingContext\" ? SetCodingContextRequest\n : N extends \"observe\" ? ObserveRequest\n : N extends \"memoryStore\" ? MemoryStoreRequest\n : N extends \"suggestionSubmit\" ? SuggestionSubmitRequest\n : N extends \"reviewDisposition\" ? ReviewDispositionRequest\n : N extends \"trustZonePromote\" ? TrustZonePromoteRequest\n : N extends \"trustZoneDemoSeed\" ? TrustZoneDemoSeedRequest\n : N extends \"lcmSearch\" ? LcmSearchRequest\n : N extends \"lcmCompactionFlush\" ? LcmCompactionFlushRequest\n : N extends \"lcmCompactionRecord\" ? LcmCompactionRecordRequest\n : N extends \"daySummary\" ? DaySummaryRequest\n : N extends \"capsuleExport\" ? CapsuleExportRequest\n : N extends \"capsuleImport\" ? CapsuleImportRequest\n : N extends \"capsuleList\" ? CapsuleListRequest\n : N extends \"offlineSyncSnapshot\" ? OfflineSyncSnapshotRequest\n : N extends \"offlineSyncFiles\" ? OfflineSyncFilesRequest\n : N extends \"offlineSyncFileContent\" ? OfflineSyncFileContentRequest\n : N extends \"offlineSyncApply\" ? OfflineSyncApplyRequest\n : N extends \"actionConfidence\" ? ActionConfidenceRequest\n : never;\n\nconst schemas: Record<SchemaName, z.ZodTypeAny> = {\n recall: recallRequestSchema,\n recallExplain: recallExplainRequestSchema,\n setCodingContext: setCodingContextRequestSchema,\n observe: observeRequestSchema,\n memoryStore: memoryStoreRequestSchema,\n suggestionSubmit: suggestionSubmitRequestSchema,\n reviewDisposition: reviewDispositionRequestSchema,\n trustZonePromote: trustZonePromoteRequestSchema,\n trustZoneDemoSeed: trustZoneDemoSeedRequestSchema,\n lcmSearch: lcmSearchRequestSchema,\n lcmCompactionFlush: lcmCompactionFlushRequestSchema,\n lcmCompactionRecord: lcmCompactionRecordRequestSchema,\n daySummary: daySummaryRequestSchema,\n capsuleExport: capsuleExportRequestSchema,\n capsuleImport: capsuleImportRequestSchema,\n capsuleList: capsuleListRequestSchema,\n offlineSyncSnapshot: offlineSyncSnapshotRequestSchema,\n offlineSyncFiles: offlineSyncFilesRequestSchema,\n offlineSyncFileContent: offlineSyncFileContentRequestSchema,\n offlineSyncApply: offlineSyncApplyRequestSchema,\n actionConfidence: actionConfidenceRequestSchema,\n};\n\n/**\n * Validate a request body against the named schema.\n * Returns `{ success: true, data }` on pass or\n * `{ success: false, error }` on failure with field-level detail.\n */\nexport function validateRequest<T = unknown>(\n schemaName: SchemaName,\n body: unknown,\n): { success: true; data: T } | { success: false; error: SchemaValidationError } {\n const schema = schemas[schemaName];\n if (!schema) {\n return {\n success: false,\n error: {\n error: `unknown schema: ${schemaName}`,\n code: \"validation_error\",\n details: [],\n },\n };\n }\n const result = schema.safeParse(body);\n if (result.success) {\n return { success: true, data: result.data as T };\n }\n return { success: false, error: formatZodError(result.error) };\n}\n"],"mappings":"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","names":[]}
@@ -1,544 +0,0 @@
1
- // ---------------------------------------------------------------------------
2
- // Off-thread archive scoring for the cold-fallback recall path (issue #1674).
3
- //
4
- // `searchLongTermArchiveFallback` (orchestrator.ts) falls back to scanning
5
- // EVERY archived memory file when hybrid/vector search returns zero hits.
6
- // The scoring loop — for each memory × for each token, `haystack.includes(token)`
7
- // — is fully synchronous, unbounded, and CPU-bound. Under concurrent recall
8
- // load this monopolized the JS main thread: N concurrent recalls serialized
9
- // on one core and each blew past the client-side timeout even though total
10
- // CPU work would have finished comfortably if parallelized.
11
- //
12
- // This module extracts the scoring loop into a pure function and provides two
13
- // strategies:
14
- //
15
- // 1. `SyncArchiveScoring` — runs the pure function on the calling thread
16
- // (the OLD behavior; preserved for prove-fail
17
- // tests and as the graceful fallback).
18
- // 2. `OffThreadArchiveScoring` — dispatches the pure function to a
19
- // `worker_threads` pool so concurrent recalls
20
- // run on separate cores instead of serializing
21
- // on the main thread. Falls back to sync if
22
- // workers cannot be created.
23
- //
24
- // Both strategies share the identical `scoreArchiveMemories` pure function,
25
- // so the scoring semantics are byte-identical regardless of which path runs.
26
- // ---------------------------------------------------------------------------
27
-
28
- import os from "node:os";
29
- import { Worker } from "node:worker_threads";
30
- import { log } from "../logger.js";
31
- import type { MemoryFile } from "../types.js";
32
-
33
- // ─────────────────────────────────────────────────────────────────────────────
34
- // Wire types — plain-serializable shapes that cross the worker boundary via
35
- // structured clone. Only the fields the scoring loop reads are included.
36
- // ─────────────────────────────────────────────────────────────────────────────
37
-
38
- /** Minimal serializable projection of {@link MemoryFile} for scoring. */
39
- export interface ArchiveScoreItem {
40
- id: string;
41
- path: string;
42
- content: string;
43
- category: string;
44
- tags: string[];
45
- }
46
-
47
- /** Scoring output — maps 1:1 to the relevant QmdSearchResult fields. */
48
- export interface ArchiveScoreResult {
49
- docid: string;
50
- path: string;
51
- score: number;
52
- snippet: string;
53
- }
54
-
55
- /** Worker request envelope. */
56
- interface ScoreTask {
57
- items: ArchiveScoreItem[];
58
- tokens: string[];
59
- }
60
-
61
- /** Worker reply envelope. */
62
- type ScoreReply = { ok: true; results: ArchiveScoreResult[] } | { ok: false; error: string };
63
-
64
- // ─────────────────────────────────────────────────────────────────────────────
65
- // Pure scoring function — shared by both strategies and by the inline worker.
66
- // Extracted verbatim from the original inline loop in
67
- // `searchLongTermArchiveFallback` so behavior is identical.
68
- // ─────────────────────────────────────────────────────────────────────────────
69
-
70
- /**
71
- * Score archived memories against query tokens using substring overlap.
72
- *
73
- * For each memory, builds a lowercase haystack from `[content, category, ...tags]`,
74
- * counts how many distinct tokens appear in it, and scores by `hits / tokens.length`.
75
- * Memories with zero hits are dropped. Snippets are the first 400 chars of content
76
- * with newlines collapsed to spaces — matching the original orchestrator behavior.
77
- *
78
- * This function is intentionally synchronous and CPU-bound; that is precisely
79
- * why the off-thread strategy exists.
80
- */
81
- export function scoreArchiveMemories(
82
- items: ReadonlyArray<ArchiveScoreItem>,
83
- tokens: ReadonlyArray<string>
84
- ): ArchiveScoreResult[] {
85
- if (items.length === 0 || tokens.length === 0) return [];
86
-
87
- const scored: ArchiveScoreResult[] = [];
88
- for (const item of items) {
89
- const haystack = [item.content, item.category, ...item.tags].join(" ").toLowerCase();
90
- let hits = 0;
91
- for (const token of tokens) {
92
- if (haystack.includes(token)) hits += 1;
93
- }
94
- if (hits === 0) continue;
95
- scored.push({
96
- docid: item.id,
97
- path: item.path,
98
- score: hits / tokens.length,
99
- snippet: item.content.slice(0, 400).replace(/\n/g, " "),
100
- });
101
- }
102
- return scored;
103
- }
104
-
105
- /**
106
- * Project a {@link MemoryFile} into the minimal serializable shape the scoring
107
- * function consumes. Called on the main thread BEFORE dispatching to a worker
108
- * so the heavy `MemoryFrontmatter` (dozens of optional fields, nested objects)
109
- * never crosses the worker boundary.
110
- */
111
- export function memoryFileToScoreItem(memory: MemoryFile): ArchiveScoreItem {
112
- return {
113
- id: memory.frontmatter.id,
114
- path: memory.path,
115
- content: memory.content,
116
- category: memory.frontmatter.category,
117
- tags: memory.frontmatter.tags ?? [],
118
- };
119
- }
120
-
121
- // ─────────────────────────────────────────────────────────────────────────────
122
- // Strategy interface
123
- // ─────────────────────────────────────────────────────────────────────────────
124
-
125
- /**
126
- * Pluggable scoring backend. The orchestrator holds one instance and calls
127
- * `score()` from the cold-fallback path. The default is off-thread; tests and
128
- * restricted environments can swap in the sync strategy.
129
- */
130
- export interface ArchiveScoringStrategy {
131
- score(
132
- items: ReadonlyArray<ArchiveScoreItem>,
133
- tokens: ReadonlyArray<string>,
134
- abortSignal?: AbortSignal
135
- ): Promise<ArchiveScoreResult[]>;
136
- }
137
-
138
- // ─────────────────────────────────────────────────────────────────────────────
139
- // 1. SyncArchiveScoring — the OLD serialized behavior, preserved for fallback
140
- // ─────────────────────────────────────────────────────────────────────────────
141
-
142
- /**
143
- * Runs the scoring loop synchronously on the calling thread.
144
- *
145
- * This is the exact behavior that caused issue #1674: the synchronous loop
146
- * blocks the event loop for its entire duration, so concurrent recall
147
- * requests serialize behind each other. It is retained as the graceful
148
- * fallback when worker_threads are unavailable, and as the prove-fail
149
- * baseline in regression tests.
150
- */
151
- export class SyncArchiveScoring implements ArchiveScoringStrategy {
152
- async score(
153
- items: ReadonlyArray<ArchiveScoreItem>,
154
- tokens: ReadonlyArray<string>,
155
- abortSignal?: AbortSignal
156
- ): Promise<ArchiveScoreResult[]> {
157
- if (items.length === 0 || tokens.length === 0) return [];
158
- if (abortSignal?.aborted) return [];
159
- // Process in chunks so an abort during a large archive scan is observed
160
- // without burning the full synchronous CPU pass (#1674 review: sync
161
- // fallback should check mid-scoring abort, like the old inline loop).
162
- const CHUNK = 500;
163
- if (items.length <= CHUNK) return scoreArchiveMemories(items, tokens);
164
- const results: ArchiveScoreResult[] = [];
165
- for (let i = 0; i < items.length; i += CHUNK) {
166
- if (abortSignal?.aborted) return [];
167
- const scored = scoreArchiveMemories(items.slice(i, i + CHUNK), tokens);
168
- for (const r of scored) results.push(r);
169
- }
170
- return results;
171
- }
172
- }
173
-
174
- // ─────────────────────────────────────────────────────────────────────────────
175
- // Inline worker code (eval mode) — eliminates file-resolution / build-config
176
- // issues entirely. The worker is self-contained CJS (no imports), so it runs
177
- // identically under tsx, compiled dist, and published npm packages.
178
- // ─────────────────────────────────────────────────────────────────────────────
179
-
180
- /**
181
- * Inline worker source. Runs via `new Worker(code, { eval: true })`.
182
- *
183
- * MUST stay byte-identical to {@link scoreArchiveMemories} above. The
184
- * regression test "worker scoring matches canonical scoreArchiveMemories"
185
- * asserts this equivalence at runtime.
186
- */
187
- const WORKER_SOURCE = String.raw`
188
- const { parentPort } = require('node:worker_threads');
189
-
190
- function scoreArchiveMemories(items, tokens) {
191
- if (items.length === 0 || tokens.length === 0) return [];
192
- var scored = [];
193
- for (var i = 0; i < items.length; i++) {
194
- var item = items[i];
195
- var haystack = [item.content, item.category].concat(item.tags || []).join(' ').toLowerCase();
196
- var hits = 0;
197
- for (var j = 0; j < tokens.length; j++) {
198
- if (haystack.indexOf(tokens[j]) !== -1) hits++;
199
- }
200
- if (hits === 0) continue;
201
- scored.push({
202
- docid: item.id,
203
- path: item.path,
204
- score: hits / tokens.length,
205
- snippet: item.content.slice(0, 400).replace(/\n/g, ' '),
206
- });
207
- }
208
- return scored;
209
- }
210
-
211
- if (parentPort) {
212
- parentPort.on('message', function(task) {
213
- try {
214
- var results = scoreArchiveMemories(task.items, task.tokens);
215
- parentPort.postMessage({ ok: true, results: results });
216
- } catch (err) {
217
- parentPort.postMessage({ ok: false, error: err && err.message ? err.message : String(err) });
218
- }
219
- });
220
- }
221
- `;
222
-
223
- // ─────────────────────────────────────────────────────────────────────────────
224
- // 2. OffThreadArchiveScoring — worker pool for genuine multi-core parallelism
225
- // ─────────────────────────────────────────────────────────────────────────────
226
-
227
- /**
228
- * Default worker pool size. Uses `availableParallelism()` (Node 19.4+) minus
229
- * one so the main thread always has a dedicated core for I/O dispatch. Capped
230
- * at 8 to bound memory overhead (each worker has its own V8 heap).
231
- */
232
- function defaultPoolSize(): number {
233
- const cpus = typeof os.availableParallelism === "function" ? os.availableParallelism() : os.cpus().length;
234
- return Math.max(1, Math.min(Math.max(1, cpus - 1), 8));
235
- }
236
-
237
- /**
238
- * Safety-net timeout for a single dispatch. The cold-fallback pipeline already
239
- * has its own deadline mechanism (runColdStepWithinDeadline); this is a
240
- * last-resort guard so a hung worker never blocks recall indefinitely.
241
- * Generously large to avoid interfering with large corpora (issue #1674
242
- * reported scans up to ~70s on large archives).
243
- */
244
- const DISPATCH_TIMEOUT_MS = 120_000;
245
-
246
- /** Lazy worker pool. Workers are created on first use and recycled. */
247
- class ArchiveScoringWorkerPool {
248
- private readonly targetSize: number;
249
- private workers: Worker[] = [];
250
- private idle: Worker[] = [];
251
- private waiters: Array<{ resolve: (worker: Worker) => void; reject: (err: Error) => void }> = [];
252
- private terminated = false;
253
- private busy = 0;
254
-
255
- /**
256
- * Workers currently checked out and scoring — NOT callers waiting in line.
257
- * A caller parked in `acquire()` is queued, not running, so this is the only
258
- * honest measure of real task overlap: with a size-1 pool it never exceeds 1
259
- * no matter how many callers are queued behind it.
260
- */
261
- get busyWorkers(): number {
262
- return this.busy;
263
- }
264
-
265
- constructor(size: number = defaultPoolSize()) {
266
- this.targetSize = Math.max(1, size);
267
- }
268
-
269
- async run(task: ScoreTask, abortSignal?: AbortSignal): Promise<ArchiveScoreResult[]> {
270
- if (this.terminated) throw new Error("archive-scoring pool terminated");
271
- const worker = await this.acquire(abortSignal);
272
- // If the caller already aborted before dispatch, return the worker to idle
273
- // instead of retiring it — it was never posted to (#1674).
274
- if (abortSignal?.aborted) {
275
- this.release(worker);
276
- return [];
277
- }
278
- let abandoned = false;
279
- this.busy += 1;
280
- try {
281
- return await this.dispatch(worker, task, abortSignal, () => {
282
- abandoned = true;
283
- });
284
- } finally {
285
- this.busy -= 1;
286
- if (abandoned) this.retireWorker(worker);
287
- else this.release(worker);
288
- }
289
- }
290
-
291
- async terminate(): Promise<void> {
292
- if (this.terminated) return;
293
- this.terminated = true;
294
- // Reject all queued waiters so they don't hang indefinitely (#1674).
295
- const queued = this.waiters;
296
- this.waiters = [];
297
- for (const w of queued) w.reject(new Error("archive-scoring pool terminated"));
298
- const all = [...this.workers];
299
- this.workers = [];
300
- this.idle = [];
301
- await Promise.allSettled(all.map((w) => w.terminate()));
302
- }
303
-
304
- private async acquire(abortSignal?: AbortSignal): Promise<Worker> {
305
- const idle = this.idle.pop();
306
- if (idle) return idle;
307
- if (this.workers.length < this.targetSize) return this.spawn();
308
- // Park until a worker is released. If the caller aborts (or the pool
309
- // terminates) while queued, reject so the recall falls back to sync
310
- // instead of consuming a worker for a request that already timed out.
311
- return new Promise<Worker>((resolve, reject) => {
312
- const entry = { resolve, reject };
313
- this.waiters.push(entry);
314
- if (!abortSignal) return;
315
- const onAbort = () => {
316
- const idx = this.waiters.indexOf(entry);
317
- if (idx !== -1) this.waiters.splice(idx, 1);
318
- reject(new Error("archive-scoring acquire aborted"));
319
- };
320
- if (abortSignal.aborted) { onAbort(); return; }
321
- abortSignal.addEventListener("abort", onAbort, { once: true });
322
- });
323
- }
324
-
325
- private release(worker: Worker): void {
326
- const next = this.waiters.shift();
327
- if (next) {
328
- next.resolve(worker);
329
- } else if (!this.terminated) {
330
- this.idle.push(worker);
331
- } else {
332
- void worker.terminate();
333
- }
334
- }
335
-
336
- /** Terminate a worker that may still be busy, then spawn a replacement
337
- * if a waiter is queued. */
338
- private retireWorker(worker: Worker): void {
339
- const idx = this.workers.indexOf(worker);
340
- if (idx !== -1) this.workers.splice(idx, 1);
341
- void worker.terminate();
342
- const next = this.waiters.shift();
343
- if (next) next.resolve(this.spawn());
344
- }
345
-
346
- private spawn(): Worker {
347
- const worker = new Worker(WORKER_SOURCE, { eval: true });
348
- // Unref so idle workers never keep the event loop alive (#1674).
349
- worker.unref();
350
- this.workers.push(worker);
351
- return worker;
352
- }
353
-
354
- private dispatch(
355
- worker: Worker,
356
- task: ScoreTask,
357
- abortSignal: AbortSignal | undefined,
358
- onAbandon: () => void
359
- ): Promise<ArchiveScoreResult[]> {
360
- return new Promise<ArchiveScoreResult[]>((resolve, reject) => {
361
- let settled = false;
362
- const timer = setTimeout(() => {
363
- if (settled) return;
364
- settled = true;
365
- cleanup();
366
- onAbandon();
367
- log.debug(`archive-scoring dispatch timed out after ${DISPATCH_TIMEOUT_MS}ms — falling back to sync`);
368
- reject(new Error(`archive-scoring dispatch timed out after ${DISPATCH_TIMEOUT_MS}ms`));
369
- }, DISPATCH_TIMEOUT_MS);
370
-
371
- const onMessage = (reply: ScoreReply) => {
372
- if (settled) return;
373
- settled = true;
374
- cleanup();
375
- if (reply.ok) resolve(reply.results);
376
- else reject(new Error(reply.error));
377
- };
378
- const onError = (err: Error) => {
379
- if (settled) return;
380
- settled = true;
381
- cleanup();
382
- onAbandon();
383
- reject(err);
384
- };
385
- // worker.terminate() ends via 'exit', not 'error' — listen so in-flight
386
- // dispatches during pool shutdown reject immediately instead of hanging
387
- // until the 120s timeout (#1674).
388
- const onExit = (code: number) => {
389
- if (settled) return;
390
- settled = true;
391
- cleanup();
392
- onAbandon();
393
- reject(new Error(`archive-scoring worker exited with code ${code}`));
394
- };
395
- const onAbort = () => {
396
- if (settled) return;
397
- settled = true;
398
- cleanup();
399
- onAbandon();
400
- resolve([]);
401
- };
402
-
403
- const cleanup = () => {
404
- clearTimeout(timer);
405
- worker.off("message", onMessage);
406
- worker.off("error", onError);
407
- worker.off("exit", onExit);
408
- abortSignal?.removeEventListener("abort", onAbort);
409
- };
410
-
411
- worker.on("message", onMessage);
412
- worker.on("error", onError);
413
- worker.on("exit", onExit);
414
- abortSignal?.addEventListener("abort", onAbort, { once: true });
415
- worker.postMessage(task);
416
- });
417
- }
418
- }
419
-
420
- /**
421
- * Off-thread scoring via a `worker_threads` pool.
422
- *
423
- * Concurrent `score()` calls are dispatched to separate workers, giving
424
- * genuine multi-core parallelism: K concurrent recalls run on K cores
425
- * instead of serializing on the main JS thread. If the pool cannot be
426
- * created (e.g. restricted runtime), it transparently falls back to
427
- * {@link SyncArchiveScoring} so recall never breaks.
428
- */
429
- export class OffThreadArchiveScoring implements ArchiveScoringStrategy {
430
- private pool: ArchiveScoringWorkerPool | null = null;
431
- private poolFailed = false;
432
- private readonly syncFallback = new SyncArchiveScoring();
433
-
434
- constructor(poolSize?: number) {
435
- if (poolSize !== undefined) {
436
- this.pool = new ArchiveScoringWorkerPool(poolSize);
437
- }
438
- }
439
-
440
- /** Workers currently scoring; 0 when no pool has been created yet. */
441
- get busyWorkers(): number {
442
- return this.pool?.busyWorkers ?? 0;
443
- }
444
-
445
- async score(
446
- items: ReadonlyArray<ArchiveScoreItem>,
447
- tokens: ReadonlyArray<string>,
448
- abortSignal?: AbortSignal
449
- ): Promise<ArchiveScoreResult[]> {
450
- if (items.length === 0 || tokens.length === 0) return [];
451
- if (abortSignal?.aborted) return [];
452
-
453
- // Lazy pool init — workers are only created when the cold-fallback path
454
- // is first hit, so hot-path recall pays zero overhead.
455
- if (this.pool === null && !this.poolFailed) {
456
- try {
457
- this.pool = new ArchiveScoringWorkerPool();
458
- } catch (err) {
459
- this.poolFailed = true;
460
- log.debug(`archive-scoring: worker pool unavailable, using sync fallback — ${(err as Error).message}`);
461
- }
462
- }
463
-
464
- if (this.pool !== null) {
465
- const dispatchStart = Date.now();
466
- try {
467
- const task: ScoreTask = {
468
- items: items as ArchiveScoreItem[],
469
- tokens: tokens as string[],
470
- };
471
- const results = await this.pool.run(task, abortSignal);
472
- if (abortSignal?.aborted) return [];
473
- return results;
474
- } catch (err) {
475
- // Timeout or worker error — fall back to sync scoring so recall
476
- // quality is never silently dropped. An already-aborted signal
477
- // short-circuits first. If the dispatch consumed most of the timeout
478
- // budget (genuine timeout, not a fast error), skip the sync rescore —
479
- // the recall deadline has very likely expired by then (#1674).
480
- if (abortSignal?.aborted) return [];
481
- if (Date.now() - dispatchStart > DISPATCH_TIMEOUT_MS * 0.5) return [];
482
- log.debug(`archive-scoring: worker dispatch failed, using sync fallback — ${(err as Error).message}`);
483
- }
484
- }
485
-
486
- return this.syncFallback.score(items, tokens, abortSignal);
487
- }
488
-
489
- /** @internal — terminate the underlying pool (tests / shutdown). */
490
- async terminate(): Promise<void> {
491
- if (this.pool !== null) {
492
- await this.pool.terminate();
493
- this.pool = null;
494
- }
495
- }
496
- }
497
-
498
- // ─────────────────────────────────────────────────────────────────────────────
499
- // Factory + process-wide default
500
- // ─────────────────────────────────────────────────────────────────────────────
501
-
502
- let defaultStrategy: ArchiveScoringStrategy | null = null;
503
-
504
- /**
505
- * Process-wide default archive-scoring strategy. Lazily creates an
506
- * {@link OffThreadArchiveScoring} on first use. All orchestrator instances
507
- * share one pool — a single daemon serves all concurrent sessions, so one
508
- * shared pool is the correct sizing unit.
509
- */
510
- export function getDefaultArchiveScoring(): ArchiveScoringStrategy {
511
- if (defaultStrategy === null) {
512
- defaultStrategy = new OffThreadArchiveScoring();
513
- }
514
- return defaultStrategy;
515
- }
516
-
517
- /**
518
- * Dispose the process-wide default archive-scoring strategy, terminating any
519
- * worker threads. Called from `Orchestrator.destroy()` so worker threads don't
520
- * outlive the orchestrator (#1674). The strategy is lazily recreated on the
521
- * next cold-fallback recall, so this is safe to call from tests that create
522
- * and destroy orchestrator instances.
523
- */
524
- export async function disposeDefaultArchiveScoring(): Promise<void> {
525
- if (defaultStrategy !== null) {
526
- const strategy = defaultStrategy;
527
- defaultStrategy = null;
528
- if (strategy instanceof OffThreadArchiveScoring) {
529
- await strategy.terminate();
530
- }
531
- }
532
- }
533
-
534
- /**
535
- * Create a fresh strategy instance (for tests that need isolation or
536
- * explicit control over pool size / sync vs off-thread).
537
- */
538
- export function createArchiveScoring(opts?: {
539
- poolSize?: number;
540
- sync?: boolean;
541
- }): ArchiveScoringStrategy {
542
- if (opts?.sync) return new SyncArchiveScoring();
543
- return new OffThreadArchiveScoring(opts?.poolSize);
544
- }