@ouro.bot/cli 0.1.0-alpha.28 → 0.1.0-alpha.281

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 (268) hide show
  1. package/README.md +187 -191
  2. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/agent.json +3 -2
  3. package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/SOUL.md +1 -1
  4. package/changelog.json +1703 -0
  5. package/dist/arc/attention-types.js +8 -0
  6. package/dist/arc/cares.js +140 -0
  7. package/dist/arc/episodes.js +117 -0
  8. package/dist/arc/intentions.js +133 -0
  9. package/dist/arc/json-store.js +117 -0
  10. package/dist/arc/obligations.js +237 -0
  11. package/dist/arc/presence.js +185 -0
  12. package/dist/heart/active-work.js +832 -0
  13. package/dist/heart/agent-entry.js +37 -2
  14. package/dist/heart/auth/auth-flow.js +456 -0
  15. package/dist/heart/bridges/manager.js +358 -0
  16. package/dist/heart/bridges/state-machine.js +135 -0
  17. package/dist/heart/bridges/store.js +123 -0
  18. package/dist/heart/bundle-state.js +147 -0
  19. package/dist/heart/commitments.js +111 -0
  20. package/dist/heart/config-registry.js +304 -0
  21. package/dist/heart/config.js +63 -30
  22. package/dist/heart/core.js +644 -196
  23. package/dist/heart/cross-chat-delivery.js +131 -0
  24. package/dist/heart/daemon/agent-config-check.js +149 -0
  25. package/dist/heart/daemon/agent-discovery.js +79 -3
  26. package/dist/heart/daemon/agent-service.js +360 -0
  27. package/dist/heart/daemon/cadence.js +70 -0
  28. package/dist/heart/daemon/cli-defaults.js +574 -0
  29. package/dist/heart/daemon/cli-exec.js +1932 -0
  30. package/dist/heart/daemon/cli-parse.js +762 -0
  31. package/dist/heart/daemon/cli-render.js +503 -0
  32. package/dist/heart/daemon/cli-types.js +8 -0
  33. package/dist/heart/daemon/daemon-cli.js +29 -1155
  34. package/dist/heart/daemon/daemon-entry.js +234 -3
  35. package/dist/heart/daemon/daemon-health.js +136 -0
  36. package/dist/heart/daemon/daemon-runtime-sync.js +153 -12
  37. package/dist/heart/daemon/daemon-tombstone.js +236 -0
  38. package/dist/heart/daemon/daemon.js +702 -57
  39. package/dist/heart/daemon/hooks/agent-config-v2.js +33 -0
  40. package/dist/heart/daemon/hooks/bundle-meta.js +115 -1
  41. package/dist/heart/daemon/inner-status.js +89 -0
  42. package/dist/heart/daemon/launchd.js +46 -9
  43. package/dist/heart/daemon/log-tailer.js +82 -12
  44. package/dist/heart/daemon/logs-prune.js +105 -0
  45. package/dist/heart/daemon/message-router.js +17 -8
  46. package/dist/heart/daemon/os-cron-deps.js +134 -0
  47. package/dist/heart/daemon/ouro-bot-entry.js +1 -1
  48. package/dist/heart/daemon/process-manager.js +180 -0
  49. package/dist/heart/daemon/pulse.js +463 -0
  50. package/dist/heart/daemon/run-hooks.js +2 -0
  51. package/dist/heart/daemon/runtime-logging.js +67 -16
  52. package/dist/heart/daemon/runtime-metadata.js +101 -0
  53. package/dist/heart/daemon/runtime-mode.js +67 -0
  54. package/dist/heart/daemon/safe-mode.js +161 -0
  55. package/dist/heart/daemon/sense-manager.js +72 -3
  56. package/dist/heart/daemon/session-id-resolver.js +131 -0
  57. package/dist/heart/daemon/skill-management-installer.js +94 -0
  58. package/dist/heart/daemon/socket-client.js +307 -0
  59. package/dist/heart/daemon/task-scheduler.js +3 -25
  60. package/dist/heart/daemon/thoughts.js +510 -0
  61. package/dist/heart/delegation.js +62 -0
  62. package/dist/heart/habits/habit-migration.js +181 -0
  63. package/dist/heart/habits/habit-parser.js +119 -0
  64. package/dist/heart/habits/habit-scheduler.js +371 -0
  65. package/dist/heart/{daemon → hatch}/hatch-flow.js +30 -120
  66. package/dist/heart/{daemon → hatch}/hatch-specialist.js +3 -3
  67. package/dist/heart/{daemon → hatch}/specialist-prompt.js +10 -7
  68. package/dist/heart/{daemon → hatch}/specialist-tools.js +49 -3
  69. package/dist/heart/identity.js +163 -60
  70. package/dist/heart/kicks.js +2 -20
  71. package/dist/heart/mcp/mcp-server.js +653 -0
  72. package/dist/heart/migrate-config.js +127 -0
  73. package/dist/heart/model-capabilities.js +59 -0
  74. package/dist/heart/outlook/outlook-http.js +439 -0
  75. package/dist/heart/outlook/outlook-read.js +1618 -0
  76. package/dist/heart/outlook/outlook-render.js +1032 -0
  77. package/dist/heart/outlook/outlook-types.js +7 -0
  78. package/dist/heart/outlook/outlook-view.js +194 -0
  79. package/dist/heart/progress-story.js +42 -0
  80. package/dist/heart/provider-failover.js +88 -0
  81. package/dist/heart/provider-ping.js +162 -0
  82. package/dist/heart/providers/anthropic-token.js +163 -0
  83. package/dist/heart/providers/anthropic.js +169 -46
  84. package/dist/heart/providers/azure.js +98 -11
  85. package/dist/heart/providers/error-classification.js +63 -0
  86. package/dist/heart/providers/github-copilot.js +136 -0
  87. package/dist/heart/providers/minimax-vlm.js +189 -0
  88. package/dist/heart/providers/minimax.js +23 -5
  89. package/dist/heart/providers/openai-codex.js +33 -22
  90. package/dist/heart/session-activity.js +172 -0
  91. package/dist/heart/session-recall.js +216 -0
  92. package/dist/heart/start-of-turn-packet.js +339 -0
  93. package/dist/heart/streaming.js +36 -27
  94. package/dist/heart/sync.js +277 -0
  95. package/dist/heart/target-resolution.js +127 -0
  96. package/dist/heart/tempo.js +93 -0
  97. package/dist/heart/temporal-view.js +41 -0
  98. package/dist/heart/tool-activity-callbacks.js +36 -0
  99. package/dist/heart/tool-description.js +135 -0
  100. package/dist/heart/tool-loop.js +200 -0
  101. package/dist/heart/turn-context.js +358 -0
  102. package/dist/heart/turn-coordinator.js +28 -0
  103. package/dist/heart/versioning/ouro-bot-global-installer.js +128 -0
  104. package/dist/heart/{daemon → versioning}/ouro-bot-wrapper.js +1 -1
  105. package/dist/heart/{daemon → versioning}/ouro-path-installer.js +78 -35
  106. package/dist/heart/versioning/ouro-version-manager.js +295 -0
  107. package/dist/heart/{daemon → versioning}/staged-restart.js +40 -8
  108. package/dist/heart/{daemon → versioning}/update-checker.js +12 -2
  109. package/dist/heart/{daemon → versioning}/update-hooks.js +63 -59
  110. package/dist/mind/associative-recall.js +126 -66
  111. package/dist/mind/bundle-manifest.js +8 -1
  112. package/dist/mind/context.js +125 -14
  113. package/dist/mind/{memory.js → diary.js} +68 -96
  114. package/dist/mind/embedding-provider.js +60 -0
  115. package/dist/mind/file-state.js +179 -0
  116. package/dist/mind/first-impressions.js +14 -1
  117. package/dist/mind/friends/channel.js +56 -0
  118. package/dist/mind/friends/group-context.js +144 -0
  119. package/dist/mind/friends/resolver.js +37 -0
  120. package/dist/mind/friends/store-file.js +58 -3
  121. package/dist/mind/friends/trust-explanation.js +74 -0
  122. package/dist/mind/friends/types.js +8 -0
  123. package/dist/mind/journal-index.js +161 -0
  124. package/dist/mind/obligation-steering.js +221 -0
  125. package/dist/mind/pending.js +76 -9
  126. package/dist/mind/prompt.js +874 -109
  127. package/dist/mind/scrutiny.js +173 -0
  128. package/dist/mind/token-estimate.js +8 -12
  129. package/dist/nerves/cli-logging.js +7 -1
  130. package/dist/nerves/coverage/audit.js +1 -1
  131. package/dist/nerves/coverage/file-completeness.js +50 -5
  132. package/dist/nerves/coverage/run-artifacts.js +1 -1
  133. package/dist/nerves/event-buffer.js +111 -0
  134. package/dist/nerves/index.js +220 -4
  135. package/dist/nerves/observation.js +20 -0
  136. package/dist/nerves/runtime.js +5 -1
  137. package/dist/outlook-ui/assets/index-Ck8agNeO.js +61 -0
  138. package/dist/outlook-ui/assets/index-LwChZTgL.css +1 -0
  139. package/dist/outlook-ui/index.html +15 -0
  140. package/dist/repertoire/ado-client.js +15 -56
  141. package/dist/repertoire/ado-semantic.js +11 -10
  142. package/dist/repertoire/api-client.js +97 -0
  143. package/dist/repertoire/bitwarden-store.js +319 -0
  144. package/dist/repertoire/bw-installer.js +79 -0
  145. package/dist/repertoire/coding/codex-jsonl.js +64 -0
  146. package/dist/repertoire/coding/context-pack.js +330 -0
  147. package/dist/repertoire/coding/feedback.js +197 -30
  148. package/dist/repertoire/coding/manager.js +149 -2
  149. package/dist/repertoire/coding/spawner.js +55 -9
  150. package/dist/repertoire/coding/tools.js +170 -7
  151. package/dist/repertoire/commerce-errors.js +109 -0
  152. package/dist/repertoire/commerce-self-test.js +156 -0
  153. package/dist/repertoire/credential-access.js +515 -0
  154. package/dist/repertoire/duffel-client.js +185 -0
  155. package/dist/repertoire/github-client.js +14 -55
  156. package/dist/repertoire/graph-client.js +11 -52
  157. package/dist/repertoire/guardrails.js +369 -0
  158. package/dist/repertoire/mcp-client.js +255 -0
  159. package/dist/repertoire/mcp-manager.js +305 -0
  160. package/dist/repertoire/mcp-tools.js +63 -0
  161. package/dist/repertoire/shell-sessions.js +133 -0
  162. package/dist/repertoire/skills.js +14 -23
  163. package/dist/repertoire/stripe-client.js +131 -0
  164. package/dist/repertoire/tasks/board.js +43 -5
  165. package/dist/repertoire/tasks/fix.js +182 -0
  166. package/dist/repertoire/tasks/index.js +28 -10
  167. package/dist/repertoire/tasks/lifecycle.js +2 -2
  168. package/dist/repertoire/tasks/parser.js +3 -2
  169. package/dist/repertoire/tasks/scanner.js +194 -37
  170. package/dist/repertoire/tasks/transitions.js +11 -28
  171. package/dist/repertoire/tools-base.js +43 -771
  172. package/dist/repertoire/tools-bluebubbles.js +201 -0
  173. package/dist/repertoire/tools-bridge.js +141 -0
  174. package/dist/repertoire/tools-config.js +185 -0
  175. package/dist/repertoire/tools-continuity.js +248 -0
  176. package/dist/repertoire/tools-credential.js +182 -0
  177. package/dist/repertoire/tools-files.js +342 -0
  178. package/dist/repertoire/tools-flight.js +224 -0
  179. package/dist/repertoire/tools-flow.js +62 -0
  180. package/dist/repertoire/tools-github.js +1 -7
  181. package/dist/repertoire/tools-memory.js +347 -0
  182. package/dist/repertoire/tools-session.js +739 -0
  183. package/dist/repertoire/tools-shell.js +120 -0
  184. package/dist/repertoire/tools-stripe.js +180 -0
  185. package/dist/repertoire/tools-surface.js +243 -0
  186. package/dist/repertoire/tools-teams.js +12 -62
  187. package/dist/repertoire/tools-travel.js +125 -0
  188. package/dist/repertoire/tools-user-profile.js +144 -0
  189. package/dist/repertoire/tools-vault.js +110 -0
  190. package/dist/repertoire/tools.js +155 -130
  191. package/dist/repertoire/travel-api-client.js +360 -0
  192. package/dist/repertoire/user-profile.js +118 -0
  193. package/dist/repertoire/vault-setup.js +241 -0
  194. package/dist/scripts/claude-code-hook.js +41 -0
  195. package/dist/scripts/claude-code-stop-hook.js +47 -0
  196. package/dist/senses/attention-queue.js +97 -0
  197. package/dist/senses/bluebubbles/attachment-cache.js +53 -0
  198. package/dist/senses/{bluebubbles-client.js → bluebubbles/client.js} +143 -9
  199. package/dist/senses/bluebubbles/entry.js +13 -0
  200. package/dist/senses/bluebubbles/inbound-log.js +110 -0
  201. package/dist/senses/bluebubbles/index.js +1410 -0
  202. package/dist/senses/{bluebubbles-media.js → bluebubbles/media.js} +140 -23
  203. package/dist/senses/{bluebubbles-model.js → bluebubbles/model.js} +20 -5
  204. package/dist/senses/{bluebubbles-mutation-log.js → bluebubbles/mutation-log.js} +46 -6
  205. package/dist/senses/bluebubbles/runtime-state.js +109 -0
  206. package/dist/senses/bluebubbles/session-cleanup.js +72 -0
  207. package/dist/senses/cli/bracketed-paste.js +82 -0
  208. package/dist/senses/cli/image-paste.js +211 -0
  209. package/dist/senses/cli/image-ref-navigation.js +75 -0
  210. package/dist/senses/cli/ink-app.js +156 -0
  211. package/dist/senses/cli/inline-diff.js +64 -0
  212. package/dist/senses/cli/input-keys.js +174 -0
  213. package/dist/senses/cli/kill-ring.js +86 -0
  214. package/dist/senses/cli/message-list.js +51 -0
  215. package/dist/senses/cli/ouro-tui.js +595 -0
  216. package/dist/senses/cli/spinner-imperative.js +135 -0
  217. package/dist/senses/cli/spinner.js +101 -0
  218. package/dist/senses/cli/status-line.js +60 -0
  219. package/dist/senses/cli/streaming-markdown.js +526 -0
  220. package/dist/senses/cli/tool-display.js +83 -0
  221. package/dist/senses/cli/tool-render.js +85 -0
  222. package/dist/senses/cli/tui-store.js +240 -0
  223. package/dist/senses/cli/virtual-list.js +35 -0
  224. package/dist/senses/cli-entry.js +1 -1
  225. package/dist/senses/cli-layout.js +187 -0
  226. package/dist/senses/cli.js +569 -246
  227. package/dist/senses/commands.js +65 -1
  228. package/dist/senses/continuity.js +94 -0
  229. package/dist/senses/habit-turn-message.js +108 -0
  230. package/dist/senses/inner-dialog-worker.js +112 -19
  231. package/dist/senses/inner-dialog.js +593 -85
  232. package/dist/senses/pipeline.js +560 -0
  233. package/dist/senses/shared-turn.js +199 -0
  234. package/dist/senses/surface-tool.js +68 -0
  235. package/dist/senses/teams.js +664 -165
  236. package/dist/senses/trust-gate.js +112 -2
  237. package/package.json +14 -7
  238. package/skills/agent-commerce.md +106 -0
  239. package/skills/browser-navigation.md +110 -0
  240. package/skills/commerce-setup-guide.md +116 -0
  241. package/skills/commerce-setup.md +84 -0
  242. package/skills/configure-dev-tools.md +81 -0
  243. package/skills/travel-planning.md +138 -0
  244. package/dist/heart/daemon/subagent-installer.js +0 -134
  245. package/dist/senses/bluebubbles-entry.js +0 -11
  246. package/dist/senses/bluebubbles.js +0 -421
  247. package/dist/senses/debug-activity.js +0 -108
  248. package/subagents/README.md +0 -73
  249. package/subagents/work-doer.md +0 -235
  250. package/subagents/work-merger.md +0 -618
  251. package/subagents/work-planner.md +0 -382
  252. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/basilisk.md +0 -0
  253. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jafar.md +0 -0
  254. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/jormungandr.md +0 -0
  255. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/kaa.md +0 -0
  256. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/medusa.md +0 -0
  257. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/monty.md +0 -0
  258. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/nagini.md +0 -0
  259. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/ouroboros.md +0 -0
  260. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/python.md +0 -0
  261. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/quetzalcoatl.md +0 -0
  262. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/sir-hiss.md +0 -0
  263. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-serpent.md +0 -0
  264. /package/{AdoptionSpecialist.ouro → SerpentGuide.ouro}/psyche/identities/the-snake.md +0 -0
  265. /package/dist/heart/{daemon → hatch}/hatch-animation.js +0 -0
  266. /package/dist/heart/{daemon → hatch}/specialist-orchestrator.js +0 -0
  267. /package/dist/heart/{daemon → versioning}/ouro-uti.js +0 -0
  268. /package/dist/heart/{daemon → versioning}/wrapper-publish-guard.js +0 -0
@@ -33,12 +33,37 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.VLM_TEXT_WRAPPERS = void 0;
37
+ exports.downloadBlueBubblesAttachment = downloadBlueBubblesAttachment;
36
38
  exports.hydrateBlueBubblesAttachments = hydrateBlueBubblesAttachments;
37
39
  const node_child_process_1 = require("node:child_process");
38
40
  const fs = __importStar(require("node:fs/promises"));
39
41
  const os = __importStar(require("node:os"));
40
42
  const path = __importStar(require("node:path"));
41
- const runtime_1 = require("../nerves/runtime");
43
+ const runtime_1 = require("../../nerves/runtime");
44
+ const identity_1 = require("../../heart/identity");
45
+ const model_capabilities_1 = require("../../heart/model-capabilities");
46
+ const attachment_cache_1 = require("./attachment-cache");
47
+ // Pin the exact wrapper strings so tests and code read from one source.
48
+ exports.VLM_TEXT_WRAPPERS = {
49
+ description: (desc) => `[image description: ${desc}]`,
50
+ unsupported: (mimeType) => `[image attachment not shown: unsupported format ${mimeType}]`,
51
+ failure: (reason) => `[image description failed: ${reason}]`,
52
+ };
53
+ // VLM supported formats for the /v1/coding_plan/vlm endpoint. The client in
54
+ // minimax-vlm.ts enforces the same set — this helper lets the sense skip the
55
+ // call entirely and emit a clearer `vision_format_unsupported` event instead
56
+ // of letting the VLM client throw.
57
+ const VLM_SUPPORTED_MIME_TYPES = new Set(["image/png", "image/jpeg", "image/webp"]);
58
+ function isSupportedVlmFormat(contentType) {
59
+ return VLM_SUPPORTED_MIME_TYPES.has(contentType.toLowerCase());
60
+ }
61
+ // D3 prompt template. Included here (not templated out) because the contract
62
+ // is load-bearing — see planning doc section D3 and AX-4.
63
+ function buildVlmPrompt(userText) {
64
+ const body = userText ?? "";
65
+ return `User message: "${body}"\n\nDescribe this image in detail, focusing on anything relevant to what the user said above.\nInclude any text visible in the image verbatim.`;
66
+ }
42
67
  const MAX_ATTACHMENT_BYTES = 8 * 1024 * 1024;
43
68
  const AUDIO_EXTENSIONS = new Set([".mp3", ".wav", ".m4a", ".caf", ".ogg"]);
44
69
  const IMAGE_EXTENSIONS = new Set([".jpg", ".jpeg", ".png", ".gif", ".webp", ".heic", ".heif"]);
@@ -65,9 +90,16 @@ const AUDIO_INPUT_FORMAT_BY_EXTENSION = {
65
90
  const WHISPER_CPP_FORMULA = "whisper-cpp";
66
91
  const WHISPER_CPP_MODEL_NAME = "ggml-base.en.bin";
67
92
  const WHISPER_CPP_MODEL_URL = `https://huggingface.co/ggerganov/whisper.cpp/resolve/main/${WHISPER_CPP_MODEL_NAME}`;
68
- const WHISPER_CPP_TOOLS_DIR = path.join(os.homedir(), ".agentstate", "tools", "whisper-cpp");
69
- const WHISPER_CPP_MODELS_DIR = path.join(WHISPER_CPP_TOOLS_DIR, "models");
70
- const WHISPER_CPP_MODEL_PATH = path.join(WHISPER_CPP_MODELS_DIR, WHISPER_CPP_MODEL_NAME);
93
+ // Lazy — getAgentToolsRoot() requires identity to be resolved, which isn't
94
+ // true at module-load time in most unit test contexts. Tests that only touch
95
+ // the image/VLM path shouldn't break because the audio path asked for a
96
+ // tools root they don't need.
97
+ function whisperCppPaths() {
98
+ const toolsDir = path.join((0, identity_1.getAgentToolsRoot)(), "whisper-cpp");
99
+ const modelsDir = path.join(toolsDir, "models");
100
+ const modelPath = path.join(modelsDir, WHISPER_CPP_MODEL_NAME);
101
+ return { toolsDir, modelsDir, modelPath };
102
+ }
71
103
  function buildBlueBubblesApiUrl(baseUrl, endpoint, password) {
72
104
  const root = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
73
105
  const url = new URL(endpoint.replace(/^\//, ""), root);
@@ -169,12 +201,13 @@ async function resolveWhisperCppBinary(timeoutMs) {
169
201
  return candidate;
170
202
  }
171
203
  async function ensureWhisperCppModel(timeoutMs, fetchImpl) {
204
+ const { modelsDir, modelPath } = whisperCppPaths();
172
205
  try {
173
- await fs.access(WHISPER_CPP_MODEL_PATH);
174
- return WHISPER_CPP_MODEL_PATH;
206
+ await fs.access(modelPath);
207
+ return modelPath;
175
208
  }
176
209
  catch {
177
- await fs.mkdir(WHISPER_CPP_MODELS_DIR, { recursive: true });
210
+ await fs.mkdir(modelsDir, { recursive: true });
178
211
  const response = await fetchImpl(WHISPER_CPP_MODEL_URL, {
179
212
  method: "GET",
180
213
  signal: AbortSignal.timeout(Math.max(timeoutMs, 300_000)),
@@ -182,8 +215,8 @@ async function ensureWhisperCppModel(timeoutMs, fetchImpl) {
182
215
  if (!response.ok) {
183
216
  throw new Error(`failed to download whisper.cpp model: HTTP ${response.status}`);
184
217
  }
185
- await fs.writeFile(WHISPER_CPP_MODEL_PATH, Buffer.from(await response.arrayBuffer()));
186
- return WHISPER_CPP_MODEL_PATH;
218
+ await fs.writeFile(modelPath, Buffer.from(await response.arrayBuffer()));
219
+ return modelPath;
187
220
  }
188
221
  }
189
222
  async function convertAudioForWhisperCpp(sourcePath, outputPath, timeoutMs) {
@@ -235,6 +268,9 @@ async function transcribeAudioWithWhisperCpp(params, modelFetchImpl = fetch) {
235
268
  await fs.rm(workDir, { recursive: true, force: true }).catch(() => undefined);
236
269
  }
237
270
  }
271
+ async function downloadBlueBubblesAttachment(attachment, config, channelConfig, fetchImpl = fetch) {
272
+ return downloadAttachment(attachment, config, channelConfig, fetchImpl);
273
+ }
238
274
  async function downloadAttachment(attachment, config, channelConfig, fetchImpl) {
239
275
  const guid = attachment.guid?.trim();
240
276
  if (!guid) {
@@ -261,33 +297,114 @@ async function downloadAttachment(attachment, config, channelConfig, fetchImpl)
261
297
  };
262
298
  }
263
299
  async function hydrateBlueBubblesAttachments(attachments, config, channelConfig, deps = {}) {
264
- (0, runtime_1.emitNervesEvent)({
265
- component: "senses",
266
- event: "senses.bluebubbles_media_hydrate",
267
- message: "hydrating bluebubbles attachments",
268
- meta: {
269
- attachmentCount: attachments.length,
270
- preferAudioInput: deps.preferAudioInput ?? false,
271
- },
272
- });
273
300
  const fetchImpl = deps.fetchImpl ?? fetch;
274
301
  const modelFetchImpl = deps.modelFetchImpl ?? fetch;
275
302
  const transcribeAudio = deps.transcribeAudio ?? ((params) => transcribeAudioWithWhisperCpp(params, modelFetchImpl));
276
303
  const preferAudioInput = deps.preferAudioInput ?? false;
304
+ const chatModel = deps.chatModel;
305
+ const visionCapable = chatModel ? (0, model_capabilities_1.getModelCapabilities)(chatModel).vision === true : true;
277
306
  const inputParts = [];
278
307
  const transcriptAdditions = [];
279
308
  const notices = [];
280
309
  for (const attachment of attachments) {
281
310
  const name = describeAttachment(attachment);
311
+ // Remember every attachment we see — the describe_image agent tool looks
312
+ // up guids against this cache later to re-fetch bytes on demand.
313
+ (0, attachment_cache_1.rememberBlueBubblesAttachment)(attachment);
282
314
  try {
283
315
  const downloaded = await downloadAttachment(attachment, config, channelConfig, fetchImpl);
284
316
  const base64 = downloaded.buffer.toString("base64");
317
+ const byteCount = downloaded.buffer.length;
285
318
  if (isImageAttachment(attachment, downloaded.contentType)) {
286
- inputParts.push({
287
- type: "image_url",
288
- image_url: {
289
- url: `data:${downloaded.contentType ?? "application/octet-stream"};base64,${base64}`,
290
- detail: "auto",
319
+ const mimeType = downloaded.contentType ?? "application/octet-stream";
320
+ if (visionCapable) {
321
+ inputParts.push({
322
+ type: "image_url",
323
+ image_url: {
324
+ url: `data:${mimeType};base64,${base64}`,
325
+ detail: "auto",
326
+ },
327
+ });
328
+ (0, runtime_1.emitNervesEvent)({
329
+ level: "warn",
330
+ component: "senses",
331
+ event: "senses.bluebubbles_media_hydrate",
332
+ message: "bluebubbles media hydrate",
333
+ meta: {
334
+ attachmentGuid: attachment.guid,
335
+ mimeType,
336
+ byteCount,
337
+ hydrationPath: "native-passthrough",
338
+ },
339
+ });
340
+ continue;
341
+ }
342
+ // Non-vision chat model — try the VLM describe fallback.
343
+ if (!isSupportedVlmFormat(mimeType)) {
344
+ (0, runtime_1.emitNervesEvent)({
345
+ level: "warn",
346
+ component: "senses",
347
+ event: "senses.bluebubbles_vision_format_unsupported",
348
+ message: "bluebubbles vision format unsupported",
349
+ meta: {
350
+ mimeType,
351
+ transferName: attachment.transferName,
352
+ attachmentGuid: attachment.guid,
353
+ chatModel,
354
+ },
355
+ });
356
+ inputParts.push({
357
+ type: "text",
358
+ text: exports.VLM_TEXT_WRAPPERS.unsupported(mimeType),
359
+ });
360
+ (0, runtime_1.emitNervesEvent)({
361
+ level: "warn",
362
+ component: "senses",
363
+ event: "senses.bluebubbles_media_hydrate",
364
+ message: "bluebubbles media hydrate",
365
+ meta: {
366
+ attachmentGuid: attachment.guid,
367
+ mimeType,
368
+ byteCount,
369
+ hydrationPath: "skip-unsupported",
370
+ },
371
+ });
372
+ continue;
373
+ }
374
+ const dataUrl = `data:${mimeType};base64,${base64}`;
375
+ try {
376
+ if (!deps.vlmDescribe) {
377
+ throw new Error("no VLM describer configured — wire a vlmDescribe dep or configure a vision-capable chat model");
378
+ }
379
+ const description = await deps.vlmDescribe({
380
+ prompt: buildVlmPrompt(deps.userText),
381
+ imageDataUrl: dataUrl,
382
+ attachmentGuid: attachment.guid,
383
+ mimeType,
384
+ chatModel,
385
+ });
386
+ inputParts.push({
387
+ type: "text",
388
+ text: exports.VLM_TEXT_WRAPPERS.description(description),
389
+ });
390
+ }
391
+ catch (vlmError) {
392
+ const reason = vlmError instanceof Error ? vlmError.message : String(vlmError);
393
+ inputParts.push({
394
+ type: "text",
395
+ text: exports.VLM_TEXT_WRAPPERS.failure(reason),
396
+ });
397
+ }
398
+ (0, runtime_1.emitNervesEvent)({
399
+ level: "warn",
400
+ component: "senses",
401
+ event: "senses.bluebubbles_media_hydrate",
402
+ message: "bluebubbles media hydrate",
403
+ meta: {
404
+ attachmentGuid: attachment.guid,
405
+ mimeType,
406
+ byteCount,
407
+ hydrationPath: "vlm-describe",
291
408
  },
292
409
  });
293
410
  continue;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.normalizeBlueBubblesEvent = normalizeBlueBubblesEvent;
4
- const runtime_1 = require("../nerves/runtime");
4
+ const runtime_1 = require("../../nerves/runtime");
5
5
  function asRecord(value) {
6
6
  return value && typeof value === "object" && !Array.isArray(value)
7
7
  ? value
@@ -39,6 +39,7 @@ function extractChatIdentifierFromGuid(chatGuid) {
39
39
  return parts.length >= 3 ? parts[2]?.trim() || undefined : undefined;
40
40
  }
41
41
  function buildChatRef(data, threadOriginatorGuid) {
42
+ void threadOriginatorGuid;
42
43
  const chats = Array.isArray(data.chats) ? data.chats : [];
43
44
  const chat = asRecord(chats[0]) ?? null;
44
45
  const chatGuid = readString(chat, "guid");
@@ -48,12 +49,18 @@ function buildChatRef(data, threadOriginatorGuid) {
48
49
  const displayName = readString(chat, "displayName")?.trim() || undefined;
49
50
  const style = readNumber(chat, "style");
50
51
  const isGroup = style === 43 || (chatGuid?.includes(";+;") ?? false) || Boolean(displayName);
51
- const baseKey = chatGuid?.trim()
52
+ const sessionKey = chatGuid?.trim()
52
53
  ? `chat:${chatGuid.trim()}`
53
54
  : `chat_identifier:${(chatIdentifier ?? "unknown").trim()}`;
54
- const sessionKey = threadOriginatorGuid?.trim()
55
- ? `${baseKey}:thread:${threadOriginatorGuid.trim()}`
56
- : baseKey;
55
+ // Extract participant handles from chat.participants (when available from BB API)
56
+ const rawParticipants = Array.isArray(chat?.participants) ? chat.participants : [];
57
+ const participantHandles = rawParticipants
58
+ .map((p) => {
59
+ const rec = asRecord(p);
60
+ const addr = readString(rec, "address") ?? readString(rec, "id");
61
+ return addr ? normalizeHandle(addr) : "";
62
+ })
63
+ .filter(Boolean);
57
64
  return {
58
65
  chatGuid: chatGuid?.trim() || undefined,
59
66
  chatIdentifier: chatIdentifier?.trim() || undefined,
@@ -63,6 +70,7 @@ function buildChatRef(data, threadOriginatorGuid) {
63
70
  sendTarget: chatGuid?.trim()
64
71
  ? { kind: "chat_guid", value: chatGuid.trim() }
65
72
  : { kind: "chat_identifier", value: (chatIdentifier ?? "unknown").trim() },
73
+ participantHandles,
66
74
  };
67
75
  }
68
76
  function extractSender(data, chat) {
@@ -119,6 +127,13 @@ function formatMessageText(data, attachments) {
119
127
  if (balloonBundleId === "com.apple.messages.URLBalloonProvider") {
120
128
  return `${text}\n[link preview attached]`;
121
129
  }
130
+ // B2 fix: when text and attachments both exist, append the attachment
131
+ // marker so downstream senses can see the guid/filename. Previously the
132
+ // marker was dropped whenever text was non-empty, which hid images from
133
+ // the agent when the user captioned a screenshot.
134
+ if (attachments.length > 0) {
135
+ return `${text}\n${formatAttachmentText(attachments)}`;
136
+ }
122
137
  return text;
123
138
  }
124
139
  return formatAttachmentText(attachments);
@@ -35,15 +35,14 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.getBlueBubblesMutationLogPath = getBlueBubblesMutationLogPath;
37
37
  exports.recordBlueBubblesMutation = recordBlueBubblesMutation;
38
+ exports.listBlueBubblesRecoveryCandidates = listBlueBubblesRecoveryCandidates;
38
39
  const fs = __importStar(require("node:fs"));
39
- const os = __importStar(require("node:os"));
40
40
  const path = __importStar(require("node:path"));
41
- const runtime_1 = require("../nerves/runtime");
42
- function sanitizeKey(key) {
43
- return key.replace(/[/:]/g, "_");
44
- }
41
+ const runtime_1 = require("../../nerves/runtime");
42
+ const identity_1 = require("../../heart/identity");
43
+ const config_1 = require("../../heart/config");
45
44
  function getBlueBubblesMutationLogPath(agentName, sessionKey) {
46
- return path.join(os.homedir(), ".agentstate", agentName, "senses", "bluebubbles", "mutations", `${sanitizeKey(sessionKey)}.ndjson`);
45
+ return path.join((0, identity_1.getAgentRoot)(agentName), "state", "senses", "bluebubbles", "mutations", `${(0, config_1.sanitizeKey)(sessionKey)}.ndjson`);
47
46
  }
48
47
  function recordBlueBubblesMutation(agentName, event) {
49
48
  const filePath = getBlueBubblesMutationLogPath(agentName, event.chat.sessionKey);
@@ -74,3 +73,44 @@ function recordBlueBubblesMutation(agentName, event) {
74
73
  });
75
74
  return filePath;
76
75
  }
76
+ function listBlueBubblesRecoveryCandidates(agentName) {
77
+ const rootDir = path.join((0, identity_1.getAgentRoot)(agentName), "state", "senses", "bluebubbles", "mutations");
78
+ let files;
79
+ try {
80
+ files = fs.readdirSync(rootDir);
81
+ }
82
+ catch {
83
+ return [];
84
+ }
85
+ const deduped = new Map();
86
+ for (const file of files.filter((entry) => entry.endsWith(".ndjson")).sort()) {
87
+ const filePath = path.join(rootDir, file);
88
+ let raw = "";
89
+ try {
90
+ raw = fs.readFileSync(filePath, "utf-8");
91
+ }
92
+ catch {
93
+ continue;
94
+ }
95
+ for (const line of raw.split("\n")) {
96
+ const trimmed = line.trim();
97
+ if (!trimmed)
98
+ continue;
99
+ try {
100
+ const entry = JSON.parse(trimmed);
101
+ if (typeof entry.messageGuid !== "string"
102
+ || !entry.messageGuid.trim()
103
+ || entry.fromMe
104
+ || entry.shouldNotifyAgent
105
+ || (entry.mutationType !== "read" && entry.mutationType !== "delivery")) {
106
+ continue;
107
+ }
108
+ deduped.set(entry.messageGuid, entry);
109
+ }
110
+ catch {
111
+ // ignore malformed recovery candidates
112
+ }
113
+ }
114
+ }
115
+ return [...deduped.values()].sort((left, right) => left.recordedAt.localeCompare(right.recordedAt));
116
+ }
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.getBlueBubblesRuntimeStatePath = getBlueBubblesRuntimeStatePath;
37
+ exports.readBlueBubblesRuntimeState = readBlueBubblesRuntimeState;
38
+ exports.writeBlueBubblesRuntimeState = writeBlueBubblesRuntimeState;
39
+ const fs = __importStar(require("node:fs"));
40
+ const path = __importStar(require("node:path"));
41
+ const identity_1 = require("../../heart/identity");
42
+ const runtime_1 = require("../../nerves/runtime");
43
+ const DEFAULT_RUNTIME_STATE = {
44
+ upstreamStatus: "unknown",
45
+ detail: "startup health probe pending",
46
+ pendingRecoveryCount: 0,
47
+ };
48
+ function getBlueBubblesRuntimeStatePath(agentName, agentRoot = (0, identity_1.getAgentRoot)(agentName)) {
49
+ return path.join(agentRoot, "state", "senses", "bluebubbles", "runtime.json");
50
+ }
51
+ function readBlueBubblesRuntimeState(agentName, agentRoot) {
52
+ const filePath = getBlueBubblesRuntimeStatePath(agentName, agentRoot);
53
+ try {
54
+ const raw = fs.readFileSync(filePath, "utf-8");
55
+ const parsed = JSON.parse(raw);
56
+ return {
57
+ upstreamStatus: parsed.upstreamStatus === "ok" || parsed.upstreamStatus === "error"
58
+ ? parsed.upstreamStatus
59
+ : "unknown",
60
+ detail: typeof parsed.detail === "string" && parsed.detail.trim()
61
+ ? parsed.detail
62
+ : DEFAULT_RUNTIME_STATE.detail,
63
+ lastCheckedAt: typeof parsed.lastCheckedAt === "string" ? parsed.lastCheckedAt : undefined,
64
+ pendingRecoveryCount: typeof parsed.pendingRecoveryCount === "number" && Number.isFinite(parsed.pendingRecoveryCount)
65
+ ? parsed.pendingRecoveryCount
66
+ : 0,
67
+ lastRecoveredAt: typeof parsed.lastRecoveredAt === "string" ? parsed.lastRecoveredAt : undefined,
68
+ lastRecoveredMessageGuid: typeof parsed.lastRecoveredMessageGuid === "string"
69
+ ? parsed.lastRecoveredMessageGuid
70
+ : undefined,
71
+ };
72
+ }
73
+ catch {
74
+ return { ...DEFAULT_RUNTIME_STATE };
75
+ }
76
+ }
77
+ function writeBlueBubblesRuntimeState(agentName, state, agentRoot) {
78
+ const filePath = getBlueBubblesRuntimeStatePath(agentName, agentRoot);
79
+ try {
80
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
81
+ fs.writeFileSync(filePath, JSON.stringify(state, null, 2) + "\n", "utf-8");
82
+ }
83
+ catch (error) {
84
+ (0, runtime_1.emitNervesEvent)({
85
+ level: "warn",
86
+ component: "senses",
87
+ event: "senses.bluebubbles_runtime_state_error",
88
+ message: "failed to write bluebubbles runtime state",
89
+ meta: {
90
+ agentName,
91
+ upstreamStatus: state.upstreamStatus,
92
+ reason: error instanceof Error ? error.message : String(error),
93
+ },
94
+ });
95
+ return filePath;
96
+ }
97
+ (0, runtime_1.emitNervesEvent)({
98
+ component: "senses",
99
+ event: "senses.bluebubbles_runtime_state_written",
100
+ message: "wrote bluebubbles runtime state",
101
+ meta: {
102
+ agentName,
103
+ upstreamStatus: state.upstreamStatus,
104
+ pendingRecoveryCount: state.pendingRecoveryCount,
105
+ path: filePath,
106
+ },
107
+ });
108
+ return filePath;
109
+ }
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.findObsoleteBlueBubblesThreadSessions = findObsoleteBlueBubblesThreadSessions;
37
+ const fs = __importStar(require("node:fs"));
38
+ const path = __importStar(require("node:path"));
39
+ const runtime_1 = require("../../nerves/runtime");
40
+ function findObsoleteBlueBubblesThreadSessions(trunkSessionPath) {
41
+ const normalized = trunkSessionPath.trim();
42
+ if (!normalized.endsWith(".json"))
43
+ return [];
44
+ const trunkName = path.basename(normalized);
45
+ if (trunkName.includes("_thread_"))
46
+ return [];
47
+ if (!fs.existsSync(normalized))
48
+ return [];
49
+ const dir = path.dirname(normalized);
50
+ const prefix = trunkName.slice(0, -".json".length);
51
+ const threadLaneFiles = [];
52
+ for (const entry of fs.readdirSync(dir)) {
53
+ if (!entry.endsWith(".json"))
54
+ continue;
55
+ if (!entry.startsWith(`${prefix}_thread_`))
56
+ continue;
57
+ threadLaneFiles.push(path.join(dir, entry));
58
+ }
59
+ if (threadLaneFiles.length > 0) {
60
+ (0, runtime_1.emitNervesEvent)({
61
+ level: "warn",
62
+ component: "senses",
63
+ event: "senses.bluebubbles_thread_lane_artifacts_detected",
64
+ message: "detected obsolete bluebubbles thread-lane sessions",
65
+ meta: {
66
+ sessionPath: normalized,
67
+ artifactCount: threadLaneFiles.length,
68
+ },
69
+ });
70
+ }
71
+ return threadLaneFiles;
72
+ }
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BracketedPasteHandler = void 0;
4
+ /**
5
+ * Bracketed paste mode handler for the TUI.
6
+ *
7
+ * Detects \x1b[200~ (paste start) and \x1b[201~ (paste end) markers in
8
+ * raw stdin data. Buffers paste content between markers and emits it as
9
+ * a single "paste" event. Non-paste data is emitted as "data" unchanged.
10
+ *
11
+ * Works alongside Ink's stdin handling by intercepting raw data events.
12
+ */
13
+ const events_1 = require("events");
14
+ const runtime_1 = require("../../nerves/runtime");
15
+ const PASTE_START = "\x1b[200~";
16
+ const PASTE_END = "\x1b[201~";
17
+ class BracketedPasteHandler extends events_1.EventEmitter {
18
+ stdin;
19
+ stdout;
20
+ pasting = false;
21
+ buffer = "";
22
+ dataHandler;
23
+ constructor(stdin, stdout) {
24
+ super();
25
+ this.stdin = stdin;
26
+ this.stdout = stdout;
27
+ // Enable bracketed paste mode
28
+ stdout.write("\x1b[?2004h");
29
+ this.dataHandler = (chunk) => {
30
+ this.processChunk(chunk.toString());
31
+ };
32
+ stdin.prependListener("data", this.dataHandler);
33
+ }
34
+ processChunk(data) {
35
+ let remaining = data;
36
+ while (remaining.length > 0) {
37
+ if (this.pasting) {
38
+ // Look for end marker in buffer + remaining
39
+ const combined = this.buffer + remaining;
40
+ const endIdx = combined.indexOf(PASTE_END);
41
+ if (endIdx !== -1) {
42
+ // Found end marker -- emit paste content
43
+ const pasteContent = combined.slice(0, endIdx);
44
+ (0, runtime_1.emitNervesEvent)({ component: "senses", event: "senses.bracketed_paste", message: "bracketed paste received", meta: { length: pasteContent.length } });
45
+ this.emit("paste", pasteContent);
46
+ this.buffer = "";
47
+ this.pasting = false;
48
+ // Process remaining data after end marker
49
+ remaining = combined.slice(endIdx + PASTE_END.length);
50
+ continue;
51
+ }
52
+ // No end marker yet -- buffer everything so far
53
+ this.buffer = combined;
54
+ return;
55
+ }
56
+ // Not pasting -- look for start marker
57
+ const startIdx = remaining.indexOf(PASTE_START);
58
+ if (startIdx !== -1) {
59
+ // Emit any data before the start marker
60
+ const before = remaining.slice(0, startIdx);
61
+ if (before.length > 0) {
62
+ this.emit("data", before);
63
+ }
64
+ // Enter paste mode
65
+ this.pasting = true;
66
+ this.buffer = "";
67
+ remaining = remaining.slice(startIdx + PASTE_START.length);
68
+ continue;
69
+ }
70
+ // No start marker -- emit as regular data
71
+ this.emit("data", remaining);
72
+ return;
73
+ }
74
+ }
75
+ /** Disable bracketed paste mode and remove listeners. */
76
+ destroy() {
77
+ this.stdout.write("\x1b[?2004l");
78
+ this.stdin.removeListener("data", this.dataHandler);
79
+ this.removeAllListeners();
80
+ }
81
+ }
82
+ exports.BracketedPasteHandler = BracketedPasteHandler;