@cephalization/phoenix-insight 1.0.4 → 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 CHANGED
@@ -6,6 +6,25 @@ Phoenix Insight brings AI-powered analysis to your [Phoenix](https://github.com/
6
6
 
7
7
  This filesystem-native approach provides transparency that traditional APIs can't match. Every query the agent runs is visible and reproducible. You can inspect the exact files it reads, copy its commands, and run them yourself. The data is just files, and the analysis is just bash, making AI-driven observability debuggable, auditable, and extensible with any tool in your Unix toolkit.
8
8
 
9
+ ## Requirements
10
+
11
+ - **Node.js v22 or newer** - Required for the CLI to run
12
+ - **Anthropic API key** - Required for the AI agent
13
+
14
+ Set your Anthropic API key before running:
15
+
16
+ ```bash
17
+ export ANTHROPIC_API_KEY=sk-ant-api03-...
18
+ ```
19
+
20
+ Or add it to your shell profile for persistence:
21
+
22
+ ```bash
23
+ echo 'export ANTHROPIC_API_KEY=sk-ant-api03-...' >> ~/.zshrc # or ~/.bashrc
24
+ ```
25
+
26
+ You can get an API key from [console.anthropic.com](https://console.anthropic.com/).
27
+
9
28
  ## Installation
10
29
 
11
30
  ```bash
package/dist/cli.js CHANGED
@@ -2709,6 +2709,7 @@ Make sure to build the UI package first: pnpm --filter @cephalization/phoenix-in
2709
2709
  );
2710
2710
  }
2711
2711
  return new Promise((resolve2, reject) => {
2712
+ const activeConnections = /* @__PURE__ */ new Set();
2712
2713
  const httpServer = createServer((req, res) => {
2713
2714
  const urlPath = req.url ?? "/";
2714
2715
  let filePath = sanitizePath(urlPath, distPath);
@@ -2760,6 +2761,12 @@ Make sure to build the UI package first: pnpm --filter @cephalization/phoenix-in
2760
2761
  res.end("Internal Server Error");
2761
2762
  });
2762
2763
  });
2764
+ httpServer.on("connection", (socket) => {
2765
+ activeConnections.add(socket);
2766
+ socket.on("close", () => {
2767
+ activeConnections.delete(socket);
2768
+ });
2769
+ });
2763
2770
  httpServer.on("error", (err) => {
2764
2771
  reject(err);
2765
2772
  });
@@ -2781,6 +2788,12 @@ Make sure to build the UI package first: pnpm --filter @cephalization/phoenix-in
2781
2788
  }
2782
2789
  });
2783
2790
  });
2791
+ },
2792
+ forceClose() {
2793
+ for (const socket of activeConnections) {
2794
+ socket.destroy();
2795
+ }
2796
+ activeConnections.clear();
2784
2797
  }
2785
2798
  });
2786
2799
  });
@@ -2955,6 +2968,19 @@ var PhoenixWebSocketServer = class {
2955
2968
  });
2956
2969
  });
2957
2970
  }
2971
+ /**
2972
+ * Force terminate all WebSocket connections immediately.
2973
+ * Use this when graceful close doesn't complete in time.
2974
+ */
2975
+ forceClose() {
2976
+ if (!this.wss) {
2977
+ return;
2978
+ }
2979
+ for (const client of this.clients) {
2980
+ client.terminate();
2981
+ }
2982
+ this.clients.clear();
2983
+ }
2958
2984
  };
2959
2985
  function createWebSocketServer(httpServer, options) {
2960
2986
  const server = new PhoenixWebSocketServer(options);
@@ -3317,6 +3343,26 @@ function formatBashCommand(command) {
3317
3343
  return firstLine.substring(0, 80) + (firstLine.length > 80 ? "..." : "");
3318
3344
  }
3319
3345
  }
3346
+ function ensureAnthropicApiKey() {
3347
+ if (!process.env.ANTHROPIC_API_KEY) {
3348
+ console.error(
3349
+ "\n\u274C Error: Missing ANTHROPIC_API_KEY environment variable\n"
3350
+ );
3351
+ console.error("The Anthropic API key is required to run the AI agent.\n");
3352
+ console.error("To fix this, set the environment variable:\n");
3353
+ console.error(" export ANTHROPIC_API_KEY=sk-ant-api03-...\n");
3354
+ console.error(
3355
+ "Or add it to your shell profile (~/.zshrc, ~/.bashrc, etc.):\n"
3356
+ );
3357
+ console.error(
3358
+ " echo 'export ANTHROPIC_API_KEY=sk-ant-api03-...' >> ~/.zshrc\n"
3359
+ );
3360
+ console.error(
3361
+ "You can get an API key from: https://console.anthropic.com/\n"
3362
+ );
3363
+ process.exit(1);
3364
+ }
3365
+ }
3320
3366
  function handleError(error, context) {
3321
3367
  console.error(`
3322
3368
  \u274C Error ${context}:`);
@@ -3561,6 +3607,7 @@ program.argument("[query]", "Query to run against Phoenix data").option(
3561
3607
  await runInteractiveMode();
3562
3608
  return;
3563
3609
  }
3610
+ ensureAnthropicApiKey();
3564
3611
  if (config.trace) {
3565
3612
  initializeObservability({
3566
3613
  enabled: true,
@@ -3683,6 +3730,7 @@ function openBrowser(url) {
3683
3730
  });
3684
3731
  }
3685
3732
  async function runUIServer(options) {
3733
+ ensureAnthropicApiKey();
3686
3734
  const config = getConfig();
3687
3735
  const port = options.port ?? 6007;
3688
3736
  const shouldOpen = options.open !== false;
@@ -3767,21 +3815,30 @@ async function runUIServer(options) {
3767
3815
  openBrowser(url);
3768
3816
  }
3769
3817
  let isShuttingDown = false;
3818
+ const SHUTDOWN_TIMEOUT_MS = 3e3;
3770
3819
  const shutdown = async (signal) => {
3771
3820
  if (isShuttingDown) return;
3772
3821
  isShuttingDown = true;
3773
3822
  console.log(`
3774
3823
 
3775
3824
  \u{1F4E5} Received ${signal}, shutting down gracefully...`);
3825
+ const forceExitTimeout = setTimeout(() => {
3826
+ console.log("\u23F1\uFE0F Shutdown timeout reached, forcing exit...");
3827
+ wsServer.forceClose();
3828
+ uiServer.forceClose();
3829
+ process.exit(0);
3830
+ }, SHUTDOWN_TIMEOUT_MS);
3776
3831
  try {
3777
3832
  await wsServer.close();
3778
3833
  await uiServer.close();
3779
3834
  await sessionManager.cleanup();
3780
3835
  await mode.cleanup();
3781
3836
  await shutdownObservability();
3837
+ clearTimeout(forceExitTimeout);
3782
3838
  console.log("\u{1F44B} Server stopped. Goodbye!");
3783
3839
  process.exit(0);
3784
3840
  } catch (error) {
3841
+ clearTimeout(forceExitTimeout);
3785
3842
  console.error("Error during shutdown:", error);
3786
3843
  process.exit(1);
3787
3844
  }
@@ -3795,6 +3852,7 @@ async function runUIServer(options) {
3795
3852
  }
3796
3853
  }
3797
3854
  async function runInteractiveMode() {
3855
+ ensureAnthropicApiKey();
3798
3856
  const config = getConfig();
3799
3857
  console.log("\u{1F680} Phoenix Insight Interactive Mode");
3800
3858
  console.log(