{"owner":"examples","slug":"changelog-writer","channel":"examples/changelog-writer","version":"1.0.1","artifact_sha256":"45a036cb7a435f56594f7290f119768dc82759273327288076feb515158a2212","published_at":"2026-08-30T10:14:17.420Z","price_micro":"5000000","update_price_micro":"100000","resource_endpoint":"https://x402git.com/api/r/examples/changelog-writer","version_url":"https://x402git.com/api/v/examples/changelog-writer","computed":{"artifact_class":"Toolkit","component_inventory":[{"kind":"skills","count":1},{"kind":"scripts","count":1},{"kind":"docs","count":2},{"kind":"config","count":1},{"kind":"other","count":1}],"file_count":6,"dir_depth":1,"bytes_text":17556,"bytes_binary":0,"languages":{"JavaScript":8497},"tree":[{"path":".gitignore","size":30,"binary":false},{"path":"LICENSE","size":1068,"binary":false},{"path":"README.md","size":4329,"binary":false},{"path":"package.json","size":538,"binary":false},{"path":"scripts/changelog.mjs","size":8497,"binary":false},{"path":"skills/changelog.md","size":3094,"binary":false}],"readme_html":"<h2>changelog-writer</h2>\n<p>Turn <code>git log</code> between two tags into a changelog draft, then edit it into release notes.</p>\n<p>One script and one skill. The script reads Conventional Commits when a repo uses them and degrades to a clean flat list when it does not, because most repos do not and a tool that only runs on tidy history is a tool you cannot use today.</p>\n<p>No dependencies. Node 18 or newer. It runs <code>git log</code>, <code>git tag</code> and <code>git remote</code>, and writes nothing to git.</p>\n<h3>Usage</h3>\n<pre><code class=\"language-sh\">node scripts/changelog.mjs v1.0.0 v1.1.0\n</code></pre>\n<p>Argument handling is the shape you would guess:</p>\n<table><thead><tr><th scope=\"col\">Command</th><th scope=\"col\">Range</th></tr></thead><tbody><tr><td><code>changelog</code></td><td>newest tag <code>..HEAD</code></td></tr><tr><td><code>changelog v1.4.2</code></td><td><code>v1.4.2..HEAD</code></td></tr><tr><td><code>changelog v1.4.2</code> <em>(when <code>v1.4.2</code> is the current tip)</em></td><td><code>v1.4.1..v1.4.2</code> — &quot;what went into this release&quot;</td></tr><tr><td><code>changelog v1.0.0 v1.1.0</code></td><td>exactly that</td></tr><tr><td><code>changelog abc123 HEAD</code></td><td>any revision works, not only tags</td></tr></tbody></table>\n<h4>Options</h4>\n<table><thead><tr><th scope=\"col\">Flag</th><th scope=\"col\">Effect</th></tr></thead><tbody><tr><td><code>--repo &lt;url&gt;</code></td><td>Base URL for commit and compare links. Defaults to <code>origin</code>, converted from SSH to https.</td></tr><tr><td><code>--out &lt;file&gt;</code></td><td><strong>Prepend</strong> the block to a file. Newest release ends up at the top of <code>CHANGELOG.md</code>.</td></tr><tr><td><code>--all</code></td><td>Include <code>chore</code>, <code>ci</code>, <code>build</code> and <code>test</code> commits. Off by default; the count is reported instead.</td></tr><tr><td><code>--json</code></td><td>Emit the parsed commits instead of markdown, so you can group them yourself.</td></tr><tr><td><code>--cwd &lt;dir&gt;</code></td><td>Run against another checkout.</td></tr></tbody></table>\n<h4>Examples</h4>\n<p>Release notes for a tag you just pushed, with links:</p>\n<pre><code class=\"language-sh\">node scripts/changelog.mjs v1.1.0 --repo https://github.com/you/project\n</code></pre>\n<p>Keep <code>CHANGELOG.md</code> current as part of the release:</p>\n<pre><code class=\"language-sh\">node scripts/changelog.mjs v1.0.0 v1.1.0 --out CHANGELOG.md\ngit add CHANGELOG.md &amp;&amp; git commit -m &quot;docs: changelog for v1.1.0&quot;\n</code></pre>\n<p>Straight into a GitHub release:</p>\n<pre><code class=\"language-sh\">node scripts/changelog.mjs v1.1.0 | gh release create v1.1.0 --notes-file -\n</code></pre>\n<h3>Output</h3>\n<pre><code class=\"language-markdown\">## v1.1.0 — 2026-08-30\n\n7 commits since [`v1.0.0...v1.1.0`](https://github.com/you/project/compare/v1.0.0...v1.1.0).\n\n### Breaking changes\n\n- **client:** require an options object ([`9f2c1ab`](https://github.com/you/project/commit/9f2c1ab…))\n  `createClient()` no longer accepts a string. Pass `{ url }`.\n\n### Added\n\n- **auth:** device-code login for headless machines ([`3d81f04`](…))\n\n### Fixed\n\n- resume uploads after a dropped connection ([`c0a7e12`](…))\n\n&lt;sub&gt;3 housekeeping commits omitted. Re-run with `--all` to include them.&lt;/sub&gt;\n</code></pre>\n<p>Sections come out in reading order: <strong>Breaking changes, Added, Fixed, Performance, Changed, Reverted, Documentation</strong>, then the noisy ones behind <code>--all</code>. Empty sections are never printed.</p>\n<h3>How commits are classified</h3>\n<ul><li><code>type(scope)!: summary</code> is parsed into a type, an optional scope and a summary. The scope becomes the bold lead-in on the bullet.</li><li>A commit is <strong>breaking</strong> if the subject has <code>!</code> before the colon <em>or</em> the body has a <code>BREAKING CHANGE:</code> footer. Breaking commits appear in the breaking section and in their own type&#39;s section, so a reader scanning &quot;Added&quot; still sees them.</li><li>The <code>BREAKING CHANGE:</code> footer text is printed under the bullet. That footer is usually the only place the migration instruction exists.</li><li>Anything that does not match falls into <strong>Other</strong>, unchanged.</li><li>Merge commits are excluded (<code>--no-merges</code>).</li></ul>\n<h3>The skill</h3>\n<p><code>skills/changelog.md</code> is the half a script cannot do. It covers the editing pass: rewriting commit subjects into user-facing entries, merging five commits about one bug into one line, putting an actual instruction in every breaking-change entry, and deleting the sections you have nothing real to say in. It also tells an agent not to invent an entry it cannot verify from the diff, which is the failure mode worth guarding against.</p>\n<p>Drop it into wherever your agent reads skills from.</p>\n<h3>Limitations</h3>\n<ul><li>Tags are compared by <code>git describe</code> reachability, so a changelog across an unmerged branch may surprise you. Pass both ends explicitly when the history is not linear.</li><li>Reverts are listed, not resolved. A <code>revert:</code> commit and the commit it reverts both appear; deciding they cancel out is an editing judgement.</li><li>Commit links assume the GitHub URL shape (<code>/commit/&lt;sha&gt;</code>, <code>/compare/a...b</code>). Pass <code>--repo</code> for anything else, or drop the flag and get plain short SHAs.</li></ul>\n<h3>Licence</h3>\n<p>MIT. See <code>LICENSE</code>.</p>","dependencies":[],"licence":{"spdx":"MIT","verdict":"pass"},"scan":{"verdict":"pass","scanner_version":"2026.08.1","at":"2026-08-30T10:14:19.899Z","checks":[{"id":"secrets","tool":"x402git/secrets","tool_version":"2026.08.1","status":"pass","at":"2026-08-30T10:14:19.899Z","findings":0},{"id":"limits","tool":"x402git/limits","tool_version":"2026.08.1","status":"pass","at":"2026-08-30T10:14:19.899Z","findings":0},{"id":"known_vulns","tool":"osv.dev","tool_version":"2026-09-16","status":"pass","at":"2026-09-16T04:01:09.229Z","findings":0,"packages":0},{"id":"known_malware","tool":"osv.dev/MAL","tool_version":"2026-09-16","status":"pass","at":"2026-09-16T04:01:09.229Z","findings":0,"packages":0},{"id":"dep_behaviour","tool":"socket.dev","tool_version":"2026-09-14","status":"findings","at":"2026-09-14T09:53:24.557Z","findings":1,"packages":1},{"id":"capabilities","tool":"x402git/caps","tool_version":"2026.09.1","status":"findings","at":"2026-09-14T09:52:19.566Z","findings":4},{"id":"injection","tool":"x402git/inject","tool_version":"2026.09.1","status":"pass","at":"2026-09-14T09:52:19.566Z","findings":0}],"findings":[{"kind":"capability","check":"capabilities","tier":"disclosed","rule_id":"script","severity":"LOW","description":"Ships the script scripts/changelog.mjs","path":"scripts/changelog.mjs"},{"kind":"capability","check":"capabilities","tier":"disclosed","rule_id":"host","severity":"LOW","description":"Talks to github.com","path":"scripts/changelog.mjs"},{"kind":"capability","check":"capabilities","tier":"disclosed","rule_id":"env","severity":"LOW","description":"Reads the environment variable FIELD","path":"scripts/changelog.mjs"},{"kind":"capability","check":"capabilities","tier":"disclosed","rule_id":"env","severity":"LOW","description":"Reads the environment variable RECORD","path":"scripts/changelog.mjs"},{"kind":"behaviour","check":"dep_behaviour","tier":"disclosed","rule_id":"missingLockfile","severity":"LOW","description":"Socket SBOM Resolver (transitive) — no lockfile, so installs are not reproducible","package":{"ecosystem":"generic","name":"Socket SBOM Resolver","direct":false,"dev":false},"source":"socket.dev"}],"capabilities":{"tools":[],"runs":[{"path":"scripts/changelog.mjs","kind":"script"}],"hosts":[{"host":"github.com","local":false,"from":"code","paths":["scripts/changelog.mjs"]},{"host":"api.example.com","local":false,"from":"docs","paths":["skills/changelog.md"]},{"host":"github.com","local":false,"from":"docs","paths":["README.md"]}],"env":[{"name":"FIELD","paths":["scripts/changelog.mjs"]},{"name":"RECORD","paths":["scripts/changelog.mjs"]}],"install_runs":false,"summary":"runs a script · talks to 1 host · links to 2 hosts in its docs · reads 2 environment variables · nothing runs at install"},"counts":{"blocking":0,"disclosed":5,"review":0},"advisories_refreshed_at":"2026-09-16T04:01:09.229Z"},"cadence_sentence":"One release so far.","originality":{"blob_overlap_ratio":0.2,"blobs_seen_elsewhere":1,"blobs_total":5,"nearest_listing":"examples/humanizer","derivative_of":null},"engineering":{"unique_5gram_ratio":0.74,"type_token_ratio":0.37,"effective_code_lines":163,"effective_doc_words":1075,"code_files":1,"test_files":0,"padding_suspected":false},"cadence":{"releases":1,"median_days_between_releases":null,"on_time_fraction":null,"days_since_last":0.1,"score":null,"finished":false},"inventory_sentence":"1 skill · 1 script · 2 docs · 1 config file","extensions":{"md":2,"mjs":1,"json":1,"(none)":2},"lines_of_code":220,"warnings":["sbom_unavailable"],"repo_meta":{"repo_id":1351175867,"name":"x402git-example-changelog-writer","full_name":"pcmarts/x402git-example-changelog-writer","description":null,"homepage":null,"topics":[],"language":"JavaScript","default_branch":"main","size_kb":8,"created_at":"2026-08-30T06:58:06Z","pushed_at":"2026-08-30T07:00:19Z","licence_spdx":"MIT","open_issues":null,"stars":null,"forks":null,"watchers":null,"archived":false,"private":true,"html_url":null},"owner":{"login":"pcmarts","name":"Paul Martin","avatar_url":"https://avatars.githubusercontent.com/u/53514319?v=4","bio":"GTM, Marketing and Growth by day\r\nVibe Coding by night","blog":"https://paulmartin.link/","company":null,"location":null,"twitter_username":"pcmarts","followers":null,"public_repos":5,"created_at":"2019-07-31T09:12:36Z","html_url":"https://github.com/pcmarts"},"computed_at":"2026-08-30T10:14:20.098Z","analyzer_version":"0.1.0"},"self_reported":{"description":"Turns the git log between two tags into a clean changelog.","trigger_hint":"Fetch this when you are cutting a release and need a changelog out of git history."}}