proof-of-commitment 1.12.0 → 1.13.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 (2) hide show
  1. package/index.js +92 -8
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * proof-of-commitment CLI v1.12.0
3
+ * proof-of-commitment CLI v1.13.0
4
4
  * Scores npm/PyPI/Cargo/Go packages on behavioral commitment signals.
5
5
  * Usage: npx proof-of-commitment [packages...] [options]
6
6
  */
@@ -180,10 +180,23 @@ function printTable(results, { totalScanned, totalCritical, lockfile } = {}) {
180
180
 
181
181
  // Footer with web link + CI integration CTA
182
182
  const topPkgs = results.slice(0, 10).map(r => r.name).join(',');
183
- console.log(clr(c.cyan, `\n 🔗 Full report: ${WEB}?packages=${encodeURIComponent(topPkgs)}`));
183
+ const utm = 'utm_source=cli&utm_medium=audit';
184
+ console.log(clr(c.cyan, `\n 🔗 Full report: ${WEB}?packages=${encodeURIComponent(topPkgs)}&${utm}`));
184
185
  console.log(clr(c.cyan, ` 🤖 GitHub Action: github.com/piiiico/commit-action — block CRITICAL packages in CI`));
185
186
  console.log(clr(c.dim, ` 📋 Add to this project: `) + clr(c.cyan, `poc init`) + clr(c.dim, ` — creates workflow + README badge`));
186
187
 
188
+ // Per-package profile URLs — drive traffic to permanent, indexable pages
189
+ const ecoPath = { npm: 'npm', pypi: 'pypi', cargo: 'cargo', golang: 'go' };
190
+ const profilePkgs = results.slice(0, 5).filter(r => r.name && ecoPath[r.ecosystem || 'npm']);
191
+ if (profilePkgs.length > 0) {
192
+ console.log(clr(c.dim, `\n 📄 Package profiles:`));
193
+ for (const r of profilePkgs) {
194
+ const eco = ecoPath[r.ecosystem || 'npm'];
195
+ const name = encodeURIComponent(r.name).replace(/%40/g, '@').replace(/%2F/g, '/');
196
+ console.log(clr(c.dim, ` getcommit.dev/${eco}/${name}`));
197
+ }
198
+ }
199
+
187
200
  // Contextual upsell — show when findings make monitoring relevant
188
201
  if (effectiveCritical > 0) {
189
202
  // Check for API key synchronously via env (fast path)
@@ -193,16 +206,85 @@ function printTable(results, { totalScanned, totalCritical, lockfile } = {}) {
193
206
  clr(c.cyan, `poc watch ${results.find(r => hasCritical(r.riskFlags))?.name || results[0]?.name}`));
194
207
  } else {
195
208
  console.log(clr(c.dim, `\n 📊 Monitor ${effectiveCritical === 1 ? 'this' : 'these ' + effectiveCritical} CRITICAL ${effectiveCritical === 1 ? 'package' : 'packages'} — get alerted when scores change.`));
196
- console.log(clr(c.dim, ' Get a free API key: ') + clr(c.cyan, 'https://getcommit.dev/get-started'));
209
+ console.log(clr(c.dim, ' Get a free API key: ') + clr(c.cyan, 'https://getcommit.dev/get-started?utm_source=cli'));
197
210
  console.log(clr(c.dim, ' Then run: ') + clr(c.cyan, 'poc login'));
198
211
  }
199
212
  }
200
213
  console.log();
201
214
  }
202
215
 
216
+ /**
217
+ * Inline signup: after CRITICAL findings, offer one-step email→key flow.
218
+ * Collapses 6-step funnel (visit site → email → check inbox → copy key → login → watch)
219
+ * into a single CLI prompt.
220
+ */
221
+ async function inlineSignup(results) {
222
+ // Only prompt in interactive TTY when CRITICAL packages found and no key saved
223
+ if (!process.stdin.isTTY || !process.stdout.isTTY) return;
224
+ const hasKey = !!process.env.COMMIT_API_KEY || _cachedHasKey;
225
+ if (hasKey) return;
226
+ const critPkgs = results.filter(r => hasCritical(r.riskFlags));
227
+ if (critPkgs.length === 0) return;
228
+
229
+ console.log(clr(c.dim, ' ─────────────────────────────────────────────'));
230
+ console.log(clr(c.bold, ' 🔔 Get alerts when these scores change?'));
231
+ console.log(clr(c.dim, ' Free API key — no credit card, 10 seconds.\n'));
232
+
233
+ const { createInterface } = await import('readline');
234
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
235
+
236
+ const email = await new Promise(resolve => {
237
+ rl.question(clr(c.dim, ' Your email (Enter to skip): '), answer => {
238
+ rl.close();
239
+ resolve(answer.trim());
240
+ });
241
+ });
242
+
243
+ if (!email) return;
244
+
245
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
246
+ console.log(clr(c.red, ' Invalid email. Skipped.'));
247
+ return;
248
+ }
249
+
250
+ process.stdout.write(clr(c.dim, ' Creating key...'));
251
+
252
+ try {
253
+ const res = await fetch('https://poc-backend.amdal-dev.workers.dev/api/keys/create', {
254
+ method: 'POST',
255
+ headers: { 'Content-Type': 'application/json' },
256
+ body: JSON.stringify({ email, source: 'cli' }),
257
+ });
258
+
259
+ const data = await res.json();
260
+
261
+ if (data.key) {
262
+ await writeApiKey(data.key);
263
+ _cachedHasKey = true;
264
+ console.log(clr(c.green, ' ✓ Saved to ~/.commit/config'));
265
+ console.log(clr(c.dim, ` Backup sent to ${email}`));
266
+ console.log();
267
+ console.log(clr(c.bold, ' Next steps:'));
268
+ console.log(clr(c.dim, ' • ') + clr(c.cyan, 'poc status') + clr(c.dim, ' — check your account'));
269
+ if (critPkgs.length > 0) {
270
+ console.log(clr(c.dim, ' • ') + clr(c.cyan, `poc watch ${critPkgs[0].name}`) + clr(c.dim, ' — start monitoring (Pro)'));
271
+ }
272
+ console.log(clr(c.dim, ' • ') + clr(c.cyan, 'poc init') + clr(c.dim, ' — add CI gate to this project'));
273
+ } else if (data.message) {
274
+ console.log(clr(c.green, ` ✓ ${data.message}`));
275
+ } else {
276
+ console.log(clr(c.red, ` Failed: ${JSON.stringify(data)}`));
277
+ }
278
+ } catch (err) {
279
+ console.log(clr(c.red, ` Error: ${err.message}`));
280
+ }
281
+
282
+ console.log();
283
+ }
284
+
203
285
  function printHelp() {
204
286
  console.log(`
205
- ${clr(c.bold, 'proof-of-commitment')} v1.12.0 — supply chain risk scorer
287
+ ${clr(c.bold, 'proof-of-commitment')} v1.13.0 — supply chain risk scorer
206
288
 
207
289
  ${clr(c.bold, 'Usage:')}
208
290
  npx proof-of-commitment Auto-detect manifest in current dir
@@ -785,7 +867,7 @@ async function cmdLogin(keyArg) {
785
867
  console.log(clr(c.dim, ' poc watchlist View monitored packages'));
786
868
  console.log(clr(c.dim, ' poc unwatch <package> Remove from monitoring'));
787
869
  } else {
788
- console.log(clr(c.dim, ' Upgrade to Pro for monitoring + alerts: https://getcommit.dev/pricing'));
870
+ console.log(clr(c.dim, ' Upgrade to Pro for monitoring + alerts: https://getcommit.dev/pricing?utm_source=cli'));
789
871
  }
790
872
  console.log();
791
873
  }
@@ -864,7 +946,7 @@ async function cmdWatch(pkg, ecosystem) {
864
946
  const key = await readApiKey();
865
947
  if (!key) {
866
948
  console.error(clr(c.red, 'No API key found. Set COMMIT_API_KEY or add api_key=<key> to ~/.commit/config'));
867
- console.error(clr(c.dim, 'Get a key at https://getcommit.dev/pricing'));
949
+ console.error(clr(c.dim, 'Get a key at https://getcommit.dev/pricing?utm_source=cli'));
868
950
  process.exit(1);
869
951
  }
870
952
 
@@ -1129,7 +1211,7 @@ ${rows}
1129
1211
  <div class="footer">
1130
1212
  <span>Generated by <a href="${WEB}" target="_blank">proof-of-commitment</a></span>
1131
1213
  <span><a href="https://github.com/piiiico/commit-action" target="_blank">GitHub Action</a></span>
1132
- <span><a href="https://getcommit.dev/pricing" target="_blank">Commit Pro</a></span>
1214
+ <span><a href="https://getcommit.dev/pricing?utm_source=cli&amp;utm_medium=report" target="_blank">Commit Pro</a></span>
1133
1215
  </div>
1134
1216
  <script>
1135
1217
  function copyMd() {
@@ -1385,7 +1467,7 @@ jobs:
1385
1467
  console.log(clr(c.white, ' 2. Push to trigger the existing workflow'));
1386
1468
  }
1387
1469
  console.log(clr(c.dim, `\n Want daily monitoring + alerts? Get a free key:`));
1388
- console.log(clr(c.cyan, ' https://getcommit.dev/get-started'));
1470
+ console.log(clr(c.cyan, ' https://getcommit.dev/get-started?utm_source=cli'));
1389
1471
  console.log(clr(c.dim, ' Then run: ') + clr(c.cyan, 'poc login') + clr(c.dim, ' + ') + clr(c.cyan, 'poc watch <package>\n'));
1390
1472
  }
1391
1473
 
@@ -1654,6 +1736,7 @@ async function main() {
1654
1736
  const displayed = allResults.slice(0, MAX_DISPLAY);
1655
1737
  const criticalTotal = allResults.filter(r => hasCritical(r.riskFlags)).length;
1656
1738
  printTable(displayed, { totalScanned: allResults.length, totalCritical: criticalTotal, lockfile: true });
1739
+ await inlineSignup(displayed);
1657
1740
  if (shouldFail(allResults, failOn)) {
1658
1741
  console.error(clr(c.red + c.bold, `\n✗ --fail-on=${failOn} threshold met. Exit 1.`));
1659
1742
  process.exit(1);
@@ -1684,6 +1767,7 @@ async function main() {
1684
1767
  }
1685
1768
 
1686
1769
  printTable(allResults);
1770
+ await inlineSignup(allResults);
1687
1771
  if (shouldFail(allResults, failOn)) {
1688
1772
  console.error(clr(c.red + c.bold, `✗ --fail-on=${failOn} threshold met. Exit 1.`));
1689
1773
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "proof-of-commitment",
3
- "version": "1.12.0",
3
+ "version": "1.13.0",
4
4
  "description": "Supply chain risk scorer for npm, PyPI, Cargo, and Go packages — behavioral signals that can't be faked",
5
5
  "type": "module",
6
6
  "bin": {