limbo-ai 1.24.6 → 1.24.8
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/README.md +14 -0
- package/package.json +1 -1
- package/setup-server/server.js +11 -26
- package/test/setup-server.test.js +0 -19
package/README.md
CHANGED
|
@@ -10,6 +10,20 @@ Limbo is a second brain with a conversational interface. It stores atomic notes
|
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
+
## Hardware Requirements
|
|
14
|
+
|
|
15
|
+
Limbo runs as a single Docker container (~35 MB RAM at idle). The main resource cost is Docker and the host OS, not Limbo itself.
|
|
16
|
+
|
|
17
|
+
| Tier | RAM | vCPU | Disk | Notes |
|
|
18
|
+
|------|-----|------|------|-------|
|
|
19
|
+
| Minimum | 512 MB | 1 | 1 GB | Needs swap configured |
|
|
20
|
+
| Recommended | 1 GB | 1 | 5 GB | Comfortable for Limbo alone |
|
|
21
|
+
| With other services | 2 GB | 1 | 10 GB | Room for reverse proxy, monitoring, etc. |
|
|
22
|
+
|
|
23
|
+
> Limbo's container uses ~35 MB at rest and peaks around ~70 MB during cold starts. CPU usage is negligible — short bursts of 5-7% when processing messages.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
13
27
|
## Quick Start
|
|
14
28
|
|
|
15
29
|
Requires [Docker Desktop](https://docs.docker.com/get-docker/) and Node.js 18+.
|
package/package.json
CHANGED
package/setup-server/server.js
CHANGED
|
@@ -229,9 +229,11 @@ function decodeJwtPayload(token) {
|
|
|
229
229
|
return JSON.parse(Buffer.from(parts[1], 'base64url').toString());
|
|
230
230
|
}
|
|
231
231
|
|
|
232
|
-
//
|
|
233
|
-
//
|
|
234
|
-
//
|
|
232
|
+
// ─── OpenAI Codex auth profiles ──────────────────────────────────────────────
|
|
233
|
+
// OpenAI OAuth tokens expire and need refresh. ZeroClaw reads auth-profiles.json
|
|
234
|
+
// for the refresh token and handles renewal automatically. This is ONLY needed
|
|
235
|
+
// for OpenAI Codex — Anthropic tokens are static and stored as secrets instead.
|
|
236
|
+
const AUTH_PROFILES_FILE = path.join(ZEROCLAW_STATE, 'auth-profiles.json');
|
|
235
237
|
|
|
236
238
|
function buildCodexAuthProfile(profile) {
|
|
237
239
|
const profileId = profile.email ? `openai-codex:${profile.email}` : 'openai-codex:default';
|
|
@@ -253,26 +255,6 @@ function buildCodexAuthProfile(profile) {
|
|
|
253
255
|
};
|
|
254
256
|
}
|
|
255
257
|
|
|
256
|
-
function buildAnthropicAuthProfile(token) {
|
|
257
|
-
return {
|
|
258
|
-
version: 1,
|
|
259
|
-
profiles: {
|
|
260
|
-
'anthropic:token': {
|
|
261
|
-
type: 'token',
|
|
262
|
-
provider: 'anthropic',
|
|
263
|
-
token,
|
|
264
|
-
},
|
|
265
|
-
},
|
|
266
|
-
order: { anthropic: ['anthropic:token'] },
|
|
267
|
-
lastGood: {},
|
|
268
|
-
usageStats: {},
|
|
269
|
-
};
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
// ZeroClaw resolves auth profiles from the state dir root: ~/.zeroclaw/auth-profiles.json
|
|
273
|
-
// See: ZeroClaw src/auth/profiles.rs — state_dir.join("auth-profiles.json")
|
|
274
|
-
const AUTH_PROFILES_FILE = path.join(ZEROCLAW_STATE, 'auth-profiles.json');
|
|
275
|
-
|
|
276
258
|
function writeAuthProfiles(store) {
|
|
277
259
|
fs.mkdirSync(ZEROCLAW_STATE, { recursive: true, mode: 0o700 });
|
|
278
260
|
fs.writeFileSync(AUTH_PROFILES_FILE, JSON.stringify(store, null, 2), { mode: 0o600 });
|
|
@@ -557,6 +539,7 @@ async function exchangeOAuthCode(code, verifier, redirectUri) {
|
|
|
557
539
|
function processOAuthTokens(tokenRes) {
|
|
558
540
|
const jwt = decodeJwtPayload(tokenRes.access_token);
|
|
559
541
|
const authClaim = jwt['https://api.openai.com/auth'] || {};
|
|
542
|
+
// Write auth profile for ZeroClaw's OAuth refresh flow
|
|
560
543
|
const store = buildCodexAuthProfile({
|
|
561
544
|
access: tokenRes.access_token,
|
|
562
545
|
refresh: tokenRes.refresh_token,
|
|
@@ -565,6 +548,8 @@ function processOAuthTokens(tokenRes) {
|
|
|
565
548
|
email: jwt.email || '',
|
|
566
549
|
});
|
|
567
550
|
writeAuthProfiles(store);
|
|
551
|
+
// Also write access token as secret for entrypoint to export
|
|
552
|
+
writeSecretFile('llm_api_key', tokenRes.access_token);
|
|
568
553
|
return { email: jwt.email || '' };
|
|
569
554
|
}
|
|
570
555
|
|
|
@@ -676,8 +661,9 @@ async function handleAnthropicToken(req, res) {
|
|
|
676
661
|
return;
|
|
677
662
|
}
|
|
678
663
|
|
|
679
|
-
|
|
680
|
-
|
|
664
|
+
// Anthropic tokens are static (no refresh needed) — store as secret
|
|
665
|
+
writeSecretFile('llm_api_key', token);
|
|
666
|
+
log('Anthropic token written to secrets/llm_api_key');
|
|
681
667
|
sendJSON(res, 200, { success: true });
|
|
682
668
|
}
|
|
683
669
|
|
|
@@ -861,7 +847,6 @@ module.exports = {
|
|
|
861
847
|
buildOAuthUrl,
|
|
862
848
|
decodeJwtPayload,
|
|
863
849
|
buildCodexAuthProfile,
|
|
864
|
-
buildAnthropicAuthProfile,
|
|
865
850
|
handleRequest,
|
|
866
851
|
_internals: {
|
|
867
852
|
OPENAI_OAUTH,
|
|
@@ -15,7 +15,6 @@ const {
|
|
|
15
15
|
buildOAuthUrl,
|
|
16
16
|
decodeJwtPayload,
|
|
17
17
|
buildCodexAuthProfile,
|
|
18
|
-
buildAnthropicAuthProfile,
|
|
19
18
|
handleRequest,
|
|
20
19
|
_internals: { OPENAI_OAUTH },
|
|
21
20
|
} = require('../setup-server/server.js');
|
|
@@ -197,24 +196,6 @@ describe('buildCodexAuthProfile', () => {
|
|
|
197
196
|
});
|
|
198
197
|
});
|
|
199
198
|
|
|
200
|
-
describe('buildAnthropicAuthProfile', () => {
|
|
201
|
-
it('builds correct structure', () => {
|
|
202
|
-
const result = buildAnthropicAuthProfile('sk-ant-test123');
|
|
203
|
-
assert.strictEqual(result.version, 1);
|
|
204
|
-
const pid = 'anthropic:token';
|
|
205
|
-
assert.ok(result.profiles[pid], 'profile entry exists');
|
|
206
|
-
assert.strictEqual(result.profiles[pid].provider, 'anthropic');
|
|
207
|
-
assert.strictEqual(result.profiles[pid].type, 'token');
|
|
208
|
-
assert.strictEqual(result.profiles[pid].token, 'sk-ant-test123');
|
|
209
|
-
});
|
|
210
|
-
|
|
211
|
-
it('order includes anthropic key', () => {
|
|
212
|
-
const result = buildAnthropicAuthProfile('sk-ant-xyz');
|
|
213
|
-
assert.ok(result.order.anthropic, 'order has anthropic key');
|
|
214
|
-
assert.deepStrictEqual(result.order.anthropic, ['anthropic:token']);
|
|
215
|
-
});
|
|
216
|
-
});
|
|
217
|
-
|
|
218
199
|
// ─── B. HTTP handler tests ──────────────────────────────────────────────────
|
|
219
200
|
|
|
220
201
|
describe('HTTP handler', () => {
|