hippo-memory 0.36.0 → 0.37.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 (199) hide show
  1. package/README.md +16 -0
  2. package/dist/api.d.ts +20 -0
  3. package/dist/api.d.ts.map +1 -1
  4. package/dist/api.js +23 -3
  5. package/dist/api.js.map +1 -1
  6. package/dist/benchmarks/e1.3/incident-recall-eval.js +74 -0
  7. package/dist/benchmarks/e1.3/incident-recall-eval.js.map +1 -0
  8. package/dist/benchmarks/e1.3/scenarios.json +2587 -0
  9. package/dist/benchmarks/e1.3/slack-1000-event-smoke.js +102 -0
  10. package/dist/benchmarks/e1.3/slack-1000-event-smoke.js.map +1 -0
  11. package/dist/cli.js +82 -0
  12. package/dist/cli.js.map +1 -1
  13. package/dist/connectors/slack/backfill.d.ts +42 -0
  14. package/dist/connectors/slack/backfill.d.ts.map +1 -0
  15. package/dist/connectors/slack/backfill.js +76 -0
  16. package/dist/connectors/slack/backfill.js.map +1 -0
  17. package/dist/connectors/slack/deletion.d.ts +14 -0
  18. package/dist/connectors/slack/deletion.d.ts.map +1 -0
  19. package/dist/connectors/slack/deletion.js +46 -0
  20. package/dist/connectors/slack/deletion.js.map +1 -0
  21. package/dist/connectors/slack/dlq.d.ts +21 -0
  22. package/dist/connectors/slack/dlq.d.ts.map +1 -0
  23. package/dist/connectors/slack/dlq.js +23 -0
  24. package/dist/connectors/slack/dlq.js.map +1 -0
  25. package/dist/connectors/slack/idempotency.d.ts +5 -0
  26. package/dist/connectors/slack/idempotency.d.ts.map +1 -0
  27. package/dist/connectors/slack/idempotency.js +13 -0
  28. package/dist/connectors/slack/idempotency.js.map +1 -0
  29. package/dist/connectors/slack/ingest.d.ts +27 -0
  30. package/dist/connectors/slack/ingest.d.ts.map +1 -0
  31. package/dist/connectors/slack/ingest.js +48 -0
  32. package/dist/connectors/slack/ingest.js.map +1 -0
  33. package/dist/connectors/slack/ratelimit.d.ts +9 -0
  34. package/dist/connectors/slack/ratelimit.d.ts.map +1 -0
  35. package/dist/connectors/slack/ratelimit.js +18 -0
  36. package/dist/connectors/slack/ratelimit.js.map +1 -0
  37. package/dist/connectors/slack/scope.d.ts +16 -0
  38. package/dist/connectors/slack/scope.d.ts.map +1 -0
  39. package/dist/connectors/slack/scope.js +13 -0
  40. package/dist/connectors/slack/scope.js.map +1 -0
  41. package/dist/connectors/slack/signature.d.ts +12 -0
  42. package/dist/connectors/slack/signature.d.ts.map +1 -0
  43. package/dist/connectors/slack/signature.js +20 -0
  44. package/dist/connectors/slack/signature.js.map +1 -0
  45. package/dist/connectors/slack/tenant-routing.d.ts +13 -0
  46. package/dist/connectors/slack/tenant-routing.d.ts.map +1 -0
  47. package/dist/connectors/slack/tenant-routing.js +17 -0
  48. package/dist/connectors/slack/tenant-routing.js.map +1 -0
  49. package/dist/connectors/slack/transform.d.ts +20 -0
  50. package/dist/connectors/slack/transform.d.ts.map +1 -0
  51. package/dist/connectors/slack/transform.js +31 -0
  52. package/dist/connectors/slack/transform.js.map +1 -0
  53. package/dist/connectors/slack/types.d.ts +35 -0
  54. package/dist/connectors/slack/types.d.ts.map +1 -0
  55. package/dist/connectors/slack/types.js +23 -0
  56. package/dist/connectors/slack/types.js.map +1 -0
  57. package/dist/connectors/slack/web-client.d.ts +12 -0
  58. package/dist/connectors/slack/web-client.d.ts.map +1 -0
  59. package/dist/connectors/slack/web-client.js +43 -0
  60. package/dist/connectors/slack/web-client.js.map +1 -0
  61. package/dist/db.d.ts.map +1 -1
  62. package/dist/db.js +46 -1
  63. package/dist/db.js.map +1 -1
  64. package/dist/importers.js +3 -3
  65. package/dist/importers.js.map +1 -1
  66. package/dist/mcp/server.js +1 -1
  67. package/dist/server.d.ts.map +1 -1
  68. package/dist/server.js +174 -2
  69. package/dist/server.js.map +1 -1
  70. package/dist/src/ambient.js +147 -0
  71. package/dist/src/ambient.js.map +1 -0
  72. package/dist/src/api.js +343 -0
  73. package/dist/src/api.js.map +1 -0
  74. package/dist/src/audit.js +152 -0
  75. package/dist/src/audit.js.map +1 -0
  76. package/dist/src/auth.js +65 -0
  77. package/dist/src/auth.js.map +1 -0
  78. package/dist/src/autolearn.js +143 -0
  79. package/dist/src/autolearn.js.map +1 -0
  80. package/dist/src/capture.js +512 -0
  81. package/dist/src/capture.js.map +1 -0
  82. package/dist/src/cli.js +4971 -0
  83. package/dist/src/cli.js.map +1 -0
  84. package/dist/src/client.js +181 -0
  85. package/dist/src/client.js.map +1 -0
  86. package/dist/src/config.js +108 -0
  87. package/dist/src/config.js.map +1 -0
  88. package/dist/src/connectors/slack/backfill.js +76 -0
  89. package/dist/src/connectors/slack/backfill.js.map +1 -0
  90. package/dist/src/connectors/slack/deletion.js +46 -0
  91. package/dist/src/connectors/slack/deletion.js.map +1 -0
  92. package/dist/src/connectors/slack/dlq.js +23 -0
  93. package/dist/src/connectors/slack/dlq.js.map +1 -0
  94. package/dist/src/connectors/slack/idempotency.js +13 -0
  95. package/dist/src/connectors/slack/idempotency.js.map +1 -0
  96. package/dist/src/connectors/slack/ingest.js +48 -0
  97. package/dist/src/connectors/slack/ingest.js.map +1 -0
  98. package/dist/src/connectors/slack/ratelimit.js +18 -0
  99. package/dist/src/connectors/slack/ratelimit.js.map +1 -0
  100. package/dist/src/connectors/slack/scope.js +13 -0
  101. package/dist/src/connectors/slack/scope.js.map +1 -0
  102. package/dist/src/connectors/slack/signature.js +20 -0
  103. package/dist/src/connectors/slack/signature.js.map +1 -0
  104. package/dist/src/connectors/slack/tenant-routing.js +17 -0
  105. package/dist/src/connectors/slack/tenant-routing.js.map +1 -0
  106. package/dist/src/connectors/slack/transform.js +31 -0
  107. package/dist/src/connectors/slack/transform.js.map +1 -0
  108. package/dist/src/connectors/slack/types.js +23 -0
  109. package/dist/src/connectors/slack/types.js.map +1 -0
  110. package/dist/src/connectors/slack/web-client.js +43 -0
  111. package/dist/src/connectors/slack/web-client.js.map +1 -0
  112. package/dist/src/consolidate.js +517 -0
  113. package/dist/src/consolidate.js.map +1 -0
  114. package/dist/src/dag.js +104 -0
  115. package/dist/src/dag.js.map +1 -0
  116. package/dist/src/dashboard.js +409 -0
  117. package/dist/src/dashboard.js.map +1 -0
  118. package/dist/src/db.js +584 -0
  119. package/dist/src/db.js.map +1 -0
  120. package/dist/src/embeddings.js +344 -0
  121. package/dist/src/embeddings.js.map +1 -0
  122. package/dist/src/eval-suite.js +289 -0
  123. package/dist/src/eval-suite.js.map +1 -0
  124. package/dist/src/eval.js +187 -0
  125. package/dist/src/eval.js.map +1 -0
  126. package/dist/src/extract.js +87 -0
  127. package/dist/src/extract.js.map +1 -0
  128. package/dist/src/handoff.js +30 -0
  129. package/dist/src/handoff.js.map +1 -0
  130. package/dist/src/hooks.js +582 -0
  131. package/dist/src/hooks.js.map +1 -0
  132. package/dist/src/importers.js +399 -0
  133. package/dist/src/importers.js.map +1 -0
  134. package/dist/src/index.js +25 -0
  135. package/dist/src/index.js.map +1 -0
  136. package/dist/src/invalidation.js +94 -0
  137. package/dist/src/invalidation.js.map +1 -0
  138. package/dist/src/mcp/framing.js +45 -0
  139. package/dist/src/mcp/framing.js.map +1 -0
  140. package/dist/src/mcp/server.js +510 -0
  141. package/dist/src/mcp/server.js.map +1 -0
  142. package/dist/src/memory.js +280 -0
  143. package/dist/src/memory.js.map +1 -0
  144. package/dist/src/multihop.js +32 -0
  145. package/dist/src/multihop.js.map +1 -0
  146. package/dist/src/path-context.js +32 -0
  147. package/dist/src/path-context.js.map +1 -0
  148. package/dist/src/physics-config.js +26 -0
  149. package/dist/src/physics-config.js.map +1 -0
  150. package/dist/src/physics-state.js +163 -0
  151. package/dist/src/physics-state.js.map +1 -0
  152. package/dist/src/physics.js +361 -0
  153. package/dist/src/physics.js.map +1 -0
  154. package/dist/src/postinstall.js +68 -0
  155. package/dist/src/postinstall.js.map +1 -0
  156. package/dist/src/raw-archive.js +72 -0
  157. package/dist/src/raw-archive.js.map +1 -0
  158. package/dist/src/refine-llm.js +147 -0
  159. package/dist/src/refine-llm.js.map +1 -0
  160. package/dist/src/replay.js +117 -0
  161. package/dist/src/replay.js.map +1 -0
  162. package/dist/src/salience.js +74 -0
  163. package/dist/src/salience.js.map +1 -0
  164. package/dist/src/scheduler.js +67 -0
  165. package/dist/src/scheduler.js.map +1 -0
  166. package/dist/src/scope.js +35 -0
  167. package/dist/src/scope.js.map +1 -0
  168. package/dist/src/search.js +801 -0
  169. package/dist/src/search.js.map +1 -0
  170. package/dist/src/server-detect.js +70 -0
  171. package/dist/src/server-detect.js.map +1 -0
  172. package/dist/src/server.js +784 -0
  173. package/dist/src/server.js.map +1 -0
  174. package/dist/src/shared.js +309 -0
  175. package/dist/src/shared.js.map +1 -0
  176. package/dist/src/sso.js +22 -0
  177. package/dist/src/sso.js.map +1 -0
  178. package/dist/src/store.js +1390 -0
  179. package/dist/src/store.js.map +1 -0
  180. package/dist/src/tenant.js +17 -0
  181. package/dist/src/tenant.js.map +1 -0
  182. package/dist/src/trace.js +64 -0
  183. package/dist/src/trace.js.map +1 -0
  184. package/dist/src/working-memory.js +149 -0
  185. package/dist/src/working-memory.js.map +1 -0
  186. package/dist/src/yaml.js +98 -0
  187. package/dist/src/yaml.js.map +1 -0
  188. package/dist/store.d.ts +9 -1
  189. package/dist/store.d.ts.map +1 -1
  190. package/dist/store.js +30 -2
  191. package/dist/store.js.map +1 -1
  192. package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
  193. package/extensions/openclaw-plugin/package.json +1 -1
  194. package/openclaw.plugin.json +1 -1
  195. package/package.json +2 -2
  196. package/dist/import.d.ts +0 -31
  197. package/dist/import.d.ts.map +0 -1
  198. package/dist/import.js +0 -307
  199. package/dist/import.js.map +0 -1
@@ -0,0 +1,147 @@
1
+ /**
2
+ * LLM-powered refinement of consolidated semantic memories.
3
+ *
4
+ * The rule-based `mergeContents` in consolidate.ts produces functional but
5
+ * ugly semantic memories — typically "[Consolidated from N related memories]"
6
+ * prepended to the longest source, or a bulleted list. `hippo refine` takes
7
+ * those and asks Claude to synthesize a clean, generalized principle.
8
+ *
9
+ * Design choices:
10
+ * - Separate command (not baked into `hippo sleep`) so API-key users opt in.
11
+ * - Idempotent via the `llm-refined` tag — re-running skips already-refined.
12
+ * - Uses fetch directly so no SDK dependency.
13
+ * - On failure (API error, bad response), the original memory is untouched.
14
+ */
15
+ import { Layer } from './memory.js';
16
+ import { loadAllEntries, readEntry, writeEntry } from './store.js';
17
+ const REFINED_TAG = 'llm-refined';
18
+ const CONSOLIDATED_MARKERS = [
19
+ '[Consolidated from',
20
+ '[Consolidated pattern from',
21
+ ];
22
+ /**
23
+ * Ask Claude to synthesize a clean semantic memory from the merged content
24
+ * plus the original source memories. Returns the refined content string or
25
+ * `null` when the API call failed.
26
+ */
27
+ export async function refineSemanticMemory(merged, sources, opts) {
28
+ const model = opts.model ?? 'claude-sonnet-4-6';
29
+ const fetchFn = opts.fetcher ?? fetch;
30
+ const sourceBlock = sources
31
+ .slice(0, 8)
32
+ .map((s, i) => `[source ${i + 1}] ${s.content.slice(0, 400)}`)
33
+ .join('\n\n');
34
+ const prompt = `You are refining a semantic memory in an agent's memory store. The rule-based consolidator merged several related episodic memories into one, but the output is clumsy. Produce a single coherent semantic memory that captures the underlying principle.
35
+
36
+ Rules:
37
+ - Output ONLY the refined content — no preamble, no quote marks, no "Here is...".
38
+ - Keep it concise: one paragraph, no headers, no bullet lists unless the sources are inherently a list.
39
+ - Preserve specific facts (names, numbers, paths, IDs) from the sources.
40
+ - Generalize: state the pattern, not each instance.
41
+ - Do NOT include the "[Consolidated from N ...]" marker.
42
+
43
+ Current merged content:
44
+ ${merged}
45
+
46
+ Source memories (up to 8 shown):
47
+ ${sourceBlock}`;
48
+ let res;
49
+ try {
50
+ res = await fetchFn('https://api.anthropic.com/v1/messages', {
51
+ method: 'POST',
52
+ headers: {
53
+ 'content-type': 'application/json',
54
+ 'x-api-key': opts.apiKey,
55
+ 'anthropic-version': '2023-06-01',
56
+ },
57
+ body: JSON.stringify({
58
+ model,
59
+ max_tokens: 800,
60
+ messages: [{ role: 'user', content: prompt }],
61
+ }),
62
+ });
63
+ }
64
+ catch {
65
+ return null;
66
+ }
67
+ if (!res.ok)
68
+ return null;
69
+ try {
70
+ const data = await res.json();
71
+ const text = data.content?.[0]?.text?.trim() ?? '';
72
+ if (text.length < 10)
73
+ return null;
74
+ return text;
75
+ }
76
+ catch {
77
+ return null;
78
+ }
79
+ }
80
+ function isConsolidated(entry) {
81
+ if (entry.layer !== Layer.Semantic)
82
+ return false;
83
+ return CONSOLIDATED_MARKERS.some((m) => entry.content.startsWith(m));
84
+ }
85
+ /**
86
+ * Scan the store for consolidated semantic memories, refine each with the
87
+ * LLM, and write the refined content back. Tags with `llm-refined` so
88
+ * repeated runs are idempotent (unless `all` is set).
89
+ */
90
+ export async function refineStore(hippoRoot, opts) {
91
+ const result = {
92
+ scanned: 0,
93
+ refined: 0,
94
+ skipped: 0,
95
+ failed: 0,
96
+ details: [],
97
+ };
98
+ const entries = loadAllEntries(hippoRoot);
99
+ let processed = 0;
100
+ for (const entry of entries) {
101
+ if (!isConsolidated(entry))
102
+ continue;
103
+ result.scanned++;
104
+ if (!opts.all && entry.tags.includes(REFINED_TAG)) {
105
+ result.skipped++;
106
+ result.details.push({ id: entry.id, status: 'skipped', reason: 'already refined' });
107
+ continue;
108
+ }
109
+ if (opts.limit !== undefined && processed >= opts.limit)
110
+ break;
111
+ processed++;
112
+ // Best-effort: walk parents_json (schema v9) to fetch originals. When
113
+ // parents aren't recorded we still refine using just the merged content.
114
+ const sources = [];
115
+ const parentIds = Array.isArray(entry.parents) ? entry.parents : [];
116
+ for (const pid of parentIds) {
117
+ const p = readEntry(hippoRoot, pid);
118
+ if (p)
119
+ sources.push(p);
120
+ }
121
+ const refined = await refineSemanticMemory(entry.content, sources, {
122
+ apiKey: opts.apiKey,
123
+ model: opts.model,
124
+ fetcher: opts.fetcher,
125
+ });
126
+ if (refined === null) {
127
+ result.failed++;
128
+ result.details.push({ id: entry.id, status: 'failed', reason: 'api error or empty response' });
129
+ continue;
130
+ }
131
+ if (opts.dryRun) {
132
+ result.refined++;
133
+ result.details.push({ id: entry.id, status: 'refined', reason: 'dry-run (no write)' });
134
+ continue;
135
+ }
136
+ const updated = {
137
+ ...entry,
138
+ content: refined,
139
+ tags: entry.tags.includes(REFINED_TAG) ? entry.tags : [...entry.tags, REFINED_TAG],
140
+ };
141
+ writeEntry(hippoRoot, updated);
142
+ result.refined++;
143
+ result.details.push({ id: entry.id, status: 'refined' });
144
+ }
145
+ return result;
146
+ }
147
+ //# sourceMappingURL=refine-llm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refine-llm.js","sourceRoot":"","sources":["../../src/refine-llm.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAe,KAAK,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEnE,MAAM,WAAW,GAAG,aAAa,CAAC;AAClC,MAAM,oBAAoB,GAAG;IAC3B,oBAAoB;IACpB,4BAA4B;CAC7B,CAAC;AAqBF;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,MAAc,EACd,OAAsB,EACtB,IAAgE;IAEhE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,mBAAmB,CAAC;IAChD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC;IAEtC,MAAM,WAAW,GAAG,OAAO;SACxB,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;SACX,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;SAC7D,IAAI,CAAC,MAAM,CAAC,CAAC;IAEhB,MAAM,MAAM,GAAG;;;;;;;;;;EAUf,MAAM;;;EAGN,WAAW,EAAE,CAAC;IAEd,IAAI,GAAa,CAAC;IAClB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,OAAO,CAAC,uCAAuC,EAAE;YAC3D,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,WAAW,EAAE,IAAI,CAAC,MAAM;gBACxB,mBAAmB,EAAE,YAAY;aAClC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,KAAK;gBACL,UAAU,EAAE,GAAG;gBACf,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;aAC9C,CAAC;SACH,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC,GAAG,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC;IAEzB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAA4C,CAAC;QACxE,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;QACnD,IAAI,IAAI,CAAC,MAAM,GAAG,EAAE;YAAE,OAAO,IAAI,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,KAAkB;IACxC,IAAI,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC,QAAQ;QAAE,OAAO,KAAK,CAAC;IACjD,OAAO,oBAAoB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;AACvE,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,SAAiB,EACjB,IAAmB;IAEnB,MAAM,MAAM,GAAiB;QAC3B,OAAO,EAAE,CAAC;QACV,OAAO,EAAE,CAAC;QACV,OAAO,EAAE,CAAC;QACV,MAAM,EAAE,CAAC;QACT,OAAO,EAAE,EAAE;KACZ,CAAC;IAEF,MAAM,OAAO,GAAG,cAAc,CAAC,SAAS,CAAC,CAAC;IAC1C,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC;YAAE,SAAS;QACrC,MAAM,CAAC,OAAO,EAAE,CAAC;QAEjB,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;YAClD,MAAM,CAAC,OAAO,EAAE,CAAC;YACjB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,iBAAiB,EAAE,CAAC,CAAC;YACpF,SAAS;QACX,CAAC;QAED,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,IAAI,SAAS,IAAI,IAAI,CAAC,KAAK;YAAE,MAAM;QAC/D,SAAS,EAAE,CAAC;QAEZ,sEAAsE;QACtE,yEAAyE;QACzE,MAAM,OAAO,GAAkB,EAAE,CAAC;QAClC,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACpE,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;YAC5B,MAAM,CAAC,GAAG,SAAS,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;YACpC,IAAI,CAAC;gBAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACzB,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,oBAAoB,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE;YACjE,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,OAAO,EAAE,IAAI,CAAC,OAAO;SACtB,CAAC,CAAC;QAEH,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACrB,MAAM,CAAC,MAAM,EAAE,CAAC;YAChB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,6BAA6B,EAAE,CAAC,CAAC;YAC/F,SAAS;QACX,CAAC;QAED,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,MAAM,CAAC,OAAO,EAAE,CAAC;YACjB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,oBAAoB,EAAE,CAAC,CAAC;YACvF,SAAS;QACX,CAAC;QAED,MAAM,OAAO,GAAgB;YAC3B,GAAG,KAAK;YACR,OAAO,EAAE,OAAO;YAChB,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,WAAW,CAAC;SACnF,CAAC;QACF,UAAU,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAC/B,MAAM,CAAC,OAAO,EAAE,CAAC;QACjB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAAC;IAC3D,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Replay — biologically-inspired rehearsal during consolidation.
3
+ *
4
+ * Hippocampal replay is internally-driven reactivation of memories during
5
+ * slow-wave sleep: the brain picks important recent experiences and "plays
6
+ * them back" without external input, strengthening them before they decay.
7
+ * In McClelland's complementary-learning-systems framing, replay is also
8
+ * how episodic memories train the neocortex (interleaved rehearsal); in
9
+ * reward-modulated STDP, replay is gated by dopamine so rewarded
10
+ * experiences get preferentially consolidated.
11
+ *
12
+ * This module implements a lightweight, deterministic analog. During each
13
+ * `hippo sleep`, we sample N surviving memories by a priority score that
14
+ * weighs reward feedback, emotional valence, under-rehearsal, and age —
15
+ * then apply the same retrieval-strengthening dynamics `markRetrieved`
16
+ * applies to real queries. The effect is that important memories stay
17
+ * strong even when the user hasn't explicitly queried them recently.
18
+ *
19
+ * Distinct from the other consolidation passes:
20
+ * - decay: removes what's too weak
21
+ * - physics: moves particles in embedding space
22
+ * - merge: collapses near-duplicate episodics into semantics
23
+ * - REPLAY: picks winners and rehearses them (this file)
24
+ */
25
+ const VALENCE_WEIGHT = {
26
+ neutral: 1.0,
27
+ positive: 1.3,
28
+ negative: 1.5,
29
+ critical: 2.0,
30
+ };
31
+ /**
32
+ * Priority score used to rank survivors for replay. Higher = more likely
33
+ * to be sampled. Pure function of the entry and current time.
34
+ */
35
+ export function replayPriority(entry, now) {
36
+ const pos = entry.outcome_positive ?? 0;
37
+ const neg = entry.outcome_negative ?? 0;
38
+ // Reward signal: neutral memories get 1, strongly-rewarded memories > 1,
39
+ // negative-dominated memories floor at 0.1 (so they're still eligible, just
40
+ // much less likely to be sampled than neutral peers). Clamp is required
41
+ // because sampleForReplay depends on all weights being positive.
42
+ const rewardSignal = Math.max(0.1, 1 + pos * 0.5 + (pos - neg) * 0.25);
43
+ const valence = VALENCE_WEIGHT[entry.emotional_valence] ?? 1.0;
44
+ // Under-rehearsed memories benefit most from replay.
45
+ const underRehearsed = 1 / (1 + (entry.retrieval_count ?? 0));
46
+ // Idle-time boost: memories that haven't been touched recently need rehearsal more.
47
+ const lastRetrieved = new Date(entry.last_retrieved);
48
+ const deltaMs = now.getTime() - lastRetrieved.getTime();
49
+ const ageHours = Number.isFinite(deltaMs) ? Math.max(0, deltaMs / 3_600_000) : 0;
50
+ const idleBoost = 1 + Math.log1p(ageHours) * 0.1;
51
+ // Weight by current strength so dead-and-decaying memories don't waste replay slots.
52
+ const rawStrength = Number.isFinite(entry.strength) ? entry.strength : 0;
53
+ const strengthFloor = Math.max(0.1, rawStrength);
54
+ return rewardSignal * valence * underRehearsed * idleBoost * strengthFloor;
55
+ }
56
+ /**
57
+ * Deterministic 32-bit RNG (Mulberry32). Same seed → same sequence.
58
+ * Keeps replay reproducible for tests and audit runs without bringing
59
+ * in a random-number dependency.
60
+ */
61
+ function mulberry32(seed) {
62
+ let s = seed >>> 0;
63
+ return () => {
64
+ let t = (s += 0x6D2B79F5);
65
+ t = Math.imul(t ^ (t >>> 15), t | 1);
66
+ t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
67
+ return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
68
+ };
69
+ }
70
+ /**
71
+ * Pick `count` memories for replay, weighted by `replayPriority`, without
72
+ * replacement. Deterministic given the same seed.
73
+ *
74
+ * The sampler is weighted but not greedy — picking by priority alone would
75
+ * always pick the top-N, which overfits. Biological replay shows both
76
+ * preferential-for-reward AND stochastic-exploration characteristics; we
77
+ * keep the stochastic element so adjacent survivors aren't always ignored.
78
+ */
79
+ export function sampleForReplay(survivors, count, now, seed = Date.now() >>> 0) {
80
+ if (count <= 0 || survivors.length === 0)
81
+ return [];
82
+ const rng = mulberry32(seed);
83
+ // Stale memories have been deliberately marked as untrusted; rehearsing
84
+ // them would defeat the purpose of staleness. Skip them entirely.
85
+ const eligible = survivors.filter((e) => e.confidence !== 'stale');
86
+ if (eligible.length === 0)
87
+ return [];
88
+ const pool = eligible.map((entry, idx) => ({
89
+ entry,
90
+ idx,
91
+ weight: replayPriority(entry, now),
92
+ }));
93
+ const want = Math.min(count, pool.length);
94
+ const chosen = [];
95
+ const taken = new Set();
96
+ for (let k = 0; k < want; k++) {
97
+ let totalW = 0;
98
+ for (const p of pool)
99
+ if (!taken.has(p.idx))
100
+ totalW += p.weight;
101
+ if (totalW <= 0)
102
+ break;
103
+ let r = rng() * totalW;
104
+ for (const p of pool) {
105
+ if (taken.has(p.idx))
106
+ continue;
107
+ r -= p.weight;
108
+ if (r <= 0) {
109
+ chosen.push(p.entry);
110
+ taken.add(p.idx);
111
+ break;
112
+ }
113
+ }
114
+ }
115
+ return chosen;
116
+ }
117
+ //# sourceMappingURL=replay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"replay.js","sourceRoot":"","sources":["../../src/replay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAIH,MAAM,cAAc,GAAqC;IACvD,OAAO,EAAE,GAAG;IACZ,QAAQ,EAAE,GAAG;IACb,QAAQ,EAAE,GAAG;IACb,QAAQ,EAAE,GAAG;CACd,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,KAAkB,EAAE,GAAS;IAC1D,MAAM,GAAG,GAAG,KAAK,CAAC,gBAAgB,IAAI,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,KAAK,CAAC,gBAAgB,IAAI,CAAC,CAAC;IACxC,yEAAyE;IACzE,4EAA4E;IAC5E,wEAAwE;IACxE,iEAAiE;IACjE,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC;IAEvE,MAAM,OAAO,GAAG,cAAc,CAAC,KAAK,CAAC,iBAAiB,CAAC,IAAI,GAAG,CAAC;IAE/D,qDAAqD;IACrD,MAAM,cAAc,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,eAAe,IAAI,CAAC,CAAC,CAAC,CAAC;IAE9D,oFAAoF;IACpF,MAAM,aAAa,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IACrD,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,EAAE,GAAG,aAAa,CAAC,OAAO,EAAE,CAAC;IACxD,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACjF,MAAM,SAAS,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,GAAG,CAAC;IAEjD,qFAAqF;IACrF,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IACzE,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IAEjD,OAAO,YAAY,GAAG,OAAO,GAAG,cAAc,GAAG,SAAS,GAAG,aAAa,CAAC;AAC7E,CAAC;AAED;;;;GAIG;AACH,SAAS,UAAU,CAAC,IAAY;IAC9B,IAAI,CAAC,GAAG,IAAI,KAAK,CAAC,CAAC;IACnB,OAAO,GAAG,EAAE;QACV,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,UAAU,CAAC,CAAC;QAC1B,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QACrC,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;QAC1C,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,UAAU,CAAC;IAC/C,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAC7B,SAAwB,EACxB,KAAa,EACb,GAAS,EACT,OAAe,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC;IAE/B,IAAI,KAAK,IAAI,CAAC,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IACpD,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAE7B,wEAAwE;IACxE,kEAAkE;IAClE,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,OAAO,CAAC,CAAC;IACnE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAErC,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;QACzC,KAAK;QACL,GAAG;QACH,MAAM,EAAE,cAAc,CAAC,KAAK,EAAE,GAAG,CAAC;KACnC,CAAC,CAAC,CAAC;IAEJ,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAkB,EAAE,CAAC;IACjC,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAEhC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;QAC9B,IAAI,MAAM,GAAG,CAAC,CAAC;QACf,KAAK,MAAM,CAAC,IAAI,IAAI;YAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;gBAAE,MAAM,IAAI,CAAC,CAAC,MAAM,CAAC;QAChE,IAAI,MAAM,IAAI,CAAC;YAAE,MAAM;QACvB,IAAI,CAAC,GAAG,GAAG,EAAE,GAAG,MAAM,CAAC;QACvB,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;YACrB,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;gBAAE,SAAS;YAC/B,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;YACd,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;gBACX,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;gBACrB,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;gBACjB,MAAM;YACR,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Salience gate — decides at memory creation time whether content is worth
3
+ * storing at full strength, should start weakened, or should be skipped.
4
+ *
5
+ * Inspired by the biological salience network (anterior insula + dACC):
6
+ * not everything that enters working memory deserves long-term storage.
7
+ */
8
+ import { textOverlap } from './search.js';
9
+ const DEFAULTS = {
10
+ recentWindow: 20,
11
+ overlapThreshold: 0.6,
12
+ minContentLength: 5,
13
+ maxRepeatErrors: 4,
14
+ };
15
+ export function computeSalience(content, tags, recentMemories, options = {}) {
16
+ const opts = { ...DEFAULTS, ...options };
17
+ const trimmed = content.trim();
18
+ const isPinned = tags.includes('pinned');
19
+ if (isPinned) {
20
+ return { decision: 'store', reason: 'pinned', score: 1.0 };
21
+ }
22
+ if (trimmed.length < opts.minContentLength) {
23
+ return { decision: 'skip', reason: 'content_too_short', score: 0 };
24
+ }
25
+ const isError = tags.some(t => t === 'error' || t === 'critical' || t.startsWith('error:'));
26
+ const window = recentMemories.slice(-opts.recentWindow);
27
+ const duplicateMatch = findBestOverlap(trimmed, window);
28
+ if (duplicateMatch.overlap > opts.overlapThreshold) {
29
+ if (isError) {
30
+ const recentErrors = countRecentErrors(window);
31
+ if (recentErrors >= opts.maxRepeatErrors) {
32
+ return {
33
+ decision: 'start_weak',
34
+ reason: `repeat_error (${recentErrors} recent errors, overlap ${(duplicateMatch.overlap * 100).toFixed(0)}% with ${duplicateMatch.matchId})`,
35
+ score: 0.3,
36
+ };
37
+ }
38
+ return { decision: 'store', reason: 'error_despite_overlap', score: 0.7 };
39
+ }
40
+ return {
41
+ decision: 'skip',
42
+ reason: `duplicate (${(duplicateMatch.overlap * 100).toFixed(0)}% overlap with ${duplicateMatch.matchId})`,
43
+ score: 0.1,
44
+ };
45
+ }
46
+ if (isError) {
47
+ return { decision: 'store', reason: 'error_novel', score: 0.9 };
48
+ }
49
+ const hasStructuredTags = tags.some(t => t.startsWith('speaker:') || t.startsWith('topic:') || t.startsWith('scope:'));
50
+ let score = 0.5;
51
+ if (hasStructuredTags)
52
+ score += 0.15;
53
+ if (trimmed.length > 100)
54
+ score += 0.1;
55
+ if (trimmed.length > 300)
56
+ score += 0.1;
57
+ return { decision: 'store', reason: 'novel', score: Math.min(score, 1.0) };
58
+ }
59
+ function findBestOverlap(content, memories) {
60
+ let best = 0;
61
+ let matchId = null;
62
+ for (const m of memories) {
63
+ const overlap = textOverlap(content, m.content);
64
+ if (overlap > best) {
65
+ best = overlap;
66
+ matchId = m.id;
67
+ }
68
+ }
69
+ return { overlap: best, matchId };
70
+ }
71
+ function countRecentErrors(memories) {
72
+ return memories.filter(m => m.emotional_valence === 'negative' || m.emotional_valence === 'critical').length;
73
+ }
74
+ //# sourceMappingURL=salience.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"salience.js","sourceRoot":"","sources":["../../src/salience.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ export const DAILY_TASK_NAME = 'hippo-daily-runner';
4
+ function defaultRegistry() {
5
+ return {
6
+ version: 1,
7
+ workspaces: [],
8
+ };
9
+ }
10
+ export function workspaceRegistryPath(globalRoot) {
11
+ return path.join(globalRoot, 'workspaces.json');
12
+ }
13
+ function normalizeWorkspace(projectDir) {
14
+ return path.resolve(projectDir).replace(/\\/g, '/');
15
+ }
16
+ export function loadWorkspaceRegistry(globalRoot) {
17
+ const registryPath = workspaceRegistryPath(globalRoot);
18
+ if (!fs.existsSync(registryPath))
19
+ return defaultRegistry();
20
+ try {
21
+ const parsed = JSON.parse(fs.readFileSync(registryPath, 'utf8'));
22
+ const workspaces = Array.isArray(parsed.workspaces)
23
+ ? [...new Set(parsed.workspaces.map((entry) => normalizeWorkspace(String(entry))).filter(Boolean))].sort()
24
+ : [];
25
+ return {
26
+ version: 1,
27
+ workspaces,
28
+ };
29
+ }
30
+ catch {
31
+ return defaultRegistry();
32
+ }
33
+ }
34
+ export function saveWorkspaceRegistry(globalRoot, registry) {
35
+ fs.mkdirSync(globalRoot, { recursive: true });
36
+ fs.writeFileSync(workspaceRegistryPath(globalRoot), JSON.stringify({
37
+ version: 1,
38
+ workspaces: [...new Set(registry.workspaces.map(normalizeWorkspace))].sort(),
39
+ }, null, 2) + '\n', 'utf8');
40
+ }
41
+ export function registerWorkspace(globalRoot, projectDir) {
42
+ const registry = loadWorkspaceRegistry(globalRoot);
43
+ registry.workspaces = [...new Set([...registry.workspaces, normalizeWorkspace(projectDir)])].sort();
44
+ saveWorkspaceRegistry(globalRoot, registry);
45
+ return registry;
46
+ }
47
+ export function listRegisteredWorkspaces(globalRoot) {
48
+ return loadWorkspaceRegistry(globalRoot).workspaces;
49
+ }
50
+ export function buildDailyRunnerCommand(projectDir, platform = process.platform) {
51
+ if (platform === 'win32') {
52
+ const resolved = path.win32.resolve(projectDir).replace(/\\/g, '/');
53
+ return `cd /d "${resolved}" && hippo daily-runner`;
54
+ }
55
+ const resolved = path.posix.resolve(projectDir.replace(/\\/g, '/'));
56
+ return `cd "${resolved}" && hippo daily-runner`;
57
+ }
58
+ export function runDailyMaintenance(workspaces, runCommand) {
59
+ for (const workspace of workspaces) {
60
+ const resolved = normalizeWorkspace(workspace);
61
+ if (!fs.existsSync(path.join(resolved, '.hippo')))
62
+ continue;
63
+ runCommand(resolved, ['learn', '--git', '--days', '1']);
64
+ runCommand(resolved, ['sleep']);
65
+ }
66
+ }
67
+ //# sourceMappingURL=scheduler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../../src/scheduler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Detect the current operational scope from environment signals.
3
+ * Returns a scope name string (no prefix), or null if no scope detected.
4
+ * Priority: HIPPO_SCOPE > GSTACK_SKILL > OPENCLAW_SKILL.
5
+ *
6
+ * Pure env var reads: no I/O, safe to call from hot paths (e.g. UserPromptSubmit hook).
7
+ */
8
+ export function detectScope() {
9
+ const explicit = process.env['HIPPO_SCOPE'];
10
+ if (explicit && explicit.trim())
11
+ return explicit.trim();
12
+ const gstackSkill = process.env['GSTACK_SKILL'];
13
+ if (gstackSkill && gstackSkill.trim())
14
+ return gstackSkill.trim();
15
+ const openclawSkill = process.env['OPENCLAW_SKILL'];
16
+ if (openclawSkill && openclawSkill.trim())
17
+ return openclawSkill.trim();
18
+ return null;
19
+ }
20
+ /**
21
+ * Compute scope match between a memory's scope tags and the active scope.
22
+ * Returns: 1 if matching scope, -1 if mismatching scope, 0 if neutral (no scope on either side).
23
+ */
24
+ export function scopeMatch(memoryTags, activeScope) {
25
+ const scopeTags = memoryTags.filter(t => t.startsWith('scope:'));
26
+ if (scopeTags.length === 0)
27
+ return 0; // memory has no scope: always neutral
28
+ if (!activeScope)
29
+ return 0; // no active scope: everything neutral
30
+ const scopeKey = `scope:${activeScope}`;
31
+ if (scopeTags.includes(scopeKey))
32
+ return 1; // match
33
+ return -1; // mismatch
34
+ }
35
+ //# sourceMappingURL=scope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scope.js","sourceRoot":"","sources":["../../src/scope.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,UAAU,WAAW;IACzB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAC5C,IAAI,QAAQ,IAAI,QAAQ,CAAC,IAAI,EAAE;QAAE,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;IAExD,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IAChD,IAAI,WAAW,IAAI,WAAW,CAAC,IAAI,EAAE;QAAE,OAAO,WAAW,CAAC,IAAI,EAAE,CAAC;IAEjE,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IACpD,IAAI,aAAa,IAAI,aAAa,CAAC,IAAI,EAAE;QAAE,OAAO,aAAa,CAAC,IAAI,EAAE,CAAC;IAEvE,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,UAAoB,EAAE,WAA0B;IACzE,MAAM,SAAS,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC;IACjE,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC,CAAE,sCAAsC;IAC7E,IAAI,CAAC,WAAW;QAAE,OAAO,CAAC,CAAC,CAAY,sCAAsC;IAC7E,MAAM,QAAQ,GAAG,SAAS,WAAW,EAAE,CAAC;IACxC,IAAI,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,CAAC,CAAC,CAAG,QAAQ;IACtD,OAAO,CAAC,CAAC,CAAC,CAAuC,WAAW;AAC9D,CAAC"}