proof-of-commitment 1.18.1 → 1.19.0

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 +14 -17
  2. package/index.js +67 -38
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -51,26 +51,23 @@ npx proof-of-commitment --file go.sum # full transitive set
51
51
 
52
52
  **Web demo (no install):** [getcommit.dev/audit](https://getcommit.dev/audit) — paste your packages, see risk scores in seconds.
53
53
 
54
- **Account + monitoring (v1.10.0):**
54
+ ## Get notified before the next attack
55
+
56
+ The CLI tells you what's risky today. A free API key unlocks **monitoring** — daily score recomputation across the packages you depend on, with alerts when one degrades (publisher drops, release stalls, score falls ≥10 points).
57
+
58
+ [**Get a free API key →**](https://getcommit.dev/get-started?ref=npm-readme-monitoring&utm_source=cli) — no card, 30 seconds · 200 audits/day free · Developer $15/mo unlocks alerts + watchlist.
59
+
55
60
  ```bash
56
61
  # Install once, then use the `poc` alias:
57
62
  npm install -g proof-of-commitment
58
63
 
59
- # Get a free API key at https://getcommit.dev/get-started?utm_source=cli, then:
60
- poc login sk_commit_your_key_here
61
- # Authenticated Tier: Free — Usage: 0/200 requests (daily)
62
-
63
- poc status # check tier + usage anytime
64
- poc logout # remove saved key
65
-
66
- # Monitoring (Pro tier — daily scans + alerts):
67
- poc watch chalk
64
+ # After getting your free key:
65
+ poc login sk_commit_your_key_here # save and validate
66
+ poc status # check tier + usage
67
+ poc watch chalk # start monitoring (Developer $15/mo)
68
68
  poc watch requests --ecosystem pypi
69
- poc watch serde --ecosystem cargo
70
- poc watchlist # view scores + risk levels
71
- poc unwatch chalk
72
-
73
- # Upgrade to Pro: https://getcommit.dev/pricing
69
+ poc watchlist # view all watched packages
70
+ poc init # add CI gate to this project
74
71
  ```
75
72
 
76
73
  Alerts fire on: score drop ≥10 points · package crosses CRITICAL threshold · recovery to HEALTHY.
@@ -132,12 +129,12 @@ When `comment-on-pr: true` (default), the action automatically posts the audit t
132
129
  | `max-packages` | `20` | Max packages to audit when auto-detecting |
133
130
  | `include-dev-dependencies` | `false` | Include `devDependencies` from `package.json` |
134
131
  | `comment-on-pr` | `true` | Post audit results as a PR comment (requires `pull-requests: write` permission) |
135
- | `api-key` | _(none)_ | [Commit Pro](https://getcommit.dev/pricing) API key — enables batch requests and 10K requests/month |
132
+ | `api-key` | _(none)_ | [Commit](https://getcommit.dev/pricing) API key — enables batch requests; Developer ($15/mo) gets 10K requests/month |
136
133
  | `api-url` | _(prod)_ | Override API endpoint (useful for self-hosting) |
137
134
 
138
135
  **Outputs:** `has-critical`, `critical-count`, `audit-summary` (markdown table, also written to Step Summary).
139
136
 
140
- **Free vs Pro:** Without an API key, packages are audited one at a time (with delays to respect rate limits). With a Pro API key, all packages are audited in a single batch request — faster and with higher monthly limits.
137
+ **Free vs paid:** Without an API key, packages are audited one at a time (with delays to respect rate limits). With any API key (free or paid), all packages are audited in a single batch request — faster. Paid tiers (Developer $15/mo+) raise the monthly request limit and unlock daily monitoring.
141
138
 
142
139
  Example PR comment / Step Summary output:
143
140
 
package/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * proof-of-commitment CLI v1.18.1
3
+ * proof-of-commitment CLI v1.19.0
4
4
  * Scores npm/PyPI/Cargo/Go packages on behavioral commitment signals.
5
5
  * Usage: npx proof-of-commitment [packages...] [options]
6
6
  */
@@ -293,15 +293,11 @@ function printTable(results, { totalScanned, totalCritical, lockfile } = {}) {
293
293
  console.log(clr(c.dim, ' Then run: ') + clr(c.cyan, 'poc login'));
294
294
  }
295
295
  // else: TTY mode — inlineSignup() will prompt interactively after printTable
296
- } else if (!hasKey) {
297
- // HEALTHY case + no saved key: soft watchlist CTA. The all-healthy
298
- // footer previously surfaced only CI-shaped CTAs (Action, `poc init`)
299
- // which both require active commitment workflow change + repo edit.
300
- // The lowest-friction conversion (email API key watchlist) was
301
- // hidden behind the CRITICAL gate of inlineSignup(). Buyer-journey
302
- // dogfood 2026-05-24 found 1472 weekly downloads → 0 organic signups;
303
- // the watchlist value prop ("alert me when these degrade") is real
304
- // for healthy packages too — that's exactly when monitoring matters.
296
+ } else if (!hasKey && (!process.stdin.isTTY || !process.stdout.isTTY)) {
297
+ // HEALTHY case + no saved key + non-TTY (CI/piped): static baseline CTA.
298
+ // In TTY mode, inlineSignup() now prompts interactively for healthy results
299
+ // too the dim text below converted 0/621 weekly downloads. Keep static
300
+ // text only in CI/piped output where interactive prompts can't fire.
305
301
  // ref=audit-baseline distinguishes this funnel from audit-cli-429
306
302
  // (rate-limit rescue) and from the static utm_source=cli help-line.
307
303
  console.log(clr(c.dim, '\n 📊 Save this scan as your baseline. Re-run anytime with a free key:'));
@@ -311,23 +307,35 @@ function printTable(results, { totalScanned, totalCritical, lockfile } = {}) {
311
307
  }
312
308
 
313
309
  /**
314
- * Inline signup: after CRITICAL findings, offer one-step email→key flow.
310
+ * Inline signup: after any real audit, offer one-step email→key flow.
315
311
  * Collapses 6-step funnel (visit site → email → check inbox → copy key → login → watch)
316
312
  * into a single CLI prompt.
313
+ *
314
+ * v1.19: Triggers on healthy results too (≥3 packages). The dim "Save this scan
315
+ * as your baseline" footer line converted 0/621 weekly downloads — replacing it
316
+ * with an interactive prompt at the moment of audit success captures more
317
+ * intent. Copy adapts to context: degradation alerts (CRITICAL) vs baseline
318
+ * lock-in (healthy). Quick lookups (<3 packages) still skip the prompt.
317
319
  */
318
320
  async function inlineSignup(results) {
319
- // Only prompt in interactive TTY when findings make monitoring relevant and no key saved
321
+ // Only prompt in interactive TTY when no key saved
320
322
  if (!process.stdin.isTTY || !process.stdout.isTTY) return;
321
323
  const hasKey = !!process.env.COMMIT_API_KEY || _cachedHasKey;
322
324
  if (hasKey) return;
323
325
  const critPkgs = results.filter(r => hasCritical(r.riskFlags));
324
326
  const lowScorePkgs = results.filter(r => typeof r.score === 'number' && r.score < 60);
325
- // Gate: ≥1 CRITICAL, OR ≥2 packages with score<60, OR large scan (≥50 packages)
326
- const shouldPrompt = critPkgs.length >= 1 || lowScorePkgs.length >= 2 || results.length >= 50;
327
- if (!shouldPrompt) return;
327
+ // Gate: ≥3 packages scanned (real audit, not a one-off `npx poc somepkg` check)
328
+ if (results.length < 3) return;
329
+
330
+ const hasFindings = critPkgs.length >= 1 || lowScorePkgs.length >= 2;
331
+ // Copy adapts to context. Findings → degradation framing.
332
+ // Healthy → baseline-lock framing (still real value: alert me if any score drops).
333
+ const heading = hasFindings
334
+ ? ' 🔔 Lock in this audit. Get alerted if these packages get worse.'
335
+ : ' 🔔 Lock in this baseline. Get alerted if any of these packages degrade.';
328
336
 
329
337
  console.log(clr(c.dim, ' ─────────────────────────────────────────────'));
330
- console.log(clr(c.bold, ' 🔔 Lock in this audit. Get alerts if these packages get worse.'));
338
+ console.log(clr(c.bold, heading));
331
339
  console.log(clr(c.dim, ' Free, no card, 10 seconds. Saves to ~/.commit/config.\n'));
332
340
 
333
341
  const { createInterface } = await import('readline');
@@ -366,8 +374,12 @@ async function inlineSignup(results) {
366
374
  console.log();
367
375
  console.log(clr(c.bold, ' Next steps:'));
368
376
  console.log(clr(c.dim, ' • ') + clr(c.cyan, 'poc status') + clr(c.dim, ' — check your account'));
369
- if (critPkgs.length > 0) {
370
- console.log(clr(c.dim, ' • ') + clr(c.cyan, `poc watch ${critPkgs[0].name}`) + clr(c.dim, ' — start monitoring (Pro)'));
377
+ // Surface a concrete watch target. CRITICAL first (highest urgency);
378
+ // otherwise pick the lowest-score package as the most-likely-to-degrade.
379
+ const watchTarget = critPkgs[0]?.name
380
+ || results.slice().sort((a, b) => (a.score || 100) - (b.score || 100))[0]?.name;
381
+ if (watchTarget) {
382
+ console.log(clr(c.dim, ' • ') + clr(c.cyan, `poc watch ${watchTarget}`) + clr(c.dim, ' — start monitoring (Developer $15/mo)'));
371
383
  }
372
384
  console.log(clr(c.dim, ' • ') + clr(c.cyan, 'poc init') + clr(c.dim, ' — add CI gate to this project'));
373
385
  } else if (data.message) {
@@ -384,7 +396,7 @@ async function inlineSignup(results) {
384
396
 
385
397
  function printHelp() {
386
398
  console.log(`
387
- ${clr(c.bold, 'proof-of-commitment')} v1.18.1 — supply chain risk scorer
399
+ ${clr(c.bold, 'proof-of-commitment')} v1.19.0 — supply chain risk scorer
388
400
 
389
401
  ${clr(c.bold, 'Usage:')}
390
402
  npx proof-of-commitment Auto-detect manifest in current dir
@@ -415,14 +427,14 @@ ${clr(c.bold, 'Account:')}
415
427
  poc status Show current tier, usage, and limits
416
428
  poc logout Remove saved API key
417
429
 
418
- ${clr(c.bold, 'Monitoring (Pro):')}
430
+ ${clr(c.bold, 'Monitoring (Developer $15/mo+):')}
419
431
  poc watch <package> [--ecosystem npm|pypi|cargo|golang]
420
432
  Add a package to daily monitoring
421
433
  poc watchlist List monitored packages with current scores + risk
422
434
  poc unwatch <pkg> Remove a package from monitoring
423
435
 
424
- Get a free key: https://getcommit.dev/get-started?utm_source=cli
425
- Upgrade to Pro: https://getcommit.dev/pricing
436
+ Get a free key: https://getcommit.dev/get-started?utm_source=cli
437
+ Enable monitoring: https://getcommit.dev/pricing?utm_source=cli&utm_campaign=help
426
438
 
427
439
  ${clr(c.bold, 'Options:')}
428
440
  --json Output results as JSON
@@ -965,13 +977,14 @@ async function cmdLogin(keyArg) {
965
977
  console.log(clr(c.dim, ` Saved to: ${configPath}`));
966
978
  console.log();
967
979
 
968
- if (info.tier === 'pro' || info.tier === 'enterprise') {
969
- console.log(clr(c.cyan, ' Pro features unlocked:'));
980
+ if (info.tier === 'developer' || info.tier === 'pro' || info.tier === 'enterprise') {
981
+ console.log(clr(c.cyan, ' Monitoring unlocked:'));
970
982
  console.log(clr(c.dim, ' poc watch <package> Add a package to daily monitoring'));
971
983
  console.log(clr(c.dim, ' poc watchlist View monitored packages'));
972
984
  console.log(clr(c.dim, ' poc unwatch <package> Remove from monitoring'));
973
985
  } else {
974
- console.log(clr(c.dim, ' Upgrade to Pro for monitoring + alerts: https://getcommit.dev/pricing?utm_source=cli'));
986
+ console.log(clr(c.dim, ' Enable monitoring + alerts on Developer ($15/mo):'));
987
+ console.log(clr(c.cyan, ' https://getcommit.dev/pricing?utm_source=cli&utm_campaign=post-login'));
975
988
  }
976
989
  console.log();
977
990
  }
@@ -1009,7 +1022,8 @@ async function cmdStatus() {
1009
1022
  if (info.tier === 'free') {
1010
1023
  const pct = info.requests_limit > 0 ? Math.round((info.requests_used / info.requests_limit) * 100) : 0;
1011
1024
  if (pct >= 80) {
1012
- console.log(clr(c.yellow, ` ⚠ ${pct}% of daily limit used. Upgrade for 10K/month: https://getcommit.dev/pricing`));
1025
+ console.log(clr(c.yellow, ` ⚠ ${pct}% of daily limit used. Developer ($15/mo) gets 10K/month + monitoring:`));
1026
+ console.log(clr(c.cyan, ` https://getcommit.dev/pricing?utm_source=cli&utm_campaign=status-limit`));
1013
1027
  }
1014
1028
  }
1015
1029
  }
@@ -1036,11 +1050,24 @@ function tierLabel(tier) {
1036
1050
 
1037
1051
  /**
1038
1052
  * Handle 402 upgrade response from watchlist endpoints.
1053
+ * Reads server response so the tier name, price, and URL stay authoritative
1054
+ * (server is canonical — CLI was historically out of date saying "Pro" when
1055
+ * "Developer" was the actual gate). Appends CLI UTM for attribution.
1039
1056
  */
1040
- function printUpgradeRequired() {
1041
- console.error(clr(c.yellow + c.bold, '\n ✦ Commit Pro required'));
1042
- console.error(clr(c.dim, ' Monitoring, daily scans, and alerts are Pro features.'));
1043
- console.error(clr(c.cyan, ' Upgrade at https://getcommit.dev/pricing\n'));
1057
+ async function printUpgradeRequired(res, campaign = 'watchlist-402') {
1058
+ let body = null;
1059
+ try { body = await res.json(); } catch {}
1060
+ const plan = (body && body.upgrade && body.upgrade.plan) || 'developer';
1061
+ const planLabel = plan.charAt(0).toUpperCase() + plan.slice(1);
1062
+ const price = (body && body.upgrade && body.upgrade.price) || '$15/month';
1063
+ const baseUrl = (body && body.upgrade && body.upgrade.url) || 'https://getcommit.dev/pricing';
1064
+ const url = baseUrl + (baseUrl.includes('?') ? '&' : '?') + `utm_source=cli&utm_campaign=${campaign}`;
1065
+ const currentTier = body && body.current_tier ? body.current_tier : 'free';
1066
+
1067
+ console.error(clr(c.yellow + c.bold, `\n ✦ ${planLabel} (${price}) required`));
1068
+ console.error(clr(c.dim, ` Monitoring, daily scans, and alerts start on ${planLabel}.`));
1069
+ console.error(clr(c.dim, ` Current tier: ${currentTier}`));
1070
+ console.error(clr(c.cyan, ` Upgrade at ${url}\n`));
1044
1071
  }
1045
1072
 
1046
1073
  /**
@@ -1061,7 +1088,7 @@ async function cmdWatch(pkg, ecosystem) {
1061
1088
  body: JSON.stringify({ package: pkg, ecosystem }),
1062
1089
  });
1063
1090
 
1064
- if (res.status === 402) { printUpgradeRequired(); process.exit(1); }
1091
+ if (res.status === 402) { process.stdout.write('\n'); await printUpgradeRequired(res, 'watch-cmd'); process.exit(1); }
1065
1092
 
1066
1093
  const data = await res.json();
1067
1094
  if (!res.ok) {
@@ -1093,7 +1120,7 @@ async function cmdWatchlist() {
1093
1120
  headers: { 'Authorization': `Bearer ${key}` },
1094
1121
  });
1095
1122
 
1096
- if (res.status === 402) { printUpgradeRequired(); process.exit(1); }
1123
+ if (res.status === 402) { await printUpgradeRequired(res, 'watchlist-cmd'); process.exit(1); }
1097
1124
 
1098
1125
  const data = await res.json();
1099
1126
  if (!res.ok) {
@@ -1132,7 +1159,7 @@ async function cmdWatchlist() {
1132
1159
  const divider = '─'.repeat(divWidth);
1133
1160
 
1134
1161
  console.log('\n' + divider);
1135
- console.log(clr(c.dim, ` Commit Pro watchlist · ${pkgs.length}/${data.limit} packages · tier: ${data.tier}`));
1162
+ console.log(clr(c.dim, ` Commit watchlist · ${pkgs.length}/${data.limit} packages · tier: ${data.tier}`));
1136
1163
  console.log(divider);
1137
1164
  console.log(header);
1138
1165
  console.log(divider);
@@ -1175,7 +1202,7 @@ async function cmdUnwatch(pkg, ecosystem) {
1175
1202
  body: JSON.stringify({ package: pkg, ecosystem }),
1176
1203
  });
1177
1204
 
1178
- if (res.status === 402) { printUpgradeRequired(); process.exit(1); }
1205
+ if (res.status === 402) { process.stdout.write('\n'); await printUpgradeRequired(res, 'unwatch-cmd'); process.exit(1); }
1179
1206
 
1180
1207
  const data = await res.json();
1181
1208
  if (!res.ok) {
@@ -1315,7 +1342,7 @@ ${rows}
1315
1342
  <div class="footer">
1316
1343
  <span>Generated by <a href="${WEB}" target="_blank">proof-of-commitment</a></span>
1317
1344
  <span><a href="https://github.com/piiiico/commit-action" target="_blank">GitHub Action</a></span>
1318
- <span><a href="https://getcommit.dev/pricing?utm_source=cli&amp;utm_medium=report" target="_blank">Commit Pro</a></span>
1345
+ <span><a href="https://getcommit.dev/pricing?utm_source=cli&amp;utm_medium=report" target="_blank">Enable monitoring</a></span>
1319
1346
  </div>
1320
1347
  <script>
1321
1348
  function copyMd() {
@@ -1573,9 +1600,11 @@ jobs:
1573
1600
  console.log(clr(c.white, ' 1. The badge updates daily with your project\'s score'));
1574
1601
  console.log(clr(c.white, ' 2. Push to trigger the existing workflow'));
1575
1602
  }
1576
- console.log(clr(c.dim, `\n Want daily monitoring + alerts? Get a free key:`));
1577
- console.log(clr(c.cyan, ' https://getcommit.dev/get-started?utm_source=cli'));
1578
- console.log(clr(c.dim, ' Then run: ') + clr(c.cyan, 'poc login') + clr(c.dim, ' + ') + clr(c.cyan, 'poc watch <package>\n'));
1603
+ console.log(clr(c.dim, `\n Want daily monitoring + alerts on your dependencies?`));
1604
+ console.log(clr(c.dim, ' 1. Free key (200 scans/day): ') + clr(c.cyan, 'https://getcommit.dev/get-started?utm_source=cli'));
1605
+ console.log(clr(c.dim, ' 2. Authenticate: ') + clr(c.cyan, 'poc login'));
1606
+ console.log(clr(c.dim, ' 3. Enable monitoring ($15/mo): ') + clr(c.cyan, 'https://getcommit.dev/pricing?utm_source=cli&utm_campaign=init'));
1607
+ console.log(clr(c.dim, ' 4. Watch a package: ') + clr(c.cyan, 'poc watch <package>\n'));
1579
1608
  }
1580
1609
 
1581
1610
  async function main() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "proof-of-commitment",
3
- "version": "1.18.1",
3
+ "version": "1.19.0",
4
4
  "mcpName": "io.github.piiiico/proof-of-commitment",
5
5
  "description": "Supply chain risk scorer for npm, PyPI, Cargo, and Go packages — behavioral signals that can't be faked",
6
6
  "type": "module",