@shieldly/cli 1.0.0 → 1.0.2

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 +31 -3
  2. package/dist/cli.cjs +40 -33
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -10,10 +10,28 @@ any terminal, shell script, or CI/CD pipeline. Powered by
10
10
  npm install -g @shieldly/cli
11
11
  ```
12
12
 
13
+ ## Try it free — no account needed
14
+
15
+ `analyze-iam` runs in demo mode without an API key (5 lifetime analyses):
16
+
17
+ ```bash
18
+ shieldly analyze-iam policy.json
19
+ ```
20
+
21
+ To unlock `analyze-cf`, history, and 20 free analyses per day,
22
+ [create a free account](https://www.shieldly.io/app/api) and set your key:
23
+
24
+ ```bash
25
+ export SHIELDLY_API_KEY=sk_live_...
26
+ shieldly analyze-cf template.yaml
27
+ ```
28
+
29
+ Upgrade to a paid plan for higher daily limits, team access, and priority AI.
30
+
13
31
  ## Quick start
14
32
 
15
33
  ```bash
16
- # Authenticate (get a key at https://www.shieldly.io/app/api)
34
+ # Set your API key (get one free at https://www.shieldly.io/app/api)
17
35
  export SHIELDLY_API_KEY=sk_live_...
18
36
 
19
37
  # Analyze an IAM policy
@@ -26,8 +44,18 @@ shieldly analyze-cf template.yaml
26
44
  shieldly api-keys list
27
45
  ```
28
46
 
29
- Without an API key, `analyze-iam` runs in demo mode (5 lifetime analyses, IAM only).
30
- `analyze-cf` and `api-keys` require a key.
47
+ ## Free tier
48
+
49
+ | Mode | Limit | Requires |
50
+ | --- | --- | --- |
51
+ | Demo (no key) | 5 analyses total | No account |
52
+ | Free account | 20 units/day | Free sign-up |
53
+ | Builder | 150 units/day | Paid plan |
54
+ | Pro | 300 units/day | Paid plan |
55
+ | Team | 600 units/day | Paid plan |
56
+
57
+ Analysis units depend on input size — a small IAM policy costs 1 unit;
58
+ large CloudFormation templates cost more. [Compare plans →](https://www.shieldly.io/#pricing)
31
59
 
32
60
  ## Commands
33
61
 
package/dist/cli.cjs CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
- var J=Object.create;var O=Object.defineProperty;var B=Object.getOwnPropertyDescriptor;var q=Object.getOwnPropertyNames;var V=Object.getPrototypeOf,Z=Object.prototype.hasOwnProperty;var Q=(e,o,t,n)=>{if(o&&typeof o=="object"||typeof o=="function")for(let s of q(o))!Z.call(e,s)&&s!==t&&O(e,s,{get:()=>o[s],enumerable:!(n=B(o,s))||n.enumerable});return e};var C=(e,o,t)=>(t=e!=null?J(V(e)):{},Q(o||!e||!e.__esModule?O(t,"default",{value:e,enumerable:!0}):t,e));var $=require("node:fs"),j=require("node:os"),D=require("node:path"),b="Shieldly-CLI/1.0.0",z=(0,D.join)((0,j.homedir)(),".shieldly","config.json"),X="https://api.shieldly.io",ee="https://www.shieldly.io";function g(e){if(e)return e;if(process.env.SHIELDLY_API_KEY)return process.env.SHIELDLY_API_KEY;if((0,$.existsSync)(z))try{let o=JSON.parse((0,$.readFileSync)(z,"utf8"));if(o.apiKey)return o.apiKey}catch{}return null}function _(){return(process.env.SHIELDLY_API_URL||X).replace(/\/$/,"")}function oe(){return(process.env.SHIELDLY_WEB_URL||ee).replace(/\/$/,"")}async function R(e,o){let t=oe(),n=await fetch(`${t}${e}`,{method:"POST",headers:{"Content-Type":"application/json","User-Agent":b},body:JSON.stringify(o)});if(!n.ok){let s=await n.json().catch(()=>({}));throw new Error(s.error||`API error ${n.status}`)}return n.json()}async function I(e,o,t){let n=_(),s=await fetch(`${n}${e}`,{method:"POST",headers:{"Content-Type":"application/json","User-Agent":b,Authorization:`Bearer ${t}`},body:JSON.stringify(o)});if(s.status===202){let r=await s.json().catch(()=>({}));if(r.jobId)return se(r.jobId,t)}if(!s.ok){let r=await s.json().catch(()=>({}));throw new Error(r.error||`API error ${s.status}`)}return s.json()}async function se(e,o){let t=[2e3,3e3,5e3],n=Date.now(),s=0;for(let r=0;r<180;r++){let i=t[Math.min(r,t.length-1)];await new Promise(c=>setTimeout(c,i));let l=Math.round((Date.now()-n)/1e3);process.stderr.write(`\rAI-Powered analysis in progress\u2026 (${l}s)`);let a;try{a=await v(`/v1/jobs/${encodeURIComponent(e)}`,o),s=0}catch(c){if(++s>=3)throw process.stderr.write(`
3
- `),c;continue}if(a.status==="complete")return process.stderr.write(`
4
- `),{...a.result,unitInfo:a.unitInfo};if(a.status==="failed")throw process.stderr.write(`
5
- `),new Error(a.error||"Analysis failed")}throw process.stderr.write(`
6
- `),new Error("Analysis timed out after polling")}async function v(e,o){let t=_(),n=await fetch(`${t}${e}`,{headers:{Authorization:`Bearer ${o}`,"User-Agent":b}});if(!n.ok){let s=await n.json().catch(()=>({}));throw new Error(s.error||`API error ${n.status}`)}return n.json()}async function M(e,o,t){let n=_(),s=await fetch(`${n}${e}`,{method:"DELETE",headers:{"Content-Type":"application/json","User-Agent":b,Authorization:`Bearer ${t}`},body:JSON.stringify(o)});if(!s.ok){let r=await s.json().catch(()=>({}));throw new Error(r.error||`API error ${s.status}`)}return s.json()}function w(e){return(0,$.existsSync)(e)||(console.error(`Error: File not found: ${e}`),process.exit(1)),(0,$.readFileSync)(e,"utf8")}var K={CRITICAL:"\x1B[31m",HIGH:"\x1B[33m",MEDIUM:"\x1B[36m",LOW:"\x1B[32m",INFO:"\x1B[90m"},m="\x1B[0m",k="\x1B[1m",L="\x1B[2m",Y="\x1B[36m";function x(e,o){if(o==="json"){console.log(JSON.stringify(e,null,2));return}let{score:t,riskLevel:n,findings:s=[],cached:r}=e;if(console.log(""),console.log(`${k}AI-Powered Security Analysis \u2014 Shieldly${m}`),console.log(`${L}${"\u2500".repeat(50)}${m}`),console.log(` ${k}Security Score:${m} ${te(t)}${t}/100${m}`),console.log(` ${k}Risk Level:${m} ${ne(n)}${n}${m}`),r&&console.log(` ${L}(cached result)${m}`),console.log(""),s.length===0)console.log(` ${Y}[PASS] No findings${m}`);else{console.log(`${k}Findings (${s.length}):${m}`);for(let i of s){let l=K[(i.severity||"").toUpperCase()]||"";console.log(`
7
- ${l}[${i.severity}]${m} ${k}${i.title}${m}`),i.description&&console.log(` ${L}${i.description}${m}`),i.remediation&&console.log(` ${Y}Fix:${m} ${i.remediation}`)}}console.log("")}function te(e){return e>=80?"\x1B[32m":e>=50?"\x1B[33m":"\x1B[31m"}function ne(e){let o=(e||"").toUpperCase();return K[o]||""}var le=`
2
+ var B=Object.create;var C=Object.defineProperty;var q=Object.getOwnPropertyDescriptor;var V=Object.getOwnPropertyNames;var Z=Object.getPrototypeOf,Q=Object.prototype.hasOwnProperty;var X=(e,o,t,n)=>{if(o&&typeof o=="object"||typeof o=="function")for(let s of V(o))!Q.call(e,s)&&s!==t&&C(e,s,{get:()=>o[s],enumerable:!(n=q(o,s))||n.enumerable});return e};var z=(e,o,t)=>(t=e!=null?B(Z(e)):{},X(o||!e||!e.__esModule?C(t,"default",{value:e,enumerable:!0}):t,e));var g=require("node:fs"),j=require("node:os"),D=require("node:path"),w="Shieldly-CLI/1.0.2",O=(0,D.join)((0,j.homedir)(),".shieldly","config.json"),ee="https://api.shieldly.io",oe="https://www.shieldly.io";function I(e){if(e)return e;if(process.env.SHIELDLY_API_KEY)return process.env.SHIELDLY_API_KEY;if((0,g.existsSync)(O))try{let o=JSON.parse((0,g.readFileSync)(O,"utf8"));if(o.apiKey)return o.apiKey}catch{}return null}function L(){return(process.env.SHIELDLY_API_URL||ee).replace(/\/$/,"")}function se(){return(process.env.SHIELDLY_WEB_URL||oe).replace(/\/$/,"")}async function R(e,o){let t=se(),n=await fetch(`${t}${e}`,{method:"POST",headers:{"Content-Type":"application/json","User-Agent":w},body:JSON.stringify(o)});if(!n.ok){let s=await n.json().catch(()=>({}));throw new Error(s.error||`API error ${n.status}`)}return n.json()}async function k(e,o,t){let n=L(),s=await fetch(`${n}${e}`,{method:"POST",headers:{"Content-Type":"application/json","User-Agent":w,Authorization:`Bearer ${t}`},body:JSON.stringify(o)});if(s.status===202){let r=await s.json().catch(()=>({}));if(r.jobId)return te(r.jobId,t)}if(!s.ok){let r=await s.json().catch(()=>({}));throw new Error(r.error||`API error ${s.status}`)}return s.json()}async function te(e,o){let t=[2e3,3e3,5e3],n=Date.now(),s=0;for(let r=0;r<180;r++){let a=t[Math.min(r,t.length-1)];await new Promise(c=>setTimeout(c,a));let l=Math.round((Date.now()-n)/1e3);process.stderr.write(`\rAI-Powered analysis in progress\u2026 (${l}s)`);let i;try{i=await v(`/v1/jobs/${encodeURIComponent(e)}`,o),s=0}catch(c){if(++s>=3)throw process.stderr.write(`
3
+ `),c;continue}if(i.status==="complete")return process.stderr.write(`
4
+ `),{...i.result,unitInfo:i.unitInfo};if(i.status==="failed")throw process.stderr.write(`
5
+ `),new Error(i.error||"Analysis failed")}throw process.stderr.write(`
6
+ `),new Error("Analysis timed out after polling")}async function v(e,o){let t=L(),n=await fetch(`${t}${e}`,{headers:{Authorization:`Bearer ${o}`,"User-Agent":w}});if(!n.ok){let s=await n.json().catch(()=>({}));throw new Error(s.error||`API error ${n.status}`)}return n.json()}async function M(e,o,t){let n=L(),s=await fetch(`${n}${e}`,{method:"DELETE",headers:{"Content-Type":"application/json","User-Agent":w,Authorization:`Bearer ${t}`},body:JSON.stringify(o)});if(!s.ok){let r=await s.json().catch(()=>({}));throw new Error(r.error||`API error ${s.status}`)}return s.json()}function P(e){return(0,g.existsSync)(e)||(console.error(`Error: File not found: ${e}`),process.exit(1)),(0,g.readFileSync)(e,"utf8")}var K={CRITICAL:"\x1B[31m",HIGH:"\x1B[33m",MEDIUM:"\x1B[36m",LOW:"\x1B[32m",INFO:"\x1B[90m"},y="\x1B[0m",A="\x1B[1m",_="\x1B[2m",Y="\x1B[36m";function x(e,o){if(o==="json"){console.log(JSON.stringify(e,null,2));return}let{score:t,riskLevel:n,findings:s=[],cached:r}=e;if(console.log(""),console.log(`${A}AI-Powered Security Analysis \u2014 Shieldly${y}`),console.log(`${_}${"\u2500".repeat(50)}${y}`),console.log(` ${A}Security Score:${y} ${ne(t)}${t}/100${y}`),console.log(` ${A}Risk Level:${y} ${le(n)}${n}${y}`),r&&console.log(` ${_}(cached result)${y}`),console.log(""),s.length===0)console.log(` ${Y}[PASS] No findings${y}`);else{console.log(`${A}Findings (${s.length}):${y}`);for(let a of s){let l=K[(a.severity||"").toUpperCase()]||"";console.log(`
7
+ ${l}[${a.severity}]${y} ${A}${a.title}${y}`),a.description&&console.log(` ${_}${a.description}${y}`),a.remediation&&console.log(` ${Y}Fix:${y} ${a.remediation}`)}}console.log("")}function ne(e){return e>=80?"\x1B[32m":e>=50?"\x1B[33m":"\x1B[31m"}function le(e){let o=(e||"").toUpperCase();return K[o]||""}var re=`
8
8
  Usage: shieldly analyze-cf <template-file> [options]
9
9
 
10
10
  Analyze a CloudFormation template for security issues using AI.
@@ -20,8 +20,12 @@ Options:
20
20
  Examples:
21
21
  shieldly analyze-cf template.json
22
22
  shieldly analyze-cf template.yaml --format json
23
- `;async function H(e){if(e.includes("-h")||e.includes("--help")||e.length===0){console.log(le);return}let o=e.find(l=>!l.startsWith("--"));o||(console.error("Error: template-file argument is required"),process.exit(1));let t=e.indexOf("--format"),n=t!==-1?e[t+1]:"table",s=e.indexOf("--api-key"),r=g(s!==-1?e[s+1]:null);r||(console.error(`Error: API key required. Set SHIELDLY_API_KEY env var or use --api-key.
24
- Get your free key at https://www.shieldly.io/app/api`),process.exit(1));let i=w(o);n!=="json"&&console.log(`Analyzing ${o}\u2026`);try{let l=await I("/v1/analyze/cf",{template:i},r);x(l,n);let a=(l.findings||[]).filter(y=>y.severity==="CRITICAL").length,c=(l.findings||[]).filter(y=>y.severity==="HIGH").length;(a>0||c>0)&&process.exit(1)}catch(l){console.error(`Error: ${l.message}`),process.exit(1)}}var re=`
23
+ `;async function H(e){if(e.includes("-h")||e.includes("--help")||e.length===0){console.log(re);return}let o=e.find(l=>!l.startsWith("--"));o||(console.error("Error: template-file argument is required"),process.exit(1));let t=e.indexOf("--format"),n=t!==-1?e[t+1]:"table",s=e.indexOf("--api-key"),r=I(s!==-1?e[s+1]:null);r||(console.error(`CloudFormation analysis requires an API key.
24
+
25
+ Free account: 20 analyses/day \u2014 https://www.shieldly.io/app/api
26
+
27
+ Set SHIELDLY_API_KEY or use --api-key once you have your key.
28
+ Tip: shieldly analyze-iam runs without a key (5 free demo analyses).`),process.exit(1));let a=P(o);n!=="json"&&console.log(`Analyzing ${o}\u2026`);try{let l=await k("/v1/analyze/cf",{template:a},r);x(l,n);let i=(l.findings||[]).filter(h=>h.severity==="CRITICAL").length,c=(l.findings||[]).filter(h=>h.severity==="HIGH").length;(i>0||c>0)&&process.exit(1)}catch(l){console.error(`Error: ${l.message}`),process.exit(1)}}var ie=`
25
29
  Usage: shieldly analyze-iam <policy-file> [options]
26
30
 
27
31
  Analyze an AWS IAM policy for security issues using AI.
@@ -41,7 +45,7 @@ Examples:
41
45
  shieldly analyze-iam policy.json
42
46
  shieldly analyze-iam policy.json --type resource --format json
43
47
  SHIELDLY_API_KEY=sk_... shieldly analyze-iam policy.json
44
- `;async function F(e){if(e.includes("-h")||e.includes("--help")||e.length===0){console.log(re);return}let o=e.find(y=>!y.startsWith("--"));o||(console.error("Error: policy-file argument is required"),process.exit(1));let t=e.indexOf("--type"),n=t!==-1?e[t+1]:"identity",s=e.indexOf("--format"),r=s!==-1?e[s+1]:"table",i=e.indexOf("--api-key"),l=g(i!==-1?e[i+1]:null),a=w(o),c;try{c=JSON.parse(a)}catch{console.error("Error: policy-file must be valid JSON"),process.exit(1)}r!=="json"&&(console.log(`Analyzing ${o} (type: ${n})\u2026`),l||console.log("Demo mode (5 lifetime analyses). Get a free key at https://www.shieldly.io/app/api"));try{let y=l?await I("/v1/analyze/iam",{policy:c,policyType:n},l):await R("/api/demo/analyze-iam",{policy:c,policyType:n});x(y,r);let E=(y.findings||[]).filter(S=>S.severity==="CRITICAL").length,d=(y.findings||[]).filter(S=>S.severity==="HIGH").length;(E>0||d>0)&&process.exit(1)}catch(y){console.error(`Error: ${y.message}`),process.exit(1)}}var U=`
48
+ `;async function F(e){if(e.includes("-h")||e.includes("--help")||e.length===0){console.log(ie);return}let o=e.find(u=>!u.startsWith("--"));o||(console.error("Error: policy-file argument is required"),process.exit(1));let t=e.indexOf("--type"),n=t!==-1?e[t+1]:"identity",s=e.indexOf("--format"),r=s!==-1?e[s+1]:"table",a=e.indexOf("--api-key"),l=I(a!==-1?e[a+1]:null),i=P(o);try{JSON.parse(i)}catch{console.error("Error: policy-file must be valid JSON"),process.exit(1)}let c=i.trim(),h=n==="identity"||n==="iam_identity"?"iam_identity":n==="cross_account"?"cross_account":"iam_identity";r!=="json"&&(console.log(`Analyzing ${o} (type: ${h})\u2026`),l||console.log("Demo mode (5 lifetime analyses). Get a free key at https://www.shieldly.io/app/api"));try{let u=l?await k("/v1/analyze/iam",{policy:c,policyType:h},l):await R("/api/demo/analyze-iam",{policy:c,policyType:h});x(u,r);let d=(u.findings||[]).filter(S=>S.severity==="CRITICAL").length,J=(u.findings||[]).filter(S=>S.severity==="HIGH").length;(d>0||J>0)&&process.exit(1)}catch(u){console.error(`Error: ${u.message}`),process.exit(1)}}var U=`
45
49
  Usage: shieldly api-keys <subcommand> [options]
46
50
 
47
51
  Manage Shieldly API keys.
@@ -61,9 +65,12 @@ Examples:
61
65
  shieldly api-keys list
62
66
  shieldly api-keys create --label "CI/CD Key" --scopes iam,cf
63
67
  shieldly api-keys revoke key_abc123
64
- `,u="\x1B[1m",N="\x1B[2m",T="\x1B[36m",h="\x1B[0m";function ie(e){return e?new Date(e).toLocaleDateString("en-US",{month:"short",day:"numeric",year:"numeric"}):"\u2014"}async function G(e){if(e.includes("-h")||e.includes("--help")||e.length===0){console.log(U);return}let o=e[0],t=e.slice(1),n=t.indexOf("--api-key"),s=g(n!==-1?t[n+1]:null),r=t.indexOf("--format"),i=r!==-1?t[r+1]:"table";if(s||(console.error(`Error: API key required. Set SHIELDLY_API_KEY env var or use --api-key.
65
- Get your free key at https://www.shieldly.io/app/api`),process.exit(1)),o==="list"){try{let a=(await v("/v1/api-keys",s)).keys||[];if(i==="json"){console.log(JSON.stringify(a,null,2));return}if(a.length===0){console.log("No API keys found. Create one at https://www.shieldly.io/app/api");return}console.log(""),console.log(`${u}API Keys (${a.length}):${h}`),console.log(`${N}${"\u2500".repeat(60)}${h}`);for(let c of a){let y=(c.scopes||[]).join(", ")||"all";console.log(` ${T}${c.keyId}${h}`),console.log(` ${u}Label:${h} ${c.label||"(unlabeled)"}`),console.log(` ${u}Scopes:${h} ${y}`),console.log(` ${u}Uses:${h} ${c.usageCount||0}`),console.log(` ${u}Created:${h} ${ie(c.createdAt)}`),console.log("")}}catch(l){console.error(`Error: ${l.message}`),process.exit(1)}return}if(o==="create"){let l=t.indexOf("--label"),a=l!==-1?t[l+1]:"CLI Key",c=t.indexOf("--scopes"),E=(c!==-1?t[c+1]:"iam,cf").split(",").map(d=>d.trim()).filter(Boolean);try{let d=await I("/v1/api-keys",{label:a,scopes:E},s);if(i==="json"){console.log(JSON.stringify(d,null,2));return}console.log(""),console.log(`${u}[OK] API key created${h}`),console.log(` ${u}Key ID:${h} ${d.keyId}`),console.log(` ${u}API Key:${h} ${T}${d.apiKey}${h}`),console.log(` ${N}Store this key securely \u2014 it won't be shown again.${h}`),console.log("")}catch(d){console.error(`Error: ${d.message}`),process.exit(1)}return}if(o==="revoke"){let l=t.find(a=>!a.startsWith("--")&&a!=="revoke");l||(console.error(`Error: key-id argument is required
66
- Usage: shieldly api-keys revoke <key-id>`),process.exit(1));try{if(await M("/v1/api-keys",{keyId:l},s),i==="json"){console.log(JSON.stringify({success:!0,keyId:l}));return}console.log(`[OK] API key ${l} revoked`)}catch(a){console.error(`Error: ${a.message}`),process.exit(1)}return}console.error(`Unknown subcommand: ${o}`),console.log(U),process.exit(1)}var ae=`
68
+ `,f="\x1B[1m",N="\x1B[2m",T="\x1B[36m",m="\x1B[0m";function ae(e){return e?new Date(e).toLocaleDateString("en-US",{month:"short",day:"numeric",year:"numeric"}):"\u2014"}async function W(e){if(e.includes("-h")||e.includes("--help")||e.length===0){console.log(U);return}let o=e[0],t=e.slice(1),n=t.indexOf("--api-key"),s=I(n!==-1?t[n+1]:null),r=t.indexOf("--format"),a=r!==-1?t[r+1]:"table";if(s||(console.error(`API key management requires an API key to authenticate.
69
+
70
+ Create your free account: https://www.shieldly.io/app/api
71
+
72
+ Set SHIELDLY_API_KEY or use --api-key once you have your key.`),process.exit(1)),o==="list"){try{let i=(await v("/v1/api-keys",s)).keys||[];if(a==="json"){console.log(JSON.stringify(i,null,2));return}if(i.length===0){console.log("No API keys found. Create one at https://www.shieldly.io/app/api");return}console.log(""),console.log(`${f}API Keys (${i.length}):${m}`),console.log(`${N}${"\u2500".repeat(60)}${m}`);for(let c of i){let h=(c.scopes||[]).join(", ")||"all";console.log(` ${T}${c.keyId}${m}`),console.log(` ${f}Label:${m} ${c.label||"(unlabeled)"}`),console.log(` ${f}Scopes:${m} ${h}`),console.log(` ${f}Uses:${m} ${c.usageCount||0}`),console.log(` ${f}Created:${m} ${ae(c.createdAt)}`),console.log("")}}catch(l){console.error(`Error: ${l.message}`),process.exit(1)}return}if(o==="create"){let l=t.indexOf("--label"),i=l!==-1?t[l+1]:"CLI Key",c=t.indexOf("--scopes"),u=(c!==-1?t[c+1]:"iam,cf").split(",").map(d=>d.trim()).filter(Boolean);try{let d=await k("/v1/api-keys",{label:i,scopes:u},s);if(a==="json"){console.log(JSON.stringify(d,null,2));return}console.log(""),console.log(`${f}[OK] API key created${m}`),console.log(` ${f}Key ID:${m} ${d.keyId}`),console.log(` ${f}API Key:${m} ${T}${d.apiKey}${m}`),console.log(` ${N}Store this key securely \u2014 it won't be shown again.${m}`),console.log("")}catch(d){console.error(`Error: ${d.message}`),process.exit(1)}return}if(o==="revoke"){let l=t.find(i=>!i.startsWith("--")&&i!=="revoke");l||(console.error(`Error: key-id argument is required
73
+ Usage: shieldly api-keys revoke <key-id>`),process.exit(1));try{if(await M("/v1/api-keys",{keyId:l},s),a==="json"){console.log(JSON.stringify({success:!0,keyId:l}));return}console.log(`[OK] API key ${l} revoked`)}catch(i){console.error(`Error: ${i.message}`),process.exit(1)}return}console.error(`Unknown subcommand: ${o}`),console.log(U),process.exit(1)}var ce=`
67
74
  _shieldly() {
68
75
  local cur prev words cword
69
76
  _init_completion || return
@@ -123,7 +130,7 @@ _shieldly() {
123
130
  fi
124
131
  } &&
125
132
  complete -F _shieldly shieldly
126
- `,ce=`
133
+ `,pe=`
127
134
  #compdef shieldly
128
135
 
129
136
  _shieldly() {
@@ -194,7 +201,7 @@ _shieldly() {
194
201
  }
195
202
 
196
203
  _shieldly
197
- `,pe=`
204
+ `,ye=`
198
205
  Usage: shieldly completion <shell>
199
206
 
200
207
  Generate shell completion scripts for the shieldly CLI.
@@ -208,42 +215,42 @@ Examples:
208
215
  eval "$(shieldly completion bash)" # Source bash completion
209
216
  shieldly completion zsh > /usr/local/share/zsh/site-functions/_shieldly # Install zsh completion
210
217
  shieldly completion install # Auto-detect and install
211
- `;async function W(e){if(!e.length||e.includes("-h")||e.includes("--help")){console.log(pe);return}let o=e[0];switch(o){case"bash":console.log(ae.trimStart());break;case"zsh":console.log(ce.trimStart());break;case"install":await ye();break;default:console.error(`Unsupported shell: ${o}`),console.log("Supported shells: bash, zsh"),process.exit(1)}}async function ye(){let e=process.env.SHELL||"",o=process.env.HOME||"";if(e.includes("zsh")){let t=`${o}/.zshrc`,n=`
218
+ `;async function G(e){if(!e.length||e.includes("-h")||e.includes("--help")){console.log(ye);return}let o=e[0];switch(o){case"bash":console.log(ce.trimStart());break;case"zsh":console.log(pe.trimStart());break;case"install":await me();break;default:console.error(`Unsupported shell: ${o}`),console.log("Supported shells: bash, zsh"),process.exit(1)}}async function me(){let e=process.env.SHELL||"",o=process.env.HOME||"";if(e.includes("zsh")){let t=`${o}/.zshrc`,n=`
212
219
  # shieldly CLI completion
213
220
  autoload -Uz compinit && compinit -C 2>/dev/null
214
- eval "$(shieldly completion zsh)" 2>/dev/null`;try{let{readFileSync:s,appendFileSync:r,existsSync:i}=await import("node:fs");if(i(t)&&s(t,"utf8").includes("shieldly completion")){console.log("shieldly completion already installed in ~/.zshrc");return}r(t,n),console.log("Installed shieldly completion in ~/.zshrc"),console.log("Run: source ~/.zshrc")}catch(s){console.error(`Failed to install: ${s.message}`),process.exit(1)}}else if(e.includes("bash")){let t=`${o}/.bashrc`,n=`
221
+ eval "$(shieldly completion zsh)" 2>/dev/null`;try{let{readFileSync:s,appendFileSync:r,existsSync:a}=await import("node:fs");if(a(t)&&s(t,"utf8").includes("shieldly completion")){console.log("shieldly completion already installed in ~/.zshrc");return}r(t,n),console.log("Installed shieldly completion in ~/.zshrc"),console.log("Run: source ~/.zshrc")}catch(s){console.error(`Failed to install: ${s.message}`),process.exit(1)}}else if(e.includes("bash")){let t=`${o}/.bashrc`,n=`
215
222
  # shieldly CLI completion
216
- source /dev/stdin <<< "$(shieldly completion bash)" 2>/dev/null`;try{let{readFileSync:s,appendFileSync:r,existsSync:i}=await import("node:fs");if(i(t)&&s(t,"utf8").includes("shieldly completion")){console.log("shieldly completion already installed in ~/.bashrc");return}r(t,n),console.log("Installed shieldly completion in ~/.bashrc"),console.log("Run: source ~/.bashrc")}catch(s){console.error(`Failed to install: ${s.message}`),process.exit(1)}}else console.error(`Unsupported shell: ${e}. Install manually:`),console.log(' eval "$(shieldly completion bash)" # For bash'),console.log(' eval "$(shieldly completion zsh)" # For zsh'),process.exit(1)}var f="\x1B[1m",A="\x1B[36m",P="\x1B[2m",p="\x1B[0m",me="1.0.0",he=`
217
- ${f}shieldly${p} \u2014 AI-Powered Security Analysis for AWS
223
+ source /dev/stdin <<< "$(shieldly completion bash)" 2>/dev/null`;try{let{readFileSync:s,appendFileSync:r,existsSync:a}=await import("node:fs");if(a(t)&&s(t,"utf8").includes("shieldly completion")){console.log("shieldly completion already installed in ~/.bashrc");return}r(t,n),console.log("Installed shieldly completion in ~/.bashrc"),console.log("Run: source ~/.bashrc")}catch(s){console.error(`Failed to install: ${s.message}`),process.exit(1)}}else console.error(`Unsupported shell: ${e}. Install manually:`),console.log(' eval "$(shieldly completion bash)" # For bash'),console.log(' eval "$(shieldly completion zsh)" # For zsh'),process.exit(1)}var $="\x1B[1m",b="\x1B[36m",E="\x1B[2m",p="\x1B[0m",he="1.0.0",ue=`
224
+ ${$}shieldly${p} \u2014 AI-Powered Security Analysis for AWS
218
225
 
219
- ${f}Usage:${p}
226
+ ${$}Usage:${p}
220
227
  shieldly <command> [args] [options]
221
228
 
222
- ${f}Commands:${p}
223
- ${A}analyze-iam${p} <policy-file> Analyze an IAM policy for security issues
224
- ${A}analyze-cf${p} <template-file> Analyze a CloudFormation template
225
- ${A}api-keys${p} list|create|revoke Manage API keys
226
- ${A}completion${p} bash|zsh|install Generate shell completion
229
+ ${$}Commands:${p}
230
+ ${b}analyze-iam${p} <policy-file> Analyze an IAM policy for security issues
231
+ ${b}analyze-cf${p} <template-file> Analyze a CloudFormation template
232
+ ${b}api-keys${p} list|create|revoke Manage API keys
233
+ ${b}completion${p} bash|zsh|install Generate shell completion
227
234
 
228
- ${f}Global Options:${p}
235
+ ${$}Global Options:${p}
229
236
  --api-key <key> API key (or set SHIELDLY_API_KEY env var)
230
237
  --version Show version
231
238
  -h, --help Show this help
232
239
 
233
- ${f}Authentication:${p}
240
+ ${$}Authentication:${p}
234
241
  Set your API key via env var: export SHIELDLY_API_KEY=sk_...
235
- Get a free API key at: ${A}https://www.shieldly.io/app/api${p}
242
+ Get a free API key at: ${b}https://www.shieldly.io/app/api${p}
236
243
 
237
- ${f}Examples:${p}
238
- ${P}# Analyze an IAM policy${p}
244
+ ${$}Examples:${p}
245
+ ${E}# Analyze an IAM policy${p}
239
246
  shieldly analyze-iam policy.json
240
247
 
241
- ${P}# Analyze a CloudFormation template${p}
248
+ ${E}# Analyze a CloudFormation template${p}
242
249
  shieldly analyze-cf template.yaml
243
250
 
244
- ${P}# List API keys${p}
251
+ ${E}# List API keys${p}
245
252
  shieldly api-keys list
246
253
 
247
- ${P}# Use in CI${p}
254
+ ${E}# Use in CI${p}
248
255
  SHIELDLY_API_KEY=\${{ secrets.SHIELDLY_API_KEY }} shieldly analyze-iam policy.json
249
- `;async function de(){let[,,e,...o]=process.argv;switch((!e||e==="-h"||e==="--help")&&(console.log(he),process.exit(0)),(e==="--version"||e==="-v")&&(console.log(me),process.exit(0)),e){case"analyze-iam":await F(o);break;case"analyze-cf":await H(o);break;case"api-keys":await G(o);break;case"completion":await W(o);break;default:console.error(`Unknown command: ${e}`),console.log(`Run ${f}shieldly --help${p} for usage`),process.exit(1)}}de().catch(e=>{console.error("Fatal error:",e.message),process.exit(1)});
256
+ `;async function de(){let[,,e,...o]=process.argv;switch((!e||e==="-h"||e==="--help")&&(console.log(ue),process.exit(0)),(e==="--version"||e==="-v")&&(console.log(he),process.exit(0)),e){case"analyze-iam":await F(o);break;case"analyze-cf":await H(o);break;case"api-keys":await W(o);break;case"completion":await G(o);break;default:console.error(`Unknown command: ${e}`),console.log(`Run ${$}shieldly --help${p} for usage`),process.exit(1)}}de().catch(e=>{console.error("Fatal error:",e.message),process.exit(1)});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shieldly/cli",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "AI-Powered Security Analysis for AWS — official CLI",
5
5
  "license": "MIT",
6
6
  "homepage": "https://www.shieldly.io",