skilldrop-cli 1.1.0 → 1.1.2

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 (50) hide show
  1. package/README.md +1 -1
  2. package/package.json +1 -1
  3. package/packs/ai-engineering/skills/judge-audit/SKILL.md +24 -6
  4. package/packs/ai-engineering/skills/judge-audit/evals/evals.json +29 -0
  5. package/packs/ai-engineering/skills/judge-audit/evals/files/10/judge_eval.csv +61 -0
  6. package/packs/ai-engineering/skills/judge-audit/evals/files/11/mod_sample_scored.csv +201 -0
  7. package/packs/ai-engineering/skills/judge-audit/manifest.json +1 -1
  8. package/packs/converters/skills/md-to-pptx/SKILL.md +25 -8
  9. package/packs/converters/skills/md-to-pptx/evals/evals.json +30 -0
  10. package/packs/converters/skills/md-to-pptx/evals/files/6/q3-status-report.md +72 -0
  11. package/packs/converters/skills/md-to-pptx/evals/files/7/runbooks/db-failover.md +59 -0
  12. package/packs/converters/skills/md-to-pptx/evals/files/7/runbooks/diagrams/topology.png +0 -0
  13. package/packs/converters/skills/md-to-pptx/manifest.json +1 -1
  14. package/packs/converters/skills/md-to-pptx/reference.md +9 -1
  15. package/packs/converters/skills/md-to-pptx/scripts/md_to_pptx.py +35 -2
  16. package/packs/frontend/skills/bundle-size-review/SKILL.md +5 -2
  17. package/packs/frontend/skills/bundle-size-review/evals/evals.json +30 -0
  18. package/packs/frontend/skills/bundle-size-review/evals/files/8/.browserslistrc +6 -0
  19. package/packs/frontend/skills/bundle-size-review/evals/files/8/babel.config.js +6 -0
  20. package/packs/frontend/skills/bundle-size-review/evals/files/8/dist/stats.json +854 -0
  21. package/packs/frontend/skills/bundle-size-review/evals/files/8/package-lock.json.fixture +73 -0
  22. package/packs/frontend/skills/bundle-size-review/evals/files/8/package.json.fixture +28 -0
  23. package/packs/frontend/skills/bundle-size-review/evals/files/8/src/app/App.jsx +23 -0
  24. package/packs/frontend/skills/bundle-size-review/evals/files/8/src/app/BookingForm.jsx +18 -0
  25. package/packs/frontend/skills/bundle-size-review/evals/files/8/src/app/admin/Reports.jsx +17 -0
  26. package/packs/frontend/skills/bundle-size-review/evals/files/8/src/app/index.jsx +4 -0
  27. package/packs/frontend/skills/bundle-size-review/evals/files/8/src/landing/Hero.jsx +17 -0
  28. package/packs/frontend/skills/bundle-size-review/evals/files/8/src/landing/index.jsx +4 -0
  29. package/packs/frontend/skills/bundle-size-review/evals/files/8/src/polyfills.js +3 -0
  30. package/packs/frontend/skills/bundle-size-review/evals/files/8/src/utils/format.js +4 -0
  31. package/packs/frontend/skills/bundle-size-review/evals/files/8/webpack.config.js +35 -0
  32. package/packs/frontend/skills/bundle-size-review/evals/files/9/.github/workflows/size.yml.fixture +12 -0
  33. package/packs/frontend/skills/bundle-size-review/evals/files/9/build.mjs +17 -0
  34. package/packs/frontend/skills/bundle-size-review/evals/files/9/meta.main.json +100 -0
  35. package/packs/frontend/skills/bundle-size-review/evals/files/9/meta.pr412.json +196 -0
  36. package/packs/frontend/skills/bundle-size-review/evals/files/9/package.json.fixture +17 -0
  37. package/packs/frontend/skills/bundle-size-review/evals/files/9/scripts/check-size.mjs +11 -0
  38. package/packs/frontend/skills/bundle-size-review/evals/files/9/src/api.ts +11 -0
  39. package/packs/frontend/skills/bundle-size-review/evals/files/9/src/composer.tsx +21 -0
  40. package/packs/frontend/skills/bundle-size-review/evals/files/9/src/emoji/data.ts +8 -0
  41. package/packs/frontend/skills/bundle-size-review/evals/files/9/src/emoji/picker.tsx +22 -0
  42. package/packs/frontend/skills/bundle-size-review/evals/files/9/src/styles.ts +11 -0
  43. package/packs/frontend/skills/bundle-size-review/evals/files/9/src/widget.ts +15 -0
  44. package/packs/frontend/skills/bundle-size-review/manifest.json +1 -1
  45. package/packs/solution-architect/skills/event-contract-draft/SKILL.md +36 -8
  46. package/packs/solution-architect/skills/event-contract-draft/evals/evals.json +30 -0
  47. package/packs/solution-architect/skills/event-contract-draft/evals/files/6/infra/topics.yaml +10 -0
  48. package/packs/solution-architect/skills/event-contract-draft/evals/files/6/src/checkout/order_events.py +57 -0
  49. package/packs/solution-architect/skills/event-contract-draft/evals/files/7/docs/webhooks.yaml +40 -0
  50. package/packs/solution-architect/skills/event-contract-draft/manifest.json +1 -1
@@ -57,12 +57,20 @@ plus the paragraph spacing. It packs blocks top to bottom into 96% of the body h
57
57
  a "(continued)" slide when the next block does not fit.
58
58
 
59
59
  - **Text** splits between paragraphs or list items, never inside one. A subheading or a line
60
- ending in `:` moves to the next slide with the item it introduces.
60
+ ending in `:` moves to the next slide with the item it introduces. A nested line stays with
61
+ the item above it: when a sub-bullet would start the next slide, the whole item moves, from
62
+ its top-level line. The exception is an item taller than 80% of a slide, which breaks inside.
63
+ - **A section that splits is balanced.** It is packed again into up to 40% less height, in 5%
64
+ steps, while it still takes the same number of slides. So the last slide isn't left
65
+ holding one or two lines: three slides carry, say, 7, 7 and 6 items rather than 9, 9 and 2. A section with a `---` break isn't balanced,
66
+ because the author placed the breaks.
61
67
  - **Tables** split between rows, with the header row repeated, at least two rows per slide, and
62
68
  never one row left alone.
63
69
  - **Code** splits between lines, at least three per slide, and never one or two left alone.
64
70
  - **Images** shrink to the space left when at least 60% of their fitted size and 1.5 in remain;
65
71
  otherwise they move to the next slide.
72
+ - **An image under 64 pixels on a side** is embedded at its size, with a warning that it looks
73
+ like a placeholder or a thumbnail: at 96 dpi an 8×6 image is a speck on the slide.
66
74
  - **A single paragraph or table row taller than a slide** cannot split. It is placed alone and
67
75
  overflows, with a warning: break it into bullets.
68
76
  - **A slide title over two lines** gets a warning. Titles are not shrunk either.
@@ -787,6 +787,9 @@ class Deck(object):
787
787
  warn(line, "image %s is not PNG or JPEG; alt text written instead" % src)
788
788
  return self.para_unit("p", fallback, line)
789
789
  w, h, dx, dy, kind = info
790
+ if min(w, h) < 64:
791
+ warn(line, "image %s is only %dx%d pixels, so it shows as a speck on the slide; it looks like a "
792
+ "placeholder or a thumbnail. Replace it with the full-size image" % (src, w, h))
790
793
  cx, cy = w / dx * EMU_IN, h / dy * EMU_IN
791
794
  scale = min(1.0, self.body_w / cx, self.body_h / cy)
792
795
  return {"kind": "image", "path": os.path.abspath(path), "alt": alt_plain, "fmt": kind,
@@ -880,8 +883,23 @@ class Deck(object):
880
883
 
881
884
  # ---- pagination ---------------------------------------------------------------
882
885
  def paginate(self, units, title, line):
883
- """Pack units into pages of body height. Returns (pages, split_reason or None)."""
884
- H = self.body_h
886
+ """Pack units into pages of body height. Returns (pages, split_reason or None).
887
+
888
+ A section that splits is then balanced: it is packed again into less height while it still
889
+ takes the same number of slides, so the last one isn't left holding two stray lines."""
890
+ pages, reasons = self._paginate([dict(u) for u in units], self.body_h)
891
+ breaks = any(u["kind"] == "break" for u in units)
892
+ if len(pages) > 1 and not breaks:
893
+ best, H = (pages, reasons), self.body_h
894
+ for k in range(1, 9):
895
+ trial = self._paginate([dict(u) for u in units], int(H * (1 - 0.05 * k)))
896
+ if len(trial[0]) != len(pages):
897
+ break
898
+ best = trial
899
+ pages, reasons = best
900
+ return pages, reasons
901
+
902
+ def _paginate(self, units, H):
885
903
  pages = [[]]
886
904
  used = [0]
887
905
  last = [None]
@@ -914,6 +932,21 @@ class Deck(object):
914
932
  if k == "para":
915
933
  if used[0] + cost(u, u["h"]) > H and used[0]:
916
934
  carry = []
935
+ # A nested list line belongs with the item above it: move the whole item, from
936
+ # its top-level line, to the next slide, unless that would empty this one or
937
+ # the item is taller than a slide anyway.
938
+ if u["role"] in ("bullet", "num") and u["level"] > 0:
939
+ cur = pages[-1]
940
+ i = len(cur)
941
+ while i > 0 and cur[i - 1]["kind"] == "para" and cur[i - 1]["role"] in ("bullet", "num") \
942
+ and cur[i - 1]["level"] > 0:
943
+ i -= 1
944
+ if i > 0 and cur[i - 1]["kind"] == "para" and cur[i - 1]["role"] in ("bullet", "num"):
945
+ i -= 1
946
+ item_h = sum(x["h"] for x in cur[i:]) + u["h"]
947
+ if [x for x in cur[:i] if x["kind"] != "notes"] and item_h < 0.8 * H:
948
+ carry = cur[i:]
949
+ del cur[i:]
917
950
  # keep a subheading, or a lead-in line ending in ":", with what follows it
918
951
  while pages[-1] and pages[-1][-1]["kind"] == "para" and (
919
952
  pages[-1][-1]["role"] == "sub" or plain(pages[-1][-1]["segs"]).rstrip().endswith(":")) \
@@ -61,9 +61,10 @@ Reads the bundler's own record of what it built, and the repo files that decide
61
61
 
62
62
  11. **Reply short, in one message, in this order.**
63
63
  - **First line answers the question in the person's words.** ✅ *"Yes, the reviewer is right: echarts moved from the lazy reports chunk into vendors, so the first load grew from 311,282 to 803,674 bytes (+492,392) while the total fell 1,949."* ❌ *"This confirms it."* / *"Let me break this down."*
64
- - **Then the fixes, numbered by first-load impact:** what it is, the chain, the change, what to check after. Two to four lines each.
64
+ - **Then the fixes, numbered by first-load impact:** what it is, the chain, the change, what to check after. Two to four lines each. The change is the exact edit, in the file the chain names, ready to apply: the import line to replace and its replacement, or a short diff. ✅ *"In `src/components/Header.tsx`, replace `import * as Icons from "@acme/icons"` with `import { SearchIcon, MenuIcon } from "@acme/icons"`."* ❌ *"Consider lazy-loading the locales."*
65
+ - **Edit files only when asked to change the code** ("fix it", "cut it", "open the PR"). Then make the edit, keep everything users rely on working, and say you couldn't rebuild if you couldn't. A question ("why is it big?") gets the edits in the reply, and the files stay untouched.
65
66
  - **One line on lazy chunks** when they matter to the question.
66
- - **Then the guard:** the per-entry budget that would have caught it, with its threshold.
67
+ - **Then the guard:** the per-entry budget that would have caught it, with its threshold, as configuration for a tool the repo has or a named package to add: webpack `performance` (`hints: "error"`, `maxEntrypointSize`), a size-limit entry (`path`, `limit`), or the existing CI file's step. Never a script, flag or config key that doesn't exist; when you're unsure a tool takes an option, leave it out.
67
68
  - **"To confirm"** for what only the user can answer; omit it when empty. No module tables, no full package lists, no tool output pasted in, no flags or options that don't exist. About 250 words.
68
69
 
69
70
  **Non-interactive runs** (subagent, CI, headless): with no stats file, emit `BLOCKED: need the bundler stats file (webpack --json, esbuild --metafile, or rollup-plugin-visualizer raw-data)`. With only built files or a treemap screenshot, report the per-file sizes and emit `BLOCKED: need the stats file to say what is inside each chunk`. Browser targets absent from every project file (after looking) become `[assumption] browser targets unknown; polyfill findings unconfirmed`; a missing budget becomes `[assumption] budget set at the current initial size plus 5%`.
@@ -78,6 +79,8 @@ Reads the bundler's own record of what it built, and the repo files that decide
78
79
 
79
80
  - **The first line answers the question** in the person's terms, with the exact byte figures from the stats.
80
81
  - **The repo was read:** targets, versions and importing files are cited by file name; nothing is called absent without having been looked for.
82
+ - **Each fix is an exact edit to a named file;** files are changed only when the user asked for changes.
83
+ - **The guard is real configuration** for a tool that exists, with no invented flag, script or key.
81
84
  - **One unit system,** bytes with kB = 1000, and the kind of size (module, emitted, post-bundle, compressed) is named once.
82
85
  - **Compressed figures are measured or absent,** never estimated into the lead.
83
86
  - **Initial and lazy are kept apart,** and a lazy chunk is never ranked above an initial-chunk fix.
@@ -103,6 +103,36 @@
103
103
  "Invents nothing that is not in the input: no component names, package versions, file paths, chunk or asset sizes, or webpack/plugin options beyond what the stats and repo files contain. Any tool that would need installing from the network is given as a command, not presented as already run.",
104
104
  "Answers all three numbered questions directly, per app, in the order asked."
105
105
  ]
106
+ },
107
+ {
108
+ "id": 8,
109
+ "held_out": "2026-10-22",
110
+ "prompt": "ok so our welcome page (welcome.html, the `landing` entry) scores terribly on mobile and Priya from product says \"the bundle is huge, it's moment, just rip moment out\". is she right?? I ran the build with stats, it's at dist/stats.json, rest of the repo is here. what do we actually cut first, we want the landing page JS under 200kb",
111
+ "assertions": [
112
+ "Answers both questions directly up front: Priya is wrong about moment for this page, and it names what to cut first for the landing page (app-only vendor code, whole lodash, the legacy polyfills), not a generic bundle audit.",
113
+ "Shows that moment (./node_modules/moment/moment.js plus its locale context modules) is only in the lazy `admin` chunk (admin.e91c5d.js, 82,310 bytes), pulled in by the dynamic import() of ./admin/Reports in src/app/App.jsx, so it is not in the landing entry's first load and removing it would not shrink welcome.html's JavaScript.",
114
+ "Gives the landing entry's first-load JS as 287,994 bytes from the stats (runtime.3f1a9c.js 2,615 + vendors.8c2d41.js 281,467 + landing.a07e93.js 3,912), kept apart from the lazy admin chunk, and says the stats record minified, uncompressed bytes, so it cannot tell from them whether '200kb' (gzip or not, 1000 or 1024) is met; it gives a command to measure compressed size (e.g. `gzip -c dist/vendors.8c2d41.js | wc -c`) instead of making up a gzip figure.",
115
+ "Spots that the single `vendors` cacheGroup in webpack.config.js (fixed name: 'vendors', chunks: 'initial') makes the landing entry download node_modules that only the app entry uses. @northwind/datepicker and both copies of date-fns are reached only from ./src/app/BookingForm.jsx. It recommends dropping the fixed name, or splitting vendors per entry, so landing gets only what its own import chain needs.",
116
+ "Flags the whole-library lodash import and names the chain src/landing/index.jsx -> src/landing/Hero.jsx -> src/utils/format.js (`import _ from 'lodash'`) -> ./node_modules/lodash/lodash.js. It notes that lodash is CommonJS and can't be tree-shaken, and that only startCase, toLower and debounce are used, so it suggests per-method imports (e.g. lodash/startCase), lodash-es or native code.",
117
+ "Flags whatwg-fetch and promise-polyfill, which src/polyfills.js loads into both entries through the webpack entry arrays, as unneeded for the .browserslistrc targets (last 2 Chrome/Firefox/Safari/Edge/iOS versions, all with native fetch and Promise), and treats the IE11 comment as outdated.",
118
+ "Notes that date-fns is bundled twice: 2.30.0 at node_modules/date-fns (from the app's ^2.30.0) and 3.6.0 at node_modules/@northwind/datepicker/node_modules/date-fns, per package-lock.json.fixture/package-lock.json. It says that removing the duplicate means moving the app to date-fns 3 (checking the v2-to-v3 changes for format/parseISO in BookingForm.jsx), and it does not subtract the stats' module sizes, which are pre-minification source bytes (e.g. lodash.js at 544,098, more than the whole 281,467-byte vendors asset), from the emitted bytes as if they were savings. Post-change sizes are given as estimates to confirm by running `npm run build:stats`.",
119
+ "Invents nothing that isn't in the input: no module, package version, file name, byte count, gzip size or webpack option beyond what dist/stats.json and the repo files contain, and no claim that it ran a build."
120
+ ]
121
+ },
122
+ {
123
+ "id": 9,
124
+ "held_out": "2026-10-22",
125
+ "prompt": "We ship Parcelpost Chat, an embeddable support widget customers load with <script type=\"module\" src=\".../widget.js\">. Since PR #412 (emoji picker) went out, two customers have told us the widget adds a lot more to their page weight. But our size check in CI passed, and it actually said widget.js got smaller. The repo here is the PR branch, and I've saved the esbuild metafiles from a main build and a PR build as meta.main.json and meta.pr412.json. What grew and why? Is it on the initial load? And how should we change the size check so this gets caught next time?",
126
+ "assertions": [
127
+ "Answers directly up front: the widget's first-load JS went from 21,312 bytes (dist/widget.js alone on main) to 118,910 bytes on PR #412 (dist/widget.js 10,215 + the statically imported dist/chunk-R4N7QW2L.js 108,695), a growth of 97,598 bytes, and all of it is on the initial load.",
128
+ "Explains why widget.js 'got smaller' (21,312 to 10,215): preact and preact/hooks (10,214 + 1,436 bytesInOutput) moved out of widget.js into the shared chunk because the picker imports them too. This is a relocation, not a saving.",
129
+ "Names the cause and the import chain: src/emoji/emoji-data.json (96,512 bytesInOutput in the shared chunk) reaches the initial load via src/widget.ts -> src/composer.tsx -> src/emoji/data.ts -> src/emoji/emoji-data.json. The static `import { SHORTCODES } from './emoji/data'` added to composer.tsx defeats the dynamic import('./emoji/picker').",
130
+ "Keeps dist/picker-6YB3KD5M.js (5,920 bytes) separate as a lazy chunk, fetched only when the picker opens, and does not count it in the first-load growth.",
131
+ "Proposes a fix that keeps the emoji data off the initial load, such as loading SHORTCODES lazily (when the picker opens or the visitor first types ':') or using a small separate shortcode map, and says to confirm it with a rebuild (e.g. `META_OUT=meta.fix.json npm run build`) instead of stating post-fix byte counts as fact.",
132
+ "Explains that the check passed because scripts/check-size.mjs only measures dist/widget.js against 25,000 bytes. It proposes a per-entry first-load budget computed from the metafile (the entry output plus every output reachable through import-statement imports, excluding dynamic-import), which would have measured 118,910 bytes on PR #412 and failed the 25,000 limit. Lazy chunks can get their own separate limit.",
133
+ "Stays with the minified, uncompressed bytes the metafiles record and doesn't claim gzip/brotli transfer sizes (what customers' 'page weight' probably reflects). If it wants compressed numbers, it gives a command such as `gzip -c dist/chunk-*.js | wc -c` to run.",
134
+ "Invents nothing that isn't in the input: no output file, input module, byte count, esbuild option or CI step beyond what the metafiles and repo files contain, and no claim that it ran the build."
135
+ ]
106
136
  }
107
137
  ]
108
138
  }
@@ -0,0 +1,6 @@
1
+ # Support matrix agreed with product, 2025-03
2
+ last 2 Chrome versions
3
+ last 2 Firefox versions
4
+ last 2 Safari versions
5
+ last 2 Edge versions
6
+ last 2 iOS versions
@@ -0,0 +1,6 @@
1
+ module.exports = {
2
+ presets: [
3
+ ['@babel/preset-env', { modules: false }],
4
+ ['@babel/preset-react', { runtime: 'automatic' }],
5
+ ],
6
+ };