@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 +19 -0
- package/dist/cli.js +58 -0
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
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(
|