fluxy-bot 0.2.33 → 0.2.34

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": "fluxy-bot",
3
- "version": "0.2.33",
3
+ "version": "0.2.34",
4
4
  "description": "Self-hosted AI bot — run your own AI assistant from anywhere",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -120,32 +120,42 @@ export function readClaudeAccessToken(): string | null {
120
120
  /* ── Helpers ── */
121
121
 
122
122
  /**
123
- * Read the OAuth block from credentials file or macOS Keychain.
123
+ * Read the OAuth block from the most reliable source.
124
+ * On macOS: Keychain is the source of truth (Claude Code reads/writes there on refresh).
125
+ * If Keychain has no valid entry, stale files are not trusted.
126
+ * On Linux/Windows: credentials file is the source of truth.
124
127
  * Handles both formats:
125
128
  * - Claude Code format: { claudeAiOauth: { accessToken, refreshToken, expiresAt, ... } }
126
129
  * - Legacy flat format: { accessToken, refreshToken, expiresAt }
127
130
  */
128
131
  function readOAuthBlock(): { accessToken?: string; refreshToken?: string; expiresAt?: number } | null {
129
- // Primary: credentials file
130
- try {
131
- if (fs.existsSync(CREDENTIALS_FILE)) {
132
- const creds = JSON.parse(fs.readFileSync(CREDENTIALS_FILE, 'utf-8'));
133
- const oauth = creds.claudeAiOauth || creds;
134
- if (oauth.accessToken) return oauth;
135
- }
136
- } catch {}
137
-
138
- // macOS Keychain fallback
132
+ // macOS: Keychain is the source of truth
139
133
  if (process.platform === 'darwin') {
140
134
  try {
141
135
  const result = execFileSync('security', [
142
136
  'find-generic-password', '-s', 'Claude Code-credentials', '-w',
143
137
  ], { stdio: ['pipe', 'pipe', 'pipe'] }).toString().trim();
144
138
  const parsed = JSON.parse(result);
145
- if (parsed.claudeAiOauth?.accessToken) return parsed.claudeAiOauth;
139
+ const oauth = parsed.claudeAiOauth || parsed;
140
+ if (oauth.accessToken) {
141
+ log.ok('Read credentials from macOS Keychain');
142
+ return oauth;
143
+ }
146
144
  } catch {}
145
+ // On macOS, if Keychain has no valid entry, don't trust stale files
146
+ log.warn('No valid credentials in macOS Keychain');
147
+ return null;
147
148
  }
148
149
 
150
+ // Linux/Windows: credentials file
151
+ try {
152
+ if (fs.existsSync(CREDENTIALS_FILE)) {
153
+ const creds = JSON.parse(fs.readFileSync(CREDENTIALS_FILE, 'utf-8'));
154
+ const oauth = creds.claudeAiOauth || creds;
155
+ if (oauth.accessToken) return oauth;
156
+ }
157
+ } catch {}
158
+
149
159
  return null;
150
160
  }
151
161