clementine-agent 1.0.37 → 1.0.40
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.
- package/dist/agent/assistant.js +30 -2
- package/dist/agent/mcp-bridge.js +6 -1
- package/dist/cli/dashboard.js +16 -5
- package/package.json +1 -1
package/dist/agent/assistant.js
CHANGED
|
@@ -1046,12 +1046,40 @@ Delegate data-heavy work (SEO, analytics, bulk API calls for 3+ entities) to sub
|
|
|
1046
1046
|
Never spawn a sub-agent with vague instructions like "handle this brief" — tell it exactly what to read, what to change, and where to write the result.
|
|
1047
1047
|
`);
|
|
1048
1048
|
}
|
|
1049
|
-
// Inject Claude Desktop integration awareness
|
|
1049
|
+
// Inject Claude Desktop integration awareness. Two lists:
|
|
1050
|
+
// - Known-confirmed: integrations the agent has actually used before
|
|
1051
|
+
// (persisted in claude-integrations.json). High confidence.
|
|
1052
|
+
// - Possibly-available: common integrations the owner may have connected
|
|
1053
|
+
// at claude.ai level that we don't have a usage record for yet. The
|
|
1054
|
+
// integrations-file is written reactively — only entries with
|
|
1055
|
+
// successful tool uses get captured — so a freshly-connected
|
|
1056
|
+
// Google Drive / Gmail / Slack connector is invisible to us until we
|
|
1057
|
+
// try it. Hint the agent that it can try these blindly; the tool
|
|
1058
|
+
// call will either succeed or return an auth error, at which point
|
|
1059
|
+
// the record gets captured.
|
|
1050
1060
|
try {
|
|
1051
1061
|
const integrations = _mcpBridge?.getClaudeIntegrations() ?? [];
|
|
1062
|
+
const knownNames = new Set(integrations.map(ig => ig.name));
|
|
1052
1063
|
if (integrations.length > 0) {
|
|
1053
1064
|
const names = integrations.map(ig => ig.label).join(', ');
|
|
1054
|
-
parts.push(`**Connected via Claude Desktop:** ${names}. Use their \`mcp__claude_ai_*\` tools
|
|
1065
|
+
parts.push(`**Connected via Claude Desktop:** ${names}. Use their \`mcp__claude_ai_*\` tools (e.g. \`mcp__claude_ai_Google_Drive__search_files\`).`);
|
|
1066
|
+
}
|
|
1067
|
+
// Common integrations to speculatively mention. If the owner has
|
|
1068
|
+
// connected any of these at claude.ai, the corresponding tool names
|
|
1069
|
+
// will work even if no prior record exists.
|
|
1070
|
+
const SPECULATIVE = [
|
|
1071
|
+
['Google_Drive', 'Google Drive'], ['Gmail', 'Gmail'],
|
|
1072
|
+
['Google_Calendar', 'Google Calendar'], ['Google_Workspace', 'Google Workspace'],
|
|
1073
|
+
['Slack', 'Slack'], ['Notion', 'Notion'], ['GitHub', 'GitHub'],
|
|
1074
|
+
['Linear', 'Linear'], ['Asana', 'Asana'], ['Jira', 'Jira'],
|
|
1075
|
+
['Dropbox', 'Dropbox'], ['Salesforce', 'Salesforce'],
|
|
1076
|
+
['Microsoft_365', 'Microsoft 365'],
|
|
1077
|
+
];
|
|
1078
|
+
const maybe = SPECULATIVE.filter(([name]) => !knownNames.has(name)).map(([, label]) => label);
|
|
1079
|
+
if (maybe.length > 0) {
|
|
1080
|
+
parts.push(`**Possibly connected (try them — they'll either work or return an auth error):** ${maybe.join(', ')}. ` +
|
|
1081
|
+
`Tool names follow \`mcp__claude_ai_<IntegrationName>__<tool>\` — e.g. \`mcp__claude_ai_Google_Drive__search_files\`, \`mcp__claude_ai_Gmail__authenticate\`. ` +
|
|
1082
|
+
`Don't tell ${owner} an integration is "not available" without first attempting the tool call — a fresh connection won't be in your recorded list until after first use.`);
|
|
1055
1083
|
}
|
|
1056
1084
|
}
|
|
1057
1085
|
catch { /* non-fatal */ }
|
package/dist/agent/mcp-bridge.js
CHANGED
|
@@ -329,7 +329,12 @@ function parseClaudeDesktopTool(toolName) {
|
|
|
329
329
|
const match = toolName.match(/^mcp__claude_ai_([^_]+(?:_[^_]+)*)__(.+)$/);
|
|
330
330
|
if (!match)
|
|
331
331
|
return null;
|
|
332
|
-
|
|
332
|
+
const raw = match[1];
|
|
333
|
+
// Normalize against the known canonical set (case-insensitive) so we don't
|
|
334
|
+
// create both `Microsoft_365` and `microsoft_365` entries when the SDK
|
|
335
|
+
// occasionally hands us a lowercased tool name.
|
|
336
|
+
const canonical = Object.keys(INTEGRATION_LABELS).find(k => k.toLowerCase() === raw.toLowerCase()) ?? raw;
|
|
337
|
+
return { integration: canonical, tool: match[2] };
|
|
333
338
|
}
|
|
334
339
|
/** Load persisted integrations from disk. */
|
|
335
340
|
export function loadClaudeIntegrations() {
|
package/dist/cli/dashboard.js
CHANGED
|
@@ -1159,6 +1159,17 @@ function writeCronFileAt(cronFile, parsed, jobs) {
|
|
|
1159
1159
|
}
|
|
1160
1160
|
// ── Express app ──────────────────────────────────────────────────────
|
|
1161
1161
|
export async function cmdDashboard(opts) {
|
|
1162
|
+
// Ensure BASE_DIR exists before any dashboard-local files (PID file, auth
|
|
1163
|
+
// token) are written. Other CLI commands route through ensureDataHome() in
|
|
1164
|
+
// index.ts, but the dashboard command doesn't — on a truly fresh install
|
|
1165
|
+
// where someone runs `clementine dashboard` before `clementine launch` or
|
|
1166
|
+
// `config setup`, the parent-process writeFileSync(DASHBOARD_PID_FILE)
|
|
1167
|
+
// would ENOENT and the dashboard would die before the browser could see
|
|
1168
|
+
// it. Idempotent, so safe for every invocation.
|
|
1169
|
+
try {
|
|
1170
|
+
mkdirSync(BASE_DIR, { recursive: true });
|
|
1171
|
+
}
|
|
1172
|
+
catch { /* ignore */ }
|
|
1162
1173
|
// Child process skips the kill step — parent already handled it
|
|
1163
1174
|
if (!process.env.__CLEM_DASHBOARD_CHILD) {
|
|
1164
1175
|
const killed = killExistingDashboards();
|
|
@@ -9328,7 +9339,7 @@ if('serviceWorker' in navigator){navigator.serviceWorker.getRegistrations().then
|
|
|
9328
9339
|
const wmHtml = a.workingMemorySnippet
|
|
9329
9340
|
? '<div style="margin-top:8px;padding:8px;background:var(--bg-input);border-radius:6px;font-size:11px;color:var(--text-secondary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap">' + a.workingMemorySnippet + '</div>'
|
|
9330
9341
|
: '';
|
|
9331
|
-
return '<div style="background:var(--bg-card);border:1px solid var(--border);border-radius:12px;padding:16px;cursor:pointer" onclick="showPage(
|
|
9342
|
+
return '<div style="background:var(--bg-card);border:1px solid var(--border);border-radius:12px;padding:16px;cursor:pointer" onclick="showPage(\\'team\\');setTimeout(()=>selectAgent(\\''+a.slug+'\\'),100)">' +
|
|
9332
9343
|
'<div style="display:flex;align-items:center;gap:10px;margin-bottom:10px">' +
|
|
9333
9344
|
'<div style="width:40px;height:40px;border-radius:50%;background:var(--clementine);color:#fff;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:18px">' + avatarLetter + '</div>' +
|
|
9334
9345
|
'<div><div style="font-weight:600">' + (a.name || a.slug) + '</div>' +
|
|
@@ -16480,11 +16491,11 @@ async function applyBrokenJobFix(jobName) {
|
|
|
16480
16491
|
return;
|
|
16481
16492
|
}
|
|
16482
16493
|
var diffPreview = (dryRes.diff || '(no diff)').slice(0, 1200);
|
|
16483
|
-
var msg = 'Apply this fix to ' + jobName + '
|
|
16484
|
-
+ 'File: ' + (dryRes.file || 'unknown') + '
|
|
16485
|
-
+ 'Operations: ' + (dryRes.appliedOps || []).length + '
|
|
16494
|
+
var msg = 'Apply this fix to ' + jobName + '?\\n\\n'
|
|
16495
|
+
+ 'File: ' + (dryRes.file || 'unknown') + '\\n'
|
|
16496
|
+
+ 'Operations: ' + (dryRes.appliedOps || []).length + '\\n\\n'
|
|
16486
16497
|
+ diffPreview
|
|
16487
|
-
+ '
|
|
16498
|
+
+ '\\n\\nA .bak will be written. The daemon auto-reloads; the next run will be fix-verified.';
|
|
16488
16499
|
if (!confirm(msg)) return;
|
|
16489
16500
|
|
|
16490
16501
|
var res = await apiJson('POST', '/api/cron/broken-jobs/' + encodeURIComponent(jobName) + '/apply-fix', {});
|