clementine-agent 1.0.74 → 1.0.76
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.
|
@@ -208,16 +208,10 @@ Steps:
|
|
|
208
208
|
fields: [
|
|
209
209
|
{
|
|
210
210
|
key: 'contact',
|
|
211
|
-
label: '
|
|
211
|
+
label: 'Phone number or email',
|
|
212
|
+
placeholder: '+15551234567 or someone@example.com',
|
|
212
213
|
required: true,
|
|
213
|
-
help: '
|
|
214
|
-
picker: {
|
|
215
|
-
tool: 'mcp__imessage__search_contacts',
|
|
216
|
-
intent: 'call search_contacts with query "{{query}}". For each match, output {id: the contact\'s phone number or email handle, label: the display name (or the handle if no name), sublabel: "handle: " + handle}. Return up to 15 results.',
|
|
217
|
-
queryArg: 'query',
|
|
218
|
-
minQueryLength: 2,
|
|
219
|
-
allowCustom: true,
|
|
220
|
-
},
|
|
214
|
+
help: 'Paste the contact\'s iMessage handle exactly as it appears in your Messages thread. The iMessage MCP\'s search_contacts reads the Contacts app via AppleScript and is unreliable — we bypass it by letting you paste the handle directly.',
|
|
221
215
|
},
|
|
222
216
|
{ key: 'limit', label: 'Max messages per run', placeholder: '50', defaultValue: '50' },
|
|
223
217
|
],
|
package/dist/cli/dashboard.js
CHANGED
|
@@ -2659,7 +2659,13 @@ export async function cmdDashboard(opts) {
|
|
|
2659
2659
|
}
|
|
2660
2660
|
const { query } = await import('@anthropic-ai/claude-agent-sdk');
|
|
2661
2661
|
const { parseJsonResponse } = await import('../brain/llm-client.js');
|
|
2662
|
+
const { getMcpServersForAgent } = await import('../agent/mcp-bridge.js');
|
|
2662
2663
|
const { MODELS } = await import('../config.js');
|
|
2664
|
+
// Pass the full MCP server map so the one-shot probe can call
|
|
2665
|
+
// Extension-provided tools (iMessage, figma, supabase, etc.).
|
|
2666
|
+
// Without this the SDK only sees built-in + claude_ai_* tools
|
|
2667
|
+
// and every Extension tool call is silently rejected at runtime.
|
|
2668
|
+
const mcpServers = getMcpServersForAgent();
|
|
2663
2669
|
// Strict prompt: force JSON-only output. The tool lookup goes through
|
|
2664
2670
|
// the SDK so claude_ai_* and regular MCP servers work uniformly.
|
|
2665
2671
|
const stream = query({
|
|
@@ -2672,6 +2678,7 @@ If the tool returns nothing or errors, return an empty array \`[]\`.`,
|
|
|
2672
2678
|
maxTurns: 3,
|
|
2673
2679
|
systemPrompt: 'You are a data enumerator. You call the given tool once, extract the items from its response, and emit a strict JSON array. No commentary.',
|
|
2674
2680
|
allowedTools: [tool],
|
|
2681
|
+
mcpServers,
|
|
2675
2682
|
permissionMode: 'bypassPermissions',
|
|
2676
2683
|
settingSources: [],
|
|
2677
2684
|
},
|
|
@@ -10820,7 +10827,7 @@ if('serviceWorker' in navigator){navigator.serviceWorker.getRegistrations().then
|
|
|
10820
10827
|
return;
|
|
10821
10828
|
}
|
|
10822
10829
|
brainPickerTypeahead[field.key] = {
|
|
10823
|
-
timer: setTimeout(function() { brainFireTypeaheadProbe(field, q); },
|
|
10830
|
+
timer: setTimeout(function() { brainFireTypeaheadProbe(field, q); }, 600),
|
|
10824
10831
|
};
|
|
10825
10832
|
};
|
|
10826
10833
|
return;
|
|
@@ -10886,7 +10893,15 @@ if('serviceWorker' in navigator){navigator.serviceWorker.getRegistrations().then
|
|
|
10886
10893
|
if (!resp.ok) throw new Error(data.error || 'probe failed');
|
|
10887
10894
|
const items = data.items || [];
|
|
10888
10895
|
if (!items.length) {
|
|
10889
|
-
|
|
10896
|
+
// If the raw preview is anything other than an empty array (with
|
|
10897
|
+
// or without a markdown code fence), show it so the user can tell
|
|
10898
|
+
// whether the tool actually ran.
|
|
10899
|
+
const trimmed = (data.rawPreview || '').trim();
|
|
10900
|
+
const isEmptyArray = /^\s*\[\s*\]\s*$/.test(trimmed.replace(/^[^\[]*/, '').replace(/[^\]]*$/, ''));
|
|
10901
|
+
const rawHint = trimmed && !isEmptyArray
|
|
10902
|
+
? ' <span style="color:var(--muted)">Tool said: ' + escapeHtml(trimmed.slice(0, 140)) + '</span>'
|
|
10903
|
+
: '';
|
|
10904
|
+
resultsEl.innerHTML = '<div style="color:#8a5a00;font-size:12px;padding:6px">No matches for "' + escapeHtml(query) + '". The tool may be limited by macOS permissions or not support this query — use <a href="#" onclick="brainFieldPickerToggleCustom(\\'' + field.key + '\\', \\'\\');return false">type a value directly</a>.' + rawHint + '</div>';
|
|
10890
10905
|
return;
|
|
10891
10906
|
}
|
|
10892
10907
|
resultsEl.innerHTML = items.map(function(it) {
|
|
@@ -12365,14 +12380,24 @@ async function checkAnthropicAuth() {
|
|
|
12365
12380
|
var btn = document.getElementById('gs-auth-btn');
|
|
12366
12381
|
if (d.authenticated && card) {
|
|
12367
12382
|
card.className = 'gs-card gs-done';
|
|
12368
|
-
|
|
12383
|
+
// Email is null when auth comes from the Claude Code keychain (OAuth
|
|
12384
|
+
// login via clementine-login or claude-login that we do not have read
|
|
12385
|
+
// access to). Avoid rendering "Connected as null" — looks broken and
|
|
12386
|
+
// makes users re-click login, which hits an SDK bug in claudeAuthenticate.
|
|
12387
|
+
var label = d.email
|
|
12388
|
+
? 'Connected as ' + d.email
|
|
12389
|
+
: 'Connected via ' + (d.apiKeySource === 'keychain' ? 'Claude Code keychain' : d.apiKeySource || 'API');
|
|
12390
|
+
if (desc) desc.textContent = label;
|
|
12369
12391
|
if (btn) { btn.textContent = 'Connected'; btn.disabled = true; }
|
|
12370
12392
|
}
|
|
12371
12393
|
// Also update settings auth indicator
|
|
12372
12394
|
var settingsAuth = document.getElementById('settings-auth-status');
|
|
12373
12395
|
if (settingsAuth) {
|
|
12396
|
+
var sLabel = d.authenticated
|
|
12397
|
+
? (d.email ? 'Connected as ' + d.email : 'Connected via ' + (d.apiKeySource || 'API'))
|
|
12398
|
+
: '';
|
|
12374
12399
|
settingsAuth.innerHTML = d.authenticated
|
|
12375
|
-
? '<span style="color:var(--green)">
|
|
12400
|
+
? '<span style="color:var(--green)">' + sLabel + '</span>'
|
|
12376
12401
|
: '<span style="color:var(--text-muted)">Not connected</span>';
|
|
12377
12402
|
}
|
|
12378
12403
|
return d;
|
|
@@ -12382,6 +12407,23 @@ async function checkAnthropicAuth() {
|
|
|
12382
12407
|
async function startAnthropicOAuth() {
|
|
12383
12408
|
var btn = document.getElementById('gs-auth-btn');
|
|
12384
12409
|
var desc = document.getElementById('gs-auth-desc');
|
|
12410
|
+
// Precheck: if the user is already authenticated (env var or keychain),
|
|
12411
|
+
// don't trigger the SDK OAuth flow — which has an upstream bug where
|
|
12412
|
+
// claudeAuthenticate sends a malformed Messages API request with
|
|
12413
|
+
// cache_control on an empty text block (HTTP 400).
|
|
12414
|
+
try {
|
|
12415
|
+
var statusResp = await apiFetch('/api/auth/anthropic/status');
|
|
12416
|
+
var statusData = await statusResp.json();
|
|
12417
|
+
if (statusData && statusData.authenticated) {
|
|
12418
|
+
var card = document.getElementById('gs-step-auth');
|
|
12419
|
+
if (card) card.className = 'gs-card gs-done';
|
|
12420
|
+
if (desc) desc.textContent = statusData.email
|
|
12421
|
+
? 'Connected as ' + statusData.email
|
|
12422
|
+
: 'Already connected via ' + (statusData.apiKeySource || 'API') + ' — no login needed';
|
|
12423
|
+
if (btn) { btn.textContent = 'Connected'; btn.disabled = true; }
|
|
12424
|
+
return;
|
|
12425
|
+
}
|
|
12426
|
+
} catch (_) { /* fall through to real login */ }
|
|
12385
12427
|
if (btn) { btn.textContent = 'Opening login...'; btn.disabled = true; }
|
|
12386
12428
|
try {
|
|
12387
12429
|
var r = await apiFetch('/api/auth/anthropic/login', { method: 'POST' });
|
|
@@ -12402,7 +12444,15 @@ async function startAnthropicOAuth() {
|
|
|
12402
12444
|
throw new Error(wd.error || 'Login did not complete');
|
|
12403
12445
|
}
|
|
12404
12446
|
} catch (err) {
|
|
12405
|
-
|
|
12447
|
+
// Special case: the SDK's claudeAuthenticate has a known bug where it
|
|
12448
|
+
// sends malformed API payloads ("cache_control cannot be set for empty
|
|
12449
|
+
// text blocks"). If that fires, point the user at the CLI login path.
|
|
12450
|
+
var msg = err && err.message ? err.message : String(err);
|
|
12451
|
+
if (/cache_control.+empty text blocks/i.test(msg)) {
|
|
12452
|
+
if (desc) desc.textContent = 'In-browser login hit a known SDK bug. Run "clementine login" in your terminal instead, or check if you are already logged in — the daemon only needs to start once.';
|
|
12453
|
+
} else {
|
|
12454
|
+
if (desc) desc.textContent = 'Login failed: ' + msg;
|
|
12455
|
+
}
|
|
12406
12456
|
if (btn) { btn.textContent = 'Retry Login'; btn.disabled = false; }
|
|
12407
12457
|
}
|
|
12408
12458
|
}
|