@alfe.ai/gateway 0.0.1 → 0.0.2
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/dist/health.js +65 -24
- package/dist/src/index.d.ts +4 -4
- package/package.json +5 -3
package/dist/health.js
CHANGED
|
@@ -5,6 +5,7 @@ import { homedir } from "node:os";
|
|
|
5
5
|
import pino from "pino";
|
|
6
6
|
import { chmodSync, existsSync, mkdirSync, unlinkSync } from "node:fs";
|
|
7
7
|
import { getEndpointFromToken, readConfig } from "@alfe.ai/config";
|
|
8
|
+
import { AlfeApiClient, AuthService } from "@alfe/api-client";
|
|
8
9
|
import { parse } from "smol-toml";
|
|
9
10
|
import WebSocket from "ws";
|
|
10
11
|
import { createConnection, createServer } from "node:net";
|
|
@@ -71,22 +72,32 @@ const PID_PATH = join(ALFE_DIR, "gateway.pid");
|
|
|
71
72
|
* Returns agentId (derived from tokenId) and orgId (tenantId).
|
|
72
73
|
*/
|
|
73
74
|
async function resolveAgentIdentity(apiKey, apiEndpoint) {
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
75
|
+
const auth = new AuthService(new AlfeApiClient({
|
|
76
|
+
apiBaseUrl: apiEndpoint,
|
|
77
|
+
getToken: () => Promise.resolve(apiKey)
|
|
78
|
+
}));
|
|
79
|
+
const maxAttempts = 3;
|
|
80
|
+
const delayMs = 3e3;
|
|
81
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
82
|
+
const result = await auth.validate(apiKey);
|
|
83
|
+
if (!result.ok) {
|
|
84
|
+
if (result.status === 401 || result.status === 403) throw new Error(`Token validation failed: ${result.error}. Is your API key valid? Run \`alfe login\` to reconfigure.`);
|
|
85
|
+
if (attempt < maxAttempts) {
|
|
86
|
+
await new Promise((r) => setTimeout(r, delayMs));
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
throw new Error(`Token validation failed after ${String(maxAttempts)} attempts: ${result.error}. Is your API key valid? Run \`alfe login\` to reconfigure.`);
|
|
90
|
+
}
|
|
91
|
+
if (!result.data.valid) throw new Error("API key invalid: validation failed. Run `alfe login` to reconfigure.");
|
|
92
|
+
const orgId = result.data.tenantId;
|
|
93
|
+
if (!orgId) throw new Error("Token validation returned no tenantId — cannot determine org.");
|
|
94
|
+
return {
|
|
95
|
+
agentId: result.data.tokenId ?? deriveAgentId(apiKey),
|
|
96
|
+
orgId,
|
|
97
|
+
runtime: result.data.runtime ?? "openclaw"
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
throw new Error("Token validation failed: exhausted retries.");
|
|
90
101
|
}
|
|
91
102
|
/**
|
|
92
103
|
* Derive a stable agent ID from an API key (fallback when tokenId not available).
|
|
@@ -192,10 +203,10 @@ async function loadDaemonConfig() {
|
|
|
192
203
|
/**
|
|
193
204
|
* Fetch agent workspace config from the API.
|
|
194
205
|
*
|
|
195
|
-
* 1. GET /agents/me/workspace → {
|
|
196
|
-
* 2. If
|
|
206
|
+
* 1. GET /agents/me/workspace → { templateKey }
|
|
207
|
+
* 2. If templateKey set, GET /templates/:key/files → persona file contents
|
|
197
208
|
*
|
|
198
|
-
* Returns null if the agent has no
|
|
209
|
+
* Returns null if the agent has no template assigned or the fetch fails.
|
|
199
210
|
*/
|
|
200
211
|
async function fetchAgentConfig(apiKey, apiEndpoint) {
|
|
201
212
|
try {
|
|
@@ -204,18 +215,18 @@ async function fetchAgentConfig(apiKey, apiEndpoint) {
|
|
|
204
215
|
headers: { "Authorization": `Bearer ${apiKey}` }
|
|
205
216
|
});
|
|
206
217
|
if (!wsResponse.ok) return null;
|
|
207
|
-
const
|
|
208
|
-
if (!
|
|
209
|
-
const filesResponse = await fetch(`${apiEndpoint}/
|
|
218
|
+
const templateKey = (await wsResponse.json()).data?.templateKey;
|
|
219
|
+
if (!templateKey) return null;
|
|
220
|
+
const filesResponse = await fetch(`${apiEndpoint}/templates/${encodeURIComponent(templateKey)}/files`, {
|
|
210
221
|
method: "GET",
|
|
211
222
|
headers: { "Authorization": `Bearer ${apiKey}` }
|
|
212
223
|
});
|
|
213
224
|
if (!filesResponse.ok) return {
|
|
214
|
-
|
|
225
|
+
templateKey,
|
|
215
226
|
files: {}
|
|
216
227
|
};
|
|
217
228
|
return {
|
|
218
|
-
|
|
229
|
+
templateKey,
|
|
219
230
|
files: (await filesResponse.json()).data?.files ?? {}
|
|
220
231
|
};
|
|
221
232
|
} catch {
|
|
@@ -232,6 +243,7 @@ const ID_PREFIXES = {
|
|
|
232
243
|
token: "tok",
|
|
233
244
|
transaction: "txn",
|
|
234
245
|
subscription: "sub",
|
|
246
|
+
conversation: "conv",
|
|
235
247
|
request: "req",
|
|
236
248
|
connection: "conn",
|
|
237
249
|
correlation: "cor",
|
|
@@ -1635,6 +1647,35 @@ async function startDaemon() {
|
|
|
1635
1647
|
}, "Alfe Gateway Daemon started ✅");
|
|
1636
1648
|
}
|
|
1637
1649
|
async function handleCloudCommand(command) {
|
|
1650
|
+
if (command.command === "support.diagnostic") try {
|
|
1651
|
+
const { runDiagnostic } = await import("@alfe.ai/doctor");
|
|
1652
|
+
const payload = command.payload;
|
|
1653
|
+
const workspacePath = Object.values(config.runtimes)[0]?.workspace ?? "~/.openclaw";
|
|
1654
|
+
const report = await runDiagnostic({
|
|
1655
|
+
task: payload.task,
|
|
1656
|
+
workspacePath,
|
|
1657
|
+
apiKey: payload.apiKey,
|
|
1658
|
+
timeoutSeconds: 60
|
|
1659
|
+
});
|
|
1660
|
+
return {
|
|
1661
|
+
type: "COMMAND_ACK",
|
|
1662
|
+
commandId: command.commandId,
|
|
1663
|
+
status: report.success ? "ok" : "error",
|
|
1664
|
+
result: report
|
|
1665
|
+
};
|
|
1666
|
+
} catch (err) {
|
|
1667
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1668
|
+
logger.error({ err: message }, "Diagnostic failed");
|
|
1669
|
+
return {
|
|
1670
|
+
type: "COMMAND_ACK",
|
|
1671
|
+
commandId: command.commandId,
|
|
1672
|
+
status: "error",
|
|
1673
|
+
result: {
|
|
1674
|
+
code: "DIAGNOSTIC_FAILED",
|
|
1675
|
+
message
|
|
1676
|
+
}
|
|
1677
|
+
};
|
|
1678
|
+
}
|
|
1638
1679
|
const ipcRequest = cloudCommandToIPCRequest(command);
|
|
1639
1680
|
if (!ipcRequest) {
|
|
1640
1681
|
logger.warn({ command: command.command }, "Unrecognized cloud command");
|
package/dist/src/index.d.ts
CHANGED
|
@@ -38,7 +38,7 @@ declare function startDaemon(): Promise<void>;
|
|
|
38
38
|
* 4. Use tokenId as agent identity for cloud registration
|
|
39
39
|
*/
|
|
40
40
|
interface AgentWorkspaceConfig {
|
|
41
|
-
|
|
41
|
+
templateKey?: string;
|
|
42
42
|
files: Record<string, string>;
|
|
43
43
|
}
|
|
44
44
|
declare const ALFE_DIR: string;
|
|
@@ -86,10 +86,10 @@ declare function loadDaemonConfig(): Promise<DaemonConfig>;
|
|
|
86
86
|
/**
|
|
87
87
|
* Fetch agent workspace config from the API.
|
|
88
88
|
*
|
|
89
|
-
* 1. GET /agents/me/workspace → {
|
|
90
|
-
* 2. If
|
|
89
|
+
* 1. GET /agents/me/workspace → { templateKey }
|
|
90
|
+
* 2. If templateKey set, GET /templates/:key/files → persona file contents
|
|
91
91
|
*
|
|
92
|
-
* Returns null if the agent has no
|
|
92
|
+
* Returns null if the agent has no template assigned or the fetch fails.
|
|
93
93
|
*/
|
|
94
94
|
declare function fetchAgentConfig(apiKey: string, apiEndpoint: string): Promise<AgentWorkspaceConfig | null>;
|
|
95
95
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alfe.ai/gateway",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
4
4
|
"description": "Alfe local gateway daemon — persistent control plane for agent integrations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -22,8 +22,10 @@
|
|
|
22
22
|
"smol-toml": "^1.3.0",
|
|
23
23
|
"pino-roll": "^1.2.0",
|
|
24
24
|
"ws": "^8.18.0",
|
|
25
|
-
"@alfe
|
|
26
|
-
"@alfe.ai/
|
|
25
|
+
"@alfe/api-client": "0.1.0",
|
|
26
|
+
"@alfe.ai/config": "^0.0.2",
|
|
27
|
+
"@alfe.ai/doctor": "^0.1.0",
|
|
28
|
+
"@alfe.ai/integrations": "^0.0.2"
|
|
27
29
|
},
|
|
28
30
|
"devDependencies": {
|
|
29
31
|
"@types/ws": "^8.5.13",
|