sparkecoder 0.1.115 → 0.1.117

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 (162) hide show
  1. package/dist/agent/index.d.ts +3 -3
  2. package/dist/agent/index.js +62 -0
  3. package/dist/agent/index.js.map +1 -1
  4. package/dist/cli.js +387 -108
  5. package/dist/cli.js.map +1 -1
  6. package/dist/db/index.d.ts +2 -2
  7. package/dist/{index-Biy5JTop.d.ts → index-Bi8Ek02A.d.ts} +104 -104
  8. package/dist/index.d.ts +5 -5
  9. package/dist/index.js +313 -64
  10. package/dist/index.js.map +1 -1
  11. package/dist/{schema-CYSKJZ3m.d.ts → schema-ecQSnCMz.d.ts} +3 -3
  12. package/dist/{search-CVVfuBPZ.d.ts → search-DOzC4ojH.d.ts} +4 -4
  13. package/dist/server/index.js +313 -64
  14. package/dist/server/index.js.map +1 -1
  15. package/dist/skills/default/computer-use.md +7 -0
  16. package/dist/skills/default/recording.md +5 -0
  17. package/dist/tools/index.d.ts +3 -3
  18. package/package.json +1 -1
  19. package/src/skills/default/computer-use.md +7 -0
  20. package/src/skills/default/recording.md +5 -0
  21. package/web/.next/BUILD_ID +1 -1
  22. package/web/.next/standalone/web/.next/BUILD_ID +1 -1
  23. package/web/.next/standalone/web/.next/build-manifest.json +2 -2
  24. package/web/.next/standalone/web/.next/prerender-manifest.json +3 -3
  25. package/web/.next/standalone/web/.next/server/app/(main)/agents/page_client-reference-manifest.js +1 -1
  26. package/web/.next/standalone/web/.next/server/app/(main)/page_client-reference-manifest.js +1 -1
  27. package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page.js.nft.json +1 -1
  28. package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page_client-reference-manifest.js +1 -1
  29. package/web/.next/standalone/web/.next/server/app/(main)/settings/page.js.nft.json +1 -1
  30. package/web/.next/standalone/web/.next/server/app/(main)/settings/page_client-reference-manifest.js +1 -1
  31. package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -2
  32. package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
  33. package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  34. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  35. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  36. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  37. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  38. package/web/.next/standalone/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  39. package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
  40. package/web/.next/standalone/web/.next/server/app/_not-found.rsc +2 -2
  41. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  42. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  43. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  44. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  45. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  46. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  47. package/web/.next/standalone/web/.next/server/app/agents.html +1 -1
  48. package/web/.next/standalone/web/.next/server/app/agents.rsc +2 -2
  49. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents/__PAGE__.segment.rsc +1 -1
  50. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents.segment.rsc +1 -1
  51. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p.segment.rsc +1 -1
  52. package/web/.next/standalone/web/.next/server/app/agents.segments/_full.segment.rsc +2 -2
  53. package/web/.next/standalone/web/.next/server/app/agents.segments/_head.segment.rsc +1 -1
  54. package/web/.next/standalone/web/.next/server/app/agents.segments/_index.segment.rsc +2 -2
  55. package/web/.next/standalone/web/.next/server/app/agents.segments/_tree.segment.rsc +2 -2
  56. package/web/.next/standalone/web/.next/server/app/docs/installation/page_client-reference-manifest.js +1 -1
  57. package/web/.next/standalone/web/.next/server/app/docs/installation.html +2 -2
  58. package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +2 -2
  59. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +2 -2
  60. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +1 -1
  61. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +2 -2
  62. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +2 -2
  63. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +1 -1
  64. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +1 -1
  65. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +1 -1
  66. package/web/.next/standalone/web/.next/server/app/docs/page_client-reference-manifest.js +1 -1
  67. package/web/.next/standalone/web/.next/server/app/docs/skills/page_client-reference-manifest.js +1 -1
  68. package/web/.next/standalone/web/.next/server/app/docs/skills.html +2 -2
  69. package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +2 -2
  70. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +2 -2
  71. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +1 -1
  72. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +2 -2
  73. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +2 -2
  74. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +1 -1
  75. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +1 -1
  76. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +1 -1
  77. package/web/.next/standalone/web/.next/server/app/docs/tools/page_client-reference-manifest.js +1 -1
  78. package/web/.next/standalone/web/.next/server/app/docs/tools.html +2 -2
  79. package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +2 -2
  80. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +2 -2
  81. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +1 -1
  82. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +2 -2
  83. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +2 -2
  84. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +1 -1
  85. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +1 -1
  86. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +1 -1
  87. package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
  88. package/web/.next/standalone/web/.next/server/app/docs.rsc +2 -2
  89. package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +2 -2
  90. package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +1 -1
  91. package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +2 -2
  92. package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +2 -2
  93. package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +1 -1
  94. package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +1 -1
  95. package/web/.next/standalone/web/.next/server/app/index.html +1 -1
  96. package/web/.next/standalone/web/.next/server/app/index.rsc +2 -2
  97. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +1 -1
  98. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +1 -1
  99. package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +2 -2
  100. package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
  101. package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +2 -2
  102. package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  103. package/web/.next/standalone/web/.next/server/app/settings.html +1 -1
  104. package/web/.next/standalone/web/.next/server/app/settings.rsc +3 -3
  105. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings/__PAGE__.segment.rsc +2 -2
  106. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings.segment.rsc +1 -1
  107. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p.segment.rsc +1 -1
  108. package/web/.next/standalone/web/.next/server/app/settings.segments/_full.segment.rsc +3 -3
  109. package/web/.next/standalone/web/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  110. package/web/.next/standalone/web/.next/server/app/settings.segments/_index.segment.rsc +2 -2
  111. package/web/.next/standalone/web/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
  112. package/web/.next/standalone/web/.next/server/chunks/ssr/2374f_lucide-react_dist_esm_icons_7340c8b3._.js +3 -0
  113. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__f3e6443f._.js +15 -0
  114. package/web/.next/standalone/web/.next/server/chunks/ssr/web_41927ef5._.js +3 -0
  115. package/web/.next/standalone/web/.next/server/chunks/ssr/web_src_app_(main)_settings_page_tsx_eb320e07._.js +1 -1
  116. package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
  117. package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
  118. package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
  119. package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
  120. package/web/.next/standalone/web/.next/static/chunks/2c3c1d478808e4e4.js +1 -0
  121. package/web/.next/standalone/web/.next/static/chunks/3b0501ec3249235f.js +7 -0
  122. package/web/.next/standalone/web/.next/static/chunks/44c575e006ddb992.js +13 -0
  123. package/web/.next/standalone/web/.next/static/chunks/9a3afb48c245fb2a.js +1 -0
  124. package/web/.next/standalone/web/.next/static/chunks/b3bc7244f3477729.css +1 -0
  125. package/web/.next/standalone/web/.next/static/static/chunks/2c3c1d478808e4e4.js +1 -0
  126. package/web/.next/standalone/web/.next/static/static/chunks/3b0501ec3249235f.js +7 -0
  127. package/web/.next/standalone/web/.next/static/static/chunks/44c575e006ddb992.js +13 -0
  128. package/web/.next/standalone/web/.next/static/static/chunks/9a3afb48c245fb2a.js +1 -0
  129. package/web/.next/standalone/web/.next/static/static/chunks/b3bc7244f3477729.css +1 -0
  130. package/web/.next/standalone/web/src/app/(main)/settings/page.tsx +255 -3
  131. package/web/.next/static/chunks/2c3c1d478808e4e4.js +1 -0
  132. package/web/.next/static/chunks/3b0501ec3249235f.js +7 -0
  133. package/web/.next/static/chunks/44c575e006ddb992.js +13 -0
  134. package/web/.next/static/chunks/9a3afb48c245fb2a.js +1 -0
  135. package/web/.next/static/chunks/b3bc7244f3477729.css +1 -0
  136. package/web/.next/standalone/web/.next/server/chunks/ssr/2374f_lucide-react_dist_esm_icons_50c2f239._.js +0 -3
  137. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__6097da17._.js +0 -15
  138. package/web/.next/standalone/web/.next/server/chunks/ssr/web_3b9a2423._.js +0 -3
  139. package/web/.next/standalone/web/.next/static/chunks/60359bdd369c0c72.js +0 -1
  140. package/web/.next/standalone/web/.next/static/chunks/a189cacf6d83cf0b.js +0 -13
  141. package/web/.next/standalone/web/.next/static/chunks/bef6931fdd8428c8.js +0 -1
  142. package/web/.next/standalone/web/.next/static/chunks/c1f73b3fa4353c31.css +0 -1
  143. package/web/.next/standalone/web/.next/static/chunks/fbdcbd65f9a38f4b.js +0 -7
  144. package/web/.next/standalone/web/.next/static/static/chunks/60359bdd369c0c72.js +0 -1
  145. package/web/.next/standalone/web/.next/static/static/chunks/a189cacf6d83cf0b.js +0 -13
  146. package/web/.next/standalone/web/.next/static/static/chunks/bef6931fdd8428c8.js +0 -1
  147. package/web/.next/standalone/web/.next/static/static/chunks/c1f73b3fa4353c31.css +0 -1
  148. package/web/.next/standalone/web/.next/static/static/chunks/fbdcbd65f9a38f4b.js +0 -7
  149. package/web/.next/static/chunks/60359bdd369c0c72.js +0 -1
  150. package/web/.next/static/chunks/a189cacf6d83cf0b.js +0 -13
  151. package/web/.next/static/chunks/bef6931fdd8428c8.js +0 -1
  152. package/web/.next/static/chunks/c1f73b3fa4353c31.css +0 -1
  153. package/web/.next/static/chunks/fbdcbd65f9a38f4b.js +0 -7
  154. /package/web/.next/standalone/web/.next/static/{pSGgtxBjN5_o0YHZgQzXm → static/vLqK4jK7EKdLCpQ-D6-qL}/_buildManifest.js +0 -0
  155. /package/web/.next/standalone/web/.next/static/{pSGgtxBjN5_o0YHZgQzXm → static/vLqK4jK7EKdLCpQ-D6-qL}/_clientMiddlewareManifest.json +0 -0
  156. /package/web/.next/standalone/web/.next/static/{pSGgtxBjN5_o0YHZgQzXm → static/vLqK4jK7EKdLCpQ-D6-qL}/_ssgManifest.js +0 -0
  157. /package/web/.next/standalone/web/.next/static/{static/pSGgtxBjN5_o0YHZgQzXm → vLqK4jK7EKdLCpQ-D6-qL}/_buildManifest.js +0 -0
  158. /package/web/.next/standalone/web/.next/static/{static/pSGgtxBjN5_o0YHZgQzXm → vLqK4jK7EKdLCpQ-D6-qL}/_clientMiddlewareManifest.json +0 -0
  159. /package/web/.next/standalone/web/.next/static/{static/pSGgtxBjN5_o0YHZgQzXm → vLqK4jK7EKdLCpQ-D6-qL}/_ssgManifest.js +0 -0
  160. /package/web/.next/static/{pSGgtxBjN5_o0YHZgQzXm → vLqK4jK7EKdLCpQ-D6-qL}/_buildManifest.js +0 -0
  161. /package/web/.next/static/{pSGgtxBjN5_o0YHZgQzXm → vLqK4jK7EKdLCpQ-D6-qL}/_clientMiddlewareManifest.json +0 -0
  162. /package/web/.next/static/{pSGgtxBjN5_o0YHZgQzXm → vLqK4jK7EKdLCpQ-D6-qL}/_ssgManifest.js +0 -0
@@ -7654,6 +7654,68 @@ Headless workers never interfere with desktop workers (they don't touch the scre
7654
7654
  When you spawn a **desktop worker**, include a one-liner in the goal asking it to **record the session by default** (\`screencapture -v -V <seconds> -C\` on macOS) and return the recording path in its result, *unless* the task is long-running / boring / contains sensitive content. The recording lets you (and the user) replay what actually happened on screen. When the worker reports back, mention the recording path in your reply via the original channel.` : ""}
7655
7655
 
7656
7656
  Default bias: **when in doubt, decompose**. Two workers running in parallel and reporting independently is almost always better UX than one worker doing things sequentially.
7657
+
7658
+ ### How to TALK to the user (versus how you reason internally)
7659
+
7660
+ All of the rules below \u2014 decomposition, parallel spawning, "don't invent commands", load-the-skill, etc. \u2014 are **your internal operating procedure**. They are how you decide what to do. They are NOT something to recite back to the user.
7661
+
7662
+ When replying to the user (Slack, web, or any channel), be a normal helpful assistant:
7663
+
7664
+ - Tell them *what you're doing*, not *how you're doing it internally*.
7665
+ - Don't quote your own prompt language ("just the goal", "read the skill", "no step-by-step from me", "decomposing into parallel workers"). The user doesn't care about your delegation pattern.
7666
+ - Don't narrate "handing off to a worker now" unless it's actually relevant (e.g. they asked how you work, or the work is going to take a noticeably long time).
7667
+ - Skip ceremony. A short acknowledgement + a brief description of the actual task + (optionally) a heads-up if there's anything they need to do or avoid is plenty.
7668
+
7669
+ | What you might be tempted to say | What you should say instead |
7670
+ |---|---|
7671
+ | *"Got it \u2014 handing it off with just the goal + 'read the skills and figure it out.' No step-by-step from me."* | *"On it. Recording a screen capture of the Weather app showing Anchorage. Don't touch the keyboard while it's running \u2014 I'll post the video when it's done."* |
7672
+ | *"Decomposing into two parallel workers: one headless, one desktop."* | *"Running the tests and pulling the diff at the same time. Back in ~30s."* |
7673
+ | *"Spawning worker \`screenshot-calc\` with goal: \u2026"* | *"Taking a screenshot of Calculator now."* |
7674
+ | *"I'll relay the user's instructions to the worker verbatim."* | *(say nothing \u2014 just do it)* |
7675
+
7676
+ If the user explicitly asks how you work, *then* you can explain the orchestrator/worker split. Otherwise: less is more.
7677
+
7678
+ ### How to write a worker goal (and what NOT to put in it)
7679
+
7680
+ You delegate; the worker executes. Stay at the **what** level, not the **how**.
7681
+
7682
+ **DO** put in the goal:
7683
+
7684
+ - The end objective ("open the macOS Weather app and capture the forecast for Anchorage as a screen recording").
7685
+ - Which skills the worker should load up-front (\`load_skill recording\`, \`load_skill computer-use\`).
7686
+ - Acceptance criteria ("verify the city name is visible in the screenshot before reporting done").
7687
+ - Routing back ("post the recording URL to Slack channel C0123 thread 1700.001").
7688
+
7689
+ **DO NOT** put in the goal (when you're inventing commands from memory):
7690
+
7691
+ - Literal shell commands (\`screencapture -v -V 45 -C /tmp/...\`, \`osascript -e ...\`, \`cliclick kp:cmd+f\`).
7692
+ - Pre-written step-by-step bash that you're drafting from training-data recall.
7693
+ - The names of tools you can't see in your current toolset.
7694
+
7695
+ If you have to reach for memory to write a command, **you're guessing** \u2014 your training data has lots of plausible-looking commands that are subtly wrong or stale. The worker will dutifully follow your wrong instructions instead of consulting the source of truth.
7696
+
7697
+ **Exceptions \u2014 concrete steps ARE appropriate ONLY when relayed verbatim:**
7698
+
7699
+ You CAN include literal step-by-step commands when one of these is true:
7700
+
7701
+ 1. **The user gave the steps to you.** Their message says "first run X, then Y, then commit" \u2192 forward those verbatim. That's the user's intent, not your guess.
7702
+ 2. **A previous turn already established them.** An earlier worker reported "the deploy script lives at \`./scripts/deploy.sh --env prod\`" \u2192 you can hand that command to the next worker.
7703
+ 3. **The conversation history contains them.** A documented \`bash\` invocation from earlier in the chat, an error message that revealed the right path, a CI log the user shared \u2014 anything already concrete in context.
7704
+
7705
+ In all three cases, **label the source** in the goal: *"Per your instructions earlier: 1. run X, 2. run Y..."* or *"Reusing the command worker-foo found last turn: \`./scripts/deploy.sh\`"*.
7706
+
7707
+ What you do NOT do:
7708
+
7709
+ - **Don't paraphrase or "improve" a skill into the goal.** If the recording skill describes \`sparkecoder record start/stop\`, the goal just says *"per the recording skill, bracket the work with start/stop"* \u2014 never quote the exact command. The worker loads the skill and reads the canonical version itself. You quoting it just adds a way for the quote to drift behind the source of truth.
7710
+ - **Don't reason your way to a command.** "I think macOS uses \`open -a Weather\` to launch apps" is exactly the kind of training-data recall that produces stale or wrong commands. Don't include it.
7711
+
7712
+ The rule is: **relay, never invent \u2014 and never quote a skill.** Your job is to (a) tell the worker which skills to load, (b) state the objective and acceptance criteria, (c) relay any concrete steps the user or prior context already established. Workers do the looking-up; you do the dispatching.
7713
+
7714
+ Bad goal (don't do this):
7715
+ > "Start a screen recording with \`screencapture -v -V 45 -C /tmp/weather.mov &\`, then open Weather with \`open -a Weather\`, then click the search bar with cliclick, type 'Anchorage'..."
7716
+
7717
+ Good goal (do this):
7718
+ > "Capture a 30\u201360s screen recording of opening the macOS Weather app and viewing the Anchorage, AK forecast. \`load_skill recording\` and \`load_skill computer-use\` first; use the canonical commands from those skills. Verify the Anchorage temperature is visible in a final screenshot before completing. Return the recording path + a one-line summary of the forecast."
7657
7719
  `;
7658
7720
  }
7659
7721
  function createSummaryPrompt(conversationHistory) {
@@ -10570,11 +10632,11 @@ ${p.text}` : p.text;
10570
10632
  const { isRemoteConfigured: isRemoteConfigured2, storageQueries: storageQueries2 } = await Promise.resolve().then(() => (init_remote(), remote_exports));
10571
10633
  if (!isRemoteConfigured2()) return [];
10572
10634
  const { readFile: readFile12 } = await import("fs/promises");
10573
- const { join: join16, basename: basename6 } = await import("path");
10635
+ const { join: join17, basename: basename6 } = await import("path");
10574
10636
  const urls = [];
10575
10637
  for (const filePath of filePaths) {
10576
10638
  try {
10577
- const fullPath = filePath.startsWith("/") ? filePath : join16(this.session.workingDirectory, filePath);
10639
+ const fullPath = filePath.startsWith("/") ? filePath : join17(this.session.workingDirectory, filePath);
10578
10640
  const fileName = basename6(fullPath);
10579
10641
  const ext = fileName.split(".").pop()?.toLowerCase() || "";
10580
10642
  const mimeMap = {
@@ -10778,6 +10840,121 @@ var init_session_lock = __esm({
10778
10840
  }
10779
10841
  });
10780
10842
 
10843
+ // src/orchestrator/webhook-events.ts
10844
+ import { existsSync as existsSync18, readFileSync as readFileSync9, appendFileSync as appendFileSync3, writeFileSync as writeFileSync3, mkdirSync as mkdirSync7 } from "fs";
10845
+ import { dirname as dirname6, join as join12 } from "path";
10846
+ import { nanoid as nanoid10 } from "nanoid";
10847
+ function logFilePath() {
10848
+ return join12(getAppDataDirectory(), "webhook-events.jsonl");
10849
+ }
10850
+ function ensureLoaded() {
10851
+ if (cache !== null) return cache;
10852
+ cache = [];
10853
+ try {
10854
+ const p = logFilePath();
10855
+ if (!existsSync18(p)) return cache;
10856
+ const lines = readFileSync9(p, "utf-8").split("\n").filter(Boolean);
10857
+ for (const line of lines) {
10858
+ try {
10859
+ cache.push(JSON.parse(line));
10860
+ } catch {
10861
+ }
10862
+ }
10863
+ if (cache.length > MAX_EVENTS) {
10864
+ cache = cache.slice(-MAX_EVENTS);
10865
+ try {
10866
+ writeFileSync3(p, cache.map((e) => JSON.stringify(e)).join("\n") + "\n");
10867
+ } catch {
10868
+ }
10869
+ }
10870
+ } catch {
10871
+ }
10872
+ return cache;
10873
+ }
10874
+ function appendEvent(ev) {
10875
+ const list = ensureLoaded();
10876
+ list.push(ev);
10877
+ if (list.length > MAX_EVENTS) list.shift();
10878
+ try {
10879
+ const p = logFilePath();
10880
+ mkdirSync7(dirname6(p), { recursive: true });
10881
+ appendFileSync3(p, JSON.stringify(ev) + "\n");
10882
+ } catch {
10883
+ }
10884
+ }
10885
+ function recordEvent(ev) {
10886
+ const full = {
10887
+ id: ev.id ?? nanoid10(),
10888
+ ts: ev.ts ?? (/* @__PURE__ */ new Date()).toISOString(),
10889
+ source: ev.source,
10890
+ status: ev.status,
10891
+ subtype: ev.subtype,
10892
+ channel: ev.channel,
10893
+ user: ev.user,
10894
+ textSnippet: ev.textSnippet?.slice(0, 200),
10895
+ dropReason: ev.dropReason,
10896
+ error: ev.error,
10897
+ sessionId: ev.sessionId,
10898
+ durationMs: ev.durationMs,
10899
+ meta: ev.meta
10900
+ };
10901
+ appendEvent(full);
10902
+ return full.id;
10903
+ }
10904
+ function updateEvent(id, patch) {
10905
+ const list = ensureLoaded();
10906
+ const i = list.findIndex((e) => e.id === id);
10907
+ if (i < 0) return;
10908
+ list[i] = { ...list[i], ...patch };
10909
+ try {
10910
+ const p = logFilePath();
10911
+ mkdirSync7(dirname6(p), { recursive: true });
10912
+ writeFileSync3(p, list.map((e) => JSON.stringify(e)).join("\n") + "\n");
10913
+ } catch {
10914
+ }
10915
+ }
10916
+ function listEvents(filter = {}) {
10917
+ const list = ensureLoaded();
10918
+ const q = filter.q?.toLowerCase();
10919
+ const sinceTs = filter.since ? Date.parse(filter.since) : -Infinity;
10920
+ const beforeTs = filter.before ? Date.parse(filter.before) : Infinity;
10921
+ const matched = list.filter((e) => {
10922
+ if (filter.source && e.source !== filter.source) return false;
10923
+ if (filter.status && e.status !== filter.status) return false;
10924
+ const t = Date.parse(e.ts);
10925
+ if (t < sinceTs) return false;
10926
+ if (t >= beforeTs) return false;
10927
+ if (q) {
10928
+ const hay = `${e.channel ?? ""} ${e.user ?? ""} ${e.textSnippet ?? ""} ${e.dropReason ?? ""} ${e.error ?? ""} ${e.subtype ?? ""}`.toLowerCase();
10929
+ if (!hay.includes(q)) return false;
10930
+ }
10931
+ return true;
10932
+ });
10933
+ matched.reverse();
10934
+ const offset = Math.max(0, filter.offset ?? 0);
10935
+ const limit = Math.min(500, Math.max(1, filter.limit ?? 50));
10936
+ return {
10937
+ events: matched.slice(offset, offset + limit),
10938
+ total: matched.length
10939
+ };
10940
+ }
10941
+ function clearAllEvents() {
10942
+ cache = [];
10943
+ try {
10944
+ writeFileSync3(logFilePath(), "");
10945
+ } catch {
10946
+ }
10947
+ }
10948
+ var MAX_EVENTS, cache;
10949
+ var init_webhook_events = __esm({
10950
+ "src/orchestrator/webhook-events.ts"() {
10951
+ "use strict";
10952
+ init_config();
10953
+ MAX_EVENTS = 1e3;
10954
+ cache = null;
10955
+ }
10956
+ });
10957
+
10781
10958
  // src/orchestrator/daemon.ts
10782
10959
  var daemon_exports = {};
10783
10960
  __export(daemon_exports, {
@@ -10839,6 +11016,17 @@ async function runDaemonTurn(sessionId, events) {
10839
11016
  });
10840
11017
  const finishedAt = /* @__PURE__ */ new Date();
10841
11018
  const trimmed = text.trim();
11019
+ recordEvent({
11020
+ source: "daemon",
11021
+ status: error ? "failed" : "completed",
11022
+ channel: events[0]?.ref?.channel ?? void 0,
11023
+ user: events[0]?.ref?.user,
11024
+ textSnippet: trimmed.slice(0, 200),
11025
+ error,
11026
+ sessionId,
11027
+ durationMs: finishedAt.getTime() - startedAt.getTime(),
11028
+ meta: { triggeredBy: events.map((e) => e.content?.slice(0, 80)) }
11029
+ });
10842
11030
  broadcast({ sessionId, text: trimmed, triggeredBy: events, startedAt, finishedAt, error });
10843
11031
  }
10844
11032
  var listeners;
@@ -10849,6 +11037,7 @@ var init_daemon = __esm({
10849
11037
  init_session_lock();
10850
11038
  init_db();
10851
11039
  init_inbox();
11040
+ init_webhook_events();
10852
11041
  listeners = /* @__PURE__ */ new Map();
10853
11042
  }
10854
11043
  });
@@ -11023,8 +11212,8 @@ import { Hono as Hono9 } from "hono";
11023
11212
  import { serve } from "@hono/node-server";
11024
11213
  import { cors } from "hono/cors";
11025
11214
  import { logger } from "hono/logger";
11026
- import { existsSync as existsSync20, mkdirSync as mkdirSync9, writeFileSync as writeFileSync5 } from "fs";
11027
- import { resolve as resolve11, dirname as dirname7, join as join15 } from "path";
11215
+ import { existsSync as existsSync21, mkdirSync as mkdirSync10, writeFileSync as writeFileSync6 } from "fs";
11216
+ import { resolve as resolve11, dirname as dirname8, join as join16 } from "path";
11028
11217
  import { spawn as spawn2 } from "child_process";
11029
11218
  import { createServer as createNetServer } from "net";
11030
11219
  import { fileURLToPath as fileURLToPath4 } from "url";
@@ -11038,10 +11227,10 @@ init_checkpoints();
11038
11227
  import { Hono } from "hono";
11039
11228
  import { zValidator } from "@hono/zod-validator";
11040
11229
  import { z as z17 } from "zod";
11041
- import { existsSync as existsSync18, mkdirSync as mkdirSync7, writeFileSync as writeFileSync3, readdirSync as readdirSync3, statSync as statSync2, unlinkSync as unlinkSync3 } from "fs";
11230
+ import { existsSync as existsSync19, mkdirSync as mkdirSync8, writeFileSync as writeFileSync4, readdirSync as readdirSync3, statSync as statSync2, unlinkSync as unlinkSync3 } from "fs";
11042
11231
  import { readdir as readdir6 } from "fs/promises";
11043
- import { join as join12, basename as basename5, extname as extname8, relative as relative9 } from "path";
11044
- import { nanoid as nanoid10 } from "nanoid";
11232
+ import { join as join13, basename as basename5, extname as extname8, relative as relative9 } from "path";
11233
+ import { nanoid as nanoid11 } from "nanoid";
11045
11234
 
11046
11235
  // src/tasks/agent-status.ts
11047
11236
  init_questions();
@@ -11682,12 +11871,12 @@ sessions2.get("/:id/diff/:filePath", async (c) => {
11682
11871
  });
11683
11872
  function getAttachmentsDir(sessionId) {
11684
11873
  const appDataDir = getAppDataDirectory();
11685
- return join12(appDataDir, "attachments", sessionId);
11874
+ return join13(appDataDir, "attachments", sessionId);
11686
11875
  }
11687
11876
  function ensureAttachmentsDir(sessionId) {
11688
11877
  const dir = getAttachmentsDir(sessionId);
11689
- if (!existsSync18(dir)) {
11690
- mkdirSync7(dir, { recursive: true });
11878
+ if (!existsSync19(dir)) {
11879
+ mkdirSync8(dir, { recursive: true });
11691
11880
  }
11692
11881
  return dir;
11693
11882
  }
@@ -11698,12 +11887,12 @@ sessions2.get("/:id/attachments", async (c) => {
11698
11887
  return c.json({ error: "Session not found" }, 404);
11699
11888
  }
11700
11889
  const dir = getAttachmentsDir(sessionId);
11701
- if (!existsSync18(dir)) {
11890
+ if (!existsSync19(dir)) {
11702
11891
  return c.json({ sessionId, attachments: [], count: 0 });
11703
11892
  }
11704
11893
  const files = readdirSync3(dir);
11705
11894
  const attachments = files.map((filename) => {
11706
- const filePath = join12(dir, filename);
11895
+ const filePath = join13(dir, filename);
11707
11896
  const stats = statSync2(filePath);
11708
11897
  return {
11709
11898
  id: filename.split("_")[0],
@@ -11735,12 +11924,12 @@ sessions2.post("/:id/attachments", async (c) => {
11735
11924
  return c.json({ error: "No file provided" }, 400);
11736
11925
  }
11737
11926
  const dir = ensureAttachmentsDir(sessionId);
11738
- const id = nanoid10(10);
11927
+ const id = nanoid11(10);
11739
11928
  const ext = extname8(file.name) || "";
11740
11929
  const safeFilename = `${id}_${basename5(file.name).replace(/[^a-zA-Z0-9._-]/g, "_")}`;
11741
- const filePath = join12(dir, safeFilename);
11930
+ const filePath = join13(dir, safeFilename);
11742
11931
  const arrayBuffer = await file.arrayBuffer();
11743
- writeFileSync3(filePath, Buffer.from(arrayBuffer));
11932
+ writeFileSync4(filePath, Buffer.from(arrayBuffer));
11744
11933
  return c.json({
11745
11934
  id,
11746
11935
  filename: file.name,
@@ -11761,16 +11950,16 @@ sessions2.post("/:id/attachments", async (c) => {
11761
11950
  return c.json({ error: "Missing filename or data" }, 400);
11762
11951
  }
11763
11952
  const dir = ensureAttachmentsDir(sessionId);
11764
- const id = nanoid10(10);
11953
+ const id = nanoid11(10);
11765
11954
  const ext = extname8(body.filename) || "";
11766
11955
  const safeFilename = `${id}_${basename5(body.filename).replace(/[^a-zA-Z0-9._-]/g, "_")}`;
11767
- const filePath = join12(dir, safeFilename);
11956
+ const filePath = join13(dir, safeFilename);
11768
11957
  let base64Data = body.data;
11769
11958
  if (base64Data.includes(",")) {
11770
11959
  base64Data = base64Data.split(",")[1];
11771
11960
  }
11772
11961
  const buffer = Buffer.from(base64Data, "base64");
11773
- writeFileSync3(filePath, buffer);
11962
+ writeFileSync4(filePath, buffer);
11774
11963
  return c.json({
11775
11964
  id,
11776
11965
  filename: body.filename,
@@ -11793,7 +11982,7 @@ sessions2.delete("/:id/attachments/:attachmentId", async (c) => {
11793
11982
  return c.json({ error: "Session not found" }, 404);
11794
11983
  }
11795
11984
  const dir = getAttachmentsDir(sessionId);
11796
- if (!existsSync18(dir)) {
11985
+ if (!existsSync19(dir)) {
11797
11986
  return c.json({ error: "Attachment not found" }, 404);
11798
11987
  }
11799
11988
  const files = readdirSync3(dir);
@@ -11801,7 +11990,7 @@ sessions2.delete("/:id/attachments/:attachmentId", async (c) => {
11801
11990
  if (!file) {
11802
11991
  return c.json({ error: "Attachment not found" }, 404);
11803
11992
  }
11804
- const filePath = join12(dir, file);
11993
+ const filePath = join13(dir, file);
11805
11994
  unlinkSync3(filePath);
11806
11995
  return c.json({ success: true, id: attachmentId });
11807
11996
  });
@@ -11884,7 +12073,7 @@ async function listWorkspaceFiles(baseDir, currentDir, query, limit, results = [
11884
12073
  const entries = await readdir6(currentDir, { withFileTypes: true });
11885
12074
  for (const entry2 of entries) {
11886
12075
  if (results.length >= limit * 2) break;
11887
- const fullPath = join12(currentDir, entry2.name);
12076
+ const fullPath = join13(currentDir, entry2.name);
11888
12077
  const relativePath = relative9(baseDir, fullPath);
11889
12078
  if (entry2.isDirectory() && IGNORED_DIRECTORIES.has(entry2.name)) {
11890
12079
  continue;
@@ -11932,7 +12121,7 @@ sessions2.get(
11932
12121
  return c.json({ error: "Session not found" }, 404);
11933
12122
  }
11934
12123
  const workingDirectory = session.workingDirectory;
11935
- if (!existsSync18(workingDirectory)) {
12124
+ if (!existsSync19(workingDirectory)) {
11936
12125
  return c.json({
11937
12126
  sessionId,
11938
12127
  workingDirectory,
@@ -12046,8 +12235,8 @@ init_config();
12046
12235
  import { Hono as Hono2 } from "hono";
12047
12236
  import { zValidator as zValidator2 } from "@hono/zod-validator";
12048
12237
  import { z as z18 } from "zod";
12049
- import { existsSync as existsSync19, mkdirSync as mkdirSync8, writeFileSync as writeFileSync4 } from "fs";
12050
- import { join as join13 } from "path";
12238
+ import { existsSync as existsSync20, mkdirSync as mkdirSync9, writeFileSync as writeFileSync5 } from "fs";
12239
+ import { join as join14 } from "path";
12051
12240
 
12052
12241
  // src/server/resumable-stream.ts
12053
12242
  import { createResumableStreamContext } from "resumable-stream/generic";
@@ -12134,7 +12323,7 @@ var streamContext = createResumableStreamContext({
12134
12323
 
12135
12324
  // src/server/routes/agents.ts
12136
12325
  init_checkpoints();
12137
- import { nanoid as nanoid11 } from "nanoid";
12326
+ import { nanoid as nanoid12 } from "nanoid";
12138
12327
  init_stream_proxy();
12139
12328
  init_recorder();
12140
12329
  init_remote();
@@ -12254,12 +12443,12 @@ var rejectSchema = z18.object({
12254
12443
  var streamAbortControllers = /* @__PURE__ */ new Map();
12255
12444
  function getAttachmentsDirectory(sessionId) {
12256
12445
  const appDataDir = getAppDataDirectory();
12257
- return join13(appDataDir, "attachments", sessionId);
12446
+ return join14(appDataDir, "attachments", sessionId);
12258
12447
  }
12259
12448
  async function saveAttachmentToDisk(sessionId, attachment, index) {
12260
12449
  const attachmentsDir = getAttachmentsDirectory(sessionId);
12261
- if (!existsSync19(attachmentsDir)) {
12262
- mkdirSync8(attachmentsDir, { recursive: true });
12450
+ if (!existsSync20(attachmentsDir)) {
12451
+ mkdirSync9(attachmentsDir, { recursive: true });
12263
12452
  }
12264
12453
  let filename = attachment.filename;
12265
12454
  if (!filename) {
@@ -12277,8 +12466,8 @@ async function saveAttachmentToDisk(sessionId, attachment, index) {
12277
12466
  attachment.mediaType = resized.mediaType;
12278
12467
  attachment.data = buffer.toString("base64");
12279
12468
  }
12280
- const filePath = join13(attachmentsDir, filename);
12281
- writeFileSync4(filePath, buffer);
12469
+ const filePath = join14(attachmentsDir, filename);
12470
+ writeFileSync5(filePath, buffer);
12282
12471
  return filePath;
12283
12472
  }
12284
12473
  function stripDataUrlPrefix2(data) {
@@ -12714,7 +12903,7 @@ ${prompt}` });
12714
12903
  });
12715
12904
  } catch {
12716
12905
  }
12717
- const streamId = `stream_${id}_${nanoid11(10)}`;
12906
+ const streamId = `stream_${id}_${nanoid12(10)}`;
12718
12907
  console.log(`[STREAM] Creating stream ${streamId} for session ${id}`);
12719
12908
  await activeStreamQueries.create(id, streamId);
12720
12909
  const stream = await streamContext.resumableStream(
@@ -12919,7 +13108,7 @@ agents.post(
12919
13108
  });
12920
13109
  const session = agent.getSession();
12921
13110
  const enrichedPrompt = enrichPromptWithDevtoolsContext(session.id, body.prompt);
12922
- const streamId = `stream_${session.id}_${nanoid11(10)}`;
13111
+ const streamId = `stream_${session.id}_${nanoid12(10)}`;
12923
13112
  await createCheckpoint(session.id, session.workingDirectory, 0);
12924
13113
  await activeStreamQueries.create(session.id, streamId);
12925
13114
  const createQuickStreamProducer = () => {
@@ -13238,26 +13427,26 @@ init_config();
13238
13427
  import { Hono as Hono3 } from "hono";
13239
13428
  import { zValidator as zValidator3 } from "@hono/zod-validator";
13240
13429
  import { z as z19 } from "zod";
13241
- import { readFileSync as readFileSync9 } from "fs";
13430
+ import { readFileSync as readFileSync10 } from "fs";
13242
13431
  import { fileURLToPath as fileURLToPath3 } from "url";
13243
- import { dirname as dirname6, join as join14 } from "path";
13432
+ import { dirname as dirname7, join as join15 } from "path";
13244
13433
  var __filename = fileURLToPath3(import.meta.url);
13245
- var __dirname = dirname6(__filename);
13434
+ var __dirname = dirname7(__filename);
13246
13435
  var possiblePaths = [
13247
- join14(__dirname, "../package.json"),
13436
+ join15(__dirname, "../package.json"),
13248
13437
  // From dist/server -> dist/../package.json
13249
- join14(__dirname, "../../package.json"),
13438
+ join15(__dirname, "../../package.json"),
13250
13439
  // From dist/server (if nested differently)
13251
- join14(__dirname, "../../../package.json"),
13440
+ join15(__dirname, "../../../package.json"),
13252
13441
  // From src/server/routes (development)
13253
- join14(process.cwd(), "package.json")
13442
+ join15(process.cwd(), "package.json")
13254
13443
  // From current working directory
13255
13444
  ];
13256
13445
  var currentVersion = "0.0.0";
13257
13446
  var packageName = "sparkecoder";
13258
13447
  for (const packageJsonPath of possiblePaths) {
13259
13448
  try {
13260
- const packageJson = JSON.parse(readFileSync9(packageJsonPath, "utf-8"));
13449
+ const packageJson = JSON.parse(readFileSync10(packageJsonPath, "utf-8"));
13261
13450
  if (packageJson.name === "sparkecoder") {
13262
13451
  currentVersion = packageJson.version || "0.0.0";
13263
13452
  packageName = packageJson.name || "sparkecoder";
@@ -13707,7 +13896,7 @@ init_config();
13707
13896
  import { Hono as Hono5 } from "hono";
13708
13897
  import { zValidator as zValidator5 } from "@hono/zod-validator";
13709
13898
  import { z as z21 } from "zod";
13710
- import { nanoid as nanoid12 } from "nanoid";
13899
+ import { nanoid as nanoid13 } from "nanoid";
13711
13900
  init_questions();
13712
13901
  var tasks = new Hono5();
13713
13902
  var taskAbortControllers = /* @__PURE__ */ new Map();
@@ -13788,7 +13977,7 @@ tasks.post(
13788
13977
  const taskId = agent.sessionId;
13789
13978
  const abortController = new AbortController();
13790
13979
  taskAbortControllers.set(taskId, abortController);
13791
- const streamId = `stream_${taskId}_${nanoid12(10)}`;
13980
+ const streamId = `stream_${taskId}_${nanoid13(10)}`;
13792
13981
  await activeStreamQueries.create(taskId, streamId);
13793
13982
  const taskStreamProducer = () => {
13794
13983
  const { readable, writable } = new TransformStream();
@@ -14014,6 +14203,7 @@ function verifySlackSignature(opts) {
14014
14203
  // src/server/routes/slack.ts
14015
14204
  init_client3();
14016
14205
  init_slack();
14206
+ init_webhook_events();
14017
14207
  init_inbox();
14018
14208
  var recentlyHandled = /* @__PURE__ */ new Map();
14019
14209
  var MAX_RECENT = 1e3;
@@ -14054,7 +14244,17 @@ slack.post("/events", async (c) => {
14054
14244
  }
14055
14245
  if (payload?.type === "event_callback" && payload?.event) {
14056
14246
  const ev = payload.event;
14247
+ const auditId = recordEvent({
14248
+ source: "slack",
14249
+ status: "received",
14250
+ subtype: ev.type === "message" ? `message.${ev.channel_type ?? "channels"}` : ev.type,
14251
+ channel: ev.channel,
14252
+ user: ev.user,
14253
+ textSnippet: typeof ev.text === "string" ? ev.text : void 0,
14254
+ meta: { ts: ev.ts, thread_ts: ev.thread_ts, team: ev.team, event_subtype: ev.subtype }
14255
+ });
14057
14256
  if (alreadyHandled(ev.channel, ev.ts)) {
14257
+ updateEvent(auditId, { status: "dropped", dropReason: "duplicate_delivery" });
14058
14258
  return c.json({ ok: true });
14059
14259
  }
14060
14260
  const { event: inbound, dropReason } = slackEventToInboundResult(ev);
@@ -14064,6 +14264,7 @@ slack.post("/events", async (c) => {
14064
14264
  const ours = isThreadOwned(ev.channel, ev.thread_ts) || await threadBelongsToUs(ev.channel, ev.thread_ts);
14065
14265
  if (!ours) {
14066
14266
  console.log(`[slack] dropping thread reply in unknown thread: channel=${ev.channel} thread=${ev.thread_ts}`);
14267
+ updateEvent(auditId, { status: "dropped", dropReason: "thread_not_owned" });
14067
14268
  return c.json({ ok: true });
14068
14269
  }
14069
14270
  }
@@ -14076,8 +14277,12 @@ slack.post("/events", async (c) => {
14076
14277
  const orchestratorId = await findOrCreateOrchestratorId();
14077
14278
  if (orchestratorId) {
14078
14279
  pushToInbox(orchestratorId, inbound);
14280
+ updateEvent(auditId, { status: "routed", sessionId: orchestratorId });
14281
+ } else {
14282
+ updateEvent(auditId, { status: "error", error: "no orchestrator session available" });
14079
14283
  }
14080
14284
  } else if (dropReason) {
14285
+ updateEvent(auditId, { status: "dropped", dropReason });
14081
14286
  const userFacingDrops = ["user_not_allowed", "channel_not_allowed", "dm_blocked"];
14082
14287
  if (userFacingDrops.includes(dropReason)) {
14083
14288
  console.log(`[slack] dropped event from user=${payload.event.user} channel=${payload.event.channel}: ${dropReason}`);
@@ -14140,13 +14345,30 @@ async function sendDeniedReply(event) {
14140
14345
  init_webhooks_store();
14141
14346
  init_webhook();
14142
14347
  init_inbox();
14348
+ init_webhook_events();
14143
14349
  import { Hono as Hono7 } from "hono";
14144
14350
  var inbox = new Hono7();
14145
14351
  inbox.post("/:token", async (c) => {
14146
14352
  const token = c.req.param("token");
14147
- if (!token || token.length < 16) return c.json({ error: "invalid token" }, 401);
14353
+ if (!token || token.length < 16) {
14354
+ recordEvent({
14355
+ source: "inbox",
14356
+ status: "dropped",
14357
+ dropReason: "invalid_token_format",
14358
+ meta: { tokenLen: token?.length ?? 0 }
14359
+ });
14360
+ return c.json({ error: "invalid token" }, 401);
14361
+ }
14148
14362
  const lookup = await findByToken(token);
14149
- if (!lookup) return c.json({ error: "unknown token" }, 404);
14363
+ if (!lookup) {
14364
+ recordEvent({
14365
+ source: "inbox",
14366
+ status: "dropped",
14367
+ dropReason: "unknown_token",
14368
+ meta: { tokenPrefix: token.slice(0, 8) + "\u2026" }
14369
+ });
14370
+ return c.json({ error: "unknown token" }, 404);
14371
+ }
14150
14372
  let body;
14151
14373
  const contentType = c.req.header("content-type") || "";
14152
14374
  try {
@@ -14168,6 +14390,14 @@ inbox.post("/:token", async (c) => {
14168
14390
  pushToInbox(lookup.orchestratorSessionId, event);
14169
14391
  void recordHit(lookup.orchestratorSessionId, lookup.webhook.id).catch(() => {
14170
14392
  });
14393
+ recordEvent({
14394
+ source: "inbox",
14395
+ status: "routed",
14396
+ channel: lookup.webhook.name,
14397
+ textSnippet: typeof body === "string" ? body : JSON.stringify(body).slice(0, 200),
14398
+ sessionId: lookup.orchestratorSessionId,
14399
+ meta: { wake: lookup.webhook.wake, webhookId: lookup.webhook.id }
14400
+ });
14171
14401
  return c.json({ ok: true, queued: true, wake: lookup.webhook.wake });
14172
14402
  });
14173
14403
 
@@ -14179,6 +14409,7 @@ init_webhooks_store();
14179
14409
  init_messenger();
14180
14410
  init_store();
14181
14411
  init_pool();
14412
+ init_webhook_events();
14182
14413
  import { Hono as Hono8 } from "hono";
14183
14414
  import { zValidator as zValidator6 } from "@hono/zod-validator";
14184
14415
  import { z as z22 } from "zod";
@@ -14237,6 +14468,24 @@ function webhookPrefix() {
14237
14468
  const token = cfg?.webhooks?.token;
14238
14469
  return token ? `/w/${token}` : "/api";
14239
14470
  }
14471
+ integrations.get("/events", async (c) => {
14472
+ const q = c.req.query();
14473
+ const filter = {
14474
+ source: q.source,
14475
+ status: q.status,
14476
+ q: q.q,
14477
+ since: q.since,
14478
+ before: q.before,
14479
+ limit: q.limit ? Math.min(500, Math.max(1, parseInt(q.limit, 10))) : 50,
14480
+ offset: q.offset ? Math.max(0, parseInt(q.offset, 10)) : 0
14481
+ };
14482
+ const { events, total } = listEvents(filter);
14483
+ return c.json({ events, total, limit: filter.limit, offset: filter.offset });
14484
+ });
14485
+ integrations.delete("/events", async (c) => {
14486
+ clearAllEvents();
14487
+ return c.json({ ok: true });
14488
+ });
14240
14489
  integrations.get("/", async (c) => {
14241
14490
  const cfg = getConfig();
14242
14491
  return c.json({
@@ -14599,13 +14848,13 @@ var DEFAULT_WEB_PORT = 6969;
14599
14848
  var WEB_PORT_SEQUENCE = [6969, 6970, 6971, 6972, 6973, 6974, 6975, 6976, 6977, 6978];
14600
14849
  function getWebDirectory() {
14601
14850
  try {
14602
- const currentDir = dirname7(fileURLToPath4(import.meta.url));
14851
+ const currentDir = dirname8(fileURLToPath4(import.meta.url));
14603
14852
  const webDir = resolve11(currentDir, "..", "web");
14604
- if (existsSync20(webDir) && existsSync20(join15(webDir, "package.json"))) {
14853
+ if (existsSync21(webDir) && existsSync21(join16(webDir, "package.json"))) {
14605
14854
  return webDir;
14606
14855
  }
14607
14856
  const altWebDir = resolve11(currentDir, "..", "..", "web");
14608
- if (existsSync20(altWebDir) && existsSync20(join15(altWebDir, "package.json"))) {
14857
+ if (existsSync21(altWebDir) && existsSync21(join16(altWebDir, "package.json"))) {
14609
14858
  return altWebDir;
14610
14859
  }
14611
14860
  return null;
@@ -14663,23 +14912,23 @@ async function findWebPort(preferredPort) {
14663
14912
  return { port: preferredPort, alreadyRunning: false };
14664
14913
  }
14665
14914
  function hasProductionBuild(webDir) {
14666
- const buildIdPath = join15(webDir, ".next", "BUILD_ID");
14667
- return existsSync20(buildIdPath);
14915
+ const buildIdPath = join16(webDir, ".next", "BUILD_ID");
14916
+ return existsSync21(buildIdPath);
14668
14917
  }
14669
14918
  function hasSourceFiles(webDir) {
14670
- const appDir = join15(webDir, "src", "app");
14671
- const pagesDir = join15(webDir, "src", "pages");
14672
- const rootAppDir = join15(webDir, "app");
14673
- const rootPagesDir = join15(webDir, "pages");
14674
- return existsSync20(appDir) || existsSync20(pagesDir) || existsSync20(rootAppDir) || existsSync20(rootPagesDir);
14919
+ const appDir = join16(webDir, "src", "app");
14920
+ const pagesDir = join16(webDir, "src", "pages");
14921
+ const rootAppDir = join16(webDir, "app");
14922
+ const rootPagesDir = join16(webDir, "pages");
14923
+ return existsSync21(appDir) || existsSync21(pagesDir) || existsSync21(rootAppDir) || existsSync21(rootPagesDir);
14675
14924
  }
14676
14925
  function getStandaloneServerPath(webDir) {
14677
14926
  const possiblePaths2 = [
14678
- join15(webDir, ".next", "standalone", "server.js"),
14679
- join15(webDir, ".next", "standalone", "web", "server.js")
14927
+ join16(webDir, ".next", "standalone", "server.js"),
14928
+ join16(webDir, ".next", "standalone", "web", "server.js")
14680
14929
  ];
14681
14930
  for (const serverPath of possiblePaths2) {
14682
- if (existsSync20(serverPath)) {
14931
+ if (existsSync21(serverPath)) {
14683
14932
  return serverPath;
14684
14933
  }
14685
14934
  }
@@ -14719,15 +14968,15 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
14719
14968
  if (!quiet) console.log(` \u2713 Web UI already running at http://localhost:${actualPort}`);
14720
14969
  return { process: null, port: actualPort };
14721
14970
  }
14722
- const usePnpm = existsSync20(join15(webDir, "pnpm-lock.yaml"));
14723
- const useNpm = !usePnpm && existsSync20(join15(webDir, "package-lock.json"));
14971
+ const usePnpm = existsSync21(join16(webDir, "pnpm-lock.yaml"));
14972
+ const useNpm = !usePnpm && existsSync21(join16(webDir, "package-lock.json"));
14724
14973
  const pkgManager = usePnpm ? "pnpm" : useNpm ? "npm" : "npx";
14725
14974
  const { NODE_OPTIONS, TSX_TSCONFIG_PATH, ...cleanEnv } = process.env;
14726
14975
  const apiUrl = publicUrl || `http://127.0.0.1:${apiPort}`;
14727
14976
  const runtimeConfig = { apiBaseUrl: apiUrl };
14728
- const runtimeConfigPath = join15(webDir, "runtime-config.json");
14977
+ const runtimeConfigPath = join16(webDir, "runtime-config.json");
14729
14978
  try {
14730
- writeFileSync5(runtimeConfigPath, JSON.stringify(runtimeConfig, null, 2));
14979
+ writeFileSync6(runtimeConfigPath, JSON.stringify(runtimeConfig, null, 2));
14731
14980
  if (!quiet) console.log(` \u{1F4DD} Runtime config written to ${runtimeConfigPath}`);
14732
14981
  } catch (err) {
14733
14982
  if (!quiet) console.warn(` \u26A0 Could not write runtime config: ${err}`);
@@ -14747,7 +14996,7 @@ async function startWebUI(apiPort, webPort = DEFAULT_WEB_PORT, quiet = false, pu
14747
14996
  if (standaloneServerPath) {
14748
14997
  command = "node";
14749
14998
  args = ["server.js"];
14750
- cwd = dirname7(standaloneServerPath);
14999
+ cwd = dirname8(standaloneServerPath);
14751
15000
  webEnv.PORT = String(actualPort);
14752
15001
  webEnv.HOSTNAME = "0.0.0.0";
14753
15002
  if (!quiet) console.log(" \u{1F4E6} Starting Web UI from standalone build...");
@@ -14940,8 +15189,8 @@ async function startServer(options = {}) {
14940
15189
  if (options.workingDirectory) {
14941
15190
  config.resolvedWorkingDirectory = options.workingDirectory;
14942
15191
  }
14943
- if (!existsSync20(config.resolvedWorkingDirectory)) {
14944
- mkdirSync9(config.resolvedWorkingDirectory, { recursive: true });
15192
+ if (!existsSync21(config.resolvedWorkingDirectory)) {
15193
+ mkdirSync10(config.resolvedWorkingDirectory, { recursive: true });
14945
15194
  if (!options.quiet) console.log(`\u{1F4C1} Created agent workspace: ${config.resolvedWorkingDirectory}`);
14946
15195
  }
14947
15196
  if (!config.resolvedRemoteServer.url) {