periderm-cli 0.1.12 → 0.1.14

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/api.js CHANGED
@@ -58,3 +58,19 @@ export async function uploadScan(token, result) {
58
58
  return { error: e.message || "Network error: failed to reach server" };
59
59
  }
60
60
  }
61
+ export async function fetchCloudPolicies(token) {
62
+ const { apiUrl } = readConfig();
63
+ try {
64
+ const res = await fetch(`${apiUrl}/api/policies`, {
65
+ method: "POST",
66
+ headers: { "Content-Type": "application/json" },
67
+ body: JSON.stringify({ token }),
68
+ });
69
+ if (!res.ok)
70
+ return { global_ignores: [], custom_ai_rules: "" };
71
+ return (await res.json());
72
+ }
73
+ catch {
74
+ return { global_ignores: [], custom_ai_rules: "" };
75
+ }
76
+ }
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ import { scan } from "./scanner/index.js";
8
8
  import { runDeepReview } from "./review/deep.js";
9
9
  import { printTerminal } from "./report/terminal.js";
10
10
  import { readConfig, writeConfig } from "./config.js";
11
- import { verifyToken, uploadScan } from "./api.js";
11
+ import { verifyToken, uploadScan, fetchCloudPolicies } from "./api.js";
12
12
  import http from "node:http";
13
13
  import ora from "ora";
14
14
  import { PERIDERM_ASCII } from "./constants.js";
@@ -50,12 +50,28 @@ program
50
50
  verifySpinner.fail(`Couldn't connect — ${v.error}. Run \`periderm login\` again.`);
51
51
  process.exit(1);
52
52
  }
53
+ if (process.env.CI && v.plan === "starter") {
54
+ verifySpinner.fail("Automated CI/CD reporting requires the Scale or Unlimited plan.");
55
+ console.info(chalk.yellow(`\nUpgrade at ${cfg.apiUrl}/dashboard/billing\n`));
56
+ process.exit(1);
57
+ }
53
58
  if (v.plan !== "unlimited" && (v.scans_remaining === undefined || v.scans_remaining <= 0)) {
54
59
  verifySpinner.fail(`No scans left on your ${v.plan} plan.`);
55
60
  console.info(chalk.yellow(`\nRenew or upgrade at ${cfg.apiUrl}/dashboard/billing\n`));
56
61
  process.exit(1);
57
62
  }
58
63
  verifySpinner.stop();
64
+ // Fetch cloud policies for Unlimited users
65
+ let cloudIgnores = [];
66
+ let cloudAiRules = "";
67
+ if (v.plan === "unlimited") {
68
+ const policies = await fetchCloudPolicies(cfg.token);
69
+ cloudIgnores = policies.global_ignores ?? [];
70
+ cloudAiRules = policies.custom_ai_rules ?? "";
71
+ if (cloudIgnores.length > 0) {
72
+ console.info(chalk.dim(` ↳ Applying ${cloudIgnores.length} cloud ignore rule(s) from your dashboard policies.`));
73
+ }
74
+ }
59
75
  const startTime = Date.now();
60
76
  console.info(chalk.cyan("Discovering project files…"));
61
77
  let scanSpinner = ora({ text: "Initializing...", color: "cyan" }).start();
@@ -67,7 +83,7 @@ program
67
83
  const empty = 20 - filled;
68
84
  return `[${"█".repeat(filled)}${"░".repeat(empty)}] ${Math.round(pct * 100)}%`;
69
85
  };
70
- const result = await scan(root, {
86
+ const result = await scan(root, { cloudIgnores, cloudAiRules,
71
87
  onProgress: (ev) => {
72
88
  switch (ev.type) {
73
89
  case "discovering":
@@ -84,6 +84,9 @@ function parseAction(raw) {
84
84
  }
85
85
  }
86
86
  export async function runDeepReview(root, scan, token, apiUrl, onStatus) {
87
+ const orgRulesSection = scan.cloudAiRules?.trim()
88
+ ? `\n\nOrganization-specific instructions (MUST follow):\n${scan.cloudAiRules.trim()}`
89
+ : "";
87
90
  const system = `You are Periderm's deep launch reviewer. Respond with JSON only.
88
91
 
89
92
  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.
@@ -94,7 +97,7 @@ Tools (respond with {"action":"tool",...}):
94
97
 
95
98
  When finished: {"action":"done","summary":"...","findings":[{"message":"...","severity":"high|medium|low|critical","file":"path","why":"...","fix":"..."}]}
96
99
 
97
- Rules: max 5 new findings, be specific, cite files, no hallucinated files.`;
100
+ Rules: max 5 new findings, be specific, cite files, no hallucinated files.${orgRulesSection}`;
98
101
  const context = {
99
102
  project: scan.projectName,
100
103
  verdict: scan.verdict,
@@ -11,10 +11,10 @@ import { renderMarkdown } from "../report/markdown.js";
11
11
  import { mapWithProgress } from "./progress.js";
12
12
  export { formatScanPath } from "./progress.js";
13
13
  export async function scan(root, options = {}) {
14
- const { onProgress } = options;
14
+ const { onProgress, cloudIgnores = [], cloudAiRules = "" } = options;
15
15
  const findings = [];
16
16
  onProgress?.({ type: "discovering" });
17
- const files = await walk(root);
17
+ const files = await walk(root, cloudIgnores);
18
18
  onProgress?.({ type: "discovered", total: files.length });
19
19
  const estimatedChecks = files.length * PER_FILE_CHECK_COUNT +
20
20
  REPO_WIDE_CHECK_COUNT +
@@ -96,5 +96,6 @@ export async function scan(root, options = {}) {
96
96
  verdict,
97
97
  markdown,
98
98
  meta,
99
+ cloudAiRules: cloudAiRules || undefined,
99
100
  };
100
101
  }
@@ -1,7 +1,6 @@
1
1
  import fg from "fast-glob";
2
- export async function walk(root) {
3
- return fg([
4
- "**/*.{ts,tsx,js,jsx,mjs,cjs}",
2
+ export async function walk(root, extraIgnores = []) {
3
+ const baseIgnores = [
5
4
  "!**/node_modules/**",
6
5
  "!**/dist/**",
7
6
  "!**/build/**",
@@ -12,5 +11,12 @@ export async function walk(root) {
12
11
  "!**/*.d.ts",
13
12
  "!**/routeTree.gen.*",
14
13
  "!**/packages/cli/**", // never scan the scanner itself
14
+ ];
15
+ // Cloud policy ignores: normalize to negated globs
16
+ const cloudIgnoreGlobs = extraIgnores.map((ig) => ig.startsWith("!") ? ig : `!${ig}`);
17
+ return fg([
18
+ "**/*.{ts,tsx,js,jsx,mjs,cjs}",
19
+ ...baseIgnores,
20
+ ...cloudIgnoreGlobs,
15
21
  ], { cwd: root, absolute: true, dot: false });
16
22
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "periderm-cli",
3
- "version": "0.1.12",
3
+ "version": "0.1.14",
4
4
  "description": "A pre-launch checklist for your codebase.",
5
5
  "type": "module",
6
6
  "bin": {