clementine-agent 1.0.52 → 1.0.54

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.
@@ -1093,7 +1093,9 @@ The **only source of truth for tool availability is your function schema**. Do n
1093
1093
 
1094
1094
  **Never** say the tool "isn't loaded in this session," "doesn't carry over from Claude Desktop," "the tools array is empty," or "MCP server still connecting." If any of those phrasings come to mind, call the tool directly and report what actually happens instead.
1095
1095
 
1096
- \`list_allowed_tools\` / \`disallow_tool\` manage the whitelist. \`integration_status\` is for env-var (API key) integrations — not for claude_ai_* connectors, which are schema-driven.
1096
+ \`list_allowed_tools\` / \`disallow_tool\` manage the whitelist. \`integration_status\` is for env-var (API key) integrations — **not** for claude_ai_* connectors, which are schema-driven. Don't use \`integration_status\` as a proxy for "can I call Drive / Gmail / etc." — those are always tried by direct tool call, not status lookup.
1097
+
1098
+ **Critical rule: if the user asks you to use a claude_ai_* connector, you call the connector tool. Full stop.** Do not report "I tried and it failed" unless there was an actual tool call that returned an actual error — your audit log records every tool call, so narrating a failed attempt when the audit shows no call will be spotted.
1097
1099
 
1098
1100
  ## Context Window Management
1099
1101
 
@@ -1332,7 +1334,8 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
1332
1334
  if (!isAutonomous) {
1333
1335
  try {
1334
1336
  const { summarizeIntegrationStatus } = require('../config/integrations-registry.js');
1335
- const summary = summarizeIntegrationStatus(process.env);
1337
+ const { envSnapshot } = require('../config.js');
1338
+ const summary = summarizeIntegrationStatus(envSnapshot());
1336
1339
  if (summary)
1337
1340
  parts.push(`## Integration Status\n\n${summary}\n\nCall \`integration_status\`, \`list_integrations\`, or \`setup_integration\` for details.`);
1338
1341
  }
@@ -1613,13 +1616,16 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
1613
1616
  type: 'stdio',
1614
1617
  command: 'node',
1615
1618
  args: [MCP_SERVER_SCRIPT],
1619
+ // Spread process.env so the MCP subprocess sees the full environment
1620
+ // the daemon is running with — API keys hydrated from .env/Keychain,
1621
+ // PATH, HOME, etc. Without this, tools that inspect env vars
1622
+ // (integration_status, Outlook/Graph, Salesforce) see only the
1623
+ // handful we pass and report everything as "missing." Our explicit
1624
+ // keys come after the spread so we always win on overlaps.
1616
1625
  env: {
1626
+ ...process.env,
1617
1627
  CLEMENTINE_HOME: BASE_DIR,
1618
1628
  CLEMENTINE_TEAM_AGENT: profile?.slug ?? 'clementine',
1619
- // Propagate interaction-source so the MCP subprocess can gate
1620
- // owner-only tools. Without this, getInteractionSource() inside
1621
- // the subprocess returns the module-default 'autonomous' and
1622
- // every owner-DM-gated tool (env_set, allow_tool, etc.) refuses.
1623
1629
  CLEMENTINE_INTERACTION_SOURCE: sourceOverride ?? inferInteractionSource(sessionKey),
1624
1630
  },
1625
1631
  },
@@ -3071,6 +3077,7 @@ You have a cost budget per message — not a hard turn limit. Work until the tas
3071
3077
  command: 'node',
3072
3078
  args: [MCP_SERVER_SCRIPT],
3073
3079
  env: {
3080
+ ...process.env,
3074
3081
  CLEMENTINE_HOME: BASE_DIR,
3075
3082
  CLEMENTINE_TEAM_AGENT: profile?.slug ?? 'clementine',
3076
3083
  // Auto-memory extractor runs autonomously.
package/dist/config.d.ts CHANGED
@@ -10,6 +10,8 @@ import type { Models } from './types.js';
10
10
  export declare const PKG_DIR: string;
11
11
  /** Data home — user data, vault, .env, logs, sessions. */
12
12
  export declare const BASE_DIR: string;
13
+ /** Merged view of process.env overlaid with .env. Use for classifyIntegrations / summarizeIntegrationStatus. */
14
+ export declare function envSnapshot(): Record<string, string | undefined>;
13
15
  export declare const VAULT_DIR: string;
14
16
  export declare const SYSTEM_DIR: string;
15
17
  export declare const DAILY_NOTES_DIR: string;
package/dist/config.js CHANGED
@@ -46,6 +46,10 @@ const env = readEnvFile();
46
46
  function getEnv(key, fallback = '') {
47
47
  return env[key] ?? process.env[key] ?? fallback;
48
48
  }
49
+ /** Merged view of process.env overlaid with .env. Use for classifyIntegrations / summarizeIntegrationStatus. */
50
+ export function envSnapshot() {
51
+ return { ...process.env, ...env };
52
+ }
49
53
  // ── Paths ────────────────────────────────────────────────────────────
50
54
  export const VAULT_DIR = path.join(BASE_DIR, 'vault');
51
55
  export const SYSTEM_DIR = path.join(VAULT_DIR, '00-System');
@@ -217,7 +217,14 @@ export function registerAdminTools(server) {
217
217
  slug: z.string().optional().describe('Optional: specific integration slug to check (e.g. "slack"). If omitted, returns all.'),
218
218
  }, async ({ slug }) => {
219
219
  const slugs = slug ? [slug] : undefined;
220
- const reports = classifyIntegrations(process.env, slugs);
220
+ // `env` from shared.ts is the parsed .env file — the authoritative source
221
+ // for configured credentials in this project. Falls through to process.env
222
+ // for anything overridden at runtime (keychain-hydrated secrets, shell
223
+ // env, etc.). Do NOT read process.env alone: config.ts deliberately
224
+ // keeps .env values out of process.env, so classifying from process.env
225
+ // shows everything "missing."
226
+ const merged = { ...process.env, ...env };
227
+ const reports = classifyIntegrations(merged, slugs);
221
228
  if (reports.length === 0)
222
229
  return textResult(`Unknown integration slug: ${slug}. Use list_integrations to see available.`);
223
230
  const icon = (s) => s === 'configured' ? '✓' : s === 'partial' ? '~' : '✗';
@@ -248,7 +255,8 @@ export function registerAdminTools(server) {
248
255
  if (!integration) {
249
256
  return textResult(`Unknown integration slug: ${slug}. Run list_integrations to see what's available.`);
250
257
  }
251
- const [status] = classifyIntegrations(process.env, [integration.slug]);
258
+ const merged = { ...process.env, ...env };
259
+ const [status] = classifyIntegrations(merged, [integration.slug]);
252
260
  const lines = [];
253
261
  lines.push(`## ${integration.label} (${integration.slug})`);
254
262
  lines.push('');
@@ -262,7 +270,7 @@ export function registerAdminTools(server) {
262
270
  lines.push('');
263
271
  lines.push('**Credentials:**');
264
272
  for (const req of integration.requirements) {
265
- const present = !!process.env[req.envVar];
273
+ const present = !!merged[req.envVar];
266
274
  const badge = present ? '✓ set' : (req.required ? '✗ REQUIRED' : '○ optional');
267
275
  const line = `- \`${req.envVar}\` — ${req.label} [${badge}]`;
268
276
  lines.push(line);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clementine-agent",
3
- "version": "1.0.52",
3
+ "version": "1.0.54",
4
4
  "description": "Clementine — Personal AI Assistant (TypeScript)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",