@lobu/cli 3.0.3 → 3.0.4

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.
Files changed (106) hide show
  1. package/README.md +8 -8
  2. package/dist/__tests__/login.test.d.ts +2 -0
  3. package/dist/__tests__/login.test.d.ts.map +1 -0
  4. package/dist/__tests__/login.test.js +173 -0
  5. package/dist/__tests__/login.test.js.map +1 -0
  6. package/dist/api/client.d.ts.map +1 -1
  7. package/dist/api/client.js +3 -5
  8. package/dist/api/client.js.map +1 -1
  9. package/dist/api/context.d.ts +22 -0
  10. package/dist/api/context.d.ts.map +1 -0
  11. package/dist/api/context.js +113 -0
  12. package/dist/api/context.js.map +1 -0
  13. package/dist/api/credentials.d.ts +9 -4
  14. package/dist/api/credentials.d.ts.map +1 -1
  15. package/dist/api/credentials.js +127 -15
  16. package/dist/api/credentials.js.map +1 -1
  17. package/dist/commands/chat.d.ts +11 -0
  18. package/dist/commands/chat.d.ts.map +1 -0
  19. package/dist/commands/chat.js +195 -0
  20. package/dist/commands/chat.js.map +1 -0
  21. package/dist/commands/context.d.ts +8 -0
  22. package/dist/commands/context.d.ts.map +1 -0
  23. package/dist/commands/context.js +46 -0
  24. package/dist/commands/context.js.map +1 -0
  25. package/dist/commands/dev.d.ts +1 -8
  26. package/dist/commands/dev.d.ts.map +1 -1
  27. package/dist/commands/dev.js +236 -57
  28. package/dist/commands/dev.js.map +1 -1
  29. package/dist/commands/init.d.ts.map +1 -1
  30. package/dist/commands/init.js +351 -676
  31. package/dist/commands/init.js.map +1 -1
  32. package/dist/commands/launch.d.ts.map +1 -1
  33. package/dist/commands/launch.js +2 -8
  34. package/dist/commands/launch.js.map +1 -1
  35. package/dist/commands/login.d.ts +2 -0
  36. package/dist/commands/login.d.ts.map +1 -1
  37. package/dist/commands/login.js +283 -14
  38. package/dist/commands/login.js.map +1 -1
  39. package/dist/commands/logout.d.ts +3 -1
  40. package/dist/commands/logout.d.ts.map +1 -1
  41. package/dist/commands/logout.js +5 -3
  42. package/dist/commands/logout.js.map +1 -1
  43. package/dist/commands/providers/add.d.ts.map +1 -1
  44. package/dist/commands/providers/add.js +38 -14
  45. package/dist/commands/providers/add.js.map +1 -1
  46. package/dist/commands/providers/list.d.ts.map +1 -1
  47. package/dist/commands/providers/list.js +4 -2
  48. package/dist/commands/providers/list.js.map +1 -1
  49. package/dist/commands/skills/add.d.ts.map +1 -1
  50. package/dist/commands/skills/add.js +25 -7
  51. package/dist/commands/skills/add.js.map +1 -1
  52. package/dist/commands/skills/info.d.ts.map +1 -1
  53. package/dist/commands/skills/info.js.map +1 -1
  54. package/dist/commands/skills/list.d.ts.map +1 -1
  55. package/dist/commands/skills/list.js.map +1 -1
  56. package/dist/commands/skills/registry.d.ts +5 -0
  57. package/dist/commands/skills/registry.d.ts.map +1 -1
  58. package/dist/commands/skills/registry.js.map +1 -1
  59. package/dist/commands/skills/search.d.ts.map +1 -1
  60. package/dist/commands/skills/search.js +3 -1
  61. package/dist/commands/skills/search.js.map +1 -1
  62. package/dist/commands/status.d.ts +1 -1
  63. package/dist/commands/status.d.ts.map +1 -1
  64. package/dist/commands/status.js +107 -4
  65. package/dist/commands/status.js.map +1 -1
  66. package/dist/commands/validate.d.ts.map +1 -1
  67. package/dist/commands/validate.js +9 -20
  68. package/dist/commands/validate.js.map +1 -1
  69. package/dist/commands/whoami.d.ts +3 -1
  70. package/dist/commands/whoami.d.ts.map +1 -1
  71. package/dist/commands/whoami.js +17 -3
  72. package/dist/commands/whoami.js.map +1 -1
  73. package/dist/config/agents-manifest.d.ts +92 -0
  74. package/dist/config/agents-manifest.d.ts.map +1 -0
  75. package/dist/config/agents-manifest.js +7 -0
  76. package/dist/config/agents-manifest.js.map +1 -0
  77. package/dist/config/loader.d.ts +18 -0
  78. package/dist/config/loader.d.ts.map +1 -1
  79. package/dist/config/loader.js +62 -2
  80. package/dist/config/loader.js.map +1 -1
  81. package/dist/config/platform-schemas.d.ts +120 -0
  82. package/dist/config/platform-schemas.d.ts.map +1 -0
  83. package/dist/config/platform-schemas.js +97 -0
  84. package/dist/config/platform-schemas.js.map +1 -0
  85. package/dist/config/schema.d.ts +546 -111
  86. package/dist/config/schema.d.ts.map +1 -1
  87. package/dist/config/schema.js +26 -19
  88. package/dist/config/schema.js.map +1 -1
  89. package/dist/config/transformer.d.ts +3 -0
  90. package/dist/config/transformer.d.ts.map +1 -1
  91. package/dist/config/transformer.js +7 -10
  92. package/dist/config/transformer.js.map +1 -1
  93. package/dist/index.d.ts +0 -4
  94. package/dist/index.d.ts.map +1 -1
  95. package/dist/index.js +52 -10
  96. package/dist/index.js.map +1 -1
  97. package/dist/system-skills.json +89 -29
  98. package/dist/templates/.env.tmpl +3 -14
  99. package/dist/templates/.gitignore.tmpl +1 -0
  100. package/dist/templates/README.md.tmpl +7 -8
  101. package/dist/utils/markdown.d.ts +3 -0
  102. package/dist/utils/markdown.d.ts.map +1 -0
  103. package/dist/utils/markdown.js +10 -0
  104. package/dist/utils/markdown.js.map +1 -0
  105. package/package.json +4 -2
  106. package/dist/templates/lobu.toml.tmpl +0 -44
package/README.md CHANGED
@@ -32,7 +32,7 @@ Lobu supports two deployment patterns for workers:
32
32
 
33
33
  ```dockerfile
34
34
  # Extends our curated base image
35
- FROM buremba/lobu-worker-base:0.1.0
35
+ FROM ghcr.io/lobu-ai/lobu-worker-base:0.1.0
36
36
 
37
37
  # Add your customizations
38
38
  RUN pip install pandas
@@ -131,7 +131,7 @@ docker compose build worker
131
131
  ### Dockerfile.worker (Base Image Mode)
132
132
 
133
133
  ```dockerfile
134
- FROM buremba/lobu-worker-base:0.1.0
134
+ FROM ghcr.io/lobu-ai/lobu-worker-base:0.1.0
135
135
 
136
136
  # Add system packages
137
137
  RUN apt-get update && apt-get install -y postgresql-client
@@ -198,8 +198,8 @@ docker compose down
198
198
 
199
199
  The CLI version locks to base image versions:
200
200
 
201
- - CLI `0.1.0` -> `buremba/lobu-worker-base:0.1.0`
202
- - CLI `0.2.0` -> `buremba/lobu-worker-base:0.2.0`
201
+ - CLI `0.1.0` -> `ghcr.io/lobu-ai/lobu-worker-base:0.1.0`
202
+ - CLI `0.2.0` -> `ghcr.io/lobu-ai/lobu-worker-base:0.2.0`
203
203
 
204
204
  This ensures compatibility between CLI and runtime images.
205
205
 
@@ -208,7 +208,7 @@ This ensures compatibility between CLI and runtime images.
208
208
  Lobu uses a dual distribution pattern:
209
209
 
210
210
  **Day 0 (Quick Start):**
211
- - Use `buremba/lobu-worker-base` Docker image
211
+ - Use `ghcr.io/lobu-ai/lobu-worker-base` Docker image
212
212
  - Extend with Dockerfile
213
213
  - Perfect for learning, prototypes
214
214
 
@@ -219,13 +219,13 @@ Lobu uses a dual distribution pattern:
219
219
 
220
220
  ## Published Artifacts
221
221
 
222
- **Docker Hub:**
222
+ **GHCR:**
223
223
  ```bash
224
224
  # For production (gateway)
225
- docker pull buremba/lobu-gateway:0.1.0
225
+ docker pull ghcr.io/lobu-ai/lobu-gateway:0.1.0
226
226
 
227
227
  # For quick start (extend this)
228
- docker pull buremba/lobu-worker-base:0.1.0
228
+ docker pull ghcr.io/lobu-ai/lobu-worker-base:0.1.0
229
229
  ```
230
230
 
231
231
  **NPM Registry:**
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=login.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/login.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,173 @@
1
+ import { afterEach, beforeEach, describe, expect, mock, spyOn, test, } from "bun:test";
2
+ describe("loginCommand", () => {
3
+ const originalFetch = globalThis.fetch;
4
+ let consoleLog;
5
+ beforeEach(() => {
6
+ mock.restore();
7
+ consoleLog = spyOn(console, "log").mockImplementation(() => undefined);
8
+ });
9
+ afterEach(() => {
10
+ globalThis.fetch = originalFetch;
11
+ consoleLog.mockRestore();
12
+ });
13
+ test("uses device-first login when the gateway returns device mode", async () => {
14
+ const saveCredentials = mock(async () => undefined);
15
+ const loadCredentials = mock(async () => null);
16
+ const openMock = mock(async () => undefined);
17
+ const spinner = {
18
+ start: mock(() => spinner),
19
+ fail: mock(() => spinner),
20
+ succeed: mock(() => spinner),
21
+ };
22
+ mock.module("open", () => ({
23
+ default: openMock,
24
+ }));
25
+ mock.module("ora", () => ({
26
+ default: mock(() => spinner),
27
+ }));
28
+ mock.module("../api/context.js", () => ({
29
+ resolveContext: mock(async () => ({
30
+ name: "dev",
31
+ apiUrl: "https://lobu.example.com/api/v1",
32
+ })),
33
+ }));
34
+ mock.module("../api/credentials.js", () => ({
35
+ loadCredentials,
36
+ saveCredentials,
37
+ }));
38
+ let calls = 0;
39
+ globalThis.fetch = mock(async (input) => {
40
+ const url = String(input);
41
+ calls += 1;
42
+ if (url.endsWith("/auth/cli/start")) {
43
+ return new Response(JSON.stringify({
44
+ mode: "device",
45
+ deviceAuthId: "device-123",
46
+ userCode: "ABCD-EFGH",
47
+ verificationUri: "https://issuer.example.com/device",
48
+ verificationUriComplete: "https://issuer.example.com/device?user_code=ABCD-EFGH",
49
+ interval: 1,
50
+ expiresAt: Date.now() + 10_000,
51
+ }), { status: 200, headers: { "content-type": "application/json" } });
52
+ }
53
+ if (url.endsWith("/auth/cli/poll")) {
54
+ return new Response(JSON.stringify({
55
+ status: "complete",
56
+ accessToken: "lobu-access-token",
57
+ refreshToken: "lobu-refresh-token",
58
+ expiresAt: Date.now() + 3600_000,
59
+ user: {
60
+ userId: "user-123",
61
+ email: "user@example.com",
62
+ name: "Example User",
63
+ },
64
+ }), { status: 200, headers: { "content-type": "application/json" } });
65
+ }
66
+ throw new Error(`Unexpected fetch: ${url}`);
67
+ });
68
+ const { loginCommand } = await import(`../commands/login.ts?device=${Date.now()}`);
69
+ await loginCommand({});
70
+ expect(calls).toBe(2);
71
+ expect(openMock).toHaveBeenCalledWith("https://issuer.example.com/device?user_code=ABCD-EFGH");
72
+ expect(saveCredentials).toHaveBeenCalledTimes(1);
73
+ expect(spinner.succeed).toHaveBeenCalledTimes(1);
74
+ });
75
+ test("falls back to browser login when the gateway returns browser mode", async () => {
76
+ const saveCredentials = mock(async () => undefined);
77
+ const loadCredentials = mock(async () => null);
78
+ const openMock = mock(async () => undefined);
79
+ const spinner = {
80
+ start: mock(() => spinner),
81
+ fail: mock(() => spinner),
82
+ succeed: mock(() => spinner),
83
+ };
84
+ mock.module("open", () => ({
85
+ default: openMock,
86
+ }));
87
+ mock.module("ora", () => ({
88
+ default: mock(() => spinner),
89
+ }));
90
+ mock.module("../api/context.js", () => ({
91
+ resolveContext: mock(async () => ({
92
+ name: "prod",
93
+ apiUrl: "https://lobu.example.com/api/v1",
94
+ })),
95
+ }));
96
+ mock.module("../api/credentials.js", () => ({
97
+ loadCredentials,
98
+ saveCredentials,
99
+ }));
100
+ globalThis.fetch = mock(async (input) => {
101
+ const url = String(input);
102
+ if (url.endsWith("/auth/cli/start")) {
103
+ return new Response(JSON.stringify({
104
+ mode: "browser",
105
+ requestId: "request-123",
106
+ loginUrl: "https://lobu.example.com/login",
107
+ pollIntervalMs: 1,
108
+ expiresAt: Date.now() + 10_000,
109
+ }), { status: 200, headers: { "content-type": "application/json" } });
110
+ }
111
+ if (url.endsWith("/auth/cli/poll")) {
112
+ return new Response(JSON.stringify({
113
+ status: "complete",
114
+ accessToken: "lobu-access-token",
115
+ refreshToken: "lobu-refresh-token",
116
+ expiresAt: Date.now() + 3600_000,
117
+ user: {
118
+ userId: "user-456",
119
+ email: "prod@example.com",
120
+ name: "Prod User",
121
+ },
122
+ }), { status: 200, headers: { "content-type": "application/json" } });
123
+ }
124
+ throw new Error(`Unexpected fetch: ${url}`);
125
+ });
126
+ const { loginCommand } = await import(`../commands/login.ts?browser=${Date.now()}`);
127
+ await loginCommand({});
128
+ expect(openMock).toHaveBeenCalledWith("https://lobu.example.com/login");
129
+ expect(saveCredentials).toHaveBeenCalledTimes(1);
130
+ expect(spinner.succeed).toHaveBeenCalledTimes(1);
131
+ });
132
+ test("uses the explicit admin-password fallback when requested", async () => {
133
+ const saveCredentials = mock(async () => undefined);
134
+ const loadCredentials = mock(async () => null);
135
+ const promptMock = mock(async () => ({ password: "dev-secret" }));
136
+ mock.module("inquirer", () => ({
137
+ default: {
138
+ prompt: promptMock,
139
+ },
140
+ }));
141
+ mock.module("../api/context.js", () => ({
142
+ resolveContext: mock(async () => ({
143
+ name: "dev",
144
+ apiUrl: "https://lobu.example.com/api/v1",
145
+ })),
146
+ }));
147
+ mock.module("../api/credentials.js", () => ({
148
+ loadCredentials,
149
+ saveCredentials,
150
+ }));
151
+ globalThis.fetch = mock(async (input) => {
152
+ const url = String(input);
153
+ if (url.endsWith("/auth/cli/admin-login")) {
154
+ return new Response(JSON.stringify({
155
+ status: "complete",
156
+ accessToken: "lobu-access-token",
157
+ refreshToken: "lobu-refresh-token",
158
+ expiresAt: Date.now() + 3600_000,
159
+ user: {
160
+ userId: "admin",
161
+ name: "Admin (dev)",
162
+ },
163
+ }), { status: 200, headers: { "content-type": "application/json" } });
164
+ }
165
+ throw new Error(`Unexpected fetch: ${url}`);
166
+ });
167
+ const { loginCommand } = await import(`../commands/login.ts?admin=${Date.now()}`);
168
+ await loginCommand({ adminPassword: true });
169
+ expect(promptMock).toHaveBeenCalledTimes(1);
170
+ expect(saveCredentials).toHaveBeenCalledTimes(1);
171
+ });
172
+ });
173
+ //# sourceMappingURL=login.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.test.js","sourceRoot":"","sources":["../../src/__tests__/login.test.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,OAAO;IACtC,EAAE,EAAE,OAAO,CAAC;IACZ,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,CAAC,GAAG,OAAO,EAC1C,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAyBzB"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,WAAW,CAAC,CAAC,GAAG,OAAO;IACtC,EAAE,EAAE,OAAO,CAAC;IACZ,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,CAAC,GAAG,OAAO,EAC1C,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CA0BzB"}
@@ -1,15 +1,13 @@
1
+ import { resolveContext } from "./context.js";
1
2
  import { getToken } from "./credentials.js";
2
- const DEFAULT_API_URL = "https://community.lobu.ai/api/v1";
3
- function getApiUrl() {
4
- return process.env.LOBU_API_URL ?? DEFAULT_API_URL;
5
- }
6
3
  /**
7
4
  * HTTP client for community.lobu.ai API.
8
5
  * Stub for Phase 1 — most endpoints don't exist yet.
9
6
  */
10
7
  export async function apiRequest(path, options = {}) {
11
8
  const token = await getToken();
12
- const url = `${getApiUrl()}${path}`;
9
+ const context = await resolveContext();
10
+ const url = `${context.apiUrl}${path}`;
13
11
  const headers = {
14
12
  "Content-Type": "application/json",
15
13
  "X-Lobu-Org": "default",
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,MAAM,eAAe,GAAG,kCAAkC,CAAC;AAE3D,SAAS,SAAS;IAChB,OAAO,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,eAAe,CAAC;AACrD,CAAC;AAQD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,IAAY,EACZ,UAAuB,EAAE;IAEzB,MAAM,KAAK,GAAG,MAAM,QAAQ,EAAE,CAAC;IAC/B,MAAM,GAAG,GAAG,GAAG,SAAS,EAAE,GAAG,IAAI,EAAE,CAAC;IAEpC,MAAM,OAAO,GAA2B;QACtC,cAAc,EAAE,kBAAkB;QAClC,YAAY,EAAE,SAAS;QACvB,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtD,GAAI,OAAO,CAAC,OAA8C;KAC3D,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAC3D,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACnC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,QAAQ,CAAC,MAAM,KAAK,IAAI,EAAE,EAAE,CAAC;QAC7D,CAAC;QACD,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAM,CAAC;QAC1C,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAC5B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;SACxD,CAAC;IACJ,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAQ5C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,IAAY,EACZ,UAAuB,EAAE;IAEzB,MAAM,KAAK,GAAG,MAAM,QAAQ,EAAE,CAAC;IAC/B,MAAM,OAAO,GAAG,MAAM,cAAc,EAAE,CAAC;IACvC,MAAM,GAAG,GAAG,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,EAAE,CAAC;IAEvC,MAAM,OAAO,GAA2B;QACtC,cAAc,EAAE,kBAAkB;QAClC,YAAY,EAAE,SAAS;QACvB,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,UAAU,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtD,GAAI,OAAO,CAAC,OAA8C;KAC3D,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAC3D,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACnC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,QAAQ,CAAC,MAAM,KAAK,IAAI,EAAE,EAAE,CAAC;QAC7D,CAAC;QACD,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAM,CAAC;QAC1C,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;IAC5B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;SACxD,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,22 @@
1
+ export declare const LOBU_CONFIG_DIR: string;
2
+ export declare const DEFAULT_CONTEXT_NAME = "community";
3
+ export declare const DEFAULT_API_URL = "https://community.lobu.ai/api/v1";
4
+ export interface LobuContextEntry {
5
+ apiUrl: string;
6
+ }
7
+ export interface LobuContextConfig {
8
+ currentContext: string;
9
+ contexts: Record<string, LobuContextEntry>;
10
+ }
11
+ export interface ResolvedContext {
12
+ name: string;
13
+ apiUrl: string;
14
+ source: "default" | "config" | "env";
15
+ }
16
+ export declare function loadContextConfig(): Promise<LobuContextConfig>;
17
+ export declare function saveContextConfig(config: LobuContextConfig): Promise<void>;
18
+ export declare function getCurrentContextName(): Promise<string>;
19
+ export declare function resolveContext(preferredContext?: string): Promise<ResolvedContext>;
20
+ export declare function addContext(name: string, apiUrl: string): Promise<LobuContextConfig>;
21
+ export declare function setCurrentContext(name: string): Promise<LobuContextConfig>;
22
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/api/context.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,eAAe,QAAqC,CAAC;AAClE,eAAO,MAAM,oBAAoB,cAAc,CAAC;AAChD,eAAO,MAAM,eAAe,qCAAqC,CAAC;AAIlE,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;CAC5C;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,KAAK,CAAC;CACtC;AAOD,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAQpE;AAED,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,iBAAiB,GACxB,OAAO,CAAC,IAAI,CAAC,CAKf;AAED,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,MAAM,CAAC,CAQ7D;AAED,wBAAsB,cAAc,CAClC,gBAAgB,CAAC,EAAE,MAAM,GACxB,OAAO,CAAC,eAAe,CAAC,CA2B1B;AAED,wBAAsB,UAAU,CAC9B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,CAAC,CAY5B;AAED,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,iBAAiB,CAAC,CAgB5B"}
@@ -0,0 +1,113 @@
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import { homedir } from "node:os";
3
+ import { join } from "node:path";
4
+ export const LOBU_CONFIG_DIR = join(homedir(), ".config", "lobu");
5
+ export const DEFAULT_CONTEXT_NAME = "community";
6
+ export const DEFAULT_API_URL = "https://community.lobu.ai/api/v1";
7
+ const CONTEXTS_FILE = join(LOBU_CONFIG_DIR, "config.json");
8
+ export async function loadContextConfig() {
9
+ try {
10
+ const raw = await readFile(CONTEXTS_FILE, "utf-8");
11
+ const parsed = JSON.parse(raw);
12
+ return normalizeContextConfig(parsed);
13
+ }
14
+ catch {
15
+ return normalizeContextConfig({});
16
+ }
17
+ }
18
+ export async function saveContextConfig(config) {
19
+ await mkdir(LOBU_CONFIG_DIR, { recursive: true });
20
+ await writeFile(CONTEXTS_FILE, JSON.stringify(config, null, 2), {
21
+ mode: 0o600,
22
+ });
23
+ }
24
+ export async function getCurrentContextName() {
25
+ const envContext = process.env.LOBU_CONTEXT?.trim();
26
+ if (envContext) {
27
+ return envContext;
28
+ }
29
+ const config = await loadContextConfig();
30
+ return config.currentContext;
31
+ }
32
+ export async function resolveContext(preferredContext) {
33
+ const envApiUrl = process.env.LOBU_API_URL?.trim();
34
+ const requestedContext = preferredContext?.trim() || process.env.LOBU_CONTEXT?.trim();
35
+ if (envApiUrl) {
36
+ return {
37
+ name: requestedContext || (await getCurrentContextName()),
38
+ apiUrl: normalizeApiUrl(envApiUrl),
39
+ source: "env",
40
+ };
41
+ }
42
+ const config = await loadContextConfig();
43
+ const contextName = requestedContext || config.currentContext;
44
+ const context = config.contexts[contextName];
45
+ if (context) {
46
+ return {
47
+ name: contextName,
48
+ apiUrl: normalizeApiUrl(context.apiUrl),
49
+ source: contextName === DEFAULT_CONTEXT_NAME ? "default" : "config",
50
+ };
51
+ }
52
+ throw new Error(`Unknown context "${contextName}". Run \`lobu context list\` to see configured contexts.`);
53
+ }
54
+ export async function addContext(name, apiUrl) {
55
+ const trimmedName = name.trim();
56
+ if (!trimmedName) {
57
+ throw new Error("Context name cannot be empty.");
58
+ }
59
+ const config = await loadContextConfig();
60
+ config.contexts[trimmedName] = {
61
+ apiUrl: normalizeAndValidateApiUrl(apiUrl),
62
+ };
63
+ await saveContextConfig(config);
64
+ return config;
65
+ }
66
+ export async function setCurrentContext(name) {
67
+ const trimmedName = name.trim();
68
+ if (!trimmedName) {
69
+ throw new Error("Context name cannot be empty.");
70
+ }
71
+ const config = await loadContextConfig();
72
+ if (!config.contexts[trimmedName]) {
73
+ throw new Error(`Unknown context "${trimmedName}". Run \`lobu context add ${trimmedName} --api-url <url>\` first.`);
74
+ }
75
+ config.currentContext = trimmedName;
76
+ await saveContextConfig(config);
77
+ return config;
78
+ }
79
+ function normalizeContextConfig(raw) {
80
+ const contexts = {
81
+ [DEFAULT_CONTEXT_NAME]: { apiUrl: DEFAULT_API_URL },
82
+ };
83
+ for (const [name, value] of Object.entries(raw.contexts ?? {})) {
84
+ if (!value || typeof value.apiUrl !== "string") {
85
+ continue;
86
+ }
87
+ contexts[name] = { apiUrl: normalizeApiUrl(value.apiUrl) };
88
+ }
89
+ const currentContext = raw.currentContext && contexts[raw.currentContext]
90
+ ? raw.currentContext
91
+ : DEFAULT_CONTEXT_NAME;
92
+ return { currentContext, contexts };
93
+ }
94
+ function normalizeAndValidateApiUrl(apiUrl) {
95
+ const normalized = normalizeApiUrl(apiUrl.trim());
96
+ if (!normalized) {
97
+ throw new Error("API URL cannot be empty.");
98
+ }
99
+ try {
100
+ const parsed = new URL(normalized);
101
+ if (!parsed.protocol || !parsed.host) {
102
+ throw new Error("Missing protocol or host");
103
+ }
104
+ }
105
+ catch {
106
+ throw new Error(`Invalid API URL: ${apiUrl}`);
107
+ }
108
+ return normalized;
109
+ }
110
+ function normalizeApiUrl(url) {
111
+ return url.replace(/\/+$/, "");
112
+ }
113
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/api/context.ts"],"names":[],"mappings":"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"}
@@ -1,13 +1,18 @@
1
1
  export interface Credentials {
2
- token: string;
2
+ accessToken: string;
3
+ refreshToken?: string;
4
+ expiresAt?: number;
3
5
  email?: string;
6
+ name?: string;
7
+ userId?: string;
4
8
  agentId?: string;
5
9
  }
6
- export declare function loadCredentials(): Promise<Credentials | null>;
7
- export declare function saveCredentials(creds: Credentials): Promise<void>;
8
- export declare function clearCredentials(): Promise<void>;
10
+ export declare function loadCredentials(contextName?: string): Promise<Credentials | null>;
11
+ export declare function saveCredentials(creds: Credentials, contextName?: string): Promise<void>;
12
+ export declare function clearCredentials(contextName?: string): Promise<void>;
9
13
  /**
10
14
  * Get token from env var (CI/CD) or stored credentials.
11
15
  */
12
16
  export declare function getToken(): Promise<string | null>;
17
+ export declare function refreshCredentials(existing?: Credentials | null, contextName?: string): Promise<Credentials | null>;
13
18
  //# sourceMappingURL=credentials.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../src/api/credentials.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAOnE;AAED,wBAAsB,eAAe,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAKvE;AAED,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAMtD;AAED;;GAEG;AACH,wBAAsB,QAAQ,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAMvD"}
1
+ {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../../src/api/credentials.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAOD,wBAAsB,eAAe,CACnC,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAmB7B;AAED,wBAAsB,eAAe,CACnC,KAAK,EAAE,WAAW,EAClB,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAUf;AAED,wBAAsB,gBAAgB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAiB1E;AAED;;GAEG;AACH,wBAAsB,QAAQ,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiBvD;AAED,wBAAsB,kBAAkB,CACtC,QAAQ,CAAC,EAAE,WAAW,GAAG,IAAI,EAC7B,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CA+C7B"}
@@ -1,30 +1,48 @@
1
1
  import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
2
- import { homedir } from "node:os";
3
2
  import { join } from "node:path";
4
- const CONFIG_DIR = join(homedir(), ".config", "lobu");
5
- const CREDENTIALS_FILE = join(CONFIG_DIR, "credentials.json");
6
- export async function loadCredentials() {
3
+ import { DEFAULT_CONTEXT_NAME, LOBU_CONFIG_DIR, resolveContext, } from "./context.js";
4
+ const CREDENTIALS_FILE = join(LOBU_CONFIG_DIR, "credentials.json");
5
+ export async function loadCredentials(contextName) {
6
+ const target = await resolveContext(contextName);
7
7
  try {
8
8
  const raw = await readFile(CREDENTIALS_FILE, "utf-8");
9
- return JSON.parse(raw);
9
+ const parsed = JSON.parse(raw);
10
+ const stored = isCredentialsStore(parsed)
11
+ ? parsed.contexts[target.name]
12
+ : target.name === DEFAULT_CONTEXT_NAME
13
+ ? parsed
14
+ : null;
15
+ return normalizeCredentials(stored);
10
16
  }
11
17
  catch {
12
18
  return null;
13
19
  }
14
20
  }
15
- export async function saveCredentials(creds) {
16
- await mkdir(CONFIG_DIR, { recursive: true });
17
- await writeFile(CREDENTIALS_FILE, JSON.stringify(creds, null, 2), {
21
+ export async function saveCredentials(creds, contextName) {
22
+ const target = await resolveContext(contextName);
23
+ const store = await loadCredentialStore();
24
+ store.contexts[target.name] = creds;
25
+ await mkdir(LOBU_CONFIG_DIR, { recursive: true });
26
+ await writeFile(CREDENTIALS_FILE, JSON.stringify(store, null, 2), {
18
27
  mode: 0o600,
19
28
  });
20
29
  }
21
- export async function clearCredentials() {
22
- try {
23
- await rm(CREDENTIALS_FILE);
24
- }
25
- catch {
26
- // File doesn't exist, nothing to clear
30
+ export async function clearCredentials(contextName) {
31
+ const target = await resolveContext(contextName);
32
+ const store = await loadCredentialStore();
33
+ delete store.contexts[target.name];
34
+ if (Object.keys(store.contexts).length === 0) {
35
+ try {
36
+ await rm(CREDENTIALS_FILE);
37
+ }
38
+ catch {
39
+ // File doesn't exist, nothing to clear.
40
+ }
41
+ return;
27
42
  }
43
+ await writeFile(CREDENTIALS_FILE, JSON.stringify(store, null, 2), {
44
+ mode: 0o600,
45
+ });
28
46
  }
29
47
  /**
30
48
  * Get token from env var (CI/CD) or stored credentials.
@@ -34,6 +52,100 @@ export async function getToken() {
34
52
  if (envToken)
35
53
  return envToken;
36
54
  const creds = await loadCredentials();
37
- return creds?.token ?? null;
55
+ if (!creds)
56
+ return null;
57
+ if (!needsRefresh(creds)) {
58
+ return creds.accessToken;
59
+ }
60
+ if (!creds.refreshToken) {
61
+ return null;
62
+ }
63
+ const refreshed = await refreshCredentials(creds);
64
+ return refreshed?.accessToken ?? null;
65
+ }
66
+ export async function refreshCredentials(existing, contextName) {
67
+ const target = await resolveContext(contextName);
68
+ const creds = existing ?? (await loadCredentials(target.name));
69
+ if (!creds?.refreshToken) {
70
+ return creds ?? null;
71
+ }
72
+ try {
73
+ const response = await fetch(`${target.apiUrl}/auth/refresh`, {
74
+ method: "POST",
75
+ headers: {
76
+ "Content-Type": "application/json",
77
+ "X-Lobu-Org": "default",
78
+ },
79
+ body: JSON.stringify({ refreshToken: creds.refreshToken }),
80
+ });
81
+ if (!response.ok) {
82
+ return null;
83
+ }
84
+ const body = (await response.json());
85
+ const refreshed = {
86
+ ...creds,
87
+ accessToken: body.accessToken,
88
+ refreshToken: body.refreshToken || creds.refreshToken,
89
+ expiresAt: body.expiresAt,
90
+ email: body.user?.email ?? creds.email,
91
+ name: body.user?.name ?? creds.name,
92
+ userId: body.user?.userId ?? creds.userId,
93
+ };
94
+ await saveCredentials(refreshed, target.name);
95
+ return refreshed;
96
+ }
97
+ catch {
98
+ return null;
99
+ }
100
+ }
101
+ function needsRefresh(creds) {
102
+ return (typeof creds.expiresAt === "number" &&
103
+ creds.expiresAt - 60_000 <= Date.now());
104
+ }
105
+ async function loadCredentialStore() {
106
+ try {
107
+ const raw = await readFile(CREDENTIALS_FILE, "utf-8");
108
+ const parsed = JSON.parse(raw);
109
+ if (isCredentialsStore(parsed)) {
110
+ return {
111
+ version: 2,
112
+ contexts: Object.fromEntries(Object.entries(parsed.contexts)
113
+ .map(([name, value]) => [name, normalizeCredentials(value)])
114
+ .filter((entry) => !!entry[1])),
115
+ };
116
+ }
117
+ const legacy = normalizeCredentials(parsed);
118
+ return {
119
+ version: 2,
120
+ contexts: legacy ? { [DEFAULT_CONTEXT_NAME]: legacy } : {},
121
+ };
122
+ }
123
+ catch {
124
+ return {
125
+ version: 2,
126
+ contexts: {},
127
+ };
128
+ }
129
+ }
130
+ function isCredentialsStore(value) {
131
+ if (!value || typeof value !== "object") {
132
+ return false;
133
+ }
134
+ return ("contexts" in value &&
135
+ !!value.contexts &&
136
+ typeof value.contexts === "object");
137
+ }
138
+ function normalizeCredentials(value) {
139
+ if (!value || typeof value !== "object") {
140
+ return null;
141
+ }
142
+ const accessToken = value.accessToken;
143
+ if (!accessToken) {
144
+ return null;
145
+ }
146
+ return {
147
+ ...value,
148
+ accessToken,
149
+ };
38
150
  }
39
151
  //# sourceMappingURL=credentials.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/api/credentials.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClE,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;AACtD,MAAM,gBAAgB,GAAG,IAAI,CAAC,UAAU,EAAE,kBAAkB,CAAC,CAAC;AAQ9D,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC;QACtD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAgB,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,KAAkB;IACtD,MAAM,KAAK,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7C,MAAM,SAAS,CAAC,gBAAgB,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE;QAChE,IAAI,EAAE,KAAK;KACZ,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,gBAAgB,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,uCAAuC;IACzC,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ;IAC5B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAC5C,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAE9B,MAAM,KAAK,GAAG,MAAM,eAAe,EAAE,CAAC;IACtC,OAAO,KAAK,EAAE,KAAK,IAAI,IAAI,CAAC;AAC9B,CAAC"}
1
+ {"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/api/credentials.ts"],"names":[],"mappings":"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"}