periderm-cli 0.1.1 → 0.1.3

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/dist/index.js CHANGED
@@ -151,11 +151,6 @@ program
151
151
  console.error(chalk.red("Error: You must be logged in. Run `periderm login` first."));
152
152
  process.exit(1);
153
153
  }
154
- const apiKey = process.env.GROQ_API_KEY?.trim();
155
- if (!apiKey) {
156
- console.error(chalk.red("Error: Set GROQ_API_KEY in your environment to run deep review."));
157
- process.exit(1);
158
- }
159
154
  const reportPath = path.join(root, ".periderm", "last-report.json");
160
155
  let scanResult;
161
156
  try {
@@ -178,7 +173,7 @@ program
178
173
  }
179
174
  verifySpinner.succeed("Plan verified");
180
175
  const reviewSpinner = ora({ text: "Starting deep review agent…", color: "cyan" }).start();
181
- const { markdown, findings } = await runDeepReview(root, scanResult, apiKey, (msg) => {
176
+ const { markdown, findings } = await runDeepReview(root, scanResult, cfg.token, cfg.apiUrl, (msg) => {
182
177
  reviewSpinner.text = msg;
183
178
  });
184
179
  scanResult.findings.push(...findings);
@@ -374,26 +369,50 @@ program
374
369
  console.info("");
375
370
  await updatePromise;
376
371
  });
377
- program.parseAsync().catch(async (e) => {
378
- console.error(e);
379
- try {
380
- const formData = new FormData();
381
- formData.append("name", "Periderm CLI Crash Reporter");
382
- formData.append("_replyto", "support@periderm.dev");
383
- const marker = "\n\n---\n[System Info: Sent from Periderm CLI]";
384
- const errMsg = e instanceof Error ? `${e.message}\n${e.stack}` : String(e);
385
- formData.append("message", `CLI Crash:\n\n${errMsg}${marker}`);
386
- await fetch("https://formspree.io/f/mqakppnn", {
387
- method: "POST",
388
- body: formData,
389
- headers: { Accept: "application/json" }
390
- });
391
- }
392
- catch (err) {
393
- // silently fail
394
- }
395
- process.exit(1);
396
- });
372
+ if (process.argv.length === 2) {
373
+ console.info("");
374
+ console.info(chalk.hex("#FF4D00")(PERIDERM_ASCII));
375
+ console.info("");
376
+ console.info(chalk.bold.white("Welcome to the Periderm CLI."));
377
+ console.info(chalk.gray("The ultimate pre-launch checklist for your codebase."));
378
+ console.info("");
379
+ program.help();
380
+ }
381
+ else {
382
+ program.parseAsync().catch(async (e) => {
383
+ console.error(e);
384
+ try {
385
+ const formData = new FormData();
386
+ formData.append("name", "Periderm CLI Crash Reporter");
387
+ let userEmail = "support@periderm.dev";
388
+ try {
389
+ const cfg = readConfig();
390
+ if (cfg.token) {
391
+ const v = await verifyToken(cfg.token);
392
+ if (v.valid && v.email) {
393
+ userEmail = v.email;
394
+ }
395
+ }
396
+ }
397
+ catch {
398
+ // ignore token verification errors during crash
399
+ }
400
+ formData.append("_replyto", userEmail);
401
+ const marker = `\n\n---\n[System Info: Sent from Periderm CLI]\n[User Email: ${userEmail === "support@periderm.dev" ? "Unknown" : userEmail}]`;
402
+ const errMsg = e instanceof Error ? `${e.message}\n${e.stack}` : String(e);
403
+ formData.append("message", `CLI Crash:\n\n${errMsg}${marker}`);
404
+ await fetch("https://formspree.io/f/mqakppnn", {
405
+ method: "POST",
406
+ body: formData,
407
+ headers: { Accept: "application/json" }
408
+ });
409
+ }
410
+ catch (err) {
411
+ // silently fail
412
+ }
413
+ process.exit(1);
414
+ });
415
+ }
397
416
  function readLine() {
398
417
  return new Promise((resolve) => {
399
418
  let data = "";
@@ -12,27 +12,23 @@ function stripCodeFences(text) {
12
12
  const m = text.match(/```(?:json)?\s*([\s\S]*?)```/);
13
13
  return (m?.[1] ?? text).trim();
14
14
  }
15
- async function groqJson(apiKey, system, user) {
16
- const res = await fetch("https://api.groq.com/openai/v1/chat/completions", {
15
+ async function groqJson(token, apiUrl, system, user) {
16
+ const res = await fetch(`${apiUrl}/api/public/deep-review`, {
17
17
  method: "POST",
18
18
  headers: {
19
- Authorization: `Bearer ${apiKey}`,
20
19
  "Content-Type": "application/json",
20
+ "x-periderm-token": token,
21
21
  },
22
- body: JSON.stringify({
23
- model: MODEL,
24
- temperature: 0.2,
25
- response_format: { type: "json_object" },
26
- messages: [
27
- { role: "system", content: system },
28
- { role: "user", content: user },
29
- ],
30
- }),
22
+ body: JSON.stringify({ system, user }),
31
23
  });
32
- if (!res.ok)
33
- throw new Error(`Groq API error ${res.status}: ${(await res.text()).slice(0, 200)}`);
34
- const data = (await res.json());
35
- return data.choices?.[0]?.message?.content ?? "{}";
24
+ if (!res.ok) {
25
+ const text = await res.text();
26
+ throw new Error(`Deep review API error ${res.status}: ${text.slice(0, 200)}`);
27
+ }
28
+ const data = await res.json();
29
+ if (!data.valid)
30
+ throw new Error(`Deep review failed: ${data.error}`);
31
+ return data.content ?? "{}";
36
32
  }
37
33
  async function readFileSafe(root, rel) {
38
34
  const safe = rel.replace(/^(\.\/|\.\.\/)+/, "").replace(/\.\./g, "");
@@ -87,7 +83,7 @@ function parseAction(raw) {
87
83
  return null;
88
84
  }
89
85
  }
90
- export async function runDeepReview(root, scan, apiKey, onStatus) {
86
+ export async function runDeepReview(root, scan, token, apiUrl, onStatus) {
91
87
  const system = `You are Periderm's deep launch reviewer. Respond with JSON only.
92
88
 
93
89
  Existing static scan found ${scan.findings.length} issues. Your job: find ADDITIONAL nuanced launch risks the deterministic scanner missed — legal/UX/business logic edge cases, contradictions, deceptive flows, subtle security gaps.
@@ -114,7 +110,7 @@ Rules: max 5 new findings, be specific, cite files, no hallucinated files.`;
114
110
  const toolLog = [];
115
111
  for (let i = 0; i < MAX_ITERATIONS; i++) {
116
112
  onStatus?.(`Deep review · pass ${i + 1}/${MAX_ITERATIONS}…`);
117
- const raw = await groqJson(apiKey, system, transcript);
113
+ const raw = await groqJson(token, apiUrl, system, transcript);
118
114
  const action = parseAction(raw);
119
115
  if (!action) {
120
116
  transcript += `\n\nInvalid JSON. Respond with valid JSON only.\n`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "periderm-cli",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "A pre-launch checklist for your codebase.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -21,7 +21,6 @@
21
21
  "@babel/types": "^7.25.0",
22
22
  "chalk": "^5.3.0",
23
23
  "commander": "^12.1.0",
24
- "dotenv": "^17.4.2",
25
24
  "fast-glob": "^3.3.2",
26
25
  "open": "^10.1.0",
27
26
  "ora": "^9.4.1"