shippingszn 0.9.2 → 0.9.4

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 +28 -20
  2. package/dist/index.js +65 -83
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -12,12 +12,13 @@ pnpm dlx shippingszn@latest
12
12
  ```
13
13
 
14
14
  The CLI **never writes, modifies, or deletes** any files - it only reads.
15
- Normal runs send one anonymous aggregate summary with score, severity counts,
16
- files scanned, scanner version, and safe stack tags. It never uploads source
17
- code, paths, filenames, repo URLs, project names, secrets, handles, or emails.
18
- This aggregate signal is automatic and not user-configurable.
15
+ Normal runs create a locked scan handoff for checkout and send one anonymous
16
+ Wall report-card summary with score, severity counts, files scanned, scanner
17
+ version, and safe stack tags. It never uploads source code, repo URLs, project
18
+ names, secrets, handles, or emails. Finding-level detail stays out of public
19
+ CLI/Wall output and opens inside the paid Launch Fix Kit.
19
20
 
20
- Human output starts with a Launch Readiness Score, scope covered, and severity
21
+ Human output starts with a Launch Debt Score, completed checks, and severity
21
22
  counts. Run with `--json` to get the same score-and-counts summary in a
22
23
  machine-readable shape:
23
24
 
@@ -27,8 +28,14 @@ machine-readable shape:
27
28
  "band": "no_go",
28
29
  "counts": { "critical": 1, "high": 3, "medium": 4, "lower": 2 },
29
30
  "filesScanned": 128,
31
+ "coverage": { "checksCompleted": 19, "checklistAreas": 46 },
30
32
  "detailsLocked": true,
31
- "unlockUrl": "https://shippingszn.com/fix-kit"
33
+ "unlockUrl": "https://shippingszn.com/fix-kit?scanResultId=00000000-0000-4000-8000-000000000123",
34
+ "scanHandoff": {
35
+ "status": "uploaded",
36
+ "resultId": "00000000-0000-4000-8000-000000000123",
37
+ "unlockUrl": "https://shippingszn.com/fix-kit?scanResultId=00000000-0000-4000-8000-000000000123"
38
+ }
32
39
  }
33
40
  ```
34
41
 
@@ -37,14 +44,14 @@ They unlock inside the Launch Fix Kit.
37
44
 
38
45
  ## Aggregate summary
39
46
 
40
- Plain `npx shippingszn@latest` sends the aggregate summary automatically. The
41
- stored row is anonymous and intentionally small: score, launch label, files
42
- scanned, finding counts, detected stack tags, scanner version, and timestamp.
47
+ Plain `npx shippingszn@latest` sends the Wall summary automatically. The stored
48
+ row is anonymous and intentionally small: score, launch label, files scanned,
49
+ finding counts by severity, detected stack tags, scanner version, and timestamp.
43
50
 
44
- For a scan-specific paid-report handoff, run `npx shippingszn@latest --proof`.
45
- That uploads the canonical scan result, returns a proof URL plus a
46
- `/fix-kit?scanResultId=...` URL, and gives the paid Launch Fix Kit the evidence
47
- it needs after checkout.
51
+ The same run also creates a scan-specific paid-report handoff. The terminal
52
+ prints a `/fix-kit?scanResultId=...` URL so checkout can carry that scan into
53
+ the Launch Fix Kit after purchase. `--proof` is still accepted for old docs, but
54
+ it is no longer required.
48
55
 
49
56
  ## What gets checked
50
57
 
@@ -123,8 +130,8 @@ shippingszn [path] [options]
123
130
 
124
131
  Options:
125
132
  --json Output a machine-readable JSON summary.
126
- --proof Upload full scan evidence and return a scan-specific
127
- Launch Fix Kit URL.
133
+ --proof Backward-compatible alias. Normal runs already return
134
+ a scan-specific Launch Fix Kit URL.
128
135
  --base-url <url> Base URL used to build checkout and Fix Kit links.
129
136
  --cwd <path> Directory to scan. Default: current working directory.
130
137
  --no-color Disable ANSI colors in the human-readable summary.
@@ -151,11 +158,12 @@ summary as a comment: score, severity counts, and unlock URL.
151
158
  ## Privacy
152
159
 
153
160
  `shippingszn` reads files on your machine. It never uploads source code. By
154
- default it makes one best-effort outbound request to post an anonymous aggregate
155
- summary: score, launch label, files scanned count, finding counts by severity,
156
- detected stack tags, scanner version, and timestamp. It never uploads source
157
- code, file paths, filenames, project names, repo URLs, secrets, emails, handles,
158
- or report contents. The aggregate summary is automatic and not user-configurable.
161
+ default it creates a locked scan handoff for checkout and makes one best-effort
162
+ outbound request to post anonymous Wall stats: score, launch label, files
163
+ scanned count, finding counts by severity, detected stack tags, scanner version,
164
+ and timestamp. Wall stats never include source code, file paths, filenames,
165
+ project names, repo URLs, secrets, emails, handles, finding titles, evidence, or
166
+ report contents. The Wall summary is automatic and not user-configurable.
159
167
 
160
168
  ## License
161
169
 
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/index.ts
4
- import * as path19 from "node:path";
5
- import * as process2 from "node:process";
4
+ import * as path18 from "node:path";
5
+ import * as process from "node:process";
6
6
  import { createRequire } from "node:module";
7
7
 
8
8
  // src/checks/secrets.ts
@@ -3685,13 +3685,8 @@ async function publishScan(totals, filesScanned, opts) {
3685
3685
  }
3686
3686
 
3687
3687
  // src/proof.ts
3688
- import * as path18 from "node:path";
3689
3688
  var PROOF_TIMEOUT_MS = 5e3;
3690
3689
  var MAX_FINDINGS = 100;
3691
- function shouldUploadProof() {
3692
- const v = process.env["SHIPPINGSZN_PROOF"] ?? "";
3693
- return v === "1" || v.toLowerCase() === "true" || v === "yes";
3694
- }
3695
3690
  function clampText(value, max, fallback = "") {
3696
3691
  const text = value ?? fallback;
3697
3692
  return text.length > max ? text.slice(0, max - 3) + "..." : text;
@@ -3705,8 +3700,8 @@ function buildBadgeMarkdown(baseUrl, id, score) {
3705
3700
  scanResultId: id,
3706
3701
  theme: "dark"
3707
3702
  });
3708
- const proofUrl = `${baseUrl}/proof/${encodeURIComponent(id)}`;
3709
- return `[![shippingszn scan proof: ${score}%](${baseUrl}/api/badge.svg?${params.toString()})](${proofUrl})`;
3703
+ const fixKitUrl = `${baseUrl}/fix-kit?${new URLSearchParams({ scanResultId: id }).toString()}`;
3704
+ return `[![shippingszn scan score: ${score}%](${baseUrl}/api/badge.svg?${params.toString()})](${fixKitUrl})`;
3710
3705
  }
3711
3706
  function buildProofPayload(report, scannerVersion) {
3712
3707
  const counts = {
@@ -3719,7 +3714,7 @@ function buildProofPayload(report, scannerVersion) {
3719
3714
  version: 1,
3720
3715
  source: report.source ?? "cli",
3721
3716
  scanner: "shippingszn",
3722
- targetName: path18.basename(report.cwd) || "CLI scan",
3717
+ targetName: "Anonymous CLI scan",
3723
3718
  score: report.launchReadiness.score,
3724
3719
  label: report.launchReadiness.label,
3725
3720
  decision: report.launchReadiness.decision,
@@ -4376,13 +4371,13 @@ var PKG_VERSION = (() => {
4376
4371
  })();
4377
4372
  function parseArgs(argv2) {
4378
4373
  const opts = {
4379
- cwd: process2.cwd(),
4374
+ cwd: process.cwd(),
4380
4375
  json: false,
4381
- baseUrl: process2.env.SHIPPINGSZN_BASE_URL ?? process2.env.VIBE_LAUNCH_CHECK_BASE_URL ?? DEFAULT_BASE_URL2,
4376
+ baseUrl: process.env.SHIPPINGSZN_BASE_URL ?? process.env.VIBE_LAUNCH_CHECK_BASE_URL ?? DEFAULT_BASE_URL2,
4382
4377
  help: false,
4383
4378
  version: false,
4384
- noColor: !!process2.env.NO_COLOR,
4385
- proof: shouldUploadProof()
4379
+ noColor: !!process.env.NO_COLOR,
4380
+ proof: true
4386
4381
  };
4387
4382
  for (let i = 0; i < argv2.length; i++) {
4388
4383
  const a = argv2[i];
@@ -4394,8 +4389,8 @@ function parseArgs(argv2) {
4394
4389
  else if (a === "--no-publish" || a === "--publish")
4395
4390
  opts.unsupportedWallFlag = a;
4396
4391
  else if (a === "--base-url") opts.baseUrl = argv2[++i] ?? opts.baseUrl;
4397
- else if (a === "--cwd") opts.cwd = path19.resolve(argv2[++i] ?? opts.cwd);
4398
- else if (!a.startsWith("-")) opts.cwd = path19.resolve(a);
4392
+ else if (a === "--cwd") opts.cwd = path18.resolve(argv2[++i] ?? opts.cwd);
4393
+ else if (!a.startsWith("-")) opts.cwd = path18.resolve(a);
4399
4394
  }
4400
4395
  return opts;
4401
4396
  }
@@ -4415,7 +4410,7 @@ function color(enabled) {
4415
4410
  }
4416
4411
  var SEVERITY_ORDER = ["critical", "high", "medium", "lower"];
4417
4412
  function printHelp() {
4418
- process2.stdout.write(
4413
+ process.stdout.write(
4419
4414
  `shippingszn v${PKG_VERSION}
4420
4415
 
4421
4416
  Read-only scanner that checks the current project against a small set of
@@ -4426,8 +4421,8 @@ Usage:
4426
4421
 
4427
4422
  Options:
4428
4423
  --json Output a machine-readable JSON summary.
4429
- --proof Upload full scan evidence and return a scan-specific
4430
- Launch Fix Kit URL.
4424
+ --proof Backward-compatible alias. Normal runs already return
4425
+ a scan-specific Launch Fix Kit URL.
4431
4426
  --base-url <url> Base URL used to build checkout and Fix Kit links.
4432
4427
  (default: ${DEFAULT_BASE_URL2})
4433
4428
  --cwd <path> Directory to scan. Default: current working directory.
@@ -4438,35 +4433,36 @@ Options:
4438
4433
  This is the FREE preflight. It tells you launch debt exists. It does NOT tell
4439
4434
  you what's broken or how to fix it \u2014 that's gated behind the $49 Launch Fix Kit
4440
4435
  (unlocks full findings + 46-item workbook + paste-ready AI-builder prompts +
4441
- verification steps + red-flag checks). Read-only on disk. Anonymous aggregate
4442
- counts (score, severity counts, file count, scanner version \u2014 no project name,
4443
- no paths, no findings) are sent on every normal run; there is no publish opt-in
4444
- or opt-out flag. Exit code non-zero if any critical findings.
4436
+ verification steps + red-flag checks). Read-only on disk. Normal runs create a
4437
+ locked scan handoff for checkout and send anonymous Wall stats (score, severity
4438
+ counts, file count, scanner version \u2014 no project name, no paths, no
4439
+ finding-level detail); there is no Wall publish opt-in or opt-out flag. Exit
4440
+ code non-zero if any critical findings.
4445
4441
  `
4446
4442
  );
4447
4443
  }
4448
4444
  function scanSource() {
4449
- return process2.env.GITHUB_ACTIONS === "true" ? "github" : "cli";
4445
+ return process.env.GITHUB_ACTIONS === "true" ? "github" : "cli";
4450
4446
  }
4451
4447
  async function run() {
4452
- const opts = parseArgs(process2.argv.slice(2));
4448
+ const opts = parseArgs(process.argv.slice(2));
4453
4449
  if (opts.help) {
4454
4450
  printHelp();
4455
4451
  return 0;
4456
4452
  }
4457
4453
  if (opts.version) {
4458
- process2.stdout.write(`${PKG_VERSION}
4454
+ process.stdout.write(`${PKG_VERSION}
4459
4455
  `);
4460
4456
  return 0;
4461
4457
  }
4462
4458
  if (opts.unsupportedWallFlag) {
4463
- process2.stderr.write(
4464
- `${opts.unsupportedWallFlag} is not supported. shippingszn sends anonymous score and severity counts on normal runs; it never uploads code, file paths, findings, project names, repo URLs, secrets, emails, or handles.
4459
+ process.stderr.write(
4460
+ `${opts.unsupportedWallFlag} is not supported. shippingszn sends anonymous Wall stats on normal runs: score, severity counts, file count, scanner version, and safe stack tags. It never uploads code, file paths, finding-level details, project names, repo URLs, secrets, emails, or handles.
4465
4461
  `
4466
4462
  );
4467
4463
  return 2;
4468
4464
  }
4469
- const c = color(!opts.noColor && process2.stdout.isTTY === true && !opts.json);
4465
+ const c = color(!opts.noColor && process.stdout.isTTY === true && !opts.json);
4470
4466
  const files = await listFiles(opts.cwd);
4471
4467
  const tracked = getTrackedFiles(opts.cwd);
4472
4468
  const ctx = { rootDir: opts.cwd, files };
@@ -4489,7 +4485,7 @@ async function run() {
4489
4485
  const fixKitUrl = `${trimmedBaseUrl}/fix-kit`;
4490
4486
  const reportUrl = fixKitUrl;
4491
4487
  const proofCreatePath = `${trimmedBaseUrl}/scan`;
4492
- const proofUploadHint = "Run `npx shippingszn@latest --proof` to generate a scan-specific Launch Fix Kit URL.";
4488
+ const proofUploadHint = "Normal runs automatically generate a scan-specific Launch Fix Kit URL.";
4493
4489
  const tracked_aware = applyTrackingAwareSeverity(all, tracked);
4494
4490
  const source = scanSource();
4495
4491
  const enriched = tracked_aware.map((f) => {
@@ -4635,9 +4631,6 @@ async function run() {
4635
4631
  const automatedAreas = CHECKLIST.filter(
4636
4632
  (item) => item.cliCoverage === "automated"
4637
4633
  ).length;
4638
- const ownerVerifyAreas = CHECKLIST.filter(
4639
- (item) => item.cliCoverage === "manual_only"
4640
- ).length;
4641
4634
  const SCORE_BAND_LABEL = {
4642
4635
  blocked: "NO-GO",
4643
4636
  fix_first: "FIX FIRST",
@@ -4668,9 +4661,8 @@ async function run() {
4668
4661
  counts: { ...totals },
4669
4662
  filesScanned: files.length,
4670
4663
  coverage: {
4671
- automatedAreas,
4672
- ownerVerifyAreas,
4673
- totalAreas: CHECKLIST.length
4664
+ checksCompleted: automatedAreas,
4665
+ checklistAreas: CHECKLIST.length
4674
4666
  },
4675
4667
  scannerVersion: PKG_VERSION,
4676
4668
  detailsLocked: true,
@@ -4680,113 +4672,103 @@ async function run() {
4680
4672
  ...wallUrl ? { url: wallUrl } : {},
4681
4673
  ...wallError ? { error: wallError } : {}
4682
4674
  },
4683
- proof: {
4675
+ scanHandoff: {
4684
4676
  status: proofResult.status,
4685
4677
  ...proofResult.status === "uploaded" ? {
4686
- url: proofResult.proofUrl,
4687
4678
  resultId: proofResult.id,
4688
- reportUrl: proofResult.reportUrl
4679
+ unlockUrl: proofResult.reportUrl
4689
4680
  } : {},
4690
4681
  ...proofResult.status === "failed" && proofResult.error ? { error: proofResult.error } : {}
4691
4682
  }
4692
4683
  };
4693
- process2.stdout.write(JSON.stringify(scoreSummary, null, 2) + "\n");
4684
+ process.stdout.write(JSON.stringify(scoreSummary, null, 2) + "\n");
4694
4685
  return totals.critical > 0 ? 1 : 0;
4695
4686
  }
4696
4687
  const bandColor = band === "no_go" ? c.red : band === "fix_first" ? c.yellow : band === "verify_before_launch" ? c.blue : c.green;
4697
- process2.stdout.write(
4688
+ process.stdout.write(
4698
4689
  `
4699
4690
  ${c.bold("shippingszn")} ${c.dim(`v${PKG_VERSION}`)}
4700
4691
  `
4701
4692
  );
4702
- process2.stdout.write(c.dim(`Scanned ${files.length} files.
4693
+ process.stdout.write(c.dim(`Scanned ${files.length} files.
4703
4694
 
4704
4695
  `));
4705
- process2.stdout.write(
4696
+ process.stdout.write(
4706
4697
  `${c.bold("Launch Debt Score:")} ${launchReadiness.score}/100 \u2014 ${bandColor(c.bold(bandLabel))}
4707
4698
 
4708
4699
  `
4709
4700
  );
4710
- process2.stdout.write(`${c.bold("Findings detected:")}
4701
+ process.stdout.write(`${c.bold("Findings detected:")}
4711
4702
  `);
4712
- process2.stdout.write(` ${c.red(`${totals.critical} critical`)}
4703
+ process.stdout.write(` ${c.red(`${totals.critical} critical`)}
4713
4704
  `);
4714
- process2.stdout.write(` ${c.yellow(`${totals.high} high`)}
4705
+ process.stdout.write(` ${c.yellow(`${totals.high} high`)}
4715
4706
  `);
4716
- process2.stdout.write(` ${c.blue(`${totals.medium} medium`)}
4707
+ process.stdout.write(` ${c.blue(`${totals.medium} medium`)}
4717
4708
  `);
4718
- process2.stdout.write(` ${c.gray(`${totals.lower} lower`)}
4709
+ process.stdout.write(` ${c.gray(`${totals.lower} lower`)}
4719
4710
 
4720
4711
  `);
4721
- process2.stdout.write(`${c.bold("Coverage:")}
4712
+ process.stdout.write(`${c.bold("Coverage:")}
4722
4713
  `);
4723
- process2.stdout.write(
4724
- c.dim(
4725
- ` ${automatedAreas} of ${CHECKLIST.length} launch-readiness areas checked by the scanner
4726
- `
4727
- )
4728
- );
4729
- process2.stdout.write(
4730
- c.dim(` ${ownerVerifyAreas} require owner verification
4714
+ process.stdout.write(
4715
+ c.dim(` ${automatedAreas} launch-readiness checks completed
4731
4716
 
4732
4717
  `)
4733
4718
  );
4734
4719
  if (totals.critical + totals.high + totals.medium + totals.lower > 0) {
4735
4720
  if (scanSpecificUnlockUrl) {
4736
- process2.stdout.write(c.bold("Unlock this exact scan:\n"));
4737
- process2.stdout.write(` ${c.cyan(scanSpecificUnlockUrl)}
4721
+ process.stdout.write(c.bold("Unlock this exact scan:\n"));
4722
+ process.stdout.write(` ${c.cyan(scanSpecificUnlockUrl)}
4738
4723
  `);
4739
- process2.stdout.write(
4724
+ process.stdout.write(
4740
4725
  c.dim(
4741
4726
  " Full findings, file evidence, and AI-builder prompts stay locked until purchase.\n\n"
4742
4727
  )
4743
4728
  );
4744
4729
  } else {
4745
- process2.stdout.write(c.bold("Full findings are locked:\n"));
4746
- process2.stdout.write(` ${c.cyan(fixKitUrl)}
4730
+ process.stdout.write(c.bold("Full findings are locked:\n"));
4731
+ process.stdout.write(` ${c.cyan(fixKitUrl)}
4747
4732
  `);
4748
- process2.stdout.write(
4733
+ process.stdout.write(
4749
4734
  c.dim(
4750
- " For a scan-specific Fix Kit link, rerun: npx shippingszn@latest --proof\n\n"
4735
+ " This run could not attach scan evidence. The full report stays locked until purchase.\n\n"
4751
4736
  )
4752
4737
  );
4753
4738
  }
4754
4739
  } else {
4755
4740
  if (scanSpecificUnlockUrl) {
4756
- process2.stdout.write(
4741
+ process.stdout.write(
4757
4742
  c.green("No automated findings detected for this scan.\n")
4758
4743
  );
4759
- process2.stdout.write(c.bold("Unlock the owner-verification Fix Kit:\n"));
4760
- process2.stdout.write(` ${c.cyan(scanSpecificUnlockUrl)}
4744
+ process.stdout.write(c.bold("Unlock this exact scan:\n"));
4745
+ process.stdout.write(` ${c.cyan(scanSpecificUnlockUrl)}
4761
4746
 
4762
4747
  `);
4763
4748
  } else {
4764
- process2.stdout.write(
4749
+ process.stdout.write(
4765
4750
  c.green(
4766
- "No automated findings detected. The Launch Fix Kit covers the 27 owner-verify areas the scanner can't reach:\n"
4751
+ "No automated findings detected. Unlock the Launch Fix Kit for the full checklist and written launch report:\n"
4767
4752
  )
4768
4753
  );
4769
- process2.stdout.write(` ${c.cyan(fixKitUrl)}
4754
+ process.stdout.write(` ${c.cyan(fixKitUrl)}
4770
4755
  `);
4771
- process2.stdout.write(
4756
+ process.stdout.write(
4772
4757
  c.dim(
4773
- " For a scan-specific Fix Kit link, rerun: npx shippingszn@latest --proof\n\n"
4758
+ " This run could not attach scan evidence. The full report stays locked until purchase.\n\n"
4774
4759
  )
4775
4760
  );
4776
4761
  }
4777
4762
  }
4778
- if (proofResult.status === "uploaded" && proofResult.proofUrl) {
4779
- process2.stdout.write(c.dim(`Share score proof: ${proofResult.proofUrl}
4780
- `));
4781
- } else if (proofResult.status === "failed") {
4782
- process2.stdout.write(
4783
- c.dim(`(Proof upload failed: ${proofResult.error ?? "unknown"})
4763
+ if (proofResult.status === "failed") {
4764
+ process.stdout.write(
4765
+ c.dim(`(Scan handoff failed: ${proofResult.error ?? "unknown"})
4784
4766
  `)
4785
4767
  );
4786
4768
  }
4787
4769
  if (publishResult === "published") {
4788
- process2.stdout.write(
4789
- c.dim("(Anonymous aggregate score sent to shippingszn.)\n")
4770
+ process.stdout.write(
4771
+ c.dim("(Anonymous Wall stats sent: score + severity counts.)\n")
4790
4772
  );
4791
4773
  }
4792
4774
  if (totals.critical > 0) {
@@ -4795,12 +4777,12 @@ ${c.bold("shippingszn")} ${c.dim(`v${PKG_VERSION}`)}
4795
4777
  return 0;
4796
4778
  }
4797
4779
  run().then(
4798
- (code) => process2.exit(code),
4780
+ (code) => process.exit(code),
4799
4781
  (err) => {
4800
- process2.stderr.write(
4782
+ process.stderr.write(
4801
4783
  `shippingszn failed: ${err instanceof Error ? err.message : String(err)}
4802
4784
  `
4803
4785
  );
4804
- process2.exit(2);
4786
+ process.exit(2);
4805
4787
  }
4806
4788
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shippingszn",
3
- "version": "0.9.2",
3
+ "version": "0.9.4",
4
4
  "description": "Read-only CLI scanner that checks a project for common pre-launch issues from the shippingszn.com launch checklist.",
5
5
  "license": "MIT",
6
6
  "type": "module",