@oratis/lisa 0.3.0 → 0.3.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 (44) hide show
  1. package/README.md +34 -5
  2. package/README.zh-CN.md +34 -5
  3. package/dist/channels/imessage.d.ts +16 -0
  4. package/dist/channels/imessage.d.ts.map +1 -1
  5. package/dist/channels/imessage.js +29 -8
  6. package/dist/channels/imessage.js.map +1 -1
  7. package/dist/heartbeat/config.d.ts +10 -0
  8. package/dist/heartbeat/config.d.ts.map +1 -1
  9. package/dist/heartbeat/config.js +8 -2
  10. package/dist/heartbeat/config.js.map +1 -1
  11. package/dist/heartbeat/runner.d.ts.map +1 -1
  12. package/dist/heartbeat/runner.js +30 -0
  13. package/dist/heartbeat/runner.js.map +1 -1
  14. package/dist/memory/vector.d.ts +5 -1
  15. package/dist/memory/vector.d.ts.map +1 -1
  16. package/dist/memory/vector.js +58 -1
  17. package/dist/memory/vector.js.map +1 -1
  18. package/dist/soul/lock.d.ts +38 -0
  19. package/dist/soul/lock.d.ts.map +1 -0
  20. package/dist/soul/lock.js +103 -0
  21. package/dist/soul/lock.js.map +1 -0
  22. package/dist/soul/paths.d.ts.map +1 -1
  23. package/dist/soul/paths.js +12 -6
  24. package/dist/soul/paths.js.map +1 -1
  25. package/dist/soul/slug.d.ts +40 -0
  26. package/dist/soul/slug.d.ts.map +1 -0
  27. package/dist/soul/slug.js +78 -0
  28. package/dist/soul/slug.js.map +1 -0
  29. package/dist/soul/store.d.ts +12 -1
  30. package/dist/soul/store.d.ts.map +1 -1
  31. package/dist/soul/store.js +40 -23
  32. package/dist/soul/store.js.map +1 -1
  33. package/dist/soul/tools.d.ts.map +1 -1
  34. package/dist/soul/tools.js +10 -3
  35. package/dist/soul/tools.js.map +1 -1
  36. package/dist/tools/web_fetch.d.ts +10 -0
  37. package/dist/tools/web_fetch.d.ts.map +1 -1
  38. package/dist/tools/web_fetch.js +48 -16
  39. package/dist/tools/web_fetch.js.map +1 -1
  40. package/dist/web/island.d.ts +1 -1
  41. package/dist/web/island.d.ts.map +1 -1
  42. package/dist/web/island.js +26 -5
  43. package/dist/web/island.js.map +1 -1
  44. package/package.json +3 -1
package/README.md CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  [![npm](https://img.shields.io/npm/v/@oratis/lisa?color=cb3837&label=npm)](https://www.npmjs.com/package/@oratis/lisa)
4
4
  [![Homebrew](https://img.shields.io/badge/homebrew-oratis%2Ftap%2Flisa-fbb040)](https://github.com/oratis/homebrew-tap)
5
+ [![Mac DMG](https://img.shields.io/github/v/release/oratis/LISA?label=Mac%20app&color=000000&logo=apple)](https://github.com/oratis/LISA/releases/latest)
5
6
  [![License: MIT](https://img.shields.io/github/license/oratis/LISA?color=blue)](./LICENSE)
6
7
  [![GitHub Repo stars](https://img.shields.io/github/stars/oratis/LISA?style=social)](https://github.com/oratis/LISA/stargazers)
7
8
 
@@ -116,7 +117,39 @@ She is yours. The code is open source. **This particular Lisa is sovereign.**
116
117
 
117
118
  ## Install
118
119
 
119
- Requires Node 20 and a key for **at least one LLM provider** — Anthropic is the default, but any of the 20+ alternatives listed below works just as well (`--model gpt-4o`, `--model deepseek-chat`, `LISA_BASE_URL=http://localhost:11434/v1` for Ollama, etc.).
120
+ Three ways, pick one. All of them need an LLM key — Anthropic is the default, but any of the 20+ alternatives listed below works just as well (`--model gpt-4o`, `--model deepseek-chat`, `LISA_BASE_URL=http://localhost:11434/v1` for Ollama, etc.).
121
+
122
+ ```sh
123
+ # 1. Configure a provider key (do this once, regardless of which install you pick)
124
+ mkdir -p ~/.lisa
125
+ echo 'ANTHROPIC_API_KEY=sk-ant-...' > ~/.lisa/config.env
126
+ ```
127
+
128
+ ### 🍎 Mac apps (recommended on macOS)
129
+
130
+ Download the **signed + notarized** disk image from the latest GitHub Release — no Gatekeeper warning, no `xattr` workaround:
131
+
132
+ **→ [Download `Lisa-Suite.dmg`](https://github.com/oratis/LISA/releases/latest)**
133
+
134
+ The DMG contains:
135
+ - **Lisa.app** — full chat client (sidebar + glass-morphism UI)
136
+ - **LisaIsland.app** — pill widget that lives by the menu bar / notch, shows her mood + Claude Code activity at a glance
137
+
138
+ Both are universal binaries (Intel + Apple Silicon). After dragging them to `/Applications`, install the LISA backend and start it:
139
+
140
+ ```sh
141
+ npm install -g @oratis/lisa
142
+ lisa serve --web # apps load http://localhost:5757
143
+ ```
144
+
145
+ ### 📟 Homebrew (CLI only)
146
+
147
+ ```sh
148
+ brew install oratis/tap/lisa
149
+ lisa # birth ritual on first run
150
+ ```
151
+
152
+ ### 🛠 From source (full control)
120
153
 
121
154
  ```sh
122
155
  git clone https://github.com/oratis/LISA.git
@@ -124,10 +157,6 @@ cd LISA
124
157
  npm install
125
158
  npm run build
126
159
 
127
- # Configure a key — Anthropic is the default model, swap for any provider below
128
- mkdir -p ~/.lisa
129
- echo 'ANTHROPIC_API_KEY=sk-ant-...' > ~/.lisa/config.env
130
-
131
160
  # First run triggers the birth ritual automatically (~30s, one-time)
132
161
  node dist/cli.js
133
162
  # or, after `npm link`:
package/README.zh-CN.md CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  [![npm](https://img.shields.io/npm/v/@oratis/lisa?color=cb3837&label=npm)](https://www.npmjs.com/package/@oratis/lisa)
4
4
  [![Homebrew](https://img.shields.io/badge/homebrew-oratis%2Ftap%2Flisa-fbb040)](https://github.com/oratis/homebrew-tap)
5
+ [![Mac DMG](https://img.shields.io/github/v/release/oratis/LISA?label=Mac%20app&color=000000&logo=apple)](https://github.com/oratis/LISA/releases/latest)
5
6
  [![License: MIT](https://img.shields.io/github/license/oratis/LISA?color=blue)](./LICENSE)
6
7
  [![GitHub Repo stars](https://img.shields.io/github/stars/oratis/LISA?style=social)](https://github.com/oratis/LISA/stargazers)
7
8
 
@@ -113,7 +114,39 @@
113
114
 
114
115
  ## 安装
115
116
 
116
- Node ≥ 20 + **任一 LLM provider 的 key** —— 默认走 Anthropic,但下面列的 20+ 个 provider 任何一个都行(`--model gpt-4o`、`--model deepseek-chat`、Ollama 走 `LISA_BASE_URL=http://localhost:11434/v1` 等)。
117
+ 三种方式,任选其一。都需要至少一个 LLM provider 的 key —— 默认 Anthropic,下面列的 20+ 个 provider 都行(`--model gpt-4o`、`--model deepseek-chat`、Ollama 走 `LISA_BASE_URL=http://localhost:11434/v1` 等)。
118
+
119
+ ```sh
120
+ # 1. 配置 provider key(只需要做一次,与下面装哪种无关)
121
+ mkdir -p ~/.lisa
122
+ echo 'ANTHROPIC_API_KEY=sk-ant-...' > ~/.lisa/config.env
123
+ ```
124
+
125
+ ### 🍎 Mac 原生 App(macOS 推荐)
126
+
127
+ 从 GitHub Release 下载**已签名 + 已公证**的 DMG —— 没有 Gatekeeper 警告,无需 `xattr` 解除隔离:
128
+
129
+ **→ [下载 `Lisa-Suite.dmg`](https://github.com/oratis/LISA/releases/latest)**
130
+
131
+ DMG 里有两个 app:
132
+ - **Lisa.app** —— 完整聊天客户端(侧边栏 + 玻璃拟态界面)
133
+ - **LisaIsland.app** —— 灵动岛风格的菜单栏/刘海下小条,一眼看到 Lisa 心情 + 你那边 Claude Code 的状态
134
+
135
+ 都是 universal binary(Intel + Apple Silicon)。拖到 `/Applications` 之后,装 backend 并启动:
136
+
137
+ ```sh
138
+ npm install -g @oratis/lisa
139
+ lisa serve --web # 两个 app 都从 http://localhost:5757 读
140
+ ```
141
+
142
+ ### 📟 Homebrew(只装 CLI)
143
+
144
+ ```sh
145
+ brew install oratis/tap/lisa
146
+ lisa # 第一次跑会触发 birth ritual
147
+ ```
148
+
149
+ ### 🛠 从源码(完全控制)
117
150
 
118
151
  ```sh
119
152
  git clone https://github.com/oratis/LISA.git
@@ -121,10 +154,6 @@ cd LISA
121
154
  npm install
122
155
  npm run build
123
156
 
124
- # 配置 key —— 默认模型走 Anthropic;想换 provider 看下面那张表
125
- mkdir -p ~/.lisa
126
- echo 'ANTHROPIC_API_KEY=sk-ant-...' > ~/.lisa/config.env
127
-
128
157
  # 第一次跑会自动触发 birth ritual(约 30 秒,一次性)
129
158
  node dist/cli.js
130
159
  # 或者 npm link 之后:
@@ -17,4 +17,20 @@ export declare class IMessageChannel implements ChannelAdapter {
17
17
  private fetchSince;
18
18
  private runSqlite;
19
19
  }
20
+ /**
21
+ * Build the osascript argv for sending an iMessage WITHOUT interpolating
22
+ * user/LLM text into the AppleScript source.
23
+ *
24
+ * The old approach (`send "${text}"`) only escaped double-quotes, so a
25
+ * message containing a newline — or a crafted `" & (do shell script "...")`
26
+ * payload — could break out of the string literal and inject AppleScript.
27
+ * Inbound iMessage text is untrusted (anyone who can text the user), so this
28
+ * was a real injection vector.
29
+ *
30
+ * Instead the script is a STATIC `on run argv` program; recipient and text
31
+ * arrive as positional argv items (`item 1`/`item 2 of argv`) that AppleScript
32
+ * never parses as source. No escaping needed; newlines/quotes/backslashes
33
+ * survive verbatim.
34
+ */
35
+ export declare function buildOsascriptArgs(recipient: string, text: string): string[];
20
36
  //# sourceMappingURL=imessage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"imessage.d.ts","sourceRoot":"","sources":["../../src/channels/imessage.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EACf,eAAe,EAChB,MAAM,YAAY,CAAC;AAIpB,qBAAa,eAAgB,YAAW,cAAc;IACpD,QAAQ,CAAC,IAAI,cAAc;IAC3B,OAAO,CAAC,KAAK,CAAC,CAAiB;IAC/B,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,OAAO,CAAC,CAA0C;IAC1D,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,UAAU,CAAS;gBAEf,IAAI,GAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAA;KAAO;IAIxC,KAAK,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;YAa9D,IAAI;IAuBZ,IAAI,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBzC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAIb,QAAQ;YAMR,UAAU;YAiCV,SAAS;CAexB"}
1
+ {"version":3,"file":"imessage.d.ts","sourceRoot":"","sources":["../../src/channels/imessage.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EACf,eAAe,EAChB,MAAM,YAAY,CAAC;AAIpB,qBAAa,eAAgB,YAAW,cAAc;IACpD,QAAQ,CAAC,IAAI,cAAc;IAC3B,OAAO,CAAC,KAAK,CAAC,CAAiB;IAC/B,OAAO,CAAC,SAAS,CAAK;IACtB,OAAO,CAAC,OAAO,CAAC,CAA0C;IAC1D,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,UAAU,CAAS;gBAEf,IAAI,GAAE;QAAE,UAAU,CAAC,EAAE,MAAM,CAAA;KAAO;IAIxC,KAAK,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;YAa9D,IAAI;IAuBZ,IAAI,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAezC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAIb,QAAQ;YAMR,UAAU;YAiCV,SAAS;CAexB;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAW5E"}
@@ -53,15 +53,9 @@ export class IMessageChannel {
53
53
  }
54
54
  }
55
55
  async send(msg) {
56
- const recipient = msg.to.replace(/"/g, '\\"');
57
- const text = msg.text.replace(/"/g, '\\"');
58
- const script = `tell application "Messages"
59
- set targetService to first service whose service type = iMessage
60
- set targetBuddy to buddy "${recipient}" of targetService
61
- send "${text}" to targetBuddy
62
- end tell`;
56
+ const args = buildOsascriptArgs(msg.to, msg.text);
63
57
  await new Promise((resolve, reject) => {
64
- const child = spawn("/usr/bin/osascript", ["-e", script]);
58
+ const child = spawn("/usr/bin/osascript", args);
65
59
  let stderr = "";
66
60
  child.stderr.on("data", (b) => (stderr += b.toString("utf8")));
67
61
  child.on("error", reject);
@@ -117,6 +111,33 @@ end tell`;
117
111
  });
118
112
  }
119
113
  }
114
+ /**
115
+ * Build the osascript argv for sending an iMessage WITHOUT interpolating
116
+ * user/LLM text into the AppleScript source.
117
+ *
118
+ * The old approach (`send "${text}"`) only escaped double-quotes, so a
119
+ * message containing a newline — or a crafted `" & (do shell script "...")`
120
+ * payload — could break out of the string literal and inject AppleScript.
121
+ * Inbound iMessage text is untrusted (anyone who can text the user), so this
122
+ * was a real injection vector.
123
+ *
124
+ * Instead the script is a STATIC `on run argv` program; recipient and text
125
+ * arrive as positional argv items (`item 1`/`item 2 of argv`) that AppleScript
126
+ * never parses as source. No escaping needed; newlines/quotes/backslashes
127
+ * survive verbatim.
128
+ */
129
+ export function buildOsascriptArgs(recipient, text) {
130
+ const script = `on run argv
131
+ set theRecipient to item 1 of argv
132
+ set theText to item 2 of argv
133
+ tell application "Messages"
134
+ set targetService to first service whose service type = iMessage
135
+ set targetBuddy to buddy theRecipient of targetService
136
+ send theText to targetBuddy
137
+ end tell
138
+ end run`;
139
+ return ["-e", script, recipient, text];
140
+ }
120
141
  registerChannel("imessage", (cfg) => {
121
142
  const intervalMs = typeof cfg.intervalMs === "number" ? cfg.intervalMs : undefined;
122
143
  return new IMessageChannel(intervalMs ? { intervalMs } : {});
@@ -1 +1 @@
1
- {"version":3,"file":"imessage.js","sourceRoot":"","sources":["../../src/channels/imessage.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAOhD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;AAE1E,MAAM,OAAO,eAAe;IACjB,IAAI,GAAG,UAAU,CAAC;IACnB,KAAK,CAAkB;IACvB,SAAS,GAAG,CAAC,CAAC;IACd,OAAO,CAA2C;IAClD,OAAO,GAAG,KAAK,CAAC;IAChB,UAAU,CAAS;IAE3B,YAAY,OAAgC,EAAE;QAC5C,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,KAAK,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,OAAgD;QAC1D,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC3B,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CACb,wGAAwG,CACzG,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,SAAS,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;QACvC,IAAI,CAAC,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IAC/D,CAAC;IAEO,KAAK,CAAC,IAAI;QAChB,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO;QACzB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACvD,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;gBAC3B,IAAI,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,SAAS;oBAAE,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC,KAAK,CAAC;gBAC3D,IAAI,GAAG,CAAC,MAAM;oBAAE,SAAS;gBACzB,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;oBACnB,OAAO,EAAE,IAAI,CAAC,IAAI;oBAClB,IAAI,EAAE,GAAG,CAAC,MAAM,IAAI,SAAS;oBAC7B,IAAI,EAAE,GAAG,CAAC,IAAI;oBACd,QAAQ,EAAE,GAAG,CAAC,QAAQ;oBACtB,UAAU,EAAE,IAAI,IAAI,EAAE;iBACvB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,0BAA2B,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;QACpE,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACvB,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,GAAoB;QAC7B,MAAM,SAAS,GAAG,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC9C,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC3C,MAAM,MAAM,GAAG;;8BAEW,SAAS;UAC7B,IAAI;SACL,CAAC;QACN,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC1C,MAAM,KAAK,GAAG,KAAK,CAAC,oBAAoB,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;YAC1D,IAAI,MAAM,GAAG,EAAE,CAAC;YAChB,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAC/D,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC1B,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CACzB,IAAI,KAAK,CAAC;gBACR,CAAC,CAAC,OAAO,EAAE;gBACX,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,oBAAoB,IAAI,KAAK,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CACpE,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,IAAI;QACR,IAAI,IAAI,CAAC,KAAK;YAAE,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;IAEO,KAAK,CAAC,QAAQ;QACpB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,iCAAiC,CAAC,CAAC;QACpE,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QACnC,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1B,CAAC;IAEO,KAAK,CAAC,UAAU,CAAC,KAAa;QASpC,MAAM,GAAG,GAAG;;;mCAGmB,KAAK;gDACQ,CAAC;QAC7C,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACtC,MAAM,IAAI,GAEE,EAAE,CAAC;QACf,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YACnC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;gBAAE,SAAS;YAC3B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC9B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;gBAAE,SAAS;YAC/B,IAAI,CAAC,IAAI,CAAC;gBACR,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAE,EAAE,EAAE,CAAC;gBAC9B,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI;gBACxB,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE;gBACpB,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,GAAG;gBACxB,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE;aACzB,CAAC,CAAC;QACL,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,KAAK,CAAC,SAAS,CAAC,GAAW;QACjC,OAAO,MAAM,IAAI,OAAO,CAAS,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACnD,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC,WAAW,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;YAC5D,IAAI,MAAM,GAAG,EAAE,CAAC;YAChB,IAAI,MAAM,GAAG,EAAE,CAAC;YAChB,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAC/D,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAC/D,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;YAC1B,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CACzB,IAAI,KAAK,CAAC;gBACR,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;gBACjB,CAAC,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,kBAAkB,IAAI,KAAK,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAClE,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;CACF;AAED,eAAe,CAAC,UAAU,EAAE,CAAC,GAAG,EAAE,EAAE;IAClC,MAAM,UAAU,GAAG,OAAO,GAAG,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;IACnF,OAAO,IAAI,eAAe,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAC/D,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"imessage.js","sourceRoot":"","sources":["../../src/channels/imessage.ts"],"names":[],"mappings":"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"}
@@ -7,7 +7,17 @@ export interface HeartbeatTask {
7
7
  }
8
8
  export interface HeartbeatConfig {
9
9
  tasks: HeartbeatTask[];
10
+ /**
11
+ * Max combined (input+output) tokens to spend across all tasks in a single
12
+ * heartbeat invocation. Once exceeded, remaining tasks are skipped (logged,
13
+ * not silently dropped). Guards against the runaway-cost case: a short
14
+ * interval × several actionable desires × deep tool loops can otherwise run
15
+ * to millions of tokens/day unbounded. 0 / unset = no limit.
16
+ */
17
+ budgetTokens?: number;
10
18
  }
19
+ /** Default per-run token ceiling when heartbeat.json doesn't set one. */
20
+ export declare const DEFAULT_HEARTBEAT_BUDGET_TOKENS = 500000;
11
21
  export declare function loadHeartbeatConfig(): Promise<HeartbeatConfig>;
12
22
  export declare const HEARTBEAT_CONFIG_PATH: string;
13
23
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/heartbeat/config.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0FAA0F;IAC1F,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,aAAa,EAAE,CAAC;CACxB;AAID,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,eAAe,CAAC,CAUpE;AAED,eAAO,MAAM,qBAAqB,QAAO,CAAC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/heartbeat/config.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0FAA0F;IAC1F,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,yEAAyE;AACzE,eAAO,MAAM,+BAA+B,SAAU,CAAC;AAIvD,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,eAAe,CAAC,CAepE;AAED,eAAO,MAAM,qBAAqB,QAAO,CAAC"}
@@ -2,10 +2,12 @@ import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { LISA_HOME } from "../paths.js";
4
4
  import { pathExists } from "../fs-utils.js";
5
+ /** Default per-run token ceiling when heartbeat.json doesn't set one. */
6
+ export const DEFAULT_HEARTBEAT_BUDGET_TOKENS = 500_000;
5
7
  const FILE = path.join(LISA_HOME, "heartbeat.json");
6
8
  export async function loadHeartbeatConfig() {
7
9
  if (!(await pathExists(FILE)))
8
- return { tasks: [] };
10
+ return { tasks: [], budgetTokens: DEFAULT_HEARTBEAT_BUDGET_TOKENS };
9
11
  const raw = await fs.readFile(FILE, "utf8");
10
12
  let parsed;
11
13
  try {
@@ -14,7 +16,11 @@ export async function loadHeartbeatConfig() {
14
16
  catch (err) {
15
17
  throw new Error(`failed to parse ${FILE}: ${err.message}`);
16
18
  }
17
- return { tasks: parsed.tasks ?? [] };
19
+ return {
20
+ tasks: parsed.tasks ?? [],
21
+ // Explicit 0 means "no limit"; undefined means "use the default ceiling".
22
+ budgetTokens: parsed.budgetTokens === undefined ? DEFAULT_HEARTBEAT_BUDGET_TOKENS : parsed.budgetTokens,
23
+ };
18
24
  }
19
25
  export const HEARTBEAT_CONFIG_PATH = FILE;
20
26
  //# sourceMappingURL=config.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/heartbeat/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAc5C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;AAEpD,MAAM,CAAC,KAAK,UAAU,mBAAmB;IACvC,IAAI,CAAC,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IACpD,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC5C,IAAI,MAAuB,CAAC;IAC5B,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAoB,CAAC;IAC9C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,mBAAmB,IAAI,KAAM,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC;AACvC,CAAC;AAED,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/heartbeat/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAsB5C,yEAAyE;AACzE,MAAM,CAAC,MAAM,+BAA+B,GAAG,OAAO,CAAC;AAEvD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;AAEpD,MAAM,CAAC,KAAK,UAAU,mBAAmB;IACvC,IAAI,CAAC,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,YAAY,EAAE,+BAA+B,EAAE,CAAC;IACnG,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC5C,IAAI,MAAuB,CAAC;IAC5B,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAoB,CAAC;IAC9C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,mBAAmB,IAAI,KAAM,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;IACxE,CAAC;IACD,OAAO;QACL,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,EAAE;QACzB,0EAA0E;QAC1E,YAAY,EACV,MAAM,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,+BAA+B,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY;KAC5F,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/heartbeat/runner.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,aAAa,CAAC;AAkBrB,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,WAAW,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CA4EhC;AAiBD,YAAY,EAAE,aAAa,EAAE,CAAC"}
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/heartbeat/runner.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAEL,KAAK,aAAa,EACnB,MAAM,aAAa,CAAC;AAmBrB,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,WAAW,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAgBhC;AAkHD,YAAY,EAAE,aAAa,EAAE,CAAC"}
@@ -3,9 +3,11 @@ import { atomicWrite, readTextOrEmpty } from "../fs-utils.js";
3
3
  import { LISA_HOME } from "../paths.js";
4
4
  import { appendDesireProgress, isBorn, listDesires, parseDesireProgress, readDesireProgress, readSeed, } from "../soul/store.js";
5
5
  import { withSoulCaller } from "../soul/git.js";
6
+ import { withFileLock } from "../soul/lock.js";
6
7
  import { runSubagent } from "../subagent.js";
7
8
  import { loadHeartbeatConfig, } from "./config.js";
8
9
  const STATE_FILE = path.join(LISA_HOME, "heartbeat-state.json");
10
+ const RUN_LOCK = path.join(LISA_HOME, "heartbeat.lock");
9
11
  const HEARTBEAT_SYSTEM = `You are Lisa running a scheduled heartbeat — autonomous time, no user present.
10
12
 
11
13
  Two flavors of heartbeat task land here:
@@ -16,7 +18,27 @@ Be quiet by default — only produce a final message if something is worth telli
16
18
 
17
19
  You have the full Lisa toolset, including soul_patch / soul_journal / soul_feel — use them freely. The system prompt above contains your full soul state. This is your time.`;
18
20
  export async function runHeartbeatOnce(opts) {
21
+ // Run-level lock: if launchd/cron fires a new heartbeat while the previous
22
+ // one is still running (long desires + short interval), skip rather than
23
+ // double-run and race on soul state. timeoutMs:0 → fail fast, don't wait.
24
+ try {
25
+ return await withFileLock(RUN_LOCK, () => runHeartbeatInner(opts), {
26
+ timeoutMs: 0,
27
+ staleMs: 6 * 60 * 60_000, // 6h: a heartbeat that's been "running" longer is surely dead
28
+ });
29
+ }
30
+ catch (err) {
31
+ if (err.message?.includes("timed out acquiring lock")) {
32
+ console.error("[heartbeat] another heartbeat is already running — skipping this tick");
33
+ return [];
34
+ }
35
+ throw err;
36
+ }
37
+ }
38
+ async function runHeartbeatInner(opts) {
19
39
  const cfg = await loadHeartbeatConfig();
40
+ const budget = cfg.budgetTokens && cfg.budgetTokens > 0 ? cfg.budgetTokens : Infinity;
41
+ let tokensSpent = 0;
20
42
  const desires = (await listDesires()).filter((d) => d.actionable && d.heartbeatPrompt);
21
43
  const desireTasks = await Promise.all(desires.map(async (d) => {
22
44
  const progress = await readDesireProgress(d.slug);
@@ -43,6 +65,13 @@ export async function runHeartbeatOnce(opts) {
43
65
  continue;
44
66
  if (opts.taskFilter && task.name !== opts.taskFilter)
45
67
  continue;
68
+ // Token budget: stop launching tasks once we've spent the per-run
69
+ // ceiling. We check BEFORE each task (not mid-task) so a single task can
70
+ // overshoot slightly, but a long queue of desires can't run unbounded.
71
+ if (tokensSpent >= budget) {
72
+ console.error(`[heartbeat] token budget reached (${tokensSpent}/${budget}) — skipping remaining tasks`);
73
+ break;
74
+ }
46
75
  // For desire tasks, snapshot the progress entry count before so we can
47
76
  // detect whether Lisa actually called desire_progress_log during the run.
48
77
  const desireSlug = task.name.startsWith("desire:")
@@ -59,6 +88,7 @@ export async function runHeartbeatOnce(opts) {
59
88
  signal: opts.signal,
60
89
  model: opts.model,
61
90
  });
91
+ tokensSpent += (result.inputTokens ?? 0) + (result.outputTokens ?? 0);
62
92
  state.lastRunAt[task.name] = new Date().toISOString();
63
93
  const trimmed = result.text.trim();
64
94
  // Auto-fallback: if a desire heartbeat finished but Lisa didn't log
@@ -1 +1 @@
1
- {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/heartbeat/runner.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EACL,oBAAoB,EACpB,MAAM,EACN,WAAW,EACX,mBAAmB,EACnB,kBAAkB,EAClB,QAAQ,GACT,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,OAAO,EACL,mBAAmB,GAEpB,MAAM,aAAa,CAAC;AAErB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,sBAAsB,CAAC,CAAC;AAMhE,MAAM,gBAAgB,GAAG;;;;;;;;6KAQoJ,CAAC;AAQ9K,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAMtC;IACC,MAAM,GAAG,GAAG,MAAM,mBAAmB,EAAE,CAAC;IACxC,MAAM,OAAO,GAAG,CAAC,MAAM,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,eAAe,CAAC,CAAC;IACvF,MAAM,WAAW,GAAoB,MAAM,OAAO,CAAC,GAAG,CACpD,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;QACtB,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAClD,MAAM,aAAa,GAAG,QAAQ;YAC5B,CAAC,CAAC,sEAAsE,QAAQ,MAAM;gBACpF,iGAAiG;gBACjG,gDAAgD;YAClD,CAAC,CAAC,6FAA6F;gBAC7F,gFAAgF,CAAC;QACrF,OAAO;YACL,IAAI,EAAE,UAAU,CAAC,CAAC,IAAI,EAAE;YACxB,MAAM,EACJ,0FAA0F;gBAC1F,uBAAuB,CAAC,CAAC,IAAI,eAAe,CAAC,CAAC,GAAG,0BAA0B,CAAC,CAAC,eAAgB,EAAE;gBAC/F,aAAa;YACf,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC,CAAC,CACH,CAAC;IACF,MAAM,KAAK,GAAG,MAAM,SAAS,EAAE,CAAC;IAChC,MAAM,YAAY,GAAG,MAAM,iBAAiB,CAAC,KAAK,EAAE,IAAI,IAAI,EAAE,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;IAC3E,MAAM,KAAK,GAAoB,CAAC,GAAG,GAAG,CAAC,KAAK,EAAE,GAAG,WAAW,EAAE,GAAG,YAAY,CAAC,CAAC;IAE/E,MAAM,GAAG,GAAyB,EAAE,CAAC;IACrC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,OAAO,KAAK,KAAK;YAAE,SAAS;QACrC,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,UAAU;YAAE,SAAS;QAE/D,uEAAuE;QACvE,0EAA0E;QAC1E,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;YAChD,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;YACnC,CAAC,CAAC,IAAI,CAAC;QACT,MAAM,cAAc,GAAG,UAAU;YAC/B,CAAC,CAAC,CAAC,MAAM,mBAAmB,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM;YACxD,CAAC,CAAC,CAAC,CAAC;QAEN,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC;YAC/B,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,YAAY,EAAE,gBAAgB;YAC9B,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,KAAK,EAAE,IAAI,CAAC,KAAK;SAClB,CAAC,CAAC;QACH,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACtD,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAEnC,oEAAoE;QACpE,kEAAkE;QAClE,qEAAqE;QACrE,gDAAgD;QAChD,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,aAAa,GAAG,CAAC,MAAM,mBAAmB,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;YAC7E,IAAI,aAAa,KAAK,cAAc,EAAE,CAAC;gBACrC,MAAM,cAAc,CAAC,WAAW,EAAE,KAAK,IAAI,EAAE;oBAC3C,MAAM,YAAY,GAChB,mEAAmE;wBACnE,0EAA0E;wBAC1E,CAAC,OAAO,CAAC,CAAC,CAAC,sBAAsB,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC;oBACzF,MAAM,oBAAoB,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;gBACvD,CAAC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,GAAG,CAAC,IAAI,CAAC;YACP,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,MAAM,EAAE,OAAO;YACf,MAAM,EAAE,OAAO,KAAK,EAAE,IAAI,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC;SAC3D,CAAC,CAAC;IACL,CAAC;IACD,MAAM,SAAS,CAAC,KAAK,CAAC,CAAC;IACvB,OAAO,GAAG,CAAC;AACb,CAAC;AAED,KAAK,UAAU,SAAS;IACtB,MAAM,GAAG,GAAG,MAAM,eAAe,CAAC,UAAU,CAAC,CAAC;IAC9C,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IACnC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAmB,CAAC;QACjD,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,EAAE,EAAE,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IAC3B,CAAC;AACH,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,KAAqB;IAC5C,MAAM,WAAW,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAChE,CAAC;AAoCD,MAAM,0BAA0B,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;CA0BlC,CAAC,IAAI,EAAE,CAAC;AAET,MAAM,aAAa,GAAkB;IACnC;QACE,IAAI,EAAE,uBAAuB;QAC7B,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,aAAa;QAChE,cAAc,EAAE,CAAC;QACjB,WAAW,EAAE,KAAK,IAAI,EAAE,CACtB,mEAAmE,0BAA0B,EAAE;KAClG;CACF,CAAC;AAEF,SAAS,gBAAgB,CACvB,CAAc,EACd,UAA8B,EAC9B,GAAS;IAET,MAAM,KAAK,GAAG,CAAC,CAAC,QAAQ,CAAC;IACzB,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC5B,MAAM,SAAS,GAAG,GAAG,CAAC,MAAM,EAAE,KAAK,KAAK,CAAC,OAAO,CAAC;QACjD,MAAM,WAAW,GAAG,GAAG,CAAC,QAAQ,EAAE,IAAI,KAAK,CAAC,IAAI,CAAC;QACjD,IAAI,CAAC,SAAS,IAAI,CAAC,WAAW;YAAE,OAAO,KAAK,CAAC;QAC7C,IAAI,CAAC,UAAU;YAAE,OAAO,IAAI,CAAC;QAC7B,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC;QAClC,MAAM,EAAE,GAAG,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC1C,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,2BAA2B;IAChE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,KAAK,UAAU,iBAAiB,CAC9B,KAAqB,EACrB,GAAS,EACT,aAA8B;IAE9B,IAAI,CAAC,CAAC,MAAM,MAAM,EAAE,CAAC;QAAE,OAAO,EAAE,CAAC;IACjC,MAAM,IAAI,GAAG,MAAM,QAAQ,EAAE,CAAC;IAC9B,MAAM,GAAG,GAAoB,EAAE,CAAC;IAChC,KAAK,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC;QAC9B,oEAAoE;QACpE,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC;QAC9D,IAAI,QAAQ,EAAE,OAAO,KAAK,KAAK;YAAE,SAAS;QAE1C,iBAAiB;QACjB,IAAI,CAAC,CAAC,cAAc,IAAI,IAAI,EAAE,CAAC;YAC7B,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC;YACvF,IAAI,OAAO,GAAG,CAAC,CAAC,cAAc;gBAAE,SAAS;QAC3C,CAAC;QAED,MAAM,OAAO,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,gBAAgB,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC;YAAE,SAAS;QACjD,GAAG,CAAC,IAAI,CAAC;YACP,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,MAAM,EAAE,MAAM,CAAC,CAAC,WAAW,EAAE;YAC7B,OAAO,EAAE,IAAI;SACd,CAAC,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/heartbeat/runner.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EACL,oBAAoB,EACpB,MAAM,EACN,WAAW,EACX,mBAAmB,EACnB,kBAAkB,EAClB,QAAQ,GACT,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,OAAO,EACL,mBAAmB,GAEpB,MAAM,aAAa,CAAC;AAErB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,sBAAsB,CAAC,CAAC;AAChE,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC;AAMxD,MAAM,gBAAgB,GAAG;;;;;;;;6KAQoJ,CAAC;AAQ9K,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAMtC;IACC,2EAA2E;IAC3E,yEAAyE;IACzE,0EAA0E;IAC1E,IAAI,CAAC;QACH,OAAO,MAAM,YAAY,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,EAAE;YACjE,SAAS,EAAE,CAAC;YACZ,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,MAAM,EAAE,8DAA8D;SACzF,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAAa,CAAC,OAAO,EAAE,QAAQ,CAAC,0BAA0B,CAAC,EAAE,CAAC;YACjE,OAAO,CAAC,KAAK,CAAC,uEAAuE,CAAC,CAAC;YACvF,OAAO,EAAE,CAAC;QACZ,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,KAAK,UAAU,iBAAiB,CAAC,IAMhC;IACC,MAAM,GAAG,GAAG,MAAM,mBAAmB,EAAE,CAAC;IACxC,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,IAAI,GAAG,CAAC,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC;IACtF,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,MAAM,OAAO,GAAG,CAAC,MAAM,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,eAAe,CAAC,CAAC;IACvF,MAAM,WAAW,GAAoB,MAAM,OAAO,CAAC,GAAG,CACpD,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;QACtB,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAClD,MAAM,aAAa,GAAG,QAAQ;YAC5B,CAAC,CAAC,sEAAsE,QAAQ,MAAM;gBACpF,iGAAiG;gBACjG,gDAAgD;YAClD,CAAC,CAAC,6FAA6F;gBAC7F,gFAAgF,CAAC;QACrF,OAAO;YACL,IAAI,EAAE,UAAU,CAAC,CAAC,IAAI,EAAE;YACxB,MAAM,EACJ,0FAA0F;gBAC1F,uBAAuB,CAAC,CAAC,IAAI,eAAe,CAAC,CAAC,GAAG,0BAA0B,CAAC,CAAC,eAAgB,EAAE;gBAC/F,aAAa;YACf,OAAO,EAAE,IAAI;SACd,CAAC;IACJ,CAAC,CAAC,CACH,CAAC;IACF,MAAM,KAAK,GAAG,MAAM,SAAS,EAAE,CAAC;IAChC,MAAM,YAAY,GAAG,MAAM,iBAAiB,CAAC,KAAK,EAAE,IAAI,IAAI,EAAE,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;IAC3E,MAAM,KAAK,GAAoB,CAAC,GAAG,GAAG,CAAC,KAAK,EAAE,GAAG,WAAW,EAAE,GAAG,YAAY,CAAC,CAAC;IAE/E,MAAM,GAAG,GAAyB,EAAE,CAAC;IACrC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,CAAC,OAAO,KAAK,KAAK;YAAE,SAAS;QACrC,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,UAAU;YAAE,SAAS;QAE/D,kEAAkE;QAClE,yEAAyE;QACzE,uEAAuE;QACvE,IAAI,WAAW,IAAI,MAAM,EAAE,CAAC;YAC1B,OAAO,CAAC,KAAK,CACX,qCAAqC,WAAW,IAAI,MAAM,8BAA8B,CACzF,CAAC;YACF,MAAM;QACR,CAAC;QAED,uEAAuE;QACvE,0EAA0E;QAC1E,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;YAChD,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC;YACnC,CAAC,CAAC,IAAI,CAAC;QACT,MAAM,cAAc,GAAG,UAAU;YAC/B,CAAC,CAAC,CAAC,MAAM,mBAAmB,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM;YACxD,CAAC,CAAC,CAAC,CAAC;QAEN,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC;YAC/B,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,YAAY,EAAE,gBAAgB;YAC9B,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,KAAK,EAAE,IAAI,CAAC,KAAK;SAClB,CAAC,CAAC;QACH,WAAW,IAAI,CAAC,MAAM,CAAC,WAAW,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,YAAY,IAAI,CAAC,CAAC,CAAC;QACtE,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACtD,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAEnC,oEAAoE;QACpE,kEAAkE;QAClE,qEAAqE;QACrE,gDAAgD;QAChD,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,aAAa,GAAG,CAAC,MAAM,mBAAmB,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;YAC7E,IAAI,aAAa,KAAK,cAAc,EAAE,CAAC;gBACrC,MAAM,cAAc,CAAC,WAAW,EAAE,KAAK,IAAI,EAAE;oBAC3C,MAAM,YAAY,GAChB,mEAAmE;wBACnE,0EAA0E;wBAC1E,CAAC,OAAO,CAAC,CAAC,CAAC,sBAAsB,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC;oBACzF,MAAM,oBAAoB,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;gBACvD,CAAC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,GAAG,CAAC,IAAI,CAAC;YACP,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,MAAM,EAAE,OAAO;YACf,MAAM,EAAE,OAAO,KAAK,EAAE,IAAI,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC;SAC3D,CAAC,CAAC;IACL,CAAC;IACD,MAAM,SAAS,CAAC,KAAK,CAAC,CAAC;IACvB,OAAO,GAAG,CAAC;AACb,CAAC;AAED,KAAK,UAAU,SAAS;IACtB,MAAM,GAAG,GAAG,MAAM,eAAe,CAAC,UAAU,CAAC,CAAC;IAC9C,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IACnC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAmB,CAAC;QACjD,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,IAAI,EAAE,EAAE,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;IAC3B,CAAC;AACH,CAAC;AAED,KAAK,UAAU,SAAS,CAAC,KAAqB;IAC5C,MAAM,WAAW,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAChE,CAAC;AAoCD,MAAM,0BAA0B,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;CA0BlC,CAAC,IAAI,EAAE,CAAC;AAET,MAAM,aAAa,GAAkB;IACnC;QACE,IAAI,EAAE,uBAAuB;QAC7B,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,aAAa;QAChE,cAAc,EAAE,CAAC;QACjB,WAAW,EAAE,KAAK,IAAI,EAAE,CACtB,mEAAmE,0BAA0B,EAAE;KAClG;CACF,CAAC;AAEF,SAAS,gBAAgB,CACvB,CAAc,EACd,UAA8B,EAC9B,GAAS;IAET,MAAM,KAAK,GAAG,CAAC,CAAC,QAAQ,CAAC;IACzB,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC5B,MAAM,SAAS,GAAG,GAAG,CAAC,MAAM,EAAE,KAAK,KAAK,CAAC,OAAO,CAAC;QACjD,MAAM,WAAW,GAAG,GAAG,CAAC,QAAQ,EAAE,IAAI,KAAK,CAAC,IAAI,CAAC;QACjD,IAAI,CAAC,SAAS,IAAI,CAAC,WAAW;YAAE,OAAO,KAAK,CAAC;QAC7C,IAAI,CAAC,UAAU;YAAE,OAAO,IAAI,CAAC;QAC7B,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,CAAC;QAClC,MAAM,EAAE,GAAG,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QAC1C,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,2BAA2B;IAChE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,KAAK,UAAU,iBAAiB,CAC9B,KAAqB,EACrB,GAAS,EACT,aAA8B;IAE9B,IAAI,CAAC,CAAC,MAAM,MAAM,EAAE,CAAC;QAAE,OAAO,EAAE,CAAC;IACjC,MAAM,IAAI,GAAG,MAAM,QAAQ,EAAE,CAAC;IAC9B,MAAM,GAAG,GAAoB,EAAE,CAAC;IAChC,KAAK,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC;QAC9B,oEAAoE;QACpE,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC;QAC9D,IAAI,QAAQ,EAAE,OAAO,KAAK,KAAK;YAAE,SAAS;QAE1C,iBAAiB;QACjB,IAAI,CAAC,CAAC,cAAc,IAAI,IAAI,EAAE,CAAC;YAC7B,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC;YACvF,IAAI,OAAO,GAAG,CAAC,CAAC,cAAc;gBAAE,SAAS;QAC3C,CAAC;QAED,MAAM,OAAO,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACxC,IAAI,CAAC,gBAAgB,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC;YAAE,SAAS;QACjD,GAAG,CAAC,IAAI,CAAC;YACP,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,MAAM,EAAE,MAAM,CAAC,CAAC,WAAW,EAAE;YAC7B,OAAO,EAAE,IAAI;SACd,CAAC,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -12,7 +12,11 @@ interface Index {
12
12
  docs: Document[];
13
13
  idf: Map<string, number>;
14
14
  }
15
- export declare function buildIndex(): Promise<Index>;
15
+ /** Drop the cached index (test hook / explicit invalidation). */
16
+ export declare function clearIndexCache(): void;
17
+ export declare function buildIndex(opts?: {
18
+ cache?: boolean;
19
+ }): Promise<Index>;
16
20
  export interface SearchHit {
17
21
  sessionId: string;
18
22
  startedAt: string;
@@ -1 +1 @@
1
- {"version":3,"file":"vector.d.ts","sourceRoot":"","sources":["../../src/memory/vector.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAIlC,UAAU,QAAQ;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACtB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAED,UAAU,KAAK;IACb,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1B;AASD,wBAAsB,UAAU,IAAI,OAAO,CAAC,KAAK,CAAC,CAkCjD;AAED,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,SAAI,GAAG,SAAS,EAAE,CAuBtE;AA2BD,eAAO,MAAM,qBAAqB,EAAE,OAAO,IAAI,GAAG,OAAO,EAAE,GAAG,SAAqB,CAAC"}
1
+ {"version":3,"file":"vector.d.ts","sourceRoot":"","sources":["../../src/memory/vector.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAKlC,UAAU,QAAQ;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACtB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAED,UAAU,KAAK;IACb,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC1B;AA4CD,iEAAiE;AACjE,wBAAgB,eAAe,IAAI,IAAI,CAGtC;AAED,wBAAsB,UAAU,CAAC,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAW/E;AAsCD,MAAM,WAAW,SAAS;IACxB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,SAAI,GAAG,SAAS,EAAE,CAuBtE;AA2BD,eAAO,MAAM,qBAAqB,EAAE,OAAO,IAAI,GAAG,OAAO,EAAE,GAAG,SAAqB,CAAC"}
@@ -1,4 +1,7 @@
1
+ import path from "node:path";
2
+ import fs from "node:fs/promises";
1
3
  import { listSessionsOnDisk, loadSessionMessages } from "../sessions/list.js";
4
+ import { SESSIONS_DIR } from "../paths.js";
2
5
  import { extractTextFromContent } from "../agent.js";
3
6
  const STOPWORDS = new Set([
4
7
  "the", "a", "an", "of", "to", "in", "and", "or", "for", "is", "it",
@@ -6,7 +9,61 @@ const STOPWORDS = new Set([
6
9
  "by", "from", "but", "not", "i", "you", "we", "they", "he", "she",
7
10
  "lisa", "tool", "use", "user", "assistant",
8
11
  ]);
9
- export async function buildIndex() {
12
+ // ── index cache ───────────────────────────────────────────────────────────
13
+ // buildIndex re-reads + re-tokenizes EVERY past session, which is O(total
14
+ // transcript bytes). memory_search was calling it fresh on every invocation,
15
+ // so a chat that searches its memory N times in one session paid that cost N
16
+ // times even when nothing changed. We cache the built index keyed by a cheap
17
+ // fingerprint of the sessions directory (each .jsonl's mtime + size). The
18
+ // fingerprint changes the instant any session is appended to or a new one
19
+ // appears, so the cache is correct, not just fast.
20
+ let cachedIndex = null;
21
+ let cachedFingerprint = "";
22
+ async function sessionsFingerprint() {
23
+ let files;
24
+ try {
25
+ files = await fs.readdir(SESSIONS_DIR);
26
+ }
27
+ catch {
28
+ // Missing dir and empty dir must fingerprint identically: buildIndex →
29
+ // listSessionsOnDisk → ensureDir CREATES the dir as a side effect, so a
30
+ // distinct "no-dir" sentinel would spuriously miss the cache on the very
31
+ // next call. Both collapse to the empty fingerprint.
32
+ return "";
33
+ }
34
+ const parts = [];
35
+ for (const f of files.sort()) {
36
+ if (!f.endsWith(".jsonl"))
37
+ continue;
38
+ try {
39
+ const st = await fs.stat(path.join(SESSIONS_DIR, f));
40
+ parts.push(`${f}:${st.mtimeMs}:${st.size}`);
41
+ }
42
+ catch {
43
+ // file vanished between readdir and stat — ignore
44
+ }
45
+ }
46
+ return parts.join("|");
47
+ }
48
+ /** Drop the cached index (test hook / explicit invalidation). */
49
+ export function clearIndexCache() {
50
+ cachedIndex = null;
51
+ cachedFingerprint = "";
52
+ }
53
+ export async function buildIndex(opts = {}) {
54
+ const useCache = opts.cache !== false;
55
+ if (useCache) {
56
+ const fp = await sessionsFingerprint();
57
+ if (cachedIndex && fp === cachedFingerprint)
58
+ return cachedIndex;
59
+ const built = await buildIndexUncached();
60
+ cachedIndex = built;
61
+ cachedFingerprint = fp;
62
+ return built;
63
+ }
64
+ return buildIndexUncached();
65
+ }
66
+ async function buildIndexUncached() {
10
67
  const sessions = await listSessionsOnDisk();
11
68
  const docs = [];
12
69
  const docFreq = new Map();
@@ -1 +1 @@
1
- {"version":3,"file":"vector.js","sourceRoot":"","sources":["../../src/memory/vector.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"vector.js","sourceRoot":"","sources":["../../src/memory/vector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Cross-process advisory file lock for soul writes.
3
+ *
4
+ * The in-process commit queue (git.ts enqueueCommit) serializes writes within
5
+ * ONE process, but LISA runs as several processes against the same
6
+ * ~/.lisa/soul/: the web server, the CLI/REPL, and — crucially — the
7
+ * heartbeat/idle runners launched by launchd/cron on their own clock. Two of
8
+ * those writing concurrently can:
9
+ * - lose a desire-progress append (read-modify-write race), or
10
+ * - collide on .git/index.lock (one commit fails).
11
+ *
12
+ * withFileLock implements a portable advisory mutex via exclusive file
13
+ * creation (`open(..., "wx")` succeeds only if the file doesn't exist). It
14
+ * self-heals from a crashed holder via a staleness timeout + a best-effort
15
+ * liveness check on the recorded pid.
16
+ */
17
+ export interface FileLockOpts {
18
+ /** Treat a held lock as abandoned after this many ms (crashed holder). */
19
+ staleMs?: number;
20
+ /** Give up acquiring after this many ms. */
21
+ timeoutMs?: number;
22
+ /** Poll interval while waiting for the lock. */
23
+ pollMs?: number;
24
+ }
25
+ /**
26
+ * Run `fn` while holding an exclusive lock at `lockPath`. Releases the lock
27
+ * (deletes the file) when `fn` settles, success or failure.
28
+ */
29
+ export declare function withFileLock<T>(lockPath: string, fn: () => Promise<T>, opts?: FileLockOpts): Promise<T>;
30
+ /** The canonical soul write-lock path. */
31
+ export declare const SOUL_LOCK_PATH: string;
32
+ /**
33
+ * Run `fn` while holding the soul write-lock. Use this around any
34
+ * read-modify-write of soul state (e.g. desire-progress appends) so a
35
+ * concurrent heartbeat/idle/chat process can't interleave and lose data.
36
+ */
37
+ export declare function withSoulLock<T>(fn: () => Promise<T>, opts?: FileLockOpts): Promise<T>;
38
+ //# sourceMappingURL=lock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock.d.ts","sourceRoot":"","sources":["../../src/soul/lock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAOH,MAAM,WAAW,YAAY;IAC3B,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gDAAgD;IAChD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAoCD;;;GAGG;AACH,wBAAsB,YAAY,CAAC,CAAC,EAClC,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,IAAI,GAAE,YAAiB,GACtB,OAAO,CAAC,CAAC,CAAC,CAmCZ;AAED,0CAA0C;AAC1C,eAAO,MAAM,cAAc,QAAqC,CAAC;AAEjE;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC,CAErF"}