@reshotdev/screenshot 0.0.1-beta.16 → 0.0.1-beta.17

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reshotdev/screenshot",
3
- "version": "0.0.1-beta.16",
3
+ "version": "0.0.1-beta.17",
4
4
  "description": "Screenshot and video capture CLI",
5
5
  "author": "Reshot <hello@reshot.dev>",
6
6
  "license": "MIT",
@@ -179,7 +179,9 @@ async function authCommand(options = {}) {
179
179
  try {
180
180
  const apiBaseUrl = options.apiBaseUrl || getApiBaseUrl();
181
181
  const verified = await verifyApiKeyFn(apiBaseUrl, envApiKey, httpClient);
182
- projectName = verified?.project?.name || null;
182
+ // /auth/cli/verify wraps its payload in an { data: … } envelope.
183
+ const payload = verified?.data || verified;
184
+ projectName = payload?.project?.name || null;
183
185
  } catch {
184
186
  // Verification is best-effort here; keep going without the name.
185
187
  }
@@ -666,6 +666,7 @@ async function publishWithTransactionalFlow(
666
666
  let successCount = 0;
667
667
  let failCount = 0;
668
668
  let skippedCount = 0;
669
+ let reviewPendingCount = 0;
669
670
  let viewUrl = null;
670
671
 
671
672
  // Flatten all assets with metadata
@@ -878,7 +879,16 @@ async function publishWithTransactionalFlow(
878
879
  contentType: file.contentType,
879
880
  });
880
881
 
881
- console.log(chalk.green(` ✔ Uploaded ${file.visualKey}`));
882
+ // Label the artifact type so PNG + MHTML-sidecar lines for the same
883
+ // visual don't read as a duplicate-upload bug (audit run-10 F3).
884
+ const artifactLabel = file._isThumbnail
885
+ ? "thumbnail"
886
+ : file._isDomScene
887
+ ? "dom scene .mhtml"
888
+ : (path.extname(file.path || "").replace(/^\./, "") || "asset");
889
+ console.log(
890
+ chalk.green(` ✔ Uploaded ${file.visualKey} (${artifactLabel})`),
891
+ );
882
892
  return { success: true, file, s3Path: urlInfo.path };
883
893
  } catch (err) {
884
894
  console.log(
@@ -1008,6 +1018,10 @@ async function publishWithTransactionalFlow(
1008
1018
  // Unwrap API envelope: response may be { data: { results, ... } } or { results, ... }
1009
1019
  const batchResult = rawBatchResult.data || rawBatchResult;
1010
1020
 
1021
+ // Count only NEWLY-pending (new/changed) captures, so the final summary
1022
+ // doesn't imply a re-publish reset already-live captures (audit F1).
1023
+ reviewPendingCount += batchResult.reviewQueueItems || 0;
1024
+
1011
1025
  for (const r of batchResult.results || []) {
1012
1026
  if (r.status === "ok") {
1013
1027
  const count = r.assetsProcessed || 0;
@@ -1051,7 +1065,14 @@ async function publishWithTransactionalFlow(
1051
1065
  }
1052
1066
  }
1053
1067
 
1054
- return { successCount, failCount, skippedCount, viewUrl, failedUploadKeys };
1068
+ return {
1069
+ successCount,
1070
+ failCount,
1071
+ skippedCount,
1072
+ reviewPendingCount,
1073
+ viewUrl,
1074
+ failedUploadKeys,
1075
+ };
1055
1076
  }
1056
1077
 
1057
1078
  /**
@@ -1697,6 +1718,7 @@ async function publishCommand(options = {}) {
1697
1718
  let successCount = 0;
1698
1719
  let failCount = 0;
1699
1720
  let skippedCount = 0;
1721
+ let reviewPendingCount = 0;
1700
1722
  let viewUrl = null;
1701
1723
 
1702
1724
  // Load diff manifests for attaching diff data to screenshot assets
@@ -1743,6 +1765,7 @@ async function publishCommand(options = {}) {
1743
1765
  successCount = result.successCount;
1744
1766
  failCount = result.failCount;
1745
1767
  skippedCount = result.skippedCount || 0;
1768
+ reviewPendingCount = result.reviewPendingCount || 0;
1746
1769
  viewUrl = result.viewUrl || null;
1747
1770
  } catch (txError) {
1748
1771
  // Fall back to legacy flow if transactional fails
@@ -1809,21 +1832,40 @@ async function publishCommand(options = {}) {
1809
1832
  }
1810
1833
 
1811
1834
  if (!autoApprove && successCount > 0) {
1812
- console.log(
1813
- chalk.cyan(
1814
- `\n ℹ ${successCount} visual${successCount === 1 ? "" : "s"} awaiting review (PENDING)`,
1815
- ),
1816
- );
1817
- console.log(
1818
- chalk.gray(
1819
- " To skip review for first-time captures, re-run with `reshot publish --auto-approve`",
1820
- ),
1821
- );
1822
- console.log(
1823
- chalk.gray(
1824
- " or approve them in the studio link above.",
1825
- ),
1826
- );
1835
+ // Only NEW/CHANGED captures await review; unchanged captures dedup to
1836
+ // their existing (often already-approved) version and stay live. Report
1837
+ // the accurate pending count so a re-publish doesn't look like it reset
1838
+ // already-approved work (audit run-10 F1).
1839
+ const pending = reviewPendingCount;
1840
+ const keptLive = Math.max(0, successCount - pending);
1841
+ if (pending > 0) {
1842
+ console.log(
1843
+ chalk.cyan(
1844
+ `\n ℹ ${pending} new/changed visual${pending === 1 ? "" : "s"} awaiting review (PENDING)`,
1845
+ ),
1846
+ );
1847
+ if (keptLive > 0) {
1848
+ console.log(
1849
+ chalk.gray(
1850
+ ` ${keptLive} unchanged visual${keptLive === 1 ? "" : "s"} stayed live (no re-approval needed).`,
1851
+ ),
1852
+ );
1853
+ }
1854
+ console.log(
1855
+ chalk.gray(
1856
+ " To skip review for first-time captures, re-run with `reshot publish --auto-approve`",
1857
+ ),
1858
+ );
1859
+ console.log(
1860
+ chalk.gray(" or approve them in the studio link above."),
1861
+ );
1862
+ } else {
1863
+ console.log(
1864
+ chalk.cyan(
1865
+ `\n ℹ No new captures to review — all ${successCount} published visual${successCount === 1 ? "" : "s"} were unchanged and stayed live.`,
1866
+ ),
1867
+ );
1868
+ }
1827
1869
  }
1828
1870
 
1829
1871
  // Helpful guidance about diff percentages
package/src/index.js CHANGED
@@ -159,6 +159,7 @@ program
159
159
  .command("run [target]")
160
160
  .description("Execute visual capture scenarios from config")
161
161
  .option("-s, --scenarios <keys>", "Comma-separated list of scenario keys")
162
+ .option("--scenario <keys>", "Alias for --scenarios")
162
163
  .option("--no-headless", "Run browser in visible mode")
163
164
  .option("--variant <json>", "Override variant configuration as JSON")
164
165
  .option("--all-variants", "Run all configured variant combinations")
@@ -431,7 +432,24 @@ program
431
432
  });
432
433
 
433
434
  // Doctor: Validate target contract and readiness
434
- const doctor = program.command("doctor").description("Validate target configuration and readiness");
435
+ const doctor = program
436
+ .command("doctor")
437
+ .description("Validate target configuration and readiness")
438
+ .option("-s, --scenarios <keys>", "Comma-separated list of scenario keys")
439
+ .option("--timeout <ms>", "Per-step timeout in milliseconds (default 15000)")
440
+ .option("--json", "Output JSON report")
441
+ .action(async (options) => {
442
+ // Bare `reshot doctor` runs the target readiness audit by default instead
443
+ // of just printing help (audit run-10 F5). Use `doctor release` for the
444
+ // full release gate.
445
+ try {
446
+ const doctorTargetCommand = require("./commands/doctor-target");
447
+ await doctorTargetCommand(options || {});
448
+ } catch (error) {
449
+ console.error(chalk.red("Error:"), error.message);
450
+ process.exit(1);
451
+ }
452
+ });
435
453
 
436
454
  doctor
437
455
  .command("target")
@@ -640,8 +658,11 @@ function resolveRecordClipScenarioKeys(target, options = {}) {
640
658
  }
641
659
 
642
660
  function resolveScenarioKeysFromTarget(target, options = {}) {
643
- if (options.scenarios) {
644
- return options.scenarios.split(",").map((value) => value.trim()).filter(Boolean);
661
+ // Accept the singular `--scenario` as an alias for `--scenarios` — an easy
662
+ // trap that otherwise hard-fails the run (audit run-10 F2).
663
+ const scenarioList = options.scenarios || options.scenario;
664
+ if (scenarioList) {
665
+ return scenarioList.split(",").map((value) => value.trim()).filter(Boolean);
645
666
  }
646
667
 
647
668
  if (!target) {