@chrysb/alphaclaw 0.1.16 → 0.1.18

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.
@@ -47,4 +47,69 @@ body::before {
47
47
  /* Google scope picker toggle buttons */
48
48
  .scope-btn { background: rgba(255,255,255,0.03); color: var(--text-muted); border: 1px solid var(--border); transition: all 0.15s; }
49
49
  .scope-btn:hover { border-color: var(--text-dim); color: var(--text); }
50
- .scope-btn.active { background: var(--bg-active); color: var(--accent); border-color: var(--accent-dim); }
50
+ .scope-btn-read.active {
51
+ background: rgba(255, 255, 255, 0.12);
52
+ color: #f3f4f6;
53
+ border-color: rgba(255, 255, 255, 0.35);
54
+ }
55
+ .scope-btn-write.active {
56
+ background: rgba(255, 255, 255, 0.12);
57
+ color: #f3f4f6;
58
+ border-color: rgba(255, 255, 255, 0.35);
59
+ }
60
+
61
+ /* Reusable cyan action buttons */
62
+ .ac-btn-cyan {
63
+ border: 1px solid var(--accent-dim);
64
+ background: linear-gradient(
65
+ 180deg,
66
+ rgba(99, 235, 255, 0.14) 0%,
67
+ rgba(99, 235, 255, 0.08) 100%
68
+ );
69
+ color: var(--accent);
70
+ box-shadow: inset 0 0 0 1px rgba(99, 235, 255, 0.12);
71
+ transition:
72
+ border-color 0.15s ease,
73
+ background 0.15s ease,
74
+ color 0.15s ease,
75
+ box-shadow 0.15s ease,
76
+ transform 0.15s ease;
77
+ }
78
+
79
+ .ac-btn-cyan:hover:not(:disabled) {
80
+ border-color: rgba(99, 235, 255, 0.7);
81
+ background: linear-gradient(
82
+ 180deg,
83
+ rgba(99, 235, 255, 0.24) 0%,
84
+ rgba(99, 235, 255, 0.12) 100%
85
+ );
86
+ color: #b9f8ff;
87
+ box-shadow:
88
+ inset 0 0 0 1px rgba(99, 235, 255, 0.2),
89
+ 0 0 12px rgba(99, 235, 255, 0.14);
90
+ }
91
+
92
+ .ac-btn-cyan:active:not(:disabled) {
93
+ transform: translateY(1px);
94
+ }
95
+
96
+ .ac-btn-cyan:disabled {
97
+ opacity: 0.5;
98
+ cursor: not-allowed;
99
+ }
100
+
101
+ .ac-btn-cyan-ghost {
102
+ border: 1px solid var(--accent-dim);
103
+ color: rgba(99, 235, 255, 0.75);
104
+ background: rgba(99, 235, 255, 0.04);
105
+ transition:
106
+ border-color 0.15s ease,
107
+ color 0.15s ease,
108
+ background 0.15s ease;
109
+ }
110
+
111
+ .ac-btn-cyan-ghost:hover {
112
+ border-color: rgba(99, 235, 255, 0.5);
113
+ color: #a4f3ff;
114
+ background: rgba(99, 235, 255, 0.08);
115
+ }
@@ -27,6 +27,9 @@ import { Envars } from "./components/envars.js";
27
27
  import { ToastContainer, showToast } from "./components/toast.js";
28
28
  import { ChevronDownIcon } from "./components/icons.js";
29
29
  const html = htm.bind(h);
30
+ const kUiTabStorageKey = "alphaclaw_ui_tab";
31
+ const kUiTabs = ["general", "models", "envars"];
32
+ const kDefaultUiTab = "general";
30
33
 
31
34
  const GeneralTab = ({ onSwitchTab }) => {
32
35
  const [googleKey, setGoogleKey] = useState(0);
@@ -116,15 +119,23 @@ const GeneralTab = ({ onSwitchTab }) => {
116
119
  if (!syncCron) return;
117
120
  setSyncCronEnabled(syncCron.enabled !== false);
118
121
  setSyncCronSchedule(syncCron.schedule || "0 * * * *");
119
- setSyncCronChoice(syncCron.enabled === false ? "disabled" : syncCron.schedule || "0 * * * *");
122
+ setSyncCronChoice(
123
+ syncCron.enabled === false
124
+ ? "disabled"
125
+ : syncCron.schedule || "0 * * * *",
126
+ );
120
127
  }, [syncCron?.enabled, syncCron?.schedule]);
121
128
 
122
- const saveSyncCronSettings = async ({ enabled = syncCronEnabled, schedule = syncCronSchedule }) => {
129
+ const saveSyncCronSettings = async ({
130
+ enabled = syncCronEnabled,
131
+ schedule = syncCronSchedule,
132
+ }) => {
123
133
  if (savingSyncCron) return;
124
134
  setSavingSyncCron(true);
125
135
  try {
126
136
  const data = await updateSyncCron({ enabled, schedule });
127
- if (!data.ok) throw new Error(data.error || "Could not save sync settings");
137
+ if (!data.ok)
138
+ throw new Error(data.error || "Could not save sync settings");
128
139
  showToast("Sync schedule updated", "success");
129
140
  statusPoll.refresh();
130
141
  } catch (err) {
@@ -148,12 +159,26 @@ const GeneralTab = ({ onSwitchTab }) => {
148
159
  />
149
160
  <${Google} key=${googleKey} gatewayStatus=${gatewayStatus} />
150
161
 
151
- ${repo && html`
162
+ ${repo &&
163
+ html`
152
164
  <div class="bg-surface border border-border rounded-xl p-4">
153
165
  <div class="flex items-center justify-between gap-3">
154
166
  <div class="flex items-center gap-2 min-w-0">
155
- <svg class="w-4 h-4 text-gray-400" viewBox="0 0 16 16" fill="currentColor"><path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"/></svg>
156
- <a href="https://github.com/${repo}" target="_blank" class="text-sm text-gray-400 hover:text-gray-200 transition-colors truncate">${repo}</a>
167
+ <svg
168
+ class="w-4 h-4 text-gray-400"
169
+ viewBox="0 0 16 16"
170
+ fill="currentColor"
171
+ >
172
+ <path
173
+ d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"
174
+ />
175
+ </svg>
176
+ <a
177
+ href="https://github.com/${repo}"
178
+ target="_blank"
179
+ class="text-sm text-gray-400 hover:text-gray-200 transition-colors truncate"
180
+ >${repo}</a
181
+ >
157
182
  </div>
158
183
  <div class="flex items-center gap-2 shrink-0">
159
184
  <span class="text-xs text-gray-400">Auto-sync</span>
@@ -164,7 +189,9 @@ const GeneralTab = ({ onSwitchTab }) => {
164
189
  const nextChoice = e.target.value;
165
190
  setSyncCronChoice(nextChoice);
166
191
  const nextEnabled = nextChoice !== "disabled";
167
- const nextSchedule = nextEnabled ? nextChoice : syncCronSchedule;
192
+ const nextSchedule = nextEnabled
193
+ ? nextChoice
194
+ : syncCronSchedule;
168
195
  setSyncCronEnabled(nextEnabled);
169
196
  setSyncCronSchedule(nextSchedule);
170
197
  saveSyncCronSettings({
@@ -176,7 +203,9 @@ const GeneralTab = ({ onSwitchTab }) => {
176
203
  class="appearance-none bg-black/30 border border-border rounded-lg pl-2.5 pr-9 py-1.5 text-xs text-gray-300 ${savingSyncCron
177
204
  ? "opacity-50 cursor-not-allowed"
178
205
  : ""}"
179
- title=${syncCron?.installed === false ? "Not Installed Yet" : syncCronStatusText}
206
+ title=${syncCron?.installed === false
207
+ ? "Not Installed Yet"
208
+ : syncCronStatusText}
180
209
  >
181
210
  <option value="disabled">Disabled</option>
182
211
  <option value="*/30 * * * *">Every 30 min</option>
@@ -195,7 +224,7 @@ const GeneralTab = ({ onSwitchTab }) => {
195
224
  <div class="bg-surface border border-border rounded-xl p-4">
196
225
  <div class="flex items-center justify-between">
197
226
  <div>
198
- <h2 class="font-semibold text-sm">Gateway Dashboard</h2>
227
+ <h2 class="font-semibold text-sm">OpenClaw Gateway Dashboard</h2>
199
228
  </div>
200
229
  <button
201
230
  onclick=${async () => {
@@ -203,18 +232,20 @@ const GeneralTab = ({ onSwitchTab }) => {
203
232
  setDashboardLoading(true);
204
233
  try {
205
234
  const data = await fetchDashboardUrl();
206
- console.log('[dashboard] response:', JSON.stringify(data));
207
- window.open(data.url || '/openclaw', '_blank');
235
+ console.log("[dashboard] response:", JSON.stringify(data));
236
+ window.open(data.url || "/openclaw", "_blank");
208
237
  } catch (err) {
209
- console.error('[dashboard] error:', err);
210
- window.open('/openclaw', '_blank');
238
+ console.error("[dashboard] error:", err);
239
+ window.open("/openclaw", "_blank");
211
240
  }
212
241
  setDashboardLoading(false);
213
242
  }}
214
243
  disabled=${dashboardLoading}
215
- class="text-xs px-2.5 py-1 rounded-lg border border-border text-gray-500 hover:text-gray-300 hover:border-gray-500 transition-colors ${dashboardLoading ? 'opacity-50 cursor-not-allowed' : ''}"
244
+ class="text-xs px-2.5 py-1 rounded-lg border border-border text-gray-500 hover:text-gray-300 hover:border-gray-500 transition-colors ${dashboardLoading
245
+ ? "opacity-50 cursor-not-allowed"
246
+ : ""}"
216
247
  >
217
- ${dashboardLoading ? 'Opening...' : 'Open'}
248
+ ${dashboardLoading ? "Opening..." : "Open"}
218
249
  </button>
219
250
  </div>
220
251
  <${DevicePairings}
@@ -241,7 +272,14 @@ const GeneralTab = ({ onSwitchTab }) => {
241
272
 
242
273
  function App() {
243
274
  const [onboarded, setOnboarded] = useState(null);
244
- const [tab, setTab] = useState("general");
275
+ const [tab, setTab] = useState(() => {
276
+ try {
277
+ const savedTab = localStorage.getItem(kUiTabStorageKey);
278
+ return kUiTabs.includes(savedTab) ? savedTab : kDefaultUiTab;
279
+ } catch {
280
+ return kDefaultUiTab;
281
+ }
282
+ });
245
283
  const [acVersion, setAcVersion] = useState(null);
246
284
  const [acLatest, setAcLatest] = useState(null);
247
285
  const [acHasUpdate, setAcHasUpdate] = useState(false);
@@ -254,6 +292,12 @@ function App() {
254
292
  .catch(() => setOnboarded(false));
255
293
  }, []);
256
294
 
295
+ useEffect(() => {
296
+ try {
297
+ localStorage.setItem(kUiTabStorageKey, tab);
298
+ } catch {}
299
+ }, [tab]);
300
+
257
301
  useEffect(() => {
258
302
  if (!onboarded) return;
259
303
  let active = true;
@@ -268,7 +312,10 @@ function App() {
268
312
  };
269
313
  check(true);
270
314
  const id = setInterval(() => check(false), 5 * 60 * 1000);
271
- return () => { active = false; clearInterval(id); };
315
+ return () => {
316
+ active = false;
317
+ clearInterval(id);
318
+ };
272
319
  }, [onboarded]);
273
320
 
274
321
  const handleAcUpdate = async () => {
@@ -292,7 +339,10 @@ function App() {
292
339
  // Still loading onboard status
293
340
  if (onboarded === null) {
294
341
  return html`
295
- <div class="min-h-screen flex items-center justify-center" style="position: relative; z-index: 1">
342
+ <div
343
+ class="min-h-screen flex items-center justify-center"
344
+ style="position: relative; z-index: 1"
345
+ >
296
346
  <svg
297
347
  class="animate-spin h-6 w-6"
298
348
  style="color: var(--text-muted)"
@@ -320,7 +370,10 @@ function App() {
320
370
 
321
371
  if (!onboarded) {
322
372
  return html`
323
- <div class="min-h-screen flex justify-center pt-12 pb-8 px-4" style="position: relative; z-index: 1">
373
+ <div
374
+ class="min-h-screen flex justify-center pt-12 pb-8 px-4"
375
+ style="position: relative; z-index: 1"
376
+ >
324
377
  <${Welcome} onComplete=${() => setOnboarded(true)} />
325
378
  </div>
326
379
  <${ToastContainer} />
@@ -354,13 +407,17 @@ function App() {
354
407
  )}
355
408
  </nav>
356
409
  <div class="sidebar-footer">
357
- ${acHasUpdate && acLatest && !acDismissed ? html`
358
- <button
359
- onclick=${handleAcUpdate}
360
- disabled=${acUpdating}
361
- class="sidebar-update-btn"
362
- >${acUpdating ? "Updating..." : `Update to v${acLatest}`}</button>
363
- ` : null}
410
+ ${acHasUpdate && acLatest && !acDismissed
411
+ ? html`
412
+ <button
413
+ onclick=${handleAcUpdate}
414
+ disabled=${acUpdating}
415
+ class="sidebar-update-btn"
416
+ >
417
+ ${acUpdating ? "Updating..." : `Update to v${acLatest}`}
418
+ </button>
419
+ `
420
+ : null}
364
421
  </div>
365
422
  </div>
366
423
 
@@ -380,12 +437,26 @@ function App() {
380
437
 
381
438
  <div class="app-statusbar">
382
439
  <div class="statusbar-left">
383
- ${acVersion ? html`<span style="color: var(--text-muted)">v${acVersion}</span>` : null}
440
+ ${acVersion
441
+ ? html`<span style="color: var(--text-muted)">v${acVersion}</span>`
442
+ : null}
384
443
  </div>
385
444
  <div class="statusbar-right">
386
- <a href="https://docs.openclaw.ai" target="_blank" rel="noreferrer">docs</a>
387
- <a href="https://discord.com/invite/clawd" target="_blank" rel="noreferrer">discord</a>
388
- <a href="https://github.com/openclaw/openclaw" target="_blank" rel="noreferrer">github</a>
445
+ <a href="https://docs.openclaw.ai" target="_blank" rel="noreferrer"
446
+ >docs</a
447
+ >
448
+ <a
449
+ href="https://discord.com/invite/clawd"
450
+ target="_blank"
451
+ rel="noreferrer"
452
+ >discord</a
453
+ >
454
+ <a
455
+ href="https://github.com/openclaw/openclaw"
456
+ target="_blank"
457
+ rel="noreferrer"
458
+ >github</a
459
+ >
389
460
  </div>
390
461
  </div>
391
462
  </div>
@@ -322,13 +322,13 @@ export const CredentialsModal = ({ visible, onClose, onSaved }) => {
322
322
  <button
323
323
  onclick=${submit}
324
324
  disabled=${saving}
325
- class="flex-1 bg-green-500 text-black font-medium py-2 rounded-lg hover:opacity-85 transition-opacity text-sm"
325
+ class="flex-1 font-medium py-2 rounded-lg text-sm ac-btn-cyan"
326
326
  >
327
327
  ${saving ? "Saving..." : "Connect Google"}
328
328
  </button>
329
329
  <button
330
330
  onclick=${onClose}
331
- class="px-4 bg-gray-800 text-gray-300 py-2 rounded-lg hover:bg-gray-700 transition-colors text-sm"
331
+ class="px-4 py-2 rounded-lg text-sm ac-btn-cyan-ghost"
332
332
  >
333
333
  Cancel
334
334
  </button>
@@ -332,11 +332,7 @@ export const Envars = () => {
332
332
  <button
333
333
  onclick=${handleSave}
334
334
  disabled=${!dirty || saving || restartingGateway}
335
- class="w-full text-sm font-medium px-4 py-2.5 rounded-xl transition-all ${dirty &&
336
- !saving &&
337
- !restartingGateway
338
- ? "bg-white text-black hover:opacity-85"
339
- : "bg-gray-800 text-gray-500 cursor-not-allowed"}"
335
+ class="w-full text-sm font-medium px-4 py-2.5 rounded-xl transition-all ac-btn-cyan"
340
336
  >
341
337
  ${saving
342
338
  ? html`<span class="flex items-center justify-center gap-2">
@@ -357,7 +353,7 @@ export const Envars = () => {
357
353
  </svg>
358
354
  Saving...
359
355
  </span>`
360
- : "Save Changes"}
356
+ : "Save changes"}
361
357
  </button>
362
358
  </div>
363
359
  `;
@@ -175,10 +175,7 @@ export function Google({ gatewayStatus }) {
175
175
  <button
176
176
  onclick=${() => startAuth(email)}
177
177
  disabled=${isAuthed && !scopesChanged}
178
- class="text-xs font-medium px-3 py-1.5 rounded-lg ${isAuthed &&
179
- !scopesChanged
180
- ? "bg-gray-600 text-gray-400 cursor-not-allowed"
181
- : "bg-white text-black hover:opacity-85"}"
178
+ class="text-xs font-medium px-3 py-1.5 rounded-lg ac-btn-cyan"
182
179
  >
183
180
  ${isAuthed ? "Update Permissions" : "Sign in with Google"}
184
181
  </button>
@@ -207,7 +204,7 @@ export function Google({ gatewayStatus }) {
207
204
  </p>
208
205
  <button
209
206
  onclick=${() => setModalOpen(true)}
210
- class="bg-white text-black text-sm font-medium px-4 py-2 rounded-lg hover:opacity-85"
207
+ class="text-sm font-medium px-4 py-2 rounded-lg ac-btn-cyan"
211
208
  >
212
209
  Set up Google
213
210
  </button>
@@ -320,7 +320,7 @@ export const Models = () => {
320
320
  ? html`
321
321
  <button
322
322
  onclick=${startCodexAuth}
323
- class="text-xs font-medium px-3 py-1.5 rounded-lg bg-white text-black hover:opacity-85"
323
+ class="text-xs font-medium px-3 py-1.5 rounded-lg ac-btn-cyan"
324
324
  >
325
325
  Connect Codex OAuth
326
326
  </button>
@@ -357,7 +357,7 @@ export const Models = () => {
357
357
  <button
358
358
  onclick=${completeCodexAuth}
359
359
  disabled=${!codexManualInput.trim() || codexExchanging}
360
- class="text-xs font-medium px-3 py-1.5 rounded-lg ${!codexManualInput.trim() || codexExchanging ? "bg-gray-700 text-gray-400 cursor-not-allowed" : "bg-white text-black hover:opacity-85"}"
360
+ class="text-xs font-medium px-3 py-1.5 rounded-lg ac-btn-cyan"
361
361
  >
362
362
  ${codexExchanging ? "Completing..." : "Complete Codex OAuth"}
363
363
  </button>
@@ -442,9 +442,7 @@ export const Models = () => {
442
442
  <button
443
443
  onclick=${saveChanges}
444
444
  disabled=${!canSaveChanges}
445
- class="w-full text-sm font-medium px-4 py-2.5 rounded-xl transition-all ${canSaveChanges
446
- ? "bg-white text-black hover:opacity-85"
447
- : "bg-gray-800 text-gray-500 cursor-not-allowed"}"
445
+ class="w-full text-sm font-medium px-4 py-2.5 rounded-xl transition-all ac-btn-cyan"
448
446
  >
449
447
  ${savingChanges ? "Saving..." : "Save changes"}
450
448
  </button>
@@ -110,7 +110,7 @@ export const WelcomeFormStep = ({
110
110
  onclick=${startCodexAuth}
111
111
  class="text-xs font-medium px-3 py-1.5 rounded-lg ${codexStatus.connected
112
112
  ? "border border-border text-gray-300 hover:border-gray-500"
113
- : "bg-white text-black hover:opacity-85"}"
113
+ : "ac-btn-cyan"}"
114
114
  >
115
115
  ${codexStatus.connected ? "Reconnect Codex" : "Connect Codex OAuth"}
116
116
  </button>
@@ -148,10 +148,7 @@ export const WelcomeFormStep = ({
148
148
  type="button"
149
149
  onclick=${completeCodexAuth}
150
150
  disabled=${!codexManualInput.trim() || codexExchanging}
151
- class="text-xs font-medium px-3 py-1.5 rounded-lg ${!codexManualInput.trim() ||
152
- codexExchanging
153
- ? "bg-gray-700 text-gray-400 cursor-not-allowed"
154
- : "bg-white text-black hover:opacity-85"}"
151
+ class="text-xs font-medium px-3 py-1.5 rounded-lg ac-btn-cyan"
155
152
  >
156
153
  ${codexExchanging ? "Completing..." : "Complete Codex OAuth"}
157
154
  </button>
@@ -59,8 +59,8 @@ export function ScopePicker({ scopes, onToggle, apiStatus, loading }) {
59
59
  <span class="text-sm">${s.icon} ${s.label}</span>
60
60
  <div class="flex items-center gap-2">
61
61
  ${apiIndicator}
62
- <button onclick=${() => onToggle(`${s.key}:read`)} class="scope-btn ${readOn ? 'active' : ''} text-xs px-2 py-0.5 rounded">Read</button>
63
- <button onclick=${() => onToggle(`${s.key}:write`)} class="scope-btn ${writeOn ? 'active' : ''} text-xs px-2 py-0.5 rounded">Write</button>
62
+ <button onclick=${() => onToggle(`${s.key}:read`)} class="scope-btn scope-btn-read ${readOn ? 'active' : ''} text-xs px-2 py-0.5 rounded">Read</button>
63
+ <button onclick=${() => onToggle(`${s.key}:write`)} class="scope-btn scope-btn-write ${writeOn ? 'active' : ''} text-xs px-2 py-0.5 rounded">Write</button>
64
64
  </div>
65
65
  </div>`;
66
66
  })}
@@ -224,7 +224,9 @@ export const Welcome = ({ onComplete }) => {
224
224
 
225
225
  try {
226
226
  const vars = Object.entries(vals)
227
- .filter(([key]) => key !== "MODEL_KEY")
227
+ .filter(
228
+ ([key]) => key !== "MODEL_KEY" && !String(key || "").startsWith("_"),
229
+ )
228
230
  .filter(([, v]) => v)
229
231
  .map(([key, value]) => ({ key, value }));
230
232
  const result = await runOnboard(vars, vals.MODEL_KEY);
@@ -91,7 +91,6 @@ const registerGoogleRoutes = ({
91
91
 
92
92
  const services = req.body.services || [
93
93
  "gmail:read",
94
- "gmail:write",
95
94
  "calendar:read",
96
95
  "calendar:write",
97
96
  "drive:read",
@@ -208,7 +207,7 @@ const registerGoogleRoutes = ({
208
207
  const email = req.query.email || "";
209
208
  const services = (
210
209
  req.query.services ||
211
- "gmail:read,gmail:write,calendar:read,calendar:write,drive:read,sheets:read,docs:read"
210
+ "gmail:read,calendar:read,calendar:write,drive:read,sheets:read,docs:read"
212
211
  )
213
212
  .split(",")
214
213
  .filter(Boolean);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chrysb/alphaclaw",
3
- "version": "0.1.16",
3
+ "version": "0.1.18",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },