@kitschpatrol/chagent 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -49,7 +49,7 @@ type Evidence = {
49
49
  /** Git commits associated with pull-request evidence. */
50
50
  commits?: string[];
51
51
  id: string;
52
- kind: 'commit' | 'manifest' | 'pull-request' | 'range';
52
+ kind: 'commit' | 'draft' | 'manifest' | 'pull-request' | 'range';
53
53
  text: string;
54
54
  };
55
55
  /**
@@ -58,11 +58,20 @@ type Evidence = {
58
58
  */
59
59
  type ReleaseRequest = {
60
60
  evidence: Evidence[];
61
+ /**
62
+ * Entries the changelog already has for this release: text to preserve and
63
+ * not repeat, or in `revise` mode, a draft to rewrite.
64
+ */
61
65
  existingEntries: string;
62
66
  /** Unique and stable across runs; each change set echoes it. */
63
67
  id: string;
64
68
  initialRelease: boolean;
65
- mode: 'initialize' | 'update';
69
+ /**
70
+ * `initialize` writes a changelog from nothing and `update` adds to one. In
71
+ * `revise`, the existing entries are an earlier generated draft covering the
72
+ * release up to `repository.from`, and the changes returned replace it.
73
+ */
74
+ mode: 'initialize' | 'revise' | 'update';
66
75
  packageName: string;
67
76
  /**
68
77
  * Read-only research context in the local checkout; Git snapshots, not the
@@ -75,6 +84,11 @@ type ReleaseRequest = {
75
84
  to: string;
76
85
  };
77
86
  scope: 'package' | 'repository';
87
+ /**
88
+ * A recent release section of the changelog these entries will join, showing
89
+ * the writing conventions to match. It is not evidence.
90
+ */
91
+ styleReference?: string;
78
92
  version: string;
79
93
  };
80
94
  /** How to run a session, as opposed to what it should describe. */
@@ -142,6 +156,8 @@ type FileEdit = {
142
156
  type Checkpoint = {
143
157
  baseRef: string;
144
158
  contentHash: string;
159
+ /** Whether the draft is entirely generated, so a later run may revise it. */
160
+ generated: boolean;
145
161
  head: string;
146
162
  instructionVersion: string;
147
163
  path: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kitschpatrol/chagent",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "Changelog agent. CLI tool and TypeScript library to generate and update changelogs with a little help from your LLMs.",
5
5
  "keywords": [
6
6
  "changelog",
@@ -45,7 +45,7 @@
45
45
  "dist"
46
46
  ],
47
47
  "dependencies": {
48
- "@clack/prompts": "^1.8.1",
48
+ "@clack/prompts": "^1.9.0",
49
49
  "@types/node": "~24.13.6",
50
50
  "cosmiconfig": "^10.0.1",
51
51
  "cross-spawn": "^7.0.6",
@@ -67,7 +67,7 @@
67
67
  "mdat-plugin-cli-help": "^3.4.2",
68
68
  "publint": "^0.3.25",
69
69
  "shx": "^0.4.0",
70
- "tsdown": "^0.23.5",
70
+ "tsdown": "^0.23.7",
71
71
  "typescript": "~6.0.3",
72
72
  "vitest": "^5.1.0"
73
73
  },
package/readme.md CHANGED
@@ -25,7 +25,7 @@ Run `chagent` in a Git repository to either create a changelog where none previo
25
25
 
26
26
  Projects can use any language or build system. Version tags supply release boundaries; `package.json` is optional. Codex or Claude inspects historical commits and files directly to decide what belongs in each release.
27
27
 
28
- Between releases, it will add changes under the `Unreleased` heading. Historical release sections retain their original Markdown.
28
+ Between releases, it will add changes under the `Unreleased` heading. A draft that only chagent has written is revised as work continues, so a later fix folds into the entry it affects instead of adding another. A draft you wrote or edited keeps its text and is only added to. Historical release sections retain their original Markdown.
29
29
 
30
30
  Initialization reconstructs the complete reachable release history, including the initial release's capabilities and meaningful documentation, dependency, compatibility, build, test, and CI changes. Releases containing only maintenance still receive useful descriptions.
31
31
 
@@ -180,9 +180,9 @@ chagent --dry-run --no-github
180
180
 
181
181
  `generateChangelog` returns proposed edits, release summaries, diagnostics, and incremental checkpoints. `writeChangelog` verifies the original file contents and Git HEAD before applying edits. It rejects symlink destinations, rolls back a failed series of writes, and leaves the index unchanged.
182
182
 
183
- `previewChangelog(plan)` returns a unified diff. `reviewChangelog(plan, { editor })` provides terminal review and returns an edited plan, or `undefined` when cancelled. `amendRelease(plan)` is the explicit post-bump release integration described below. `setLogger(logger)` enables library logging; library calls are silent by default. Pass `onProgress` to `generateChangelog` to receive short status messages between agent sessions.
183
+ `previewChangelog(plan)` returns a unified diff. `reviewChangelog(plan, { editor })` provides terminal review and returns an edited plan, or `undefined` when cancelled. `amendRelease(plan)` is the explicit post-bump release integration described below. It reads repository configuration as generation does; pass it any `configFile`, `packages`, `exclude`, or `tagPatterns` options you gave `generateChangelog` directly. `setLogger(logger)` enables library logging; library calls are silent by default. Pass `onProgress` to `generateChangelog` to receive short status messages between agent sessions.
184
184
 
185
- Custom providers implement the exported `AgentAdapter` type and can be passed as `agent`. Their `generate(request)` method receives a `GenerationRequest` with one or more `releases` to research together, the local `repositoryRoot`, and run `settings`. Each release identifies its package, scope, mode, Git refs, and a bounded starting context, including a range citation for findings from direct research of the local Git checkout. The method resolves to `{ releases: [{ id, changes }] }`, with every requested release ID exactly once, one of the eight supported categories, and citations from that release's own `evidence`. Give an adapter a stable `cacheKey` to enable reusable draft caching, and change that key when its behavior changes. All adapter results receive the same output validation.
185
+ Custom providers implement the exported `AgentAdapter` type and can be passed as `agent`. Their `generate(request)` method receives a `GenerationRequest` with one or more `releases` to research together, the local `repositoryRoot`, and run `settings`. Each release identifies its package, scope, mode, Git refs, and a bounded starting context, including a range citation for findings from direct research of the local Git checkout. In `revise` mode, `existingEntries` is an earlier generated draft covering the release up to `repository.from`: the changes returned replace it, and entries carried over cite the `draft` evidence ID. The method resolves to `{ releases: [{ id, changes }] }`, with every requested release ID exactly once, one of the eight supported categories, and at least one citation for each change: an ID from that release's own `evidence`, or the ID of a commit within its range. Give an adapter a stable `cacheKey` to enable reusable draft caching, and change that key when its behavior changes. All adapter results receive the same output validation.
186
186
 
187
187
  #### API Examples
188
188
 
@@ -210,7 +210,7 @@ bumpp --all --execute "chagent -i"
210
210
  This runs the following sequence:
211
211
 
212
212
  1. Bumpp updates the package version.
213
- 2. Chagent moves all existing `Unreleased` notes into the new release section, preserves their text, and adds missing changes. Older release sections remain unchanged.
213
+ 2. Chagent moves all existing `Unreleased` notes into the new release section and adds missing changes. Notes you wrote or edited keep their text; a draft that only chagent has written may be revised to fold in what followed. Older release sections remain unchanged.
214
214
  3. The `-i` flag displays the diff and lets you edit, accept, or cancel. Saved edits are included when you accept.
215
215
  4. Bumpp commits the version and changelog changes together, tags the release, and pushes.
216
216
 
@@ -242,11 +242,11 @@ Avoid putting changelogs in bumpp's version-replacement `files` option: it can r
242
242
 
243
243
  With either approach, a generation error or cancelled review stops bumpp before its commit and tag. Bumpp's already updated version files remain available for correction or retry. The callback requires bumpp 12.3.0 or newer. It works with recursive releases, and with independently versioned packages released from their own directories.
244
244
 
245
- For an existing post-bump workflow, `chagent --amend` explicitly amends an unpublished version-only release commit and updates matching local tags. It checks current remote refs, preserves unrelated staged work and tag annotations, and refuses published releases, ambiguous commits, detached HEAD, and signed tags. Signed tags need manual re-signing; the pre-commit callback avoids that problem. Chagent itself never pushes or publishes.
245
+ For an existing post-bump workflow such as `npm version`, `chagent --amend` explicitly amends an unpublished version-only release commit and updates local tags that match your tag patterns. It checks current remote refs, preserves unrelated staged work and tag annotations, and refuses published releases, ambiguous commits, detached HEAD, and signed tags. Signed tags need manual re-signing; the pre-commit callback avoids that problem. Chagent itself never pushes or publishes.
246
246
 
247
247
  ### Monorepos
248
248
 
249
- Workspace declarations in `pnpm-workspace.yaml` or `package.json` determine the packages to process. Each current workspace package gets its own changelog. The root contains repository highlights and links to package releases.
249
+ Workspace declarations in `pnpm-workspace.yaml` or `package.json` determine the packages to process. Each current workspace package gets its own changelog. The root changelog summarizes the repository: each of its sections holds a few highlights written by the agent, followed by a `Packages` list linking to the package release sections it covers. Chagent maintains that list, so a draft's links to unreleased package changes are replaced by links to the releases once they exist. Package entries are not copied into the root.
250
250
 
251
251
  Use the `rootChangelog` option or `--root-changelog` flag to choose what the root changelog records. The default, `summary`, works as described above. `package` treats the root as a package of its own, for repositories whose main package lives at the root: its changelog describes the root's files and the workspace packages it depends on in full detail, without changes from other packages or links to their releases. `none` writes only the package changelogs. After changing the mode of an existing root changelog, run with `--rebuild` to reconstruct its history in the new form.
252
252
 
@@ -254,7 +254,7 @@ Use `skipPackage` directory globs, or repeat `--skip-package`, to leave workspac
254
254
 
255
255
  For other monorepo layouts, configure `packages` directory globs. These directories do not need npm manifests; their Git tags identify releases, using the directory basename as the package name.
256
256
 
257
- Shared-version repositories use repository versions at the root. Independently versioned repositories use package-qualified headings such as `@example/package@1.2.0`. Repository infrastructure changes appear in the root's `Unreleased` section. Explicit workspace dependencies contribute relevant source context to dependent packages. Dependency and tooling maintenance belongs under `Maintenance`. `build`, `coverage`, and `dist` directories at the top of a package count as generated output and are excluded, so a package named `packages/build` is still treated as source.
257
+ Shared-version repositories use repository versions at the root, where each release summarizes every package released with it. Independently versioned repositories use package-qualified headings such as `@example/package@1.2.0`, each summarizing one package release. Repository infrastructure changes appear in the root's `Unreleased` section. Explicit workspace dependencies contribute relevant source context to dependent packages. Dependency and tooling maintenance belongs under `Maintenance`. `build`, `coverage`, and `dist` directories at the top of a package usually hold generated output, so they are left out of the starting evidence and the agent decides whether their changes belong in the changelog. A package named `packages/build` is still treated as source.
258
258
 
259
259
  GitHub links to package changelogs on the default branch remain usable when a root entry is extracted for GitHub release notes.
260
260
 
@@ -281,23 +281,25 @@ Importing `defineConfig` requires chagent in the repository's own dependencies.
281
281
 
282
282
  Also supported: `chagent.config.mjs`, `chagent.config.js`, `chagent.config.json`, or a `chagent` key in `package.json`. CLI flags override configured values. `--config` selects a specific file.
283
283
 
284
- Use `packages` and `exclude` directory globs to customize workspace discovery, and `skipPackage` to leave discovered packages without changelogs. Use `tagPatterns` to select unusual release tag conventions. Templates support `{name}` and `{version}`; defaults recognize `v1.2.3`, `1.2.3`, `@scope/package@1.2.3`, and `@scope/package/v1.2.3`.
284
+ Use `packages` and `exclude` directory globs to customize workspace discovery, and `skipPackage` to leave discovered packages without changelogs. Use `tagPatterns` to select unusual release tag conventions. Templates support `{name}` and `{version}`; defaults recognize `v1.2.3`, `1.2.3`, `@scope/package@1.2.3`, and `@scope/package/v1.2.3`. Short versions such as `v1` and `v1.2` name the `1.0.0` and `1.2.0` releases when they precede every more precise tag in their series, so floating tags that track the latest release are ignored. Default patterns read one-part versions only after a `v`; configure `tagPatterns` to read bare numbers such as `1`.
285
285
 
286
286
  ## Background
287
287
 
288
288
  ### Implementation notes
289
289
 
290
- Chagent reads reachable version tags and commit history regardless of the project's language. Optional npm metadata supplies workspace discovery, local version-bump detection before tagging, and the conditional Node.js compatibility note. Repository tags remain authoritative even when a root `package.json` has an unrelated tooling version. Other projects use tagged releases, or an explicit `release` context through the library API. Without reliable released-version boundaries, new changes belong to `Unreleased`; version numbers are not invented. An existing release heading with no matching Git boundary requires its tags or a corrected tag pattern. Release headings can be level one or two, with optional links, dates, and a `v` prefix, including the Conventional Changelog format. Level three headings count as releases when they name a version, as standard-version writes patch releases. Chagent stops rather than risk duplicating history when a level one or two heading names a version in another form, or when an unclosed code fence would hide later headings. Broken `package.json` files in history are tolerated. Shallow clones must be completed before generation.
290
+ Release order follows Git ancestry, with SemVer breaking ties between tags on the same commit. Fork releases such as `1.2.0-fork.2` can therefore follow upstream `1.2.0`. Updates fill missing reachable releases even when their versions compare lower than an existing heading, while preserving the text of recorded sections.
291
291
 
292
- GitHub enrichment uses release dates and commit-associated PR information. PR lookups batch unique commits across all requested releases and packages; each release receives only its associated PRs. **GitHub release-note bodies are never generation inputs.** Changelog files and generated build output are excluded from source evidence. Existing changelog prose is supplied only to preserve edits and avoid duplicate entries.
292
+ Chagent reads reachable version tags and commit history regardless of the project's language. Optional npm metadata supplies workspace discovery, local version-bump detection before tagging, and the conditional Node.js compatibility note. Repository tags remain authoritative even when a root `package.json` has an unrelated tooling version. Other projects use tagged releases, or an explicit `release` context through the library API. Without reliable released-version boundaries, new changes belong to `Unreleased`; version numbers are not invented. An existing release heading with no matching Git boundary requires its tags or a corrected tag pattern. Release headings can be level one or two, with optional links, dates, and a `v` prefix, including the Conventional Changelog format. Headings can name short versions the way tags do, so `## 1.2` and `## v1` record the `1.2.0` and `1.0.0` releases. Level three headings count as releases when they name a version, as standard-version writes patch releases. Chagent stops rather than risk duplicating history when a level one or two heading names a version in another form, or when an unclosed code fence would hide later headings. Broken `package.json` files in history are tolerated. Shallow clones must be completed before generation.
293
+
294
+ GitHub enrichment uses release dates and commit-associated PR information. PR lookups batch unique commits across all requested releases and packages; each release receives only its associated PRs. **GitHub release-note bodies are never generation inputs.** Changelog files, lockfiles, and `node_modules` are never source evidence. Existing changelog prose is supplied only to preserve edits, avoid duplicate entries, and show the writing style to match: each request carries the changelog's newest release section as a style reference, so new entries follow its voice, punctuation, and reference conventions.
293
295
 
294
296
  The agent chooses which historical source files, public interfaces, documentation, and build configuration to inspect. It reads Git snapshots at the supplied release refs instead of treating current or uncommitted files as historical evidence. `maxInputChars` bounds the starting context supplied to agents; it does not restrict which repository files they can investigate. Requests prioritize release boundaries and existing human entries, then fit optional starting evidence into the remaining budget. An individual release's existing entries are never truncated. `timeout` sets the minutes each agent session may run. Dependency entries reflect declared version ranges; lockfile-only resolution changes and pure npm version-bump bookkeeping are excluded.
295
297
 
296
- Agents return structured changes with evidence references. Stray whitespace and list markers in descriptions are normalized. A response that still fails validation gets one correction request; a second failure stops the run before anything is written or cached. Application code owns the header, release boundaries, Markdown insertion, and Git writes. Agents run in the repository: Codex uses a read-only sandbox with approval requests disabled; Claude exposes read/search and Bash tools in [`dontAsk` mode](https://code.claude.com/docs/en/permissions), which allows read-only commands and denies actions requiring permission. Customizations are disabled for these invocations. Only chagent writes the reviewed changelog. Repository content is sent to the selected agent service using your existing account.
298
+ Agents return structured changes with evidence references. Citations are checked against Git: a change can cite supplied evidence or any commit within its release's range, abbreviated commit IDs are completed, and a change needs only one source that holds up. Stray whitespace and list markers in descriptions are normalized. A response that still fails validation gets one correction request; a second failure stops the run before anything is written or cached. Application code owns the header, release boundaries, Markdown insertion, and Git writes. Agents run in the repository: Codex uses a read-only sandbox with approval requests disabled; Claude exposes read/search and Bash tools in [`dontAsk` mode](https://code.claude.com/docs/en/permissions), which allows read-only commands and denies actions requiring permission. Customizations are disabled for these invocations. Only chagent writes the reviewed changelog. Repository content is sent to the selected agent service using your existing account.
297
299
 
298
300
  After writing, chagent passes each changed changelog to `fixFile` from the repository's own `@kitschpatrol/shared-config`, or from `@kitschpatrol/prettier-config` when that is all that imports. This formats the whole changelog, including older release sections, and no other files. `--dry-run` and `--interactive` diffs show the text before formatting. A formatting failure leaves the changelog as written and reports a diagnostic. Repositories without either package keep the changelog as written.
299
301
 
300
- Drafts and checkpoints are stored under the checkout's Git directory in `chagent/`. They are disposable and are not committed. Shared session results are validated together and cached separately for each release. Completed sessions can be reused after interruptions; an interrupted session must run again. `--no-cache` disables reuse and persistence. Dry runs can populate the draft cache but do not apply changelog edits.
302
+ Drafts and checkpoints are stored under the checkout's Git directory in `chagent/`. They are disposable and are not committed. A checkpoint records the commit a changelog covers and whether its `Unreleased` draft is entirely generated. While the changelog still reads as chagent left it, the next run researches only newer commits, and a generated draft is revised rather than appended to. Editing the changelog, in review or afterward, ends that: the draft is yours, and chagent only adds to it. Shared session results are validated together and cached separately for each release. Completed sessions can be reused after interruptions; an interrupted session must run again. `--no-cache` disables reuse and persistence. Dry runs can populate the draft cache but do not apply changelog edits.
301
303
 
302
304
  ## Maintainers
303
305