Skip to content

Commit 555fae5

Browse files
ziggyclaude
andcommitted
fix: keep OAuth token perpetually fresh via keychain write-back
Two improvements on top of the keychain read fix: - Write the fresh keychain token back to .env on every agent spawn so the file stays current. If GhostClaw restarts while the keychain is locked (reboot before first login), .env still has a recently-valid token. - Remove unused CONTAINER_TIMEOUT import from container-runner.ts. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 2f3d14e commit 555fae5

2 files changed

Lines changed: 26 additions & 3 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "ghostclaw",
3-
"version": "0.7.7",
3+
"version": "0.7.8",
44
"description": "Personal AI assistant. Bare metal, Telegram-first, no containers.",
55
"type": "module",
66
"main": "dist/index.js",

src/container-runner.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import {
1010
AGENT_ABSOLUTE_TIMEOUT,
1111
AGENT_IDLE_TIMEOUT,
1212
CONTAINER_MAX_OUTPUT_SIZE,
13-
CONTAINER_TIMEOUT,
1413
DATA_DIR,
1514
GROUPS_DIR,
1615
} from './config.js';
@@ -81,15 +80,39 @@ function readSecrets(): Record<string, string> {
8180
'ELEVENLABS_VOICE_ID',
8281
]);
8382

84-
// Prefer keychain token over .env — keychain is always current
83+
// Prefer keychain token over .env — keychain is always current.
84+
// Also write it back to .env so a reboot with a locked keychain still
85+
// has a reasonably recent token to fall back on.
8586
const keychainToken = readOAuthTokenFromKeychain();
8687
if (keychainToken) {
8788
secrets.CLAUDE_CODE_OAUTH_TOKEN = keychainToken;
89+
writeOAuthTokenToEnv(keychainToken);
8890
}
8991

9092
return secrets;
9193
}
9294

95+
/**
96+
* Write the OAuth token back to .env so it stays fresh for reboot scenarios
97+
* where the keychain may be locked before first login.
98+
* Silently no-ops if the file can't be read/written.
99+
*/
100+
function writeOAuthTokenToEnv(token: string): void {
101+
const envPath = path.join(process.cwd(), '.env');
102+
try {
103+
const content = fs.readFileSync(envPath, 'utf-8');
104+
const updated = content.replace(
105+
/^CLAUDE_CODE_OAUTH_TOKEN=.*$/m,
106+
`CLAUDE_CODE_OAUTH_TOKEN=${token}`,
107+
);
108+
if (updated !== content) {
109+
fs.writeFileSync(envPath, updated);
110+
}
111+
} catch {
112+
// .env missing or unwritable — not fatal
113+
}
114+
}
115+
93116
/**
94117
* Build the mcpServers object from global config (env vars).
95118
* Each MCP server added here becomes available to all agent instances.

0 commit comments

Comments
 (0)