@heylemon/lemonade 0.4.9 → 0.5.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.
@@ -131,7 +131,7 @@ function buildConfirmationSection(isMinimal) {
131
131
  "",
132
132
  "## Email Rules (MANDATORY)",
133
133
  "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.",
134
- "2. ALWAYS attach files when the task involves creating AND sending a file.",
134
+ "2. ALWAYS attach files when the task involves creating AND sending a file. When the user asks you to send/email a document (report, spreadsheet, PDF, etc.), your job is to CREATE the file AND ATTACH it to the email — do NOT just send an email saying 'the file is on your Desktop'. The whole point is delivering the file. Only skip attaching if the user explicitly says to save it locally without sending.",
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
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.",
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.4.9",
3
- "commit": "3b6838d381879be6654e0402185e231a15bf7f3c",
4
- "builtAt": "2026-02-25T05:17:09.702Z"
2
+ "version": "0.5.0",
3
+ "commit": "a13eab6d9fff1ec7ccecd4f8abbe2679bf88cbee",
4
+ "builtAt": "2026-02-25T08:16:55.962Z"
5
5
  }
@@ -1 +1 @@
1
- edeb39165d712bc22ac4db917397e97d960bc33ac988beebcfb2148e4ca02cf6
1
+ 095be0769244f46020c935adb52b83f602459c8318e55f7513862d7abb51c029
@@ -61,6 +61,8 @@ function candidateBinDirs(opts) {
61
61
  const miseShims = path.join(miseDataDir, "shims");
62
62
  if (isDirectory(miseShims))
63
63
  candidates.push(miseShims);
64
+ // Portable Node.js install managed by Lemon macOS app.
65
+ candidates.push(path.join(homeDir, ".lemonade", "node", "bin"));
64
66
  candidates.push(...resolveBrewPathDirs({ homeDir }));
65
67
  // Common global install locations (macOS first).
66
68
  if (platform === "darwin") {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heylemon/lemonade",
3
- "version": "0.4.9",
3
+ "version": "0.5.0",
4
4
  "description": "AI gateway CLI for Lemon - local AI assistant with integrations",
5
5
  "publishConfig": {
6
6
  "access": "restricted"
@@ -25,7 +25,8 @@ uv run {baseDir}/scripts/generate_image.py --prompt "combine these into one scen
25
25
  ```
26
26
 
27
27
  API key
28
- - `GEMINI_API_KEY` env var
28
+ - Automatically routed through the Lemonade backend proxy when `LEMON_BACKEND_URL` and `GATEWAY_TOKEN` are set (API key stays server-side)
29
+ - Or `GEMINI_API_KEY` env var for direct access
29
30
  - Or set `skills."nano-banana-pro".apiKey` / `skills."nano-banana-pro".env.GEMINI_API_KEY` in `~/.lemonade/lemonade.json`
30
31
 
31
32
  Notes
@@ -29,6 +29,15 @@ def get_api_key(provided_key: str | None) -> str | None:
29
29
  return os.environ.get("GEMINI_API_KEY")
30
30
 
31
31
 
32
+ def get_proxy_config() -> tuple[str | None, str | None]:
33
+ """Get backend proxy URL and gateway token for server-side API key routing."""
34
+ backend_url = os.environ.get("LEMON_BACKEND_URL", "").rstrip("/")
35
+ gateway_token = os.environ.get("GATEWAY_TOKEN", "")
36
+ if backend_url and gateway_token:
37
+ return f"{backend_url}/api/lemonade/proxy/gemini", gateway_token
38
+ return None, None
39
+
40
+
32
41
  def main():
33
42
  parser = argparse.ArgumentParser(
34
43
  description="Generate images using Nano Banana Pro (Gemini 3 Pro Image)"
@@ -63,22 +72,30 @@ def main():
63
72
 
64
73
  args = parser.parse_args()
65
74
 
66
- # Get API key
75
+ # Prefer backend proxy (API key stays server-side), fall back to local key
76
+ proxy_url, gateway_token = get_proxy_config()
67
77
  api_key = get_api_key(args.api_key)
68
- if not api_key:
69
- print("Error: No API key provided.", file=sys.stderr)
78
+
79
+ if not proxy_url and not api_key:
80
+ print("Error: No API key or backend proxy available.", file=sys.stderr)
70
81
  print("Please either:", file=sys.stderr)
71
- print(" 1. Provide --api-key argument", file=sys.stderr)
72
- print(" 2. Set GEMINI_API_KEY environment variable", file=sys.stderr)
82
+ print(" 1. Set LEMON_BACKEND_URL + GATEWAY_TOKEN (backend proxy)", file=sys.stderr)
83
+ print(" 2. Provide --api-key argument", file=sys.stderr)
84
+ print(" 3. Set GEMINI_API_KEY environment variable", file=sys.stderr)
73
85
  sys.exit(1)
74
86
 
75
- # Import here after checking API key to avoid slow import on error
76
87
  from google import genai
77
88
  from google.genai import types
78
89
  from PIL import Image as PILImage
79
90
 
80
- # Initialise client
81
- client = genai.Client(api_key=api_key)
91
+ if proxy_url:
92
+ print(f"Using backend proxy for Gemini API")
93
+ client = genai.Client(
94
+ api_key=gateway_token,
95
+ http_options=types.HttpOptions(api_endpoint=proxy_url),
96
+ )
97
+ else:
98
+ client = genai.Client(api_key=api_key)
82
99
 
83
100
  # Set up output path
84
101
  output_path = Path(args.filename)