ai-agent-config 2.6.0 → 2.6.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-agent-config",
3
- "version": "2.6.0",
3
+ "version": "2.6.2",
4
4
  "description": "Universal skill & workflow manager for AI coding assistants with bi-directional GitHub sync",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -9,7 +9,6 @@ const { execSync, spawnSync } = require("child_process");
9
9
  const os = require("os");
10
10
 
11
11
  const HOME = os.homedir();
12
- const BITWARDEN_FOLDER = "MCP Secrets";
13
12
 
14
13
  /**
15
14
  * Validate that Bitwarden CLI is installed
@@ -152,6 +151,49 @@ function unlockBitwarden(password) {
152
151
  }
153
152
  }
154
153
 
154
+ /**
155
+ * Try to reuse BW_SESSION from Antigravity MCP config
156
+ * This prevents creating a new session that would invalidate the MCP server's session
157
+ * @returns {{ success: boolean, sessionKey?: string, reason?: string }}
158
+ */
159
+ function tryReuseAntigravitySession() {
160
+ const platforms = require("./platforms");
161
+ const antigravity = platforms.getByName("antigravity");
162
+
163
+ if (!antigravity || !antigravity.mcpConfigPath) {
164
+ return { success: false, reason: "Antigravity not configured" };
165
+ }
166
+
167
+ if (!fs.existsSync(antigravity.mcpConfigPath)) {
168
+ return { success: false, reason: "mcp_config.json not found" };
169
+ }
170
+
171
+ try {
172
+ const mcpConfig = JSON.parse(fs.readFileSync(antigravity.mcpConfigPath, "utf-8"));
173
+ const bitwardenServer = mcpConfig.mcpServers?.bitwarden;
174
+
175
+ if (!bitwardenServer || !bitwardenServer.env || !bitwardenServer.env.BW_SESSION) {
176
+ return { success: false, reason: "No BW_SESSION in bitwarden MCP config" };
177
+ }
178
+
179
+ const sessionKey = bitwardenServer.env.BW_SESSION;
180
+
181
+ // Validate session by trying to list folders
182
+ const testResult = spawnSync("bw", ["list", "folders", "--session", sessionKey], {
183
+ encoding: "utf-8",
184
+ stdio: ["pipe", "pipe", "pipe"],
185
+ });
186
+
187
+ if (testResult.status === 0) {
188
+ return { success: true, sessionKey };
189
+ } else {
190
+ return { success: false, reason: "Session expired or invalid" };
191
+ }
192
+ } catch (error) {
193
+ return { success: false, reason: `Failed to read config: ${error.message}` };
194
+ }
195
+ }
196
+
155
197
  /**
156
198
  * Discover required secrets from MCP server configs in the repo
157
199
  * Scans .agent/mcp-servers/{name}/config.json for bitwardenEnv fields
@@ -176,7 +218,7 @@ function discoverRequiredSecrets() {
176
218
 
177
219
  /**
178
220
  * Fetch secrets from Bitwarden vault
179
- * Only searches in "MCP Secrets" folder
221
+ * Searches entire vault (all folders) for matching items
180
222
  */
181
223
  function fetchSecretsFromBitwarden(sessionKey, secretNames) {
182
224
  const results = {
@@ -185,38 +227,47 @@ function fetchSecretsFromBitwarden(sessionKey, secretNames) {
185
227
  };
186
228
 
187
229
  try {
188
- // Step 1: Get folder ID for "MCP Secrets"
189
- const foldersJson = execSync(`bw list folders --session ${sessionKey}`, {
190
- encoding: "utf-8",
191
- stdio: ["pipe", "pipe", "pipe"],
192
- });
193
- const folders = JSON.parse(foldersJson);
194
- const mcpFolder = folders.find((f) => f.name === BITWARDEN_FOLDER);
195
-
196
- if (!mcpFolder) {
197
- console.warn(`\n⚠️ Folder "${BITWARDEN_FOLDER}" not found in Bitwarden vault`);
198
- console.warn(` Create folder "${BITWARDEN_FOLDER}" and add your secrets there\n`);
199
- // All secrets are missing since folder doesn't exist
200
- secretNames.forEach((name) => results.missing.push(name));
201
- return results;
202
- }
203
-
204
- // Step 2: List all items in "MCP Secrets" folder
205
- const itemsJson = execSync(`bw list items --folderid ${mcpFolder.id} --session ${sessionKey}`, {
230
+ // List all items in the vault (across all folders)
231
+ const itemsJson = execSync(`bw list items --session ${sessionKey}`, {
206
232
  encoding: "utf-8",
207
233
  stdio: ["pipe", "pipe", "pipe"],
208
234
  });
209
235
  const items = JSON.parse(itemsJson);
210
236
 
211
- // Step 3: Match secrets by name
237
+ // Match secrets by name
212
238
  for (const secretName of secretNames) {
213
239
  const item = items.find((i) => i.name === secretName);
214
240
 
215
- if (item && item.login && item.login.password) {
216
- results.found.push({
217
- name: secretName,
218
- value: item.login.password,
219
- });
241
+ if (item) {
242
+ // Try multiple sources for the secret value
243
+ let secretValue = null;
244
+
245
+ // Priority 1: Login password (most common for API keys)
246
+ if (item.login && item.login.password) {
247
+ secretValue = item.login.password;
248
+ }
249
+ // Priority 2: Secure note content
250
+ else if (item.notes && item.notes.trim()) {
251
+ secretValue = item.notes.trim();
252
+ }
253
+ // Priority 3: Custom field named "value" or "secret"
254
+ else if (item.fields && item.fields.length > 0) {
255
+ const valueField = item.fields.find(
256
+ (f) => f.name.toLowerCase() === "value" || f.name.toLowerCase() === "secret"
257
+ );
258
+ if (valueField && valueField.value) {
259
+ secretValue = valueField.value;
260
+ }
261
+ }
262
+
263
+ if (secretValue) {
264
+ results.found.push({
265
+ name: secretName,
266
+ value: secretValue,
267
+ });
268
+ } else {
269
+ results.missing.push(secretName);
270
+ }
220
271
  } else {
221
272
  results.missing.push(secretName);
222
273
  }
@@ -291,6 +342,7 @@ function writeToShellProfile(secrets) {
291
342
  */
292
343
  async function syncSecrets() {
293
344
  let sessionKey = null;
345
+ let sessionSource = null; // Track where session came from: "reused" or "new"
294
346
 
295
347
  try {
296
348
  console.log("\n🔐 Bitwarden Secret Sync\n");
@@ -309,22 +361,36 @@ async function syncSecrets() {
309
361
  process.exit(1);
310
362
  }
311
363
 
312
- // 3. Prompt for password
313
- const password = await promptPassword();
364
+ // 3. Try to reuse existing session from Antigravity MCP
365
+ console.log("🔄 Checking for existing Bitwarden session...");
366
+ const reuseResult = tryReuseAntigravitySession();
314
367
 
315
- // 4. Unlock vault
316
- console.log("\n🔓 Unlocking vault...");
317
- const unlockResult = unlockBitwarden(password);
368
+ if (reuseResult.success) {
369
+ console.log("✓ Reusing session from Antigravity MCP config\n");
370
+ sessionKey = reuseResult.sessionKey;
371
+ sessionSource = "reused";
372
+ } else {
373
+ console.log(` ⊗ ${reuseResult.reason}`);
374
+ console.log(" → Creating new session\n");
318
375
 
319
- if (!unlockResult.success) {
320
- console.error(`❌ ${unlockResult.message}\n`);
321
- process.exit(1);
322
- }
376
+ // 4. Fallback: Prompt for password
377
+ const password = await promptPassword();
378
+
379
+ // 5. Unlock vault
380
+ console.log("\n🔓 Unlocking vault...");
381
+ const unlockResult = unlockBitwarden(password);
323
382
 
324
- console.log("✓ Vault unlocked\n");
325
- sessionKey = unlockResult.sessionKey;
383
+ if (!unlockResult.success) {
384
+ console.error(`❌ ${unlockResult.message}\n`);
385
+ process.exit(1);
386
+ }
387
+
388
+ console.log("✓ Vault unlocked\n");
389
+ sessionKey = unlockResult.sessionKey;
390
+ sessionSource = "new";
391
+ }
326
392
 
327
- // 5. Discover required secrets from repo's bitwardenEnv
393
+ // 6. Discover required secrets from repo's bitwardenEnv
328
394
  console.log("🔍 Scanning MCP server configs for required secrets...");
329
395
  const discovery = discoverRequiredSecrets();
330
396
 
@@ -344,8 +410,8 @@ async function syncSecrets() {
344
410
  console.log(` • ${name}`);
345
411
  });
346
412
 
347
- // 6. Fetch secrets from Bitwarden
348
- console.log(`\n🔐 Fetching from Bitwarden (folder: ${BITWARDEN_FOLDER})...`);
413
+ // 7. Fetch secrets from Bitwarden
414
+ console.log(`\n🔐 Fetching from Bitwarden vault...`);
349
415
  const fetchResults = fetchSecretsFromBitwarden(sessionKey, discovery.secrets);
350
416
 
351
417
  fetchResults.found.forEach((secret) => {
@@ -383,18 +449,19 @@ async function syncSecrets() {
383
449
 
384
450
  if (fetchResults.missing.length > 0) {
385
451
  console.log(`⚠️ Missing secrets: ${fetchResults.missing.join(", ")}`);
386
- console.log(` Add them to Bitwarden vault folder "${BITWARDEN_FOLDER}"\n`);
452
+ console.log(` Add them to your Bitwarden vault\n`);
387
453
  }
388
454
  } finally {
389
- // Cleanup: Lock vault to invalidate session key
390
- if (sessionKey) {
455
+ // Cleanup: Only lock if we created a new session
456
+ // Don't lock if we reused the session - let MCP keep using it
457
+ if (sessionKey && sessionSource === "new") {
391
458
  try {
392
459
  execSync("bw lock", { stdio: "pipe" });
393
460
  } catch (e) {
394
461
  // Silent fail - vault may already be locked
395
462
  }
396
- sessionKey = null;
397
463
  }
464
+ sessionKey = null;
398
465
  }
399
466
  }
400
467