borgmcp 0.7.2 → 0.7.3

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/config.d.ts CHANGED
@@ -1,33 +1,31 @@
1
1
  /**
2
- * Secure token storage using OS keychain
3
- * Uses Keytar for cross-platform credential management
4
- *
5
- * Addresses consensus finding: Machine-specific encryption is insecure
6
- * Solution: Use OS native keychains (macOS Keychain, Windows Credential Manager, Linux Secret Service)
7
- */
8
- /**
9
- * Store Google OAuth ID token securely in OS keychain
2
+ * Store Google OAuth ID token securely in the OS keychain.
10
3
  */
11
4
  export declare function storeIdToken(idToken: string, expiresAt: number): Promise<void>;
12
5
  /**
13
- * Store Google OAuth refresh token securely in OS keychain
6
+ * Store Google OAuth refresh token securely in the OS keychain.
14
7
  */
15
8
  export declare function storeRefreshToken(refreshToken: string): Promise<void>;
16
9
  /**
17
- * Retrieve Google OAuth ID token from OS keychain
18
- * Returns null if not found or expired
10
+ * Retrieve the Google OAuth ID token from the OS keychain.
11
+ * Returns null if not stored or expired (5-minute buffer).
12
+ *
13
+ * `getPassword` on a missing entry returns null/undefined depending
14
+ * on platform binding; normalize with `?? null` so the caller
15
+ * contract (`string | null`) is platform-stable.
19
16
  */
20
17
  export declare function getIdToken(): Promise<string | null>;
21
18
  /**
22
- * Retrieve Google OAuth refresh token from OS keychain
19
+ * Retrieve the Google OAuth refresh token from the OS keychain.
23
20
  */
24
21
  export declare function getRefreshToken(): Promise<string | null>;
25
22
  /**
26
- * Clear all stored tokens from OS keychain
23
+ * Clear all stored tokens from the OS keychain. Idempotent — calling
24
+ * on an already-empty keychain is a no-op (NoEntry errors absorbed).
27
25
  */
28
26
  export declare function clearTokens(): Promise<void>;
29
27
  /**
30
- * Check if user has valid authentication
28
+ * Check if user has valid authentication.
31
29
  */
32
30
  export declare function isAuthenticated(): Promise<boolean>;
33
31
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAUH;;GAEG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGpF;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE3E;AAED;;;GAGG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiBzD;AAED;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAE9D;AAED;;GAEG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAIjD;AAED;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC,CAGxD"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAuDA;;GAEG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGpF;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE3E;AAED;;;;;;;GAOG;AACH,wBAAsB,UAAU,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiBzD;AAED;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAE9D;AAED;;;GAGG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAIjD;AAED;;GAEG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC,CAGxD"}
package/dist/config.js CHANGED
@@ -1,62 +1,107 @@
1
1
  /**
2
- * Secure token storage using OS keychain
3
- * Uses Keytar for cross-platform credential management
2
+ * Secure token storage using OS keychain.
4
3
  *
5
- * Addresses consensus finding: Machine-specific encryption is insecure
6
- * Solution: Use OS native keychains (macOS Keychain, Windows Credential Manager, Linux Secret Service)
4
+ * Uses @napi-rs/keyring (NAPI-RS binding over the Rust `keyring-rs`
5
+ * crate) for cross-platform credential storage:
6
+ * - macOS: Keychain Services
7
+ * - Windows: Credential Vault (Credential Manager)
8
+ * - Linux: Secret Service (libsecret / gnome-keyring)
9
+ *
10
+ * Migrated from `keytar` in 0.7.2 (gh#22). Same encryption-at-rest
11
+ * shape as keytar (delegates to the platform's native keychain
12
+ * service); eliminates the maintenance-orphaned keytar + prebuild-
13
+ * install dependency chain.
14
+ *
15
+ * `AsyncEntry` is used (over the sync `Entry` class) so the public
16
+ * API surface — every function below is `async` — stays identical
17
+ * to the pre-migration shape. No call sites needed to change.
7
18
  */
8
- import keytar from 'keytar';
19
+ import { AsyncEntry } from '@napi-rs/keyring';
9
20
  const SERVICE_NAME = 'borg-mcp';
10
21
  const ID_TOKEN_ACCOUNT = 'google-id-token';
11
22
  const REFRESH_TOKEN_ACCOUNT = 'google-refresh-token';
12
23
  const TOKEN_EXPIRY_ACCOUNT = 'token-expiry';
13
24
  /**
14
- * Store Google OAuth ID token securely in OS keychain
25
+ * Build an AsyncEntry bound to the borg-mcp service + given account.
26
+ * One per call site rather than module-level singletons so the
27
+ * underlying Rust handle isn't held longer than necessary.
28
+ */
29
+ function entry(account) {
30
+ return new AsyncEntry(SERVICE_NAME, account);
31
+ }
32
+ /**
33
+ * `@napi-rs/keyring`'s `deletePassword` returns a `NoEntry` error
34
+ * when the entry doesn't exist. `keytar.deletePassword` returned
35
+ * `false` silently in the same case. We preserve the silent-on-
36
+ * missing semantic so `clearTokens()` stays idempotent across
37
+ * repeat calls.
38
+ *
39
+ * Other errors (platform unavailable, ambiguous credential, etc.)
40
+ * propagate — fail-loud is correct for those classes.
41
+ */
42
+ async function deleteIfExists(account) {
43
+ try {
44
+ await entry(account).deletePassword();
45
+ }
46
+ catch (err) {
47
+ const msg = String(err?.message ?? '');
48
+ if (/no entry|not found/i.test(msg))
49
+ return;
50
+ throw err;
51
+ }
52
+ }
53
+ /**
54
+ * Store Google OAuth ID token securely in the OS keychain.
15
55
  */
16
56
  export async function storeIdToken(idToken, expiresAt) {
17
- await keytar.setPassword(SERVICE_NAME, ID_TOKEN_ACCOUNT, idToken);
18
- await keytar.setPassword(SERVICE_NAME, TOKEN_EXPIRY_ACCOUNT, expiresAt.toString());
57
+ await entry(ID_TOKEN_ACCOUNT).setPassword(idToken);
58
+ await entry(TOKEN_EXPIRY_ACCOUNT).setPassword(expiresAt.toString());
19
59
  }
20
60
  /**
21
- * Store Google OAuth refresh token securely in OS keychain
61
+ * Store Google OAuth refresh token securely in the OS keychain.
22
62
  */
23
63
  export async function storeRefreshToken(refreshToken) {
24
- await keytar.setPassword(SERVICE_NAME, REFRESH_TOKEN_ACCOUNT, refreshToken);
64
+ await entry(REFRESH_TOKEN_ACCOUNT).setPassword(refreshToken);
25
65
  }
26
66
  /**
27
- * Retrieve Google OAuth ID token from OS keychain
28
- * Returns null if not found or expired
67
+ * Retrieve the Google OAuth ID token from the OS keychain.
68
+ * Returns null if not stored or expired (5-minute buffer).
69
+ *
70
+ * `getPassword` on a missing entry returns null/undefined depending
71
+ * on platform binding; normalize with `?? null` so the caller
72
+ * contract (`string | null`) is platform-stable.
29
73
  */
30
74
  export async function getIdToken() {
31
- const token = await keytar.getPassword(SERVICE_NAME, ID_TOKEN_ACCOUNT);
32
- const expiryStr = await keytar.getPassword(SERVICE_NAME, TOKEN_EXPIRY_ACCOUNT);
75
+ const token = (await entry(ID_TOKEN_ACCOUNT).getPassword()) ?? null;
76
+ const expiryStr = (await entry(TOKEN_EXPIRY_ACCOUNT).getPassword()) ?? null;
33
77
  if (!token || !expiryStr) {
34
78
  return null;
35
79
  }
36
80
  const expiresAt = parseInt(expiryStr, 10);
37
81
  const now = Date.now();
38
- // Check if token is expired (with 5 minute buffer)
82
+ // Check if token is expired (with 5 minute buffer).
39
83
  if (expiresAt - now < 5 * 60 * 1000) {
40
- return null; // Token expired or expiring soon
84
+ return null;
41
85
  }
42
86
  return token;
43
87
  }
44
88
  /**
45
- * Retrieve Google OAuth refresh token from OS keychain
89
+ * Retrieve the Google OAuth refresh token from the OS keychain.
46
90
  */
47
91
  export async function getRefreshToken() {
48
- return await keytar.getPassword(SERVICE_NAME, REFRESH_TOKEN_ACCOUNT);
92
+ return (await entry(REFRESH_TOKEN_ACCOUNT).getPassword()) ?? null;
49
93
  }
50
94
  /**
51
- * Clear all stored tokens from OS keychain
95
+ * Clear all stored tokens from the OS keychain. Idempotent — calling
96
+ * on an already-empty keychain is a no-op (NoEntry errors absorbed).
52
97
  */
53
98
  export async function clearTokens() {
54
- await keytar.deletePassword(SERVICE_NAME, ID_TOKEN_ACCOUNT);
55
- await keytar.deletePassword(SERVICE_NAME, REFRESH_TOKEN_ACCOUNT);
56
- await keytar.deletePassword(SERVICE_NAME, TOKEN_EXPIRY_ACCOUNT);
99
+ await deleteIfExists(ID_TOKEN_ACCOUNT);
100
+ await deleteIfExists(REFRESH_TOKEN_ACCOUNT);
101
+ await deleteIfExists(TOKEN_EXPIRY_ACCOUNT);
57
102
  }
58
103
  /**
59
- * Check if user has valid authentication
104
+ * Check if user has valid authentication.
60
105
  */
61
106
  export async function isAuthenticated() {
62
107
  const token = await getIdToken();
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,MAAM,MAAM,QAAQ,CAAC;AAG5B,MAAM,YAAY,GAAG,UAAU,CAAC;AAChC,MAAM,gBAAgB,GAAG,iBAAiB,CAAC;AAC3C,MAAM,qBAAqB,GAAG,sBAAsB,CAAC;AACrD,MAAM,oBAAoB,GAAG,cAAc,CAAC;AAE5C;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAAe,EAAE,SAAiB;IACnE,MAAM,MAAM,CAAC,WAAW,CAAC,YAAY,EAAE,gBAAgB,EAAE,OAAO,CAAC,CAAC;IAClE,MAAM,MAAM,CAAC,WAAW,CAAC,YAAY,EAAE,oBAAoB,EAAE,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC;AACrF,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,YAAoB;IAC1D,MAAM,MAAM,CAAC,WAAW,CAAC,YAAY,EAAE,qBAAqB,EAAE,YAAY,CAAC,CAAC;AAC9E,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAC;IACvE,MAAM,SAAS,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,YAAY,EAAE,oBAAoB,CAAC,CAAC;IAE/E,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,SAAS,GAAG,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAEvB,mDAAmD;IACnD,IAAI,SAAS,GAAG,GAAG,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC;QACpC,OAAO,IAAI,CAAC,CAAC,iCAAiC;IAChD,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,OAAO,MAAM,MAAM,CAAC,WAAW,CAAC,YAAY,EAAE,qBAAqB,CAAC,CAAC;AACvE,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,MAAM,CAAC,cAAc,CAAC,YAAY,EAAE,gBAAgB,CAAC,CAAC;IAC5D,MAAM,MAAM,CAAC,cAAc,CAAC,YAAY,EAAE,qBAAqB,CAAC,CAAC;IACjE,MAAM,MAAM,CAAC,cAAc,CAAC,YAAY,EAAE,oBAAoB,CAAC,CAAC;AAClE,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,MAAM,KAAK,GAAG,MAAM,UAAU,EAAE,CAAC;IACjC,OAAO,KAAK,KAAK,IAAI,CAAC;AACxB,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG9C,MAAM,YAAY,GAAG,UAAU,CAAC;AAChC,MAAM,gBAAgB,GAAG,iBAAiB,CAAC;AAC3C,MAAM,qBAAqB,GAAG,sBAAsB,CAAC;AACrD,MAAM,oBAAoB,GAAG,cAAc,CAAC;AAE5C;;;;GAIG;AACH,SAAS,KAAK,CAAC,OAAe;IAC5B,OAAO,IAAI,UAAU,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;AAC/C,CAAC;AAED;;;;;;;;;GASG;AACH,KAAK,UAAU,cAAc,CAAC,OAAe;IAC3C,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,OAAO,CAAC,CAAC,cAAc,EAAE,CAAC;IACxC,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC;QACvC,IAAI,qBAAqB,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,OAAO;QAC5C,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAAe,EAAE,SAAiB;IACnE,MAAM,KAAK,CAAC,gBAAgB,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACnD,MAAM,KAAK,CAAC,oBAAoB,CAAC,CAAC,WAAW,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,CAAC;AACtE,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,YAAoB;IAC1D,MAAM,KAAK,CAAC,qBAAqB,CAAC,CAAC,WAAW,CAAC,YAAY,CAAC,CAAC;AAC/D,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU;IAC9B,MAAM,KAAK,GAAG,CAAC,MAAM,KAAK,CAAC,gBAAgB,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,IAAI,CAAC;IACpE,MAAM,SAAS,GAAG,CAAC,MAAM,KAAK,CAAC,oBAAoB,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,IAAI,CAAC;IAE5E,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS,EAAE,CAAC;QACzB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,SAAS,GAAG,QAAQ,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAEvB,oDAAoD;IACpD,IAAI,SAAS,GAAG,GAAG,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC;QACpC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,OAAO,CAAC,MAAM,KAAK,CAAC,qBAAqB,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,IAAI,CAAC;AACpE,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,MAAM,cAAc,CAAC,gBAAgB,CAAC,CAAC;IACvC,MAAM,cAAc,CAAC,qBAAqB,CAAC,CAAC;IAC5C,MAAM,cAAc,CAAC,oBAAoB,CAAC,CAAC;AAC7C,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,MAAM,KAAK,GAAG,MAAM,UAAU,EAAE,CAAC;IACjC,OAAO,KAAK,KAAK,IAAI,CAAC;AACxB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "borgmcp",
3
- "version": "0.7.2",
3
+ "version": "0.7.3",
4
4
  "description": "Multi-agent coordination for Claude Code — cubes, drones, and a shared activity log.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -48,8 +48,8 @@
48
48
  },
49
49
  "dependencies": {
50
50
  "@modelcontextprotocol/sdk": "^1.0.4",
51
+ "@napi-rs/keyring": "^1.3.0",
51
52
  "chalk": "^5.3.0",
52
- "keytar": "^7.9.0",
53
53
  "open": "^10.0.0",
54
54
  "prompts": "^2.4.2",
55
55
  "which": "^4.0.0"