aquaman-plugin 0.9.0 → 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.
Files changed (3) hide show
  1. package/README.md +1 -0
  2. package/index.ts +137 -92
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -25,6 +25,7 @@ Agent / OpenClaw Gateway Aquaman Proxy
25
25
  │ (hash-chained log)
26
26
 
27
27
  api.anthropic.com
28
+ api.mistral.ai
28
29
  api.telegram.org
29
30
  slack.com/api ...
30
31
  ```
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
- const services = ["anthropic", "openai"];
65
+ let configuredServices: string[] = ["anthropic", "openai"];
56
66
 
57
67
  /** Default socket path */
58
68
  function getDefaultSocketPath(): string {
@@ -67,6 +77,8 @@ const FALLBACK_HOST_MAP = new Map<string, string>([
67
77
  ['api.github.com', 'github'],
68
78
  ['api.x.ai', 'xai'],
69
79
  ['gateway.ai.cloudflare.com', 'cloudflare-ai'],
80
+ ['api.mistral.ai', 'mistral'],
81
+ ['api-inference.huggingface.co', 'huggingface'],
70
82
  ['slack.com', 'slack'],
71
83
  ['*.slack.com', 'slack'],
72
84
  ['discord.com', 'discord'],
@@ -167,7 +179,7 @@ function activateHttpInterceptor(log: OpenClawPluginApi["logger"]): void {
167
179
  /**
168
180
  * Set environment variables for SDK clients using sentinel hostname
169
181
  */
170
- function configureEnvironment(log: OpenClawPluginApi["logger"]): void {
182
+ function configureEnvironment(log: OpenClawPluginApi["logger"], services: string[]): void {
171
183
  for (const service of services) {
172
184
  const serviceUrl = `http://aquaman.local/${service}`;
173
185
 
@@ -195,11 +207,12 @@ function configureEnvironment(log: OpenClawPluginApi["logger"]): void {
195
207
  /**
196
208
  * Register the aquaman_status tool
197
209
  */
198
- function registerStatusTool(api: OpenClawPluginApi): void {
210
+ function registerStatusTool(api: OpenClawPluginApi, services: string[]): void {
199
211
  api.registerTool(
200
212
  () => {
201
213
  return {
202
214
  name: "aquaman_status",
215
+ label: "Aquaman Status",
203
216
  description:
204
217
  "Check aquaman credential proxy status and configured services",
205
218
  parameters: {
@@ -207,8 +220,8 @@ function registerStatusTool(api: OpenClawPluginApi): void {
207
220
  properties: {},
208
221
  required: [] as string[],
209
222
  },
210
- async execute() {
211
- return {
223
+ async execute(_toolCallId: string, _params: unknown) {
224
+ const status = {
212
225
  proxyRunning: proxyManager !== null,
213
226
  socketPath: socketPath || getDefaultSocketPath(),
214
227
  services,
@@ -225,6 +238,10 @@ function registerStatusTool(api: OpenClawPluginApi): void {
225
238
  })
226
239
  ),
227
240
  };
241
+ return {
242
+ content: [{ type: "text" as const, text: JSON.stringify(status, null, 2) }],
243
+ details: status,
244
+ };
228
245
  },
229
246
  };
230
247
  },
@@ -237,7 +254,7 @@ function registerStatusTool(api: OpenClawPluginApi): void {
237
254
  * OpenClaw checks its auth store before making API calls — without a placeholder
238
255
  * key, requests are rejected before they ever reach the proxy.
239
256
  */
240
- function ensureAuthProfiles(log: OpenClawPluginApi["logger"]): void {
257
+ function ensureAuthProfiles(log: OpenClawPluginApi["logger"], services: string[]): void {
241
258
  const stateDir =
242
259
  process.env.OPENCLAW_STATE_DIR ||
243
260
  path.join(os.homedir(), ".openclaw");
@@ -278,127 +295,155 @@ function ensureAuthProfiles(log: OpenClawPluginApi["logger"]): void {
278
295
  }
279
296
 
280
297
  /**
281
- * OpenClaw plugin register function
298
+ * Aquaman OpenClaw Plugin Definition
282
299
  */
283
- export default function register(api: OpenClawPluginApi): void {
284
- api.logger.info("Aquaman plugin loaded");
285
-
286
- // Auto-generate auth-profiles.json if missing
287
- ensureAuthProfiles(api.logger);
288
-
289
- // Local proxy mode — requires aquaman CLI
290
- if (!isAquamanInstalled()) {
291
- api.logger.warn(
292
- "aquaman CLI not found. Install with: npm install -g aquaman-proxy"
293
- );
294
- api.logger.warn(
295
- "Then run: aquaman setup"
296
- );
297
- configureEnvironment(api.logger);
298
- return;
299
- }
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
+ }
300
327
 
301
- api.logger.info("aquaman CLI found, will start proxy on gateway start");
328
+ api.logger.info("aquaman CLI found, will start proxy on gateway start");
302
329
 
303
- // Configure environment variables immediately (sentinel hostname)
304
- configureEnvironment(api.logger);
330
+ // Configure environment variables immediately (sentinel hostname)
331
+ configureEnvironment(api.logger, configuredServices);
305
332
 
306
- // Register lifecycle hooks if available
307
- if (api.registerLifecycle) {
308
- api.registerLifecycle({
309
- async onGatewayStart() {
310
- api.logger.info("Starting aquaman proxy...");
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...");
311
338
 
312
- const started = await startProxy(api.logger);
339
+ const started = await startProxy(ctx.logger);
313
340
  if (started && socketPath) {
314
- api.logger.info("Aquaman proxy started successfully");
341
+ ctx.logger.info("Aquaman proxy started successfully");
315
342
 
316
343
  // Check for version mismatch between plugin and proxy
317
344
  const proxyVersion = await getProxyVersion(socketPath);
318
345
  if (proxyVersion && proxyVersion !== PLUGIN_VERSION) {
319
- api.logger.warn(
346
+ ctx.logger.warn(
320
347
  `Warning: plugin version ${PLUGIN_VERSION} \u2260 proxy version ${proxyVersion}. ` +
321
348
  `Update both: npm install -g aquaman-proxy && openclaw plugins install aquaman-plugin`
322
349
  );
323
350
  }
324
351
 
325
352
  // Activate HTTP interceptor to redirect channel traffic through proxy
326
- activateHttpInterceptor(api.logger);
353
+ activateHttpInterceptor(ctx.logger);
327
354
  } else {
328
- api.logger.error("Failed to start aquaman proxy");
355
+ ctx.logger.error("Failed to start aquaman proxy");
329
356
  // Check if another instance is already running
330
357
  const defaultSock = getDefaultSocketPath();
331
358
  const alreadyRunning = await isProxyRunning(defaultSock);
332
359
  if (alreadyRunning) {
333
360
  socketPath = defaultSock;
334
- api.logger.info(
361
+ ctx.logger.info(
335
362
  "Another aquaman instance is already running — using it"
336
363
  );
337
364
  // Load host map from existing proxy
338
365
  const map = await loadHostMap(defaultSock);
339
366
  dynamicHostMap = map.size > 0 ? map : FALLBACK_HOST_MAP;
340
- activateHttpInterceptor(api.logger);
367
+ activateHttpInterceptor(ctx.logger);
341
368
  } else {
342
- api.logger.error(
369
+ ctx.logger.error(
343
370
  "No running proxy found. Check: aquaman doctor"
344
371
  );
345
372
  }
346
373
  }
347
374
  },
348
-
349
- async onGatewayStop() {
350
- api.logger.info("Stopping aquaman proxy...");
375
+ async stop(ctx) {
376
+ ctx.logger.info("Stopping aquaman proxy...");
351
377
  stopProxy();
352
- },
378
+ }
353
379
  });
354
- }
355
380
 
356
- // Register CLI commands if available
357
- if (api.registerCli) {
358
- api.registerCli(
359
- ({ program }) => {
360
- const aquamanCmd = program
361
- .command("aquaman")
362
- .description("Aquaman credential management");
363
-
364
- aquamanCmd
365
- .command("status")
366
- .description("Show aquaman proxy status")
367
- .action(() => {
368
- console.log("\nAquaman Status:");
369
- console.log(` Proxy running: ${proxyManager !== null}`);
370
- console.log(` Socket path: ${socketPath || getDefaultSocketPath()}`);
371
- console.log(` Services: ${services.join(", ")}`);
372
- console.log("\nEnvironment Variables:");
373
- for (const service of services) {
374
- const envKey =
375
- service === "anthropic"
376
- ? "ANTHROPIC_BASE_URL"
377
- : service === "openai"
378
- ? "OPENAI_BASE_URL"
379
- : `${service.toUpperCase()}_BASE_URL`;
380
- console.log(` ${envKey}=${process.env[envKey] ?? "(not set)"}`);
381
- }
382
- });
383
-
384
- aquamanCmd
385
- .command("add <service> [key]")
386
- .description("Add a credential (opens secure prompt)")
387
- .action((service: string, key: string = "api_key") => {
388
- console.log(`\n Run in your terminal:\n aquaman credentials add ${service} ${key}\n`);
389
- });
390
-
391
- aquamanCmd
392
- .command("list")
393
- .description("List stored credentials")
394
- .action(() => {
395
- console.log(`\n Run in your terminal:\n aquaman credentials list\n`);
396
- });
397
- },
398
- { commands: ["aquaman"] }
399
- );
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");
400
446
  }
447
+ };
401
448
 
402
- registerStatusTool(api);
403
- api.logger.info("Aquaman plugin registered successfully");
404
- }
449
+ export default plugin;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aquaman-plugin",
3
- "version": "0.9.0",
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.0",
30
- "aquaman-proxy": "0.9.0"
29
+ "openclaw": ">=2026.1.11",
30
+ "aquaman-proxy": "0.9.2"
31
31
  },
32
32
  "peerDependenciesMeta": {
33
33
  "aquaman-proxy": {