aquaman-plugin 0.9.1 → 0.9.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/index.ts +135 -92
- package/package.json +3 -3
package/index.ts
CHANGED
|
@@ -17,6 +17,16 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
|
20
|
+
|
|
21
|
+
// OpenClawPluginDefinition exists in the SDK internals but isn't re-exported from "openclaw/plugin-sdk".
|
|
22
|
+
// Mirror the type here until OpenClaw exposes it from the barrel.
|
|
23
|
+
type OpenClawPluginDefinition = {
|
|
24
|
+
id?: string;
|
|
25
|
+
name?: string;
|
|
26
|
+
description?: string;
|
|
27
|
+
version?: string;
|
|
28
|
+
register?: (api: OpenClawPluginApi) => void | Promise<void>;
|
|
29
|
+
};
|
|
20
30
|
import * as fs from "node:fs";
|
|
21
31
|
import * as path from "node:path";
|
|
22
32
|
import * as os from "node:os";
|
|
@@ -52,7 +62,7 @@ let proxyManager: ProxyManager | null = null;
|
|
|
52
62
|
let httpInterceptor: HttpInterceptor | null = null;
|
|
53
63
|
let socketPath: string | null = null;
|
|
54
64
|
let dynamicHostMap: Map<string, string> | null = null;
|
|
55
|
-
|
|
65
|
+
let configuredServices: string[] = ["anthropic", "openai"];
|
|
56
66
|
|
|
57
67
|
/** Default socket path */
|
|
58
68
|
function getDefaultSocketPath(): string {
|
|
@@ -169,7 +179,7 @@ function activateHttpInterceptor(log: OpenClawPluginApi["logger"]): void {
|
|
|
169
179
|
/**
|
|
170
180
|
* Set environment variables for SDK clients using sentinel hostname
|
|
171
181
|
*/
|
|
172
|
-
function configureEnvironment(log: OpenClawPluginApi["logger"]): void {
|
|
182
|
+
function configureEnvironment(log: OpenClawPluginApi["logger"], services: string[]): void {
|
|
173
183
|
for (const service of services) {
|
|
174
184
|
const serviceUrl = `http://aquaman.local/${service}`;
|
|
175
185
|
|
|
@@ -197,11 +207,12 @@ function configureEnvironment(log: OpenClawPluginApi["logger"]): void {
|
|
|
197
207
|
/**
|
|
198
208
|
* Register the aquaman_status tool
|
|
199
209
|
*/
|
|
200
|
-
function registerStatusTool(api: OpenClawPluginApi): void {
|
|
210
|
+
function registerStatusTool(api: OpenClawPluginApi, services: string[]): void {
|
|
201
211
|
api.registerTool(
|
|
202
212
|
() => {
|
|
203
213
|
return {
|
|
204
214
|
name: "aquaman_status",
|
|
215
|
+
label: "Aquaman Status",
|
|
205
216
|
description:
|
|
206
217
|
"Check aquaman credential proxy status and configured services",
|
|
207
218
|
parameters: {
|
|
@@ -209,8 +220,8 @@ function registerStatusTool(api: OpenClawPluginApi): void {
|
|
|
209
220
|
properties: {},
|
|
210
221
|
required: [] as string[],
|
|
211
222
|
},
|
|
212
|
-
async execute() {
|
|
213
|
-
|
|
223
|
+
async execute(_toolCallId: string, _params: unknown) {
|
|
224
|
+
const status = {
|
|
214
225
|
proxyRunning: proxyManager !== null,
|
|
215
226
|
socketPath: socketPath || getDefaultSocketPath(),
|
|
216
227
|
services,
|
|
@@ -227,6 +238,10 @@ function registerStatusTool(api: OpenClawPluginApi): void {
|
|
|
227
238
|
})
|
|
228
239
|
),
|
|
229
240
|
};
|
|
241
|
+
return {
|
|
242
|
+
content: [{ type: "text" as const, text: JSON.stringify(status, null, 2) }],
|
|
243
|
+
details: status,
|
|
244
|
+
};
|
|
230
245
|
},
|
|
231
246
|
};
|
|
232
247
|
},
|
|
@@ -239,7 +254,7 @@ function registerStatusTool(api: OpenClawPluginApi): void {
|
|
|
239
254
|
* OpenClaw checks its auth store before making API calls — without a placeholder
|
|
240
255
|
* key, requests are rejected before they ever reach the proxy.
|
|
241
256
|
*/
|
|
242
|
-
function ensureAuthProfiles(log: OpenClawPluginApi["logger"]): void {
|
|
257
|
+
function ensureAuthProfiles(log: OpenClawPluginApi["logger"], services: string[]): void {
|
|
243
258
|
const stateDir =
|
|
244
259
|
process.env.OPENCLAW_STATE_DIR ||
|
|
245
260
|
path.join(os.homedir(), ".openclaw");
|
|
@@ -280,127 +295,155 @@ function ensureAuthProfiles(log: OpenClawPluginApi["logger"]): void {
|
|
|
280
295
|
}
|
|
281
296
|
|
|
282
297
|
/**
|
|
283
|
-
* OpenClaw
|
|
298
|
+
* Aquaman OpenClaw Plugin Definition
|
|
284
299
|
*/
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
300
|
+
const plugin: OpenClawPluginDefinition = {
|
|
301
|
+
id: 'aquaman-plugin',
|
|
302
|
+
name: 'Aquaman Vault',
|
|
303
|
+
version: PLUGIN_VERSION,
|
|
304
|
+
description: 'Credential isolation for OpenClaw — API keys never enter the agent process',
|
|
305
|
+
|
|
306
|
+
register(api) {
|
|
307
|
+
api.logger.info("Aquaman plugin loaded");
|
|
308
|
+
|
|
309
|
+
// Read services from plugin config
|
|
310
|
+
const pluginCfg = api.pluginConfig as { backend?: string; services?: string[] } | undefined;
|
|
311
|
+
configuredServices = pluginCfg?.services ?? ["anthropic", "openai"];
|
|
312
|
+
|
|
313
|
+
// Auto-generate auth-profiles.json if missing
|
|
314
|
+
ensureAuthProfiles(api.logger, configuredServices);
|
|
315
|
+
|
|
316
|
+
// Local proxy mode — requires aquaman CLI
|
|
317
|
+
if (!isAquamanInstalled()) {
|
|
318
|
+
api.logger.warn(
|
|
319
|
+
"aquaman CLI not found. Install with: npm install -g aquaman-proxy"
|
|
320
|
+
);
|
|
321
|
+
api.logger.warn(
|
|
322
|
+
"Then run: aquaman setup"
|
|
323
|
+
);
|
|
324
|
+
configureEnvironment(api.logger, configuredServices);
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
302
327
|
|
|
303
|
-
|
|
328
|
+
api.logger.info("aquaman CLI found, will start proxy on gateway start");
|
|
304
329
|
|
|
305
|
-
|
|
306
|
-
|
|
330
|
+
// Configure environment variables immediately (sentinel hostname)
|
|
331
|
+
configureEnvironment(api.logger, configuredServices);
|
|
307
332
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
async
|
|
312
|
-
|
|
333
|
+
// Register service for proxy lifecycle management
|
|
334
|
+
api.registerService({
|
|
335
|
+
id: 'aquaman-proxy',
|
|
336
|
+
async start(ctx) {
|
|
337
|
+
ctx.logger.info("Starting aquaman proxy...");
|
|
313
338
|
|
|
314
|
-
const started = await startProxy(
|
|
339
|
+
const started = await startProxy(ctx.logger);
|
|
315
340
|
if (started && socketPath) {
|
|
316
|
-
|
|
341
|
+
ctx.logger.info("Aquaman proxy started successfully");
|
|
317
342
|
|
|
318
343
|
// Check for version mismatch between plugin and proxy
|
|
319
344
|
const proxyVersion = await getProxyVersion(socketPath);
|
|
320
345
|
if (proxyVersion && proxyVersion !== PLUGIN_VERSION) {
|
|
321
|
-
|
|
346
|
+
ctx.logger.warn(
|
|
322
347
|
`Warning: plugin version ${PLUGIN_VERSION} \u2260 proxy version ${proxyVersion}. ` +
|
|
323
348
|
`Update both: npm install -g aquaman-proxy && openclaw plugins install aquaman-plugin`
|
|
324
349
|
);
|
|
325
350
|
}
|
|
326
351
|
|
|
327
352
|
// Activate HTTP interceptor to redirect channel traffic through proxy
|
|
328
|
-
activateHttpInterceptor(
|
|
353
|
+
activateHttpInterceptor(ctx.logger);
|
|
329
354
|
} else {
|
|
330
|
-
|
|
355
|
+
ctx.logger.error("Failed to start aquaman proxy");
|
|
331
356
|
// Check if another instance is already running
|
|
332
357
|
const defaultSock = getDefaultSocketPath();
|
|
333
358
|
const alreadyRunning = await isProxyRunning(defaultSock);
|
|
334
359
|
if (alreadyRunning) {
|
|
335
360
|
socketPath = defaultSock;
|
|
336
|
-
|
|
361
|
+
ctx.logger.info(
|
|
337
362
|
"Another aquaman instance is already running — using it"
|
|
338
363
|
);
|
|
339
364
|
// Load host map from existing proxy
|
|
340
365
|
const map = await loadHostMap(defaultSock);
|
|
341
366
|
dynamicHostMap = map.size > 0 ? map : FALLBACK_HOST_MAP;
|
|
342
|
-
activateHttpInterceptor(
|
|
367
|
+
activateHttpInterceptor(ctx.logger);
|
|
343
368
|
} else {
|
|
344
|
-
|
|
369
|
+
ctx.logger.error(
|
|
345
370
|
"No running proxy found. Check: aquaman doctor"
|
|
346
371
|
);
|
|
347
372
|
}
|
|
348
373
|
}
|
|
349
374
|
},
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
api.logger.info("Stopping aquaman proxy...");
|
|
375
|
+
async stop(ctx) {
|
|
376
|
+
ctx.logger.info("Stopping aquaman proxy...");
|
|
353
377
|
stopProxy();
|
|
354
|
-
}
|
|
378
|
+
}
|
|
355
379
|
});
|
|
356
|
-
}
|
|
357
380
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
381
|
+
// Register /aquaman-status slash command for humans
|
|
382
|
+
api.registerCommand({
|
|
383
|
+
name: 'aquaman-status',
|
|
384
|
+
description: 'Show aquaman credential proxy status and configured services',
|
|
385
|
+
acceptsArgs: false,
|
|
386
|
+
requireAuth: true,
|
|
387
|
+
async handler() {
|
|
388
|
+
const status = {
|
|
389
|
+
proxyRunning: proxyManager !== null,
|
|
390
|
+
socketPath: socketPath || getDefaultSocketPath(),
|
|
391
|
+
services: configuredServices,
|
|
392
|
+
httpInterceptorActive: httpInterceptor?.isActive() ?? false,
|
|
393
|
+
};
|
|
394
|
+
return { text: JSON.stringify(status, null, 2) };
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
// Register CLI commands if available
|
|
399
|
+
if (api.registerCli) {
|
|
400
|
+
api.registerCli(
|
|
401
|
+
({ program }) => {
|
|
402
|
+
const aquamanCmd = program
|
|
403
|
+
.command("aquaman")
|
|
404
|
+
.description("Aquaman credential management");
|
|
405
|
+
|
|
406
|
+
aquamanCmd
|
|
407
|
+
.command("status")
|
|
408
|
+
.description("Show aquaman proxy status")
|
|
409
|
+
.action(() => {
|
|
410
|
+
console.log("\nAquaman Status:");
|
|
411
|
+
console.log(` Proxy running: ${proxyManager !== null}`);
|
|
412
|
+
console.log(` Socket path: ${socketPath || getDefaultSocketPath()}`);
|
|
413
|
+
console.log(` Services: ${configuredServices.join(", ")}`);
|
|
414
|
+
console.log("\nEnvironment Variables:");
|
|
415
|
+
for (const service of configuredServices) {
|
|
416
|
+
const envKey =
|
|
417
|
+
service === "anthropic"
|
|
418
|
+
? "ANTHROPIC_BASE_URL"
|
|
419
|
+
: service === "openai"
|
|
420
|
+
? "OPENAI_BASE_URL"
|
|
421
|
+
: `${service.toUpperCase()}_BASE_URL`;
|
|
422
|
+
console.log(` ${envKey}=${process.env[envKey] ?? "(not set)"}`);
|
|
423
|
+
}
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
aquamanCmd
|
|
427
|
+
.command("add <service> [key]")
|
|
428
|
+
.description("Add a credential (opens secure prompt)")
|
|
429
|
+
.action((service: string, key: string = "api_key") => {
|
|
430
|
+
console.log(`\n Run in your terminal:\n aquaman credentials add ${service} ${key}\n`);
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
aquamanCmd
|
|
434
|
+
.command("list")
|
|
435
|
+
.description("List stored credentials")
|
|
436
|
+
.action(() => {
|
|
437
|
+
console.log(`\n Run in your terminal:\n aquaman credentials list\n`);
|
|
438
|
+
});
|
|
439
|
+
},
|
|
440
|
+
{ commands: ["aquaman"] }
|
|
441
|
+
);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
registerStatusTool(api, configuredServices);
|
|
445
|
+
api.logger.info("Aquaman plugin registered successfully");
|
|
402
446
|
}
|
|
447
|
+
};
|
|
403
448
|
|
|
404
|
-
|
|
405
|
-
api.logger.info("Aquaman plugin registered successfully");
|
|
406
|
-
}
|
|
449
|
+
export default plugin;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aquaman-plugin",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.2",
|
|
4
4
|
"description": "Credential isolation plugin for OpenClaw",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -26,8 +26,8 @@
|
|
|
26
26
|
"undici": "^7.0.0"
|
|
27
27
|
},
|
|
28
28
|
"peerDependencies": {
|
|
29
|
-
"openclaw": ">=2026.1.
|
|
30
|
-
"aquaman-proxy": "0.9.
|
|
29
|
+
"openclaw": ">=2026.1.11",
|
|
30
|
+
"aquaman-proxy": "0.9.2"
|
|
31
31
|
},
|
|
32
32
|
"peerDependenciesMeta": {
|
|
33
33
|
"aquaman-proxy": {
|