clementine-agent 1.0.40 → 1.0.41

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.
@@ -694,10 +694,29 @@ export class PersonalAssistant {
694
694
  /** Capture MCP server status from system init messages. */
695
695
  captureMcpStatus(message) {
696
696
  const sysMsg = message;
697
- if (sysMsg.subtype === 'init' && sysMsg.mcp_servers) {
697
+ if (sysMsg.subtype !== 'init')
698
+ return;
699
+ if (sysMsg.mcp_servers) {
698
700
  this._lastMcpStatus = sysMsg.mcp_servers;
699
701
  this._lastMcpStatusTime = new Date().toISOString();
700
702
  }
703
+ // Auto-register Claude Desktop integrations from the authoritative tool
704
+ // list the SDK reports on init. Previously the claude-integrations file
705
+ // was written reactively — only after the agent successfully called an
706
+ // integration tool — which meant a freshly-connected Google Drive or
707
+ // Gmail was invisible until used. Now every session-init rewrites the
708
+ // list to match reality.
709
+ if (Array.isArray(sysMsg.tools) && sysMsg.tools.length > 0 && _mcpBridge) {
710
+ try {
711
+ const { added, updated } = _mcpBridge.registerClaudeIntegrationsFromToolList(sysMsg.tools);
712
+ if (added.length > 0 || updated.length > 0) {
713
+ logger.info({ added, updated }, 'Registered Claude Desktop integrations from SDK tool inventory');
714
+ }
715
+ }
716
+ catch (err) {
717
+ logger.debug({ err }, 'Integration auto-registration failed (non-fatal)');
718
+ }
719
+ }
701
720
  }
702
721
  setUnleashedCompleteCallback(cb) {
703
722
  this.onUnleashedComplete = cb;
@@ -54,6 +54,21 @@ export declare function loadClaudeIntegrations(): Record<string, ClaudeIntegrati
54
54
  export declare function recordClaudeIntegrationUse(toolName: string): void;
55
55
  /** Get all discovered Claude Desktop integrations as a list. */
56
56
  export declare function getClaudeIntegrations(): ClaudeIntegration[];
57
+ /**
58
+ * Register every integration found in a tool inventory. The SDK's system
59
+ * init message (subtype='init') includes a `tools: string[]` with the full
60
+ * set of tools the agent actually has access to this session — including
61
+ * every mcp__claude_ai_* tool Claude Desktop is surfacing. Walking that
62
+ * list on init gives us the authoritative, up-to-date integration set
63
+ * without waiting for the agent to blindly try each one.
64
+ *
65
+ * Idempotent: if an entry already exists, we merge new tool names into it
66
+ * and bump `connected = true` without touching firstSeen/lastUsed.
67
+ */
68
+ export declare function registerClaudeIntegrationsFromToolList(tools: string[]): {
69
+ added: string[];
70
+ updated: string[];
71
+ };
57
72
  /**
58
73
  * Bootstrap integrations from the audit log.
59
74
  * Call once on startup to seed the integrations file from historical data.
@@ -384,6 +384,60 @@ export function recordClaudeIntegrationUse(toolName) {
384
384
  export function getClaudeIntegrations() {
385
385
  return Object.values(loadClaudeIntegrations());
386
386
  }
387
+ /**
388
+ * Register every integration found in a tool inventory. The SDK's system
389
+ * init message (subtype='init') includes a `tools: string[]` with the full
390
+ * set of tools the agent actually has access to this session — including
391
+ * every mcp__claude_ai_* tool Claude Desktop is surfacing. Walking that
392
+ * list on init gives us the authoritative, up-to-date integration set
393
+ * without waiting for the agent to blindly try each one.
394
+ *
395
+ * Idempotent: if an entry already exists, we merge new tool names into it
396
+ * and bump `connected = true` without touching firstSeen/lastUsed.
397
+ */
398
+ export function registerClaudeIntegrationsFromToolList(tools) {
399
+ const added = [];
400
+ const updated = [];
401
+ if (!Array.isArray(tools) || tools.length === 0)
402
+ return { added, updated };
403
+ const integrations = loadClaudeIntegrations();
404
+ const now = new Date().toISOString();
405
+ let dirty = false;
406
+ for (const toolName of tools) {
407
+ const parsed = parseClaudeDesktopTool(toolName);
408
+ if (!parsed)
409
+ continue;
410
+ const existing = integrations[parsed.integration];
411
+ if (existing) {
412
+ if (!existing.tools.includes(parsed.tool)) {
413
+ existing.tools.push(parsed.tool);
414
+ existing.tools.sort();
415
+ dirty = true;
416
+ }
417
+ if (!existing.connected) {
418
+ existing.connected = true;
419
+ dirty = true;
420
+ }
421
+ if (!updated.includes(parsed.integration))
422
+ updated.push(parsed.integration);
423
+ }
424
+ else {
425
+ integrations[parsed.integration] = {
426
+ name: parsed.integration,
427
+ label: INTEGRATION_LABELS[parsed.integration] ?? parsed.integration.replace(/_/g, ' '),
428
+ tools: [parsed.tool],
429
+ firstSeen: now,
430
+ lastUsed: now,
431
+ connected: true,
432
+ };
433
+ added.push(parsed.integration);
434
+ dirty = true;
435
+ }
436
+ }
437
+ if (dirty)
438
+ saveClaudeIntegrations(integrations);
439
+ return { added, updated };
440
+ }
387
441
  /**
388
442
  * Bootstrap integrations from the audit log.
389
443
  * Call once on startup to seed the integrations file from historical data.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clementine-agent",
3
- "version": "1.0.40",
3
+ "version": "1.0.41",
4
4
  "description": "Clementine — Personal AI Assistant (TypeScript)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",