skilldrop-cli 1.11.0 → 1.11.1

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": "skilldrop-cli",
3
- "version": "1.11.0",
3
+ "version": "1.11.1",
4
4
  "description": "Portable AI-agent skills, measured against the agent without them. ADRs, PRDs, runbooks, decks and reviews, installable into Claude Code, Cursor, Kiro, and any IDE that takes custom instructions. One command per skill or per role-based pack.",
5
5
  "author": {
6
6
  "name": "Sanjay Ananthanarayan",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "file-to-markdown",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Convert a Word document, PowerPoint deck, Excel workbook, web page, CSV, JSON, text file, email (.eml or Outlook .msg) or PDF into clean Markdown. It keeps headings, lists, tables, links, bold and italic, slide titles and speaker notes. It saves embedded images beside the Markdown and links them, shows tracked changes as pending rather than accepted, and reports everything else it dropped (charts, comments, formulas), so the content can be read, reviewed or fed to another skill. Use when the user hands over a .docx, .pptx, .xlsx, .html, .csv, .json, .eml, .msg or .pdf and says \"read this\", \"turn this into markdown\", \"extract the text\", or wants it critiqued or briefed.",
5
5
  "entrypoint": "SKILL.md",
6
6
  "deps": {
@@ -727,6 +727,14 @@ def cell_ref(ref):
727
727
  return int(m.group(2)) - 1, n - 1
728
728
 
729
729
 
730
+ def _int_or(text, default):
731
+ """int(text), or default when a damaged file leaves it empty or not a number."""
732
+ try:
733
+ return int(text)
734
+ except (TypeError, ValueError):
735
+ return default
736
+
737
+
730
738
  def xlsx_to_md(path, rep, max_rows=0):
731
739
  z = open_zip(path, ".xlsx")
732
740
  names = set(z.namelist())
@@ -749,10 +757,10 @@ def xlsx_to_md(path, rep, max_rows=0):
749
757
  nf = st.find(S + "numFmts")
750
758
  for f in (nf if nf is not None else []):
751
759
  code = re.sub(r'"[^"]*"|\[[^\]]*\]|\\.', "", f.get("formatCode", "")).lower()
752
- custom[int(f.get("numFmtId"))] = bool(re.search(r"[dmyh]", code))
760
+ custom[_int_or(f.get("numFmtId"), -1)] = bool(re.search(r"[dmyh]", code))
753
761
  xfs = st.find(S + "cellXfs")
754
762
  for k, xf in enumerate(xfs if xfs is not None else []):
755
- fid = int(xf.get("numFmtId", "0"))
763
+ fid = _int_or(xf.get("numFmtId", "0"), 0)
756
764
  if fid in BUILTIN_DATE_FMTS or custom.get(fid):
757
765
  date_styles.add(k)
758
766
  rels = read_rels(z, "xl/_rels/workbook.xml.rels")
@@ -788,14 +796,15 @@ def xlsx_to_md(path, rep, max_rows=0):
788
796
  if c.find(S + "f") is not None:
789
797
  formulas += 1
790
798
  if t == "s" and v is not None:
791
- val = shared[int(v.text)] if int(v.text) < len(shared) else ""
799
+ i = _int_or(v.text, -1) # an empty or non-numeric index reads as a blank cell
800
+ val = shared[i] if 0 <= i < len(shared) else ""
792
801
  elif t == "inlineStr":
793
802
  val = "".join(x.text or "" for x in c.iter(S + "t"))
794
803
  elif t == "b" and v is not None:
795
804
  val = "TRUE" if v.text == "1" else "FALSE"
796
805
  elif v is not None and v.text is not None:
797
806
  val = v.text
798
- if t == "n" and int(c.get("s", "0")) in date_styles:
807
+ if t == "n" and _int_or(c.get("s", "0"), 0) in date_styles:
799
808
  try:
800
809
  d = epoch + timedelta(days=float(val))
801
810
  val = d.strftime("%Y-%m-%d") if float(val) == int(float(val)) \