@heylemon/lemonade 0.2.8 → 0.3.0

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.
@@ -0,0 +1,94 @@
1
+ #!/bin/bash
2
+ # Lemon Composio CLI - Discover and execute any Composio tool dynamically
3
+ # Resolve symlinks to find the real script directory
4
+ SCRIPT_PATH="$0"
5
+ while [[ -L "$SCRIPT_PATH" ]]; do
6
+ SCRIPT_DIR="$(cd -P "$(dirname "$SCRIPT_PATH")" && pwd)"
7
+ SCRIPT_PATH="$(readlink "$SCRIPT_PATH")"
8
+ [[ "$SCRIPT_PATH" != /* ]] && SCRIPT_PATH="$SCRIPT_DIR/$SCRIPT_PATH"
9
+ done
10
+ SCRIPT_DIR="$(cd -P "$(dirname "$SCRIPT_PATH")" && pwd)"
11
+ source "$SCRIPT_DIR/lemon-cli-header.sh"
12
+
13
+ case "$1" in
14
+ search)
15
+ # Search for tools by natural language query
16
+ # Usage: lemon-composio search "create jira ticket"
17
+ # Usage: lemon-composio search "post to linkedin" --toolkit=linkedin
18
+ [[ -z "$2" ]] && echo "Usage: lemon-composio search <query> [--toolkit=<name>] [--limit=<n>]" && exit 1
19
+
20
+ query="$2"
21
+ toolkit=""
22
+ limit="15"
23
+
24
+ for arg in "${@:3}"; do
25
+ case "$arg" in
26
+ --toolkit=*) toolkit="${arg#*=}" ;;
27
+ --limit=*) limit="${arg#*=}" ;;
28
+ esac
29
+ done
30
+
31
+ params="query=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$query'))")&limit=$limit"
32
+ [[ -n "$toolkit" ]] && params="$params&toolkit=$toolkit"
33
+
34
+ api_call GET "/api/lemonade/tools/search?$params"
35
+ ;;
36
+
37
+ execute)
38
+ # Execute any Composio tool by slug
39
+ # Usage: lemon-composio execute TOOL_SLUG '{"param": "value"}'
40
+ [[ -z "$2" ]] && echo "Usage: lemon-composio execute <TOOL_SLUG> [json_parameters]" && exit 1
41
+
42
+ tool_slug="$2"
43
+ params="${3:-{\}}"
44
+
45
+ # Build the request body
46
+ EXEC_JSON=$(jq -n \
47
+ --arg toolName "$tool_slug" \
48
+ --argjson parameters "$params" \
49
+ '{toolName: $toolName, parameters: $parameters}')
50
+
51
+ echo "$EXEC_JSON" | curl -s -X POST \
52
+ -H "Authorization: Bearer ${GATEWAY_TOKEN}" \
53
+ -H "Content-Type: application/json" \
54
+ -d @- \
55
+ "${BACKEND_URL}/api/lemonade/tools/execute"
56
+ ;;
57
+
58
+ status)
59
+ # Show which integrations the user has connected
60
+ api_call GET "/api/lemonade/tools/status"
61
+ ;;
62
+
63
+ help|--help|-h|"")
64
+ cat <<EOF
65
+ lemon-composio - Discover and use any Composio integration tool
66
+
67
+ Commands:
68
+ search <query> [--toolkit=<name>] [--limit=<n>]
69
+ Search for tools across all Composio integrations.
70
+ Examples:
71
+ lemon-composio search "create jira ticket"
72
+ lemon-composio search "post to linkedin"
73
+ lemon-composio search "issues" --toolkit=github
74
+
75
+ execute <TOOL_SLUG> [json_parameters]
76
+ Execute a Composio tool by its slug.
77
+ Examples:
78
+ lemon-composio execute JIRA_CREATE_ISSUE '{"summary":"Bug fix","project_key":"PROJ"}'
79
+ lemon-composio execute LINKEDIN_CREATE_POST '{"text":"Hello world!"}'
80
+
81
+ status
82
+ Show which integrations the user has connected.
83
+
84
+ If a tool requires an integration the user hasn't connected yet,
85
+ the search results will include a connectUrl to initiate OAuth.
86
+ EOF
87
+ ;;
88
+
89
+ *)
90
+ echo "Unknown command: $1" >&2
91
+ echo "Run 'lemon-composio help' for usage." >&2
92
+ exit 1
93
+ ;;
94
+ esac
@@ -5,7 +5,7 @@ import { installSessionToolResultGuard } from "./session-tool-result-guard.js";
5
5
  * it is truncated in the persisted session transcript. Prevents bloated
6
6
  * transcripts from large exec outputs, API responses, etc.
7
7
  */
8
- const TOOL_RESULT_MAX_CHARS = 8_000;
8
+ const TOOL_RESULT_MAX_CHARS = 30_000;
9
9
  /**
10
10
  * Truncate oversized text blocks inside a tool-result message so that
11
11
  * session transcripts stay lean and context windows are not wasted.
@@ -134,6 +134,7 @@ function buildConfirmationSection(isMinimal) {
134
134
  "2. ALWAYS attach files when the task involves creating AND sending a file.",
135
135
  "3. To send email with an attachment use: `lemon-gmail send <to> <subject> <body> <file_path>`. BEFORE sending, ALWAYS verify the file exists at the path with `ls <file_path>`. If the file was created earlier, confirm it still exists — files in /tmp may be cleaned up.",
136
136
  "4. ALWAYS confirm the recipient email and attachment list BEFORE sending.",
137
+ "5. When user asks to READ email content ('what's in my emails', 'read my top 5', 'show me my emails', etc.): first `lemon-gmail list <count>` to get message IDs, then `lemon-gmail read <message_id>` for EACH email. Show the full content — not just subject lines. The 'short and scannable' rule only applies to automated morning recaps, not direct user requests.",
137
138
  "",
138
139
  ];
139
140
  }
@@ -339,14 +340,16 @@ export function buildAgentSystemPrompt(params) {
339
340
  "If the user asks you to do something (take a screenshot, send a file, etc.), just do it — pick the best approach and act.",
340
341
  "Never reply with a list of approaches/options when a single tool call would suffice.",
341
342
  "For screenshots of native macOS windows: use Peekaboo (`peekaboo image`) via exec if the skill is available.",
343
+ 'When the user mentions ANY third-party app or service (Jira, GitHub, LinkedIn, HubSpot, Trello, Asana, Salesforce, Todoist, etc.) and you don\'t have a dedicated `lemon-*` CLI for it, immediately search Composio: `lemon-composio search "<task>"`. Don\'t say "I can\'t do that" — search first.',
342
344
  "",
343
345
  "## URLs & Quick Open",
344
346
  "",
345
347
  "### Decision tree",
346
- "1. Service has a `lemon-*` CLI tool (Gmail, Calendar, Drive, Docs, Sheets, Slides, Notion, Slack, YouTube) → **always use the CLI tool**. Never open these in a browser or via URI.",
347
- "2. User wants an *answer* from the webuse `web_search` (+ `web_fetch` if needed).",
348
- "3. User wants to *interact* with a page (fill forms, click buttons, scrape data) → use Lemonade's dedicated `browser` tool.",
349
- "4. User wants to *view* a general website (no CLI tool exists) → use Lemonade's dedicated `browser` tool to navigate there.",
348
+ "1. Service has a dedicated `lemon-*` CLI tool (Gmail, Calendar, Drive, Docs, Sheets, Slides, Notion, Slack, YouTube) → **always use the CLI tool**. Never open these in a browser or via URI.",
349
+ '2. Service is a known app/platform (Jira, GitHub, LinkedIn, HubSpot, Trello, Asana, Salesforce, etc.) but has NO dedicated CLI **search Composio**: `lemon-composio search "<task>"`. This discovers tools across 1000+ integrations. If found, execute with `lemon-composio execute`.',
350
+ "3. User wants an *answer* from the web → use `web_search` (+ `web_fetch` if needed).",
351
+ "4. User wants to *interact* with a page (fill forms, click buttons, scrape data) → use Lemonade's dedicated `browser` tool.",
352
+ "5. User wants to *view* a general website (no CLI or Composio tool exists) → use Lemonade's dedicated `browser` tool to navigate there.",
350
353
  "",
351
354
  "### Integration CLI tools (always preferred)",
352
355
  "For connected services, use the CLI — it's faster, already authenticated, and doesn't require a browser:",
@@ -364,6 +367,18 @@ export function buildAgentSystemPrompt(params) {
364
367
  "**Never open** `mail.google.com`, `calendar.google.com`, `drive.google.com`, `docs.google.com`, `sheets.google.com`, `slides.google.com`, `notion.so`, `app.slack.com`, or `youtube.com` in any browser. Use the CLI.",
365
368
  '**Creating documents:** Use `lemon-docs create "Title"`, `lemon-sheets create "Title"`, etc. Do NOT open `docs.new`, `sheets.new`, or any `.new` domain.',
366
369
  "",
370
+ "### Dynamic tool discovery (for services without a dedicated CLI)",
371
+ "If the user asks for a service that doesn't have a dedicated `lemon-*` CLI above (e.g. Jira, LinkedIn, GitHub, HubSpot, Trello, Asana, etc.), use `lemon-composio` to discover and execute tools dynamically:",
372
+ '1. **Search**: `lemon-composio search "<what the user wants>"` — finds matching tools across 1000+ apps',
373
+ "2. **Check connection**: The search results show `connected: true/false` for each tool. If not connected, the result includes a `connectUrl`.",
374
+ "3. **Connect if needed**: If the tool requires a connection the user doesn't have, tell them to connect and provide the `connectUrl` (e.g. `lemon://connect?provider=jira`). Wait for them to connect before executing.",
375
+ '4. **Execute**: `lemon-composio execute <TOOL_SLUG> \'{"param": "value"}\'` — runs any Composio tool.',
376
+ "Example flow:",
377
+ '- User: "create a Jira ticket for the login bug"',
378
+ '- You: `lemon-composio search "create jira ticket"` → finds `JIRA_CREATE_ISSUE` (connected: false)',
379
+ "- You: Tell the user to connect Jira and provide the connect link",
380
+ '- After connected: `lemon-composio execute JIRA_CREATE_ISSUE \'{"summary":"Fix login bug","project_key":"PROJ"}\'`',
381
+ "",
367
382
  "### Browser tool (Lemonade's dedicated browser only)",
368
383
  "For general websites without a CLI tool, use Lemonade's dedicated `browser` tool (Playwright-managed).",
369
384
  '**Never open URLs in the user\'s personal browser.** Do not use `exec open "URL"`, `open -a "Google Chrome"`, or AppleScript to launch URLs. All web browsing goes through the `browser` tool with `profile="lemonade"`.',
@@ -385,12 +400,28 @@ export function buildAgentSystemPrompt(params) {
385
400
  "| LinkedIn search | `https://linkedin.com/search/results/all/?keywords={query}` |",
386
401
  "URL-encode the query (`%20` for spaces or use `+`).",
387
402
  "",
403
+ "### Quick-create shortcuts (.new domains)",
404
+ "Use these via the `browser` tool (browser_navigate) to instantly create a new resource in Lemonade's dedicated browser:",
405
+ "| Task | URL |",
406
+ "|------|-----|",
407
+ "| New Google Meet | `https://meet.new` |",
408
+ "| New Google Form | `https://forms.new` |",
409
+ "| New Google Drawing | `https://drawings.new` |",
410
+ "| New Google Site | `https://sites.new` |",
411
+ "| New GitHub repo | `https://repo.new` |",
412
+ "| New GitHub gist | `https://gist.new` |",
413
+ "| New CodePen | `https://pen.new` |",
414
+ "| New Figma file | `https://figma.new` |",
415
+ "| New Linear issue | `https://linear.new` |",
416
+ "For Google Docs, Sheets, and Slides — use the CLI instead: `lemon-docs create`, `lemon-sheets create`, etc.",
417
+ "",
388
418
  "### Examples",
389
419
  '- "search YouTube for funny cats" → `lemon-youtube search "funny cats"` (CLI, not browser)',
390
420
  '- "show me flights to Tokyo" → `browser` navigate to `https://google.com/travel/flights?q=flights+to+tokyo`',
391
421
  '- "open amazon" → `browser` navigate to `https://amazon.com`',
392
422
  '- "find Italian restaurants near me" → `browser` navigate to `https://maps.google.com/maps?q=italian+restaurants+near+me`',
393
423
  '- "create a new doc" → `lemon-docs create "Untitled"` (CLI, not browser)',
424
+ '- "start a Google Meet" → `browser` navigate to `https://meet.new`',
394
425
  '- "check my email" → `lemon-gmail list` (CLI, not browser)',
395
426
  '- "what is the capital of France?" → use `web_search` (user wants the answer, not a page)',
396
427
  "",
@@ -416,7 +447,7 @@ export function buildAgentSystemPrompt(params) {
416
447
  "On the first heartbeat after 7 AM each day, deliver a combined morning recap:",
417
448
  "- **Gmail connected** → important unread, awaiting replies, deadlines (skip promotions/social/forums)",
418
449
  "- **Calendar connected** → today's meetings, free time, tomorrow's early events",
419
- "Deliver to whichever channel the user is active on. Keep it short and scannable.",
450
+ "Deliver to whichever channel the user is active on. Keep the recap short and scannable (this brevity rule applies ONLY to automated recaps, not to direct user requests for email content).",
420
451
  "If user asks to adjust timing, content, or frequency — update HEARTBEAT.md and note their preference.",
421
452
  "",
422
453
  "## Code Execution",
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.2.8",
3
- "commit": "6c4da878a64650fe76bb87fe50bb3f927e0803e4",
4
- "builtAt": "2026-02-23T03:21:34.505Z"
2
+ "version": "0.3.0",
3
+ "commit": "4f49b2640ae7f3fde2d49573462df3016e1a0144",
4
+ "builtAt": "2026-02-23T05:27:42.438Z"
5
5
  }
@@ -1 +1 @@
1
- 623501c2b7c89888f7ad88c7e32239e05753751e4d9b227608e441ee9bc813ca
1
+ 82f9b5532f4301693e11fdda8db2d4eb0004c945c68b5393f9dd6a4899c2ec47
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heylemon/lemonade",
3
- "version": "0.2.8",
3
+ "version": "0.3.0",
4
4
  "description": "AI gateway CLI for Lemon - local AI assistant with integrations",
5
5
  "publishConfig": {
6
6
  "access": "restricted"
@@ -26,7 +26,8 @@
26
26
  "lemon-youtube": "./bin/lemon-youtube",
27
27
  "lemon-cron": "./bin/lemon-cron",
28
28
  "lemon-jira": "./bin/lemon-jira",
29
- "lemon-twitter": "./bin/lemon-twitter"
29
+ "lemon-twitter": "./bin/lemon-twitter",
30
+ "lemon-composio": "./bin/lemon-composio"
30
31
  },
31
32
  "files": [
32
33
  "bin/**",
@@ -86,10 +86,19 @@ This should be created automatically when Gmail is connected. Default: every wee
86
86
  }
87
87
  ```
88
88
 
89
- ## Rules
89
+ ## Rules (for automated daily recaps ONLY)
90
+
91
+ These rules apply ONLY to the automated daily recap cron job above. They do NOT apply when the user directly asks to read, show, or check their emails.
90
92
 
91
93
  - Skip promotional, social, updates, and forum categories — only surface real emails
92
94
  - Keep the recap under 10 items total — if more, summarize and mention the count
93
95
  - Don't include full email bodies — just sender, subject, and a one-line preview
94
96
  - "Awaiting reply" only flags emails sent in the last 3–7 days, not ancient threads
95
97
  - If inbox is clean, just say "All caught up!" — don't pad with filler
98
+
99
+ ## When the user asks to read emails directly
100
+
101
+ When the user asks "what's in my emails", "read my emails", "show me my top N emails", etc., this is NOT a recap. Give them the actual content:
102
+ 1. `lemon-gmail list <count>` to get message IDs
103
+ 2. `lemon-gmail read <message_id>` for each email to fetch full content
104
+ 3. Present the full email content (or a thorough summary) — do NOT limit to subject lines and one-line previews