proof-of-commitment 1.25.0 → 1.25.1

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 +7 -7
  2. package/index.js +56 -2
  3. package/package.json +10 -2
package/README.md CHANGED
@@ -11,15 +11,15 @@ An MCP server and web tool that scores npm packages, PyPI packages, Rust crates,
11
11
  26 of the 91 npm packages with >10M weekly downloads have a **single npm publisher**. Together they account for over 3 billion downloads per week. `npm audit` doesn't surface this. Stars don't either.
12
12
 
13
13
  Four packages in a typical Node.js project are CRITICAL right now:
14
- - **chalk** — 413M downloads/week, **1 npm publisher**
15
- - **zod** — 163M downloads/week, **1 npm publisher** (30+ GitHub contributors)
16
- - **lodash** — 145M downloads/week, **1 npm publisher**
17
- - **axios** — 99M downloads/week, **1 npm publisher** (attacked March 30, 2026)
14
+ - **chalk** — 432M downloads/week, **1 npm publisher**
15
+ - **zod** — 185M downloads/week, **1 npm publisher** (30+ GitHub contributors)
16
+ - **lodash** — 156M downloads/week, **1 npm publisher**
17
+ - **axios** — 113M downloads/week, **1 npm publisher** (attacked March 30, 2026)
18
18
 
19
19
  They won't appear in your `package.json` either — but these are in almost every project:
20
- - **minimatch** — 562M downloads/week, **1 npm publisher**
21
- - **glob** — 333M downloads/week, **1 npm publisher**
22
- - **cross-spawn** — 190M downloads/week, **1 npm publisher**
20
+ - **minimatch** — 625M downloads/week, **1 npm publisher**
21
+ - **glob** — 366M downloads/week, **1 npm publisher**
22
+ - **cross-spawn** — 215M downloads/week, **1 npm publisher**
23
23
 
24
24
  Behavioral signals surface this. Stars and READMEs don't.
25
25
 
package/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * proof-of-commitment CLI v1.24.0
3
+ * proof-of-commitment CLI v1.25.1
4
4
  * Scores npm/PyPI/Cargo/Go packages on behavioral commitment signals.
5
5
  * Usage: npx proof-of-commitment [packages...] [options]
6
6
  */
@@ -98,9 +98,14 @@ async function handle429(res) {
98
98
  const partial = Array.isArray(data.packages_already_scored)
99
99
  ? data.packages_already_scored
100
100
  : [];
101
+ // Authenticated keys: retry_after (seconds, used by worker auth-middleware quota path).
102
+ // Anonymous IPs: retry_after_seconds (legacy / overshoot rescue path).
103
+ // Read both so both paths surface a reset-time hint.
101
104
  const retryAfter = Number.isFinite(data.retry_after_seconds)
102
105
  ? data.retry_after_seconds
103
- : null;
106
+ : Number.isFinite(data.retry_after)
107
+ ? data.retry_after
108
+ : null;
104
109
  // Backend signals "you've blown past the free wall, Developer $15/mo is the
105
110
  // right fix" via overshoot=true / tier_suggestion="developer" (added
106
111
  // backend-side 2026-06-04). When set, backend routes instantKeyUrl to
@@ -109,6 +114,25 @@ async function handle429(res) {
109
114
  // Mismatched CTA text + destination kills trust and conversion. This branch
110
115
  // aligns label + URL + skips the inline email prompt. (Dogfood, 2026-06-06.)
111
116
  const overshoot = data.overshoot === true || data.tier_suggestion === 'developer';
117
+ // Authenticated-key quota path (added 2026-06-10): when the user already
118
+ // owns an API key and burns through their daily allowance, the backend
119
+ // auth-middleware (worker.ts resolveApiKey) returns a NESTED upgrade object:
120
+ // { error, message, tier, upgrade: { url, plan, price, limit, message }, retry_after }
121
+ // The legacy handle429() shape only knew the FLAT anonymous-IP shape
122
+ // (instant_key_url, upgrade_url, overshoot, tier_suggestion). On a free-tier
123
+ // key quota hit, all those flat fields were undefined → handler fell back
124
+ // to "Get a free key" + inline email prompt → user (who already has a key)
125
+ // got bait-and-switched at their highest-intent moment: invested in setup,
126
+ // used the key all day, ready to upgrade — and we offered them to create
127
+ // ANOTHER free key. Detect via `data.upgrade?.url && data.upgrade?.plan` +
128
+ // a non-anonymous `data.tier`, route to dedicated upgrade UX. Aligns CLI
129
+ // CTA + URL + skips email prompt symmetric to the overshoot branch.
130
+ const keyUpgrade =
131
+ data.upgrade &&
132
+ typeof data.upgrade.url === 'string' &&
133
+ typeof data.upgrade.plan === 'string' &&
134
+ typeof data.tier === 'string' &&
135
+ data.tier !== 'anonymous';
112
136
 
113
137
  // Forward-compat: if backend ever returns partial scoring on 429,
114
138
  // print what we have BEFORE the rescue message. Falls back to JSON
@@ -138,6 +162,36 @@ async function handle429(res) {
138
162
  }
139
163
  console.error('');
140
164
 
165
+ // Authenticated-key quota path: user already has a key, hit their daily
166
+ // allowance. Free-key inline prompt is the wrong tool — surface upgrade.
167
+ // (Diagnosis: 2026-06-10 idle-mode dogfood — see comment block above.)
168
+ if (keyUpgrade) {
169
+ const planLabel = data.upgrade.plan.charAt(0).toUpperCase() + data.upgrade.plan.slice(1);
170
+ const price = data.upgrade.price || '';
171
+ const limit = data.upgrade.limit || '';
172
+ const pitch = data.upgrade.message || `Upgrade to ${planLabel}.`;
173
+ // URL already carries utm_campaign=key-upgrade + utm_source=key +
174
+ // utm_medium=quota from backend buildUpgradeUrl — no rewrite needed,
175
+ // /pricing key-upgrade banner reads these and pre-selects the tier.
176
+ console.error(
177
+ clr(
178
+ c.cyan + c.bold,
179
+ ` → ${planLabel} (${price}${limit ? ' · ' + limit : ''}): ${data.upgrade.url}`
180
+ )
181
+ );
182
+ if (pitch) {
183
+ console.error(clr(c.dim, ` ${pitch}`));
184
+ }
185
+ if (retryAfter && retryAfter > 0) {
186
+ const hours = Math.floor(retryAfter / 3600);
187
+ const mins = Math.floor((retryAfter % 3600) / 60);
188
+ const resetIn = hours > 0 ? `${hours}h ${mins}m` : `${mins}m`;
189
+ console.error(clr(c.dim, ` or wait — your free-tier quota resets in ${resetIn}.`));
190
+ }
191
+ console.error('');
192
+ process.exit(1);
193
+ }
194
+
141
195
  // Overshoot path: free key is the wrong tool. Surface a URL aligned with
142
196
  // the backend's Developer recommendation, skip the email prompt, exit.
143
197
  // Without this branch, the CLI would say "Free API key in 30 seconds (no
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "proof-of-commitment",
3
- "version": "1.25.0",
3
+ "version": "1.25.1",
4
4
  "mcpName": "io.github.piiiico/proof-of-commitment",
5
5
  "description": "Supply chain security risk scorer for npm, PyPI, Cargo, and Go packages — behavioral signals that can't be faked",
6
6
  "type": "module",
@@ -34,7 +34,15 @@
34
34
  "maintainer",
35
35
  "publisher",
36
36
  "provenance",
37
- "trusted-publishing"
37
+ "trusted-publishing",
38
+ "mcp",
39
+ "mcp-server",
40
+ "vulnerability",
41
+ "sca",
42
+ "dependency-audit",
43
+ "lockfile",
44
+ "devsecops",
45
+ "ci"
38
46
  ],
39
47
  "author": "piiiico",
40
48
  "license": "MIT",