From 5e3c469039def7035c86302ce6df01e8beb8aab2 Mon Sep 17 00:00:00 2001 From: Stefan Preu Date: Sat, 13 Jun 2026 23:24:46 +0200 Subject: [PATCH 1/2] =?UTF-8?q?feat(cli):=20single-call=20mutation=20ergon?= =?UTF-8?q?omics=20=E2=80=94=20--body-file,=20close=20-m/-r/-d,=20--resolu?= =?UTF-8?q?tion=20as=20close=20reason?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reduce agent round-trips on the core mutation surface (project management = context management). Three changes from the 2026-06-12 dogfooding audit: - pm create/update --body-file (GH-214, pm-7c48): load a long markdown body from a file instead of escaping a huge inline --body or chaining a second pm append. New src/core/io/body-file.ts resolveBodyFileContent helper is a CLI-only input alias onto the existing body field (no MCP surface — file paths are meaningless over MCP). Mutually exclusive with --body; actionable errors for conflict / empty-path / unreadable file. Wired into create+update actions before normalize, CREATE/UPDATE_FLAG_CONTRACTS, zsh/fish completion, contracts golden, and docs. - pm close short aliases -m/-r/-d (GH-226, pm-i1mu) for --message/--reason/ --duplicate-of. No semantic change. - pm close --resolution as close reason (pm-7x8d): under governance.require_close_reason, when no positional/--reason text is given the close reason is derived from the next-best signal — explicit reason > --duplicate-of ("Duplicate of ") > --resolution. The resolution still persists to metadata.resolution, so `pm close --resolution "..."` no longer hard-blocks. Tests: 100%-covered src/core/io/body-file.ts unit spec (in tests/unit/core/io/ to respect the 120-file-per-dir cap); in-process integration coverage for the create/update/close wiring; close-command precedence unit tests. Full coverage suite green (3275 tests). Closes pm-7c48, pm-i1mu, pm-7x8d. Co-Authored-By: Claude Opus 4.8 --- .../pm/extensions/.managed-extensions.json | 8 +- .../pm/extensions/pm-changelog/CHANGELOG.md | 6 + .../extensions/pm-changelog/dist/extension.js | 2 +- .../pm-changelog/dist/extension.js.map | 2 +- .../pm-changelog/dist/generator.d.ts.map | 2 +- .../extensions/pm-changelog/dist/generator.js | 57 +++++++++- .../pm-changelog/dist/generator.js.map | 2 +- .../pm/extensions/pm-changelog/manifest.json | 2 +- .../pm/extensions/pm-changelog/package.json | 4 +- .agents/pm/features/pm-7c48.toon | 16 +++ .agents/pm/features/pm-i1mu.toon | 16 +++ .agents/pm/history/pm-7c48.jsonl | 4 + .agents/pm/history/pm-7x8d.jsonl | 3 + .agents/pm/history/pm-i1mu.jsonl | 4 + .agents/pm/history/pm-kanu.jsonl | 2 + .agents/pm/tasks/pm-7x8d.toon | 8 +- .agents/pm/tasks/pm-kanu.toon | 14 +++ CHANGELOG.md | 11 ++ docs/AGENT_GUIDE.md | 5 +- docs/COMMANDS.md | 11 ++ src/cli/commands/close.ts | 17 ++- src/cli/commands/completion.ts | 4 + src/cli/register-mutation.ts | 27 ++++- src/core/io/body-file.ts | 63 +++++++++++ src/sdk/cli-contracts.ts | 2 + tests/fixtures/contracts/full.json | 6 + .../cli-inprocess-runner.integration.spec.ts | 105 +++++++++++++++++- tests/unit/close-command.spec.ts | 56 ++++++++++ tests/unit/completion-command.spec.ts | 2 + tests/unit/core/io/body-file.spec.ts | 86 ++++++++++++++ 30 files changed, 524 insertions(+), 23 deletions(-) create mode 100644 .agents/pm/features/pm-7c48.toon create mode 100644 .agents/pm/features/pm-i1mu.toon create mode 100644 .agents/pm/history/pm-7c48.jsonl create mode 100644 .agents/pm/history/pm-i1mu.jsonl create mode 100644 .agents/pm/history/pm-kanu.jsonl create mode 100644 .agents/pm/tasks/pm-kanu.toon create mode 100644 src/core/io/body-file.ts create mode 100644 tests/unit/core/io/body-file.spec.ts diff --git a/.agents/pm/extensions/.managed-extensions.json b/.agents/pm/extensions/.managed-extensions.json index 1a52f8fc3..aa6ea3001 100644 --- a/.agents/pm/extensions/.managed-extensions.json +++ b/.agents/pm/extensions/.managed-extensions.json @@ -1,12 +1,12 @@ { "version": 1, - "updated_at": "2026-06-13T20:20:10.905Z", + "updated_at": "2026-06-13T21:22:12.172Z", "entries": [ { "name": "pm-changelog", "directory": "pm-changelog", "scope": "project", - "manifest_version": "2026.6.13", + "manifest_version": "2026.6.13-1", "manifest_entry": "./dist/extension.js", "capabilities": [ "commands", @@ -14,13 +14,13 @@ "schema" ], "installed_at": "2026-05-23T20:26:03.509Z", - "updated_at": "2026-06-13T19:47:04.792Z", + "updated_at": "2026-06-13T21:21:47.904Z", "source": { "kind": "npm", "input": "npm:pm-changelog", "location": "package", "package": "pm-changelog", - "version": "2026.6.13" + "version": "2026.6.13-1" } } ] diff --git a/.agents/pm/extensions/pm-changelog/CHANGELOG.md b/.agents/pm/extensions/pm-changelog/CHANGELOG.md index 4b57a1ce7..afdd160d4 100644 --- a/.agents/pm/extensions/pm-changelog/CHANGELOG.md +++ b/.agents/pm/extensions/pm-changelog/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 2026.6.13-1 - 2026-06-13 + +### Fixed + +- Prepend merge promotes a stale Unreleased section into the released version instead of duplicating it \(GH \#47\) ([pmc-8ssd](https://github.com/unbraind/pm-changelog/blob/main/.agents/pm/issues/pmc-8ssd.toon)) + ## 2026.6.8 - 2026-06-08 ### Fixed diff --git a/.agents/pm/extensions/pm-changelog/dist/extension.js b/.agents/pm/extensions/pm-changelog/dist/extension.js index 128933b3b..33ad8c041 100644 --- a/.agents/pm/extensions/pm-changelog/dist/extension.js +++ b/.agents/pm/extensions/pm-changelog/dist/extension.js @@ -5,7 +5,7 @@ import { buildChangelogDocument, createChangelog, explainChangelogSelection, mer import { resolveReleaseContext, resolveReleaseTagWindows } from "./release-context.js"; export default defineExtension({ name: "pm-changelog", - version: "2026.6.13", + version: "2026.6.13-1", activate(api) { api.registerCommand({ name: "changelog generate", diff --git a/.agents/pm/extensions/pm-changelog/dist/extension.js.map b/.agents/pm/extensions/pm-changelog/dist/extension.js.map index 3909bb2d0..5eef7c7ad 100644 --- a/.agents/pm/extensions/pm-changelog/dist/extension.js.map +++ b/.agents/pm/extensions/pm-changelog/dist/extension.js.map @@ -1 +1 @@ -{"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"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","sourcesContent":["import { writeFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\n\nimport {\n defineExtension,\n listAllFrontMatter,\n locateItem,\n readLocatedItem,\n readSettings,\n resolveItemTypeRegistry,\n EXIT_CODE,\n PmCliError,\n} from \"@unbrained/pm-cli/sdk\";\n\nimport { buildChangelogDocument, createChangelog, explainChangelogSelection, mergeChangelog, suggestSemver, writeChangelog } from \"./generator.js\";\nimport { resolveReleaseContext, resolveReleaseTagWindows } from \"./release-context.js\";\nimport type { ChangelogGroupBy, ChangelogSectionBy, PmItem } from \"./types.js\";\n\nexport default defineExtension({\n name: \"pm-changelog\",\n version: \"2026.6.13\",\n\n activate(api) {\n api.registerCommand({\n name: \"changelog generate\",\n description: \"Generate a CHANGELOG.md file from pm items.\",\n intent: \"generate changelog release notes from completed pm items\",\n examples: [\n \"pm changelog generate\",\n \"pm changelog generate --release-version 1.2.0\",\n \"pm changelog generate --release-version-from-package --since-previous-tag --until-release-tag\",\n \"pm changelog generate --all-release-tags --mode replace\",\n \"pm changelog generate --output RELEASE_NOTES.md --since 2026-05-01\",\n \"pm changelog generate --stdout --group-by release\",\n \"pm changelog generate --stdout --group-by milestone\",\n \"pm changelog generate --check --mode prepend --release-version 1.2.0\",\n ],\n flags: [\n { long: \"--output\", value_name: \"file\", description: \"Output file path (default: CHANGELOG.md)\" },\n { long: \"--stdout\", description: \"Return markdown instead of writing a file\" },\n { long: \"--title\", value_name: \"text\", description: \"Changelog title (default: Changelog)\" },\n { long: \"--release-version\", value_name: \"version\", description: \"Release/version heading (default: Unreleased)\" },\n { long: \"--release-version-from-package\", description: \"Read release/version heading from nearest package.json\" },\n { long: \"--date\", value_name: \"date\", description: \"Release date (default: resolved tag date when available, otherwise today)\" },\n { long: \"--since\", value_name: \"date\", description: \"Include items changed on or after this date\" },\n { long: \"--since-previous-tag\", description: \"Derive --since from the previous git tag\" },\n { long: \"--until\", value_name: \"date\", description: \"Include items changed on or before this date\" },\n { long: \"--until-release-tag\", description: \"Derive --until from the current release tag when it exists\" },\n { long: \"--all-release-tags\", description: \"Rebuild full history from git release tag windows\" },\n { long: \"--release-tag-pattern\", value_name: \"glob\", description: \"Git tag glob for --all-release-tags (default: v*)\" },\n { long: \"--status\", value_name: \"list\", description: \"Comma-separated statuses (default: closed)\" },\n { long: \"--group-by\", value_name: \"mode\", description: \"version, release, or milestone (default: version)\" },\n { long: \"--section-by\", value_name: \"mode\", description: \"Within-release grouping: category, type, status, or label (default: category)\" },\n { long: \"--conventional\", description: \"Use Conventional-Commits headings (Features/Bug Fixes/...) for category grouping\" },\n { long: \"--contributors\", description: \"Append a Contributors list per release from item assignee/author\" },\n { long: \"--limit\", value_name: \"n\", description: \"Keep only the most recent N release sections (history modes only)\" },\n { long: \"--since-version\", value_name: \"version\", description: \"Keep only releases at or newer than this version (history modes only)\" },\n { long: \"--breaking-changes\", description: \"Emit a Breaking Changes section listing items detected as breaking\" },\n { long: \"--suggest-semver\", description: \"Return a suggested semver bump (major/minor/patch); never writes the changelog\" },\n { long: \"--body-preview\", value_name: \"n\", description: \"Append the first N chars of each item body to its entry\" },\n { long: \"--emoji-prefix\", description: \"Prefix section headings with conventional emoji (Added 🎉, Fixed 🐛, ...)\" },\n { long: \"--include-metadata\", description: \"Append compact item metadata (type/status/priority/release/milestone) to each entry\" },\n { long: \"--changelog-json\", description: \"Return the full structured changelog document (releases->sections->items)\" },\n { long: \"--explain\", description: \"Return item-selection diagnostics (counts, exclusions, hints)\" },\n { long: \"--mode\", value_name: \"mode\", description: \"replace or prepend existing changelog (default: replace)\" },\n { long: \"--include-empty\", description: \"Emit an empty release section when no items match\" },\n { long: \"--include-links\", description: \"Include item URLs in generated entries (default: false)\" },\n { long: \"--item-url-base\", value_name: \"url\", description: \"Make item IDs clickable links to .toon files under the base URL\" },\n { long: \"--check\", description: \"Do not write; report whether the changelog would change\" },\n ],\n async run(ctx) {\n const output = (ctx.options[\"output\"] as string | undefined) ?? \"CHANGELOG.md\";\n const stdout = Boolean(ctx.options[\"stdout\"]);\n const groupByOption = stringOption(ctx.options, \"group-by\", \"groupBy\") ?? \"version\";\n const modeOption = (ctx.options[\"mode\"] as string | undefined) ?? \"replace\";\n\n // Throw (with a numeric exitCode) rather than returning { error }: the\n // runtime treats a returned object as a successful run (exit 0), so a\n // returned error silently passed validation failures. A PmCliError\n // carries its exitCode so the handler exits non-zero and runs once.\n if (groupByOption !== \"version\" && groupByOption !== \"release\" && groupByOption !== \"milestone\") {\n throw new PmCliError(\"--group-by must be 'version', 'release', or 'milestone'\", EXIT_CODE.USAGE);\n }\n if (modeOption !== \"replace\" && modeOption !== \"prepend\") {\n throw new PmCliError(\"--mode must be 'replace' or 'prepend'\", EXIT_CODE.USAGE);\n }\n const sectionByOption = stringOption(ctx.options, \"section-by\", \"sectionBy\") ?? \"category\";\n if (sectionByOption !== \"category\" && sectionByOption !== \"type\" && sectionByOption !== \"status\" && sectionByOption !== \"label\") {\n throw new PmCliError(\"--section-by must be 'category', 'type', 'status', or 'label'\", EXIT_CODE.USAGE);\n }\n const limitValue = parseLimitOption(ctx.options);\n const groupBy: ChangelogGroupBy = groupByOption;\n const sectionBy: ChangelogSectionBy = sectionByOption;\n const mode: \"replace\" | \"prepend\" = modeOption;\n\n const statuses = (ctx.options[\"status\"] as string | undefined)\n ?.split(\",\")\n .map((status) => status.trim())\n .filter(Boolean);\n\n const allReleaseTags = booleanOption(ctx.options, \"all-release-tags\", \"allReleaseTags\");\n const releaseVersion = stringOption(ctx.options, \"release-version\", \"releaseVersion\");\n const titleOption = stringOption(ctx.options, \"title\", \"title\");\n const dateOption = stringOption(ctx.options, \"date\", \"date\");\n const sinceOption = stringOption(ctx.options, \"since\", \"since\");\n const untilOption = stringOption(ctx.options, \"until\", \"until\");\n const releaseContext = allReleaseTags\n ? { version: undefined, date: undefined, since: undefined, until: undefined }\n : resolveReleaseContext({\n cwd: ctx.pm_root,\n version: releaseVersion,\n versionFromPackage: booleanOption(ctx.options, \"release-version-from-package\", \"releaseVersionFromPackage\"),\n since: sinceOption,\n sincePreviousTag: booleanOption(ctx.options, \"since-previous-tag\", \"sincePreviousTag\"),\n until: untilOption,\n untilReleaseTag: booleanOption(ctx.options, \"until-release-tag\", \"untilReleaseTag\"),\n });\n const releaseWindows = allReleaseTags\n ? resolveReleaseTagWindows({\n cwd: ctx.pm_root,\n tagPattern: stringOption(ctx.options, \"release-tag-pattern\", \"releaseTagPattern\"),\n pendingVersion: releaseVersion,\n pendingTimestamp: untilOption ?? dateOption,\n })\n : undefined;\n\n const items = (await listAllFrontMatter(ctx.pm_root)) as PmItem[];\n const bodyPreview = parseBodyPreviewOption(ctx.options);\n // listAllFrontMatter omits item bodies, so --body-preview would silently\n // render nothing (GH #27). Load bodies on demand only when previewing.\n if (bodyPreview !== undefined && bodyPreview > 0) {\n await enrichItemBodies(ctx.pm_root, items);\n }\n const generationOptions = {\n items,\n title: titleOption,\n version: releaseContext.version,\n date: dateOption ?? releaseContext.date,\n since: releaseContext.since,\n until: releaseContext.until,\n releaseWindows,\n includeStatuses: statuses,\n groupBy,\n sectionBy,\n conventional: booleanOption(ctx.options, \"conventional\", \"conventional\"),\n contributors: booleanOption(ctx.options, \"contributors\", \"contributors\"),\n limit: limitValue,\n sinceVersion: stringOption(ctx.options, \"since-version\", \"sinceVersion\"),\n breakingChanges: booleanOption(ctx.options, \"breaking-changes\", \"breakingChanges\"),\n bodyPreview,\n emojiPrefix: booleanOption(ctx.options, \"emoji-prefix\", \"emojiPrefix\"),\n includeMetadata: booleanOption(ctx.options, \"include-metadata\", \"includeMetadata\"),\n suggestSemver: booleanOption(ctx.options, \"suggest-semver\", \"suggestSemver\"),\n includeEmpty: booleanOption(ctx.options, \"include-empty\", \"includeEmpty\"),\n includeLinks: booleanOption(ctx.options, \"include-links\", \"includeLinks\"),\n itemUrlBase: stringOption(ctx.options, \"item-url-base\", \"itemUrlBase\"),\n };\n const selectionReport = booleanOption(ctx.options, \"explain\", \"explain\")\n ? explainChangelogSelection(generationOptions)\n : undefined;\n\n // OPT-IN (`--changelog-json`): structured document; never writes a file.\n if (booleanOption(ctx.options, \"changelog-json\", \"changelogJson\")) {\n const document = buildChangelogDocument(generationOptions);\n return {\n document,\n format: \"json\",\n item_count: document.item_count,\n ...(selectionReport ? { selection_report: selectionReport } : {}),\n };\n }\n\n // OPT-IN (`--suggest-semver`) standalone: emit only the semver analysis;\n // never writes a file and never alters default markdown.\n if (booleanOption(ctx.options, \"suggest-semver\", \"suggestSemver\")) {\n const suggestion = suggestSemver(generationOptions);\n return {\n suggested_semver: suggestion,\n format: \"json\",\n ...(selectionReport ? { selection_report: selectionReport } : {}),\n };\n }\n\n const generated = createChangelog(generationOptions);\n\n if (stdout) {\n const merged = mode === \"prepend\"\n ? mergeChangelog(undefined, generated.markdown, { title: titleOption })\n : { markdown: generated.markdown, action: \"replaced\" as const, changed: true };\n return {\n changelog: merged.markdown,\n action: merged.action,\n changed: merged.changed,\n item_count: generated.itemCount,\n ...(selectionReport ? { selection_report: selectionReport } : {}),\n };\n }\n\n const result = writeChangelog({\n ...generationOptions,\n output,\n mode,\n check: Boolean(ctx.options[\"check\"]),\n });\n if (result.changed && Boolean(ctx.options[\"check\"])) {\n throw new PmCliError(`Changelog is out of date: ${result.output}`, EXIT_CODE.GENERIC_FAILURE);\n }\n return {\n file: result.output,\n action: result.action,\n changed: result.changed,\n item_count: result.itemCount,\n bytes: result.bytes,\n check: Boolean(ctx.options[\"check\"]),\n ...(selectionReport ? { selection_report: selectionReport } : {}),\n };\n },\n });\n\n // -----------------------------------------------------------------------\n // Exporter: `pm changelog export` — native export pipeline.\n // Reuses the same generation core as `changelog generate` (whose default\n // output is intentionally left byte-identical). Adds --format md|json and a\n // --release-notes concise mode. Does NOT write CHANGELOG.md unless --output\n // is given, so it is side-effect free by default.\n // -----------------------------------------------------------------------\n const changelogExportMetadata = {\n description: \"Export changelog or release notes through the pm import/export pipeline.\",\n intent: \"export changelog release notes as markdown or json\",\n examples: [\n \"pm changelog export\",\n \"pm changelog export --format json\",\n \"pm changelog export --release-notes --since-previous-tag --until-release-tag\",\n \"pm changelog export --output RELEASE_NOTES.md --release-version-from-package\",\n ],\n flags: [\n { long: \"--format\", value_name: \"md|json\", description: \"Export format (default: md)\" },\n { long: \"--output\", value_name: \"file\", description: \"Write output to a file instead of stdout\" },\n { long: \"--release-notes\", description: \"Use a concise release-notes title and output shape\" },\n { long: \"--title\", value_name: \"text\", description: \"Output title (default: Changelog or Release Notes)\" },\n { long: \"--release-version\", value_name: \"version\", description: \"Release/version heading (default: Unreleased)\" },\n { long: \"--release-version-from-package\", description: \"Read release/version heading from nearest package.json\" },\n { long: \"--date\", value_name: \"date\", description: \"Release date (default: resolved tag date when available, otherwise today)\" },\n { long: \"--since\", value_name: \"date\", description: \"Include items changed on or after this date\" },\n { long: \"--since-previous-tag\", description: \"Derive --since from the previous git tag\" },\n { long: \"--until\", value_name: \"date\", description: \"Include items changed on or before this date\" },\n { long: \"--until-release-tag\", description: \"Derive --until from the current release tag when it exists\" },\n { long: \"--status\", value_name: \"list\", description: \"Comma-separated statuses (default: closed)\" },\n { long: \"--group-by\", value_name: \"mode\", description: \"version, release, or milestone (default: version)\" },\n { long: \"--include-empty\", description: \"Emit an empty release section when no items match\" },\n { long: \"--include-links\", description: \"Include item URLs in generated entries (default: false)\" },\n { long: \"--include-metadata\", description: \"Append compact item metadata (type/status/priority/release/milestone) to each entry\" },\n { long: \"--item-url-base\", value_name: \"url\", description: \"Make item IDs clickable links to .toon files under the base URL\" },\n ],\n };\n const registerExporterWithMetadata = api.registerExporter as unknown as (\n name: string,\n exporter: Parameters[1],\n options: typeof changelogExportMetadata,\n ) => void;\n\n registerExporterWithMetadata(\"changelog\", async (ctx) => {\n const format = (stringOption(ctx.options, \"format\", \"format\") ?? \"md\").toLowerCase();\n if (format !== \"md\" && format !== \"json\") {\n throw new PmCliError(\"--format must be 'md' or 'json'\", EXIT_CODE.USAGE);\n }\n const groupByOption = stringOption(ctx.options, \"group-by\", \"groupBy\") ?? \"version\";\n if (groupByOption !== \"version\" && groupByOption !== \"release\" && groupByOption !== \"milestone\") {\n throw new PmCliError(\"--group-by must be 'version', 'release', or 'milestone'\", EXIT_CODE.USAGE);\n }\n const releaseNotes = booleanOption(ctx.options, \"release-notes\", \"releaseNotes\");\n const releaseVersion = stringOption(ctx.options, \"release-version\", \"releaseVersion\");\n const sinceOption = stringOption(ctx.options, \"since\", \"since\");\n const untilOption = stringOption(ctx.options, \"until\", \"until\");\n const statuses = (ctx.options[\"status\"] as string | undefined)\n ?.split(\",\").map((s) => s.trim()).filter(Boolean);\n\n const releaseContext = resolveReleaseContext({\n cwd: ctx.pm_root,\n version: releaseVersion,\n versionFromPackage: booleanOption(ctx.options, \"release-version-from-package\", \"releaseVersionFromPackage\"),\n since: sinceOption,\n sincePreviousTag: booleanOption(ctx.options, \"since-previous-tag\", \"sincePreviousTag\"),\n until: untilOption,\n untilReleaseTag: booleanOption(ctx.options, \"until-release-tag\", \"untilReleaseTag\"),\n });\n\n const items = await listAllFrontMatter(ctx.pm_root);\n const generated = createChangelog({\n items,\n title: stringOption(ctx.options, \"title\", \"title\") ?? (releaseNotes ? \"Release Notes\" : undefined),\n version: releaseContext.version,\n date: stringOption(ctx.options, \"date\", \"date\") ?? releaseContext.date,\n since: releaseContext.since,\n until: releaseContext.until,\n includeStatuses: statuses,\n groupBy: groupByOption as ChangelogGroupBy,\n includeEmpty: booleanOption(ctx.options, \"include-empty\", \"includeEmpty\"),\n includeLinks: booleanOption(ctx.options, \"include-links\", \"includeLinks\"),\n includeMetadata: booleanOption(ctx.options, \"include-metadata\", \"includeMetadata\"),\n itemUrlBase: stringOption(ctx.options, \"item-url-base\", \"itemUrlBase\"),\n });\n\n const outputPath = stringOption(ctx.options, \"output\", \"output\");\n if (format === \"json\") {\n const payload = {\n version: releaseContext.version ?? \"Unreleased\",\n item_count: generated.itemCount,\n group_by: groupByOption,\n markdown: generated.markdown,\n };\n if (outputPath) {\n writeFileSync(resolve(outputPath), JSON.stringify(payload, null, 2) + \"\\n\", \"utf-8\");\n return { file: outputPath, format: \"json\", item_count: generated.itemCount };\n }\n return payload;\n }\n\n if (outputPath) {\n writeFileSync(resolve(outputPath), generated.markdown.endsWith(\"\\n\") ? generated.markdown : generated.markdown + \"\\n\", \"utf-8\");\n return { file: outputPath, format: \"markdown\", item_count: generated.itemCount };\n }\n return { changelog: generated.markdown, format: \"markdown\", item_count: generated.itemCount };\n }, changelogExportMetadata);\n if (api.registerExporter.length < 3 && typeof api.registerFlags === \"function\") {\n api.registerFlags(\"changelog export\", changelogExportMetadata.flags);\n }\n },\n});\n\n/**\n * Best-effort enrichment of front-matter items with their on-disk body, used so\n * `--body-preview` renders real body content in the extension path (GH #27).\n * `listAllFrontMatter` omits bodies, so each item is re-read via the public SDK\n * locate/read helpers. Items already carrying a body are skipped, and any\n * per-item read failure is swallowed so changelog generation never breaks.\n */\nasync function enrichItemBodies(pmRoot: string, items: PmItem[]): Promise {\n let typeToFolder: Record;\n let idPrefix: string;\n let format: Awaited>[\"item_format\"];\n try {\n const settings = await readSettings(pmRoot);\n typeToFolder = resolveItemTypeRegistry(settings).type_to_folder;\n idPrefix = settings.id_prefix;\n format = settings.item_format;\n } catch {\n return; // cannot resolve settings/registry → leave front matter as-is\n }\n\n const loadBody = async (item: PmItem): Promise => {\n if (!item.id) return;\n if (typeof item.body === \"string\" && item.body.trim() !== \"\") return;\n try {\n const located = await locateItem(pmRoot, item.id, idPrefix, format, typeToFolder);\n if (!located) return;\n const { document } = await readLocatedItem(located);\n if (typeof document.body === \"string\" && document.body.trim() !== \"\") {\n item.body = document.body;\n }\n } catch {\n // best-effort: a single unreadable item must not fail generation\n }\n };\n\n // Bound concurrency so a large workspace can't exhaust file descriptors\n // (EMFILE) by issuing one locate+read per item all at once.\n const CONCURRENCY_LIMIT = 16;\n for (let i = 0; i < items.length; i += CONCURRENCY_LIMIT) {\n await Promise.all(items.slice(i, i + CONCURRENCY_LIMIT).map(loadBody));\n }\n}\n\nfunction stringOption(options: Record, kebabKey: string, camelKey: string): string | undefined {\n const value = options[kebabKey] ?? options[camelKey];\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction booleanOption(options: Record, kebabKey: string, camelKey: string): boolean {\n return Boolean(options[kebabKey] ?? options[camelKey]);\n}\n\nfunction parseLimitOption(options: Record): number | undefined {\n const raw = options[\"limit\"];\n if (raw === undefined || raw === null || raw === \"\") return undefined;\n const parsed = typeof raw === \"number\" ? raw : Number.parseInt(String(raw), 10);\n if (!Number.isInteger(parsed) || parsed < 1) {\n throw new PmCliError(\"--limit must be a positive integer\", EXIT_CODE.USAGE);\n }\n return parsed;\n}\n\nfunction parseBodyPreviewOption(options: Record): number | undefined {\n const raw = options[\"body-preview\"] ?? options[\"bodyPreview\"];\n if (raw === undefined || raw === null || raw === \"\") return undefined;\n const parsed = typeof raw === \"number\" ? raw : Number.parseInt(String(raw), 10);\n if (!Number.isInteger(parsed) || parsed < 1) {\n throw new PmCliError(\"--body-preview must be a positive integer\", EXIT_CODE.USAGE);\n }\n return parsed;\n}\n"]} \ No newline at end of file +{"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"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","sourcesContent":["import { writeFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\n\nimport {\n defineExtension,\n listAllFrontMatter,\n locateItem,\n readLocatedItem,\n readSettings,\n resolveItemTypeRegistry,\n EXIT_CODE,\n PmCliError,\n} from \"@unbrained/pm-cli/sdk\";\n\nimport { buildChangelogDocument, createChangelog, explainChangelogSelection, mergeChangelog, suggestSemver, writeChangelog } from \"./generator.js\";\nimport { resolveReleaseContext, resolveReleaseTagWindows } from \"./release-context.js\";\nimport type { ChangelogGroupBy, ChangelogSectionBy, PmItem } from \"./types.js\";\n\nexport default defineExtension({\n name: \"pm-changelog\",\n version: \"2026.6.13-1\",\n\n activate(api) {\n api.registerCommand({\n name: \"changelog generate\",\n description: \"Generate a CHANGELOG.md file from pm items.\",\n intent: \"generate changelog release notes from completed pm items\",\n examples: [\n \"pm changelog generate\",\n \"pm changelog generate --release-version 1.2.0\",\n \"pm changelog generate --release-version-from-package --since-previous-tag --until-release-tag\",\n \"pm changelog generate --all-release-tags --mode replace\",\n \"pm changelog generate --output RELEASE_NOTES.md --since 2026-05-01\",\n \"pm changelog generate --stdout --group-by release\",\n \"pm changelog generate --stdout --group-by milestone\",\n \"pm changelog generate --check --mode prepend --release-version 1.2.0\",\n ],\n flags: [\n { long: \"--output\", value_name: \"file\", description: \"Output file path (default: CHANGELOG.md)\" },\n { long: \"--stdout\", description: \"Return markdown instead of writing a file\" },\n { long: \"--title\", value_name: \"text\", description: \"Changelog title (default: Changelog)\" },\n { long: \"--release-version\", value_name: \"version\", description: \"Release/version heading (default: Unreleased)\" },\n { long: \"--release-version-from-package\", description: \"Read release/version heading from nearest package.json\" },\n { long: \"--date\", value_name: \"date\", description: \"Release date (default: resolved tag date when available, otherwise today)\" },\n { long: \"--since\", value_name: \"date\", description: \"Include items changed on or after this date\" },\n { long: \"--since-previous-tag\", description: \"Derive --since from the previous git tag\" },\n { long: \"--until\", value_name: \"date\", description: \"Include items changed on or before this date\" },\n { long: \"--until-release-tag\", description: \"Derive --until from the current release tag when it exists\" },\n { long: \"--all-release-tags\", description: \"Rebuild full history from git release tag windows\" },\n { long: \"--release-tag-pattern\", value_name: \"glob\", description: \"Git tag glob for --all-release-tags (default: v*)\" },\n { long: \"--status\", value_name: \"list\", description: \"Comma-separated statuses (default: closed)\" },\n { long: \"--group-by\", value_name: \"mode\", description: \"version, release, or milestone (default: version)\" },\n { long: \"--section-by\", value_name: \"mode\", description: \"Within-release grouping: category, type, status, or label (default: category)\" },\n { long: \"--conventional\", description: \"Use Conventional-Commits headings (Features/Bug Fixes/...) for category grouping\" },\n { long: \"--contributors\", description: \"Append a Contributors list per release from item assignee/author\" },\n { long: \"--limit\", value_name: \"n\", description: \"Keep only the most recent N release sections (history modes only)\" },\n { long: \"--since-version\", value_name: \"version\", description: \"Keep only releases at or newer than this version (history modes only)\" },\n { long: \"--breaking-changes\", description: \"Emit a Breaking Changes section listing items detected as breaking\" },\n { long: \"--suggest-semver\", description: \"Return a suggested semver bump (major/minor/patch); never writes the changelog\" },\n { long: \"--body-preview\", value_name: \"n\", description: \"Append the first N chars of each item body to its entry\" },\n { long: \"--emoji-prefix\", description: \"Prefix section headings with conventional emoji (Added 🎉, Fixed 🐛, ...)\" },\n { long: \"--include-metadata\", description: \"Append compact item metadata (type/status/priority/release/milestone) to each entry\" },\n { long: \"--changelog-json\", description: \"Return the full structured changelog document (releases->sections->items)\" },\n { long: \"--explain\", description: \"Return item-selection diagnostics (counts, exclusions, hints)\" },\n { long: \"--mode\", value_name: \"mode\", description: \"replace or prepend existing changelog (default: replace)\" },\n { long: \"--include-empty\", description: \"Emit an empty release section when no items match\" },\n { long: \"--include-links\", description: \"Include item URLs in generated entries (default: false)\" },\n { long: \"--item-url-base\", value_name: \"url\", description: \"Make item IDs clickable links to .toon files under the base URL\" },\n { long: \"--check\", description: \"Do not write; report whether the changelog would change\" },\n ],\n async run(ctx) {\n const output = (ctx.options[\"output\"] as string | undefined) ?? \"CHANGELOG.md\";\n const stdout = Boolean(ctx.options[\"stdout\"]);\n const groupByOption = stringOption(ctx.options, \"group-by\", \"groupBy\") ?? \"version\";\n const modeOption = (ctx.options[\"mode\"] as string | undefined) ?? \"replace\";\n\n // Throw (with a numeric exitCode) rather than returning { error }: the\n // runtime treats a returned object as a successful run (exit 0), so a\n // returned error silently passed validation failures. A PmCliError\n // carries its exitCode so the handler exits non-zero and runs once.\n if (groupByOption !== \"version\" && groupByOption !== \"release\" && groupByOption !== \"milestone\") {\n throw new PmCliError(\"--group-by must be 'version', 'release', or 'milestone'\", EXIT_CODE.USAGE);\n }\n if (modeOption !== \"replace\" && modeOption !== \"prepend\") {\n throw new PmCliError(\"--mode must be 'replace' or 'prepend'\", EXIT_CODE.USAGE);\n }\n const sectionByOption = stringOption(ctx.options, \"section-by\", \"sectionBy\") ?? \"category\";\n if (sectionByOption !== \"category\" && sectionByOption !== \"type\" && sectionByOption !== \"status\" && sectionByOption !== \"label\") {\n throw new PmCliError(\"--section-by must be 'category', 'type', 'status', or 'label'\", EXIT_CODE.USAGE);\n }\n const limitValue = parseLimitOption(ctx.options);\n const groupBy: ChangelogGroupBy = groupByOption;\n const sectionBy: ChangelogSectionBy = sectionByOption;\n const mode: \"replace\" | \"prepend\" = modeOption;\n\n const statuses = (ctx.options[\"status\"] as string | undefined)\n ?.split(\",\")\n .map((status) => status.trim())\n .filter(Boolean);\n\n const allReleaseTags = booleanOption(ctx.options, \"all-release-tags\", \"allReleaseTags\");\n const releaseVersion = stringOption(ctx.options, \"release-version\", \"releaseVersion\");\n const titleOption = stringOption(ctx.options, \"title\", \"title\");\n const dateOption = stringOption(ctx.options, \"date\", \"date\");\n const sinceOption = stringOption(ctx.options, \"since\", \"since\");\n const untilOption = stringOption(ctx.options, \"until\", \"until\");\n const releaseContext = allReleaseTags\n ? { version: undefined, date: undefined, since: undefined, until: undefined }\n : resolveReleaseContext({\n cwd: ctx.pm_root,\n version: releaseVersion,\n versionFromPackage: booleanOption(ctx.options, \"release-version-from-package\", \"releaseVersionFromPackage\"),\n since: sinceOption,\n sincePreviousTag: booleanOption(ctx.options, \"since-previous-tag\", \"sincePreviousTag\"),\n until: untilOption,\n untilReleaseTag: booleanOption(ctx.options, \"until-release-tag\", \"untilReleaseTag\"),\n });\n const releaseWindows = allReleaseTags\n ? resolveReleaseTagWindows({\n cwd: ctx.pm_root,\n tagPattern: stringOption(ctx.options, \"release-tag-pattern\", \"releaseTagPattern\"),\n pendingVersion: releaseVersion,\n pendingTimestamp: untilOption ?? dateOption,\n })\n : undefined;\n\n const items = (await listAllFrontMatter(ctx.pm_root)) as PmItem[];\n const bodyPreview = parseBodyPreviewOption(ctx.options);\n // listAllFrontMatter omits item bodies, so --body-preview would silently\n // render nothing (GH #27). Load bodies on demand only when previewing.\n if (bodyPreview !== undefined && bodyPreview > 0) {\n await enrichItemBodies(ctx.pm_root, items);\n }\n const generationOptions = {\n items,\n title: titleOption,\n version: releaseContext.version,\n date: dateOption ?? releaseContext.date,\n since: releaseContext.since,\n until: releaseContext.until,\n releaseWindows,\n includeStatuses: statuses,\n groupBy,\n sectionBy,\n conventional: booleanOption(ctx.options, \"conventional\", \"conventional\"),\n contributors: booleanOption(ctx.options, \"contributors\", \"contributors\"),\n limit: limitValue,\n sinceVersion: stringOption(ctx.options, \"since-version\", \"sinceVersion\"),\n breakingChanges: booleanOption(ctx.options, \"breaking-changes\", \"breakingChanges\"),\n bodyPreview,\n emojiPrefix: booleanOption(ctx.options, \"emoji-prefix\", \"emojiPrefix\"),\n includeMetadata: booleanOption(ctx.options, \"include-metadata\", \"includeMetadata\"),\n suggestSemver: booleanOption(ctx.options, \"suggest-semver\", \"suggestSemver\"),\n includeEmpty: booleanOption(ctx.options, \"include-empty\", \"includeEmpty\"),\n includeLinks: booleanOption(ctx.options, \"include-links\", \"includeLinks\"),\n itemUrlBase: stringOption(ctx.options, \"item-url-base\", \"itemUrlBase\"),\n };\n const selectionReport = booleanOption(ctx.options, \"explain\", \"explain\")\n ? explainChangelogSelection(generationOptions)\n : undefined;\n\n // OPT-IN (`--changelog-json`): structured document; never writes a file.\n if (booleanOption(ctx.options, \"changelog-json\", \"changelogJson\")) {\n const document = buildChangelogDocument(generationOptions);\n return {\n document,\n format: \"json\",\n item_count: document.item_count,\n ...(selectionReport ? { selection_report: selectionReport } : {}),\n };\n }\n\n // OPT-IN (`--suggest-semver`) standalone: emit only the semver analysis;\n // never writes a file and never alters default markdown.\n if (booleanOption(ctx.options, \"suggest-semver\", \"suggestSemver\")) {\n const suggestion = suggestSemver(generationOptions);\n return {\n suggested_semver: suggestion,\n format: \"json\",\n ...(selectionReport ? { selection_report: selectionReport } : {}),\n };\n }\n\n const generated = createChangelog(generationOptions);\n\n if (stdout) {\n const merged = mode === \"prepend\"\n ? mergeChangelog(undefined, generated.markdown, { title: titleOption })\n : { markdown: generated.markdown, action: \"replaced\" as const, changed: true };\n return {\n changelog: merged.markdown,\n action: merged.action,\n changed: merged.changed,\n item_count: generated.itemCount,\n ...(selectionReport ? { selection_report: selectionReport } : {}),\n };\n }\n\n const result = writeChangelog({\n ...generationOptions,\n output,\n mode,\n check: Boolean(ctx.options[\"check\"]),\n });\n if (result.changed && Boolean(ctx.options[\"check\"])) {\n throw new PmCliError(`Changelog is out of date: ${result.output}`, EXIT_CODE.GENERIC_FAILURE);\n }\n return {\n file: result.output,\n action: result.action,\n changed: result.changed,\n item_count: result.itemCount,\n bytes: result.bytes,\n check: Boolean(ctx.options[\"check\"]),\n ...(selectionReport ? { selection_report: selectionReport } : {}),\n };\n },\n });\n\n // -----------------------------------------------------------------------\n // Exporter: `pm changelog export` — native export pipeline.\n // Reuses the same generation core as `changelog generate` (whose default\n // output is intentionally left byte-identical). Adds --format md|json and a\n // --release-notes concise mode. Does NOT write CHANGELOG.md unless --output\n // is given, so it is side-effect free by default.\n // -----------------------------------------------------------------------\n const changelogExportMetadata = {\n description: \"Export changelog or release notes through the pm import/export pipeline.\",\n intent: \"export changelog release notes as markdown or json\",\n examples: [\n \"pm changelog export\",\n \"pm changelog export --format json\",\n \"pm changelog export --release-notes --since-previous-tag --until-release-tag\",\n \"pm changelog export --output RELEASE_NOTES.md --release-version-from-package\",\n ],\n flags: [\n { long: \"--format\", value_name: \"md|json\", description: \"Export format (default: md)\" },\n { long: \"--output\", value_name: \"file\", description: \"Write output to a file instead of stdout\" },\n { long: \"--release-notes\", description: \"Use a concise release-notes title and output shape\" },\n { long: \"--title\", value_name: \"text\", description: \"Output title (default: Changelog or Release Notes)\" },\n { long: \"--release-version\", value_name: \"version\", description: \"Release/version heading (default: Unreleased)\" },\n { long: \"--release-version-from-package\", description: \"Read release/version heading from nearest package.json\" },\n { long: \"--date\", value_name: \"date\", description: \"Release date (default: resolved tag date when available, otherwise today)\" },\n { long: \"--since\", value_name: \"date\", description: \"Include items changed on or after this date\" },\n { long: \"--since-previous-tag\", description: \"Derive --since from the previous git tag\" },\n { long: \"--until\", value_name: \"date\", description: \"Include items changed on or before this date\" },\n { long: \"--until-release-tag\", description: \"Derive --until from the current release tag when it exists\" },\n { long: \"--status\", value_name: \"list\", description: \"Comma-separated statuses (default: closed)\" },\n { long: \"--group-by\", value_name: \"mode\", description: \"version, release, or milestone (default: version)\" },\n { long: \"--include-empty\", description: \"Emit an empty release section when no items match\" },\n { long: \"--include-links\", description: \"Include item URLs in generated entries (default: false)\" },\n { long: \"--include-metadata\", description: \"Append compact item metadata (type/status/priority/release/milestone) to each entry\" },\n { long: \"--item-url-base\", value_name: \"url\", description: \"Make item IDs clickable links to .toon files under the base URL\" },\n ],\n };\n const registerExporterWithMetadata = api.registerExporter as unknown as (\n name: string,\n exporter: Parameters[1],\n options: typeof changelogExportMetadata,\n ) => void;\n\n registerExporterWithMetadata(\"changelog\", async (ctx) => {\n const format = (stringOption(ctx.options, \"format\", \"format\") ?? \"md\").toLowerCase();\n if (format !== \"md\" && format !== \"json\") {\n throw new PmCliError(\"--format must be 'md' or 'json'\", EXIT_CODE.USAGE);\n }\n const groupByOption = stringOption(ctx.options, \"group-by\", \"groupBy\") ?? \"version\";\n if (groupByOption !== \"version\" && groupByOption !== \"release\" && groupByOption !== \"milestone\") {\n throw new PmCliError(\"--group-by must be 'version', 'release', or 'milestone'\", EXIT_CODE.USAGE);\n }\n const releaseNotes = booleanOption(ctx.options, \"release-notes\", \"releaseNotes\");\n const releaseVersion = stringOption(ctx.options, \"release-version\", \"releaseVersion\");\n const sinceOption = stringOption(ctx.options, \"since\", \"since\");\n const untilOption = stringOption(ctx.options, \"until\", \"until\");\n const statuses = (ctx.options[\"status\"] as string | undefined)\n ?.split(\",\").map((s) => s.trim()).filter(Boolean);\n\n const releaseContext = resolveReleaseContext({\n cwd: ctx.pm_root,\n version: releaseVersion,\n versionFromPackage: booleanOption(ctx.options, \"release-version-from-package\", \"releaseVersionFromPackage\"),\n since: sinceOption,\n sincePreviousTag: booleanOption(ctx.options, \"since-previous-tag\", \"sincePreviousTag\"),\n until: untilOption,\n untilReleaseTag: booleanOption(ctx.options, \"until-release-tag\", \"untilReleaseTag\"),\n });\n\n const items = await listAllFrontMatter(ctx.pm_root);\n const generated = createChangelog({\n items,\n title: stringOption(ctx.options, \"title\", \"title\") ?? (releaseNotes ? \"Release Notes\" : undefined),\n version: releaseContext.version,\n date: stringOption(ctx.options, \"date\", \"date\") ?? releaseContext.date,\n since: releaseContext.since,\n until: releaseContext.until,\n includeStatuses: statuses,\n groupBy: groupByOption as ChangelogGroupBy,\n includeEmpty: booleanOption(ctx.options, \"include-empty\", \"includeEmpty\"),\n includeLinks: booleanOption(ctx.options, \"include-links\", \"includeLinks\"),\n includeMetadata: booleanOption(ctx.options, \"include-metadata\", \"includeMetadata\"),\n itemUrlBase: stringOption(ctx.options, \"item-url-base\", \"itemUrlBase\"),\n });\n\n const outputPath = stringOption(ctx.options, \"output\", \"output\");\n if (format === \"json\") {\n const payload = {\n version: releaseContext.version ?? \"Unreleased\",\n item_count: generated.itemCount,\n group_by: groupByOption,\n markdown: generated.markdown,\n };\n if (outputPath) {\n writeFileSync(resolve(outputPath), JSON.stringify(payload, null, 2) + \"\\n\", \"utf-8\");\n return { file: outputPath, format: \"json\", item_count: generated.itemCount };\n }\n return payload;\n }\n\n if (outputPath) {\n writeFileSync(resolve(outputPath), generated.markdown.endsWith(\"\\n\") ? generated.markdown : generated.markdown + \"\\n\", \"utf-8\");\n return { file: outputPath, format: \"markdown\", item_count: generated.itemCount };\n }\n return { changelog: generated.markdown, format: \"markdown\", item_count: generated.itemCount };\n }, changelogExportMetadata);\n if (api.registerExporter.length < 3 && typeof api.registerFlags === \"function\") {\n api.registerFlags(\"changelog export\", changelogExportMetadata.flags);\n }\n },\n});\n\n/**\n * Best-effort enrichment of front-matter items with their on-disk body, used so\n * `--body-preview` renders real body content in the extension path (GH #27).\n * `listAllFrontMatter` omits bodies, so each item is re-read via the public SDK\n * locate/read helpers. Items already carrying a body are skipped, and any\n * per-item read failure is swallowed so changelog generation never breaks.\n */\nasync function enrichItemBodies(pmRoot: string, items: PmItem[]): Promise {\n let typeToFolder: Record;\n let idPrefix: string;\n let format: Awaited>[\"item_format\"];\n try {\n const settings = await readSettings(pmRoot);\n typeToFolder = resolveItemTypeRegistry(settings).type_to_folder;\n idPrefix = settings.id_prefix;\n format = settings.item_format;\n } catch {\n return; // cannot resolve settings/registry → leave front matter as-is\n }\n\n const loadBody = async (item: PmItem): Promise => {\n if (!item.id) return;\n if (typeof item.body === \"string\" && item.body.trim() !== \"\") return;\n try {\n const located = await locateItem(pmRoot, item.id, idPrefix, format, typeToFolder);\n if (!located) return;\n const { document } = await readLocatedItem(located);\n if (typeof document.body === \"string\" && document.body.trim() !== \"\") {\n item.body = document.body;\n }\n } catch {\n // best-effort: a single unreadable item must not fail generation\n }\n };\n\n // Bound concurrency so a large workspace can't exhaust file descriptors\n // (EMFILE) by issuing one locate+read per item all at once.\n const CONCURRENCY_LIMIT = 16;\n for (let i = 0; i < items.length; i += CONCURRENCY_LIMIT) {\n await Promise.all(items.slice(i, i + CONCURRENCY_LIMIT).map(loadBody));\n }\n}\n\nfunction stringOption(options: Record, kebabKey: string, camelKey: string): string | undefined {\n const value = options[kebabKey] ?? options[camelKey];\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction booleanOption(options: Record, kebabKey: string, camelKey: string): boolean {\n return Boolean(options[kebabKey] ?? options[camelKey]);\n}\n\nfunction parseLimitOption(options: Record): number | undefined {\n const raw = options[\"limit\"];\n if (raw === undefined || raw === null || raw === \"\") return undefined;\n const parsed = typeof raw === \"number\" ? raw : Number.parseInt(String(raw), 10);\n if (!Number.isInteger(parsed) || parsed < 1) {\n throw new PmCliError(\"--limit must be a positive integer\", EXIT_CODE.USAGE);\n }\n return parsed;\n}\n\nfunction parseBodyPreviewOption(options: Record): number | undefined {\n const raw = options[\"body-preview\"] ?? options[\"bodyPreview\"];\n if (raw === undefined || raw === null || raw === \"\") return undefined;\n const parsed = typeof raw === \"number\" ? raw : Number.parseInt(String(raw), 10);\n if (!Number.isInteger(parsed) || parsed < 1) {\n throw new PmCliError(\"--body-preview must be a positive integer\", EXIT_CODE.USAGE);\n }\n return parsed;\n}\n"]} \ No newline at end of file diff --git a/.agents/pm/extensions/pm-changelog/dist/generator.d.ts.map b/.agents/pm/extensions/pm-changelog/dist/generator.d.ts.map index fbfc84f5d..18bd13a76 100644 --- a/.agents/pm/extensions/pm-changelog/dist/generator.d.ts.map +++ b/.agents/pm/extensions/pm-changelog/dist/generator.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../src/generator.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,iBAAiB,EAKjB,wBAAwB,EAGxB,kBAAkB,EAClB,wBAAwB,EACxB,qBAAqB,EACrB,oBAAoB,EACpB,MAAM,EACN,kBAAkB,EAElB,gBAAgB,EAChB,qBAAqB,EACrB,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAkBpB,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,MAAM,CAE3E;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,wBAAwB,GAAG,kBAAkB,CAmGrF;AAwCD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,wBAAwB,GAAG,iBAAiB,CAgD3F;AAgBD,wBAAgB,cAAc,CAC5B,gBAAgB,EAAE,MAAM,GAAG,SAAS,EACpC,iBAAiB,EAAE,MAAM,EACzB,OAAO,GAAE,qBAA0B,GAClC,oBAAoB,CA4CtB;AAED,wBAAgB,WAAW,CAAC,OAAO,GAAE,kBAAuB,GAAG,MAAM,EAAE,CAqBtE;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,oBAAoB,CAqBnF;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAKtD;AAumBD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,wBAAwB,GAAG,gBAAgB,CAOjF;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,wBAAwB,GAAG,MAAM,EAAE,CAQjF;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,wBAAwB,GAAG,wBAAwB,CA+FrG;AAED,qFAAqF;AACrF,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,gBAAgB,CAoCvE"} \ No newline at end of file +{"version":3,"file":"generator.d.ts","sourceRoot":"","sources":["../src/generator.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,iBAAiB,EAKjB,wBAAwB,EAGxB,kBAAkB,EAClB,wBAAwB,EACxB,qBAAqB,EACrB,oBAAoB,EACpB,MAAM,EACN,kBAAkB,EAElB,gBAAgB,EAChB,qBAAqB,EACrB,oBAAoB,EACrB,MAAM,YAAY,CAAC;AAkBpB,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,MAAM,CAE3E;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,wBAAwB,GAAG,kBAAkB,CAmGrF;AAwCD;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,wBAAwB,GAAG,iBAAiB,CAgD3F;AAgBD,wBAAgB,cAAc,CAC5B,gBAAgB,EAAE,MAAM,GAAG,SAAS,EACpC,iBAAiB,EAAE,MAAM,EACzB,OAAO,GAAE,qBAA0B,GAClC,oBAAoB,CAqEtB;AAED,wBAAgB,WAAW,CAAC,OAAO,GAAE,kBAAuB,GAAG,MAAM,EAAE,CAqBtE;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,oBAAoB,CAqBnF;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAKtD;AAwoBD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,wBAAwB,GAAG,gBAAgB,CAOjF;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,wBAAwB,GAAG,MAAM,EAAE,CAQjF;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,wBAAwB,GAAG,wBAAwB,CA+FrG;AAED,qFAAqF;AACrF,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,gBAAgB,CAoCvE"} \ No newline at end of file diff --git a/.agents/pm/extensions/pm-changelog/dist/generator.js b/.agents/pm/extensions/pm-changelog/dist/generator.js index 633b3bfc3..5b1240b61 100644 --- a/.agents/pm/extensions/pm-changelog/dist/generator.js +++ b/.agents/pm/extensions/pm-changelog/dist/generator.js @@ -234,7 +234,16 @@ export function mergeChangelog(existingMarkdown, generatedMarkdown, options = {} } let next = ensureTitle(existing, options.title); let action = "unchanged"; - for (const releaseSection of releaseSections) { + // Keep a Changelog semantics (issue #47): when a release is generated — i.e. + // the generated output carries a concrete version section and no `Unreleased` + // section of its own — any leading `## Unreleased` section already in the + // changelog is the pending-release section and must be PROMOTED into the + // version it ships in, not left behind as a duplicate alongside the new + // `## ` heading. Only the newest generated section may consume it, + // and never when the generator itself emits an Unreleased section. + const generatedHasUnreleased = releaseSections.some((section) => normalizeReleaseHeadingKey(section.heading) === UNRELEASED_HEADING_KEY); + const canPromoteUnreleased = !generatedHasUnreleased; + for (const [index, releaseSection] of releaseSections.entries()) { const replacement = releaseSection.markdown.trimEnd(); const replaced = replaceReleaseSection(next, releaseSection.heading, replacement); if (replaced.replaced) { @@ -242,7 +251,19 @@ export function mergeChangelog(existingMarkdown, generatedMarkdown, options = {} action = "replaced"; continue; } - next = insertAfterTitle(next, replacement); + // Restrict promotion to the newest generated section (index 0). Otherwise, + // when the newest version already exists (replaced above) an older section + // that is missing could steal the pending `## Unreleased` and overwrite it, + // losing the pending changes (GH #48 review). + if (canPromoteUnreleased && index === 0) { + const promoted = replaceReleaseSection(next, "Unreleased", replacement); + if (promoted.replaced) { + next = promoted.markdown; + action = "replaced"; + continue; + } + } + next = insertReleaseSection(next, releaseSection.heading, replacement); if (action !== "replaced") action = "inserted"; } @@ -503,6 +524,8 @@ function replaceReleaseSection(markdown, heading, replacement) { const merged = after ? `${before}\n\n${replacement}\n\n${after}` : `${before}\n\n${replacement}`; return { markdown: merged, replaced: true }; } +/** Normalized heading key for the pending `Unreleased` section. */ +const UNRELEASED_HEADING_KEY = "unreleased"; function normalizeReleaseHeadingKey(heading) { const trimmed = heading.trim(); const bracketed = trimmed.match(/^\[([^\]]+)\](?:\([^)]+\))?(?:\s+-\s+.+)?$/); @@ -514,6 +537,36 @@ function ensureTitle(markdown, title) { return markdown; return `# ${title ?? DEFAULT_TITLE}\n\n${markdown.trimStart()}`; } +/** + * Insert a release section in chronological position (Unreleased first, then + * newest-to-oldest by version) rather than always at the top. Used by the + * prepend merge when a generated section has no existing heading to replace, + * so a backfilled older release cannot land above newer ones or the pending + * `## Unreleased` section (GH #48 review). + */ +function insertReleaseSection(markdown, heading, replacement) { + const matches = Array.from(markdown.matchAll(/^##\s+(.+)$/gm)); + if (matches.length === 0) + return insertAfterTitle(markdown, replacement); + const newKey = normalizeReleaseHeadingKey(heading); + const insertBefore = matches.find((match) => { + const key = normalizeReleaseHeadingKey(match[1].trim()); + if (key === UNRELEASED_HEADING_KEY) + return false; // never displace the pending section + if (newKey === UNRELEASED_HEADING_KEY) + return true; // a new Unreleased sorts ahead of any version + return compareVersionStrings(newKey, key) > 0; // place before the first strictly-older release + }); + if (!insertBefore) { + return `${markdown.trimEnd()}\n\n${replacement}`; + } + const start = insertBefore.index ?? 0; + const before = markdown.slice(0, start).trimEnd(); + const after = markdown.slice(start).trimStart(); + // `before` is normally the `# Changelog` title (ensureTitle runs first), but + // guard the empty case so we never emit leading blank lines. + return before ? `${before}\n\n${replacement}\n\n${after}` : `${replacement}\n\n${after}`; +} function insertAfterTitle(markdown, releaseSection) { const titleMatch = markdown.match(/^#\s+.+$/m); if (!titleMatch || titleMatch.index === undefined) { diff --git a/.agents/pm/extensions/pm-changelog/dist/generator.js.map b/.agents/pm/extensions/pm-changelog/dist/generator.js.map index 99fca40ce..887595908 100644 --- a/.agents/pm/extensions/pm-changelog/dist/generator.js.map +++ b/.agents/pm/extensions/pm-changelog/dist/generator.js.map @@ -1 +1 @@ -{"version":3,"file":"generator.js","sourceRoot":"","sources":["../src/generator.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawnSync } from \"node:child_process\";\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\n\nimport type {\n ChangelogDocument,\n ChangelogDocumentItem,\n ChangelogDocumentRelease,\n ChangelogDocumentSection,\n ChangelogReleaseWindow,\n ChangelogSelectionReport,\n ChangelogSectionBy,\n ChangelogSection,\n GeneratedChangelog,\n GenerateChangelogOptions,\n MergeChangelogOptions,\n MergeChangelogResult,\n PmItem,\n ReadPmItemsOptions,\n SemverBump,\n SemverSuggestion,\n WriteChangelogOptions,\n WriteChangelogResult,\n} from \"./types.js\";\n\nconst DEFAULT_TITLE = \"Changelog\";\nconst DEFAULT_STATUSES = [\"closed\"];\nconst DEFAULT_PM_JSON_MAX_BUFFER = 64 * 1024 * 1024;\n\nconst CATEGORY_ORDER = [\n \"Added\",\n \"Changed\",\n \"Fixed\",\n \"Removed\",\n \"Security\",\n \"Deprecated\",\n \"Other\",\n] as const;\n\ntype Category = (typeof CATEGORY_ORDER)[number];\n\nexport function generateChangelog(options: GenerateChangelogOptions): string {\n return createChangelog(options).markdown;\n}\n\nexport function createChangelog(options: GenerateChangelogOptions): GeneratedChangelog {\n const title = options.title ?? DEFAULT_TITLE;\n const items = filterItems(options);\n const sections = buildSections(items, options);\n const lines: string[] = [`# ${title}`, \"\"];\n\n if (sections.length === 0) {\n if (options.includeEmpty) {\n const heading = buildVersionHeading(options.version, options.date);\n lines.push(`## ${heading}`, \"\", \"No changes.\", \"\");\n }\n return {\n markdown: lines.join(\"\\n\").trimEnd() + \"\\n\",\n sections,\n itemCount: items.length,\n };\n }\n\n // Apply visibility before limiting so `--limit N` counts N releases that\n // actually render (empty windows like a fresh \"Unreleased\" don't consume a\n // slot). With no limit/since-version flags this is a pure identity pass.\n const candidateSections = options.includeEmpty\n ? sections\n : sections.filter((section) => section.items.length > 0);\n const visibleSections = limitSections(candidateSections, options);\n\n if (visibleSections.length === 0) {\n return {\n markdown: lines.join(\"\\n\").trimEnd() + \"\\n\",\n sections,\n itemCount: 0,\n };\n }\n\n const sectionBy = options.sectionBy ?? \"category\";\n\n for (const section of visibleSections) {\n lines.push(`## ${section.heading}`, \"\");\n if (section.items.length === 0) {\n lines.push(\"No changes.\", \"\");\n continue;\n }\n\n // OPT-IN (`--breaking-changes`): a dedicated heading listing breaking items\n // up front. Items still appear in their normal category/field group below,\n // so this is purely additive and absent by default.\n if (options.breakingChanges) {\n const breaking = section.items.filter(isBreakingItem);\n if (breaking.length > 0) {\n lines.push(`### ${maybeEmoji(\"Breaking Changes\", options)}`, \"\");\n for (const item of breaking) {\n lines.push(`- ${formatItem(item, options)}`);\n }\n lines.push(\"\");\n }\n }\n\n if (sectionBy === \"category\") {\n const grouped = groupByCategory(section.items);\n\n for (const category of CATEGORY_ORDER) {\n const categoryItems = grouped.get(category);\n if (!categoryItems || categoryItems.length === 0) continue;\n\n // OPT-IN: --conventional remaps the heading text only; item order,\n // bucketing, and bullet rendering are untouched, so dropping the flag\n // restores byte-identical output.\n const heading = options.conventional ? CONVENTIONAL_HEADINGS[category] : category;\n lines.push(`### ${maybeEmoji(heading, options)}`, \"\");\n for (const item of categoryItems) {\n lines.push(`- ${formatItem(item, options)}`);\n }\n lines.push(\"\");\n }\n } else {\n for (const group of groupByField(section.items, sectionBy)) {\n lines.push(`### ${maybeEmoji(group.heading, options)}`, \"\");\n for (const item of group.items) {\n lines.push(`- ${formatItem(item, options)}`);\n }\n lines.push(\"\");\n }\n }\n\n if (options.contributors) {\n const names = collectContributors(section.items);\n if (names.length > 0) {\n lines.push(\"### Contributors\", \"\");\n lines.push(names.map((name) => `@${name}`).join(\", \"));\n lines.push(\"\");\n }\n }\n }\n\n return {\n markdown: lines.join(\"\\n\").trimEnd() + \"\\n\",\n sections,\n itemCount: visibleSections.reduce((sum, section) => sum + section.items.length, 0),\n };\n}\n\n/**\n * OPT-IN (`--limit` / `--since-version`): restrict release sections to the\n * most recent N or to those at or newer than a version. Only release-window\n * sections (the `## version - date` history rebuilt by `--all-release-tags`)\n * are eligible; the leading `Unreleased` section is always kept. When neither\n * option is set this is an identity pass, preserving default output exactly.\n */\nfunction limitSections(\n sections: ChangelogSection[],\n options: GenerateChangelogOptions\n): ChangelogSection[] {\n const limit = options.limit && options.limit > 0 ? options.limit : undefined;\n const sinceVersion = options.sinceVersion?.trim()\n ? normalizeReleaseKey(options.sinceVersion)\n : undefined;\n if (limit === undefined && sinceVersion === undefined) return sections;\n if (!options.releaseWindows || options.releaseWindows.length === 0) return sections;\n\n let result = sections;\n if (sinceVersion !== undefined) {\n result = result.filter((section) => {\n const key = sectionVersionKey(section.heading);\n if (key === undefined) return true; // keep Unreleased and unparsable headings\n return compareVersionStrings(key, sinceVersion) >= 0;\n });\n }\n if (limit !== undefined && result.length > limit) {\n result = result.slice(0, limit);\n }\n return result;\n}\n\nfunction sectionVersionKey(heading: string): string | undefined {\n const version = heading.split(/\\s+-\\s+/, 1)[0]?.trim() ?? heading.trim();\n if (!version || version.toLowerCase() === \"unreleased\") return undefined;\n return normalizeReleaseKey(version);\n}\n\n/**\n * OPT-IN (`--changelog-json`): build a structured representation of the\n * changelog (releases -> sections -> items) for downstream tooling. This is\n * deliberately distinct from the `--json` CLI summary (action/bytes/changed)\n * and from the `changelog export --format json` payload (which wraps markdown).\n * It applies the same filtering, limiting and grouping as the markdown path so\n * the two stay in sync, but emits structured data instead of rendered text.\n */\nexport function buildChangelogDocument(options: GenerateChangelogOptions): ChangelogDocument {\n const filtered = filterItems(options);\n const sections = buildSections(filtered, options);\n const candidateSections = options.includeEmpty\n ? sections\n : sections.filter((section) => section.items.length > 0);\n const visibleSections = limitSections(candidateSections, options);\n const sectionBy = options.sectionBy ?? \"category\";\n\n const releases: ChangelogDocumentRelease[] = visibleSections.map((section) => {\n const sectionGroups: ChangelogDocumentSection[] = [];\n if (sectionBy === \"category\") {\n const grouped = groupByCategory(section.items);\n for (const category of CATEGORY_ORDER) {\n const categoryItems = grouped.get(category);\n if (!categoryItems || categoryItems.length === 0) continue;\n const heading = options.conventional ? CONVENTIONAL_HEADINGS[category] : category;\n sectionGroups.push({ heading, items: categoryItems.map(toDocumentItem) });\n }\n } else {\n for (const group of groupByField(section.items, sectionBy)) {\n sectionGroups.push({ heading: group.heading, items: group.items.map(toDocumentItem) });\n }\n }\n return {\n heading: section.heading,\n version: sectionVersionKey(section.heading),\n item_count: section.items.length,\n sections: sectionGroups,\n contributors: options.contributors ? collectContributors(section.items) : undefined,\n breaking_changes: options.breakingChanges\n ? section.items.filter(isBreakingItem).map(toDocumentItem)\n : undefined,\n };\n });\n\n return {\n title: options.title ?? DEFAULT_TITLE,\n group_by: options.groupBy ?? \"version\",\n section_by: sectionBy,\n item_count: visibleSections.reduce((sum, section) => sum + section.items.length, 0),\n releases,\n // Classify the same visible-section items emitted above, not the full\n // filtered set, so the bump matches the released sections (GH #28).\n suggested_semver: options.suggestSemver\n ? suggestSemverForItems(visibleSections.flatMap((section) => section.items))\n : undefined,\n };\n}\n\nfunction toDocumentItem(item: PmItem): ChangelogDocumentItem {\n return {\n id: item.id,\n title: toSingleLine(item.title),\n type: item.type,\n status: item.status,\n priority: item.priority,\n tags: item.tags,\n release: item.release,\n milestone: item.milestone,\n url: item.url,\n };\n}\n\nexport function mergeChangelog(\n existingMarkdown: string | undefined,\n generatedMarkdown: string,\n options: MergeChangelogOptions = {}\n): MergeChangelogResult {\n const existing = existingMarkdown?.trimEnd();\n const generated = generatedMarkdown.trimEnd();\n if (!existing) {\n return {\n markdown: generated + \"\\n\",\n action: \"created\",\n changed: true,\n };\n }\n\n const releaseSections = extractReleaseSections(generated);\n if (releaseSections.length === 0) {\n const unchanged = existing + \"\\n\";\n return {\n markdown: unchanged,\n action: \"unchanged\",\n changed: false,\n };\n }\n\n let next = ensureTitle(existing, options.title);\n let action: MergeChangelogResult[\"action\"] = \"unchanged\";\n\n for (const releaseSection of releaseSections) {\n const replacement = releaseSection.markdown.trimEnd();\n const replaced = replaceReleaseSection(next, releaseSection.heading, replacement);\n\n if (replaced.replaced) {\n next = replaced.markdown;\n action = \"replaced\";\n continue;\n }\n\n next = insertAfterTitle(next, replacement);\n if (action !== \"replaced\") action = \"inserted\";\n }\n\n next = next.trimEnd() + \"\\n\";\n return {\n markdown: next,\n action,\n changed: next !== existing + \"\\n\",\n };\n}\n\nexport function readPmItems(options: ReadPmItemsOptions = {}): PmItem[] {\n const pmBin = options.pmBin ?? \"pm\";\n const args = [...(options.pmArgs ?? []), \"list-all\", \"--json\"];\n if (options.includeBody) {\n args.push(\"--include-body\");\n }\n if (options.pmRoot) {\n args.unshift(\"--path\", options.pmRoot);\n }\n\n const result = spawnSync(pmBin, args, {\n cwd: options.cwd,\n env: options.env,\n encoding: \"utf-8\",\n maxBuffer: options.maxBuffer ?? DEFAULT_PM_JSON_MAX_BUFFER,\n });\n if (result.status !== 0) {\n throw new Error(result.stderr || `${pmBin} list-all --json failed`);\n }\n\n return parsePmItemsJson(result.stdout);\n}\n\nexport function writeChangelog(options: WriteChangelogOptions): WriteChangelogResult {\n const output = resolve(options.output ?? \"CHANGELOG.md\");\n const generated = createChangelog(options);\n const mode = options.mode ?? \"replace\";\n const existing = existsSync(output) ? readFileSync(output, \"utf-8\") : undefined;\n const merged = mode === \"prepend\"\n ? mergeChangelog(existing, generated.markdown, { title: options.title })\n : replaceChangelog(existing, generated.markdown);\n\n if (!options.check) {\n writeFileSync(output, merged.markdown, \"utf-8\");\n }\n\n return {\n output,\n markdown: merged.markdown,\n action: merged.action,\n changed: merged.changed,\n itemCount: generated.itemCount,\n bytes: Buffer.byteLength(merged.markdown, \"utf-8\"),\n };\n}\n\nexport function parsePmItemsJson(raw: string): PmItem[] {\n const parsed = JSON.parse(raw) as unknown;\n if (Array.isArray(parsed)) return parsed as PmItem[];\n if (isRecord(parsed) && Array.isArray(parsed.items)) return parsed.items as PmItem[];\n throw new Error(\"Expected pm JSON to be an array or an object with an items array\");\n}\n\nfunction replaceChangelog(\n existingMarkdown: string | undefined,\n generatedMarkdown: string\n): MergeChangelogResult {\n const generated = generatedMarkdown.trimEnd() + \"\\n\";\n const existing = existingMarkdown?.trimEnd();\n if (!existing) {\n return {\n markdown: generated,\n action: \"created\",\n changed: true,\n };\n }\n\n const changed = generated !== existing + \"\\n\";\n return {\n markdown: generated,\n action: changed ? \"replaced\" : \"unchanged\",\n changed,\n };\n}\n\nfunction filterItems(options: GenerateChangelogOptions): PmItem[] {\n const items = filterItemsByStatus(options);\n if (options.releaseWindows && options.releaseWindows.length > 0) return items;\n\n return filterItemsByTime(items, {\n since: options.since,\n until: options.until,\n });\n}\n\nfunction filterItemsByStatus(options: GenerateChangelogOptions): PmItem[] {\n const statuses = new Set(\n (options.includeStatuses ?? DEFAULT_STATUSES).map((status) => status.toLowerCase())\n );\n\n return options.items\n .filter((item) => item.title)\n .filter((item) => {\n if (statuses.size === 0) return true;\n return statuses.has(String(item.status ?? \"\").toLowerCase());\n })\n .sort(compareItems);\n}\n\nfunction buildSections(items: PmItem[], options: GenerateChangelogOptions): ChangelogSection[] {\n if (options.releaseWindows && options.releaseWindows.length > 0) {\n return assignItemsToReleaseWindows(items, options.releaseWindows);\n }\n\n if (options.groupBy === \"release\" && !options.version) {\n return groupSectionsByMetadata(items, \"release\", \"Unreleased\");\n }\n\n if (options.groupBy === \"milestone\" && !options.version) {\n return groupSectionsByMetadata(items, \"milestone\", \"Unreleased\");\n }\n\n return [\n {\n heading: buildVersionHeading(options.version, options.date),\n items,\n },\n ];\n}\n\nfunction assignItemsToReleaseWindows(\n items: PmItem[],\n windows: ChangelogReleaseWindow[]\n): ChangelogSection[] {\n const buckets = new Map();\n for (const window of windows) buckets.set(window.heading, []);\n\n const releaseIndex = new Map();\n for (const window of windows) {\n if (!window.releaseTag) continue;\n const key = normalizeReleaseKey(window.releaseTag);\n if (!key || releaseIndex.has(key)) continue;\n releaseIndex.set(key, window.heading);\n }\n\n const remaining: PmItem[] = [];\n for (const item of items) {\n const releaseField = getStringField(item, \"release\");\n const key = releaseField ? normalizeReleaseKey(releaseField) : \"\";\n const heading = key ? releaseIndex.get(key) : undefined;\n if (heading) {\n buckets.get(heading)!.push(item);\n continue;\n }\n remaining.push(item);\n }\n\n for (const window of windows) {\n const filtered = filterItemsByTime(remaining, window);\n buckets.get(window.heading)!.push(...filtered);\n }\n\n return windows.map((window) => ({\n heading: window.heading,\n items: buckets.get(window.heading) ?? [],\n }));\n}\n\nfunction normalizeReleaseKey(value: string): string {\n return value.trim().replace(/^v/i, \"\").toLowerCase();\n}\n\n// Truncate an epoch-millisecond value to whole-second granularity. Release-tag\n// boundaries come from git committer dates at second precision, while pm item\n// timestamps carry milliseconds (see filterItemsByTime).\nconst toSecond = (ms: number): number => Math.floor(ms / 1000);\n\nfunction filterItemsByTime(\n items: PmItem[],\n window: { since?: string; sinceExclusive?: boolean; until?: string }\n): PmItem[] {\n const since = window.since ? Date.parse(window.since) : undefined;\n const until = window.until ? Date.parse(window.until) : undefined;\n\n // Compare window boundaries at second granularity. Comparing the raw values\n // pushes an item closed at 12:34:56.789 outside a window ending at\n // 12:34:56(.000), so it resurfaces under Unreleased (issue #41). An inclusive\n // `until` covers the whole boundary second, and an exclusive `since` excludes\n // the entire boundary second.\n //\n // Consequence for sub-second `since` inputs (non-exclusive `--since` flag): a\n // boundary like `--since 13:00:00.500Z` now also admits items closed earlier\n // in that same second (e.g. 13:00:00.000Z), where the previous millisecond\n // comparison would have excluded them. This is intentional: release-tag\n // boundaries are always second-precision, so the millisecond tail carried no\n // reliable signal.\n return items.filter((item) => {\n const timestamp = itemTimestamp(item);\n if (!timestamp) return since === undefined && until === undefined;\n const value = Date.parse(timestamp);\n if (Number.isNaN(value)) return false;\n if (since !== undefined) {\n const sinceSecond = toSecond(since);\n const valueSecond = toSecond(value);\n if (window.sinceExclusive ? valueSecond <= sinceSecond : valueSecond < sinceSecond) return false;\n }\n if (until !== undefined && toSecond(value) > toSecond(until)) return false;\n return true;\n });\n}\n\nfunction groupSectionsByMetadata(\n items: PmItem[],\n field: \"release\" | \"milestone\",\n fallback: string\n): ChangelogSection[] {\n const grouped = new Map();\n for (const item of items) {\n const key = getStringField(item, field) || fallback;\n const group = grouped.get(key) ?? [];\n group.push(item);\n grouped.set(key, group);\n }\n return Array.from(grouped.entries())\n .map(([heading, groupedItems]) => ({ heading, items: groupedItems }))\n .sort((a, b) => compareVersionHeadings(a.heading, b.heading, fallback));\n}\n\nfunction compareVersionHeadings(a: string, b: string, fallback: string): number {\n if (a === fallback) return -1;\n if (b === fallback) return 1;\n return compareVersionStrings(b, a);\n}\n\nfunction compareVersionStrings(a: string, b: string): number {\n const normalize = (v: string): string => v.replace(/^v/, \"\");\n const segmentsA = normalize(a).split(/[.\\-]/);\n const segmentsB = normalize(b).split(/[.\\-]/);\n const len = Math.max(segmentsA.length, segmentsB.length);\n for (let i = 0; i < len; i++) {\n const sa = segmentsA[i] ?? \"\";\n const sb = segmentsB[i] ?? \"\";\n const na = parseInt(sa, 10);\n const nb = parseInt(sb, 10);\n if (!Number.isNaN(na) && !Number.isNaN(nb)) {\n if (na !== nb) return na - nb;\n } else {\n const cmp = sa.localeCompare(sb);\n if (cmp !== 0) return cmp;\n }\n }\n return 0;\n}\n\nfunction buildVersionHeading(version: string | undefined, date: string | undefined): string {\n const heading = version?.trim() || \"Unreleased\";\n const stamp = date?.trim() || formatLocalDate(new Date());\n return `${heading} - ${stamp}`;\n}\n\nfunction extractReleaseSections(markdown: string): Array<{ heading: string; markdown: string }> {\n const releaseHeading = /^##\\s+(.+)$/gm;\n const matches = Array.from(markdown.matchAll(releaseHeading));\n return matches.map((match, index) => {\n const start = match.index ?? 0;\n const next = matches[index + 1];\n const end = next?.index ?? markdown.length;\n return {\n heading: match[1].trim(),\n markdown: markdown.slice(start, end).trimEnd(),\n };\n });\n}\n\nfunction replaceReleaseSection(\n markdown: string,\n heading: string,\n replacement: string\n): { markdown: string; replaced: boolean } {\n const releaseHeading = /^##\\s+(.+)$/gm;\n const matches = Array.from(markdown.matchAll(releaseHeading));\n const targetHeadingKey = normalizeReleaseHeadingKey(heading);\n const matchIndex = matches.findIndex(\n (match) => normalizeReleaseHeadingKey(match[1].trim()) === targetHeadingKey\n );\n if (matchIndex === -1) return { markdown, replaced: false };\n\n const match = matches[matchIndex];\n const start = match.index ?? 0;\n const nextMatch = matches[matchIndex + 1];\n const end = nextMatch?.index ?? markdown.length;\n const before = markdown.slice(0, start).trimEnd();\n const after = markdown.slice(end).trimStart();\n const merged = after ? `${before}\\n\\n${replacement}\\n\\n${after}` : `${before}\\n\\n${replacement}`;\n return { markdown: merged, replaced: true };\n}\n\nfunction normalizeReleaseHeadingKey(heading: string): string {\n const trimmed = heading.trim();\n const bracketed = trimmed.match(/^\\[([^\\]]+)\\](?:\\([^)]+\\))?(?:\\s+-\\s+.+)?$/);\n const version = bracketed?.[1] ?? trimmed.split(/\\s+-\\s+/, 1)[0] ?? trimmed;\n return version.trim().replace(/^v/i, \"\").toLowerCase();\n}\n\nfunction ensureTitle(markdown: string, title: string | undefined): string {\n if (/^#\\s+.+$/m.test(markdown)) return markdown;\n return `# ${title ?? DEFAULT_TITLE}\\n\\n${markdown.trimStart()}`;\n}\n\nfunction insertAfterTitle(markdown: string, releaseSection: string): string {\n const titleMatch = markdown.match(/^#\\s+.+$/m);\n if (!titleMatch || titleMatch.index === undefined) {\n return `${releaseSection}\\n\\n${markdown.trimStart()}`;\n }\n\n const titleEnd = titleMatch.index + titleMatch[0].length;\n const before = markdown.slice(0, titleEnd).trimEnd();\n const after = markdown.slice(titleEnd).trim();\n if (!after) return `${before}\\n\\n${releaseSection}`;\n return `${before}\\n\\n${releaseSection}\\n\\n${after}`;\n}\n\n// OPT-IN (`--conventional`): keep-a-changelog category -> Conventional-Commits\n// style heading. Every key maps so the mapping is total; values mirror common\n// conventional-changelog section titles.\nconst CONVENTIONAL_HEADINGS: Record = {\n Added: \"Features\",\n Changed: \"Changes\",\n Fixed: \"Bug Fixes\",\n Removed: \"Reverts\",\n Security: \"Security\",\n Deprecated: \"Deprecations\",\n Other: \"Other\",\n};\n\n/**\n * OPT-IN (`--section-by type|status|label`): group a release's items by a\n * single item field instead of the keep-a-changelog category. Groups are\n * ordered by first appearance (items arrive pre-sorted by `compareItems`), so\n * output is deterministic. Items missing the field fall into an \"Other\" /\n * \"Unlabeled\" bucket. For `label`, an item may appear under several headings\n * (one per tag) — this is by design and clearly opt-in.\n */\nfunction groupByField(\n items: PmItem[],\n sectionBy: Exclude\n): Array<{ heading: string; items: PmItem[] }> {\n const groups = new Map();\n const push = (heading: string, item: PmItem): void => {\n const bucket = groups.get(heading) ?? [];\n bucket.push(item);\n groups.set(heading, bucket);\n };\n\n for (const item of items) {\n if (sectionBy === \"type\") {\n push(titleCase(typeof item.type === \"string\" && item.type.trim() ? item.type.trim() : \"Other\"), item);\n } else if (sectionBy === \"status\") {\n push(titleCase(typeof item.status === \"string\" && item.status.trim() ? item.status.trim() : \"Unknown\"), item);\n } else {\n const tags = [\n ...new Set(\n (Array.isArray(item.tags) ? item.tags : [])\n .filter((tag): tag is string => typeof tag === \"string\")\n .map((tag) => tag.trim())\n .filter(Boolean)\n ),\n ];\n if (tags.length === 0) {\n push(\"Unlabeled\", item);\n } else {\n for (const tag of tags) push(tag, item);\n }\n }\n }\n\n return Array.from(groups.entries()).map(([heading, groupedItems]) => ({ heading, items: groupedItems }));\n}\n\nfunction titleCase(value: string): string {\n return value\n .replace(/[_-]+/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim()\n .replace(/\\b\\w/g, (char) => char.toUpperCase());\n}\n\n/**\n * OPT-IN (`--contributors`): unique contributor handles for a release, ordered\n * by first appearance. Prefers `assignee`, falls back to `author`; ignores the\n * `unknown` placeholder pm writes when no author is recorded.\n */\nfunction collectContributors(items: PmItem[]): string[] {\n const seen = new Set();\n const ordered: string[] = [];\n for (const item of items) {\n const candidate = pickContributor(item.assignee) ?? pickContributor(item.author);\n if (!candidate) continue;\n const key = candidate.toLowerCase();\n if (seen.has(key)) continue;\n seen.add(key);\n ordered.push(candidate);\n }\n return ordered;\n}\n\nfunction pickContributor(value: unknown): string | undefined {\n if (typeof value !== \"string\") return undefined;\n const trimmed = value.trim();\n if (!trimmed || trimmed.toLowerCase() === \"unknown\") return undefined;\n return trimmed;\n}\n\nfunction groupByCategory(items: PmItem[]): Map {\n const grouped = new Map();\n for (const item of items) {\n const category = classifyItem(item);\n const categoryItems = grouped.get(category) ?? [];\n categoryItems.push(item);\n grouped.set(category, categoryItems);\n }\n return grouped;\n}\n\nconst BUG_LIKE_ITEM_TYPES: ReadonlySet = new Set([\"issue\", \"bug\", \"bugfix\", \"defect\"]);\nconst CHANGED_NEEDLES = [\"change\", \"changed\", \"refactor\", \"update\", \"updated\", \"improve\"];\nconst REMOVED_NEEDLES = [\"removed\", \"remove\", \"deleted\", \"delete\"];\n\nfunction classifyItem(item: PmItem): Category {\n // Strip CLI-flag-like tokens from titles before scanning. Without this, an\n // item titled \"pm --add fails...\" gets classified as \"Added\" because\n // the word \"add\" matches inside \"--add\". The pattern:\n // - Negative lookbehind on `[\\w-]` so in-word hyphens like \"non-add\" or\n // \"in-test\" stay intact, while flags wrapped in punctuation/quotes\n // (`\\`--add\\``, `(--add)`, `[--add]`) still match.\n // - Accepts 1 or 2 leading dashes (covers `-x` POSIX shorts too).\n // - First char after the dashes is alnum (lets `--2fa` work).\n // - Body is the alnum/underscore/hyphen flag name, optionally followed by\n // `=` where value runs to the next whitespace. This wholesale\n // strips `--url=https://example.com/add` so URL/path values don't leak\n // spurious keyword matches downstream.\n //\n // Tags and type still contribute their full token, so an explicit\n // `feature`/`added` tag still wins regardless of title content.\n const sanitizedTitle = (item.title ?? \"\").replace(/(? new RegExp(`\\\\b${escapeRegExp(needle)}\\\\b`).test(value));\n}\n\nconst SELECTION_SAMPLE_LIMIT = 3;\n\nfunction sampleItems(items: PmItem[]): string[] {\n const labels: string[] = [];\n const seen = new Set();\n for (const item of items) {\n const label = sampleItemLabel(item);\n if (seen.has(label)) continue;\n seen.add(label);\n labels.push(label);\n if (labels.length >= SELECTION_SAMPLE_LIMIT) break;\n }\n return labels;\n}\n\nfunction sampleItemLabel(item: PmItem): string {\n const id = typeof item.id === \"string\" && item.id.trim() !== \"\"\n ? item.id.trim()\n : \"(no-id)\";\n const title = typeof item.title === \"string\" && item.title.trim() !== \"\"\n ? toSingleLine(item.title)\n : \"(untitled)\";\n return `${id}: ${title}`;\n}\n\nfunction buildSelectionHints(input: {\n visibleItemCount: number;\n hasReleaseWindows: boolean;\n excludedCounts: {\n missing_title: number;\n status: number;\n time_window: number;\n release_window: number;\n hidden_by_visibility: number;\n };\n}): string[] {\n const hints: string[] = [];\n if (input.excludedCounts.status > 0) {\n hints.push(\"Some items were excluded by status; expand --status (for example: --status open,closed).\");\n }\n if (input.excludedCounts.time_window > 0) {\n hints.push(\"Time filtering excluded items; widen --since/--until if those items should be included.\");\n }\n if (input.hasReleaseWindows && input.excludedCounts.release_window > 0) {\n hints.push(\"Some items fell outside release tag windows; verify tag boundaries or item release metadata.\");\n }\n if (input.excludedCounts.hidden_by_visibility > 0) {\n hints.push(\"Visibility narrowing hid sections; relax --limit or --since-version to include older releases.\");\n }\n if (input.visibleItemCount === 0 && hints.length === 0) {\n hints.push(\"No items matched the current filters.\");\n }\n return hints;\n}\n\nfunction formatItem(item: PmItem, options: GenerateChangelogOptions): string {\n const title = escapeMarkdown(toSingleLine(item.title));\n const id = formatItemId(item, options);\n const metadata = formatItemMetadata(item, options);\n const link = options.includeLinks ? formatLink(item.url) : \"\";\n const preview = formatBodyPreview(item, options);\n return `${title}${id}${metadata}${link}${preview}`;\n}\n\nfunction formatItemMetadata(item: PmItem, options: GenerateChangelogOptions): string {\n if (!options.includeMetadata) return \"\";\n const parts: string[] = [];\n if (typeof item.type === \"string\" && item.type.trim()) parts.push(`type:${item.type.trim()}`);\n if (typeof item.status === \"string\" && item.status.trim()) parts.push(`status:${item.status.trim()}`);\n if (typeof item.priority === \"number\" && Number.isFinite(item.priority)) parts.push(`P${item.priority}`);\n const release = getStringField(item, \"release\");\n if (release) parts.push(`release:${release}`);\n const milestone = getStringField(item, \"milestone\");\n if (milestone) parts.push(`milestone:${milestone}`);\n if (parts.length === 0) return \"\";\n return ` _${parts.map((part) => escapeMarkdown(toSingleLine(part))).join(\"; \")}_`;\n}\n\n/**\n * OPT-IN (`--body-preview `): append a truncated, single-lined, escaped\n * preview of the item body. Returns \"\" when the flag is unset/0 or the item has\n * no body, so default output is byte-identical. Truncation appends an ellipsis\n * only when the body actually exceeds N characters.\n */\nfunction formatBodyPreview(item: PmItem, options: GenerateChangelogOptions): string {\n const limit = options.bodyPreview && options.bodyPreview > 0 ? options.bodyPreview : 0;\n if (limit === 0) return \"\";\n // pm workspaces store long-form prose in `description`; `body` is usually\n // empty. Prefer a non-empty `body`, then fall back to `description`, so the\n // preview actually has content against real pm items.\n const rawSource =\n typeof item.body === \"string\" && item.body.trim() !== \"\"\n ? item.body\n : typeof item.description === \"string\"\n ? item.description\n : \"\";\n const body = toSingleLine(rawSource);\n if (!body) return \"\";\n const truncated = body.length > limit ? `${body.slice(0, limit)}…` : body;\n return ` — ${escapeMarkdown(truncated)}`;\n}\n\n/**\n * OPT-IN (`--emoji-prefix`): prefix a known heading with a conventional emoji.\n * Unknown headings (custom labels/types) pass through unchanged. Off by\n * default, so headings render exactly as before.\n */\nfunction maybeEmoji(heading: string, options: GenerateChangelogOptions): string {\n if (!options.emojiPrefix) return heading;\n const emoji = HEADING_EMOJI[heading];\n return emoji ? `${emoji} ${heading}` : heading;\n}\n\nconst HEADING_EMOJI: Record = {\n // keep-a-changelog categories\n Added: \"🎉\",\n Changed: \"♻️\",\n Fixed: \"🐛\",\n Removed: \"🗑️\",\n Security: \"🔒\",\n Deprecated: \"⚠️\",\n Other: \"📦\",\n // conventional-commits headings (when --conventional is also set)\n Features: \"🎉\",\n Changes: \"♻️\",\n \"Bug Fixes\": \"🐛\",\n Reverts: \"⏪\",\n Deprecations: \"⚠️\",\n // breaking changes section\n \"Breaking Changes\": \"💥\",\n};\n\n/**\n * Detect whether an item is a breaking change. Signals (any one suffices):\n * - a truthy `breaking` flag on the item or in its metadata, OR\n * - an explicit breaking tag (`breaking`, `breaking-change`, `breaking_change`), OR\n * - the word \"breaking\" appearing as a standalone token in the type or title.\n *\n * Negated/safe phrasings such as \"non-breaking\", \"non breaking\", \"not breaking\"\n * and \"no breaking\" are stripped before the token check, so describing a change\n * as non-breaking no longer triggers a major-bump suggestion (GH #26).\n * Used only by the opt-in `--breaking-changes` / `--suggest-semver` features.\n */\nfunction isBreakingItem(item: PmItem): boolean {\n if (isTruthyFlag(item.breaking)) return true;\n if (isTruthyFlag(item.metadata?.[\"breaking\"])) return true;\n\n const tags = Array.isArray(item.tags)\n ? item.tags.filter((t): t is string => typeof t === \"string\")\n : [];\n // An explicit tag is an unambiguous, intentional breaking signal.\n if (tags.some((t) => BREAKING_TAGS.has(normalizeTag(t)))) return true;\n\n const haystack = [typeof item.type === \"string\" ? item.type : \"\", typeof item.title === \"string\" ? item.title : \"\", ...tags]\n .join(\" \")\n .toLowerCase();\n // Drop negated/safe phrasings first (\"non-breaking\", \"not breaking\", …) so\n // they cannot satisfy the standalone-token check below.\n const withoutNegations = haystack.replace(NEGATED_BREAKING, \" \");\n return BREAKING_TOKEN.test(withoutNegations);\n}\n\n/** Tags that explicitly mark a breaking change (compared after normalization). */\nconst BREAKING_TAGS = new Set([\"breaking\", \"breakingchange\", \"breaking-change\", \"breaking_change\"]);\n\nfunction normalizeTag(tag: string): string {\n return tag.trim().toLowerCase();\n}\n\n/** Negated/safe \"breaking\" phrasings to strip before the standalone-token test. */\nconst NEGATED_BREAKING = /\\b(?:non[-\\s]?breaking|not\\s+(?:a\\s+)?breaking|no\\s+breaking)\\b/g;\n\n/** \"breaking\" as a standalone word (not part of e.g. \"nonbreaking\"). */\nconst BREAKING_TOKEN = /\\bbreaking\\b/;\n\nfunction isTruthyFlag(value: unknown): boolean {\n if (value === true) return true;\n if (typeof value === \"string\") {\n const v = value.trim().toLowerCase();\n return v === \"true\" || v === \"yes\" || v === \"1\";\n }\n if (typeof value === \"number\") return value === 1;\n return false;\n}\n\n/**\n * OPT-IN (`--suggest-semver`): classify the in-scope items into breaking /\n * feature / fix / other and recommend a semver bump. Emitted as JSON or a\n * footer note; never alters default markdown.\n */\nexport function suggestSemver(options: GenerateChangelogOptions): SemverSuggestion {\n // Base the suggestion on the items that actually render (after section\n // building, empty-section pruning and --limit/--since-version narrowing) so a\n // bump is never reported from releases hidden by visibility flags (GH #28).\n // With no narrowing flags this is exactly filterItems(options), so the\n // default suggestion is unchanged.\n return suggestSemverForItems(visibleChangelogItems(options));\n}\n\n/**\n * The items that actually render for the given options: the union of all\n * visible release-section items after filtering, empty-section pruning and\n * `--limit`/`--since-version` narrowing. Exposed so semver suggestions and the\n * structured `--changelog-json` document classify the same set the markdown\n * emits (GH #28).\n */\nexport function visibleChangelogItems(options: GenerateChangelogOptions): PmItem[] {\n const filtered = filterItems(options);\n const sections = buildSections(filtered, options);\n const candidateSections = options.includeEmpty\n ? sections\n : sections.filter((section) => section.items.length > 0);\n const visibleSections = limitSections(candidateSections, options);\n return visibleSections.flatMap((section) => section.items);\n}\n\n/**\n * OPT-IN (`--explain`): return machine-readable diagnostics showing how input\n * items moved through title/status/time/release-window filters and visibility\n * narrowing (`--limit`/`--since-version`). Designed for agent/operator UX when\n * output is unexpectedly empty or smaller than expected.\n */\nexport function explainChangelogSelection(options: GenerateChangelogOptions): ChangelogSelectionReport {\n const statuses = new Set((options.includeStatuses ?? DEFAULT_STATUSES).map((status) => status.toLowerCase()));\n const hasReleaseWindows = Boolean(options.releaseWindows && options.releaseWindows.length > 0);\n\n const withTitle: PmItem[] = [];\n const missingTitle: PmItem[] = [];\n for (const item of options.items) {\n if (item.title) withTitle.push(item);\n else missingTitle.push(item);\n }\n\n const afterStatus: PmItem[] = [];\n const excludedByStatus: PmItem[] = [];\n for (const item of withTitle) {\n if (statuses.size === 0 || statuses.has(String(item.status ?? \"\").toLowerCase())) {\n afterStatus.push(item);\n } else {\n excludedByStatus.push(item);\n }\n }\n\n const afterTime = hasReleaseWindows\n ? afterStatus\n : filterItemsByTime(afterStatus, {\n since: options.since,\n until: options.until,\n });\n const afterTimeRefs = new Set(afterTime);\n const excludedByTime = hasReleaseWindows\n ? []\n : afterStatus.filter((item) => !afterTimeRefs.has(item));\n\n const sections = buildSections(afterTime, options);\n const assignedToReleaseWindows = new Set(\n hasReleaseWindows ? sections.flatMap((section) => section.items) : []\n );\n const excludedByReleaseWindow = hasReleaseWindows\n ? afterTime.filter((item) => !assignedToReleaseWindows.has(item))\n : [];\n\n const candidateSections = options.includeEmpty\n ? sections\n : sections.filter((section) => section.items.length > 0);\n const visibleSections = limitSections(candidateSections, options);\n const visibleSectionRefs = new Set(visibleSections);\n const hiddenByVisibility = candidateSections\n .filter((section) => !visibleSectionRefs.has(section))\n .flatMap((section) => section.items);\n const candidateItems = candidateSections.flatMap((section) => section.items);\n const visibleItems = visibleSections.flatMap((section) => section.items);\n\n const excludedCounts = {\n missing_title: missingTitle.length,\n status: excludedByStatus.length,\n time_window: excludedByTime.length,\n release_window: excludedByReleaseWindow.length,\n hidden_by_visibility: hiddenByVisibility.length,\n };\n const visibleItemCount = visibleItems.length;\n\n return {\n filters: {\n statuses: Array.from(statuses),\n since: options.since,\n until: options.until,\n release_windows: hasReleaseWindows,\n include_empty: Boolean(options.includeEmpty),\n limit: options.limit,\n since_version: options.sinceVersion,\n },\n stage_counts: {\n input: options.items.length,\n after_title: withTitle.length,\n after_status: afterStatus.length,\n after_time: afterTime.length,\n after_release_windows: hasReleaseWindows ? afterTime.length - excludedByReleaseWindow.length : undefined,\n candidate_sections: candidateSections.length,\n visible_sections: visibleSections.length,\n candidate_items: candidateItems.length,\n visible_items: visibleItemCount,\n },\n excluded_counts: excludedCounts,\n sample_items: {\n missing_title: sampleItems(missingTitle),\n status: sampleItems(excludedByStatus),\n time_window: sampleItems(excludedByTime),\n release_window: sampleItems(excludedByReleaseWindow),\n hidden_by_visibility: sampleItems(hiddenByVisibility),\n },\n hints: buildSelectionHints({\n visibleItemCount,\n hasReleaseWindows,\n excludedCounts,\n }),\n };\n}\n\n/** Classify an explicit item set into a semver bump (no option-driven filtering). */\nexport function suggestSemverForItems(items: PmItem[]): SemverSuggestion {\n let breaking = 0;\n let feature = 0;\n let fix = 0;\n let other = 0;\n for (const item of items) {\n if (isBreakingItem(item)) {\n breaking++;\n continue;\n }\n const category = classifyItem(item);\n if (category === \"Added\") feature++;\n else if (category === \"Fixed\") fix++;\n else other++;\n }\n\n let bump: SemverBump;\n let reason: string;\n if (breaking > 0) {\n bump = \"major\";\n reason = `${breaking} breaking change${breaking === 1 ? \"\" : \"s\"}`;\n } else if (feature > 0) {\n bump = \"minor\";\n reason = `${feature} feature${feature === 1 ? \"\" : \"s\"}`;\n } else if (fix > 0) {\n bump = \"patch\";\n reason = `${fix} fix${fix === 1 ? \"\" : \"es\"}`;\n } else if (other > 0) {\n bump = \"patch\";\n reason = `${other} other change${other === 1 ? \"\" : \"s\"}`;\n } else {\n bump = \"none\";\n reason = \"no changes\";\n }\n\n return { bump, reason, counts: { breaking, feature, fix, other } };\n}\n\nfunction formatItemId(item: PmItem, options: GenerateChangelogOptions): string {\n if (!item.id) return \"\";\n const escapedId = escapeMarkdown(item.id);\n if (options.itemUrlBase) {\n const base = options.itemUrlBase.replace(/\\/$/, \"\");\n const typeDir = itemTypeToDir(item.type);\n const url = `${base}/${typeDir}/${item.id}.toon`;\n return ` ([${escapedId}](${url}))`;\n }\n return ` (${escapedId})`;\n}\n\nfunction itemTypeToDir(type: string | undefined): string {\n const t = (type ?? \"issue\").toLowerCase();\n const irregular: Record = { story: \"stories\" };\n return irregular[t] ?? `${t}s`;\n}\n\nfunction formatLink(url: string | undefined): string {\n if (!url) return \"\";\n try {\n const parsed = new URL(toSingleLine(url));\n if (parsed.protocol !== \"https:\" && parsed.protocol !== \"http:\") return \"\";\n parsed.username = \"\";\n parsed.password = \"\";\n parsed.search = \"\";\n parsed.hash = \"\";\n return ` [link](${parsed.href.replace(/\\)/g, \"%29\")})`;\n } catch {\n return \"\";\n }\n}\n\nfunction getStringField(item: PmItem, field: \"release\" | \"milestone\"): string | undefined {\n const direct = item[field];\n if (typeof direct === \"string\" && direct.trim()) return direct.trim();\n const fromMetadata = item.metadata?.[field];\n if (typeof fromMetadata === \"string\" && fromMetadata.trim()) return fromMetadata.trim();\n return undefined;\n}\n\nfunction compareItems(a: PmItem, b: PmItem): number {\n const aTime = Date.parse(itemTimestamp(a) ?? \"\");\n const bTime = Date.parse(itemTimestamp(b) ?? \"\");\n if (!Number.isNaN(aTime) && !Number.isNaN(bTime) && aTime !== bTime) {\n return bTime - aTime;\n }\n return a.title.localeCompare(b.title);\n}\n\nfunction itemTimestamp(item: PmItem): string | undefined {\n return item.closed_at ?? item.updated_at ?? item.created_at;\n}\n\nfunction escapeMarkdown(value: string): string {\n return value.replace(/([\\\\`*_[\\]()#|>])/g, \"\\\\$1\");\n}\n\nfunction toSingleLine(value: string): string {\n return value.trim().replace(/\\s+/g, \" \");\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction isRecord(value: unknown): value is Record {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction formatLocalDate(date: Date): string {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, \"0\");\n const day = String(date.getDate()).padStart(2, \"0\");\n return `${year}-${month}-${day}`;\n}\n"]} \ No newline at end of file +{"version":3,"file":"generator.js","sourceRoot":"","sources":["../src/generator.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawnSync } from \"node:child_process\";\nimport { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\n\nimport type {\n ChangelogDocument,\n ChangelogDocumentItem,\n ChangelogDocumentRelease,\n ChangelogDocumentSection,\n ChangelogReleaseWindow,\n ChangelogSelectionReport,\n ChangelogSectionBy,\n ChangelogSection,\n GeneratedChangelog,\n GenerateChangelogOptions,\n MergeChangelogOptions,\n MergeChangelogResult,\n PmItem,\n ReadPmItemsOptions,\n SemverBump,\n SemverSuggestion,\n WriteChangelogOptions,\n WriteChangelogResult,\n} from \"./types.js\";\n\nconst DEFAULT_TITLE = \"Changelog\";\nconst DEFAULT_STATUSES = [\"closed\"];\nconst DEFAULT_PM_JSON_MAX_BUFFER = 64 * 1024 * 1024;\n\nconst CATEGORY_ORDER = [\n \"Added\",\n \"Changed\",\n \"Fixed\",\n \"Removed\",\n \"Security\",\n \"Deprecated\",\n \"Other\",\n] as const;\n\ntype Category = (typeof CATEGORY_ORDER)[number];\n\nexport function generateChangelog(options: GenerateChangelogOptions): string {\n return createChangelog(options).markdown;\n}\n\nexport function createChangelog(options: GenerateChangelogOptions): GeneratedChangelog {\n const title = options.title ?? DEFAULT_TITLE;\n const items = filterItems(options);\n const sections = buildSections(items, options);\n const lines: string[] = [`# ${title}`, \"\"];\n\n if (sections.length === 0) {\n if (options.includeEmpty) {\n const heading = buildVersionHeading(options.version, options.date);\n lines.push(`## ${heading}`, \"\", \"No changes.\", \"\");\n }\n return {\n markdown: lines.join(\"\\n\").trimEnd() + \"\\n\",\n sections,\n itemCount: items.length,\n };\n }\n\n // Apply visibility before limiting so `--limit N` counts N releases that\n // actually render (empty windows like a fresh \"Unreleased\" don't consume a\n // slot). With no limit/since-version flags this is a pure identity pass.\n const candidateSections = options.includeEmpty\n ? sections\n : sections.filter((section) => section.items.length > 0);\n const visibleSections = limitSections(candidateSections, options);\n\n if (visibleSections.length === 0) {\n return {\n markdown: lines.join(\"\\n\").trimEnd() + \"\\n\",\n sections,\n itemCount: 0,\n };\n }\n\n const sectionBy = options.sectionBy ?? \"category\";\n\n for (const section of visibleSections) {\n lines.push(`## ${section.heading}`, \"\");\n if (section.items.length === 0) {\n lines.push(\"No changes.\", \"\");\n continue;\n }\n\n // OPT-IN (`--breaking-changes`): a dedicated heading listing breaking items\n // up front. Items still appear in their normal category/field group below,\n // so this is purely additive and absent by default.\n if (options.breakingChanges) {\n const breaking = section.items.filter(isBreakingItem);\n if (breaking.length > 0) {\n lines.push(`### ${maybeEmoji(\"Breaking Changes\", options)}`, \"\");\n for (const item of breaking) {\n lines.push(`- ${formatItem(item, options)}`);\n }\n lines.push(\"\");\n }\n }\n\n if (sectionBy === \"category\") {\n const grouped = groupByCategory(section.items);\n\n for (const category of CATEGORY_ORDER) {\n const categoryItems = grouped.get(category);\n if (!categoryItems || categoryItems.length === 0) continue;\n\n // OPT-IN: --conventional remaps the heading text only; item order,\n // bucketing, and bullet rendering are untouched, so dropping the flag\n // restores byte-identical output.\n const heading = options.conventional ? CONVENTIONAL_HEADINGS[category] : category;\n lines.push(`### ${maybeEmoji(heading, options)}`, \"\");\n for (const item of categoryItems) {\n lines.push(`- ${formatItem(item, options)}`);\n }\n lines.push(\"\");\n }\n } else {\n for (const group of groupByField(section.items, sectionBy)) {\n lines.push(`### ${maybeEmoji(group.heading, options)}`, \"\");\n for (const item of group.items) {\n lines.push(`- ${formatItem(item, options)}`);\n }\n lines.push(\"\");\n }\n }\n\n if (options.contributors) {\n const names = collectContributors(section.items);\n if (names.length > 0) {\n lines.push(\"### Contributors\", \"\");\n lines.push(names.map((name) => `@${name}`).join(\", \"));\n lines.push(\"\");\n }\n }\n }\n\n return {\n markdown: lines.join(\"\\n\").trimEnd() + \"\\n\",\n sections,\n itemCount: visibleSections.reduce((sum, section) => sum + section.items.length, 0),\n };\n}\n\n/**\n * OPT-IN (`--limit` / `--since-version`): restrict release sections to the\n * most recent N or to those at or newer than a version. Only release-window\n * sections (the `## version - date` history rebuilt by `--all-release-tags`)\n * are eligible; the leading `Unreleased` section is always kept. When neither\n * option is set this is an identity pass, preserving default output exactly.\n */\nfunction limitSections(\n sections: ChangelogSection[],\n options: GenerateChangelogOptions\n): ChangelogSection[] {\n const limit = options.limit && options.limit > 0 ? options.limit : undefined;\n const sinceVersion = options.sinceVersion?.trim()\n ? normalizeReleaseKey(options.sinceVersion)\n : undefined;\n if (limit === undefined && sinceVersion === undefined) return sections;\n if (!options.releaseWindows || options.releaseWindows.length === 0) return sections;\n\n let result = sections;\n if (sinceVersion !== undefined) {\n result = result.filter((section) => {\n const key = sectionVersionKey(section.heading);\n if (key === undefined) return true; // keep Unreleased and unparsable headings\n return compareVersionStrings(key, sinceVersion) >= 0;\n });\n }\n if (limit !== undefined && result.length > limit) {\n result = result.slice(0, limit);\n }\n return result;\n}\n\nfunction sectionVersionKey(heading: string): string | undefined {\n const version = heading.split(/\\s+-\\s+/, 1)[0]?.trim() ?? heading.trim();\n if (!version || version.toLowerCase() === \"unreleased\") return undefined;\n return normalizeReleaseKey(version);\n}\n\n/**\n * OPT-IN (`--changelog-json`): build a structured representation of the\n * changelog (releases -> sections -> items) for downstream tooling. This is\n * deliberately distinct from the `--json` CLI summary (action/bytes/changed)\n * and from the `changelog export --format json` payload (which wraps markdown).\n * It applies the same filtering, limiting and grouping as the markdown path so\n * the two stay in sync, but emits structured data instead of rendered text.\n */\nexport function buildChangelogDocument(options: GenerateChangelogOptions): ChangelogDocument {\n const filtered = filterItems(options);\n const sections = buildSections(filtered, options);\n const candidateSections = options.includeEmpty\n ? sections\n : sections.filter((section) => section.items.length > 0);\n const visibleSections = limitSections(candidateSections, options);\n const sectionBy = options.sectionBy ?? \"category\";\n\n const releases: ChangelogDocumentRelease[] = visibleSections.map((section) => {\n const sectionGroups: ChangelogDocumentSection[] = [];\n if (sectionBy === \"category\") {\n const grouped = groupByCategory(section.items);\n for (const category of CATEGORY_ORDER) {\n const categoryItems = grouped.get(category);\n if (!categoryItems || categoryItems.length === 0) continue;\n const heading = options.conventional ? CONVENTIONAL_HEADINGS[category] : category;\n sectionGroups.push({ heading, items: categoryItems.map(toDocumentItem) });\n }\n } else {\n for (const group of groupByField(section.items, sectionBy)) {\n sectionGroups.push({ heading: group.heading, items: group.items.map(toDocumentItem) });\n }\n }\n return {\n heading: section.heading,\n version: sectionVersionKey(section.heading),\n item_count: section.items.length,\n sections: sectionGroups,\n contributors: options.contributors ? collectContributors(section.items) : undefined,\n breaking_changes: options.breakingChanges\n ? section.items.filter(isBreakingItem).map(toDocumentItem)\n : undefined,\n };\n });\n\n return {\n title: options.title ?? DEFAULT_TITLE,\n group_by: options.groupBy ?? \"version\",\n section_by: sectionBy,\n item_count: visibleSections.reduce((sum, section) => sum + section.items.length, 0),\n releases,\n // Classify the same visible-section items emitted above, not the full\n // filtered set, so the bump matches the released sections (GH #28).\n suggested_semver: options.suggestSemver\n ? suggestSemverForItems(visibleSections.flatMap((section) => section.items))\n : undefined,\n };\n}\n\nfunction toDocumentItem(item: PmItem): ChangelogDocumentItem {\n return {\n id: item.id,\n title: toSingleLine(item.title),\n type: item.type,\n status: item.status,\n priority: item.priority,\n tags: item.tags,\n release: item.release,\n milestone: item.milestone,\n url: item.url,\n };\n}\n\nexport function mergeChangelog(\n existingMarkdown: string | undefined,\n generatedMarkdown: string,\n options: MergeChangelogOptions = {}\n): MergeChangelogResult {\n const existing = existingMarkdown?.trimEnd();\n const generated = generatedMarkdown.trimEnd();\n if (!existing) {\n return {\n markdown: generated + \"\\n\",\n action: \"created\",\n changed: true,\n };\n }\n\n const releaseSections = extractReleaseSections(generated);\n if (releaseSections.length === 0) {\n const unchanged = existing + \"\\n\";\n return {\n markdown: unchanged,\n action: \"unchanged\",\n changed: false,\n };\n }\n\n let next = ensureTitle(existing, options.title);\n let action: MergeChangelogResult[\"action\"] = \"unchanged\";\n\n // Keep a Changelog semantics (issue #47): when a release is generated — i.e.\n // the generated output carries a concrete version section and no `Unreleased`\n // section of its own — any leading `## Unreleased` section already in the\n // changelog is the pending-release section and must be PROMOTED into the\n // version it ships in, not left behind as a duplicate alongside the new\n // `## ` heading. Only the newest generated section may consume it,\n // and never when the generator itself emits an Unreleased section.\n const generatedHasUnreleased = releaseSections.some(\n (section) => normalizeReleaseHeadingKey(section.heading) === UNRELEASED_HEADING_KEY\n );\n const canPromoteUnreleased = !generatedHasUnreleased;\n\n for (const [index, releaseSection] of releaseSections.entries()) {\n const replacement = releaseSection.markdown.trimEnd();\n const replaced = replaceReleaseSection(next, releaseSection.heading, replacement);\n\n if (replaced.replaced) {\n next = replaced.markdown;\n action = \"replaced\";\n continue;\n }\n\n // Restrict promotion to the newest generated section (index 0). Otherwise,\n // when the newest version already exists (replaced above) an older section\n // that is missing could steal the pending `## Unreleased` and overwrite it,\n // losing the pending changes (GH #48 review).\n if (canPromoteUnreleased && index === 0) {\n const promoted = replaceReleaseSection(next, \"Unreleased\", replacement);\n if (promoted.replaced) {\n next = promoted.markdown;\n action = \"replaced\";\n continue;\n }\n }\n\n next = insertReleaseSection(next, releaseSection.heading, replacement);\n if (action !== \"replaced\") action = \"inserted\";\n }\n\n next = next.trimEnd() + \"\\n\";\n return {\n markdown: next,\n action,\n changed: next !== existing + \"\\n\",\n };\n}\n\nexport function readPmItems(options: ReadPmItemsOptions = {}): PmItem[] {\n const pmBin = options.pmBin ?? \"pm\";\n const args = [...(options.pmArgs ?? []), \"list-all\", \"--json\"];\n if (options.includeBody) {\n args.push(\"--include-body\");\n }\n if (options.pmRoot) {\n args.unshift(\"--path\", options.pmRoot);\n }\n\n const result = spawnSync(pmBin, args, {\n cwd: options.cwd,\n env: options.env,\n encoding: \"utf-8\",\n maxBuffer: options.maxBuffer ?? DEFAULT_PM_JSON_MAX_BUFFER,\n });\n if (result.status !== 0) {\n throw new Error(result.stderr || `${pmBin} list-all --json failed`);\n }\n\n return parsePmItemsJson(result.stdout);\n}\n\nexport function writeChangelog(options: WriteChangelogOptions): WriteChangelogResult {\n const output = resolve(options.output ?? \"CHANGELOG.md\");\n const generated = createChangelog(options);\n const mode = options.mode ?? \"replace\";\n const existing = existsSync(output) ? readFileSync(output, \"utf-8\") : undefined;\n const merged = mode === \"prepend\"\n ? mergeChangelog(existing, generated.markdown, { title: options.title })\n : replaceChangelog(existing, generated.markdown);\n\n if (!options.check) {\n writeFileSync(output, merged.markdown, \"utf-8\");\n }\n\n return {\n output,\n markdown: merged.markdown,\n action: merged.action,\n changed: merged.changed,\n itemCount: generated.itemCount,\n bytes: Buffer.byteLength(merged.markdown, \"utf-8\"),\n };\n}\n\nexport function parsePmItemsJson(raw: string): PmItem[] {\n const parsed = JSON.parse(raw) as unknown;\n if (Array.isArray(parsed)) return parsed as PmItem[];\n if (isRecord(parsed) && Array.isArray(parsed.items)) return parsed.items as PmItem[];\n throw new Error(\"Expected pm JSON to be an array or an object with an items array\");\n}\n\nfunction replaceChangelog(\n existingMarkdown: string | undefined,\n generatedMarkdown: string\n): MergeChangelogResult {\n const generated = generatedMarkdown.trimEnd() + \"\\n\";\n const existing = existingMarkdown?.trimEnd();\n if (!existing) {\n return {\n markdown: generated,\n action: \"created\",\n changed: true,\n };\n }\n\n const changed = generated !== existing + \"\\n\";\n return {\n markdown: generated,\n action: changed ? \"replaced\" : \"unchanged\",\n changed,\n };\n}\n\nfunction filterItems(options: GenerateChangelogOptions): PmItem[] {\n const items = filterItemsByStatus(options);\n if (options.releaseWindows && options.releaseWindows.length > 0) return items;\n\n return filterItemsByTime(items, {\n since: options.since,\n until: options.until,\n });\n}\n\nfunction filterItemsByStatus(options: GenerateChangelogOptions): PmItem[] {\n const statuses = new Set(\n (options.includeStatuses ?? DEFAULT_STATUSES).map((status) => status.toLowerCase())\n );\n\n return options.items\n .filter((item) => item.title)\n .filter((item) => {\n if (statuses.size === 0) return true;\n return statuses.has(String(item.status ?? \"\").toLowerCase());\n })\n .sort(compareItems);\n}\n\nfunction buildSections(items: PmItem[], options: GenerateChangelogOptions): ChangelogSection[] {\n if (options.releaseWindows && options.releaseWindows.length > 0) {\n return assignItemsToReleaseWindows(items, options.releaseWindows);\n }\n\n if (options.groupBy === \"release\" && !options.version) {\n return groupSectionsByMetadata(items, \"release\", \"Unreleased\");\n }\n\n if (options.groupBy === \"milestone\" && !options.version) {\n return groupSectionsByMetadata(items, \"milestone\", \"Unreleased\");\n }\n\n return [\n {\n heading: buildVersionHeading(options.version, options.date),\n items,\n },\n ];\n}\n\nfunction assignItemsToReleaseWindows(\n items: PmItem[],\n windows: ChangelogReleaseWindow[]\n): ChangelogSection[] {\n const buckets = new Map();\n for (const window of windows) buckets.set(window.heading, []);\n\n const releaseIndex = new Map();\n for (const window of windows) {\n if (!window.releaseTag) continue;\n const key = normalizeReleaseKey(window.releaseTag);\n if (!key || releaseIndex.has(key)) continue;\n releaseIndex.set(key, window.heading);\n }\n\n const remaining: PmItem[] = [];\n for (const item of items) {\n const releaseField = getStringField(item, \"release\");\n const key = releaseField ? normalizeReleaseKey(releaseField) : \"\";\n const heading = key ? releaseIndex.get(key) : undefined;\n if (heading) {\n buckets.get(heading)!.push(item);\n continue;\n }\n remaining.push(item);\n }\n\n for (const window of windows) {\n const filtered = filterItemsByTime(remaining, window);\n buckets.get(window.heading)!.push(...filtered);\n }\n\n return windows.map((window) => ({\n heading: window.heading,\n items: buckets.get(window.heading) ?? [],\n }));\n}\n\nfunction normalizeReleaseKey(value: string): string {\n return value.trim().replace(/^v/i, \"\").toLowerCase();\n}\n\n// Truncate an epoch-millisecond value to whole-second granularity. Release-tag\n// boundaries come from git committer dates at second precision, while pm item\n// timestamps carry milliseconds (see filterItemsByTime).\nconst toSecond = (ms: number): number => Math.floor(ms / 1000);\n\nfunction filterItemsByTime(\n items: PmItem[],\n window: { since?: string; sinceExclusive?: boolean; until?: string }\n): PmItem[] {\n const since = window.since ? Date.parse(window.since) : undefined;\n const until = window.until ? Date.parse(window.until) : undefined;\n\n // Compare window boundaries at second granularity. Comparing the raw values\n // pushes an item closed at 12:34:56.789 outside a window ending at\n // 12:34:56(.000), so it resurfaces under Unreleased (issue #41). An inclusive\n // `until` covers the whole boundary second, and an exclusive `since` excludes\n // the entire boundary second.\n //\n // Consequence for sub-second `since` inputs (non-exclusive `--since` flag): a\n // boundary like `--since 13:00:00.500Z` now also admits items closed earlier\n // in that same second (e.g. 13:00:00.000Z), where the previous millisecond\n // comparison would have excluded them. This is intentional: release-tag\n // boundaries are always second-precision, so the millisecond tail carried no\n // reliable signal.\n return items.filter((item) => {\n const timestamp = itemTimestamp(item);\n if (!timestamp) return since === undefined && until === undefined;\n const value = Date.parse(timestamp);\n if (Number.isNaN(value)) return false;\n if (since !== undefined) {\n const sinceSecond = toSecond(since);\n const valueSecond = toSecond(value);\n if (window.sinceExclusive ? valueSecond <= sinceSecond : valueSecond < sinceSecond) return false;\n }\n if (until !== undefined && toSecond(value) > toSecond(until)) return false;\n return true;\n });\n}\n\nfunction groupSectionsByMetadata(\n items: PmItem[],\n field: \"release\" | \"milestone\",\n fallback: string\n): ChangelogSection[] {\n const grouped = new Map();\n for (const item of items) {\n const key = getStringField(item, field) || fallback;\n const group = grouped.get(key) ?? [];\n group.push(item);\n grouped.set(key, group);\n }\n return Array.from(grouped.entries())\n .map(([heading, groupedItems]) => ({ heading, items: groupedItems }))\n .sort((a, b) => compareVersionHeadings(a.heading, b.heading, fallback));\n}\n\nfunction compareVersionHeadings(a: string, b: string, fallback: string): number {\n if (a === fallback) return -1;\n if (b === fallback) return 1;\n return compareVersionStrings(b, a);\n}\n\nfunction compareVersionStrings(a: string, b: string): number {\n const normalize = (v: string): string => v.replace(/^v/, \"\");\n const segmentsA = normalize(a).split(/[.\\-]/);\n const segmentsB = normalize(b).split(/[.\\-]/);\n const len = Math.max(segmentsA.length, segmentsB.length);\n for (let i = 0; i < len; i++) {\n const sa = segmentsA[i] ?? \"\";\n const sb = segmentsB[i] ?? \"\";\n const na = parseInt(sa, 10);\n const nb = parseInt(sb, 10);\n if (!Number.isNaN(na) && !Number.isNaN(nb)) {\n if (na !== nb) return na - nb;\n } else {\n const cmp = sa.localeCompare(sb);\n if (cmp !== 0) return cmp;\n }\n }\n return 0;\n}\n\nfunction buildVersionHeading(version: string | undefined, date: string | undefined): string {\n const heading = version?.trim() || \"Unreleased\";\n const stamp = date?.trim() || formatLocalDate(new Date());\n return `${heading} - ${stamp}`;\n}\n\nfunction extractReleaseSections(markdown: string): Array<{ heading: string; markdown: string }> {\n const releaseHeading = /^##\\s+(.+)$/gm;\n const matches = Array.from(markdown.matchAll(releaseHeading));\n return matches.map((match, index) => {\n const start = match.index ?? 0;\n const next = matches[index + 1];\n const end = next?.index ?? markdown.length;\n return {\n heading: match[1].trim(),\n markdown: markdown.slice(start, end).trimEnd(),\n };\n });\n}\n\nfunction replaceReleaseSection(\n markdown: string,\n heading: string,\n replacement: string\n): { markdown: string; replaced: boolean } {\n const releaseHeading = /^##\\s+(.+)$/gm;\n const matches = Array.from(markdown.matchAll(releaseHeading));\n const targetHeadingKey = normalizeReleaseHeadingKey(heading);\n const matchIndex = matches.findIndex(\n (match) => normalizeReleaseHeadingKey(match[1].trim()) === targetHeadingKey\n );\n if (matchIndex === -1) return { markdown, replaced: false };\n\n const match = matches[matchIndex];\n const start = match.index ?? 0;\n const nextMatch = matches[matchIndex + 1];\n const end = nextMatch?.index ?? markdown.length;\n const before = markdown.slice(0, start).trimEnd();\n const after = markdown.slice(end).trimStart();\n const merged = after ? `${before}\\n\\n${replacement}\\n\\n${after}` : `${before}\\n\\n${replacement}`;\n return { markdown: merged, replaced: true };\n}\n\n/** Normalized heading key for the pending `Unreleased` section. */\nconst UNRELEASED_HEADING_KEY = \"unreleased\";\n\nfunction normalizeReleaseHeadingKey(heading: string): string {\n const trimmed = heading.trim();\n const bracketed = trimmed.match(/^\\[([^\\]]+)\\](?:\\([^)]+\\))?(?:\\s+-\\s+.+)?$/);\n const version = bracketed?.[1] ?? trimmed.split(/\\s+-\\s+/, 1)[0] ?? trimmed;\n return version.trim().replace(/^v/i, \"\").toLowerCase();\n}\n\nfunction ensureTitle(markdown: string, title: string | undefined): string {\n if (/^#\\s+.+$/m.test(markdown)) return markdown;\n return `# ${title ?? DEFAULT_TITLE}\\n\\n${markdown.trimStart()}`;\n}\n\n/**\n * Insert a release section in chronological position (Unreleased first, then\n * newest-to-oldest by version) rather than always at the top. Used by the\n * prepend merge when a generated section has no existing heading to replace,\n * so a backfilled older release cannot land above newer ones or the pending\n * `## Unreleased` section (GH #48 review).\n */\nfunction insertReleaseSection(markdown: string, heading: string, replacement: string): string {\n const matches = Array.from(markdown.matchAll(/^##\\s+(.+)$/gm));\n if (matches.length === 0) return insertAfterTitle(markdown, replacement);\n\n const newKey = normalizeReleaseHeadingKey(heading);\n const insertBefore = matches.find((match) => {\n const key = normalizeReleaseHeadingKey(match[1].trim());\n if (key === UNRELEASED_HEADING_KEY) return false; // never displace the pending section\n if (newKey === UNRELEASED_HEADING_KEY) return true; // a new Unreleased sorts ahead of any version\n return compareVersionStrings(newKey, key) > 0; // place before the first strictly-older release\n });\n\n if (!insertBefore) {\n return `${markdown.trimEnd()}\\n\\n${replacement}`;\n }\n const start = insertBefore.index ?? 0;\n const before = markdown.slice(0, start).trimEnd();\n const after = markdown.slice(start).trimStart();\n // `before` is normally the `# Changelog` title (ensureTitle runs first), but\n // guard the empty case so we never emit leading blank lines.\n return before ? `${before}\\n\\n${replacement}\\n\\n${after}` : `${replacement}\\n\\n${after}`;\n}\n\nfunction insertAfterTitle(markdown: string, releaseSection: string): string {\n const titleMatch = markdown.match(/^#\\s+.+$/m);\n if (!titleMatch || titleMatch.index === undefined) {\n return `${releaseSection}\\n\\n${markdown.trimStart()}`;\n }\n\n const titleEnd = titleMatch.index + titleMatch[0].length;\n const before = markdown.slice(0, titleEnd).trimEnd();\n const after = markdown.slice(titleEnd).trim();\n if (!after) return `${before}\\n\\n${releaseSection}`;\n return `${before}\\n\\n${releaseSection}\\n\\n${after}`;\n}\n\n// OPT-IN (`--conventional`): keep-a-changelog category -> Conventional-Commits\n// style heading. Every key maps so the mapping is total; values mirror common\n// conventional-changelog section titles.\nconst CONVENTIONAL_HEADINGS: Record = {\n Added: \"Features\",\n Changed: \"Changes\",\n Fixed: \"Bug Fixes\",\n Removed: \"Reverts\",\n Security: \"Security\",\n Deprecated: \"Deprecations\",\n Other: \"Other\",\n};\n\n/**\n * OPT-IN (`--section-by type|status|label`): group a release's items by a\n * single item field instead of the keep-a-changelog category. Groups are\n * ordered by first appearance (items arrive pre-sorted by `compareItems`), so\n * output is deterministic. Items missing the field fall into an \"Other\" /\n * \"Unlabeled\" bucket. For `label`, an item may appear under several headings\n * (one per tag) — this is by design and clearly opt-in.\n */\nfunction groupByField(\n items: PmItem[],\n sectionBy: Exclude\n): Array<{ heading: string; items: PmItem[] }> {\n const groups = new Map();\n const push = (heading: string, item: PmItem): void => {\n const bucket = groups.get(heading) ?? [];\n bucket.push(item);\n groups.set(heading, bucket);\n };\n\n for (const item of items) {\n if (sectionBy === \"type\") {\n push(titleCase(typeof item.type === \"string\" && item.type.trim() ? item.type.trim() : \"Other\"), item);\n } else if (sectionBy === \"status\") {\n push(titleCase(typeof item.status === \"string\" && item.status.trim() ? item.status.trim() : \"Unknown\"), item);\n } else {\n const tags = [\n ...new Set(\n (Array.isArray(item.tags) ? item.tags : [])\n .filter((tag): tag is string => typeof tag === \"string\")\n .map((tag) => tag.trim())\n .filter(Boolean)\n ),\n ];\n if (tags.length === 0) {\n push(\"Unlabeled\", item);\n } else {\n for (const tag of tags) push(tag, item);\n }\n }\n }\n\n return Array.from(groups.entries()).map(([heading, groupedItems]) => ({ heading, items: groupedItems }));\n}\n\nfunction titleCase(value: string): string {\n return value\n .replace(/[_-]+/g, \" \")\n .replace(/\\s+/g, \" \")\n .trim()\n .replace(/\\b\\w/g, (char) => char.toUpperCase());\n}\n\n/**\n * OPT-IN (`--contributors`): unique contributor handles for a release, ordered\n * by first appearance. Prefers `assignee`, falls back to `author`; ignores the\n * `unknown` placeholder pm writes when no author is recorded.\n */\nfunction collectContributors(items: PmItem[]): string[] {\n const seen = new Set();\n const ordered: string[] = [];\n for (const item of items) {\n const candidate = pickContributor(item.assignee) ?? pickContributor(item.author);\n if (!candidate) continue;\n const key = candidate.toLowerCase();\n if (seen.has(key)) continue;\n seen.add(key);\n ordered.push(candidate);\n }\n return ordered;\n}\n\nfunction pickContributor(value: unknown): string | undefined {\n if (typeof value !== \"string\") return undefined;\n const trimmed = value.trim();\n if (!trimmed || trimmed.toLowerCase() === \"unknown\") return undefined;\n return trimmed;\n}\n\nfunction groupByCategory(items: PmItem[]): Map {\n const grouped = new Map();\n for (const item of items) {\n const category = classifyItem(item);\n const categoryItems = grouped.get(category) ?? [];\n categoryItems.push(item);\n grouped.set(category, categoryItems);\n }\n return grouped;\n}\n\nconst BUG_LIKE_ITEM_TYPES: ReadonlySet = new Set([\"issue\", \"bug\", \"bugfix\", \"defect\"]);\nconst CHANGED_NEEDLES = [\"change\", \"changed\", \"refactor\", \"update\", \"updated\", \"improve\"];\nconst REMOVED_NEEDLES = [\"removed\", \"remove\", \"deleted\", \"delete\"];\n\nfunction classifyItem(item: PmItem): Category {\n // Strip CLI-flag-like tokens from titles before scanning. Without this, an\n // item titled \"pm --add fails...\" gets classified as \"Added\" because\n // the word \"add\" matches inside \"--add\". The pattern:\n // - Negative lookbehind on `[\\w-]` so in-word hyphens like \"non-add\" or\n // \"in-test\" stay intact, while flags wrapped in punctuation/quotes\n // (`\\`--add\\``, `(--add)`, `[--add]`) still match.\n // - Accepts 1 or 2 leading dashes (covers `-x` POSIX shorts too).\n // - First char after the dashes is alnum (lets `--2fa` work).\n // - Body is the alnum/underscore/hyphen flag name, optionally followed by\n // `=` where value runs to the next whitespace. This wholesale\n // strips `--url=https://example.com/add` so URL/path values don't leak\n // spurious keyword matches downstream.\n //\n // Tags and type still contribute their full token, so an explicit\n // `feature`/`added` tag still wins regardless of title content.\n const sanitizedTitle = (item.title ?? \"\").replace(/(? new RegExp(`\\\\b${escapeRegExp(needle)}\\\\b`).test(value));\n}\n\nconst SELECTION_SAMPLE_LIMIT = 3;\n\nfunction sampleItems(items: PmItem[]): string[] {\n const labels: string[] = [];\n const seen = new Set();\n for (const item of items) {\n const label = sampleItemLabel(item);\n if (seen.has(label)) continue;\n seen.add(label);\n labels.push(label);\n if (labels.length >= SELECTION_SAMPLE_LIMIT) break;\n }\n return labels;\n}\n\nfunction sampleItemLabel(item: PmItem): string {\n const id = typeof item.id === \"string\" && item.id.trim() !== \"\"\n ? item.id.trim()\n : \"(no-id)\";\n const title = typeof item.title === \"string\" && item.title.trim() !== \"\"\n ? toSingleLine(item.title)\n : \"(untitled)\";\n return `${id}: ${title}`;\n}\n\nfunction buildSelectionHints(input: {\n visibleItemCount: number;\n hasReleaseWindows: boolean;\n excludedCounts: {\n missing_title: number;\n status: number;\n time_window: number;\n release_window: number;\n hidden_by_visibility: number;\n };\n}): string[] {\n const hints: string[] = [];\n if (input.excludedCounts.status > 0) {\n hints.push(\"Some items were excluded by status; expand --status (for example: --status open,closed).\");\n }\n if (input.excludedCounts.time_window > 0) {\n hints.push(\"Time filtering excluded items; widen --since/--until if those items should be included.\");\n }\n if (input.hasReleaseWindows && input.excludedCounts.release_window > 0) {\n hints.push(\"Some items fell outside release tag windows; verify tag boundaries or item release metadata.\");\n }\n if (input.excludedCounts.hidden_by_visibility > 0) {\n hints.push(\"Visibility narrowing hid sections; relax --limit or --since-version to include older releases.\");\n }\n if (input.visibleItemCount === 0 && hints.length === 0) {\n hints.push(\"No items matched the current filters.\");\n }\n return hints;\n}\n\nfunction formatItem(item: PmItem, options: GenerateChangelogOptions): string {\n const title = escapeMarkdown(toSingleLine(item.title));\n const id = formatItemId(item, options);\n const metadata = formatItemMetadata(item, options);\n const link = options.includeLinks ? formatLink(item.url) : \"\";\n const preview = formatBodyPreview(item, options);\n return `${title}${id}${metadata}${link}${preview}`;\n}\n\nfunction formatItemMetadata(item: PmItem, options: GenerateChangelogOptions): string {\n if (!options.includeMetadata) return \"\";\n const parts: string[] = [];\n if (typeof item.type === \"string\" && item.type.trim()) parts.push(`type:${item.type.trim()}`);\n if (typeof item.status === \"string\" && item.status.trim()) parts.push(`status:${item.status.trim()}`);\n if (typeof item.priority === \"number\" && Number.isFinite(item.priority)) parts.push(`P${item.priority}`);\n const release = getStringField(item, \"release\");\n if (release) parts.push(`release:${release}`);\n const milestone = getStringField(item, \"milestone\");\n if (milestone) parts.push(`milestone:${milestone}`);\n if (parts.length === 0) return \"\";\n return ` _${parts.map((part) => escapeMarkdown(toSingleLine(part))).join(\"; \")}_`;\n}\n\n/**\n * OPT-IN (`--body-preview `): append a truncated, single-lined, escaped\n * preview of the item body. Returns \"\" when the flag is unset/0 or the item has\n * no body, so default output is byte-identical. Truncation appends an ellipsis\n * only when the body actually exceeds N characters.\n */\nfunction formatBodyPreview(item: PmItem, options: GenerateChangelogOptions): string {\n const limit = options.bodyPreview && options.bodyPreview > 0 ? options.bodyPreview : 0;\n if (limit === 0) return \"\";\n // pm workspaces store long-form prose in `description`; `body` is usually\n // empty. Prefer a non-empty `body`, then fall back to `description`, so the\n // preview actually has content against real pm items.\n const rawSource =\n typeof item.body === \"string\" && item.body.trim() !== \"\"\n ? item.body\n : typeof item.description === \"string\"\n ? item.description\n : \"\";\n const body = toSingleLine(rawSource);\n if (!body) return \"\";\n const truncated = body.length > limit ? `${body.slice(0, limit)}…` : body;\n return ` — ${escapeMarkdown(truncated)}`;\n}\n\n/**\n * OPT-IN (`--emoji-prefix`): prefix a known heading with a conventional emoji.\n * Unknown headings (custom labels/types) pass through unchanged. Off by\n * default, so headings render exactly as before.\n */\nfunction maybeEmoji(heading: string, options: GenerateChangelogOptions): string {\n if (!options.emojiPrefix) return heading;\n const emoji = HEADING_EMOJI[heading];\n return emoji ? `${emoji} ${heading}` : heading;\n}\n\nconst HEADING_EMOJI: Record = {\n // keep-a-changelog categories\n Added: \"🎉\",\n Changed: \"♻️\",\n Fixed: \"🐛\",\n Removed: \"🗑️\",\n Security: \"🔒\",\n Deprecated: \"⚠️\",\n Other: \"📦\",\n // conventional-commits headings (when --conventional is also set)\n Features: \"🎉\",\n Changes: \"♻️\",\n \"Bug Fixes\": \"🐛\",\n Reverts: \"⏪\",\n Deprecations: \"⚠️\",\n // breaking changes section\n \"Breaking Changes\": \"💥\",\n};\n\n/**\n * Detect whether an item is a breaking change. Signals (any one suffices):\n * - a truthy `breaking` flag on the item or in its metadata, OR\n * - an explicit breaking tag (`breaking`, `breaking-change`, `breaking_change`), OR\n * - the word \"breaking\" appearing as a standalone token in the type or title.\n *\n * Negated/safe phrasings such as \"non-breaking\", \"non breaking\", \"not breaking\"\n * and \"no breaking\" are stripped before the token check, so describing a change\n * as non-breaking no longer triggers a major-bump suggestion (GH #26).\n * Used only by the opt-in `--breaking-changes` / `--suggest-semver` features.\n */\nfunction isBreakingItem(item: PmItem): boolean {\n if (isTruthyFlag(item.breaking)) return true;\n if (isTruthyFlag(item.metadata?.[\"breaking\"])) return true;\n\n const tags = Array.isArray(item.tags)\n ? item.tags.filter((t): t is string => typeof t === \"string\")\n : [];\n // An explicit tag is an unambiguous, intentional breaking signal.\n if (tags.some((t) => BREAKING_TAGS.has(normalizeTag(t)))) return true;\n\n const haystack = [typeof item.type === \"string\" ? item.type : \"\", typeof item.title === \"string\" ? item.title : \"\", ...tags]\n .join(\" \")\n .toLowerCase();\n // Drop negated/safe phrasings first (\"non-breaking\", \"not breaking\", …) so\n // they cannot satisfy the standalone-token check below.\n const withoutNegations = haystack.replace(NEGATED_BREAKING, \" \");\n return BREAKING_TOKEN.test(withoutNegations);\n}\n\n/** Tags that explicitly mark a breaking change (compared after normalization). */\nconst BREAKING_TAGS = new Set([\"breaking\", \"breakingchange\", \"breaking-change\", \"breaking_change\"]);\n\nfunction normalizeTag(tag: string): string {\n return tag.trim().toLowerCase();\n}\n\n/** Negated/safe \"breaking\" phrasings to strip before the standalone-token test. */\nconst NEGATED_BREAKING = /\\b(?:non[-\\s]?breaking|not\\s+(?:a\\s+)?breaking|no\\s+breaking)\\b/g;\n\n/** \"breaking\" as a standalone word (not part of e.g. \"nonbreaking\"). */\nconst BREAKING_TOKEN = /\\bbreaking\\b/;\n\nfunction isTruthyFlag(value: unknown): boolean {\n if (value === true) return true;\n if (typeof value === \"string\") {\n const v = value.trim().toLowerCase();\n return v === \"true\" || v === \"yes\" || v === \"1\";\n }\n if (typeof value === \"number\") return value === 1;\n return false;\n}\n\n/**\n * OPT-IN (`--suggest-semver`): classify the in-scope items into breaking /\n * feature / fix / other and recommend a semver bump. Emitted as JSON or a\n * footer note; never alters default markdown.\n */\nexport function suggestSemver(options: GenerateChangelogOptions): SemverSuggestion {\n // Base the suggestion on the items that actually render (after section\n // building, empty-section pruning and --limit/--since-version narrowing) so a\n // bump is never reported from releases hidden by visibility flags (GH #28).\n // With no narrowing flags this is exactly filterItems(options), so the\n // default suggestion is unchanged.\n return suggestSemverForItems(visibleChangelogItems(options));\n}\n\n/**\n * The items that actually render for the given options: the union of all\n * visible release-section items after filtering, empty-section pruning and\n * `--limit`/`--since-version` narrowing. Exposed so semver suggestions and the\n * structured `--changelog-json` document classify the same set the markdown\n * emits (GH #28).\n */\nexport function visibleChangelogItems(options: GenerateChangelogOptions): PmItem[] {\n const filtered = filterItems(options);\n const sections = buildSections(filtered, options);\n const candidateSections = options.includeEmpty\n ? sections\n : sections.filter((section) => section.items.length > 0);\n const visibleSections = limitSections(candidateSections, options);\n return visibleSections.flatMap((section) => section.items);\n}\n\n/**\n * OPT-IN (`--explain`): return machine-readable diagnostics showing how input\n * items moved through title/status/time/release-window filters and visibility\n * narrowing (`--limit`/`--since-version`). Designed for agent/operator UX when\n * output is unexpectedly empty or smaller than expected.\n */\nexport function explainChangelogSelection(options: GenerateChangelogOptions): ChangelogSelectionReport {\n const statuses = new Set((options.includeStatuses ?? DEFAULT_STATUSES).map((status) => status.toLowerCase()));\n const hasReleaseWindows = Boolean(options.releaseWindows && options.releaseWindows.length > 0);\n\n const withTitle: PmItem[] = [];\n const missingTitle: PmItem[] = [];\n for (const item of options.items) {\n if (item.title) withTitle.push(item);\n else missingTitle.push(item);\n }\n\n const afterStatus: PmItem[] = [];\n const excludedByStatus: PmItem[] = [];\n for (const item of withTitle) {\n if (statuses.size === 0 || statuses.has(String(item.status ?? \"\").toLowerCase())) {\n afterStatus.push(item);\n } else {\n excludedByStatus.push(item);\n }\n }\n\n const afterTime = hasReleaseWindows\n ? afterStatus\n : filterItemsByTime(afterStatus, {\n since: options.since,\n until: options.until,\n });\n const afterTimeRefs = new Set(afterTime);\n const excludedByTime = hasReleaseWindows\n ? []\n : afterStatus.filter((item) => !afterTimeRefs.has(item));\n\n const sections = buildSections(afterTime, options);\n const assignedToReleaseWindows = new Set(\n hasReleaseWindows ? sections.flatMap((section) => section.items) : []\n );\n const excludedByReleaseWindow = hasReleaseWindows\n ? afterTime.filter((item) => !assignedToReleaseWindows.has(item))\n : [];\n\n const candidateSections = options.includeEmpty\n ? sections\n : sections.filter((section) => section.items.length > 0);\n const visibleSections = limitSections(candidateSections, options);\n const visibleSectionRefs = new Set(visibleSections);\n const hiddenByVisibility = candidateSections\n .filter((section) => !visibleSectionRefs.has(section))\n .flatMap((section) => section.items);\n const candidateItems = candidateSections.flatMap((section) => section.items);\n const visibleItems = visibleSections.flatMap((section) => section.items);\n\n const excludedCounts = {\n missing_title: missingTitle.length,\n status: excludedByStatus.length,\n time_window: excludedByTime.length,\n release_window: excludedByReleaseWindow.length,\n hidden_by_visibility: hiddenByVisibility.length,\n };\n const visibleItemCount = visibleItems.length;\n\n return {\n filters: {\n statuses: Array.from(statuses),\n since: options.since,\n until: options.until,\n release_windows: hasReleaseWindows,\n include_empty: Boolean(options.includeEmpty),\n limit: options.limit,\n since_version: options.sinceVersion,\n },\n stage_counts: {\n input: options.items.length,\n after_title: withTitle.length,\n after_status: afterStatus.length,\n after_time: afterTime.length,\n after_release_windows: hasReleaseWindows ? afterTime.length - excludedByReleaseWindow.length : undefined,\n candidate_sections: candidateSections.length,\n visible_sections: visibleSections.length,\n candidate_items: candidateItems.length,\n visible_items: visibleItemCount,\n },\n excluded_counts: excludedCounts,\n sample_items: {\n missing_title: sampleItems(missingTitle),\n status: sampleItems(excludedByStatus),\n time_window: sampleItems(excludedByTime),\n release_window: sampleItems(excludedByReleaseWindow),\n hidden_by_visibility: sampleItems(hiddenByVisibility),\n },\n hints: buildSelectionHints({\n visibleItemCount,\n hasReleaseWindows,\n excludedCounts,\n }),\n };\n}\n\n/** Classify an explicit item set into a semver bump (no option-driven filtering). */\nexport function suggestSemverForItems(items: PmItem[]): SemverSuggestion {\n let breaking = 0;\n let feature = 0;\n let fix = 0;\n let other = 0;\n for (const item of items) {\n if (isBreakingItem(item)) {\n breaking++;\n continue;\n }\n const category = classifyItem(item);\n if (category === \"Added\") feature++;\n else if (category === \"Fixed\") fix++;\n else other++;\n }\n\n let bump: SemverBump;\n let reason: string;\n if (breaking > 0) {\n bump = \"major\";\n reason = `${breaking} breaking change${breaking === 1 ? \"\" : \"s\"}`;\n } else if (feature > 0) {\n bump = \"minor\";\n reason = `${feature} feature${feature === 1 ? \"\" : \"s\"}`;\n } else if (fix > 0) {\n bump = \"patch\";\n reason = `${fix} fix${fix === 1 ? \"\" : \"es\"}`;\n } else if (other > 0) {\n bump = \"patch\";\n reason = `${other} other change${other === 1 ? \"\" : \"s\"}`;\n } else {\n bump = \"none\";\n reason = \"no changes\";\n }\n\n return { bump, reason, counts: { breaking, feature, fix, other } };\n}\n\nfunction formatItemId(item: PmItem, options: GenerateChangelogOptions): string {\n if (!item.id) return \"\";\n const escapedId = escapeMarkdown(item.id);\n if (options.itemUrlBase) {\n const base = options.itemUrlBase.replace(/\\/$/, \"\");\n const typeDir = itemTypeToDir(item.type);\n const url = `${base}/${typeDir}/${item.id}.toon`;\n return ` ([${escapedId}](${url}))`;\n }\n return ` (${escapedId})`;\n}\n\nfunction itemTypeToDir(type: string | undefined): string {\n const t = (type ?? \"issue\").toLowerCase();\n const irregular: Record = { story: \"stories\" };\n return irregular[t] ?? `${t}s`;\n}\n\nfunction formatLink(url: string | undefined): string {\n if (!url) return \"\";\n try {\n const parsed = new URL(toSingleLine(url));\n if (parsed.protocol !== \"https:\" && parsed.protocol !== \"http:\") return \"\";\n parsed.username = \"\";\n parsed.password = \"\";\n parsed.search = \"\";\n parsed.hash = \"\";\n return ` [link](${parsed.href.replace(/\\)/g, \"%29\")})`;\n } catch {\n return \"\";\n }\n}\n\nfunction getStringField(item: PmItem, field: \"release\" | \"milestone\"): string | undefined {\n const direct = item[field];\n if (typeof direct === \"string\" && direct.trim()) return direct.trim();\n const fromMetadata = item.metadata?.[field];\n if (typeof fromMetadata === \"string\" && fromMetadata.trim()) return fromMetadata.trim();\n return undefined;\n}\n\nfunction compareItems(a: PmItem, b: PmItem): number {\n const aTime = Date.parse(itemTimestamp(a) ?? \"\");\n const bTime = Date.parse(itemTimestamp(b) ?? \"\");\n if (!Number.isNaN(aTime) && !Number.isNaN(bTime) && aTime !== bTime) {\n return bTime - aTime;\n }\n return a.title.localeCompare(b.title);\n}\n\nfunction itemTimestamp(item: PmItem): string | undefined {\n return item.closed_at ?? item.updated_at ?? item.created_at;\n}\n\nfunction escapeMarkdown(value: string): string {\n return value.replace(/([\\\\`*_[\\]()#|>])/g, \"\\\\$1\");\n}\n\nfunction toSingleLine(value: string): string {\n return value.trim().replace(/\\s+/g, \" \");\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction isRecord(value: unknown): value is Record {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction formatLocalDate(date: Date): string {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, \"0\");\n const day = String(date.getDate()).padStart(2, \"0\");\n return `${year}-${month}-${day}`;\n}\n"]} \ No newline at end of file diff --git a/.agents/pm/extensions/pm-changelog/manifest.json b/.agents/pm/extensions/pm-changelog/manifest.json index 4e88ce930..3b7ab26e9 100644 --- a/.agents/pm/extensions/pm-changelog/manifest.json +++ b/.agents/pm/extensions/pm-changelog/manifest.json @@ -1,6 +1,6 @@ { "name": "pm-changelog", - "version": "2026.6.13", + "version": "2026.6.13-1", "manifest_version": 2, "description": "Generate CHANGELOG.md release notes from pm-cli items", "author": "@unbraind", diff --git a/.agents/pm/extensions/pm-changelog/package.json b/.agents/pm/extensions/pm-changelog/package.json index c7deb7e36..705fc28b4 100644 --- a/.agents/pm/extensions/pm-changelog/package.json +++ b/.agents/pm/extensions/pm-changelog/package.json @@ -1,6 +1,6 @@ { "name": "pm-changelog", - "version": "2026.6.13", + "version": "2026.6.13-1", "description": "Generate CHANGELOG.md files from pm-cli items for local and CI usage", "repository": { "type": "git", @@ -47,7 +47,7 @@ "build:test": "tsc -p tsconfig.test.json", "changelog": "node dist/cli.js --pm-root .agents/pm --mode prepend --output CHANGELOG.md --release-version-from-package --since-previous-tag --until-release-tag --item-url-base https://github.com/unbraind/pm-changelog/blob/main/.agents/pm", "changelog:full": "node dist/cli.js --pm-root .agents/pm --mode replace --output CHANGELOG.md --all-release-tags --release-version-from-package --item-url-base https://github.com/unbraind/pm-changelog/blob/main/.agents/pm", - "changelog:check": "node dist/cli.js --pm-root .agents/pm --mode replace --output CHANGELOG.md --all-release-tags --release-version-from-package --item-url-base https://github.com/unbraind/pm-changelog/blob/main/.agents/pm --check", + "changelog:check": "npm run changelog -- --check", "audit:prod": "npm audit --omit=dev", "pack:dry-run": "npm pack --dry-run", "prepack": "npm run build", diff --git a/.agents/pm/features/pm-7c48.toon b/.agents/pm/features/pm-7c48.toon new file mode 100644 index 000000000..90aac80af --- /dev/null +++ b/.agents/pm/features/pm-7c48.toon @@ -0,0 +1,16 @@ +id: pm-7c48 +title: "pm create/update --body-file: load body markdown from a file (GH-214)" +description: "" +type: Feature +status: closed +priority: 2 +tags[3]: "area:cli",ergonomics,gh-214 +created_at: "2026-06-13T20:54:33.250Z" +updated_at: "2026-06-13T21:20:48.555Z" +author: claude-code-agent +parent: pm-mpbb +resolution: "Added --body-file to pm create and pm update via new src/core/io/body-file.ts resolveBodyFileContent helper (CLI-only input alias, mutually exclusive with --body, actionable errors for conflict/empty-path/unreadable). Wired into create+update actions before normalize, CREATE/UPDATE_FLAG_CONTRACTS + zsh/fish completion + contracts golden + docs. 100% unit-covered + in-process integration tests." +comments[1]{created_at,author,text}: + "2026-06-13T20:59:26.222Z",claude-code-agent,"Plan: new core helper src/core/io/body-file.ts resolveBodyFileContent(bodyFile, body, readFileImpl?) — reads file (utf8), errors if --body also set (mutually exclusive) or path missing/unreadable. Register --body-file commander option on create+update (direct .option) + add to CREATE_FLAG_CONTRACTS/UPDATE_FLAG_CONTRACTS for completion. Resolve+delete in create/update actions before normalize. CLI-only (no MCP — file paths meaningless over MCP, like history --diff). Mutual-exclusion error mirrors existing guided-error shape." +close_reason: "Added --body-file to pm create and pm update via new src/core/io/body-file.ts resolveBodyFileContent helper (CLI-only input alias, mutually exclusive with --body, actionable errors for conflict/empty-path/unreadable). Wired into create+update actions before normalize, CREATE/UPDATE_FLAG_CONTRACTS + zsh/fish completion + contracts golden + docs. 100% unit-covered + in-process integration tests." +body: "Add --body-file to pm create and pm update so agents can supply long markdown bodies (multi-paragraph, code blocks, tables) from a file instead of escaping huge inline --body strings or doing a second pm append call. Mutually exclusive with inline --body. '-' reads from stdin. Reduces round-trips (project management = context management)." diff --git a/.agents/pm/features/pm-i1mu.toon b/.agents/pm/features/pm-i1mu.toon new file mode 100644 index 000000000..4b6434fc5 --- /dev/null +++ b/.agents/pm/features/pm-i1mu.toon @@ -0,0 +1,16 @@ +id: pm-i1mu +title: "pm close: short aliases -m/-r/-d for --message/--reason/--duplicate-of (GH-226)" +description: "" +type: Feature +status: closed +priority: 3 +tags[3]: "area:cli",ergonomics,gh-226 +created_at: "2026-06-13T20:54:33.503Z" +updated_at: "2026-06-13T21:20:48.933Z" +author: claude-code-agent +parent: pm-mpbb +resolution: "Added Commander short aliases on pm close: -m (--message), -r (--reason), -d (--duplicate-of). No semantic change; verified no conflicts. In-process integration test asserts all three parse and apply." +comments[1]{created_at,author,text}: + "2026-06-13T20:59:26.514Z",claude-code-agent,"Plan: add Commander short aliases on close command — -m/--message, -r/--reason, -d/--duplicate-of. No semantic change; -m/-r/-d are unused on close. Verified -d free (close has no --description). Add tests asserting parse." +close_reason: "Added Commander short aliases on pm close: -m (--message), -r (--reason), -d (--duplicate-of). No semantic change; verified no conflicts. In-process integration test asserts all three parse and apply." +body: "Agents typing many commands naturally try -m (message), -r (reason), -d (duplicate-of) on pm close; all currently error. Add Commander short aliases consistent with -h/--help. No semantic change." diff --git a/.agents/pm/history/pm-7c48.jsonl b/.agents/pm/history/pm-7c48.jsonl new file mode 100644 index 000000000..46763700c --- /dev/null +++ b/.agents/pm/history/pm-7c48.jsonl @@ -0,0 +1,4 @@ +{"ts":"2026-06-13T20:54:33.250Z","author":"claude-code-agent","op":"create","patch":[{"op":"replace","path":"/body","value":"Add --body-file to pm create and pm update so agents can supply long markdown bodies (multi-paragraph, code blocks, tables) from a file instead of escaping huge inline --body strings or doing a second pm append call. Mutually exclusive with inline --body. '-' reads from stdin. Reduces round-trips (project management = context management)."},{"op":"add","path":"/metadata/id","value":"pm-7c48"},{"op":"add","path":"/metadata/title","value":"pm create/update --body-file: load body markdown from a file (GH-214)"},{"op":"add","path":"/metadata/description","value":""},{"op":"add","path":"/metadata/type","value":"Feature"},{"op":"add","path":"/metadata/status","value":"open"},{"op":"add","path":"/metadata/priority","value":2},{"op":"add","path":"/metadata/tags","value":["area:cli","ergonomics","gh-214"]},{"op":"add","path":"/metadata/created_at","value":"2026-06-13T20:54:33.250Z"},{"op":"add","path":"/metadata/updated_at","value":"2026-06-13T20:54:33.250Z"},{"op":"add","path":"/metadata/author","value":"claude-code-agent"},{"op":"add","path":"/metadata/parent","value":"pm-mpbb"}],"before_hash":"3cc22dff72be7b14824654a7a64ea62b04799939b2fee54c1b5f52ca60bf6df0","after_hash":"edf068eef3f59c90d3dea03f19a1922cd6636899c65a97103ec8abd7620197dd","message":""} +{"ts":"2026-06-13T20:59:25.417Z","author":"claude-code-agent","op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-13T20:59:25.417Z"},{"op":"replace","path":"/metadata/status","value":"in_progress"}],"before_hash":"edf068eef3f59c90d3dea03f19a1922cd6636899c65a97103ec8abd7620197dd","after_hash":"51530ecdf1ca1b429e99a52e493395eb41b06c6df0a95b6afcd97d022ff1dbaf"} +{"ts":"2026-06-13T20:59:26.222Z","author":"claude-code-agent","op":"comment_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-13T20:59:26.222Z"},{"op":"add","path":"/metadata/comments","value":[{"created_at":"2026-06-13T20:59:26.222Z","author":"claude-code-agent","text":"Plan: new core helper src/core/io/body-file.ts resolveBodyFileContent(bodyFile, body, readFileImpl?) — reads file (utf8), errors if --body also set (mutually exclusive) or path missing/unreadable. Register --body-file commander option on create+update (direct .option) + add to CREATE_FLAG_CONTRACTS/UPDATE_FLAG_CONTRACTS for completion. Resolve+delete in create/update actions before normalize. CLI-only (no MCP — file paths meaningless over MCP, like history --diff). Mutual-exclusion error mirrors existing guided-error shape."}]}],"before_hash":"51530ecdf1ca1b429e99a52e493395eb41b06c6df0a95b6afcd97d022ff1dbaf","after_hash":"36e2a2201b3d3c160d360a38a1de3a38bcc61a1eee1b877fae3b760461086700"} +{"ts":"2026-06-13T21:20:48.555Z","author":"claude-code-agent","op":"close","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-13T21:20:48.555Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/resolution","value":"Added --body-file to pm create and pm update via new src/core/io/body-file.ts resolveBodyFileContent helper (CLI-only input alias, mutually exclusive with --body, actionable errors for conflict/empty-path/unreadable). Wired into create+update actions before normalize, CREATE/UPDATE_FLAG_CONTRACTS + zsh/fish completion + contracts golden + docs. 100% unit-covered + in-process integration tests."},{"op":"add","path":"/metadata/close_reason","value":"Added --body-file to pm create and pm update via new src/core/io/body-file.ts resolveBodyFileContent helper (CLI-only input alias, mutually exclusive with --body, actionable errors for conflict/empty-path/unreadable). Wired into create+update actions before normalize, CREATE/UPDATE_FLAG_CONTRACTS + zsh/fish completion + contracts golden + docs. 100% unit-covered + in-process integration tests."}],"before_hash":"36e2a2201b3d3c160d360a38a1de3a38bcc61a1eee1b877fae3b760461086700","after_hash":"2875fc055c780a4dd5fd365eb80e39613ba5909e892f5e584ec4b90f78de903a","message":"Ship GH-214 --body-file"} diff --git a/.agents/pm/history/pm-7x8d.jsonl b/.agents/pm/history/pm-7x8d.jsonl index fc34a9728..48b175dd3 100644 --- a/.agents/pm/history/pm-7x8d.jsonl +++ b/.agents/pm/history/pm-7x8d.jsonl @@ -1 +1,4 @@ {"ts":"2026-06-12T16:19:39.149Z","author":"maintainer-agent","op":"create","patch":[{"op":"add","path":"/metadata/id","value":"pm-7x8d"},{"op":"add","path":"/metadata/title","value":"pm close: when require_close_reason is on, accept --resolution text as the close reason instead of hard-blocking"},{"op":"add","path":"/metadata/description","value":"Repro: with governance.require_close_reason enabled (sandbox default), 'pm close --resolution \"Fixed empty-password guard\" --expected ... --actual ...' fails with 'Close reason text is required'. The agent already supplied a complete closure narrative; per the never-block philosophy the resolution text is a perfectly good one-line closing summary. Suggestion: when --reason/positional text is absent but --resolution is provided, derive the close reason from the resolution (and note the derivation in output), keeping the hard error only when neither is present. The current error message is actionable (examples included) so this is polish, not a dead-end."},{"op":"add","path":"/metadata/type","value":"Task"},{"op":"add","path":"/metadata/status","value":"open"},{"op":"add","path":"/metadata/priority","value":3},{"op":"add","path":"/metadata/tags","value":["agent-ux","cli","dogfood-2026-06-12","never-block"]},{"op":"add","path":"/metadata/created_at","value":"2026-06-12T16:19:39.149Z"},{"op":"add","path":"/metadata/updated_at","value":"2026-06-12T16:19:39.149Z"},{"op":"add","path":"/metadata/author","value":"maintainer-agent"}],"before_hash":"3cc22dff72be7b14824654a7a64ea62b04799939b2fee54c1b5f52ca60bf6df0","after_hash":"2b6c9c99ec8f0110dc81ad5037dee4a99b7542356d105b3882e75c469e9a6004","message":""} +{"ts":"2026-06-13T20:59:25.968Z","author":"claude-code-agent","op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-13T20:59:25.968Z"},{"op":"replace","path":"/metadata/status","value":"in_progress"}],"before_hash":"2b6c9c99ec8f0110dc81ad5037dee4a99b7542356d105b3882e75c469e9a6004","after_hash":"1a453cedf9a3dd812569db76d991526cedb13ed009c808732cbb8ee5da5cdad8"} +{"ts":"2026-06-13T20:59:26.770Z","author":"claude-code-agent","op":"comment_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-13T20:59:26.770Z"},{"op":"add","path":"/metadata/comments","value":[{"created_at":"2026-06-13T20:59:26.770Z","author":"claude-code-agent","text":"Plan: in runClose, extend effectiveCloseReasonText fallback chain under require_close_reason — precedence: explicit positional/--reason > --duplicate-of ('Duplicate of X') > --resolution text. Resolution still also writes metadata.resolution. Fixes hard-block when agent supplies only --resolution."}]}],"before_hash":"1a453cedf9a3dd812569db76d991526cedb13ed009c808732cbb8ee5da5cdad8","after_hash":"ffb4e5bb7a1e51fe691ce18f93d81d674c212088a7cb0cae43052e2502e41492"} +{"ts":"2026-06-13T21:20:49.383Z","author":"claude-code-agent","op":"close","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-13T21:20:49.383Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/resolution","value":"pm close now derives the close reason from the next-best signal when require_close_reason is on and no positional/--reason text is given. Precedence: explicit reason > --duplicate-of ('Duplicate of ') > --resolution summary. Resolution still persists to metadata.resolution. Unit tests cover all three precedence branches + the still-blocks case."},{"op":"add","path":"/metadata/close_reason","value":"pm close now derives the close reason from the next-best signal when require_close_reason is on and no positional/--reason text is given. Precedence: explicit reason > --duplicate-of ('Duplicate of ') > --resolution summary. Resolution still persists to metadata.resolution. Unit tests cover all three precedence branches + the still-blocks case."}],"before_hash":"ffb4e5bb7a1e51fe691ce18f93d81d674c212088a7cb0cae43052e2502e41492","after_hash":"7435808c60090d1f056a02c24b01bdb66a9751f15344b96eda476c51a64114ea","message":"Ship pm-7x8d resolution-as-close-reason"} diff --git a/.agents/pm/history/pm-i1mu.jsonl b/.agents/pm/history/pm-i1mu.jsonl new file mode 100644 index 000000000..e58eb7c8a --- /dev/null +++ b/.agents/pm/history/pm-i1mu.jsonl @@ -0,0 +1,4 @@ +{"ts":"2026-06-13T20:54:33.503Z","author":"claude-code-agent","op":"create","patch":[{"op":"replace","path":"/body","value":"Agents typing many commands naturally try -m (message), -r (reason), -d (duplicate-of) on pm close; all currently error. Add Commander short aliases consistent with -h/--help. No semantic change."},{"op":"add","path":"/metadata/id","value":"pm-i1mu"},{"op":"add","path":"/metadata/title","value":"pm close: short aliases -m/-r/-d for --message/--reason/--duplicate-of (GH-226)"},{"op":"add","path":"/metadata/description","value":""},{"op":"add","path":"/metadata/type","value":"Feature"},{"op":"add","path":"/metadata/status","value":"open"},{"op":"add","path":"/metadata/priority","value":3},{"op":"add","path":"/metadata/tags","value":["area:cli","ergonomics","gh-226"]},{"op":"add","path":"/metadata/created_at","value":"2026-06-13T20:54:33.503Z"},{"op":"add","path":"/metadata/updated_at","value":"2026-06-13T20:54:33.503Z"},{"op":"add","path":"/metadata/author","value":"claude-code-agent"},{"op":"add","path":"/metadata/parent","value":"pm-mpbb"}],"before_hash":"3cc22dff72be7b14824654a7a64ea62b04799939b2fee54c1b5f52ca60bf6df0","after_hash":"0daf14e05c7e9d2f5b701d88f1048ea726f0f523e1720e2237564d1d923fe71b","message":""} +{"ts":"2026-06-13T20:59:25.694Z","author":"claude-code-agent","op":"update","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-13T20:59:25.694Z"},{"op":"replace","path":"/metadata/status","value":"in_progress"}],"before_hash":"0daf14e05c7e9d2f5b701d88f1048ea726f0f523e1720e2237564d1d923fe71b","after_hash":"e9fb44a56431960e68eeb9b1009da58494fbaf4485786b163be5d9f5d95213d8"} +{"ts":"2026-06-13T20:59:26.514Z","author":"claude-code-agent","op":"comment_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-13T20:59:26.514Z"},{"op":"add","path":"/metadata/comments","value":[{"created_at":"2026-06-13T20:59:26.514Z","author":"claude-code-agent","text":"Plan: add Commander short aliases on close command — -m/--message, -r/--reason, -d/--duplicate-of. No semantic change; -m/-r/-d are unused on close. Verified -d free (close has no --description). Add tests asserting parse."}]}],"before_hash":"e9fb44a56431960e68eeb9b1009da58494fbaf4485786b163be5d9f5d95213d8","after_hash":"4afc6909b91776bb5a943c96af6e3a2272acb99c640a8de9cc54ea391e727f48"} +{"ts":"2026-06-13T21:20:48.933Z","author":"claude-code-agent","op":"close","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-13T21:20:48.933Z"},{"op":"replace","path":"/metadata/status","value":"closed"},{"op":"add","path":"/metadata/resolution","value":"Added Commander short aliases on pm close: -m (--message), -r (--reason), -d (--duplicate-of). No semantic change; verified no conflicts. In-process integration test asserts all three parse and apply."},{"op":"add","path":"/metadata/close_reason","value":"Added Commander short aliases on pm close: -m (--message), -r (--reason), -d (--duplicate-of). No semantic change; verified no conflicts. In-process integration test asserts all three parse and apply."}],"before_hash":"4afc6909b91776bb5a943c96af6e3a2272acb99c640a8de9cc54ea391e727f48","after_hash":"d1c6b951e2d7eafcc2cdcfeefbc1d87c970de7e9b706cc71e5a8980370a0a818","message":"Ship GH-226 close short aliases"} diff --git a/.agents/pm/history/pm-kanu.jsonl b/.agents/pm/history/pm-kanu.jsonl new file mode 100644 index 000000000..b180ebb8c --- /dev/null +++ b/.agents/pm/history/pm-kanu.jsonl @@ -0,0 +1,2 @@ +{"ts":"2026-06-13T20:54:33.757Z","author":"claude-code-agent","op":"create","patch":[{"op":"replace","path":"/body","value":"During a 3d-bots audit, pm update --allow-audit-update --comment/--file/--doc was rejected as restricted, forcing separate pm comments/files/docs calls. These are append-only non-lifecycle additions that match the audit-update intent. Permit them under --allow-audit-update (keep lifecycle/destructive flags restricted)."},{"op":"add","path":"/metadata/id","value":"pm-kanu"},{"op":"add","path":"/metadata/title","value":"pm update --allow-audit-update: permit append-only --comment/--file/--doc evidence (GH-207)"},{"op":"add","path":"/metadata/description","value":""},{"op":"add","path":"/metadata/type","value":"Task"},{"op":"add","path":"/metadata/status","value":"open"},{"op":"add","path":"/metadata/priority","value":2},{"op":"add","path":"/metadata/tags","value":["area:cli","audit","ergonomics","gh-207"]},{"op":"add","path":"/metadata/created_at","value":"2026-06-13T20:54:33.757Z"},{"op":"add","path":"/metadata/updated_at","value":"2026-06-13T20:54:33.757Z"},{"op":"add","path":"/metadata/author","value":"claude-code-agent"},{"op":"add","path":"/metadata/parent","value":"pm-mpbb"}],"before_hash":"3cc22dff72be7b14824654a7a64ea62b04799939b2fee54c1b5f52ca60bf6df0","after_hash":"009a49bfb57fdc133eb5ecffa9337ed3d8493e0655082097559bed3f371d633d","message":""} +{"ts":"2026-06-13T20:59:27.028Z","author":"claude-code-agent","op":"comment_add","patch":[{"op":"replace","path":"/metadata/updated_at","value":"2026-06-13T20:59:27.028Z"},{"op":"add","path":"/metadata/comments","value":[{"created_at":"2026-06-13T20:59:27.028Z","author":"claude-code-agent","text":"DEFERRED (design tension): GH-207 was already deliberately addressed (code comment 'GH-207' in update.ts) — append-style --comment/--file/--doc are intentionally routed through dedicated commands (pm comments --allow-audit-comment, pm files --force) with exact retry guidance in the audit-scope error. Reversing that to permit inline non-owner appends under --allow-audit-update changes a documented decision and the audit-scope security story. Keeping restricted; the retry guidance already gives a one-paste path. Revisit only with explicit maintainer sign-off."}]}],"before_hash":"009a49bfb57fdc133eb5ecffa9337ed3d8493e0655082097559bed3f371d633d","after_hash":"6bc15ca1ab27fddb0b6812e977cfba32caf1fed9d709c0913e334f2b576a8b74"} diff --git a/.agents/pm/tasks/pm-7x8d.toon b/.agents/pm/tasks/pm-7x8d.toon index 3f6a5f514..8256ed67d 100644 --- a/.agents/pm/tasks/pm-7x8d.toon +++ b/.agents/pm/tasks/pm-7x8d.toon @@ -2,10 +2,14 @@ id: pm-7x8d title: "pm close: when require_close_reason is on, accept --resolution text as the close reason instead of hard-blocking" description: "Repro: with governance.require_close_reason enabled (sandbox default), 'pm close --resolution \"Fixed empty-password guard\" --expected ... --actual ...' fails with 'Close reason text is required'. The agent already supplied a complete closure narrative; per the never-block philosophy the resolution text is a perfectly good one-line closing summary. Suggestion: when --reason/positional text is absent but --resolution is provided, derive the close reason from the resolution (and note the derivation in output), keeping the hard error only when neither is present. The current error message is actionable (examples included) so this is polish, not a dead-end." type: Task -status: open +status: closed priority: 3 tags[4]: agent-ux,cli,dogfood-2026-06-12,never-block created_at: "2026-06-12T16:19:39.149Z" -updated_at: "2026-06-12T16:19:39.149Z" +updated_at: "2026-06-13T21:20:49.383Z" author: maintainer-agent +resolution: "pm close now derives the close reason from the next-best signal when require_close_reason is on and no positional/--reason text is given. Precedence: explicit reason > --duplicate-of ('Duplicate of ') > --resolution summary. Resolution still persists to metadata.resolution. Unit tests cover all three precedence branches + the still-blocks case." +comments[1]{created_at,author,text}: + "2026-06-13T20:59:26.770Z",claude-code-agent,"Plan: in runClose, extend effectiveCloseReasonText fallback chain under require_close_reason — precedence: explicit positional/--reason > --duplicate-of ('Duplicate of X') > --resolution text. Resolution still also writes metadata.resolution. Fixes hard-block when agent supplies only --resolution." +close_reason: "pm close now derives the close reason from the next-best signal when require_close_reason is on and no positional/--reason text is given. Precedence: explicit reason > --duplicate-of ('Duplicate of ') > --resolution summary. Resolution still persists to metadata.resolution. Unit tests cover all three precedence branches + the still-blocks case." body: "" diff --git a/.agents/pm/tasks/pm-kanu.toon b/.agents/pm/tasks/pm-kanu.toon new file mode 100644 index 000000000..5cf7a1553 --- /dev/null +++ b/.agents/pm/tasks/pm-kanu.toon @@ -0,0 +1,14 @@ +id: pm-kanu +title: "pm update --allow-audit-update: permit append-only --comment/--file/--doc evidence (GH-207)" +description: "" +type: Task +status: open +priority: 2 +tags[4]: "area:cli",audit,ergonomics,gh-207 +created_at: "2026-06-13T20:54:33.757Z" +updated_at: "2026-06-13T20:59:27.028Z" +author: claude-code-agent +parent: pm-mpbb +comments[1]{created_at,author,text}: + "2026-06-13T20:59:27.028Z",claude-code-agent,"DEFERRED (design tension): GH-207 was already deliberately addressed (code comment 'GH-207' in update.ts) — append-style --comment/--file/--doc are intentionally routed through dedicated commands (pm comments --allow-audit-comment, pm files --force) with exact retry guidance in the audit-scope error. Reversing that to permit inline non-owner appends under --allow-audit-update changes a documented decision and the audit-scope security story. Keeping restricted; the retry guidance already gives a one-paste path. Revisit only with explicit maintainer sign-off." +body: "During a 3d-bots audit, pm update --allow-audit-update --comment/--file/--doc was rejected as restricted, forcing separate pm comments/files/docs calls. These are append-only non-lifecycle additions that match the audit-update intent. Permit them under --allow-audit-update (keep lifecycle/destructive flags restricted)." diff --git a/CHANGELOG.md b/CHANGELOG.md index 5662d5412..145135c40 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## Unreleased + +### Added + +- pm close: short aliases -m/-r/-d for --message/--reason/--duplicate-of \(GH-226\) ([pm-i1mu](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/features/pm-i1mu.toon)) +- pm create/update --body-file: load body markdown from a file \(GH-214\) ([pm-7c48](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/features/pm-7c48.toon)) + +### Other + +- pm close: when require\_close\_reason is on, accept --resolution text as the close reason instead of hard-blocking ([pm-7x8d](https://github.com/unbraind/pm-cli/blob/main/.agents/pm/tasks/pm-7x8d.toon)) + ## 2026.6.13 - 2026-06-13 ### Changed diff --git a/docs/AGENT_GUIDE.md b/docs/AGENT_GUIDE.md index 4b7500d4c..a6f33a66a 100644 --- a/docs/AGENT_GUIDE.md +++ b/docs/AGENT_GUIDE.md @@ -129,7 +129,10 @@ pm release | Local docs routing | `pm install guide-shell --project`, then `pm guide ` | | Compact mutation echo | `pm --no-changed-fields create "..."` (drops the redundant `changed_fields` array, keeps `changed_field_count`) | | Minimal mutation echo | `pm --id-only create "..."` (prints only id and status for single-item mutations) | -| Duplicate close | `pm close --duplicate-of ` | +| Duplicate close | `pm close --duplicate-of ` (or `-d `) | +| Long body from a file | `pm create "" --body-file ./spec.md` (also on `pm update`; mutually exclusive with `--body`) | +| Close with short flags | `pm close <id> -r "<reason>"` / `-m "<history msg>"` / `-d <canonical>` | +| Close via resolution only | `pm close <id> --resolution "<summary>"` (used as the close reason when one is required) | Default TOON output is preferred for model-readable loops. Use `--json` only when strict parsing is needed. diff --git a/docs/COMMANDS.md b/docs/COMMANDS.md index 7479e9585..c7060fee6 100644 --- a/docs/COMMANDS.md +++ b/docs/COMMANDS.md @@ -178,6 +178,15 @@ pm create \ --message "Create restore replay issue" ``` +For long markdown bodies (multi-paragraph specs with code blocks or tables), load the body from a file with `--body-file <path>` on both `pm create` and `pm update` instead of escaping a huge inline `--body` string or issuing a second `pm append`: + +```bash +pm create Feature "Search relevance overhaul" --body-file ./specs/search-relevance.md +pm update pm-a1b2 --body-file ./specs/updated-spec.md +``` + +`--body-file` is mutually exclusive with `--body` (passing both errors). Use `--body -` to read the body from piped stdin. + Repeated singular/plural list flags now accumulate, so `--tag a --tag b` is equivalent to `--tags a,b` (the same holds for `--status`, `--ids`, and `--fields` on read commands). Earlier versions silently kept only the last value. `list`/`search` also accept `--tags` as a never-block alias for the canonical read filter `--tag`. `--tags` REPLACES the whole tag list. To edit tags without restating the full set, use the additive/subtractive flags on `create`/`update`/`update-many`: @@ -217,6 +226,8 @@ Use `pm create --allow-missing-parent --parent <id>` only for deliberate imports Use `pm close <duplicate-id> --duplicate-of <canonical-id>` to close duplicates. The command validates the canonical target exists, records `duplicate_of`, auto-fills the close reason as `Duplicate of <canonical-id>` when no reason text was supplied, and fills the resolution/expected/actual closure fields when they were not provided explicitly. +`pm close` accepts short aliases for the common flags: `-m` (`--message`), `-r` (`--reason`), and `-d` (`--duplicate-of`). When `governance.require_close_reason` is enabled and no positional/`--reason` text is given, the close reason is derived from the next-best signal in priority order — explicit reason text, then `--duplicate-of` (`Duplicate of <id>`), then `--resolution` — so a single `pm close <id> --resolution "<summary>"` no longer hard-blocks. The resolution is still written to the item's `resolution` field. + Over MCP the mutation tools (`pm_create`/`pm_update`/`pm_close`/`pm_run` append/update-many) are compact by default; pass `fullChangedFields=true` to restore the full `changed_fields` delta, or `idOnly=true` for single-item id/status output. ## Templates diff --git a/src/cli/commands/close.ts b/src/cli/commands/close.ts index 152e3c3fd..1e3804f81 100644 --- a/src/cli/commands/close.ts +++ b/src/cli/commands/close.ts @@ -227,10 +227,21 @@ export async function runClose( // "Duplicate of <id>" (mirroring the auto-filled closure metadata). // Explicit reason text still wins. const duplicateOf = await assertDuplicateTargetExists(pmRoot, settings, options.duplicateOf, id); - const effectiveCloseReasonText = - (closeReasonText ?? "").trim().length === 0 && duplicateOf !== undefined + // pm-7x8d / GH-204: when no explicit positional/--reason text is given, derive + // the close reason from the next-best closure signal instead of hard-blocking + // under governance.require_close_reason. Precedence: explicit reason text > + // --duplicate-of ("Duplicate of <id>") > --resolution summary. The resolution + // is still written to metadata.resolution below; reusing it as the close + // reason just lets a single `pm close <id> --resolution "..."` succeed. + const hasExplicitReason = (closeReasonText ?? "").trim().length > 0; + const trimmedResolution = typeof options.resolution === "string" ? options.resolution.trim() : ""; + const effectiveCloseReasonText = hasExplicitReason + ? closeReasonText + : duplicateOf !== undefined ? `Duplicate of ${duplicateOf}` - : closeReasonText; + : trimmedResolution.length > 0 + ? trimmedResolution + : closeReasonText; const closeReason = normalizeCloseReason(effectiveCloseReasonText, settings.governance.require_close_reason); const validateCloseMode = parseValidateCloseMode(options.validateClose) ?? settings.governance.close_validation_default; // C3 (pm-fu5d): scan for active children even under minimal governance so diff --git a/src/cli/commands/completion.ts b/src/cli/commands/completion.ts index 4c7c44018..ea21d747a 100644 --- a/src/cli/commands/completion.ts +++ b/src/cli/commands/completion.ts @@ -680,6 +680,7 @@ ${zshListRuntimeFieldFlags} '--json[Output JSON]' \\ '--tags[Comma-separated tags]:tags' \\ '--add-tags[Add tags additively without replacing existing]:tags' \\ '(-b --body)'{-b,--body}'[Item body]:body' \\ + '--body-file[Load the item body from a file]:body_file:_files' \\ '--deadline[Deadline (ISO/date string or relative +6h/+1d/+2w/+6m)]:deadline' \\ '--estimate[Estimated minutes]:minutes' \\ '--acceptance-criteria[Acceptance criteria]:criteria' \\ @@ -719,6 +720,7 @@ ${zshCreateRuntimeFieldFlags} '--json[Output JSON]' \\ '(-t --title)'{-t,--title}'[Item title]:title' \\ '(-d --description)'{-d,--description}'[Item description]:description' \\ '(-b --body)'{-b,--body}'[Item body]:body' \\ + '--body-file[Load the item body from a file]:body_file:_files' \\ '(-s --status)'{-s,--status}'[Item status]:(${statusChoices})' \\ '--close-reason[Set close reason]:close_reason' \\ '(-p --priority)'{-p,--priority}'[Priority (0-4)]:(0 1 2 3 4)' \\ @@ -1637,6 +1639,7 @@ complete -c pm -n '__fish_seen_subcommand_from create' -s p -l priority complete -c pm -n '__fish_seen_subcommand_from create' -l tags -d 'Comma-separated tags' -r complete -c pm -n '__fish_seen_subcommand_from create' -l add-tags -d 'Add tags additively without replacing existing' -r complete -c pm -n '__fish_seen_subcommand_from create' -s b -l body -d 'Item body' -r +complete -c pm -n '__fish_seen_subcommand_from create' -l body-file -d 'Load the item body from a file' -r -F complete -c pm -n '__fish_seen_subcommand_from create' -l deadline -d 'Deadline (ISO/date string or relative +6h/+1d/+2w/+6m)' -r complete -c pm -n '__fish_seen_subcommand_from create' -l estimate -d 'Estimated minutes' -r complete -c pm -n '__fish_seen_subcommand_from create' -l acceptance-criteria -d 'Acceptance criteria' -r @@ -1669,6 +1672,7 @@ complete -c pm -n '__fish_seen_subcommand_from copy' -l force -d 'Force owners complete -c pm -n '__fish_seen_subcommand_from update' -s t -l title -d 'Item title' -r complete -c pm -n '__fish_seen_subcommand_from update' -s d -l description -d 'Item description' -r complete -c pm -n '__fish_seen_subcommand_from update' -s b -l body -d 'Item body' -r +complete -c pm -n '__fish_seen_subcommand_from update' -l body-file -d 'Load the item body from a file' -r -F complete -c pm -n '__fish_seen_subcommand_from update' -s s -l status -d 'Item status' -r -a '${statusChoices}' complete -c pm -n '__fish_seen_subcommand_from update' -l close-reason -d 'Set close reason' -r complete -c pm -n '__fish_seen_subcommand_from update' -s p -l priority -d 'Priority (0-4)' -r -a '0 1 2 3 4' diff --git a/src/cli/register-mutation.ts b/src/cli/register-mutation.ts index 148a0ee5c..dbb760886 100644 --- a/src/cli/register-mutation.ts +++ b/src/cli/register-mutation.ts @@ -1,4 +1,5 @@ import { Option, type Command } from "commander"; +import { resolveBodyFileContent } from "../core/io/body-file.js"; import { EXIT_CODE } from "../core/shared/constants.js"; import { PmCliError } from "../core/shared/errors.js"; import { isPureSnakeCaseAlias } from "../core/shared/option-alias-visibility.js"; @@ -105,6 +106,7 @@ export function registerMutationCommands(program: Command): void { .description("Create a new project management item."); registerCommanderOptionContracts(createCommand, CREATE_COMMANDER_OPTION_REGISTRATION_CONTRACTS); createCommand + .option("--body-file <path>", "Load the item markdown body from a file (mutually exclusive with --body)") .option("--clear-deps", "Clear dependency entries") .option("--clear-comments", "Clear comments") .option("--clear-notes", "Clear notes") @@ -171,6 +173,15 @@ export function registerMutationCommands(program: Command): void { if (typeof positionalTitle === "string" && positionalTitle.length > 0 && options.title === undefined) { options.title = positionalTitle; } + // GH-214: resolve --body-file into the existing body field before + // normalization so the rest of create is unchanged. CLI-only input alias. + if (typeof options.bodyFile === "string") { + options.body = await resolveBodyFileContent( + options.bodyFile, + typeof options.body === "string" ? options.body : undefined, + ); + delete options.bodyFile; + } const normalized = normalizeCreateOptions(options, { requireType: false }); const { runCreate } = await import("./commands/create.js"); const result = await runCreate(normalized, globalOptions); @@ -214,6 +225,7 @@ export function registerMutationCommands(program: Command): void { .description("Update item fields and metadata."); registerCommanderOptionContracts(updateCommand, UPDATE_COMMANDER_OPTION_REGISTRATION_CONTRACTS); updateCommand + .option("--body-file <path>", "Load the item markdown body from a file (mutually exclusive with --body)") .option("--replace-deps", "Atomically replace dependency entries with the provided --dep values") .option("--replace-tests", "Atomically replace linked test entries with the provided --test values") .option("--clear-deps", "Clear dependency entries") @@ -235,6 +247,15 @@ export function registerMutationCommands(program: Command): void { .action(async (id: string, options: Record<string, unknown>, command) => { const globalOptions = getGlobalOptions(command); const startedAt = Date.now(); + // GH-214: resolve --body-file into the existing body field before + // normalization so the rest of update is unchanged. CLI-only input alias. + if (typeof options.bodyFile === "string") { + options.body = await resolveBodyFileContent( + options.bodyFile, + typeof options.body === "string" ? options.body : undefined, + ); + delete options.bodyFile; + } const { runUpdate } = await import("./commands/update.js"); const result = await runUpdate(id, normalizeUpdateOptions(options), globalOptions); await invalidateSearchCachesForMutation(globalOptions, result); @@ -424,11 +445,11 @@ export function registerMutationCommands(program: Command): void { .command("close") .argument("<id>", "Item id") .argument("[text]", "Close reason text (alias: --reason)") - .option("--reason <value>", "Close reason text (alias for positional <text>)") + .option("-r, --reason <value>", "Close reason text (alias for positional <text>)") .option("--close-reason <value>", "Close reason text (alias for positional <text>)") - .option("--duplicate-of <id>", "Close as a duplicate of the canonical item id and auto-fill duplicate closure metadata") + .option("-d, --duplicate-of <id>", "Close as a duplicate of the canonical item id and auto-fill duplicate closure metadata") .option("--author <value>", "Mutation author") - .option("--message <value>", "History message") + .option("-m, --message <value>", "History message") .option("--validate-close [mode]", 'Validate closure metadata before close: "off", "warn", or "strict" (default: settings governance preset)') .option("--resolution <value>", "Set the closure resolution summary inline (same field --validate-close strict checks; previously required a prior pm update)") .option("--expected-result <value>", "Set the expected-result note inline (closure validation field)") diff --git a/src/core/io/body-file.ts b/src/core/io/body-file.ts new file mode 100644 index 000000000..199a177e8 --- /dev/null +++ b/src/core/io/body-file.ts @@ -0,0 +1,63 @@ +import { readFile } from "node:fs/promises"; + +import { EXIT_CODE } from "../shared/constants.js"; +import { PmCliError } from "../shared/errors.js"; + +/** + * GH-214: shared resolver for the `--body-file <path>` input convenience on + * `pm create` and `pm update`. It loads a long markdown body from a file so + * agents do not have to escape multi-paragraph content (code blocks, tables) + * into a single inline `--body` string or issue a second `pm append` call. + * + * This is a CLI-only input alias that maps onto the existing `body` field, so + * it deliberately does NOT flow through the MCP/contract field surface (a file + * path is meaningless over MCP, mirroring `pm history --diff`). The file read is + * injectable so the pure resolution logic stays fully unit-coverable without + * touching disk. + */ +export type BodyFileReader = (path: string) => Promise<string>; + +const defaultBodyFileReader: BodyFileReader = (path) => readFile(path, "utf8"); + +export async function resolveBodyFileContent( + bodyFile: string, + inlineBody: string | undefined, + readFileImpl: BodyFileReader = defaultBodyFileReader, +): Promise<string> { + // Mutual exclusion: --body and --body-file both define the body, so accepting + // both silently would hide which one wins. Fail with an actionable message. + if (inlineBody !== undefined) { + throw new PmCliError( + "--body and --body-file are mutually exclusive; provide the body inline with --body or from a file with --body-file, not both.", + EXIT_CODE.USAGE, + { + code: "body_file_conflicts_with_body", + required: "Choose exactly one body source.", + why: "Both --body and --body-file set the item body; allowing both would make the effective body ambiguous.", + nextSteps: ["Re-run with only --body <text> or only --body-file <path>."], + }, + ); + } + const path = bodyFile.trim(); + if (path.length === 0) { + throw new PmCliError("--body-file requires a file path.", EXIT_CODE.USAGE, { + code: "body_file_missing_path", + required: "Pass a readable file path: --body-file <path>.", + why: "An empty --body-file value has no file to read the body from.", + }); + } + try { + return await readFileImpl(path); + } catch { + throw new PmCliError( + `--body-file could not read "${path}". Check that the file exists and is readable.`, + EXIT_CODE.NOT_FOUND, + { + code: "body_file_unreadable", + required: "Point --body-file at an existing, readable file.", + why: "The body content is loaded from the file at the supplied path, so an unreadable path cannot produce a body.", + nextSteps: [`Verify the path: ls -l "${path}"`, "Or pass the body inline with --body <text>."], + }, + ); + } +} diff --git a/src/sdk/cli-contracts.ts b/src/sdk/cli-contracts.ts index 4744daf9b..63ad47eb2 100644 --- a/src/sdk/cli-contracts.ts +++ b/src/sdk/cli-contracts.ts @@ -810,6 +810,7 @@ export const CREATE_FLAG_CONTRACTS: CliFlagContract[] = [ // corrupting the JSON-array value form before parseTags sees it. { flag: "--add-tags", aliases: ["--add_tags"] }, { short: "-b", flag: "--body" }, + { flag: "--body-file" }, { flag: "--deadline" }, { flag: "--estimate" }, { flag: "--estimated-minutes" }, @@ -899,6 +900,7 @@ export const UPDATE_FLAG_CONTRACTS: CliFlagContract[] = [ { short: "-t", flag: "--title" }, { short: "-d", flag: "--description" }, { short: "-b", flag: "--body" }, + { flag: "--body-file" }, { short: "-s", flag: "--status" }, { flag: "--close-reason" }, { flag: "--close_reason" }, diff --git a/tests/fixtures/contracts/full.json b/tests/fixtures/contracts/full.json index 4b837e2dd..876b3e4e0 100644 --- a/tests/fixtures/contracts/full.json +++ b/tests/fixtures/contracts/full.json @@ -1708,6 +1708,9 @@ "flag": "--body", "short": "-b" }, + { + "flag": "--body-file" + }, { "flag": "--deadline" }, @@ -4734,6 +4737,9 @@ "flag": "--body", "short": "-b" }, + { + "flag": "--body-file" + }, { "flag": "--status", "short": "-s" diff --git a/tests/integration/cli-inprocess-runner.integration.spec.ts b/tests/integration/cli-inprocess-runner.integration.spec.ts index 8d72b8d55..103ef9cd0 100644 --- a/tests/integration/cli-inprocess-runner.integration.spec.ts +++ b/tests/integration/cli-inprocess-runner.integration.spec.ts @@ -1,8 +1,111 @@ -import { mkdir } from "node:fs/promises"; +import { mkdir, writeFile } from "node:fs/promises"; import path from "node:path"; import { describe, expect, it } from "vitest"; import { withTempPmPath } from "../helpers/withTempPmPath.js"; +describe("create/update --body-file (GH-214)", () => { + it("loads the item body from a file on create and update", async () => { + await withTempPmPath(async (context) => { + const bodyPath = path.join(context.tempRoot, "spec.md"); + // Trailing newlines are normalized away on store, so keep the fixture + // body free of a trailing newline to assert exact round-trip equality. + const bodyContent = "# Spec\n\n## Acceptance\n- one\n- two"; + await writeFile(bodyPath, bodyContent, "utf8"); + + const created = await context.runCliInProcess( + ["create", "--json", "--type", "Feature", "--title", "body-file feature", "--body-file", bodyPath], + { expectJson: true }, + ); + expect(created.code).toBe(0); + const createdId = (created.json as { item: { id: string; body?: string } }).item.id; + + const fetched = await context.runCliInProcess(["get", createdId, "--json"], { expectJson: true }); + expect((fetched.json as { body?: string }).body).toBe(bodyContent); + + const updatedPath = path.join(context.tempRoot, "updated.md"); + await writeFile(updatedPath, "updated from file", "utf8"); + const updated = await context.runCliInProcess( + ["update", createdId, "--json", "--body-file", updatedPath], + { expectJson: true }, + ); + expect(updated.code).toBe(0); + const refetched = await context.runCliInProcess(["get", createdId, "--json"], { expectJson: true }); + expect((refetched.json as { body?: string }).body).toBe("updated from file"); + }); + }); + + it("rejects combining --body and --body-file", async () => { + await withTempPmPath(async (context) => { + const bodyPath = path.join(context.tempRoot, "conflict.md"); + await writeFile(bodyPath, "file body", "utf8"); + const result = await context.runCliInProcess([ + "create", + "--type", + "Task", + "--title", + "conflict", + "--body", + "inline body", + "--body-file", + bodyPath, + ]); + expect(result.code).not.toBe(0); + expect(result.stderr).toContain("mutually exclusive"); + }); + }); + + it("errors with an actionable message when the file is missing", async () => { + await withTempPmPath(async (context) => { + const result = await context.runCliInProcess([ + "create", + "--type", + "Task", + "--title", + "missing body file", + "--body-file", + path.join(context.tempRoot, "nope.md"), + ]); + expect(result.code).not.toBe(0); + expect(result.stderr).toContain("could not read"); + }); + }); +}); + +describe("pm close short aliases (GH-226)", () => { + it("accepts -r/--reason, -m/--message, and -d/--duplicate-of", async () => { + await withTempPmPath(async (context) => { + const reasonItem = (context.runCli( + ["create", "--json", "--type", "Task", "--title", "close -r alias"], + { expectJson: true }, + ).json as { item: { id: string } }).item.id; + const closedByReason = await context.runCliInProcess( + ["close", reasonItem, "-r", "done via -r", "-m", "history note", "--json"], + { expectJson: true }, + ); + expect(closedByReason.code).toBe(0); + expect((closedByReason.json as { item: { status: string; close_reason: string } }).item).toMatchObject({ + status: "closed", + close_reason: "done via -r", + }); + + const canonicalId = (context.runCli( + ["create", "--json", "--type", "Task", "--title", "canonical"], + { expectJson: true }, + ).json as { item: { id: string } }).item.id; + const duplicateId = (context.runCli( + ["create", "--json", "--type", "Task", "--title", "duplicate"], + { expectJson: true }, + ).json as { item: { id: string } }).item.id; + const closedByDuplicate = await context.runCliInProcess( + ["close", duplicateId, "-d", canonicalId, "--json"], + { expectJson: true }, + ); + expect(closedByDuplicate.code).toBe(0); + expect((closedByDuplicate.json as { item: { duplicate_of: string } }).item.duplicate_of).toBe(canonicalId); + }); + }); +}); + describe("CLI in-process runner integration", () => { it("keeps subprocess and in-process runner behavior aligned for core flows", async () => { await withTempPmPath(async (context) => { diff --git a/tests/unit/close-command.spec.ts b/tests/unit/close-command.spec.ts index af0f64b09..d1c45439a 100644 --- a/tests/unit/close-command.spec.ts +++ b/tests/unit/close-command.spec.ts @@ -226,6 +226,62 @@ describe("runClose", () => { }); }); + it("derives the close reason from --resolution when no explicit reason is given (pm-7x8d)", async () => { + await withTempPmPath(async (context) => { + const id = createTask(context, "resolution-as-close-reason candidate"); + const result = await runClose( + id, + undefined, + { + resolution: " Fixed by patch xyz ", + message: "Close with resolution only", + }, + { path: context.pmPath }, + ); + expect(result.changed_fields).toEqual(expect.arrayContaining(["status", "close_reason", "resolution"])); + expect(result.item).toMatchObject({ + id, + status: "closed", + close_reason: "Fixed by patch xyz", + resolution: "Fixed by patch xyz", + }); + }); + }); + + it("prefers explicit reason text over --resolution and --duplicate-of for the close reason", async () => { + await withTempPmPath(async (context) => { + const canonicalId = createTask(context, "resolution-precedence canonical"); + const id = createTask(context, "resolution-precedence candidate"); + const result = await runClose( + id, + "Explicit closing summary", + { + duplicateOf: canonicalId, + resolution: "Resolution summary", + message: "Close with explicit reason", + }, + { path: context.pmPath }, + ); + expect(result.item).toMatchObject({ + id, + status: "closed", + close_reason: "Explicit closing summary", + duplicate_of: canonicalId, + resolution: "Resolution summary", + }); + }); + }); + + it("still requires a reason when neither --reason, --duplicate-of, nor --resolution is provided", async () => { + await withTempPmPath(async (context) => { + const id = createTask(context, "no-reason-source candidate"); + await expect(runClose(id, undefined, { message: "no reason" }, { path: context.pmPath })).rejects.toMatchObject<PmCliError>({ + exitCode: EXIT_CODE.USAGE, + context: expect.objectContaining({ code: "close_reason_required" }), + }); + }); + }); + it("does not report duplicate fallback fields when explicit close metadata already exists", async () => { await withTempPmPath(async (context) => { const canonicalId = createTask(context, "canonical duplicate existing metadata target"); diff --git a/tests/unit/completion-command.spec.ts b/tests/unit/completion-command.spec.ts index f801bff8b..f564374b8 100644 --- a/tests/unit/completion-command.spec.ts +++ b/tests/unit/completion-command.spec.ts @@ -108,11 +108,13 @@ describe("generateBashScript", () => { expect(script).toContain("--comment"); expect(script).toContain("--note"); expect(script).toContain("--learning"); + expect(script).toContain("--body-file"); }); it("includes update flags", () => { const script = generateBashScript(); expect(script).toContain("--body"); + expect(script).toContain("--body-file"); expect(script).toContain("--close-reason"); expect(script).toContain("--force"); expect(script).toContain("--message"); diff --git a/tests/unit/core/io/body-file.spec.ts b/tests/unit/core/io/body-file.spec.ts new file mode 100644 index 000000000..3064528b1 --- /dev/null +++ b/tests/unit/core/io/body-file.spec.ts @@ -0,0 +1,86 @@ +import { mkdtemp, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import path from "node:path"; +import { afterAll, beforeAll, describe, expect, it } from "vitest"; +import { resolveBodyFileContent } from "../../../../src/core/io/body-file.js"; +import { PmCliError } from "../../../../src/core/shared/errors.js"; + +async function expectRejectionCode(promise: Promise<unknown>, code: string): Promise<void> { + await expect(promise).rejects.toBeInstanceOf(PmCliError); + await promise.catch((error: unknown) => { + expect(error).toBeInstanceOf(PmCliError); + expect((error as PmCliError).context.code).toBe(code); + }); +} + +describe("resolveBodyFileContent (GH-214 --body-file)", () => { + it("reads file content via an injected reader", async () => { + const seen: string[] = []; + const result = await resolveBodyFileContent("notes.md", undefined, async (p) => { + seen.push(p); + return "# Heading\n\nbody"; + }); + expect(result).toBe("# Heading\n\nbody"); + expect(seen).toEqual(["notes.md"]); + }); + + it("trims whitespace from the supplied path before reading", async () => { + const result = await resolveBodyFileContent(" spec.md ", undefined, async (p) => { + expect(p).toBe("spec.md"); + return "ok"; + }); + expect(result).toBe("ok"); + }); + + it("rejects when both --body and --body-file are provided", async () => { + await expectRejectionCode( + resolveBodyFileContent("spec.md", "inline body", async () => "unused"), + "body_file_conflicts_with_body", + ); + }); + + it("treats an empty inline body string as provided (mutual exclusion still fires)", async () => { + await expectRejectionCode( + resolveBodyFileContent("spec.md", "", async () => "unused"), + "body_file_conflicts_with_body", + ); + }); + + it("rejects an empty or whitespace-only path", async () => { + await expectRejectionCode( + resolveBodyFileContent(" ", undefined, async () => "unused"), + "body_file_missing_path", + ); + }); + + it("wraps read failures in an actionable PmCliError", async () => { + await expectRejectionCode( + resolveBodyFileContent("missing.md", undefined, async () => { + throw new Error("ENOENT"); + }), + "body_file_unreadable", + ); + }); + + describe("default filesystem reader", () => { + let dir: string; + + beforeAll(async () => { + dir = await mkdtemp(path.join(tmpdir(), "pm-body-file-")); + }); + + afterAll(async () => { + await rm(dir, { recursive: true, force: true }); + }); + + it("reads a real file from disk when no reader is injected", async () => { + const file = path.join(dir, "body.md"); + await writeFile(file, "from disk", "utf8"); + expect(await resolveBodyFileContent(file, undefined)).toBe("from disk"); + }); + + it("errors when the real file does not exist", async () => { + await expectRejectionCode(resolveBodyFileContent(path.join(dir, "nope.md"), undefined), "body_file_unreadable"); + }); + }); +}); From 3f92bcc2337f80950a3594eddd4081b66102f9df Mon Sep 17 00:00:00 2001 From: Stefan Preu <stefan@preu.at> Date: Sat, 13 Jun 2026 23:33:23 +0200 Subject: [PATCH 2/2] fix(cli): address PR review feedback (body-file robustness + error context) - register-mutation: use `options.body !== undefined ? String(options.body)` for the --body/--body-file mutual-exclusion check so a non-string body value can't silently bypass the conflict guard (Gemini). - body-file: preserve the underlying errno in the unreadable-file error and give a directory-specific message for EISDIR (a real footgun when pointing --body-file at a folder); keeps the typed PmCliError context shape (Sourcery). - body-file.spec: simplify expectRejectionCode to a single rejects assertion (no double-consume) and cover the new errno/EISDIR branches. CodeRabbit's "read item.body" suggestion is a false positive: `pm get --json` returns `body` at the top level (siblings: item/body/linked/claim_state), which the passing tests confirm. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --- src/cli/register-mutation.ts | 4 ++-- src/core/io/body-file.ts | 14 +++++++++--- tests/unit/core/io/body-file.spec.ts | 33 +++++++++++++++++++++++----- 3 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/cli/register-mutation.ts b/src/cli/register-mutation.ts index dbb760886..5b64c7326 100644 --- a/src/cli/register-mutation.ts +++ b/src/cli/register-mutation.ts @@ -178,7 +178,7 @@ export function registerMutationCommands(program: Command): void { if (typeof options.bodyFile === "string") { options.body = await resolveBodyFileContent( options.bodyFile, - typeof options.body === "string" ? options.body : undefined, + options.body !== undefined ? String(options.body) : undefined, ); delete options.bodyFile; } @@ -252,7 +252,7 @@ export function registerMutationCommands(program: Command): void { if (typeof options.bodyFile === "string") { options.body = await resolveBodyFileContent( options.bodyFile, - typeof options.body === "string" ? options.body : undefined, + options.body !== undefined ? String(options.body) : undefined, ); delete options.bodyFile; } diff --git a/src/core/io/body-file.ts b/src/core/io/body-file.ts index 199a177e8..1cd498d16 100644 --- a/src/core/io/body-file.ts +++ b/src/core/io/body-file.ts @@ -48,14 +48,22 @@ export async function resolveBodyFileContent( } try { return await readFileImpl(path); - } catch { + } catch (error: unknown) { + // Preserve the underlying errno (ENOENT/EACCES/EISDIR/...) so the failure + // is debuggable, and tailor the directory case (a real footgun: pointing + // --body-file at a folder) to an exact message instead of a generic one. + const errno = (error as NodeJS.ErrnoException | undefined)?.code; + const isDirectory = errno === "EISDIR"; + const detail = errno ? ` (${errno})` : ""; throw new PmCliError( - `--body-file could not read "${path}". Check that the file exists and is readable.`, + isDirectory + ? `--body-file "${path}" is a directory, not a file. Point it at a readable file.` + : `--body-file could not read "${path}"${detail}. Check that the file exists and is readable.`, EXIT_CODE.NOT_FOUND, { code: "body_file_unreadable", required: "Point --body-file at an existing, readable file.", - why: "The body content is loaded from the file at the supplied path, so an unreadable path cannot produce a body.", + why: `The body content is loaded from the file at the supplied path, so an unreadable path cannot produce a body${errno ? ` (underlying error: ${errno})` : ""}.`, nextSteps: [`Verify the path: ls -l "${path}"`, "Or pass the body inline with --body <text>."], }, ); diff --git a/tests/unit/core/io/body-file.spec.ts b/tests/unit/core/io/body-file.spec.ts index 3064528b1..80d242277 100644 --- a/tests/unit/core/io/body-file.spec.ts +++ b/tests/unit/core/io/body-file.spec.ts @@ -7,10 +7,7 @@ import { PmCliError } from "../../../../src/core/shared/errors.js"; async function expectRejectionCode(promise: Promise<unknown>, code: string): Promise<void> { await expect(promise).rejects.toBeInstanceOf(PmCliError); - await promise.catch((error: unknown) => { - expect(error).toBeInstanceOf(PmCliError); - expect((error as PmCliError).context.code).toBe(code); - }); + await expect(promise).rejects.toMatchObject({ context: expect.objectContaining({ code }) }); } describe("resolveBodyFileContent (GH-214 --body-file)", () => { @@ -53,15 +50,39 @@ describe("resolveBodyFileContent (GH-214 --body-file)", () => { ); }); - it("wraps read failures in an actionable PmCliError", async () => { + it("wraps read failures with no errno in an actionable PmCliError", async () => { await expectRejectionCode( resolveBodyFileContent("missing.md", undefined, async () => { - throw new Error("ENOENT"); + throw new Error("boom without code"); }), "body_file_unreadable", ); }); + it("surfaces the underlying errno code in the read-failure message", async () => { + const failure = Object.assign(new Error("denied"), { code: "EACCES" }); + await expect( + resolveBodyFileContent("locked.md", undefined, async () => { + throw failure; + }), + ).rejects.toMatchObject({ + message: expect.stringContaining("(EACCES)"), + context: expect.objectContaining({ code: "body_file_unreadable" }), + }); + }); + + it("gives a directory-specific message when the path is a directory (EISDIR)", async () => { + const failure = Object.assign(new Error("is dir"), { code: "EISDIR" }); + await expect( + resolveBodyFileContent("some-dir", undefined, async () => { + throw failure; + }), + ).rejects.toMatchObject({ + message: expect.stringContaining("is a directory"), + context: expect.objectContaining({ code: "body_file_unreadable" }), + }); + }); + describe("default filesystem reader", () => { let dir: string;