@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.
- package/README.md +8 -8
- package/dist/__tests__/login.test.d.ts +2 -0
- package/dist/__tests__/login.test.d.ts.map +1 -0
- package/dist/__tests__/login.test.js +173 -0
- package/dist/__tests__/login.test.js.map +1 -0
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/client.js +3 -5
- package/dist/api/client.js.map +1 -1
- package/dist/api/context.d.ts +22 -0
- package/dist/api/context.d.ts.map +1 -0
- package/dist/api/context.js +113 -0
- package/dist/api/context.js.map +1 -0
- package/dist/api/credentials.d.ts +9 -4
- package/dist/api/credentials.d.ts.map +1 -1
- package/dist/api/credentials.js +127 -15
- package/dist/api/credentials.js.map +1 -1
- package/dist/commands/chat.d.ts +11 -0
- package/dist/commands/chat.d.ts.map +1 -0
- package/dist/commands/chat.js +195 -0
- package/dist/commands/chat.js.map +1 -0
- package/dist/commands/context.d.ts +8 -0
- package/dist/commands/context.d.ts.map +1 -0
- package/dist/commands/context.js +46 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/dev.d.ts +1 -8
- package/dist/commands/dev.d.ts.map +1 -1
- package/dist/commands/dev.js +236 -57
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +351 -676
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/launch.d.ts.map +1 -1
- package/dist/commands/launch.js +2 -8
- package/dist/commands/launch.js.map +1 -1
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +283 -14
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/logout.d.ts +3 -1
- package/dist/commands/logout.d.ts.map +1 -1
- package/dist/commands/logout.js +5 -3
- package/dist/commands/logout.js.map +1 -1
- package/dist/commands/providers/add.d.ts.map +1 -1
- package/dist/commands/providers/add.js +38 -14
- package/dist/commands/providers/add.js.map +1 -1
- package/dist/commands/providers/list.d.ts.map +1 -1
- package/dist/commands/providers/list.js +4 -2
- package/dist/commands/providers/list.js.map +1 -1
- package/dist/commands/skills/add.d.ts.map +1 -1
- package/dist/commands/skills/add.js +25 -7
- package/dist/commands/skills/add.js.map +1 -1
- package/dist/commands/skills/info.d.ts.map +1 -1
- package/dist/commands/skills/info.js.map +1 -1
- package/dist/commands/skills/list.d.ts.map +1 -1
- package/dist/commands/skills/list.js.map +1 -1
- package/dist/commands/skills/registry.d.ts +5 -0
- package/dist/commands/skills/registry.d.ts.map +1 -1
- package/dist/commands/skills/registry.js.map +1 -1
- package/dist/commands/skills/search.d.ts.map +1 -1
- package/dist/commands/skills/search.js +3 -1
- package/dist/commands/skills/search.js.map +1 -1
- package/dist/commands/status.d.ts +1 -1
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +107 -4
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/validate.d.ts.map +1 -1
- package/dist/commands/validate.js +9 -20
- package/dist/commands/validate.js.map +1 -1
- package/dist/commands/whoami.d.ts +3 -1
- package/dist/commands/whoami.d.ts.map +1 -1
- package/dist/commands/whoami.js +17 -3
- package/dist/commands/whoami.js.map +1 -1
- package/dist/config/agents-manifest.d.ts +92 -0
- package/dist/config/agents-manifest.d.ts.map +1 -0
- package/dist/config/agents-manifest.js +7 -0
- package/dist/config/agents-manifest.js.map +1 -0
- package/dist/config/loader.d.ts +18 -0
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +62 -2
- package/dist/config/loader.js.map +1 -1
- package/dist/config/platform-schemas.d.ts +120 -0
- package/dist/config/platform-schemas.d.ts.map +1 -0
- package/dist/config/platform-schemas.js +97 -0
- package/dist/config/platform-schemas.js.map +1 -0
- package/dist/config/schema.d.ts +546 -111
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +26 -19
- package/dist/config/schema.js.map +1 -1
- package/dist/config/transformer.d.ts +3 -0
- package/dist/config/transformer.d.ts.map +1 -1
- package/dist/config/transformer.js +7 -10
- package/dist/config/transformer.js.map +1 -1
- package/dist/index.d.ts +0 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +52 -10
- package/dist/index.js.map +1 -1
- package/dist/system-skills.json +89 -29
- package/dist/templates/.env.tmpl +3 -14
- package/dist/templates/.gitignore.tmpl +1 -0
- package/dist/templates/README.md.tmpl +7 -8
- package/dist/utils/markdown.d.ts +3 -0
- package/dist/utils/markdown.d.ts.map +1 -0
- package/dist/utils/markdown.js +10 -0
- package/dist/utils/markdown.js.map +1 -0
- package/package.json +4 -2
- 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
|
|
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
|
|
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` -> `
|
|
202
|
-
- CLI `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 `
|
|
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
|
-
**
|
|
222
|
+
**GHCR:**
|
|
223
223
|
```bash
|
|
224
224
|
# For production (gateway)
|
|
225
|
-
docker pull
|
|
225
|
+
docker pull ghcr.io/lobu-ai/lobu-gateway:0.1.0
|
|
226
226
|
|
|
227
227
|
# For quick start (extend this)
|
|
228
|
-
docker pull
|
|
228
|
+
docker pull ghcr.io/lobu-ai/lobu-worker-base:0.1.0
|
|
229
229
|
```
|
|
230
230
|
|
|
231
231
|
**NPM Registry:**
|
|
@@ -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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"}
|
package/dist/api/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"
|
|
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"}
|
package/dist/api/client.js
CHANGED
|
@@ -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
|
|
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",
|
package/dist/api/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/api/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
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
|
-
|
|
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":"
|
|
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"}
|
package/dist/api/credentials.js
CHANGED
|
@@ -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
|
-
|
|
5
|
-
const CREDENTIALS_FILE = join(
|
|
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
|
-
|
|
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
|
-
|
|
17
|
-
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
|
|
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,
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/api/credentials.ts"],"names":[],"mappings":"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"}
|