aquaman-proxy 0.6.0 → 0.7.1

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 (72) hide show
  1. package/README.md +10 -9
  2. package/dist/cli/index.js +154 -99
  3. package/dist/cli/index.js.map +1 -1
  4. package/dist/core/audit/index.d.ts +5 -0
  5. package/dist/core/audit/index.d.ts.map +1 -0
  6. package/dist/core/audit/index.js +5 -0
  7. package/dist/core/audit/index.js.map +1 -0
  8. package/dist/core/audit/logger.d.ts +53 -0
  9. package/dist/core/audit/logger.d.ts.map +1 -0
  10. package/dist/core/audit/logger.js +262 -0
  11. package/dist/core/audit/logger.js.map +1 -0
  12. package/dist/core/credentials/backends/keepassxc.d.ts +45 -0
  13. package/dist/core/credentials/backends/keepassxc.d.ts.map +1 -0
  14. package/dist/core/credentials/backends/keepassxc.js +229 -0
  15. package/dist/core/credentials/backends/keepassxc.js.map +1 -0
  16. package/dist/core/credentials/backends/onepassword.d.ts +38 -0
  17. package/dist/core/credentials/backends/onepassword.d.ts.map +1 -0
  18. package/dist/core/credentials/backends/onepassword.js +223 -0
  19. package/dist/core/credentials/backends/onepassword.js.map +1 -0
  20. package/dist/core/credentials/backends/vault.d.ts +56 -0
  21. package/dist/core/credentials/backends/vault.d.ts.map +1 -0
  22. package/dist/core/credentials/backends/vault.js +206 -0
  23. package/dist/core/credentials/backends/vault.js.map +1 -0
  24. package/dist/core/credentials/index.d.ts +8 -0
  25. package/dist/core/credentials/index.d.ts.map +1 -0
  26. package/dist/core/credentials/index.js +8 -0
  27. package/dist/core/credentials/index.js.map +1 -0
  28. package/dist/core/credentials/store.d.ts +102 -0
  29. package/dist/core/credentials/store.d.ts.map +1 -0
  30. package/dist/core/credentials/store.js +289 -0
  31. package/dist/core/credentials/store.js.map +1 -0
  32. package/dist/core/index.d.ts +14 -0
  33. package/dist/core/index.d.ts.map +1 -0
  34. package/dist/core/index.js +18 -0
  35. package/dist/core/index.js.map +1 -0
  36. package/dist/core/types.d.ts +81 -0
  37. package/dist/core/types.d.ts.map +1 -0
  38. package/dist/core/types.js +11 -0
  39. package/dist/core/types.js.map +1 -0
  40. package/dist/core/utils/config.d.ts +19 -0
  41. package/dist/core/utils/config.d.ts.map +1 -0
  42. package/dist/core/utils/config.js +136 -0
  43. package/dist/core/utils/config.js.map +1 -0
  44. package/dist/core/utils/hash.d.ts +27 -0
  45. package/dist/core/utils/hash.d.ts.map +1 -0
  46. package/dist/core/utils/hash.js +348 -0
  47. package/dist/core/utils/hash.js.map +1 -0
  48. package/dist/core/utils/index.d.ts +6 -0
  49. package/dist/core/utils/index.d.ts.map +1 -0
  50. package/dist/core/utils/index.js +6 -0
  51. package/dist/core/utils/index.js.map +1 -0
  52. package/dist/daemon.d.ts +4 -19
  53. package/dist/daemon.d.ts.map +1 -1
  54. package/dist/daemon.js +52 -101
  55. package/dist/daemon.js.map +1 -1
  56. package/dist/index.d.ts +2 -1
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +2 -0
  59. package/dist/index.js.map +1 -1
  60. package/dist/migration/openclaw-migrator.d.ts +1 -1
  61. package/dist/migration/openclaw-migrator.d.ts.map +1 -1
  62. package/dist/oauth-token-cache.d.ts +1 -1
  63. package/dist/oauth-token-cache.d.ts.map +1 -1
  64. package/dist/openclaw/env-writer.d.ts +7 -7
  65. package/dist/openclaw/env-writer.d.ts.map +1 -1
  66. package/dist/openclaw/env-writer.js +8 -13
  67. package/dist/openclaw/env-writer.js.map +1 -1
  68. package/dist/openclaw/integration.d.ts +5 -3
  69. package/dist/openclaw/integration.d.ts.map +1 -1
  70. package/dist/openclaw/integration.js +7 -14
  71. package/dist/openclaw/integration.js.map +1 -1
  72. package/package.json +8 -3
package/README.md CHANGED
@@ -8,15 +8,16 @@ Credential isolation proxy and CLI for [aquaman](https://github.com/tech4242/aqu
8
8
  Agent / OpenClaw Gateway Aquaman Proxy
9
9
  ┌──────────────────────┐ ┌──────────────────────┐
10
10
  │ │ │ │
11
- │ ANTHROPIC_BASE_URL │──request────>│ Keychain / 1Pass / │
12
- │ = localhost:8081 Vault / Encrypted │
13
- │<─response────│
14
- │ fetch() interceptor │──channel────>│ + Auth injected: │
15
- │ redirects channel │ traffic │ header / url-path │
11
+ │ ANTHROPIC_BASE_URL │══ Unix ════>│ Keychain / 1Pass / │
12
+ │ = aquaman.local │ Domain │ Vault / Encrypted │
13
+ │<═ Socket ═══│
14
+ │ fetch() interceptor │══ (UDS) ══=>│ + Auth injected: │
15
+ │ redirects channel │ │ header / url-path │
16
16
  │ API traffic │ │ basic / oauth │
17
17
  │ │ │ │
18
- │ No credentials. │ │ │
19
- Nothing to steal. │ │
18
+ │ No credentials. │ ~/.aquaman/ │ │
19
+ No open ports. proxy.sock │ │
20
+ │ Nothing to steal. │ (chmod 600) │ │
20
21
  └──────────────────────┘ └───┬──────────┬───────┘
21
22
  │ │
22
23
  │ ▼
@@ -28,7 +29,7 @@ Agent / OpenClaw Gateway Aquaman Proxy
28
29
  slack.com/api ...
29
30
  ```
30
31
 
31
- This package is the right side. A reverse proxy that intercepts API requests and injects credentials from secure backends. 23 builtin services, four auth modes.
32
+ This package is the right side. A reverse proxy that listens on a Unix domain socket (`~/.aquaman/proxy.sock`) and injects credentials from secure backends. No TCP port, no network exposure. 23 builtin services, four auth modes.
32
33
 
33
34
  ## Quick Start
34
35
 
@@ -54,7 +55,7 @@ Standalone:
54
55
  npm install -g aquaman-proxy
55
56
  aquaman init
56
57
  aquaman credentials add anthropic api_key
57
- aquaman daemon
58
+ aquaman daemon # listens on ~/.aquaman/proxy.sock
58
59
  ```
59
60
 
60
61
  Troubleshooting: `aquaman doctor`
package/dist/cli/index.js CHANGED
@@ -9,10 +9,10 @@
9
9
  * - Custom service registry: YAML-based service config
10
10
  */
11
11
  import { Command } from 'commander';
12
- import * as crypto from 'node:crypto';
13
12
  import * as path from 'node:path';
14
13
  import * as fs from 'node:fs';
15
- import { loadConfig, getConfigDir, ensureConfigDir, getDefaultConfig, expandPath, createAuditLogger, createCredentialStore, generateSelfSignedCert, saveConfig } from 'aquaman-core';
14
+ import * as http from 'node:http';
15
+ import { loadConfig, getConfigDir, ensureConfigDir, getDefaultConfig, expandPath, createAuditLogger, createCredentialStore, saveConfig } from '../core/index.js';
16
16
  import { fileURLToPath } from 'node:url';
17
17
  import { createCredentialProxy } from '../daemon.js';
18
18
  import { createServiceRegistry, ServiceRegistry } from '../service-registry.js';
@@ -54,6 +54,48 @@ const isProcessRunning = (pid) => {
54
54
  return false;
55
55
  }
56
56
  };
57
+ /** Prompt for secret input with echo suppression (TTY) or plain readline (pipe) */
58
+ async function promptSecretInput(prompt) {
59
+ const readline = await import('node:readline');
60
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
61
+ if (process.stdin.isTTY) {
62
+ return new Promise((resolve) => {
63
+ process.stdout.write(prompt);
64
+ const stdin = process.stdin;
65
+ stdin.setRawMode(true);
66
+ stdin.resume();
67
+ let input = '';
68
+ const onData = (data) => {
69
+ const char = data.toString();
70
+ if (char === '\n' || char === '\r') {
71
+ stdin.setRawMode(false);
72
+ stdin.removeListener('data', onData);
73
+ stdin.pause();
74
+ rl.close();
75
+ process.stdout.write('\n');
76
+ resolve(input.trim());
77
+ }
78
+ else if (char === '\x7f' || char === '\b') {
79
+ input = input.slice(0, -1);
80
+ }
81
+ else if (char === '\x03') {
82
+ stdin.setRawMode(false);
83
+ process.exit(0);
84
+ }
85
+ else {
86
+ input += char;
87
+ }
88
+ };
89
+ stdin.on('data', onData);
90
+ });
91
+ }
92
+ return new Promise((resolve) => {
93
+ rl.question(prompt, (answer) => {
94
+ rl.close();
95
+ resolve(answer.trim());
96
+ });
97
+ });
98
+ }
57
99
  const program = new Command();
58
100
  program
59
101
  .name('aquaman')
@@ -83,8 +125,7 @@ program
83
125
  if (options.dryRun) {
84
126
  console.log('Dry run - would start with this configuration:\n');
85
127
  console.log('Credential proxy:');
86
- console.log(` Port: ${config.credentials.proxyPort}`);
87
- console.log(` TLS: ${config.credentials.tls?.enabled ? 'enabled' : 'disabled'}`);
128
+ console.log(` Socket: ${path.join(getConfigDir(), 'proxy.sock')}`);
88
129
  console.log(` Backend: ${config.credentials.backend}`);
89
130
  console.log(` Services: ${config.credentials.proxiedServices.join(', ')}`);
90
131
  console.log('');
@@ -127,14 +168,12 @@ program
127
168
  // Initialize service registry
128
169
  const serviceRegistry = createServiceRegistry({ configPath: config.services.configPath });
129
170
  // Start credential proxy
130
- const bindAddr = config.credentials.bindAddress || '127.0.0.1';
171
+ const socketPath = path.join(getConfigDir(), 'proxy.sock');
131
172
  const credentialProxy = createCredentialProxy({
132
- port: config.credentials.proxyPort,
133
- bindAddress: bindAddr,
173
+ socketPath,
134
174
  store: credentialStore,
135
175
  allowedServices: config.credentials.proxiedServices,
136
176
  serviceRegistry,
137
- tls: config.credentials.tls,
138
177
  onRequest: (info) => {
139
178
  auditLogger.logCredentialAccess('system', 'system', {
140
179
  service: info.service,
@@ -145,8 +184,7 @@ program
145
184
  }
146
185
  });
147
186
  await credentialProxy.start();
148
- const protocol = credentialProxy.isTlsEnabled() ? 'https' : 'http';
149
- console.log(`Credential proxy started on ${protocol}://${bindAddr}:${config.credentials.proxyPort}`);
187
+ console.log(`Credential proxy started on ${socketPath}`);
150
188
  if (options.launch !== false && config.openclaw.autoLaunch) {
151
189
  // Get services for OpenClaw integration
152
190
  const services = serviceRegistry.getAll().filter(s => config.credentials.proxiedServices.includes(s.name));
@@ -225,6 +263,11 @@ program
225
263
  process.kill(pid, 'SIGKILL');
226
264
  }
227
265
  removePidFile();
266
+ const sockPath = path.join(getConfigDir(), 'proxy.sock');
267
+ try {
268
+ fs.unlinkSync(sockPath);
269
+ }
270
+ catch { /* already removed */ }
228
271
  console.log('Daemon stopped.');
229
272
  }
230
273
  catch (err) {
@@ -235,8 +278,7 @@ program
235
278
  program
236
279
  .command('daemon')
237
280
  .description('Run the credential proxy daemon (for advanced users)')
238
- .option('--token <token>', 'Client authentication token (reads AQUAMAN_CLIENT_TOKEN env if not set)')
239
- .action(async (options) => {
281
+ .action(async () => {
240
282
  // Check if daemon is already running
241
283
  const existingPid = readPidFile();
242
284
  if (existingPid && isProcessRunning(existingPid)) {
@@ -244,6 +286,7 @@ program
244
286
  process.exit(1);
245
287
  }
246
288
  const config = loadConfig();
289
+ const socketPath = path.join(getConfigDir(), 'proxy.sock');
247
290
  console.log('Starting aquaman credential proxy daemon...\n');
248
291
  // Initialize audit logger
249
292
  const auditLogger = createAuditLogger({
@@ -274,18 +317,12 @@ program
274
317
  }
275
318
  // Initialize service registry
276
319
  const serviceRegistry = createServiceRegistry({ configPath: config.services.configPath });
277
- // Client token: CLI flag → env var → none
278
- const daemonClientToken = options.token || process.env.AQUAMAN_CLIENT_TOKEN || undefined;
279
320
  // Start credential proxy
280
- const bindAddr = config.credentials.bindAddress || '127.0.0.1';
281
321
  const credentialProxy = createCredentialProxy({
282
- port: config.credentials.proxyPort,
283
- bindAddress: bindAddr,
322
+ socketPath,
284
323
  store: credentialStore,
285
324
  allowedServices: config.credentials.proxiedServices,
286
325
  serviceRegistry,
287
- tls: config.credentials.tls,
288
- clientToken: daemonClientToken,
289
326
  onRequest: (info) => {
290
327
  auditLogger.logCredentialAccess('system', 'system', {
291
328
  service: info.service,
@@ -298,9 +335,7 @@ program
298
335
  await credentialProxy.start();
299
336
  // Write PID file
300
337
  writePidFile();
301
- const protocol = credentialProxy.isTlsEnabled() ? 'https' : 'http';
302
- console.log(`Credential proxy: ${protocol}://${bindAddr}:${config.credentials.proxyPort}`);
303
- console.log(`Client auth: ${daemonClientToken ? 'enabled' : 'disabled'}`);
338
+ console.log(`Credential proxy: ${socketPath}`);
304
339
  console.log(`Audit logging: ${config.audit.enabled ? 'enabled' : 'disabled'}`);
305
340
  console.log(`Credential backend: ${config.credentials.backend}`);
306
341
  console.log(`PID file: ${getPidFile()}`);
@@ -311,6 +346,10 @@ program
311
346
  console.log('\nShutting down daemon...');
312
347
  await credentialProxy.stop();
313
348
  removePidFile();
349
+ try {
350
+ fs.unlinkSync(socketPath);
351
+ }
352
+ catch { /* already removed */ }
314
353
  process.exit(0);
315
354
  };
316
355
  process.on('SIGINT', shutdown);
@@ -320,13 +359,9 @@ program
320
359
  program
321
360
  .command('plugin-mode')
322
361
  .description('Run in plugin mode (managed by OpenClaw plugin)')
323
- .option('--port <port>', 'Port to listen on', '8081')
324
- .option('--token <token>', 'Client authentication token (generated if not provided)')
325
- .option('--ipc', 'Use IPC instead of HTTP for communication')
326
- .action(async (options) => {
362
+ .action(async () => {
327
363
  const config = loadConfig();
328
- const port = parseInt(options.port, 10);
329
- const clientToken = options.token || crypto.randomBytes(32).toString('hex');
364
+ const socketPath = path.join(getConfigDir(), 'proxy.sock');
330
365
  // Initialize credential store
331
366
  let credentialStore;
332
367
  try {
@@ -348,21 +383,31 @@ program
348
383
  console.error('Fix the backend configuration and retry. Run: aquaman doctor');
349
384
  process.exit(1);
350
385
  }
386
+ // Initialize audit logger
387
+ const auditLogger = createAuditLogger({
388
+ logDir: config.audit.logDir,
389
+ enabled: config.audit.enabled
390
+ });
391
+ await auditLogger.initialize();
351
392
  // Initialize service registry
352
393
  const serviceRegistry = createServiceRegistry({ configPath: config.services.configPath });
353
394
  // Start credential proxy
354
395
  const credentialProxy = createCredentialProxy({
355
- port,
356
- bindAddress: config.credentials.bindAddress || '127.0.0.1',
396
+ socketPath,
357
397
  store: credentialStore,
358
398
  allowedServices: config.credentials.proxiedServices,
359
399
  serviceRegistry,
360
- tls: config.credentials.tls,
361
- clientToken
400
+ onRequest: (info) => {
401
+ auditLogger.logCredentialAccess('system', 'system', {
402
+ service: info.service,
403
+ operation: 'use',
404
+ success: !info.error,
405
+ error: info.error
406
+ });
407
+ }
362
408
  });
363
409
  await credentialProxy.start();
364
- const protocol = credentialProxy.isTlsEnabled() ? 'https' : 'http';
365
- // Build host map from service registry for the plugin's fetch interceptor
410
+ // Build host map from service registry for the plugin's interceptor
366
411
  const hostMap = serviceRegistry.buildHostMap();
367
412
  const hostMapObj = {};
368
413
  for (const [pattern, serviceName] of hostMap) {
@@ -371,18 +416,19 @@ program
371
416
  // Output connection info as JSON for plugin to parse
372
417
  const connectionInfo = {
373
418
  ready: true,
374
- port: credentialProxy.getPort(),
375
- protocol,
376
- baseUrl: `${protocol}://127.0.0.1:${credentialProxy.getPort()}`,
419
+ socketPath,
377
420
  services: config.credentials.proxiedServices,
378
421
  backend: config.credentials.backend,
379
- token: clientToken,
380
422
  hostMap: hostMapObj
381
423
  };
382
424
  console.log(JSON.stringify(connectionInfo));
383
425
  // Handle shutdown
384
426
  const shutdown = async () => {
385
427
  await credentialProxy.stop();
428
+ try {
429
+ fs.unlinkSync(socketPath);
430
+ }
431
+ catch { /* already removed */ }
386
432
  process.exit(0);
387
433
  };
388
434
  process.on('SIGINT', shutdown);
@@ -400,7 +446,7 @@ program
400
446
  const registry = createServiceRegistry({ configPath: config.services.configPath });
401
447
  const services = registry.getAll().filter(s => config.credentials.proxiedServices.includes(s.name));
402
448
  const integration = createOpenClawIntegration(config, services);
403
- const env = await integration.configureOpenClaw(config.credentials.proxyPort, config.credentials.tls?.enabled ?? false);
449
+ const env = await integration.configureOpenClaw();
404
450
  if (options.dryRun || options.method === 'env') {
405
451
  console.log('Environment variables for OpenClaw:\n');
406
452
  for (const [key, value] of Object.entries(env)) {
@@ -418,7 +464,6 @@ program
418
464
  .command('init')
419
465
  .description('Initialize aquaman configuration')
420
466
  .option('--force', 'Overwrite existing configuration')
421
- .option('--no-tls', 'Skip TLS certificate generation')
422
467
  .action(async (options) => {
423
468
  ensureConfigDir();
424
469
  const configPath = path.join(getConfigDir(), 'config.yaml');
@@ -428,36 +473,12 @@ program
428
473
  return;
429
474
  }
430
475
  const config = getDefaultConfig();
431
- fs.writeFileSync(configPath, yamlStringify(config), 'utf-8');
476
+ fs.writeFileSync(configPath, yamlStringify(config), { encoding: 'utf-8', mode: 0o600 });
432
477
  console.log(`Created ${configPath}`);
433
478
  // Create audit directory
434
479
  const auditDir = path.join(getConfigDir(), 'audit');
435
- fs.mkdirSync(auditDir, { recursive: true });
480
+ fs.mkdirSync(auditDir, { recursive: true, mode: 0o700 });
436
481
  console.log(`Created ${auditDir}`);
437
- // Generate TLS certificates if enabled
438
- if (options.tls !== false && config.credentials.tls?.autoGenerate) {
439
- const certsDir = path.join(getConfigDir(), 'certs');
440
- fs.mkdirSync(certsDir, { recursive: true });
441
- const certPath = config.credentials.tls.certPath || path.join(certsDir, 'proxy.crt');
442
- const keyPath = config.credentials.tls.keyPath || path.join(certsDir, 'proxy.key');
443
- if (!fs.existsSync(certPath) || options.force) {
444
- console.log('Generating TLS certificates...');
445
- try {
446
- const { cert, key } = generateSelfSignedCert('aquaman-proxy', 365);
447
- fs.writeFileSync(certPath, cert, { mode: 0o644 });
448
- fs.writeFileSync(keyPath, key, { mode: 0o600 });
449
- console.log(`Created ${certPath}`);
450
- console.log(`Created ${keyPath}`);
451
- }
452
- catch (error) {
453
- console.error('Warning: Failed to generate TLS certificates:', error);
454
- console.log('TLS will be disabled. Run "aquaman init --force" to retry.');
455
- }
456
- }
457
- else {
458
- console.log('TLS certificates already exist (use --force to regenerate)');
459
- }
460
- }
461
482
  console.log('\nNext steps:');
462
483
  console.log('1. Add your API keys: aquaman credentials add anthropic api_key');
463
484
  console.log('2. Start the proxy: aquaman start');
@@ -574,12 +595,8 @@ program
574
595
  process.exit(1);
575
596
  }
576
597
  else {
577
- const readline = await import('node:readline');
578
- const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
579
- const password = await new Promise((resolve) => {
580
- rl.question(' ? KeePassXC master password: ', resolve);
581
- });
582
- rl.close();
598
+ // Use hidden input to avoid echoing the master password
599
+ const password = await promptSecretInput(' ? KeePassXC master password: ');
583
600
  if (!password.trim()) {
584
601
  console.error(' KeePassXC backend requires a master password.');
585
602
  process.exit(1);
@@ -588,15 +605,14 @@ program
588
605
  }
589
606
  }
590
607
  }
591
- // 2. Run init internally (create dirs, config, no TLS by default)
608
+ // 2. Run init internally (create dirs, config)
592
609
  ensureConfigDir();
593
610
  const config = getDefaultConfig();
594
611
  config.credentials.backend = backend;
595
- config.credentials.tls = { enabled: false };
596
- fs.writeFileSync(configPath, yamlStringify(config), 'utf-8');
612
+ fs.writeFileSync(configPath, yamlStringify(config), { encoding: 'utf-8', mode: 0o600 });
597
613
  // Create audit directory
598
614
  const auditDir = path.join(configDir, 'audit');
599
- fs.mkdirSync(auditDir, { recursive: true });
615
+ fs.mkdirSync(auditDir, { recursive: true, mode: 0o700 });
600
616
  // 3. Prompt for API keys (or read from env in non-interactive mode)
601
617
  let store;
602
618
  try {
@@ -761,10 +777,8 @@ program
761
777
  openclawConfig.plugins.entries['aquaman-plugin'] = {
762
778
  enabled: true,
763
779
  config: {
764
- mode: 'proxy',
765
780
  backend,
766
781
  services: storedServices.length > 0 ? storedServices : ['anthropic', 'openai'],
767
- proxyPort: 8081
768
782
  }
769
783
  };
770
784
  fs.writeFileSync(openclawJsonPath, JSON.stringify(openclawConfig, null, 2), 'utf-8');
@@ -786,8 +800,8 @@ program
786
800
  }
787
801
  }
788
802
  const profilesDir = path.dirname(profilesPath);
789
- fs.mkdirSync(profilesDir, { recursive: true });
790
- fs.writeFileSync(profilesPath, JSON.stringify({ version: 1, profiles, order }, null, 2));
803
+ fs.mkdirSync(profilesDir, { recursive: true, mode: 0o700 });
804
+ fs.writeFileSync(profilesPath, JSON.stringify({ version: 1, profiles, order }, null, 2), { mode: 0o600 });
791
805
  console.log(' \u2713 Auth profiles generated at ' + profilesPath);
792
806
  }
793
807
  }
@@ -900,35 +914,77 @@ program
900
914
  config = loadConfig();
901
915
  }
902
916
  // 4. Proxy running
903
- const proxyPort = config.credentials.proxyPort;
917
+ const sockPath = path.join(getConfigDir(), 'proxy.sock');
904
918
  const pluginInstalled = fs.existsSync(path.join(openclawStateDir, 'extensions', 'aquaman-plugin'));
905
919
  const proxyFix = pluginInstalled
906
920
  ? 'Proxy starts automatically with OpenClaw. Run: openclaw'
907
921
  : 'Install plugin first: aquaman setup';
908
922
  try {
909
- const resp = await fetch(`http://127.0.0.1:${proxyPort}/_health`);
910
- if (resp.ok) {
911
- const health = await resp.json();
912
- const proxyVer = health.version || 'unknown';
913
- console.log(` \u2713 ${aqua('Proxy')} running on port ${proxyPort} (v${proxyVer})`);
914
- if (health.version && health.version !== VERSION) {
915
- console.log(` \u2717 ${aqua('Version mismatch:')} CLI v${VERSION} \u2260 proxy v${health.version}`);
916
- console.log(' \u2192 Update: npm install -g aquaman-proxy');
917
- issues++;
918
- }
919
- }
920
- else {
921
- console.log(` \u2717 ${aqua('Proxy')} not running on port ${proxyPort}`);
922
- console.log(` \u2192 ${proxyFix}`);
923
+ const healthData = await new Promise((resolve, reject) => {
924
+ const req = http.request({ socketPath: sockPath, path: '/_health', method: 'GET' }, (res) => {
925
+ let body = '';
926
+ res.on('data', (chunk) => { body += chunk.toString(); });
927
+ res.on('end', () => {
928
+ if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) {
929
+ resolve(body);
930
+ }
931
+ else {
932
+ reject(new Error(`HTTP ${res.statusCode}`));
933
+ }
934
+ });
935
+ });
936
+ req.on('error', reject);
937
+ req.end();
938
+ });
939
+ const health = JSON.parse(healthData);
940
+ const proxyVer = health.version || 'unknown';
941
+ console.log(` \u2713 ${aqua('Proxy')} running on socket (v${proxyVer})`);
942
+ if (health.version && health.version !== VERSION) {
943
+ console.log(` \u2717 ${aqua('Version mismatch:')} CLI v${VERSION} \u2260 proxy v${health.version}`);
944
+ console.log(' \u2192 Update: npm install -g aquaman-proxy');
923
945
  issues++;
924
946
  }
925
947
  }
926
948
  catch {
927
- console.log(` \u2717 ${aqua('Proxy')} not running on port ${proxyPort}`);
949
+ console.log(` \u2717 ${aqua('Proxy')} not running on socket`);
928
950
  console.log(` \u2192 ${proxyFix}`);
929
951
  issues++;
930
952
  }
931
- // 5. OpenClaw detection
953
+ // 5. Audit logger
954
+ if (config) {
955
+ const auditDir = config.audit.logDir;
956
+ const auditLog = path.join(auditDir, 'current.jsonl');
957
+ if (!config.audit.enabled) {
958
+ console.log(` - ${aqua('Audit')} disabled in config`);
959
+ }
960
+ else if (!fs.existsSync(auditDir)) {
961
+ console.log(` \u2717 ${aqua('Audit')} directory missing (${auditDir})`);
962
+ console.log(' \u2192 Run: aquaman init');
963
+ issues++;
964
+ }
965
+ else {
966
+ // Check log file exists and is writable
967
+ try {
968
+ if (fs.existsSync(auditLog)) {
969
+ fs.accessSync(auditLog, fs.constants.W_OK);
970
+ const content = fs.readFileSync(auditLog, 'utf-8').trim();
971
+ const entryCount = content ? content.split('\n').length : 0;
972
+ console.log(` \u2713 ${aqua('Audit')} log writable (${entryCount} entries)`);
973
+ }
974
+ else {
975
+ // Dir exists but no log yet — that's fine, first request will create it
976
+ fs.accessSync(auditDir, fs.constants.W_OK);
977
+ console.log(` \u2713 ${aqua('Audit')} directory writable (no entries yet)`);
978
+ }
979
+ }
980
+ catch {
981
+ console.log(` \u2717 ${aqua('Audit')} log not writable (${auditLog})`);
982
+ console.log(' \u2192 Check file permissions on ~/.aquaman/audit/');
983
+ issues++;
984
+ }
985
+ }
986
+ }
987
+ // 6. OpenClaw detection
932
988
  let openclawDetected = false;
933
989
  let cliFound = false;
934
990
  try {
@@ -1832,8 +1888,7 @@ program
1832
1888
  console.log('Configuration:');
1833
1889
  console.log(` Config dir: ${getConfigDir()}`);
1834
1890
  console.log(` Credential backend: ${config.credentials.backend}`);
1835
- console.log(` Proxy port: ${config.credentials.proxyPort}`);
1836
- console.log(` TLS: ${config.credentials.tls?.enabled ? 'enabled' : 'disabled'}`);
1891
+ console.log(` Socket path: ${path.join(getConfigDir(), 'proxy.sock')}`);
1837
1892
  console.log(` Audit logging: ${config.audit.enabled ? 'enabled' : 'disabled'}`);
1838
1893
  console.log('\nProxied services:');
1839
1894
  for (const service of config.credentials.proxiedServices) {