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.
- package/dist/agent/index.d.ts +3 -3
- package/dist/agent/index.js +62 -0
- package/dist/agent/index.js.map +1 -1
- package/dist/cli.js +387 -108
- package/dist/cli.js.map +1 -1
- package/dist/db/index.d.ts +2 -2
- package/dist/{index-Biy5JTop.d.ts → index-Bi8Ek02A.d.ts} +104 -104
- package/dist/index.d.ts +5 -5
- package/dist/index.js +313 -64
- package/dist/index.js.map +1 -1
- package/dist/{schema-CYSKJZ3m.d.ts → schema-ecQSnCMz.d.ts} +3 -3
- package/dist/{search-CVVfuBPZ.d.ts → search-DOzC4ojH.d.ts} +4 -4
- package/dist/server/index.js +313 -64
- package/dist/server/index.js.map +1 -1
- package/dist/skills/default/computer-use.md +7 -0
- package/dist/skills/default/recording.md +5 -0
- package/dist/tools/index.d.ts +3 -3
- package/package.json +1 -1
- package/src/skills/default/computer-use.md +7 -0
- package/src/skills/default/recording.md +5 -0
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/standalone/web/.next/BUILD_ID +1 -1
- package/web/.next/standalone/web/.next/build-manifest.json +2 -2
- package/web/.next/standalone/web/.next/prerender-manifest.json +3 -3
- package/web/.next/standalone/web/.next/server/app/(main)/agents/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/(main)/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page.js.nft.json +1 -1
- package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/(main)/settings/page.js.nft.json +1 -1
- package/web/.next/standalone/web/.next/server/app/(main)/settings/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/agents.html +1 -1
- package/web/.next/standalone/web/.next/server/app/agents.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/agents.segments/_full.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/agents.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/agents.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/agents.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.html +1 -1
- package/web/.next/standalone/web/.next/server/app/index.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/settings.html +1 -1
- package/web/.next/standalone/web/.next/server/app/settings.rsc +3 -3
- package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings/__PAGE__.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/settings.segments/_full.segment.rsc +3 -3
- package/web/.next/standalone/web/.next/server/app/settings.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/settings.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/chunks/ssr/2374f_lucide-react_dist_esm_icons_7340c8b3._.js +3 -0
- package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__f3e6443f._.js +15 -0
- package/web/.next/standalone/web/.next/server/chunks/ssr/web_41927ef5._.js +3 -0
- package/web/.next/standalone/web/.next/server/chunks/ssr/web_src_app_(main)_settings_page_tsx_eb320e07._.js +1 -1
- package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
- package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
- package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
- package/web/.next/standalone/web/.next/static/chunks/2c3c1d478808e4e4.js +1 -0
- package/web/.next/standalone/web/.next/static/chunks/3b0501ec3249235f.js +7 -0
- package/web/.next/standalone/web/.next/static/chunks/44c575e006ddb992.js +13 -0
- package/web/.next/standalone/web/.next/static/chunks/9a3afb48c245fb2a.js +1 -0
- package/web/.next/standalone/web/.next/static/chunks/b3bc7244f3477729.css +1 -0
- package/web/.next/standalone/web/.next/static/static/chunks/2c3c1d478808e4e4.js +1 -0
- package/web/.next/standalone/web/.next/static/static/chunks/3b0501ec3249235f.js +7 -0
- package/web/.next/standalone/web/.next/static/static/chunks/44c575e006ddb992.js +13 -0
- package/web/.next/standalone/web/.next/static/static/chunks/9a3afb48c245fb2a.js +1 -0
- package/web/.next/standalone/web/.next/static/static/chunks/b3bc7244f3477729.css +1 -0
- package/web/.next/standalone/web/src/app/(main)/settings/page.tsx +255 -3
- package/web/.next/static/chunks/2c3c1d478808e4e4.js +1 -0
- package/web/.next/static/chunks/3b0501ec3249235f.js +7 -0
- package/web/.next/static/chunks/44c575e006ddb992.js +13 -0
- package/web/.next/static/chunks/9a3afb48c245fb2a.js +1 -0
- package/web/.next/static/chunks/b3bc7244f3477729.css +1 -0
- package/web/.next/standalone/web/.next/server/chunks/ssr/2374f_lucide-react_dist_esm_icons_50c2f239._.js +0 -3
- package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__6097da17._.js +0 -15
- package/web/.next/standalone/web/.next/server/chunks/ssr/web_3b9a2423._.js +0 -3
- package/web/.next/standalone/web/.next/static/chunks/60359bdd369c0c72.js +0 -1
- package/web/.next/standalone/web/.next/static/chunks/a189cacf6d83cf0b.js +0 -13
- package/web/.next/standalone/web/.next/static/chunks/bef6931fdd8428c8.js +0 -1
- package/web/.next/standalone/web/.next/static/chunks/c1f73b3fa4353c31.css +0 -1
- package/web/.next/standalone/web/.next/static/chunks/fbdcbd65f9a38f4b.js +0 -7
- package/web/.next/standalone/web/.next/static/static/chunks/60359bdd369c0c72.js +0 -1
- package/web/.next/standalone/web/.next/static/static/chunks/a189cacf6d83cf0b.js +0 -13
- package/web/.next/standalone/web/.next/static/static/chunks/bef6931fdd8428c8.js +0 -1
- package/web/.next/standalone/web/.next/static/static/chunks/c1f73b3fa4353c31.css +0 -1
- package/web/.next/standalone/web/.next/static/static/chunks/fbdcbd65f9a38f4b.js +0 -7
- package/web/.next/static/chunks/60359bdd369c0c72.js +0 -1
- package/web/.next/static/chunks/a189cacf6d83cf0b.js +0 -13
- package/web/.next/static/chunks/bef6931fdd8428c8.js +0 -1
- package/web/.next/static/chunks/c1f73b3fa4353c31.css +0 -1
- package/web/.next/static/chunks/fbdcbd65f9a38f4b.js +0 -7
- /package/web/.next/standalone/web/.next/static/{pSGgtxBjN5_o0YHZgQzXm → static/vLqK4jK7EKdLCpQ-D6-qL}/_buildManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{pSGgtxBjN5_o0YHZgQzXm → static/vLqK4jK7EKdLCpQ-D6-qL}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/web/.next/static/{pSGgtxBjN5_o0YHZgQzXm → static/vLqK4jK7EKdLCpQ-D6-qL}/_ssgManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{static/pSGgtxBjN5_o0YHZgQzXm → vLqK4jK7EKdLCpQ-D6-qL}/_buildManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{static/pSGgtxBjN5_o0YHZgQzXm → vLqK4jK7EKdLCpQ-D6-qL}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/web/.next/static/{static/pSGgtxBjN5_o0YHZgQzXm → vLqK4jK7EKdLCpQ-D6-qL}/_ssgManifest.js +0 -0
- /package/web/.next/static/{pSGgtxBjN5_o0YHZgQzXm → vLqK4jK7EKdLCpQ-D6-qL}/_buildManifest.js +0 -0
- /package/web/.next/static/{pSGgtxBjN5_o0YHZgQzXm → vLqK4jK7EKdLCpQ-D6-qL}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{pSGgtxBjN5_o0YHZgQzXm → vLqK4jK7EKdLCpQ-D6-qL}/_ssgManifest.js +0 -0
package/dist/server/index.js
CHANGED
|
@@ -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:
|
|
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 :
|
|
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
|
|
11027
|
-
import { resolve as resolve11, dirname as
|
|
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
|
|
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
|
|
11044
|
-
import { nanoid as
|
|
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
|
|
11874
|
+
return join13(appDataDir, "attachments", sessionId);
|
|
11686
11875
|
}
|
|
11687
11876
|
function ensureAttachmentsDir(sessionId) {
|
|
11688
11877
|
const dir = getAttachmentsDir(sessionId);
|
|
11689
|
-
if (!
|
|
11690
|
-
|
|
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 (!
|
|
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 =
|
|
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 =
|
|
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 =
|
|
11930
|
+
const filePath = join13(dir, safeFilename);
|
|
11742
11931
|
const arrayBuffer = await file.arrayBuffer();
|
|
11743
|
-
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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 (!
|
|
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 =
|
|
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 =
|
|
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 (!
|
|
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
|
|
12050
|
-
import { join as
|
|
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
|
|
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
|
|
12446
|
+
return join14(appDataDir, "attachments", sessionId);
|
|
12258
12447
|
}
|
|
12259
12448
|
async function saveAttachmentToDisk(sessionId, attachment, index) {
|
|
12260
12449
|
const attachmentsDir = getAttachmentsDirectory(sessionId);
|
|
12261
|
-
if (!
|
|
12262
|
-
|
|
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 =
|
|
12281
|
-
|
|
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}_${
|
|
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}_${
|
|
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
|
|
13430
|
+
import { readFileSync as readFileSync10 } from "fs";
|
|
13242
13431
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
13243
|
-
import { dirname as
|
|
13432
|
+
import { dirname as dirname7, join as join15 } from "path";
|
|
13244
13433
|
var __filename = fileURLToPath3(import.meta.url);
|
|
13245
|
-
var __dirname =
|
|
13434
|
+
var __dirname = dirname7(__filename);
|
|
13246
13435
|
var possiblePaths = [
|
|
13247
|
-
|
|
13436
|
+
join15(__dirname, "../package.json"),
|
|
13248
13437
|
// From dist/server -> dist/../package.json
|
|
13249
|
-
|
|
13438
|
+
join15(__dirname, "../../package.json"),
|
|
13250
13439
|
// From dist/server (if nested differently)
|
|
13251
|
-
|
|
13440
|
+
join15(__dirname, "../../../package.json"),
|
|
13252
13441
|
// From src/server/routes (development)
|
|
13253
|
-
|
|
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(
|
|
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
|
|
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}_${
|
|
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)
|
|
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)
|
|
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 =
|
|
14851
|
+
const currentDir = dirname8(fileURLToPath4(import.meta.url));
|
|
14603
14852
|
const webDir = resolve11(currentDir, "..", "web");
|
|
14604
|
-
if (
|
|
14853
|
+
if (existsSync21(webDir) && existsSync21(join16(webDir, "package.json"))) {
|
|
14605
14854
|
return webDir;
|
|
14606
14855
|
}
|
|
14607
14856
|
const altWebDir = resolve11(currentDir, "..", "..", "web");
|
|
14608
|
-
if (
|
|
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 =
|
|
14667
|
-
return
|
|
14915
|
+
const buildIdPath = join16(webDir, ".next", "BUILD_ID");
|
|
14916
|
+
return existsSync21(buildIdPath);
|
|
14668
14917
|
}
|
|
14669
14918
|
function hasSourceFiles(webDir) {
|
|
14670
|
-
const appDir =
|
|
14671
|
-
const pagesDir =
|
|
14672
|
-
const rootAppDir =
|
|
14673
|
-
const rootPagesDir =
|
|
14674
|
-
return
|
|
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
|
-
|
|
14679
|
-
|
|
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 (
|
|
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 =
|
|
14723
|
-
const useNpm = !usePnpm &&
|
|
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 =
|
|
14977
|
+
const runtimeConfigPath = join16(webDir, "runtime-config.json");
|
|
14729
14978
|
try {
|
|
14730
|
-
|
|
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 =
|
|
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 (!
|
|
14944
|
-
|
|
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) {
|