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 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "limbo-ai",
3
- "version": "1.24.6",
3
+ "version": "1.24.8",
4
4
  "description": "Your personal AI memory agent — install and manage Limbo via npx",
5
5
  "type": "commonjs",
6
6
  "bin": {
@@ -229,9 +229,11 @@ function decodeJwtPayload(token) {
229
229
  return JSON.parse(Buffer.from(parts[1], 'base64url').toString());
230
230
  }
231
231
 
232
- // ZeroClaw auth-profiles.json must match the structure used by the CLI
233
- // (cli.js buildAnthropicAuthProfile / buildCodexAuthProfile).
234
- // Path: ~/.zeroclaw/agents/main/agent/auth-profiles.json
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
- const store = buildAnthropicAuthProfile(token);
680
- writeAuthProfiles(store);
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', () => {