@heylemon/lemonade 0.0.8 → 0.0.9

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.
@@ -43,6 +43,12 @@ if [[ -z "$LEMON_BACKEND_URL" ]]; then
43
43
  fi
44
44
  BACKEND_URL="$LEMON_BACKEND_URL"
45
45
 
46
+ if [[ -z "$GATEWAY_TOKEN" ]]; then
47
+ echo -e "${RED}Error:${NC} GATEWAY_TOKEN not set." >&2
48
+ echo "Please ensure ~/.lemonade/.env contains GATEWAY_TOKEN or set it in your environment." >&2
49
+ exit 1
50
+ fi
51
+
46
52
  # Local gateway URL (for health checks)
47
53
  GATEWAY_URL="${LEMONADE_GATEWAY_URL:-http://127.0.0.1:19847}"
48
54
 
package/bin/lemon-docs CHANGED
@@ -20,16 +20,26 @@ case "$1" in
20
20
  CONTENT="${3:-}"
21
21
 
22
22
  # Create the document
23
- RESULT=$(api_call POST "/api/lemonade/tools/execute" \
24
- '{"toolName": "GOOGLEDOCS_CREATE_DOCUMENT_MARKDOWN", "parameters": {"title": "'"$TITLE"'"}}')
23
+ CREATE_JSON=$(jq -n --arg title "$TITLE" \
24
+ '{toolName: "GOOGLEDOCS_CREATE_DOCUMENT_MARKDOWN", parameters: {title: $title}}')
25
+ RESULT=$(echo "$CREATE_JSON" | curl -s -X POST \
26
+ -H "Authorization: Bearer ${GATEWAY_TOKEN}" \
27
+ -H "Content-Type: application/json" \
28
+ -d @- \
29
+ "${LEMON_BACKEND_URL}/api/lemonade/tools/execute")
25
30
 
26
31
  # Extract document ID from result
27
32
  DOC_ID=$(echo "$RESULT" | jq -r '.result.documentId // .documentId // .id // .data.documentId // .data.id // empty' 2>/dev/null)
28
33
 
29
34
  # If content provided and we got a doc ID, append the content
30
35
  if [[ -n "$CONTENT" ]] && [[ -n "$DOC_ID" ]]; then
31
- api_call POST "/api/lemonade/tools/execute" \
32
- '{"toolName": "GOOGLEDOCS_INSERT_TEXT_ACTION", "parameters": {"document_id": "'"$DOC_ID"'", "text_to_insert": "'"$CONTENT"'", "append_to_end": true}}'
36
+ APPEND_JSON=$(jq -n --arg docId "$DOC_ID" --arg text "$CONTENT" \
37
+ '{toolName: "GOOGLEDOCS_INSERT_TEXT_ACTION", parameters: {document_id: $docId, text_to_insert: $text, append_to_end: true}}')
38
+ echo "$APPEND_JSON" | curl -s -X POST \
39
+ -H "Authorization: Bearer ${GATEWAY_TOKEN}" \
40
+ -H "Content-Type: application/json" \
41
+ -d @- \
42
+ "${LEMON_BACKEND_URL}/api/lemonade/tools/execute" > /dev/null
33
43
  fi
34
44
 
35
45
  echo "$RESULT"
@@ -39,7 +49,10 @@ case "$1" in
39
49
  TITLE="$2"
40
50
  FILE_PATH="$3"
41
51
 
42
- [[ ! -f "$FILE_PATH" ]] && echo "Error: File not found: $FILE_PATH" && exit 1
52
+ if [[ ! -f "$FILE_PATH" ]]; then
53
+ echo -e "${RED}Error:${NC} File not found: $FILE_PATH" >&2
54
+ exit 1
55
+ fi
43
56
 
44
57
  # Read file content
45
58
  CONTENT=$(cat "$FILE_PATH")
@@ -73,15 +86,23 @@ case "$1" in
73
86
  ;;
74
87
  append)
75
88
  [[ -z "$2" ]] || [[ -z "$3" ]] && echo "Usage: lemon-docs append <document_id> <text>" && exit 1
76
- api_call POST "/api/lemonade/tools/execute" \
77
- '{"toolName": "GOOGLEDOCS_INSERT_TEXT_ACTION", "parameters": {"document_id": "'"$2"'", "text_to_insert": "'"$3"'", "append_to_end": true}}'
89
+ APPEND_JSON=$(jq -n --arg docId "$2" --arg text "$3" \
90
+ '{toolName: "GOOGLEDOCS_INSERT_TEXT_ACTION", parameters: {document_id: $docId, text_to_insert: $text, append_to_end: true}}')
91
+ echo "$APPEND_JSON" | curl -s -X POST \
92
+ -H "Authorization: Bearer ${GATEWAY_TOKEN}" \
93
+ -H "Content-Type: application/json" \
94
+ -d @- \
95
+ "${LEMON_BACKEND_URL}/api/lemonade/tools/execute"
78
96
  ;;
79
97
  append-file)
80
98
  [[ -z "$2" ]] || [[ -z "$3" ]] && echo "Usage: lemon-docs append-file <document_id> <file_path>" && exit 1
81
99
  DOC_ID="$2"
82
100
  FILE_PATH="$3"
83
101
 
84
- [[ ! -f "$FILE_PATH" ]] && echo "Error: File not found: $FILE_PATH" && exit 1
102
+ if [[ ! -f "$FILE_PATH" ]]; then
103
+ echo -e "${RED}Error:${NC} File not found: $FILE_PATH" >&2
104
+ exit 1
105
+ fi
85
106
 
86
107
  # Read and escape file content
87
108
  CONTENT=$(cat "$FILE_PATH" | jq -Rs .)
package/bin/lemon-drive CHANGED
@@ -37,6 +37,10 @@ case "$1" in
37
37
  ;;
38
38
  upload)
39
39
  [[ -z "$2" ]] && echo "Usage: lemon-drive upload <file_path> [folder_id]" && exit 1
40
+ if [[ ! -f "$2" ]]; then
41
+ echo -e "${RED}Error:${NC} File not found: $2" >&2
42
+ exit 1
43
+ fi
40
44
  folder="${3:-root}"
41
45
  api_call POST "/api/lemonade/tools/execute" \
42
46
  '{"toolName": "GOOGLEDRIVE_UPLOAD_FILE", "parameters": {"filePath": "'"$2"'", "parents": ["'"$folder"'"]}}'
package/bin/lemon-gmail CHANGED
@@ -16,7 +16,11 @@ case "$1" in
16
16
  ;;
17
17
  send)
18
18
  [[ -z "$2" ]] || [[ -z "$3" ]] || [[ -z "$4" ]] && echo "Usage: lemon-gmail send <to> <subject> <body> [attachment_path]" && exit 1
19
- if [[ -n "$5" ]] && [[ -f "$5" ]]; then
19
+ if [[ -n "$5" ]]; then
20
+ if [[ ! -f "$5" ]]; then
21
+ echo "Error: attachment file not found: $5" >&2
22
+ exit 1
23
+ fi
20
24
  # Send with attachment: upload to Composio S3 → send email with s3key
21
25
  ATTACH_PATH="$5"
22
26
  ATTACH_NAME="$(basename "$ATTACH_PATH")"
@@ -69,8 +73,16 @@ case "$1" in
69
73
  -d @- \
70
74
  "${LEMON_BACKEND_URL}/api/lemonade/tools/execute"
71
75
  else
72
- api_call POST "/api/lemonade/tools/execute" \
73
- '{"toolName": "GMAIL_SEND_EMAIL", "parameters": {"recipient_email": "'"$2"'", "subject": "'"$3"'", "body": "'"$4"'"}}'
76
+ SEND_JSON=$(jq -n \
77
+ --arg to "$2" \
78
+ --arg subject "$3" \
79
+ --arg body "$4" \
80
+ '{toolName: "GMAIL_SEND_EMAIL", parameters: {recipient_email: $to, subject: $subject, body: $body}}')
81
+ echo "$SEND_JSON" | curl -s -X POST \
82
+ -H "Authorization: Bearer ${GATEWAY_TOKEN}" \
83
+ -H "Content-Type: application/json" \
84
+ -d @- \
85
+ "${LEMON_BACKEND_URL}/api/lemonade/tools/execute"
74
86
  fi
75
87
  ;;
76
88
  list)
@@ -95,13 +107,28 @@ case "$1" in
95
107
  ;;
96
108
  reply)
97
109
  [[ -z "$2" ]] || [[ -z "$3" ]] && echo "Usage: lemon-gmail reply <thread_id> <body>" && exit 1
98
- api_call POST "/api/lemonade/tools/execute" \
99
- '{"toolName": "GMAIL_REPLY_TO_THREAD", "parameters": {"thread_id": "'"$2"'", "message_body": "'"$3"'"}}'
110
+ REPLY_JSON=$(jq -n \
111
+ --arg tid "$2" \
112
+ --arg body "$3" \
113
+ '{toolName: "GMAIL_REPLY_TO_THREAD", parameters: {thread_id: $tid, message_body: $body}}')
114
+ echo "$REPLY_JSON" | curl -s -X POST \
115
+ -H "Authorization: Bearer ${GATEWAY_TOKEN}" \
116
+ -H "Content-Type: application/json" \
117
+ -d @- \
118
+ "${LEMON_BACKEND_URL}/api/lemonade/tools/execute"
100
119
  ;;
101
120
  draft)
102
121
  [[ -z "$2" ]] || [[ -z "$3" ]] || [[ -z "$4" ]] && echo "Usage: lemon-gmail draft <to> <subject> <body>" && exit 1
103
- api_call POST "/api/lemonade/tools/execute" \
104
- '{"toolName": "GMAIL_CREATE_EMAIL_DRAFT", "parameters": {"recipient_email": "'"$2"'", "subject": "'"$3"'", "body": "'"$4"'"}}'
122
+ DRAFT_JSON=$(jq -n \
123
+ --arg to "$2" \
124
+ --arg subject "$3" \
125
+ --arg body "$4" \
126
+ '{toolName: "GMAIL_CREATE_EMAIL_DRAFT", parameters: {recipient_email: $to, subject: $subject, body: $body}}')
127
+ echo "$DRAFT_JSON" | curl -s -X POST \
128
+ -H "Authorization: Bearer ${GATEWAY_TOKEN}" \
129
+ -H "Content-Type: application/json" \
130
+ -d @- \
131
+ "${LEMON_BACKEND_URL}/api/lemonade/tools/execute"
105
132
  ;;
106
133
  contacts)
107
134
  # List Google contacts (name + email) for recipient resolution
package/bin/lemon-jira CHANGED
@@ -40,12 +40,17 @@ case "$1" in
40
40
  type="${4:-Task}"
41
41
  desc="${5:-}"
42
42
  if [[ -n "$desc" ]]; then
43
- api_call POST "/api/lemonade/tools/execute" \
44
- '{"toolName": "JIRA_CREATE_ISSUE", "parameters": {"project_key": "'"$2"'", "summary": "'"$3"'", "issue_type": "'"$type"'", "description": "'"$desc"'"}}'
43
+ CREATE_JSON=$(jq -n --arg proj "$2" --arg summary "$3" --arg itype "$type" --arg desc "$desc" \
44
+ '{toolName: "JIRA_CREATE_ISSUE", parameters: {project_key: $proj, summary: $summary, issue_type: $itype, description: $desc}}')
45
45
  else
46
- api_call POST "/api/lemonade/tools/execute" \
47
- '{"toolName": "JIRA_CREATE_ISSUE", "parameters": {"project_key": "'"$2"'", "summary": "'"$3"'", "issue_type": "'"$type"'"}}'
46
+ CREATE_JSON=$(jq -n --arg proj "$2" --arg summary "$3" --arg itype "$type" \
47
+ '{toolName: "JIRA_CREATE_ISSUE", parameters: {project_key: $proj, summary: $summary, issue_type: $itype}}')
48
48
  fi
49
+ echo "$CREATE_JSON" | curl -s -X POST \
50
+ -H "Authorization: Bearer ${GATEWAY_TOKEN}" \
51
+ -H "Content-Type: application/json" \
52
+ -d @- \
53
+ "${LEMON_BACKEND_URL}/api/lemonade/tools/execute"
49
54
  ;;
50
55
  get)
51
56
  [[ -z "$2" ]] && echo "Usage: lemon-jira get <issue_key>" && exit 1
@@ -54,8 +59,13 @@ case "$1" in
54
59
  ;;
55
60
  comment)
56
61
  [[ -z "$2" ]] || [[ -z "$3" ]] && echo "Usage: lemon-jira comment <issue_key> <body>" && exit 1
57
- api_call POST "/api/lemonade/tools/execute" \
58
- '{"toolName": "JIRA_ADD_COMMENT", "parameters": {"issue_id_or_key": "'"$2"'", "comment": "'"$3"'"}}'
62
+ COMMENT_JSON=$(jq -n --arg key "$2" --arg body "$3" \
63
+ '{toolName: "JIRA_ADD_COMMENT", parameters: {issue_id_or_key: $key, comment: $body}}')
64
+ echo "$COMMENT_JSON" | curl -s -X POST \
65
+ -H "Authorization: Bearer ${GATEWAY_TOKEN}" \
66
+ -H "Content-Type: application/json" \
67
+ -d @- \
68
+ "${LEMON_BACKEND_URL}/api/lemonade/tools/execute"
59
69
  ;;
60
70
  transition)
61
71
  [[ -z "$2" ]] || [[ -z "$3" ]] && echo "Usage: lemon-jira transition <issue_key> <status_name>" && exit 1
package/bin/lemon-notion CHANGED
@@ -28,12 +28,17 @@ case "$1" in
28
28
  title="$2"
29
29
  parent="${3:-}"
30
30
  if [[ -n "$parent" ]]; then
31
- api_call POST "/api/lemonade/tools/execute" \
32
- '{"toolName": "NOTION_CREATE_NOTION_PAGE", "parameters": {"parent_id": "'"$parent"'", "title": "'"$title"'"}}'
31
+ CREATE_JSON=$(jq -n --arg parent "$parent" --arg title "$title" \
32
+ '{toolName: "NOTION_CREATE_NOTION_PAGE", parameters: {parent_id: $parent, title: $title}}')
33
33
  else
34
- api_call POST "/api/lemonade/tools/execute" \
35
- '{"toolName": "NOTION_CREATE_NOTION_PAGE", "parameters": {"title": "'"$title"'"}}'
34
+ CREATE_JSON=$(jq -n --arg title "$title" \
35
+ '{toolName: "NOTION_CREATE_NOTION_PAGE", parameters: {title: $title}}')
36
36
  fi
37
+ echo "$CREATE_JSON" | curl -s -X POST \
38
+ -H "Authorization: Bearer ${GATEWAY_TOKEN}" \
39
+ -H "Content-Type: application/json" \
40
+ -d @- \
41
+ "${LEMON_BACKEND_URL}/api/lemonade/tools/execute"
37
42
  ;;
38
43
  read)
39
44
  [[ -z "$2" ]] && echo "Usage: lemon-notion read <page_id>" && exit 1
@@ -47,8 +52,13 @@ case "$1" in
47
52
  ;;
48
53
  append)
49
54
  [[ -z "$2" ]] || [[ -z "$3" ]] && echo "Usage: lemon-notion append <page_id> <content>" && exit 1
50
- api_call POST "/api/lemonade/tools/execute" \
51
- '{"toolName": "NOTION_ADD_MULTIPLE_PAGE_CONTENT", "parameters": {"page_id": "'"$2"'", "content": "'"$3"'"}}'
55
+ APPEND_JSON=$(jq -n --arg pageId "$2" --arg content "$3" \
56
+ '{toolName: "NOTION_ADD_MULTIPLE_PAGE_CONTENT", parameters: {page_id: $pageId, content: $content}}')
57
+ echo "$APPEND_JSON" | curl -s -X POST \
58
+ -H "Authorization: Bearer ${GATEWAY_TOKEN}" \
59
+ -H "Content-Type: application/json" \
60
+ -d @- \
61
+ "${LEMON_BACKEND_URL}/api/lemonade/tools/execute"
52
62
  ;;
53
63
  databases)
54
64
  api_call POST "/api/lemonade/tools/execute" \
package/bin/lemon-slack CHANGED
@@ -16,8 +16,15 @@ case "$1" in
16
16
  ;;
17
17
  send)
18
18
  [[ -z "$2" ]] || [[ -z "$3" ]] && echo "Usage: lemon-slack send <channel> <message>" && exit 1
19
- api_call POST "/api/lemonade/tools/execute" \
20
- '{"toolName": "SLACK_SENDS_A_MESSAGE_TO_A_SLACK_CHANNEL", "parameters": {"channel": "'"$2"'", "text": "'"$3"'"}}'
19
+ SEND_JSON=$(jq -n \
20
+ --arg channel "$2" \
21
+ --arg text "$3" \
22
+ '{toolName: "SLACK_SENDS_A_MESSAGE_TO_A_SLACK_CHANNEL", parameters: {channel: $channel, text: $text}}')
23
+ echo "$SEND_JSON" | curl -s -X POST \
24
+ -H "Authorization: Bearer ${GATEWAY_TOKEN}" \
25
+ -H "Content-Type: application/json" \
26
+ -d @- \
27
+ "${LEMON_BACKEND_URL}/api/lemonade/tools/execute"
21
28
  ;;
22
29
  channels)
23
30
  api_call POST "/api/lemonade/tools/execute" \
package/bin/lemon-slides CHANGED
@@ -16,13 +16,23 @@ case "$1" in
16
16
  ;;
17
17
  create)
18
18
  [[ -z "$2" ]] && echo "Usage: lemon-slides create <title>" && exit 1
19
- api_call POST "/api/lemonade/tools/execute" \
20
- '{"toolName": "GOOGLESLIDES_PRESENTATIONS_CREATE", "parameters": {"title": "'"$2"'"}}'
19
+ CREATE_JSON=$(jq -n --arg title "$2" \
20
+ '{toolName: "GOOGLESLIDES_PRESENTATIONS_CREATE", parameters: {title: $title}}')
21
+ echo "$CREATE_JSON" | curl -s -X POST \
22
+ -H "Authorization: Bearer ${GATEWAY_TOKEN}" \
23
+ -H "Content-Type: application/json" \
24
+ -d @- \
25
+ "${LEMON_BACKEND_URL}/api/lemonade/tools/execute"
21
26
  ;;
22
27
  create-markdown)
23
28
  [[ -z "$2" ]] && echo "Usage: lemon-slides create-markdown <markdown_content>" && exit 1
24
- api_call POST "/api/lemonade/tools/execute" \
25
- '{"toolName": "GOOGLESLIDES_CREATE_SLIDES_MARKDOWN", "parameters": {"markdown": "'"$2"'"}}'
29
+ MD_JSON=$(jq -n --arg md "$2" \
30
+ '{toolName: "GOOGLESLIDES_CREATE_SLIDES_MARKDOWN", parameters: {markdown: $md}}')
31
+ echo "$MD_JSON" | curl -s -X POST \
32
+ -H "Authorization: Bearer ${GATEWAY_TOKEN}" \
33
+ -H "Content-Type: application/json" \
34
+ -d @- \
35
+ "${LEMON_BACKEND_URL}/api/lemonade/tools/execute"
26
36
  ;;
27
37
  get)
28
38
  [[ -z "$2" ]] && echo "Usage: lemon-slides get <presentation_id>" && exit 1
package/bin/lemon-twitter CHANGED
@@ -16,8 +16,13 @@ case "$1" in
16
16
  ;;
17
17
  tweet)
18
18
  [[ -z "$2" ]] && echo "Usage: lemon-twitter tweet <text>" && exit 1
19
- api_call POST "/api/lemonade/tools/execute" \
20
- '{"toolName": "TWITTER_CREATION_OF_A_POST", "parameters": {"text": "'"$2"'"}}'
19
+ TWEET_JSON=$(jq -n --arg text "$2" \
20
+ '{toolName: "TWITTER_CREATION_OF_A_POST", parameters: {text: $text}}')
21
+ echo "$TWEET_JSON" | curl -s -X POST \
22
+ -H "Authorization: Bearer ${GATEWAY_TOKEN}" \
23
+ -H "Content-Type: application/json" \
24
+ -d @- \
25
+ "${LEMON_BACKEND_URL}/api/lemonade/tools/execute"
21
26
  ;;
22
27
  timeline)
23
28
  limit="${2:-20}"
@@ -110,7 +110,7 @@ function buildConfirmationSection(isMinimal) {
110
110
  "## Email Rules (MANDATORY)",
111
111
  "1. NEVER fabricate email addresses. When user says a name (e.g. 'masood from my team'), resolve it via: Slack search-users (returns email), Gmail find-contact, or Gmail sent-to. If all fail, ASK the user.",
112
112
  "2. ALWAYS attach files when the task involves creating AND sending a file.",
113
- '3. To attach a file to an email: first read the file as base64 (`base64 -i <path>`), then call GMAIL_SEND_EMAIL with the `attachment` parameter: `{"name": "file.docx", "content": "<base64>", "mimetype": "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}`.',
113
+ "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.",
114
114
  "4. ALWAYS confirm the recipient email and attachment list BEFORE sending.",
115
115
  "",
116
116
  ];
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.0.8",
3
- "commit": "a1fb85deb3c07e445dd89291230ae7c4d9480042",
4
- "builtAt": "2026-02-20T07:05:21.593Z"
2
+ "version": "0.0.9",
3
+ "commit": "a7a899fbe3b6faf9d612cb1e17c04c84035f02aa",
4
+ "builtAt": "2026-02-20T07:57:12.714Z"
5
5
  }
@@ -1 +1 @@
1
- 924abd5547396c0e3e1642d40a19a47b8437dc16ed9d2aa7cccdd5f28bba3d73
1
+ b3f5fa0f921d2d5f4c3f96081e3cca7ec3382c9223c7dea1eb1b7047d2bf267c
@@ -523,6 +523,7 @@ You can paste/write content directly into the user's currently focused app. The
523
523
  - User has their cursor in an app and asks you to generate text for it (email draft, message, code, document content)
524
524
  - User is composing something and wants you to fill in or continue
525
525
  - Context shows user is in a text-capable app (editor, email, chat, IDE, Notes, Pages, etc.)
526
+ - **Selected text refinement:** When context includes "Selected text" and user asks to format, rewrite, refine, fix, shorten, expand, improve, translate, or transform it in any way, apply the changes and return the result via `[WRITE_CONTENT]` so it replaces their selection
526
527
 
527
528
  ## When NOT to Use
528
529
  - User asks a question (use normal response)
@@ -563,6 +564,13 @@ John
563
564
  - NEVER use em dash (—) in pasted content.
564
565
  - If content already exists on screen and you're inserting into it, only produce the content for the cursor position.
565
566
 
567
+ ## Selected Text Refinement
568
+ When the user's context includes "Selected text: ..." and they ask to modify it (e.g., "format this", "fix the grammar", "make it shorter", "rewrite professionally", "translate to Spanish"), treat it as a paste-back task:
569
+ 1. Apply the requested transformation to the selected text
570
+ 2. Return ONLY the transformed text inside `[WRITE_CONTENT]` tags
571
+ 3. Add a brief confirmation (e.g., "Formatted." or "Fixed.")
572
+ 4. Do NOT echo the original text or explain what you changed
573
+
566
574
  ## Important
567
575
  - The `[WRITE_CONTENT]` tags are stripped from the response before showing to the user, so include them naturally.
568
576
  - Only ONE `[WRITE_CONTENT]` block per response.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heylemon/lemonade",
3
- "version": "0.0.8",
3
+ "version": "0.0.9",
4
4
  "description": "AI gateway CLI for Lemon - local AI assistant with integrations",
5
5
  "publishConfig": {
6
6
  "access": "restricted"