@kamrankhan027/probe-ai 1.0.2 → 1.0.4

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 +128 -0
  2. package/dist/index.js +121 -58
  3. package/package.json +7 -5
package/README.md ADDED
@@ -0,0 +1,128 @@
1
+ # 🔍 ProbeAI — Autonomous API Reliability & Postman Suite Generator
2
+
3
+ <div align="center">
4
+
5
+ **An autonomous developer CLI agent that inspects OpenAPI specs, synthesizes multi-scenario test suites, executes real-time HTTP calls, and auto-exports ready-to-import Postman collections.**
6
+
7
+ [![npm version](https://img.shields.io/npm/v/@kamrankhan027/probe-ai.svg?style=for-the-badge&color=CB3837&logo=npm)](https://www.npmjs.com/package/@kamrankhan027/probe-ai)
8
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg?style=for-the-badge)](https://opensource.org/licenses/MIT)
9
+ [![LangGraph](https://img.shields.io/badge/LangGraph.js-1C3C3C?style=for-the-badge&logo=langchain&logoColor=white)](https://langchain-ai.github.io/langgraphjs/)
10
+ [![Gemini](https://img.shields.io/badge/Gemini_3.6_Flash-8E75B2?style=for-the-badge&logo=google&logoColor=white)](https://ai.google.dev/)
11
+ [![TypeScript](https://img.shields.io/badge/TypeScript-3178C6?style=for-the-badge&logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
12
+
13
+ </div>
14
+
15
+ ---
16
+
17
+ ## ⚡ Quickstart
18
+
19
+ ### Option 1: Run Instantly via `npx` (Zero Installation Required)
20
+ ```bash
21
+ npx @kamrankhan027/probe-ai
22
+ ```
23
+
24
+ ---
25
+
26
+ ### Option 2: Install Globally
27
+
28
+ **Using npm:**
29
+ ```bash
30
+ npm install -g @kamrankhan027/probe-ai
31
+ ```
32
+
33
+ **Using pnpm:**
34
+ ```bash
35
+ pnpm add -g @kamrankhan027/probe-ai
36
+ ```
37
+
38
+ **Using yarn:**
39
+ ```bash
40
+ yarn global add @kamrankhan027/probe-ai
41
+ ```
42
+
43
+ Then run ProbeAI from **any directory** on your machine:
44
+ ```bash
45
+ probe-ai
46
+ ```
47
+
48
+ ---
49
+
50
+ ## 🔑 API Key Setup
51
+
52
+ ProbeAI uses Google Gemini for fast, structured reasoning.
53
+ * **If you have a `.env` file**: Add `GEMINI_API_KEY=your_key_here`
54
+ * **If running via `npx` without a `.env`**: ProbeAI will interactively prompt you to paste your free Gemini API key on startup.
55
+
56
+ *(Get a free key in 10 seconds at [aistudio.google.com](https://aistudio.google.com/)).*
57
+
58
+ ---
59
+
60
+ ## 🌟 Key Superpowers
61
+
62
+ * **🔍 Auto-Discovery via OpenAPI**: Probes any API base URL (e.g. `http://localhost:8000`) and parses `/openapi.json` to map all routes, parameters, and security schemas.
63
+ * **📦 1-Click Postman Collection Export**: Eliminates 30+ minutes of manual route recreation by generating ready-to-import **Postman Collection v2.1** files (`reports/probe_collection.json`).
64
+ * **🔐 Smart Auth Detective**: Supports direct token injection (`Bearer ...` or `X-API-Key`) **AND** autonomous login flows (executing `POST /auth/login`, extracting the JWT token, and binding it to subsequent requests).
65
+ * **⚡ Real-Time HTTP Latency Profiling**: Fires live requests, catches `422/404/401` edge cases, and logs latency in milliseconds.
66
+ * **📊 Standalone HTML & Terminal Reports**: Generates interactive single-page HTML audit dashboards with health scores and payload replays.
67
+
68
+ ---
69
+
70
+ ## 💡 Example Prompts to Try
71
+
72
+ ```text
73
+ You: Inspect https://bookmark-agent-backend.onrender.com and export a Postman collection
74
+ ```
75
+ *Auto-maps all endpoints and creates `reports/postman_collection.json`.*
76
+
77
+ ```text
78
+ You: Test all endpoints on https://bookmark-agent-backend.onrender.com and save an HTML report
79
+ ```
80
+ *Executes Happy Path, Query Filter, and Error test cases and saves `reports/audit_report.html`.*
81
+
82
+ ```text
83
+ You: Set auth Bearer my_jwt_token_123 and test protected endpoints
84
+ ```
85
+ *Injects your authorization header into session memory for all subsequent calls.*
86
+
87
+ ```text
88
+ You: Authenticate via POST https://api.example.com/login with {"email":"dev@example.com","password":"secret"}, then test /api/dashboard
89
+ ```
90
+ *Extracts the JWT from the login response and tests the protected dashboard route automatically.*
91
+
92
+ ---
93
+
94
+ ## 🏗️ Repository Architecture
95
+
96
+ ```text
97
+ probe-ai/
98
+ ├── cli/ # 🚀 Native TypeScript NPM Package (@kamrankhan027/probe-ai)
99
+ │ ├── src/
100
+ │ │ ├── index.ts # Interactive CLI loop & Marked terminal styling
101
+ │ │ ├── agent.ts # @langchain/langgraph ReAct workflow
102
+ │ │ └── tools/ # OpenAPI, HTTP, Auth, Postman & Report tools
103
+ │ ├── dist/
104
+ │ │ └── index.js # ⚡ Single zero-dependency bundled executable (tsup)
105
+ │ └── package.json
106
+ ├── python/ # Python implementation (LangGraph + Rich)
107
+ │ ├── agent.py
108
+ │ └── requirements.txt
109
+ └── reports/ # Shared output directory
110
+ ```
111
+
112
+ ---
113
+
114
+ ## 🛠️ Local Development
115
+
116
+ ```bash
117
+ git clone https://github.com/kamran-027/probe-ai.git
118
+ cd probe-ai/cli
119
+ npm install
120
+ npm run build
121
+ npm start
122
+ ```
123
+
124
+ ---
125
+
126
+ <div align="center">
127
+ Built by <b>Kamran Khan</b> as part of <b>Cadence Labs</b>.
128
+ </div>
package/dist/index.js CHANGED
@@ -7,8 +7,7 @@ var __export = (target, all) => {
7
7
 
8
8
  // src/index.ts
9
9
  import dotenv from "dotenv";
10
- import chalk6 from "chalk";
11
- import boxen from "boxen";
10
+ import chalk7 from "chalk";
12
11
  import ora from "ora";
13
12
  import readline from "readline";
14
13
  import { marked } from "marked";
@@ -4067,15 +4066,81 @@ var NEVER = INVALID;
4067
4066
 
4068
4067
  // src/tools/openapi.ts
4069
4068
  import axios from "axios";
4069
+ import chalk2 from "chalk";
4070
+
4071
+ // src/ui.ts
4070
4072
  import chalk from "chalk";
4073
+ import boxen from "boxen";
4074
+ function printModernBanner(version = "1.0.4") {
4075
+ const content = `${chalk.bold.hex("#6366F1")("\u2726 PROBE AI")} ${chalk.dim(`v${version}`)} ${chalk.hex("#10B981")("\u25CF READY")}
4076
+ ${chalk.white("Autonomous API Schema & Reliability Inspector")}
4077
+
4078
+ ${chalk.dim("Capabilities:")}
4079
+ ${chalk.cyan("\u2022")} ${chalk.bold("OpenAPI Discovery")} ${chalk.dim("Auto-maps schemas & security")}
4080
+ ${chalk.cyan("\u2022")} ${chalk.bold("Postman Exporter")} ${chalk.dim("1-click collection generation")}
4081
+ ${chalk.cyan("\u2022")} ${chalk.bold("Smart Auth")} ${chalk.dim("Login token exchange & Bearer injection")}
4082
+ ${chalk.cyan("\u2022")} ${chalk.bold("HTML Audit Reports")} ${chalk.dim("Latency profiling & payload replays")}
4083
+
4084
+ ${chalk.dim("Quick Test Prompts:")}
4085
+ ${chalk.gray("\u276F")} ${chalk.yellow("Inspect https://bookmark-agent-backend.onrender.com and export Postman collection")}
4086
+ ${chalk.gray("\u276F")} ${chalk.yellow("Test all endpoints on http://localhost:8000 and save HTML report")}
4087
+ ${chalk.dim("Type 'exit' to quit")}`;
4088
+ console.log(
4089
+ boxen(content, {
4090
+ padding: { top: 1, bottom: 1, left: 2, right: 2 },
4091
+ margin: { top: 1, bottom: 1 },
4092
+ borderStyle: "round",
4093
+ borderColor: "#6366F1"
4094
+ })
4095
+ );
4096
+ }
4097
+ function formatMethodBadge(method) {
4098
+ const m = method.toUpperCase();
4099
+ switch (m) {
4100
+ case "GET":
4101
+ return chalk.bgBlue.bold.white(" GET ");
4102
+ case "POST":
4103
+ return chalk.bgGreen.bold.white(" POST ");
4104
+ case "PUT":
4105
+ return chalk.bgYellow.bold.black(" PUT ");
4106
+ case "DELETE":
4107
+ return chalk.bgRed.bold.white(" DEL ");
4108
+ case "PATCH":
4109
+ return chalk.bgMagenta.bold.white(" PATCH ");
4110
+ default:
4111
+ return chalk.bgGray.bold.white(` ${m} `);
4112
+ }
4113
+ }
4114
+ function formatStatusBadge(status) {
4115
+ if (status >= 200 && status < 300) {
4116
+ return chalk.hex("#10B981").bold(`${status} OK`);
4117
+ }
4118
+ if (status === 401 || status === 403) {
4119
+ return chalk.hex("#F59E0B").bold(`${status} Auth Required`);
4120
+ }
4121
+ if (status === 404) {
4122
+ return chalk.hex("#64748B").bold(`${status} Not Found`);
4123
+ }
4124
+ if (status === 422) {
4125
+ return chalk.hex("#EC4899").bold(`${status} Unprocessable Entity`);
4126
+ }
4127
+ return chalk.hex("#EF4444").bold(`${status} Error`);
4128
+ }
4129
+ function logStep(icon, title, detail = "") {
4130
+ const iconColored = chalk.hex("#6366F1")(icon);
4131
+ const titleColored = chalk.bold.white(title);
4132
+ const detailColored = detail ? chalk.dim(` ${detail}`) : "";
4133
+ console.log(` ${iconColored} ${titleColored}${detailColored}`);
4134
+ }
4135
+
4136
+ // src/tools/openapi.ts
4071
4137
  var fetchOpenApiSpecTool = tool(
4072
4138
  async ({ baseUrl }) => {
4073
- console.log(chalk.cyan(`
4074
- \u{1F50D} [Tool: fetch_openapi_spec] Probing: ${baseUrl}`));
4075
4139
  let targetUrl = baseUrl.replace(/\/+$/, "");
4076
4140
  if (!targetUrl.endsWith("openapi.json")) {
4077
4141
  targetUrl = `${targetUrl}/openapi.json`;
4078
4142
  }
4143
+ logStep("\u{1F50D}", "Probing OpenAPI Spec", chalk2.cyan(targetUrl));
4079
4144
  try {
4080
4145
  const response = await axios.get(targetUrl, { timeout: 1e4 });
4081
4146
  const spec = response.data;
@@ -4096,6 +4161,7 @@ var fetchOpenApiSpecTool = tool(
4096
4161
  });
4097
4162
  }
4098
4163
  }
4164
+ logStep("\u2713", `Discovered ${endpointsSummary.length} endpoints`, chalk2.dim(`(API v${info.version || "1.0"})`));
4099
4165
  return JSON.stringify(
4100
4166
  {
4101
4167
  title: info.title || "API Spec",
@@ -4108,6 +4174,7 @@ var fetchOpenApiSpecTool = tool(
4108
4174
  2
4109
4175
  );
4110
4176
  } catch (err) {
4177
+ logStep("\u2715", "Could not fetch OpenAPI spec", chalk2.red(err.message));
4111
4178
  return `Could not fetch OpenAPI spec from ${targetUrl}: ${err.message}`;
4112
4179
  }
4113
4180
  },
@@ -4123,7 +4190,7 @@ var fetchOpenApiSpecTool = tool(
4123
4190
  // src/tools/auth.ts
4124
4191
  import { tool as tool2 } from "@langchain/core/tools";
4125
4192
  import axios2 from "axios";
4126
- import chalk2 from "chalk";
4193
+ import chalk3 from "chalk";
4127
4194
 
4128
4195
  // src/tools/state.ts
4129
4196
  var sessionHeaders = {
@@ -4139,8 +4206,7 @@ var authenticateViaLoginTool = tool2(
4139
4206
  payloadJson = "{}",
4140
4207
  tokenField = "access_token"
4141
4208
  }) => {
4142
- console.log(chalk2.green(`
4143
- \u{1F510} [Tool: authenticate_via_login] Authenticating at: ${loginUrl}`));
4209
+ logStep("\u{1F510}", "Authenticating via login endpoint...", chalk3.dim(loginUrl));
4144
4210
  let payload = {};
4145
4211
  try {
4146
4212
  if (payloadJson && payloadJson.trim() !== "{}") {
@@ -4162,12 +4228,14 @@ var authenticateViaLoginTool = tool2(
4162
4228
  token = data[tokenField] || data.token || data.access_token || data.jwt || data.key;
4163
4229
  }
4164
4230
  if (!token) {
4231
+ logStep("\u2715", "Login succeeded but token field not found", chalk3.red(tokenField));
4165
4232
  return `Login succeeded (HTTP ${res.status}), but token field '${tokenField}' was not found in response: ${JSON.stringify(data)}`;
4166
4233
  }
4167
4234
  sessionHeaders["Authorization"] = `Bearer ${token}`;
4168
- console.log(chalk2.green(` \u2514\u2500 Success! Extracted token and bound 'Authorization: Bearer ...' to session.`));
4235
+ logStep("\u2713", "Extracted Bearer token & saved to session", chalk3.hex("#10B981")("Authorization: Bearer \u2022\u2022\u2022\u2022\u2022\u2022"));
4169
4236
  return `Authentication successful. Bearer token extracted from '${tokenField}' and saved to session headers.`;
4170
4237
  } catch (err) {
4238
+ logStep("\u2715", "Login failed", chalk3.red(err.message));
4171
4239
  return `Login request failed: ${err.message}`;
4172
4240
  }
4173
4241
  },
@@ -4189,8 +4257,7 @@ var setAuthHeaderTool = tool2(
4189
4257
  cleanVal = `Bearer ${cleanVal}`;
4190
4258
  }
4191
4259
  sessionHeaders[headerName] = cleanVal;
4192
- console.log(chalk2.green(`
4193
- \u{1F511} [Tool: set_auth_header] Set '${headerName}' header in session.`));
4260
+ logStep("\u{1F511}", `Set auth header: ${headerName}`, chalk3.hex("#10B981")("\u2022\u2022\u2022\u2022\u2022\u2022"));
4194
4261
  return `Successfully set '${headerName}' header in session.`;
4195
4262
  },
4196
4263
  {
@@ -4206,7 +4273,7 @@ var setAuthHeaderTool = tool2(
4206
4273
  // src/tools/http.ts
4207
4274
  import { tool as tool3 } from "@langchain/core/tools";
4208
4275
  import axios3 from "axios";
4209
- import chalk3 from "chalk";
4276
+ import chalk4 from "chalk";
4210
4277
  var executeHttpRequestTool = tool3(
4211
4278
  async ({
4212
4279
  method,
@@ -4216,8 +4283,6 @@ var executeHttpRequestTool = tool3(
4216
4283
  bodyJson = "{}"
4217
4284
  }) => {
4218
4285
  const cleanMethod = method.trim().toUpperCase();
4219
- console.log(chalk3.yellow(`
4220
- \u26A1 [Tool: execute_http_request] ${cleanMethod} ${url}`));
4221
4286
  const mergedHeaders = { ...sessionHeaders };
4222
4287
  try {
4223
4288
  if (headersJson && headersJson.trim() !== "{}") {
@@ -4247,12 +4312,20 @@ var executeHttpRequestTool = tool3(
4247
4312
  params,
4248
4313
  data,
4249
4314
  validateStatus: () => true,
4250
- // Don't throw on 4xx/5xx so agent can inspect response
4251
4315
  timeout: 15e3
4252
4316
  });
4253
4317
  const elapsedMs = Date.now() - startTime;
4254
- const statusColor = response.status >= 200 && response.status < 300 ? chalk3.green : chalk3.red;
4255
- console.log(` \u2514\u2500 Status: ${statusColor(response.status)} | Latency: ${chalk3.cyan(`${elapsedMs}ms`)}`);
4318
+ const methodBadge = formatMethodBadge(cleanMethod);
4319
+ const statusBadge = formatStatusBadge(response.status);
4320
+ const latencyStr = chalk4.dim(`${elapsedMs}ms`);
4321
+ let pathPreview = url;
4322
+ try {
4323
+ const u = new URL(url);
4324
+ pathPreview = u.pathname + (u.search || "");
4325
+ } catch {
4326
+ pathPreview = url;
4327
+ }
4328
+ console.log(` \u26A1 ${methodBadge} ${chalk4.white(pathPreview)} ${statusBadge} ${latencyStr}`);
4256
4329
  const now = /* @__PURE__ */ new Date();
4257
4330
  testExecutionLogs.push({
4258
4331
  method: cleanMethod,
@@ -4277,6 +4350,7 @@ var executeHttpRequestTool = tool3(
4277
4350
  2
4278
4351
  );
4279
4352
  } catch (err) {
4353
+ console.log(` \u2715 ${chalk4.bgRed.white(` ${cleanMethod} `)} ${chalk4.red(url)} ${chalk4.red(err.message)}`);
4280
4354
  return JSON.stringify({
4281
4355
  error: `Request failed: ${err.message}`,
4282
4356
  status_code: 0
@@ -4299,7 +4373,7 @@ var executeHttpRequestTool = tool3(
4299
4373
  // src/tools/postman.ts
4300
4374
  import { tool as tool4 } from "@langchain/core/tools";
4301
4375
  import axios4 from "axios";
4302
- import chalk4 from "chalk";
4376
+ import chalk5 from "chalk";
4303
4377
  import fs from "fs";
4304
4378
  import path from "path";
4305
4379
  var exportPostmanCollectionTool = tool4(
@@ -4307,12 +4381,11 @@ var exportPostmanCollectionTool = tool4(
4307
4381
  baseUrl,
4308
4382
  outputFilename = "probe_collection.json"
4309
4383
  }) => {
4310
- console.log(chalk4.magenta(`
4311
- \u{1F4E6} [Tool: export_postman_collection] Exporting Postman collection...`));
4312
4384
  let targetUrl = baseUrl.replace(/\/+$/, "");
4313
4385
  if (!targetUrl.endsWith("openapi.json")) {
4314
4386
  targetUrl = `${targetUrl}/openapi.json`;
4315
4387
  }
4388
+ logStep("\u{1F4E6}", "Generating Postman v2.1 Collection...", chalk5.dim(baseUrl));
4316
4389
  try {
4317
4390
  const res = await axios4.get(targetUrl, { timeout: 1e4 });
4318
4391
  const spec = res.data;
@@ -4359,9 +4432,10 @@ var exportPostmanCollectionTool = tool4(
4359
4432
  }
4360
4433
  const outPath = path.join(reportsDir, path.basename(outputFilename));
4361
4434
  fs.writeFileSync(outPath, JSON.stringify(postmanCollection, null, 2));
4362
- console.log(chalk4.green(` \u2514\u2500 Saved Postman Collection to: ${outPath}`));
4435
+ logStep("\u2713", `Saved Postman Collection (${postmanItems.length} routes)`, chalk5.hex("#10B981")(outPath));
4363
4436
  return `Postman collection with ${postmanItems.length} endpoints successfully generated at '${outPath}'. You can import this directly into Postman/Bruno/Insomnia!`;
4364
4437
  } catch (err) {
4438
+ logStep("\u2715", "Postman Export Failed", chalk5.red(err.message));
4365
4439
  return `Failed to export Postman collection: ${err.message}`;
4366
4440
  }
4367
4441
  },
@@ -4377,7 +4451,7 @@ var exportPostmanCollectionTool = tool4(
4377
4451
 
4378
4452
  // src/tools/report.ts
4379
4453
  import { tool as tool5 } from "@langchain/core/tools";
4380
- import chalk5 from "chalk";
4454
+ import chalk6 from "chalk";
4381
4455
  import fs2 from "fs";
4382
4456
  import path2 from "path";
4383
4457
  var saveHtmlAuditReportTool = tool5(
@@ -4478,8 +4552,7 @@ var saveHtmlAuditReportTool = tool5(
4478
4552
  </html>
4479
4553
  `;
4480
4554
  fs2.writeFileSync(outPath, htmlContent);
4481
- console.log(chalk5.green(`
4482
- \u{1F4CA} [Tool: save_html_audit_report] Interactive HTML Report saved to: ${outPath}`));
4555
+ logStep("\u{1F4CA}", "Generated HTML Audit Dashboard", chalk6.hex("#10B981")(outPath));
4483
4556
  return `HTML audit report successfully generated at '${outPath}'. Open it in your browser to view the interactive dashboard!`;
4484
4557
  },
4485
4558
  {
@@ -4512,7 +4585,9 @@ function createProbeAgent(apiKey) {
4512
4585
  const model = new ChatGoogleGenerativeAI({
4513
4586
  model: "gemini-3.6-flash",
4514
4587
  temperature: 0.2,
4515
- apiKey
4588
+ apiKey,
4589
+ maxRetries: 3
4590
+ // Auto-retry on transient Google 503 spikes
4516
4591
  }).bindTools(tools);
4517
4592
  const callModel = async (state) => {
4518
4593
  const response = await model.invoke(state.messages);
@@ -4539,9 +4614,10 @@ marked.use(
4539
4614
  width: 90,
4540
4615
  reflowText: true,
4541
4616
  tab: 2,
4542
- heading: chalk6.bold.cyan,
4543
- firstHeading: chalk6.bold.magenta,
4544
- strong: chalk6.bold.white,
4617
+ heading: chalk7.bold.hex("#6366F1"),
4618
+ firstHeading: chalk7.bold.hex("#A855F7"),
4619
+ strong: chalk7.bold.white,
4620
+ listitem: chalk7.cyan,
4545
4621
  tableOptions: {
4546
4622
  style: {
4547
4623
  head: ["cyan", "bold"],
@@ -4550,28 +4626,8 @@ marked.use(
4550
4626
  }
4551
4627
  })
4552
4628
  );
4553
- function printBanner() {
4554
- console.log(
4555
- boxen(
4556
- `${chalk6.bold.cyan("\u{1F50D} ProbeAI \u2014 Autonomous API Reliability & Postman Suite Generator")}
4557
- ${chalk6.dim("TypeScript CLI Edition \u2022 Dynamic Auth \u2022 Postman v2.1 Exporter \u2022 HTML Reports")}
4558
-
4559
- ${chalk6.yellow("Try prompts like:")}
4560
- \u2022 'Inspect https://bookmark-agent-backend.onrender.com and export a Postman collection'
4561
- \u2022 'Test all endpoints on https://bookmark-agent-backend.onrender.com and save an HTML report'
4562
- \u2022 'Set auth Bearer my_secret_token and test protected routes'
4563
- \u2022 Type ${chalk6.bold.red("'exit'")} to quit`,
4564
- {
4565
- padding: 1,
4566
- margin: 1,
4567
- borderStyle: "round",
4568
- borderColor: "cyan"
4569
- }
4570
- )
4571
- );
4572
- }
4573
4629
  async function main() {
4574
- printBanner();
4630
+ printModernBanner("1.0.4");
4575
4631
  const rl = readline.createInterface({
4576
4632
  input: process.stdin,
4577
4633
  output: process.stdout
@@ -4585,30 +4641,33 @@ async function main() {
4585
4641
  };
4586
4642
  let apiKey = process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY;
4587
4643
  if (!apiKey) {
4588
- console.log(chalk6.yellow("\u{1F511} No GEMINI_API_KEY found in your environment or .env file."));
4589
- console.log(chalk6.dim("Get a free key from https://aistudio.google.com/\n"));
4590
- apiKey = await promptUser(chalk6.bold.cyan("Enter your Gemini API Key: "));
4644
+ console.log(chalk7.yellow("\u{1F511} No GEMINI_API_KEY found in your environment or .env file."));
4645
+ console.log(chalk7.dim("Get a free key from https://aistudio.google.com/\n"));
4646
+ apiKey = await promptUser(chalk7.bold.hex("#6366F1")("Enter your Gemini API Key: "));
4591
4647
  if (!apiKey) {
4592
- console.log(chalk6.red("\nError: An API key is required to run ProbeAI. Exiting...\n"));
4648
+ console.log(chalk7.red("\nError: An API key is required to run ProbeAI. Exiting...\n"));
4593
4649
  rl.close();
4594
4650
  process.exit(1);
4595
4651
  }
4596
- console.log(chalk6.green("\u2705 API Key registered for this session.\n"));
4652
+ console.log(chalk7.hex("#10B981")("\u2713 API Key registered for this session.\n"));
4597
4653
  }
4598
4654
  const app = createProbeAgent(apiKey);
4599
4655
  const messages = [PROBE_SYSTEM_MESSAGE];
4600
4656
  while (true) {
4601
4657
  try {
4602
- const input = await promptUser(chalk6.bold.green("\nYou: "));
4658
+ const promptSymbol = chalk7.bold.hex("#6366F1")("\u276F ");
4659
+ const input = await promptUser(`
4660
+ ${promptSymbol}`);
4603
4661
  if (!input) continue;
4604
4662
  if (input.toLowerCase() === "exit" || input.toLowerCase() === "quit") {
4605
- console.log(chalk6.cyan("\nGoodbye! \u{1F44B}\n"));
4663
+ console.log(chalk7.hex("#6366F1")("\nGoodbye! \u{1F44B}\n"));
4606
4664
  rl.close();
4607
4665
  process.exit(0);
4608
4666
  }
4667
+ console.log();
4609
4668
  messages.push(new HumanMessage(input));
4610
4669
  const spinner = ora({
4611
- text: chalk6.dim("ProbeAI thinking..."),
4670
+ text: chalk7.dim("Synthesizing test scenarios & auditing schemas..."),
4612
4671
  color: "cyan"
4613
4672
  }).start();
4614
4673
  let finalResponse = "";
@@ -4623,12 +4682,16 @@ async function main() {
4623
4682
  }
4624
4683
  spinner.stop();
4625
4684
  if (finalResponse) {
4626
- console.log("\n" + chalk6.bold.cyan("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 ProbeAI Assessment \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n"));
4685
+ console.log(
4686
+ "\n" + chalk7.hex("#6366F1")(
4687
+ "\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501 ProbeAI Assessment \u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n"
4688
+ )
4689
+ );
4627
4690
  const rendered = marked(finalResponse);
4628
4691
  console.log(rendered);
4629
4692
  }
4630
4693
  } catch (err) {
4631
- console.log(chalk6.red(`
4694
+ console.log(chalk7.red(`
4632
4695
  An error occurred: ${err.message}`));
4633
4696
  }
4634
4697
  }
package/package.json CHANGED
@@ -1,17 +1,19 @@
1
1
  {
2
2
  "name": "@kamrankhan027/probe-ai",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Autonomous API Schema & Reliability Inspector CLI. Probes OpenAPI specs, generates test suites, executes real-time HTTP calls, and exports Postman collections.",
5
- "main": "dist/index.js",
6
- "types": "dist/index.d.ts",
7
- "bin": "dist/index.js",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "bin": {
8
+ "probe-ai": "./dist/index.js"
9
+ },
8
10
  "files": [
9
11
  "dist"
10
12
  ],
11
13
  "scripts": {
12
14
  "build": "tsup",
13
15
  "dev": "tsup --watch",
14
- "start": "node dist/index.js"
16
+ "start": "node ./dist/index.js"
15
17
  },
16
18
  "keywords": [
17
19
  "ai",