ht-skills 0.2.7 → 0.2.8

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/lib/cli.js +47 -22
  2. package/package.json +1 -1
package/lib/cli.js CHANGED
@@ -36,6 +36,8 @@ const CONFIG_FILE_NAME = "config.json";
36
36
  const DEFAULT_LOGIN_TIMEOUT_MS = 5 * 60 * 1000;
37
37
  const DEFAULT_LOGIN_POLL_MS = 1500;
38
38
  const DEFAULT_PUBLISH_POLL_MS = 1500;
39
+ const DEFAULT_PUBLISH_TIMEOUT_MS = 5 * 60 * 1000;
40
+ const DEFAULT_PUBLISH_POLL_ERROR_LIMIT = 3;
39
41
 
40
42
  const BANNER_TEXT = String.raw` _ _ _____ ___ _ _ _ _ __ __ _ _ _
41
43
  | || |_ _| / __| |_(_) | |___ | \/ |__ _ _ _| |_____| |_ _ __| |__ _ __
@@ -1519,6 +1521,8 @@ async function cmdPublish(flags, deps = {}) {
1519
1521
  const colorize = ui ? createUiColorizer(ui.pc) : (text) => String(text);
1520
1522
  const outputWidth = getOutputWidth(deps.outputWidth);
1521
1523
  const pollIntervalMs = Math.max(500, Number(flags["poll-interval"] || deps.pollIntervalMs || DEFAULT_PUBLISH_POLL_MS));
1524
+ const publishTimeoutMs = Math.max(10_000, Number(flags.timeout || deps.timeoutMs || DEFAULT_PUBLISH_TIMEOUT_MS));
1525
+ const pollErrorLimit = Math.max(1, Number(flags["poll-error-limit"] || deps.pollErrorLimit || DEFAULT_PUBLISH_POLL_ERROR_LIMIT));
1522
1526
  const flowState = {
1523
1527
  auth: "pending",
1524
1528
  pack: "pending",
@@ -1553,24 +1557,15 @@ async function cmdPublish(flags, deps = {}) {
1553
1557
  printFallbackPublishIntro({ registry, skillDir, archiveName, visibility }, log);
1554
1558
  }
1555
1559
 
1556
- const authSpinner = ui ? ui.spinner() : null;
1557
1560
  flowState.auth = "active";
1558
- renderPublishFlow();
1559
- if (authSpinner) {
1560
- authSpinner.start("Checking login");
1561
- } else {
1561
+ if (!ui) {
1562
1562
  log(`Checking login for ${registry}...`);
1563
1563
  }
1564
1564
  const { token } = await ensureValidAuthToken(registry, flags, deps);
1565
1565
  flowState.auth = "done";
1566
- renderPublishFlow();
1567
- if (authSpinner) {
1568
- authSpinner.stop("Login confirmed");
1569
- }
1570
1566
 
1571
1567
  const packSpinner = ui ? ui.spinner() : null;
1572
1568
  flowState.pack = "active";
1573
- renderPublishFlow();
1574
1569
  if (packSpinner) {
1575
1570
  packSpinner.start(`Packing ${path.basename(skillDir) || skillDir}`);
1576
1571
  } else {
@@ -1578,7 +1573,6 @@ async function cmdPublish(flags, deps = {}) {
1578
1573
  }
1579
1574
  const archiveBuffer = await createZipFromDirectory(skillDir);
1580
1575
  flowState.pack = "done";
1581
- renderPublishFlow();
1582
1576
  if (packSpinner) {
1583
1577
  packSpinner.stop(`Created ${archiveName} (${formatBytes(archiveBuffer.length)})`);
1584
1578
  } else {
@@ -1587,7 +1581,6 @@ async function cmdPublish(flags, deps = {}) {
1587
1581
 
1588
1582
  const uploadSpinner = ui ? ui.spinner() : null;
1589
1583
  flowState.inspect = "active";
1590
- renderPublishFlow();
1591
1584
  if (uploadSpinner) {
1592
1585
  uploadSpinner.start("Uploading archive for package inspection");
1593
1586
  } else {
@@ -1616,18 +1609,53 @@ async function cmdPublish(flags, deps = {}) {
1616
1609
 
1617
1610
  let inspection = job;
1618
1611
  let lastProgressKey = "";
1612
+ let consecutivePollErrors = 0;
1613
+ const publishDeadline = Date.now() + publishTimeoutMs;
1619
1614
  const inspectSpinner = ui ? ui.spinner() : null;
1620
1615
  if (inspectSpinner) {
1621
1616
  inspectSpinner.start("Inspecting archive");
1622
1617
  }
1623
1618
  while (inspection.status !== "succeeded" && inspection.status !== "failed") {
1619
+ if (Date.now() > publishDeadline) {
1620
+ flowState.inspect = "error";
1621
+ if (inspectSpinner) {
1622
+ inspectSpinner.stop("Inspection timed out");
1623
+ }
1624
+ throw new Error(`Inspection timed out after ${Math.round(publishTimeoutMs / 1000)}s`);
1625
+ }
1626
+
1624
1627
  await sleep(pollIntervalMs);
1625
- inspection = await requestJsonImpl(
1626
- `${registry}/api/skills/inspect-package-jobs/${encodeURIComponent(jobId)}`,
1627
- {
1628
- headers: withBearerToken({}, token),
1629
- },
1630
- );
1628
+ try {
1629
+ inspection = await requestJsonImpl(
1630
+ `${registry}/api/skills/inspect-package-jobs/${encodeURIComponent(jobId)}`,
1631
+ {
1632
+ headers: withBearerToken({}, token),
1633
+ },
1634
+ );
1635
+ consecutivePollErrors = 0;
1636
+ } catch (error) {
1637
+ consecutivePollErrors += 1;
1638
+ if (consecutivePollErrors >= pollErrorLimit) {
1639
+ flowState.inspect = "error";
1640
+ if (inspectSpinner) {
1641
+ inspectSpinner.stop("Inspection polling failed");
1642
+ }
1643
+ throw new Error(`Inspection polling failed ${consecutivePollErrors} times: ${error.message}`);
1644
+ }
1645
+ if (!inspectSpinner) {
1646
+ log(`Inspection polling retry ${consecutivePollErrors}/${pollErrorLimit}: ${error.message}`);
1647
+ }
1648
+ continue;
1649
+ }
1650
+
1651
+ const runtimeError = String(inspection.error?.message || inspection.error || "").trim();
1652
+ if (runtimeError && inspection.status !== "succeeded") {
1653
+ flowState.inspect = "error";
1654
+ if (inspectSpinner) {
1655
+ inspectSpinner.stop("Inspection failed");
1656
+ }
1657
+ throw new Error(runtimeError);
1658
+ }
1631
1659
 
1632
1660
  const step = String(inspection.progress?.step || inspection.result?.step || "").trim();
1633
1661
  const percent = inspection.progress?.percent;
@@ -1647,14 +1675,12 @@ async function cmdPublish(flags, deps = {}) {
1647
1675
 
1648
1676
  if (inspection.status !== "succeeded") {
1649
1677
  flowState.inspect = "error";
1650
- renderPublishFlow();
1651
1678
  if (inspectSpinner) {
1652
1679
  inspectSpinner.stop("Inspection failed");
1653
1680
  }
1654
1681
  throw new Error(inspection.error || "skill archive inspection failed");
1655
1682
  }
1656
1683
  flowState.inspect = "done";
1657
- renderPublishFlow();
1658
1684
  if (inspectSpinner) {
1659
1685
  inspectSpinner.stop("Inspection passed");
1660
1686
  } else {
@@ -1685,7 +1711,6 @@ async function cmdPublish(flags, deps = {}) {
1685
1711
 
1686
1712
  const submitSpinner = ui ? ui.spinner() : null;
1687
1713
  flowState.submit = "active";
1688
- renderPublishFlow();
1689
1714
  if (submitSpinner) {
1690
1715
  submitSpinner.start(`Submitting review request (${visibility})`);
1691
1716
  } else {
@@ -1699,7 +1724,6 @@ async function cmdPublish(flags, deps = {}) {
1699
1724
  body: JSON.stringify(body),
1700
1725
  });
1701
1726
  flowState.submit = "done";
1702
- renderPublishFlow();
1703
1727
  if (submitSpinner) {
1704
1728
  submitSpinner.stop(`Review submission created (${result.submission_id || "pending"})`);
1705
1729
  } else {
@@ -1726,6 +1750,7 @@ async function cmdPublish(flags, deps = {}) {
1726
1750
  ].join("\n"),
1727
1751
  "Published",
1728
1752
  );
1753
+ renderPublishFlow();
1729
1754
  ui.outro(`Submitted ${ui.pc.cyan(archiveName)} for review.`);
1730
1755
  } else {
1731
1756
  log(JSON.stringify(summaryPayload, null, 2));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ht-skills",
3
- "version": "0.2.7",
3
+ "version": "0.2.8",
4
4
  "description": "CLI for installing and submitting skills from HT Skills Marketplace.",
5
5
  "type": "commonjs",
6
6
  "bin": {