agentspd 1.0.0 → 1.1.0
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 +77 -294
- package/dist/api.d.ts +66 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +147 -0
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +114 -32
- package/dist/commands/auth.d.ts.map +1 -1
- package/dist/commands/auth.js +58 -41
- package/dist/commands/index.d.ts +2 -0
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +2 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +111 -19
- package/dist/commands/openclaw.d.ts +3 -0
- package/dist/commands/openclaw.d.ts.map +1 -0
- package/dist/commands/openclaw.js +1033 -0
- package/dist/commands/policies.d.ts.map +1 -1
- package/dist/commands/policies.js +137 -41
- package/dist/commands/threats.d.ts.map +1 -1
- package/dist/commands/threats.js +75 -29
- package/dist/commands/webhooks.d.ts.map +1 -1
- package/dist/commands/webhooks.js +24 -21
- package/dist/commands/workspaces.d.ts +5 -0
- package/dist/commands/workspaces.d.ts.map +1 -0
- package/dist/commands/workspaces.js +514 -0
- package/dist/config.d.ts +6 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +34 -23
- package/dist/index.js +178 -155
- package/dist/openclaw-api.d.ts +81 -0
- package/dist/openclaw-api.d.ts.map +1 -0
- package/dist/openclaw-api.js +262 -0
- package/package.json +6 -6
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight HTTP client for the OpenClaw Gateway API.
|
|
3
|
+
*
|
|
4
|
+
* OpenClaw exposes a single HTTP endpoint that multiplexes tool calls:
|
|
5
|
+
* - POST /tools/invoke — invoke any registered tool
|
|
6
|
+
*
|
|
7
|
+
* Available tools include:
|
|
8
|
+
* - sessions_list — list all active sessions
|
|
9
|
+
* - sessions_history — get transcript for a session
|
|
10
|
+
* - message (send) — send a message to a channel
|
|
11
|
+
*
|
|
12
|
+
* All endpoints share the same auth: Bearer token via `gateway.auth.token`.
|
|
13
|
+
*/
|
|
14
|
+
function authHeaders(token) {
|
|
15
|
+
return {
|
|
16
|
+
Authorization: `Bearer ${token}`,
|
|
17
|
+
"Content-Type": "application/json",
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Extract sessions from the OpenClaw Gateway tool-invoke response.
|
|
22
|
+
*
|
|
23
|
+
* The gateway wraps sessions_list output as:
|
|
24
|
+
* { ok, result: { details: { sessions: [...] } } }
|
|
25
|
+
*
|
|
26
|
+
* But older / simpler gateways may return a flat array at `result` directly.
|
|
27
|
+
*/
|
|
28
|
+
function extractSessions(data) {
|
|
29
|
+
const result = data.result;
|
|
30
|
+
if (Array.isArray(result))
|
|
31
|
+
return result;
|
|
32
|
+
if (result && typeof result === "object") {
|
|
33
|
+
const payload = result;
|
|
34
|
+
if (Array.isArray(payload.details?.sessions)) {
|
|
35
|
+
return payload.details.sessions;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return [];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Test connectivity to an OpenClaw Gateway by invoking `sessions_list`.
|
|
42
|
+
*/
|
|
43
|
+
export async function testConnection(gatewayUrl, token) {
|
|
44
|
+
const start = Date.now();
|
|
45
|
+
try {
|
|
46
|
+
const response = await fetch(`${gatewayUrl}/tools/invoke`, {
|
|
47
|
+
method: "POST",
|
|
48
|
+
headers: authHeaders(token),
|
|
49
|
+
body: JSON.stringify({ tool: "sessions_list", action: "json", args: {} }),
|
|
50
|
+
});
|
|
51
|
+
const latencyMs = Date.now() - start;
|
|
52
|
+
if (response.status === 401) {
|
|
53
|
+
return {
|
|
54
|
+
connected: false,
|
|
55
|
+
latencyMs,
|
|
56
|
+
error: "Authentication failed — check your Gateway token",
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
if (response.status === 404) {
|
|
60
|
+
// Tools Invoke API might not recognize sessions_list, but the endpoint responded
|
|
61
|
+
return {
|
|
62
|
+
connected: true,
|
|
63
|
+
latencyMs,
|
|
64
|
+
error: "Gateway reachable but sessions_list tool not available",
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
if (!response.ok) {
|
|
68
|
+
return {
|
|
69
|
+
connected: false,
|
|
70
|
+
latencyMs,
|
|
71
|
+
error: `Gateway returned HTTP ${response.status}`,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
const data = (await response.json());
|
|
75
|
+
const sessions = extractSessions(data);
|
|
76
|
+
return {
|
|
77
|
+
connected: true,
|
|
78
|
+
latencyMs,
|
|
79
|
+
sessions: sessions.length > 0 ? sessions : undefined,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
const latencyMs = Date.now() - start;
|
|
84
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
85
|
+
return {
|
|
86
|
+
connected: false,
|
|
87
|
+
latencyMs,
|
|
88
|
+
error: `Cannot reach Gateway: ${message}`,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* List active sessions on the OpenClaw Gateway.
|
|
94
|
+
*/
|
|
95
|
+
export async function listSessions(gatewayUrl, token) {
|
|
96
|
+
const response = await fetch(`${gatewayUrl}/tools/invoke`, {
|
|
97
|
+
method: "POST",
|
|
98
|
+
headers: authHeaders(token),
|
|
99
|
+
body: JSON.stringify({ tool: "sessions_list", action: "json", args: {} }),
|
|
100
|
+
});
|
|
101
|
+
if (!response.ok) {
|
|
102
|
+
throw new Error(`Failed to list sessions: HTTP ${response.status}`);
|
|
103
|
+
}
|
|
104
|
+
const data = (await response.json());
|
|
105
|
+
if (!data.ok) {
|
|
106
|
+
throw new Error(data.error?.message || "Failed to list sessions");
|
|
107
|
+
}
|
|
108
|
+
return extractSessions(data);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Fetch the transcript / history for a specific OpenClaw session.
|
|
112
|
+
*/
|
|
113
|
+
export async function getSessionHistory(gatewayUrl, token, sessionKey) {
|
|
114
|
+
const response = await fetch(`${gatewayUrl}/tools/invoke`, {
|
|
115
|
+
method: "POST",
|
|
116
|
+
headers: authHeaders(token),
|
|
117
|
+
body: JSON.stringify({
|
|
118
|
+
tool: "sessions_history",
|
|
119
|
+
action: "json",
|
|
120
|
+
args: { sessionKey },
|
|
121
|
+
}),
|
|
122
|
+
});
|
|
123
|
+
if (!response.ok) {
|
|
124
|
+
throw new Error(`Failed to fetch session history: HTTP ${response.status}`);
|
|
125
|
+
}
|
|
126
|
+
const data = (await response.json());
|
|
127
|
+
if (!data.ok) {
|
|
128
|
+
throw new Error(data.error?.message || "Failed to fetch session history");
|
|
129
|
+
}
|
|
130
|
+
// History may come nested in result.details.messages or result directly.
|
|
131
|
+
const result = data.result;
|
|
132
|
+
if (Array.isArray(result))
|
|
133
|
+
return result;
|
|
134
|
+
if (result && typeof result === "object") {
|
|
135
|
+
const details = result.details;
|
|
136
|
+
if (details && Array.isArray(details.messages))
|
|
137
|
+
return details.messages;
|
|
138
|
+
if (details && Array.isArray(details.history))
|
|
139
|
+
return details.history;
|
|
140
|
+
}
|
|
141
|
+
return [];
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Send a message through the OpenClaw Gateway using the `message` tool.
|
|
145
|
+
*
|
|
146
|
+
* The Gateway exposes tool invocation via `POST /tools/invoke`. The
|
|
147
|
+
* `message` tool with `action: "send"` delivers a message to the
|
|
148
|
+
* specified channel (slack, telegram, whatsapp, etc.).
|
|
149
|
+
*
|
|
150
|
+
* The `message` tool always requires a `to` target. When none is
|
|
151
|
+
* explicitly provided we auto-resolve it from the most recently active
|
|
152
|
+
* session that matches the requested channel.
|
|
153
|
+
*/
|
|
154
|
+
export async function invokeHook(gatewayUrl, token, options) {
|
|
155
|
+
const wantedChannel = options.channel && options.channel !== "last"
|
|
156
|
+
? options.channel
|
|
157
|
+
: undefined;
|
|
158
|
+
let to = options.to;
|
|
159
|
+
// Auto-resolve target from sessions if not provided.
|
|
160
|
+
if (!to) {
|
|
161
|
+
try {
|
|
162
|
+
const sessions = await listSessions(gatewayUrl, token);
|
|
163
|
+
// Sort by most recently active (updatedAt descending).
|
|
164
|
+
const sorted = [...sessions].sort((a, b) => (b.updatedAt ?? 0) - (a.updatedAt ?? 0));
|
|
165
|
+
// Pick the first session that matches the wanted channel, or the
|
|
166
|
+
// most recently active session overall.
|
|
167
|
+
const match = wantedChannel
|
|
168
|
+
? sorted.find((s) => s.channel === wantedChannel)
|
|
169
|
+
: sorted[0];
|
|
170
|
+
if (match) {
|
|
171
|
+
// deliveryContext holds the correct `to` for message_send.
|
|
172
|
+
const dc = match
|
|
173
|
+
.deliveryContext;
|
|
174
|
+
to = dc?.to;
|
|
175
|
+
// If the session doesn't carry a deliveryContext.to, fall back
|
|
176
|
+
// to deriving one from the session key.
|
|
177
|
+
if (!to && match.key) {
|
|
178
|
+
// Session keys look like "agent:main:slack:channel:C0AE86…"
|
|
179
|
+
const parts = match.key.split(":");
|
|
180
|
+
const channelIdx = parts.indexOf("channel");
|
|
181
|
+
const groupIdx = parts.indexOf("group");
|
|
182
|
+
const targetIdx = channelIdx !== -1
|
|
183
|
+
? channelIdx
|
|
184
|
+
: groupIdx !== -1
|
|
185
|
+
? groupIdx
|
|
186
|
+
: -1;
|
|
187
|
+
if (targetIdx !== -1 && parts[targetIdx + 1]) {
|
|
188
|
+
to = `channel:${parts[targetIdx + 1].toUpperCase()}`;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
if (!to) {
|
|
193
|
+
return {
|
|
194
|
+
ok: false,
|
|
195
|
+
error: wantedChannel
|
|
196
|
+
? `No active ${wantedChannel} session found on the Gateway to resolve a delivery target`
|
|
197
|
+
: "No active sessions found on the Gateway to resolve a delivery target",
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
catch (err) {
|
|
202
|
+
return {
|
|
203
|
+
ok: false,
|
|
204
|
+
error: `Failed to resolve delivery target: ${err instanceof Error ? err.message : String(err)}`,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
const args = {
|
|
209
|
+
message: options.message,
|
|
210
|
+
to,
|
|
211
|
+
};
|
|
212
|
+
if (wantedChannel) {
|
|
213
|
+
args.channel = wantedChannel;
|
|
214
|
+
}
|
|
215
|
+
try {
|
|
216
|
+
const response = await fetch(`${gatewayUrl}/tools/invoke`, {
|
|
217
|
+
method: "POST",
|
|
218
|
+
headers: authHeaders(token),
|
|
219
|
+
body: JSON.stringify({
|
|
220
|
+
tool: "message",
|
|
221
|
+
action: "send",
|
|
222
|
+
args,
|
|
223
|
+
}),
|
|
224
|
+
});
|
|
225
|
+
if (response.status === 401) {
|
|
226
|
+
return {
|
|
227
|
+
ok: false,
|
|
228
|
+
error: "Authentication failed — check your Gateway token",
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
if (!response.ok) {
|
|
232
|
+
return {
|
|
233
|
+
ok: false,
|
|
234
|
+
error: `Gateway returned HTTP ${response.status}`,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
const data = (await response.json());
|
|
238
|
+
if (!data.ok) {
|
|
239
|
+
return {
|
|
240
|
+
ok: false,
|
|
241
|
+
error: data.error?.message || "Message delivery failed",
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
return { ok: true };
|
|
245
|
+
}
|
|
246
|
+
catch (err) {
|
|
247
|
+
return {
|
|
248
|
+
ok: false,
|
|
249
|
+
error: err instanceof Error ? err.message : String(err),
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Wake the OpenClaw main session by sending a system-level message
|
|
255
|
+
* through the Gateway's `message` tool.
|
|
256
|
+
*/
|
|
257
|
+
export async function wakeGateway(gatewayUrl, token, text) {
|
|
258
|
+
return invokeHook(gatewayUrl, token, {
|
|
259
|
+
message: text,
|
|
260
|
+
channel: "last",
|
|
261
|
+
});
|
|
262
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agentspd",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Emotos CLI - Security Infrastructure for AI Agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -29,20 +29,19 @@
|
|
|
29
29
|
"author": "Emotos <hello@emotos.ai>",
|
|
30
30
|
"repository": {
|
|
31
31
|
"type": "git",
|
|
32
|
-
"url": "git+https://github.com/
|
|
33
|
-
"directory": "cli"
|
|
32
|
+
"url": "git+https://github.com/EmotosAI/AgentsPD.git"
|
|
34
33
|
},
|
|
35
34
|
"homepage": "https://emotos.ai",
|
|
36
35
|
"bugs": {
|
|
37
|
-
"url": "https://github.com/
|
|
36
|
+
"url": "https://github.com/EmotosAI/AgentsPD/issues"
|
|
38
37
|
},
|
|
39
38
|
"dependencies": {
|
|
40
39
|
"chalk": "^5.3.0",
|
|
41
40
|
"commander": "^12.1.0",
|
|
42
|
-
"conf": "^13.0
|
|
41
|
+
"conf": "^13.1.0",
|
|
43
42
|
"inquirer": "^9.2.15",
|
|
44
43
|
"ora": "^8.0.1",
|
|
45
|
-
"table": "^6.
|
|
44
|
+
"table": "^6.9.0",
|
|
46
45
|
"ws": "^8.17.0",
|
|
47
46
|
"yaml": "^2.3.4"
|
|
48
47
|
},
|
|
@@ -50,6 +49,7 @@
|
|
|
50
49
|
"@types/inquirer": "^9.0.7",
|
|
51
50
|
"@types/node": "^22.10.5",
|
|
52
51
|
"@types/ws": "^8.5.12",
|
|
52
|
+
"@types/yaml": "^1.9.6",
|
|
53
53
|
"typescript": "^5.7.3"
|
|
54
54
|
},
|
|
55
55
|
"engines": {
|