open-mem 0.4.2 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +53 -0
  2. package/dist/config.d.ts +1 -0
  3. package/dist/config.d.ts.map +1 -1
  4. package/dist/daemon/manager.d.ts +22 -0
  5. package/dist/daemon/manager.d.ts.map +1 -0
  6. package/dist/daemon/pid.d.ts +6 -0
  7. package/dist/daemon/pid.d.ts.map +1 -0
  8. package/dist/daemon/worker.d.ts +22 -0
  9. package/dist/daemon/worker.d.ts.map +1 -0
  10. package/dist/daemon.d.ts +3 -0
  11. package/dist/daemon.d.ts.map +1 -0
  12. package/dist/daemon.js +332 -0
  13. package/dist/dashboard/assets/index-9JxqY10c.css +1 -0
  14. package/dist/dashboard/assets/index-DWbZtwHB.js +60 -0
  15. package/dist/dashboard/dist/assets/index-9JxqY10c.css +1 -0
  16. package/dist/dashboard/dist/assets/index-CTwrdVhA.js +60 -0
  17. package/dist/dashboard/dist/assets/index-DWbZtwHB.js +60 -0
  18. package/dist/dashboard/dist/index.html +19 -0
  19. package/dist/dashboard/index.html +19 -0
  20. package/dist/db/database.d.ts +4 -0
  21. package/dist/db/database.d.ts.map +1 -1
  22. package/dist/db/observations.d.ts +13 -0
  23. package/dist/db/observations.d.ts.map +1 -1
  24. package/dist/db/schema.d.ts +7 -1
  25. package/dist/db/schema.d.ts.map +1 -1
  26. package/dist/events/bus.d.ts +21 -0
  27. package/dist/events/bus.d.ts.map +1 -0
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +67 -50
  30. package/dist/mcp.js +38 -26
  31. package/dist/queue/processor.d.ts +6 -0
  32. package/dist/queue/processor.d.ts.map +1 -1
  33. package/dist/search/hybrid.d.ts +1 -0
  34. package/dist/search/hybrid.d.ts.map +1 -1
  35. package/dist/servers/http-server.d.ts +25 -0
  36. package/dist/servers/http-server.d.ts.map +1 -0
  37. package/dist/servers/sse-broadcaster.d.ts +27 -0
  38. package/dist/servers/sse-broadcaster.d.ts.map +1 -0
  39. package/dist/tools/search.d.ts +1 -1
  40. package/dist/tools/search.d.ts.map +1 -1
  41. package/dist/types.d.ts +4 -0
  42. package/dist/types.d.ts.map +1 -1
  43. package/package.json +19 -8
package/README.md CHANGED
@@ -77,6 +77,7 @@ Without any provider configured, open-mem still works — it falls back to a bas
77
77
  - 🔒 **Privacy controls** with `<private>` tag support
78
78
  - 🛠️ **Six custom tools**: mem-search, mem-save, mem-timeline, mem-recall, mem-export, mem-import
79
79
  - 🌐 **MCP server mode** — expose memory tools to any MCP-compatible AI client
80
+ - 📊 **Web dashboard** — browse observations, sessions, search, and stats in a local web UI
80
81
  - 🌳 **Git worktree support** — shared memory across all worktrees
81
82
  - 📂 **AGENTS.md generation** — auto-generated folder-level context on session end
82
83
  - 📦 **Import/export** — portable JSON for backup and transfer between machines
@@ -268,6 +269,54 @@ Or add it to your MCP client config:
268
269
 
269
270
  The server communicates over stdin/stdout using JSON-RPC 2.0 and exposes: `mem-search`, `mem-save`, `mem-timeline`, `mem-recall`.
270
271
 
272
+ ## Web Dashboard
273
+
274
+ open-mem includes an optional web dashboard for browsing observations, sessions, search results, and memory statistics in your browser.
275
+
276
+ ### Enable the Dashboard
277
+
278
+ Set the environment variable before starting OpenCode:
279
+
280
+ ```bash
281
+ export OPEN_MEM_DASHBOARD=true
282
+ ```
283
+
284
+ When enabled, open-mem starts a local HTTP server and logs the URL:
285
+
286
+ ```
287
+ [open-mem] Dashboard available at http://127.0.0.1:3737
288
+ ```
289
+
290
+ Open that URL in your browser. The dashboard is read-only and bound to `127.0.0.1` (localhost only).
291
+
292
+ ### Dashboard Pages
293
+
294
+ | Page | Description |
295
+ |------|-------------|
296
+ | **Timeline** | Real-time observation feed across all sessions. Supports type filtering and infinite scroll. New observations appear live via Server-Sent Events. |
297
+ | **Sessions** | Browse past coding sessions. Expand a session to see its observations, key facts, and files involved. |
298
+ | **Search** | Full-text and semantic search across all observations. Uses hybrid FTS5 + vector search when embeddings are configured. |
299
+ | **Stats** | Memory usage analytics — total observations, sessions, token savings from compression, and a type breakdown chart. |
300
+ | **Settings** | Read-only view of the current open-mem configuration (API keys are redacted). |
301
+
302
+ ### Port Configuration
303
+
304
+ The dashboard defaults to port `3737`. If that port is busy, it automatically tries the next 9 ports (up to `3746`). To set a specific port:
305
+
306
+ ```bash
307
+ export OPEN_MEM_DASHBOARD_PORT=4000
308
+ ```
309
+
310
+ ### Building the Dashboard (Development)
311
+
312
+ If you're developing open-mem from source, the dashboard must be built before it can be served:
313
+
314
+ ```bash
315
+ bun run build:dashboard
316
+ ```
317
+
318
+ This compiles the React app in `dashboard/` and copies the output to `dist/dashboard/`. The full `bun run build` also includes this step. Published npm packages ship with the dashboard pre-built.
319
+
271
320
  ## Configuration
272
321
 
273
322
  open-mem works out of the box with zero configuration. All settings can be customized via environment variables:
@@ -293,6 +342,8 @@ open-mem works out of the box with zero configuration. All settings can be custo
293
342
  | `OPEN_MEM_MAX_OBSERVATIONS` | `50` | Maximum observations to consider for context |
294
343
  | `OPEN_MEM_FOLDER_CONTEXT` | `true` | Set to `false` to disable AGENTS.md generation |
295
344
  | `OPEN_MEM_FOLDER_CONTEXT_MAX_DEPTH` | `5` | Max folder depth for AGENTS.md generation |
345
+ | `OPEN_MEM_DASHBOARD` | `false` | Set to `true` to enable the web dashboard |
346
+ | `OPEN_MEM_DASHBOARD_PORT` | `3737` | Dashboard HTTP port (tries up to +9 if busy) |
296
347
 
297
348
  <details>
298
349
  <summary><strong>Programmatic Configuration Reference</strong></summary>
@@ -320,6 +371,8 @@ If you need to configure open-mem programmatically (e.g. for testing or custom i
320
371
  | `logLevel` | string | `warn` | Log level: `debug`, `info`, `warn`, `error` |
321
372
  | `folderContextEnabled` | boolean | `true` | Auto-generate AGENTS.md in active folders |
322
373
  | `folderContextMaxDepth` | number | `5` | Max folder depth from project root |
374
+ | `dashboardEnabled` | boolean | `false` | Enable the web dashboard |
375
+ | `dashboardPort` | number | `3737` | Dashboard HTTP port |
323
376
 
324
377
  </details>
325
378
 
package/dist/config.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { OpenMemConfig } from "./types";
2
+ export declare function getDefaultDimension(provider: string): number;
2
3
  /**
3
4
  * Resolve configuration by merging defaults, environment variables, and overrides.
4
5
  * Priority: defaults < env vars < overrides
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAmB,aAAa,EAAE,MAAM,SAAS,CAAC;AAsG9D;;;GAGG;AACH,wBAAgB,aAAa,CAC5B,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GAChC,aAAa,CAgDf;AAMD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,EAAE,CAuB9D;AAMD,8CAA8C;AAC9C,wBAAgB,gBAAgB,IAAI,aAAa,CAEhD;AAED,2CAA2C;AAC3C,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAI5E"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAmB,aAAa,EAAE,MAAM,SAAS,CAAC;AAsH9D,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAa5D;AAMD;;;GAGG;AACH,wBAAgB,aAAa,CAC5B,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC,GAChC,aAAa,CAoDf;AAMD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,EAAE,CAuB9D;AAMD,8CAA8C;AAC9C,wBAAgB,gBAAgB,IAAI,aAAa,CAEhD;AAED,2CAA2C;AAC3C,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAI5E"}
@@ -0,0 +1,22 @@
1
+ interface DaemonManagerConfig {
2
+ dbPath: string;
3
+ projectPath: string;
4
+ daemonScript: string;
5
+ }
6
+ export declare class DaemonManager {
7
+ private readonly pidPath;
8
+ private readonly projectPath;
9
+ private readonly daemonScript;
10
+ private subprocess;
11
+ constructor(config: DaemonManagerConfig);
12
+ start(): boolean;
13
+ signal(message: string): void;
14
+ stop(): void;
15
+ isRunning(): boolean;
16
+ getStatus(): {
17
+ running: boolean;
18
+ pid: number | null;
19
+ };
20
+ }
21
+ export {};
22
+ //# sourceMappingURL=manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/daemon/manager.ts"],"names":[],"mappings":"AAMA,UAAU,mBAAmB;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,aAAa;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,UAAU,CAA6C;gBAEnD,MAAM,EAAE,mBAAmB;IAMvC,KAAK,IAAI,OAAO;IA4BhB,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAQ7B,IAAI,IAAI,IAAI;IAaZ,SAAS,IAAI,OAAO;IAQpB,SAAS,IAAI;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE;CAUrD"}
@@ -0,0 +1,6 @@
1
+ export declare function writePid(pidPath: string): void;
2
+ export declare function readPid(pidPath: string): number | null;
3
+ export declare function isProcessAlive(pid: number): boolean;
4
+ export declare function removePid(pidPath: string): void;
5
+ export declare function getPidPath(dbPath: string): string;
6
+ //# sourceMappingURL=pid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pid.d.ts","sourceRoot":"","sources":["../../src/daemon/pid.ts"],"names":[],"mappings":"AAEA,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAO9C;AAED,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAUtD;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAWnD;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAM/C;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAMjD"}
@@ -0,0 +1,22 @@
1
+ export interface BatchProcessor {
2
+ processBatch(): Promise<number>;
3
+ }
4
+ export interface DaemonWorkerOptions {
5
+ queueProcessor: BatchProcessor;
6
+ pollIntervalMs: number;
7
+ }
8
+ export declare class DaemonWorker {
9
+ private queueProcessor;
10
+ private pollIntervalMs;
11
+ private timer;
12
+ private lastActiveAt;
13
+ private processing;
14
+ constructor(options: DaemonWorkerOptions);
15
+ start(): void;
16
+ stop(): void;
17
+ get isRunning(): boolean;
18
+ get idleMs(): number;
19
+ get shouldAutoExit(): boolean;
20
+ handleMessage(message: unknown): void;
21
+ }
22
+ //# sourceMappingURL=worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/daemon/worker.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,cAAc;IAC9B,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,mBAAmB;IACnC,cAAc,EAAE,cAAc,CAAC;IAC/B,cAAc,EAAE,MAAM,CAAC;CACvB;AAQD,qBAAa,YAAY;IACxB,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,KAAK,CAA+C;IAC5D,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,UAAU,CAAS;gBAEf,OAAO,EAAE,mBAAmB;IAKxC,KAAK,IAAI,IAAI;IAoBb,IAAI,IAAI,IAAI;IAOZ,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,IAAI,cAAc,IAAI,OAAO,CAE5B;IAED,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;CAkBrC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bun
2
+ export {};
3
+ //# sourceMappingURL=daemon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":""}
package/dist/daemon.js ADDED
@@ -0,0 +1,332 @@
1
+ #!/usr/bin/env bun
2
+ // @bun
3
+ var z=import.meta.require;import{parseArgs as T0}from"util";import{generateText as V0}from"ai";var Q0=new Set(["decision","bugfix","feature","refactor","discovery","change"]);function W(J,X){let Z=new RegExp(`<${X}[^>]*>([\\s\\S]*?)</${X}>`,"i"),$=J.match(Z);return $?$[1].trim():""}function G(J,X){let Z=new RegExp(`<${X}[^>]*>([\\s\\S]*?)</${X}>`,"gi"),$=[];for(let Q of J.matchAll(Z)){let H=Q[1].trim();if(H)$.push(H)}return $}function I(J){let X=W(J,"observation");if(!X)return null;let Z=W(X,"type").toLowerCase(),$=Q0.has(Z)?Z:"discovery",Q=W(X,"title")||"Untitled observation",H=W(X,"subtitle"),V=W(X,"narrative"),Y=G(W(X,"facts"),"fact"),K=G(W(X,"concepts"),"concept"),U=G(W(X,"files_read"),"file"),A=G(W(X,"files_modified"),"file");return{type:$,title:Q,subtitle:H,facts:Y,narrative:V,concepts:K,filesRead:U,filesModified:A}}function h(J){let X=W(J,"session_summary");if(!X)return null;let Z=W(X,"summary")||"No summary available",$=G(W(X,"key_decisions"),"decision"),Q=G(W(X,"files_modified"),"file"),H=G(W(X,"concepts"),"concept"),V=W(X,"request")||void 0,Y=W(X,"investigated")||void 0,K=W(X,"learned")||void 0,U=W(X,"completed")||void 0,A=W(X,"next_steps")||void 0;return{summary:Z,keyDecisions:$,filesModified:Q,concepts:H,request:V,investigated:Y,learned:K,completed:U,nextSteps:A}}function F(J){return Math.ceil(J.length/4)}function f(J,X,Z){let $=Z?`<session_context>
4
+ ${Z}
5
+ </session_context>
6
+
7
+ `:"";return`<task>
8
+ Analyze the following tool output and extract a structured observation.
9
+ </task>
10
+
11
+ <tool_name>${J}</tool_name>
12
+
13
+ <tool_output>
14
+ ${X}
15
+ </tool_output>
16
+
17
+ ${$}<instructions>
18
+ Extract a structured observation from the tool output. Determine the most appropriate type and provide a concise but informative summary.
19
+
20
+ When extracting concepts, prefer established vocabulary where appropriate:
21
+ - how-it-works: Technical mechanisms and behaviors
22
+ - why-it-exists: Rationale and motivations
23
+ - what-changed: Modifications and their effects
24
+ - problem-solution: Issues encountered and how they were resolved
25
+ - gotcha: Surprising behaviors, edge cases, or pitfalls
26
+ - pattern: Recurring design patterns or approaches
27
+ - trade-off: Deliberate compromises between competing concerns
28
+ You may also use any domain-specific concepts relevant to the observation.
29
+
30
+ Respond with EXACTLY this XML format:
31
+ <observation>
32
+ <type>decision|bugfix|feature|refactor|discovery|change</type>
33
+ <title>Brief descriptive title (max 80 chars)</title>
34
+ <subtitle>One-line elaboration</subtitle>
35
+ <facts>
36
+ <fact>Specific factual detail 1</fact>
37
+ <fact>Specific factual detail 2</fact>
38
+ </facts>
39
+ <narrative>2-3 sentence narrative explaining what happened and why it matters</narrative>
40
+ <concepts>
41
+ <concept>relevant-concept-1</concept>
42
+ <concept>relevant-concept-2</concept>
43
+ </concepts>
44
+ <files_read>
45
+ <file>path/to/file/read</file>
46
+ </files_read>
47
+ <files_modified>
48
+ <file>path/to/file/modified</file>
49
+ </files_modified>
50
+ </observation>
51
+ </instructions>`}function v(J,X){let Z=J.map(($,Q)=>` <obs index="${Q+1}" type="${$.type}">
52
+ <title>${$.title}</title>
53
+ <narrative>${$.narrative}</narrative>
54
+ </obs>`).join(`
55
+ `);return`<task>
56
+ Summarize the following coding session based on its observations.
57
+ </task>
58
+
59
+ <session_id>${X}</session_id>
60
+
61
+ <observations>
62
+ ${Z}
63
+ </observations>
64
+
65
+ <instructions>
66
+ Create a concise session summary. Focus on key decisions, outcomes, and patterns.
67
+
68
+ Respond with EXACTLY this XML format:
69
+ <session_summary>
70
+ <request>What the user asked for (1-2 sentences)</request>
71
+ <investigated>What was explored or researched</investigated>
72
+ <learned>Key discoveries and insights</learned>
73
+ <completed>What was accomplished</completed>
74
+ <next_steps>What to do next (if any)</next_steps>
75
+ <summary>2-4 sentence summary of the entire session</summary>
76
+ <key_decisions>
77
+ <decision>Important decision made during session</decision>
78
+ </key_decisions>
79
+ <files_modified>
80
+ <file>path/to/modified/file</file>
81
+ </files_modified>
82
+ <concepts>
83
+ <concept>key-concept</concept>
84
+ </concepts>
85
+ </session_summary>
86
+ </instructions>`}var Y0={"claude-sonnet-4-20250514":"us.anthropic.claude-sonnet-4-20250514-v1:0","claude-opus-4-20250514":"us.anthropic.claude-opus-4-20250514-v1:0","claude-3-5-sonnet-20241022":"us.anthropic.claude-3-5-sonnet-20241022-v2:0","claude-3-5-haiku-20241022":"us.anthropic.claude-3-5-haiku-20241022-v1:0","claude-3-haiku-20240307":"anthropic.claude-3-haiku-20240307-v1:0"};function H0(J){if(J.includes("."))return J;return Y0[J]||`us.anthropic.${J}-v1:0`}function N(J){switch(J.provider){case"anthropic":{let{createAnthropic:X}=z("@ai-sdk/anthropic");return X({apiKey:J.apiKey})(J.model)}case"bedrock":{let{createAmazonBedrock:X}=z("@ai-sdk/amazon-bedrock");return X()(H0(J.model))}case"openai":{let{createOpenAI:X}=z("@ai-sdk/openai");return X({apiKey:J.apiKey})(J.model)}case"google":{let{createGoogleGenerativeAI:X}=z("@ai-sdk/google");return X({apiKey:J.apiKey})(J.model)}default:throw Error(`Unknown provider: ${J.provider}. Supported: anthropic, bedrock, openai, google`)}}function w(J){try{switch(J.provider){case"google":{let{createGoogleGenerativeAI:X}=z("@ai-sdk/google");return X({apiKey:J.apiKey}).embedding("text-embedding-004")}case"openai":{let{createOpenAI:X}=z("@ai-sdk/openai");return X({apiKey:J.apiKey}).embedding("text-embedding-3-small")}case"bedrock":{let{createAmazonBedrock:X}=z("@ai-sdk/amazon-bedrock");return X().embedding("amazon.titan-embed-text-v2:0")}case"anthropic":return null;default:return null}}catch{return null}}var W0={"gemini-2.5-flash-lite":10,"gemini-2.5-flash":10,"gemini-2.5-pro":5,"gemini-2.0-flash":15,"gemini-2.0-flash-lite":30,"gemini-3-flash":5},u=0;async function M(J,X){if(!X)return;let Z=W0[J]||5,$=Math.ceil(60000/Z)+100,H=Date.now()-u;if(H<$){let V=$-H;await new Promise((Y)=>setTimeout(Y,V))}u=Date.now()}class _{model;config;_generate=V0;constructor(J){this.config=J,this.model=null;let X=J.provider!=="bedrock";if(J.compressionEnabled&&(!X||J.apiKey))try{this.model=N({provider:J.provider,model:J.model,apiKey:J.apiKey})}catch{}}static MAX_INPUT_LENGTH=50000;async compress(J,X,Z){if(!this.config.compressionEnabled||!this.model)return null;if(X.length<this.config.minOutputLength)return null;let $=F(X),Q=X.length>_.MAX_INPUT_LENGTH?`${X.substring(0,_.MAX_INPUT_LENGTH)}
87
+
88
+ [... truncated ...]`:X,H=f(J,Q,Z),V=2;for(let Y=0;Y<=V;Y++)try{if(this.config.provider==="google")await M(this.config.model,this.config.rateLimitingEnabled);let{text:K}=await this._generate({model:this.model,maxOutputTokens:this.config.maxTokensPerCompression,prompt:H}),U=I(K);if(U)U.discoveryTokens=$;return U}catch(K){if(z0(K)&&Y<V){let U=2**Y*1000;await b(U);continue}return null}return null}async compressBatch(J){let X=new Map;for(let Z=0;Z<J.length;Z++){let $=J[Z],Q=await this.compress($.toolName,$.toolOutput,$.sessionContext);if(X.set($.callId,Q),Z<J.length-1)await b(200)}return X}createFallbackObservation(J,X){let Z=U0(X),$=K0[J]??"discovery";return{type:$,title:`${J} execution`,subtitle:X.substring(0,100).replace(/\n/g," "),facts:[],narrative:`Tool ${J} was executed. Output length: ${X.length} chars.`,concepts:[],filesRead:$==="discovery"?Z:[],filesModified:$==="change"?Z:[],discoveryTokens:F(X)}}async isAvailable(){if(!this.model)return!1;try{return await this._generate({model:this.model,maxOutputTokens:10,prompt:"ping"}),!0}catch{return!1}}}var K0={Read:"discovery",Write:"change",Edit:"change",Bash:"change",Glob:"discovery",Grep:"discovery"},B0=/(?:^|\s)((?:\.\/|\/|src\/|tests\/|lib\/)\S+\.\w+)/gm;function U0(J){let X=[];for(let Z of J.matchAll(B0))X.push(Z[1]);return[...new Set(X)]}function z0(J){if(typeof J!=="object"||J===null)return!1;let X=J,Z=X.status;if(Z===429||Z===500||Z===503)return!0;let $=X.error;if(typeof $==="object"&&$!==null&&$.type==="overloaded_error")return!0;return!1}function b(J){return new Promise((X)=>setTimeout(X,J))}import{generateText as G0}from"ai";class C{model;config;_generate=G0;constructor(J){this.config=J,this.model=null;let X=J.provider!=="bedrock";if(J.compressionEnabled&&(!X||J.apiKey))try{this.model=N({provider:J.provider,model:J.model,apiKey:J.apiKey})}catch{}}async summarize(J,X){if(X.length===0)return null;if(!this.config.compressionEnabled||!this.model)return this.createFallbackSummary(X);let Z=v(X.map(($)=>({type:$.type,title:$.title,narrative:$.narrative})),J);try{if(this.config.provider==="google")await M(this.config.model,this.config.rateLimitingEnabled);let{text:$}=await this._generate({model:this.model,maxOutputTokens:this.config.maxTokensPerCompression,prompt:Z}),Q=h($);if(!Q)return this.createFallbackSummary(X);return Q}catch{return this.createFallbackSummary(X)}}createFallbackSummary(J){let X=new Set,Z=new Set,$=[];for(let Y of J){for(let K of Y.filesModified)X.add(K);for(let K of Y.concepts)Z.add(K);if(Y.type==="decision")$.push(Y.title)}let Q=new Map;for(let Y of J)Q.set(Y.type,(Q.get(Y.type)??0)+1);let H=Array.from(Q.entries()).map(([Y,K])=>`${K} ${Y}${K>1?"s":""}`).join(", "),V=Array.from(Z).slice(0,5).join(", ");return{summary:`Session with ${J.length} observations: ${H}. Files modified: ${X.size}. Key concepts: ${V}.`,keyDecisions:$.slice(0,5),filesModified:Array.from(X),concepts:Array.from(Z)}}shouldSummarize(J){return J>=2}}var F0={dbPath:".open-mem/memory.db",provider:"google",apiKey:void 0,model:"gemini-2.5-flash-lite",maxTokensPerCompression:1024,compressionEnabled:!0,contextInjectionEnabled:!0,maxContextTokens:4000,batchSize:5,batchIntervalMs:30000,ignoredTools:[],minOutputLength:50,maxIndexEntries:20,sensitivePatterns:[],retentionDays:90,maxDatabaseSizeMb:500,logLevel:"warn",contextShowTokenCosts:!0,contextObservationTypes:"all",contextFullObservationCount:3,maxObservations:50,contextShowLastSummary:!0,rateLimitingEnabled:!0,folderContextEnabled:!0,folderContextMaxDepth:5,daemonEnabled:!1,dashboardEnabled:!1,dashboardPort:3737,embeddingDimension:void 0};function L0(){let J={};if(process.env.OPEN_MEM_DB_PATH)J.dbPath=process.env.OPEN_MEM_DB_PATH;if(process.env.OPEN_MEM_PROVIDER)J.provider=process.env.OPEN_MEM_PROVIDER;if(process.env.OPEN_MEM_MODEL)J.model=process.env.OPEN_MEM_MODEL;if(process.env.OPEN_MEM_MAX_CONTEXT_TOKENS)J.maxContextTokens=Number.parseInt(process.env.OPEN_MEM_MAX_CONTEXT_TOKENS,10);if(process.env.OPEN_MEM_COMPRESSION==="false")J.compressionEnabled=!1;if(process.env.OPEN_MEM_CONTEXT_INJECTION==="false")J.contextInjectionEnabled=!1;if(process.env.OPEN_MEM_IGNORED_TOOLS)J.ignoredTools=process.env.OPEN_MEM_IGNORED_TOOLS.split(",").map((X)=>X.trim());if(process.env.OPEN_MEM_BATCH_SIZE)J.batchSize=Number.parseInt(process.env.OPEN_MEM_BATCH_SIZE,10);if(process.env.OPEN_MEM_RETENTION_DAYS)J.retentionDays=Number.parseInt(process.env.OPEN_MEM_RETENTION_DAYS,10);if(process.env.OPEN_MEM_LOG_LEVEL)J.logLevel=process.env.OPEN_MEM_LOG_LEVEL;if(process.env.OPEN_MEM_CONTEXT_SHOW_TOKEN_COSTS==="false")J.contextShowTokenCosts=!1;if(process.env.OPEN_MEM_CONTEXT_TYPES)J.contextObservationTypes=process.env.OPEN_MEM_CONTEXT_TYPES==="all"?"all":process.env.OPEN_MEM_CONTEXT_TYPES.split(",").map((X)=>X.trim());if(process.env.OPEN_MEM_CONTEXT_FULL_COUNT)J.contextFullObservationCount=Number.parseInt(process.env.OPEN_MEM_CONTEXT_FULL_COUNT,10);if(process.env.OPEN_MEM_MAX_OBSERVATIONS)J.maxObservations=Number.parseInt(process.env.OPEN_MEM_MAX_OBSERVATIONS,10);if(process.env.OPEN_MEM_CONTEXT_SHOW_LAST_SUMMARY==="false")J.contextShowLastSummary=!1;if(process.env.OPEN_MEM_RATE_LIMITING==="false")J.rateLimitingEnabled=!1;if(process.env.OPEN_MEM_FOLDER_CONTEXT==="false")J.folderContextEnabled=!1;if(process.env.OPEN_MEM_FOLDER_CONTEXT_MAX_DEPTH)J.folderContextMaxDepth=Number.parseInt(process.env.OPEN_MEM_FOLDER_CONTEXT_MAX_DEPTH,10);if(process.env.OPEN_MEM_DAEMON==="true")J.daemonEnabled=!0;if(process.env.OPEN_MEM_DASHBOARD==="true")J.dashboardEnabled=!0;if(process.env.OPEN_MEM_DASHBOARD_PORT)J.dashboardPort=Number.parseInt(process.env.OPEN_MEM_DASHBOARD_PORT,10);if(process.env.OPEN_MEM_EMBEDDING_DIMENSION)J.embeddingDimension=Number.parseInt(process.env.OPEN_MEM_EMBEDDING_DIMENSION,10);return J}function _0(J){switch(J){case"google":return 768;case"openai":return 1536;case"bedrock":return 1024;case"anthropic":return 0;default:return 768}}function g(J,X){let Z=L0(),$={...F0,...Z,...X};if(!$.dbPath.startsWith("/"))$.dbPath=`${J}/${$.dbPath}`;if(!process.env.OPEN_MEM_PROVIDER&&!X?.provider){if(process.env.GOOGLE_GENERATIVE_AI_API_KEY||process.env.GEMINI_API_KEY)$.provider="google";else if(process.env.ANTHROPIC_API_KEY)$.provider="anthropic";else if(process.env.AWS_BEARER_TOKEN_BEDROCK||process.env.AWS_ACCESS_KEY_ID||process.env.AWS_PROFILE)$.provider="bedrock"}if(!$.apiKey)switch($.provider){case"google":$.apiKey=process.env.GOOGLE_GENERATIVE_AI_API_KEY||process.env.GEMINI_API_KEY;break;case"anthropic":$.apiKey=process.env.ANTHROPIC_API_KEY;break;case"openai":$.apiKey=process.env.OPENAI_API_KEY;break;case"bedrock":break}if($.embeddingDimension===void 0)$.embeddingDimension=_0($.provider);return $}import{existsSync as WJ,mkdirSync as N0,readFileSync as VJ,unlinkSync as M0,writeFileSync as E0}from"fs";function p(J){let X=J.lastIndexOf("/");if(X>0){let Z=J.substring(0,X);N0(Z,{recursive:!0})}E0(J,String(process.pid),"utf-8")}function l(J){try{M0(J)}catch{}}function m(J){let X=J.lastIndexOf("/");if(X>=0)return`${J.substring(0,X)}/worker.pid`;return"worker.pid"}class j{queueProcessor;pollIntervalMs;timer=null;lastActiveAt=Date.now();processing=!1;constructor(J){this.queueProcessor=J.queueProcessor,this.pollIntervalMs=J.pollIntervalMs}start(){if(this.timer)return;this.lastActiveAt=Date.now(),this.timer=setInterval(async()=>{if(this.processing)return;this.processing=!0;try{if(await this.queueProcessor.processBatch()>0)this.lastActiveAt=Date.now()}catch{}finally{this.processing=!1}},this.pollIntervalMs)}stop(){if(this.timer)clearInterval(this.timer),this.timer=null}get isRunning(){return this.timer!==null}get idleMs(){return Date.now()-this.lastActiveAt}get shouldAutoExit(){return this.idleMs>=60000&&!process.send}handleMessage(J){if(J==="SHUTDOWN")this.stop();else if(J==="PROCESS_NOW"){if(!this.processing)this.processing=!0,this.queueProcessor.processBatch().then((X)=>{if(X>0)this.lastActiveAt=Date.now()}).catch(()=>{}).finally(()=>{this.processing=!1})}}}import{Database as c}from"bun:sqlite";import{existsSync as S,mkdirSync as A0,unlinkSync as d}from"fs";import*as n from"sqlite-vec";class E{db;dbPath;_hasVectorExtension=!1;static enableExtensionSupport(){let J=["/opt/homebrew/opt/sqlite/lib/libsqlite3.dylib","/usr/local/opt/sqlite/lib/libsqlite3.dylib"];for(let X of J)try{if(S(X))return c.setCustomSQLite(X),!0}catch{return!1}return!1}constructor(J){this.dbPath=J,this.db=this.open(J),this.configure()}open(J){let X=J.lastIndexOf("/");if(X>0){let Z=J.substring(0,X);A0(Z,{recursive:!0})}return new c(J,{create:!0})}configure(){try{this.applyPragmas(),this.loadExtensions()}catch(J){console.warn("[open-mem] Database configure failed, attempting recovery by removing WAL/SHM files:",J.message);try{this.db.close()}catch{}this.deleteSidecarFiles();try{this.db=this.open(this.dbPath),this.applyPragmas(),this.loadExtensions(),console.warn("[open-mem] Recovery successful after removing WAL/SHM files");return}catch(X){console.warn("[open-mem] WAL/SHM cleanup insufficient, recreating database from scratch:",X.message);try{this.db.close()}catch{}this.deleteDatabaseFiles();try{this.db=this.open(this.dbPath),this.applyPragmas(),this.loadExtensions(),console.warn("[open-mem] Recovery successful after full database recreation");return}catch(Z){throw console.warn("[open-mem] All recovery attempts failed, filesystem may be broken:",Z.message),J}}}}applyPragmas(){this.db.exec("PRAGMA journal_mode = WAL"),this.db.exec("PRAGMA synchronous = NORMAL"),this.db.exec("PRAGMA foreign_keys = ON"),this.db.exec("PRAGMA busy_timeout = 5000")}loadExtensions(){try{n.load(this.db),this._hasVectorExtension=!0}catch{this._hasVectorExtension=!1}}get hasVectorExtension(){return this._hasVectorExtension}deleteSidecarFiles(){for(let J of["-wal","-shm"]){let X=this.dbPath+J;try{if(S(X))d(X)}catch{}}}deleteDatabaseFiles(){this.deleteSidecarFiles();try{if(S(this.dbPath))d(this.dbPath)}catch{}}ensureMigrationTable(){this.db.exec(`
89
+ CREATE TABLE IF NOT EXISTS _migrations (
90
+ version INTEGER PRIMARY KEY,
91
+ name TEXT NOT NULL,
92
+ applied_at TEXT NOT NULL DEFAULT (datetime('now'))
93
+ )
94
+ `)}migrate(J){this.ensureMigrationTable();let X=this.db.query("SELECT version FROM _migrations ORDER BY version").all(),Z=new Set(X.map((Q)=>Q.version)),$=J.filter((Q)=>!Z.has(Q.version)).sort((Q,H)=>Q.version-H.version);for(let Q of $)this.db.transaction(()=>{this.db.exec(Q.up),this.db.query("INSERT INTO _migrations (version, name) VALUES ($version, $name)").run({$version:Q.version,$name:Q.name})})()}run(J,X){let Z=this.db.query(J);if(X)Z.run(...X);else Z.run()}get(J,X){let Z=this.db.query(J);return X?Z.get(...X):Z.get()}all(J,X){let Z=this.db.query(J);return X?Z.all(...X):Z.all()}exec(J){this.db.exec(J)}transaction(J){return this.db.transaction(J)()}close(){this.db.close()}get isOpen(){try{return this.db.query("SELECT 1").get(),!0}catch{return!1}}get raw(){return this.db}}function i(J){return new E(J)}import{randomUUID as C0}from"crypto";class q{db;constructor(J){this.db=J}create(J){let X=C0(),Z=new Date().toISOString(),$=J.discoveryTokens??0;return this.db.run(`INSERT INTO observations
95
+ (id, session_id, type, title, subtitle, facts, narrative,
96
+ concepts, files_read, files_modified, raw_tool_output,
97
+ tool_name, created_at, token_count, discovery_tokens)
98
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[X,J.sessionId,J.type,J.title,J.subtitle,JSON.stringify(J.facts),J.narrative,JSON.stringify(J.concepts),JSON.stringify(J.filesRead),JSON.stringify(J.filesModified),J.rawToolOutput,J.toolName,Z,J.tokenCount,$]),{...J,id:X,createdAt:Z,discoveryTokens:$}}importObservation(J){this.db.run(`INSERT INTO observations
99
+ (id, session_id, type, title, subtitle, facts, narrative,
100
+ concepts, files_read, files_modified, raw_tool_output,
101
+ tool_name, created_at, token_count, discovery_tokens)
102
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[J.id,J.sessionId,J.type,J.title,J.subtitle,JSON.stringify(J.facts),J.narrative,JSON.stringify(J.concepts),JSON.stringify(J.filesRead),JSON.stringify(J.filesModified),J.rawToolOutput,J.toolName,J.createdAt,J.tokenCount,J.discoveryTokens??0])}getById(J){let X=this.db.get("SELECT * FROM observations WHERE id = ?",[J]);return X?this.mapRow(X):null}getBySession(J){return this.db.all("SELECT * FROM observations WHERE session_id = ? ORDER BY created_at ASC",[J]).map((X)=>this.mapRow(X))}getCount(J){if(J)return this.db.get("SELECT COUNT(*) as count FROM observations WHERE session_id = ?",[J])?.count??0;return this.db.get("SELECT COUNT(*) as count FROM observations")?.count??0}getIndex(J,X=20){return this.db.all(`SELECT o.id, o.session_id, o.type, o.title, o.token_count, o.discovery_tokens, o.created_at
103
+ FROM observations o
104
+ JOIN sessions s ON o.session_id = s.id
105
+ WHERE s.project_path = ?
106
+ ORDER BY o.created_at DESC
107
+ LIMIT ?`,[J,X]).map((Z)=>({id:Z.id,sessionId:Z.session_id,type:Z.type,title:Z.title,tokenCount:Z.token_count,discoveryTokens:Z.discovery_tokens??0,createdAt:Z.created_at}))}search(J){let X=`
108
+ SELECT o.*, rank
109
+ FROM observations o
110
+ JOIN observations_fts fts ON o._rowid = fts.rowid
111
+ WHERE observations_fts MATCH ?
112
+ `,Z=[J.query];if(J.sessionId)X+=" AND o.session_id = ?",Z.push(J.sessionId);if(J.type)X+=" AND o.type = ?",Z.push(J.type);return X+=" ORDER BY rank LIMIT ? OFFSET ?",Z.push(J.limit??10),Z.push(J.offset??0),this.db.all(X,Z).map(($)=>({observation:this.mapRow($),rank:$.rank,snippet:$.title}))}searchByConcept(J,X=10){return this.db.all(`SELECT o.*
113
+ FROM observations o
114
+ JOIN observations_fts fts ON o._rowid = fts.rowid
115
+ WHERE observations_fts MATCH ?
116
+ ORDER BY rank
117
+ LIMIT ?`,[`concepts:${J}`,X]).map((Z)=>this.mapRow(Z))}searchByFile(J,X=10){return this.db.all(`SELECT o.*
118
+ FROM observations o
119
+ JOIN observations_fts fts ON o._rowid = fts.rowid
120
+ WHERE observations_fts MATCH ?
121
+ ORDER BY rank
122
+ LIMIT ?`,[`files_read:"${J.replace(/"/g,'""')}" OR files_modified:"${J.replace(/"/g,'""')}"`,X]).map((Z)=>this.mapRow(Z))}setEmbedding(J,X){this.db.run("UPDATE observations SET embedding = ? WHERE id = ?",[JSON.stringify(X),J])}getWithEmbeddings(J,X){return this.db.all(`SELECT o.id, o.embedding, o.title
123
+ FROM observations o
124
+ JOIN sessions s ON o.session_id = s.id
125
+ WHERE s.project_path = ? AND o.embedding IS NOT NULL
126
+ ORDER BY o.created_at DESC
127
+ LIMIT ?`,[J,X]).map((Z)=>{try{return{id:Z.id,embedding:JSON.parse(Z.embedding),title:Z.title}}catch{return null}}).filter((Z)=>Z!==null)}insertVecEmbedding(J,X){let Z=new Float32Array(X);this.db.run("BEGIN");try{this.db.run("DELETE FROM observation_embeddings WHERE observation_id = ?",[J]),this.db.run("INSERT INTO observation_embeddings (observation_id, embedding) VALUES (?, ?)",[J,Z]),this.db.run("COMMIT")}catch($){throw this.db.run("ROLLBACK"),$}}migrateExistingEmbeddings(J){let X=this.db.all("SELECT id, embedding FROM observations WHERE embedding IS NOT NULL"),Z=0,$=0;for(let Q of X)try{let H=JSON.parse(Q.embedding);if(!Array.isArray(H)||H.length!==J){$++;continue}this.insertVecEmbedding(Q.id,H),Z++}catch{$++}return{migrated:Z,skipped:$}}getVecEmbeddingMatches(J,X){try{let Z=new Float32Array(J);return this.db.all(`SELECT observation_id, distance
128
+ FROM observation_embeddings
129
+ WHERE embedding MATCH ? AND k = ?`,[Z,X]).map(($)=>({observationId:$.observation_id,distance:$.distance}))}catch{return[]}}searchVecSubset(J,X,Z){if(X.length===0)return[];try{let $=new Float32Array(J),Q=Math.max(Z*5,X.length),H=this.db.all(`SELECT observation_id, distance
130
+ FROM observation_embeddings
131
+ WHERE embedding MATCH ? AND k = ?`,[$,Q]),V=new Set(X);return H.filter((Y)=>V.has(Y.observation_id)).slice(0,Z).map((Y)=>({observationId:Y.observation_id,distance:Y.distance}))}catch{return[]}}mapRow(J){return{id:J.id,sessionId:J.session_id,type:J.type,title:J.title,subtitle:J.subtitle,facts:JSON.parse(J.facts),narrative:J.narrative,concepts:JSON.parse(J.concepts),filesRead:JSON.parse(J.files_read),filesModified:JSON.parse(J.files_modified),rawToolOutput:J.raw_tool_output,toolName:J.tool_name,createdAt:J.created_at,tokenCount:J.token_count,discoveryTokens:J.discovery_tokens??0}}}import{randomUUID as j0}from"crypto";class O{db;constructor(J){this.db=J}create(J){let X=j0(),Z=new Date().toISOString();return this.db.run(`INSERT INTO pending_messages
132
+ (id, session_id, tool_name, tool_output, call_id, created_at)
133
+ VALUES (?, ?, ?, ?, ?, ?)`,[X,J.sessionId,J.toolName,J.toolOutput,J.callId,Z]),{...J,id:X,createdAt:Z,status:"pending",retryCount:0,error:null}}getPending(J=10){return this.db.all("SELECT * FROM pending_messages WHERE status = 'pending' ORDER BY created_at ASC LIMIT ?",[J]).map((X)=>this.mapRow(X))}getByStatus(J){return this.db.all("SELECT * FROM pending_messages WHERE status = ? ORDER BY created_at ASC",[J]).map((X)=>this.mapRow(X))}markProcessing(J){this.db.run("UPDATE pending_messages SET status = 'processing' WHERE id = ?",[J])}markCompleted(J){this.db.run("UPDATE pending_messages SET status = 'completed' WHERE id = ?",[J])}markFailed(J,X){this.db.run("UPDATE pending_messages SET status = 'failed', error = ?, retry_count = retry_count + 1 WHERE id = ?",[X,J])}resetStale(J=5){return this.db.all(`UPDATE pending_messages SET status = 'pending'
134
+ WHERE status = 'processing'
135
+ AND created_at < datetime('now', ? || ' minutes')
136
+ RETURNING id`,[`-${J}`]).length}mapRow(J){return{id:J.id,sessionId:J.session_id,toolName:J.tool_name,toolOutput:J.tool_output,callId:J.call_id,createdAt:J.created_at,status:J.status,retryCount:J.retry_count,error:J.error??null}}}var S0=[{version:1,name:"create-core-tables",up:`
137
+ -- Sessions table
138
+ CREATE TABLE IF NOT EXISTS sessions (
139
+ _rowid INTEGER PRIMARY KEY AUTOINCREMENT,
140
+ id TEXT UNIQUE NOT NULL,
141
+ project_path TEXT NOT NULL,
142
+ started_at TEXT NOT NULL DEFAULT (datetime('now')),
143
+ ended_at TEXT,
144
+ status TEXT NOT NULL DEFAULT 'active'
145
+ CHECK (status IN ('active', 'idle', 'completed')),
146
+ observation_count INTEGER NOT NULL DEFAULT 0,
147
+ summary_id TEXT
148
+ );
149
+
150
+ CREATE INDEX IF NOT EXISTS idx_sessions_project
151
+ ON sessions(project_path);
152
+ CREATE INDEX IF NOT EXISTS idx_sessions_status
153
+ ON sessions(status);
154
+ CREATE INDEX IF NOT EXISTS idx_sessions_started
155
+ ON sessions(started_at DESC);
156
+
157
+ -- Observations table
158
+ CREATE TABLE IF NOT EXISTS observations (
159
+ _rowid INTEGER PRIMARY KEY AUTOINCREMENT,
160
+ id TEXT UNIQUE NOT NULL,
161
+ session_id TEXT NOT NULL,
162
+ type TEXT NOT NULL
163
+ CHECK (type IN ('decision','bugfix','feature','refactor','discovery','change')),
164
+ title TEXT NOT NULL,
165
+ subtitle TEXT NOT NULL DEFAULT '',
166
+ facts TEXT NOT NULL DEFAULT '[]',
167
+ narrative TEXT NOT NULL DEFAULT '',
168
+ concepts TEXT NOT NULL DEFAULT '[]',
169
+ files_read TEXT NOT NULL DEFAULT '[]',
170
+ files_modified TEXT NOT NULL DEFAULT '[]',
171
+ raw_tool_output TEXT NOT NULL,
172
+ tool_name TEXT NOT NULL,
173
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
174
+ token_count INTEGER NOT NULL DEFAULT 0,
175
+ FOREIGN KEY (session_id) REFERENCES sessions(id)
176
+ );
177
+
178
+ CREATE INDEX IF NOT EXISTS idx_observations_session
179
+ ON observations(session_id);
180
+ CREATE INDEX IF NOT EXISTS idx_observations_type
181
+ ON observations(type);
182
+ CREATE INDEX IF NOT EXISTS idx_observations_created
183
+ ON observations(created_at DESC);
184
+
185
+ -- Session summaries table
186
+ CREATE TABLE IF NOT EXISTS session_summaries (
187
+ _rowid INTEGER PRIMARY KEY AUTOINCREMENT,
188
+ id TEXT UNIQUE NOT NULL,
189
+ session_id TEXT NOT NULL UNIQUE,
190
+ summary TEXT NOT NULL,
191
+ key_decisions TEXT NOT NULL DEFAULT '[]',
192
+ files_modified TEXT NOT NULL DEFAULT '[]',
193
+ concepts TEXT NOT NULL DEFAULT '[]',
194
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
195
+ token_count INTEGER NOT NULL DEFAULT 0,
196
+ FOREIGN KEY (session_id) REFERENCES sessions(id)
197
+ );
198
+
199
+ -- Pending messages (queue persistence)
200
+ CREATE TABLE IF NOT EXISTS pending_messages (
201
+ _rowid INTEGER PRIMARY KEY AUTOINCREMENT,
202
+ id TEXT UNIQUE NOT NULL,
203
+ session_id TEXT NOT NULL,
204
+ tool_name TEXT NOT NULL,
205
+ tool_output TEXT NOT NULL,
206
+ call_id TEXT NOT NULL,
207
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
208
+ status TEXT NOT NULL DEFAULT 'pending'
209
+ CHECK (status IN ('pending','processing','completed','failed')),
210
+ retry_count INTEGER NOT NULL DEFAULT 0,
211
+ error TEXT,
212
+ FOREIGN KEY (session_id) REFERENCES sessions(id)
213
+ );
214
+
215
+ CREATE INDEX IF NOT EXISTS idx_pending_status
216
+ ON pending_messages(status);
217
+ CREATE INDEX IF NOT EXISTS idx_pending_session
218
+ ON pending_messages(session_id);
219
+ `},{version:2,name:"create-fts5-tables",up:`
220
+ -- FTS5 for observations (title, subtitle, narrative, facts, concepts, files)
221
+ CREATE VIRTUAL TABLE IF NOT EXISTS observations_fts USING fts5(
222
+ title,
223
+ subtitle,
224
+ narrative,
225
+ facts,
226
+ concepts,
227
+ files_read,
228
+ files_modified,
229
+ content=observations,
230
+ content_rowid=_rowid,
231
+ tokenize='porter unicode61'
232
+ );
233
+
234
+ -- Triggers to keep FTS5 in sync with observations table
235
+ CREATE TRIGGER observations_ai AFTER INSERT ON observations BEGIN
236
+ INSERT INTO observations_fts(
237
+ rowid, title, subtitle, narrative, facts, concepts,
238
+ files_read, files_modified
239
+ )
240
+ VALUES (
241
+ new._rowid, new.title, new.subtitle, new.narrative,
242
+ new.facts, new.concepts, new.files_read, new.files_modified
243
+ );
244
+ END;
245
+
246
+ CREATE TRIGGER observations_ad AFTER DELETE ON observations BEGIN
247
+ INSERT INTO observations_fts(
248
+ observations_fts, rowid, title, subtitle, narrative,
249
+ facts, concepts, files_read, files_modified
250
+ )
251
+ VALUES (
252
+ 'delete', old._rowid, old.title, old.subtitle, old.narrative,
253
+ old.facts, old.concepts, old.files_read, old.files_modified
254
+ );
255
+ END;
256
+
257
+ CREATE TRIGGER observations_au AFTER UPDATE ON observations BEGIN
258
+ INSERT INTO observations_fts(
259
+ observations_fts, rowid, title, subtitle, narrative,
260
+ facts, concepts, files_read, files_modified
261
+ )
262
+ VALUES (
263
+ 'delete', old._rowid, old.title, old.subtitle, old.narrative,
264
+ old.facts, old.concepts, old.files_read, old.files_modified
265
+ );
266
+ INSERT INTO observations_fts(
267
+ rowid, title, subtitle, narrative, facts, concepts,
268
+ files_read, files_modified
269
+ )
270
+ VALUES (
271
+ new._rowid, new.title, new.subtitle, new.narrative,
272
+ new.facts, new.concepts, new.files_read, new.files_modified
273
+ );
274
+ END;
275
+
276
+ -- FTS5 for session summaries
277
+ CREATE VIRTUAL TABLE IF NOT EXISTS summaries_fts USING fts5(
278
+ summary,
279
+ key_decisions,
280
+ concepts,
281
+ content=session_summaries,
282
+ content_rowid=_rowid,
283
+ tokenize='porter unicode61'
284
+ );
285
+
286
+ CREATE TRIGGER summaries_ai AFTER INSERT ON session_summaries BEGIN
287
+ INSERT INTO summaries_fts(rowid, summary, key_decisions, concepts)
288
+ VALUES (new._rowid, new.summary, new.key_decisions, new.concepts);
289
+ END;
290
+
291
+ CREATE TRIGGER summaries_ad AFTER DELETE ON session_summaries BEGIN
292
+ INSERT INTO summaries_fts(
293
+ summaries_fts, rowid, summary, key_decisions, concepts
294
+ )
295
+ VALUES (
296
+ 'delete', old._rowid, old.summary, old.key_decisions, old.concepts
297
+ );
298
+ END;
299
+ `},{version:3,name:"add-structured-summary-columns",up:`
300
+ ALTER TABLE session_summaries ADD COLUMN request TEXT NOT NULL DEFAULT '';
301
+ ALTER TABLE session_summaries ADD COLUMN investigated TEXT NOT NULL DEFAULT '';
302
+ ALTER TABLE session_summaries ADD COLUMN learned TEXT NOT NULL DEFAULT '';
303
+ ALTER TABLE session_summaries ADD COLUMN completed TEXT NOT NULL DEFAULT '';
304
+ ALTER TABLE session_summaries ADD COLUMN next_steps TEXT NOT NULL DEFAULT '';
305
+ `},{version:4,name:"add-discovery-tokens",up:`
306
+ ALTER TABLE observations ADD COLUMN discovery_tokens INTEGER NOT NULL DEFAULT 0;
307
+ `},{version:5,name:"add-embedding-column",up:`
308
+ ALTER TABLE observations ADD COLUMN embedding TEXT;
309
+ `},{version:6,name:"create-embedding-meta-table",up:`
310
+ CREATE TABLE IF NOT EXISTS _embedding_meta (
311
+ key TEXT PRIMARY KEY,
312
+ value TEXT NOT NULL
313
+ );
314
+ `}];function s(J,X){if(J.migrate(S0),X?.hasVectorExtension&&X?.embeddingDimension&&X.embeddingDimension>0)q0(J,X.embeddingDimension)}function q0(J,X){if(J.get("SELECT name FROM sqlite_master WHERE type='table' AND name='observation_embeddings'")){let $=J.get("SELECT value FROM _embedding_meta WHERE key = 'dimension'");if($&&Number($.value)!==X){console.warn(`[open-mem] vec0 table exists with dimension ${$.value}, but config specifies ${X}. Drop observation_embeddings to re-create with new dimension.`);return}}else J.exec(`CREATE VIRTUAL TABLE observation_embeddings USING vec0(
315
+ observation_id TEXT PRIMARY KEY,
316
+ embedding float[${X}] distance_metric=cosine
317
+ )`);J.run("INSERT OR REPLACE INTO _embedding_meta (key, value) VALUES (?, ?)",["dimension",String(X)])}class D{db;constructor(J){this.db=J}create(J,X){let Z=new Date().toISOString();return this.db.run(`INSERT INTO sessions (id, project_path, started_at, status)
318
+ VALUES (?, ?, ?, 'active')`,[J,X,Z]),this.getById(J)}getOrCreate(J,X){let Z=this.getById(J);if(Z)return Z;return this.create(J,X)}getById(J){let X=this.db.get("SELECT * FROM sessions WHERE id = ?",[J]);return X?this.mapRow(X):null}getRecent(J,X=10){return this.db.all("SELECT * FROM sessions WHERE project_path = ? ORDER BY started_at DESC LIMIT ?",[J,X]).map((Z)=>this.mapRow(Z))}getAll(J){return this.db.all("SELECT * FROM sessions WHERE project_path = ? ORDER BY started_at DESC",[J]).map((X)=>this.mapRow(X))}getActive(){return this.db.all("SELECT * FROM sessions WHERE status = 'active' ORDER BY started_at DESC").map((J)=>this.mapRow(J))}updateStatus(J,X){this.db.run("UPDATE sessions SET status = ? WHERE id = ?",[X,J])}markCompleted(J){this.db.run("UPDATE sessions SET status = 'completed', ended_at = datetime('now') WHERE id = ?",[J])}incrementObservationCount(J){this.db.run("UPDATE sessions SET observation_count = observation_count + 1 WHERE id = ?",[J])}setSummary(J,X){this.db.run("UPDATE sessions SET summary_id = ? WHERE id = ?",[X,J])}mapRow(J){return{id:J.id,projectPath:J.project_path,startedAt:J.started_at,endedAt:J.ended_at??null,status:J.status,observationCount:J.observation_count,summaryId:J.summary_id??null}}}import{randomUUID as O0}from"crypto";class R{db;constructor(J){this.db=J}create(J){let X=O0(),Z=new Date().toISOString();return this.db.run(`INSERT INTO session_summaries
319
+ (id, session_id, summary, key_decisions, files_modified,
320
+ concepts, created_at, token_count,
321
+ request, investigated, learned, completed, next_steps)
322
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[X,J.sessionId,J.summary,JSON.stringify(J.keyDecisions),JSON.stringify(J.filesModified),JSON.stringify(J.concepts),Z,J.tokenCount,J.request??"",J.investigated??"",J.learned??"",J.completed??"",J.nextSteps??""]),{...J,id:X,createdAt:Z}}importSummary(J){this.db.run(`INSERT INTO session_summaries
323
+ (id, session_id, summary, key_decisions, files_modified,
324
+ concepts, created_at, token_count,
325
+ request, investigated, learned, completed, next_steps)
326
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,[J.id,J.sessionId,J.summary,JSON.stringify(J.keyDecisions),JSON.stringify(J.filesModified),JSON.stringify(J.concepts),J.createdAt,J.tokenCount,J.request??"",J.investigated??"",J.learned??"",J.completed??"",J.nextSteps??""])}getBySessionId(J){let X=this.db.get("SELECT * FROM session_summaries WHERE session_id = ?",[J]);return X?this.mapRow(X):null}getRecent(J=10){return this.db.all("SELECT * FROM session_summaries ORDER BY created_at DESC LIMIT ?",[J]).map((X)=>this.mapRow(X))}search(J,X=10){return this.db.all(`SELECT ss.*
327
+ FROM session_summaries ss
328
+ JOIN summaries_fts fts ON ss._rowid = fts.rowid
329
+ WHERE summaries_fts MATCH ?
330
+ ORDER BY rank
331
+ LIMIT ?`,[J,X]).map((Z)=>this.mapRow(Z))}mapRow(J){return{id:J.id,sessionId:J.session_id,summary:J.summary,keyDecisions:JSON.parse(J.key_decisions),filesModified:JSON.parse(J.files_modified),concepts:JSON.parse(J.concepts),createdAt:J.created_at,tokenCount:J.token_count,request:J.request||void 0,investigated:J.investigated||void 0,learned:J.learned||void 0,completed:J.completed||void 0,nextSteps:J.next_steps||void 0}}}import{embed as D0}from"ai";async function r(J,X){try{let{embedding:Z}=await D0({model:J,value:X});return Z}catch{return null}}function a(J){let X=[J.title,J.narrative];if(J.concepts.length>0)X.push(J.concepts.join(", "));return X.join(`
332
+ `)}class k{config;compressor;summarizer;pendingRepo;observationRepo;sessionRepo;summaryRepo;embeddingModel;processing=!1;timer=null;mode="in-process";onEnqueue=null;constructor(J,X,Z,$,Q,H,V,Y=null){this.config=J;this.compressor=X;this.summarizer=Z;this.pendingRepo=$;this.observationRepo=Q;this.sessionRepo=H;this.summaryRepo=V;this.embeddingModel=Y}setMode(J){if(this.mode=J,J==="enqueue-only")this.stop()}getMode(){return this.mode}setOnEnqueue(J){this.onEnqueue=J}enqueue(J,X,Z,$){if(this.pendingRepo.create({sessionId:J,toolName:X,toolOutput:Z,callId:$}),this.mode==="enqueue-only")this.onEnqueue?.()}async processBatch(){if(this.mode==="enqueue-only")return 0;if(this.processing)return 0;this.processing=!0;let J=0;try{this.pendingRepo.resetStale(5);let X=this.pendingRepo.getPending(this.config.batchSize);if(X.length===0)return 0;for(let Z of X)try{this.pendingRepo.markProcessing(Z.id);let Q=await this.compressor.compress(Z.toolName,Z.toolOutput)??this.compressor.createFallbackObservation(Z.toolName,Z.toolOutput),H=this.observationRepo.create({sessionId:Z.sessionId,type:Q.type,title:Q.title,subtitle:Q.subtitle,facts:Q.facts,narrative:Q.narrative,concepts:Q.concepts,filesRead:Q.filesRead,filesModified:Q.filesModified,rawToolOutput:Z.toolOutput,toolName:Z.toolName,tokenCount:F(`${Q.title} ${Q.narrative} ${Q.facts.join(" ")}`),discoveryTokens:Q.discoveryTokens??F(Z.toolOutput)});if(this.embeddingModel)try{let V=a({title:H.title,narrative:H.narrative,concepts:H.concepts}),Y=await r(this.embeddingModel,V);if(Y)this.observationRepo.setEmbedding(H.id,Y)}catch{}this.sessionRepo.incrementObservationCount(Z.sessionId),this.pendingRepo.markCompleted(Z.id),J++}catch($){this.pendingRepo.markFailed(Z.id,String($))}return J}finally{this.processing=!1}}async summarizeSession(J){let X=this.observationRepo.getBySession(J);if(!this.summarizer.shouldSummarize(X.length))return;if(this.summaryRepo.getBySessionId(J))return;let $=await this.summarizer.summarize(J,X);if(!$)return;let Q=this.summaryRepo.create({sessionId:J,summary:$.summary,keyDecisions:$.keyDecisions,filesModified:$.filesModified,concepts:$.concepts,tokenCount:F($.summary)});this.sessionRepo.setSummary(J,Q.id)}start(){if(this.mode==="enqueue-only")return;if(this.timer)return;this.timer=setInterval(async()=>{try{await this.processBatch()}catch{}},this.config.batchIntervalMs)}stop(){if(this.timer)clearInterval(this.timer),this.timer=null}get isRunning(){return this.timer!==null}get isProcessing(){return this.processing}getStats(){return{pending:this.pendingRepo.getPending(1000).length,processing:this.processing}}}import{spawnSync as t}from"child_process";import{dirname as R0,resolve as e}from"path";function k0(J){try{let X=t("git",["rev-parse","--git-common-dir"],{cwd:J,encoding:"utf-8",timeout:5000});if(X.status!==0||!X.stdout)return null;let Z=X.stdout.trim();if(Z===".git")return null;let $=t("git",["rev-parse","--git-dir"],{cwd:J,encoding:"utf-8",timeout:5000});if($.status!==0||!$.stdout)return null;let Q=$.stdout.trim(),H=e(J,Z),V=e(J,Q);if(H===V)return null;let Y=R0(H);if(Y===H||Y==="/")return null;return Y}catch{return null}}function o(J){return k0(J)??J}var x0=5000,{values:T}=T0({options:{project:{type:"string",short:"p"},"poll-interval":{type:"string"}},strict:!1}),Z0=typeof T.project==="string"?T.project:null;if(!Z0)console.error("Usage: open-mem-daemon --project <path> [--poll-interval <ms>]"),process.exit(1);var J0=T["poll-interval"],x=typeof J0==="string"?Number.parseInt(J0,10):x0;if(Number.isNaN(x)||x<100)console.error("--poll-interval must be a number >= 100"),process.exit(1);var P0=o(Z0),B=g(P0);E.enableExtensionSupport();var L=i(B.dbPath);s(L,{hasVectorExtension:L.hasVectorExtension,embeddingDimension:B.embeddingDimension});var y0=new O(L),I0=new q(L),h0=new D(L),f0=new R(L),v0=new _(B),w0=new C(B),u0=B.provider!=="bedrock",b0=B.compressionEnabled&&(!u0||B.apiKey)?w({provider:B.provider,model:B.model,apiKey:B.apiKey}):null,g0=new k(B,v0,w0,y0,I0,h0,f0,b0),$0=m(B.dbPath);p($0);var P=new j({queueProcessor:g0,pollIntervalMs:x});if(process.send)process.on("message",(J)=>{P.handleMessage(J)});var X0=!1,y=()=>{if(X0)return;X0=!0,P.stop(),l($0),L.close()};process.on("SIGTERM",()=>{y(),process.exit(0)});process.on("SIGINT",()=>{y(),process.exit(0)});process.on("beforeExit",y);P.start();
@@ -0,0 +1 @@
1
+ /*! tailwindcss v4.1.18 | MIT License | https://tailwindcss.com */@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-space-y-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial;--tw-ease:initial}}}@layer theme{:root,:host{--font-sans:"DM Sans",ui-sans-serif,system-ui,sans-serif;--font-serif:"Instrument Serif",ui-serif,Georgia,serif;--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-red-50:#fef2f2;--color-red-200:#fecaca;--color-red-400:#f87171;--color-red-500:#ef4444;--color-red-700:#b91c1c;--color-amber-50:#fffbeb;--color-amber-100:#fef3c7;--color-amber-200:#fde68a;--color-amber-300:oklch(87.9% .169 91.605);--color-amber-400:#fbbf24;--color-amber-500:#f59e0b;--color-amber-600:#d97706;--color-amber-700:#b45309;--color-emerald-50:#ecfdf5;--color-emerald-100:oklch(95% .052 163.051);--color-emerald-200:#a7f3d0;--color-emerald-400:#34d399;--color-emerald-500:oklch(69.6% .17 162.48);--color-emerald-600:oklch(59.6% .145 163.225);--color-emerald-700:#047857;--color-sky-50:#f0f9ff;--color-sky-200:#bae6fd;--color-sky-400:#38bdf8;--color-sky-500:oklch(68.5% .169 237.323);--color-sky-600:oklch(58.8% .158 241.966);--color-sky-700:#0369a1;--color-violet-50:#f5f3ff;--color-violet-200:#ddd6fe;--color-violet-400:#a78bfa;--color-violet-500:oklch(60.6% .25 292.717);--color-violet-600:oklch(54.1% .281 293.009);--color-violet-700:#6d28d9;--color-stone-50:#fafaf9;--color-stone-100:#f5f5f4;--color-stone-200:#e7e5e4;--color-stone-300:#d6d3d1;--color-stone-400:#a8a29e;--color-stone-500:#78716c;--color-stone-600:#57534e;--color-stone-700:#44403c;--color-stone-800:#292524;--color-stone-900:#1c1917;--color-stone-950:#0c0a09;--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-sm:24rem;--container-4xl:56rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-base:1rem;--text-base--line-height: 1.5 ;--text-lg:1.125rem;--text-lg--line-height:calc(1.75/1.125);--text-2xl:1.5rem;--text-2xl--line-height:calc(2/1.5);--text-3xl:1.875rem;--text-3xl--line-height: 1.2 ;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-wide:.025em;--tracking-wider:.05em;--tracking-widest:.1em;--leading-tight:1.25;--leading-snug:1.375;--leading-relaxed:1.625;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--radius-2xl:1rem;--ease-out:cubic-bezier(0,0,.2,1);--animate-spin:spin 1s linear infinite;--animate-pulse:pulse 2s cubic-bezier(.4,0,.6,1)infinite;--blur-sm:8px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.inset-0{inset:calc(var(--spacing)*0)}.inset-y-0{inset-block:calc(var(--spacing)*0)}.top-1\/2{top:50%}.top-3{top:calc(var(--spacing)*3)}.right-2\.5{right:calc(var(--spacing)*2.5)}.right-3{right:calc(var(--spacing)*3)}.left-0{left:calc(var(--spacing)*0)}.left-4{left:calc(var(--spacing)*4)}.z-10{z-index:10}.z-30{z-index:30}.z-40{z-index:40}.mx-auto{margin-inline:auto}.mt-0\.5{margin-top:calc(var(--spacing)*.5)}.mt-1{margin-top:calc(var(--spacing)*1)}.mt-1\.5{margin-top:calc(var(--spacing)*1.5)}.mt-2{margin-top:calc(var(--spacing)*2)}.mt-2\.5{margin-top:calc(var(--spacing)*2.5)}.mt-3{margin-top:calc(var(--spacing)*3)}.mt-6{margin-top:calc(var(--spacing)*6)}.mr-3{margin-right:calc(var(--spacing)*3)}.mb-1{margin-bottom:calc(var(--spacing)*1)}.mb-1\.5{margin-bottom:calc(var(--spacing)*1.5)}.mb-2{margin-bottom:calc(var(--spacing)*2)}.mb-3{margin-bottom:calc(var(--spacing)*3)}.mb-4{margin-bottom:calc(var(--spacing)*4)}.mb-6{margin-bottom:calc(var(--spacing)*6)}.mb-8{margin-bottom:calc(var(--spacing)*8)}.ml-1\.5{margin-left:calc(var(--spacing)*1.5)}.ml-9{margin-left:calc(var(--spacing)*9)}.line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.flex{display:flex}.grid{display:grid}.inline-flex{display:inline-flex}.h-1{height:calc(var(--spacing)*1)}.h-2{height:calc(var(--spacing)*2)}.h-2\.5{height:calc(var(--spacing)*2.5)}.h-3{height:calc(var(--spacing)*3)}.h-4{height:calc(var(--spacing)*4)}.h-5{height:calc(var(--spacing)*5)}.h-6{height:calc(var(--spacing)*6)}.h-7{height:calc(var(--spacing)*7)}.h-8{height:calc(var(--spacing)*8)}.h-9{height:calc(var(--spacing)*9)}.h-14{height:calc(var(--spacing)*14)}.h-16{height:calc(var(--spacing)*16)}.h-full{height:100%}.h-screen{height:100vh}.w-1{width:calc(var(--spacing)*1)}.w-1\/2{width:50%}.w-1\/3{width:33.3333%}.w-2{width:calc(var(--spacing)*2)}.w-2\.5{width:calc(var(--spacing)*2.5)}.w-2\/3{width:66.6667%}.w-3{width:calc(var(--spacing)*3)}.w-3\/4{width:75%}.w-4{width:calc(var(--spacing)*4)}.w-4\/5{width:80%}.w-5{width:calc(var(--spacing)*5)}.w-7{width:calc(var(--spacing)*7)}.w-8{width:calc(var(--spacing)*8)}.w-9{width:calc(var(--spacing)*9)}.w-10{width:calc(var(--spacing)*10)}.w-12{width:calc(var(--spacing)*12)}.w-14{width:calc(var(--spacing)*14)}.w-16{width:calc(var(--spacing)*16)}.w-20{width:calc(var(--spacing)*20)}.w-24{width:calc(var(--spacing)*24)}.w-28{width:calc(var(--spacing)*28)}.w-32{width:calc(var(--spacing)*32)}.w-36{width:calc(var(--spacing)*36)}.w-64{width:calc(var(--spacing)*64)}.w-full{width:100%}.max-w-4xl{max-width:var(--container-4xl)}.max-w-sm{max-width:var(--container-sm)}.min-w-0{min-width:calc(var(--spacing)*0)}.flex-1{flex:1}.shrink-0{flex-shrink:0}.-translate-x-full{--tw-translate-x:-100%;translate:var(--tw-translate-x)var(--tw-translate-y)}.translate-x-0{--tw-translate-x:calc(var(--spacing)*0);translate:var(--tw-translate-x)var(--tw-translate-y)}.-translate-y-1\/2{--tw-translate-y: -50% ;translate:var(--tw-translate-x)var(--tw-translate-y)}.rotate-180{rotate:180deg}.animate-pulse{animation:var(--animate-pulse)}.animate-spin{animation:var(--animate-spin)}.cursor-default{cursor:default}.cursor-pointer{cursor:pointer}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1{gap:calc(var(--spacing)*1)}.gap-1\.5{gap:calc(var(--spacing)*1.5)}.gap-2{gap:calc(var(--spacing)*2)}.gap-2\.5{gap:calc(var(--spacing)*2.5)}.gap-3{gap:calc(var(--spacing)*3)}.gap-4{gap:calc(var(--spacing)*4)}:where(.space-y-0\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*.5)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*.5)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*1)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*1)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-1\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*1.5)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*1.5)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*2)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*2)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*3)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*3)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*4)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*4)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*6)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*6)*calc(1 - var(--tw-space-y-reverse)))}.gap-x-3{column-gap:calc(var(--spacing)*3)}.gap-y-1{row-gap:calc(var(--spacing)*1)}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px*var(--tw-divide-y-reverse));border-bottom-width:calc(1px*calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-stone-50>:not(:last-child)){border-color:var(--color-stone-50)}:where(.divide-stone-100>:not(:last-child)){border-color:var(--color-stone-100)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-hidden{overflow:hidden}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:var(--radius-2xl)}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l-2{border-left-style:var(--tw-border-style);border-left-width:2px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-amber-200{border-color:var(--color-amber-200)}.border-red-200{border-color:var(--color-red-200)}.border-stone-100{border-color:var(--color-stone-100)}.border-stone-200{border-color:var(--color-stone-200)}.border-stone-200\/80{border-color:#e7e5e4cc}@supports (color:color-mix(in lab,red,red)){.border-stone-200\/80{border-color:color-mix(in oklab,var(--color-stone-200)80%,transparent)}}.border-stone-300{border-color:var(--color-stone-300)}.border-stone-800{border-color:var(--color-stone-800)}.border-t-amber-500{border-top-color:var(--color-amber-500)}.bg-amber-50{background-color:var(--color-amber-50)}.bg-amber-100{background-color:var(--color-amber-100)}.bg-amber-400{background-color:var(--color-amber-400)}.bg-amber-500{background-color:var(--color-amber-500)}.bg-amber-500\/10{background-color:#f59e0b1a}@supports (color:color-mix(in lab,red,red)){.bg-amber-500\/10{background-color:color-mix(in oklab,var(--color-amber-500)10%,transparent)}}.bg-amber-500\/20{background-color:#f59e0b33}@supports (color:color-mix(in lab,red,red)){.bg-amber-500\/20{background-color:color-mix(in oklab,var(--color-amber-500)20%,transparent)}}.bg-black\/40{background-color:#0006}@supports (color:color-mix(in lab,red,red)){.bg-black\/40{background-color:color-mix(in oklab,var(--color-black)40%,transparent)}}.bg-emerald-50{background-color:var(--color-emerald-50)}.bg-emerald-100{background-color:var(--color-emerald-100)}.bg-emerald-400{background-color:var(--color-emerald-400)}.bg-emerald-500\/10{background-color:#00bb7f1a}@supports (color:color-mix(in lab,red,red)){.bg-emerald-500\/10{background-color:color-mix(in oklab,var(--color-emerald-500)10%,transparent)}}.bg-red-50{background-color:var(--color-red-50)}.bg-red-400{background-color:var(--color-red-400)}.bg-sky-50{background-color:var(--color-sky-50)}.bg-sky-400{background-color:var(--color-sky-400)}.bg-sky-500\/10{background-color:#00a5ef1a}@supports (color:color-mix(in lab,red,red)){.bg-sky-500\/10{background-color:color-mix(in oklab,var(--color-sky-500)10%,transparent)}}.bg-stone-50{background-color:var(--color-stone-50)}.bg-stone-50\/50{background-color:#fafaf980}@supports (color:color-mix(in lab,red,red)){.bg-stone-50\/50{background-color:color-mix(in oklab,var(--color-stone-50)50%,transparent)}}.bg-stone-100{background-color:var(--color-stone-100)}.bg-stone-200{background-color:var(--color-stone-200)}.bg-stone-300{background-color:var(--color-stone-300)}.bg-stone-400{background-color:var(--color-stone-400)}.bg-stone-900{background-color:var(--color-stone-900)}.bg-violet-50{background-color:var(--color-violet-50)}.bg-violet-400{background-color:var(--color-violet-400)}.bg-violet-500\/10{background-color:#8d54ff1a}@supports (color:color-mix(in lab,red,red)){.bg-violet-500\/10{background-color:color-mix(in oklab,var(--color-violet-500)10%,transparent)}}.bg-white{background-color:var(--color-white)}.bg-gradient-to-br{--tw-gradient-position:to bottom right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.from-stone-50\/80{--tw-gradient-from:#fafaf9cc}@supports (color:color-mix(in lab,red,red)){.from-stone-50\/80{--tw-gradient-from:color-mix(in oklab,var(--color-stone-50)80%,transparent)}}.from-stone-50\/80{--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-transparent{--tw-gradient-to:transparent;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.p-1{padding:calc(var(--spacing)*1)}.p-2{padding:calc(var(--spacing)*2)}.p-3{padding:calc(var(--spacing)*3)}.p-5{padding:calc(var(--spacing)*5)}.p-6{padding:calc(var(--spacing)*6)}.px-1\.5{padding-inline:calc(var(--spacing)*1.5)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-2\.5{padding-inline:calc(var(--spacing)*2.5)}.px-3{padding-inline:calc(var(--spacing)*3)}.px-4{padding-inline:calc(var(--spacing)*4)}.px-5{padding-inline:calc(var(--spacing)*5)}.px-6{padding-inline:calc(var(--spacing)*6)}.px-8{padding-inline:calc(var(--spacing)*8)}.py-0\.5{padding-block:calc(var(--spacing)*.5)}.py-1{padding-block:calc(var(--spacing)*1)}.py-2{padding-block:calc(var(--spacing)*2)}.py-2\.5{padding-block:calc(var(--spacing)*2.5)}.py-3{padding-block:calc(var(--spacing)*3)}.py-3\.5{padding-block:calc(var(--spacing)*3.5)}.py-4{padding-block:calc(var(--spacing)*4)}.py-8{padding-block:calc(var(--spacing)*8)}.py-16{padding-block:calc(var(--spacing)*16)}.py-20{padding-block:calc(var(--spacing)*20)}.pt-2{padding-top:calc(var(--spacing)*2)}.pr-9{padding-right:calc(var(--spacing)*9)}.pr-10{padding-right:calc(var(--spacing)*10)}.pb-8{padding-bottom:calc(var(--spacing)*8)}.pl-3{padding-left:calc(var(--spacing)*3)}.pl-8{padding-left:calc(var(--spacing)*8)}.pl-12{padding-left:calc(var(--spacing)*12)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.font-serif{font-family:var(--font-serif)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[13px\]{font-size:13px}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.text-amber-400{color:var(--color-amber-400)}.text-amber-500{color:var(--color-amber-500)}.text-amber-600{color:var(--color-amber-600)}.text-amber-700{color:var(--color-amber-700)}.text-emerald-600{color:var(--color-emerald-600)}.text-emerald-700{color:var(--color-emerald-700)}.text-red-500{color:var(--color-red-500)}.text-red-700{color:var(--color-red-700)}.text-sky-600{color:var(--color-sky-600)}.text-sky-700{color:var(--color-sky-700)}.text-stone-100{color:var(--color-stone-100)}.text-stone-300{color:var(--color-stone-300)}.text-stone-400{color:var(--color-stone-400)}.text-stone-500{color:var(--color-stone-500)}.text-stone-600{color:var(--color-stone-600)}.text-stone-700{color:var(--color-stone-700)}.text-stone-800{color:var(--color-stone-800)}.text-stone-900{color:var(--color-stone-900)}.text-violet-600{color:var(--color-violet-600)}.text-violet-700{color:var(--color-violet-700)}.uppercase{text-transform:uppercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,)var(--tw-slashed-zero,)var(--tw-numeric-figure,)var(--tw-numeric-spacing,)var(--tw-numeric-fraction,)}.opacity-0{opacity:0}.opacity-25{opacity:.25}.opacity-75{opacity:.75}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a),0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-1{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(1px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-\[3px\]{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(3px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-amber-500\/5{--tw-shadow-color:#f59e0b0d}@supports (color:color-mix(in lab,red,red)){.shadow-amber-500\/5{--tw-shadow-color:color-mix(in oklab,color-mix(in oklab,var(--color-amber-500)5%,transparent)var(--tw-shadow-alpha),transparent)}}.ring-amber-200{--tw-ring-color:var(--color-amber-200)}.ring-amber-200\/60{--tw-ring-color:#fde68a99}@supports (color:color-mix(in lab,red,red)){.ring-amber-200\/60{--tw-ring-color:color-mix(in oklab,var(--color-amber-200)60%,transparent)}}.ring-emerald-200{--tw-ring-color:var(--color-emerald-200)}.ring-red-200{--tw-ring-color:var(--color-red-200)}.ring-sky-200{--tw-ring-color:var(--color-sky-200)}.ring-stone-200{--tw-ring-color:var(--color-stone-200)}.ring-stone-200\/60{--tw-ring-color:#e7e5e499}@supports (color:color-mix(in lab,red,red)){.ring-stone-200\/60{--tw-ring-color:color-mix(in oklab,var(--color-stone-200)60%,transparent)}}.ring-violet-200{--tw-ring-color:var(--color-violet-200)}.ring-white{--tw-ring-color:var(--color-white)}.filter{filter:var(--tw-blur,)var(--tw-brightness,)var(--tw-contrast,)var(--tw-grayscale,)var(--tw-hue-rotate,)var(--tw-invert,)var(--tw-saturate,)var(--tw-sepia,)var(--tw-drop-shadow,)}.backdrop-blur-sm{--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,)var(--tw-backdrop-brightness,)var(--tw-backdrop-contrast,)var(--tw-backdrop-grayscale,)var(--tw-backdrop-hue-rotate,)var(--tw-backdrop-invert,)var(--tw-backdrop-opacity,)var(--tw-backdrop-saturate,)var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,)var(--tw-backdrop-brightness,)var(--tw-backdrop-contrast,)var(--tw-backdrop-grayscale,)var(--tw-backdrop-hue-rotate,)var(--tw-backdrop-invert,)var(--tw-backdrop-opacity,)var(--tw-backdrop-saturate,)var(--tw-backdrop-sepia,)}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-150{--tw-duration:.15s;transition-duration:.15s}.duration-200{--tw-duration:.2s;transition-duration:.2s}.duration-300{--tw-duration:.3s;transition-duration:.3s}.duration-500{--tw-duration:.5s;transition-duration:.5s}.ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}.outline-none{--tw-outline-style:none;outline-style:none}.ring-inset{--tw-ring-inset:inset}@media(hover:hover){.group-hover\:text-stone-500:is(:where(.group):hover *){color:var(--color-stone-500)}.group-hover\:text-stone-950:is(:where(.group):hover *){color:var(--color-stone-950)}.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}}.placeholder\:text-stone-400::placeholder{color:var(--color-stone-400)}.last\:border-b-0:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}@media(hover:hover){.hover\:border-stone-300:hover{border-color:var(--color-stone-300)}.hover\:bg-stone-50:hover{background-color:var(--color-stone-50)}.hover\:bg-stone-100:hover{background-color:var(--color-stone-100)}.hover\:bg-stone-800:hover{background-color:var(--color-stone-800)}.hover\:text-stone-200:hover{color:var(--color-stone-200)}.hover\:text-stone-500:hover{color:var(--color-stone-500)}.hover\:text-stone-700:hover{color:var(--color-stone-700)}.hover\:shadow-md:hover{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a),0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.hover\:shadow-stone-200\/50:hover{--tw-shadow-color:#e7e5e480}@supports (color:color-mix(in lab,red,red)){.hover\:shadow-stone-200\/50:hover{--tw-shadow-color:color-mix(in oklab,color-mix(in oklab,var(--color-stone-200)50%,transparent)var(--tw-shadow-alpha),transparent)}}.hover\:ring-stone-300\/80:hover{--tw-ring-color:#d6d3d1cc}@supports (color:color-mix(in lab,red,red)){.hover\:ring-stone-300\/80:hover{--tw-ring-color:color-mix(in oklab,var(--color-stone-300)80%,transparent)}}}.focus\:border-amber-300:focus{border-color:var(--color-amber-300)}.focus\:border-amber-400:focus{border-color:var(--color-amber-400)}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(2px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-amber-200\/50:focus{--tw-ring-color:#fde68a80}@supports (color:color-mix(in lab,red,red)){.focus\:ring-amber-200\/50:focus{--tw-ring-color:color-mix(in oklab,var(--color-amber-200)50%,transparent)}}.focus\:ring-amber-400\/20:focus{--tw-ring-color:#fbbf2433}@supports (color:color-mix(in lab,red,red)){.focus\:ring-amber-400\/20:focus{--tw-ring-color:color-mix(in oklab,var(--color-amber-400)20%,transparent)}}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.active\:scale-\[0\.98\]:active{scale:.98}@media(min-width:40rem){.sm\:w-44{width:calc(var(--spacing)*44)}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:flex-row{flex-direction:row}.sm\:items-end{align-items:flex-end}.sm\:justify-between{justify-content:space-between}}@media(min-width:64rem){.lg\:static{position:static}.lg\:hidden{display:none}.lg\:translate-x-0{--tw-translate-x:calc(var(--spacing)*0);translate:var(--tw-translate-x)var(--tw-translate-y)}.lg\:p-8{padding:calc(var(--spacing)*8)}}}body{font-family:var(--font-sans);background-color:var(--color-stone-50);color:var(--color-stone-900);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.sidebar-grain{position:relative}.sidebar-grain:after{content:"";opacity:.03;pointer-events:none;background-image:url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");position:absolute;top:0;right:0;bottom:0;left:0}@keyframes timeline-fade-in{0%{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:translateY(0)}}.timeline-item-new{animation:.4s ease-out timeline-fade-in}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"<length-percentage>";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"<length-percentage>";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"<length-percentage>";inherits:false;initial-value:100%}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@keyframes spin{to{transform:rotate(360deg)}}@keyframes pulse{50%{opacity:.5}}