@kitschpatrol/chagent 0.3.0 → 0.5.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.
@@ -17,6 +17,12 @@ declare const configSchema: z.ZodObject<{
17
17
  maxInputChars: z.ZodOptional<z.ZodNumber>;
18
18
  model: z.ZodOptional<z.ZodString>;
19
19
  packages: z.ZodOptional<z.ZodArray<z.ZodString>>;
20
+ rootChangelog: z.ZodOptional<z.ZodEnum<{
21
+ summary: "summary";
22
+ package: "package";
23
+ none: "none";
24
+ }>>;
25
+ skipPackage: z.ZodOptional<z.ZodArray<z.ZodString>>;
20
26
  tagPatterns: z.ZodOptional<z.ZodArray<z.ZodString>>;
21
27
  timeout: z.ZodOptional<z.ZodNumber>;
22
28
  }, z.core.$strict>;
@@ -29,8 +35,10 @@ declare const categories: readonly ["Added", "Changed", "Deprecated", "Removed",
29
35
  type Category = (typeof categories)[number];
30
36
  declare const agentNames: readonly ["codex", "claude"];
31
37
  declare const efforts: readonly ["low", "medium", "high", "xhigh", "max"];
38
+ declare const rootChangelogs: readonly ["summary", "package", "none"];
32
39
  type AgentName = (typeof agentNames)[number];
33
40
  type Effort = (typeof efforts)[number];
41
+ type RootChangelog = (typeof rootChangelogs)[number];
34
42
  type Change = {
35
43
  breaking: boolean;
36
44
  category: Category;
@@ -41,7 +49,7 @@ type Evidence = {
41
49
  /** Git commits associated with pull-request evidence. */
42
50
  commits?: string[];
43
51
  id: string;
44
- kind: 'commit' | 'manifest' | 'pull-request' | 'range';
52
+ kind: 'commit' | 'draft' | 'manifest' | 'pull-request' | 'range';
45
53
  text: string;
46
54
  };
47
55
  /**
@@ -50,11 +58,20 @@ type Evidence = {
50
58
  */
51
59
  type ReleaseRequest = {
52
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
+ */
53
65
  existingEntries: string;
54
66
  /** Unique and stable across runs; each change set echoes it. */
55
67
  id: string;
56
68
  initialRelease: boolean;
57
- 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';
58
75
  packageName: string;
59
76
  /**
60
77
  * Read-only research context in the local checkout; Git snapshots, not the
@@ -67,6 +84,11 @@ type ReleaseRequest = {
67
84
  to: string;
68
85
  };
69
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;
70
92
  version: string;
71
93
  };
72
94
  /** How to run a session, as opposed to what it should describe. */
@@ -134,6 +156,8 @@ type FileEdit = {
134
156
  type Checkpoint = {
135
157
  baseRef: string;
136
158
  contentHash: string;
159
+ /** Whether the draft is entirely generated, so a later run may revise it. */
160
+ generated: boolean;
137
161
  head: string;
138
162
  instructionVersion: string;
139
163
  path: string;
@@ -159,4 +183,4 @@ type ChangelogPlan = {
159
183
  releases: ReleaseSummary[];
160
184
  root: string;
161
185
  };
162
- export { Config as _, ChangeSet as a, Evidence as c, GenerationRequest as d, GenerationResponse as f, RunSettings as g, ReleaseSummary as h, Change as i, FileEdit as l, ReleaseRequest as m, AgentName as n, ChangelogPlan as o, ReleaseContext as p, Category as r, Effort as s, AgentAdapter as t, GenerateOptions as u, defineConfig as v, loadConfig as y };
186
+ export { RunSettings as _, ChangeSet as a, loadConfig as b, Evidence as c, GenerationRequest as d, GenerationResponse as f, RootChangelog as g, ReleaseSummary as h, Change as i, FileEdit as l, ReleaseRequest as m, AgentName as n, ChangelogPlan as o, ReleaseContext as p, Category as r, Effort as s, AgentAdapter as t, GenerateOptions as u, Config as v, defineConfig as y };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kitschpatrol/chagent",
3
- "version": "0.3.0",
3
+ "version": "0.5.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",
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
 
@@ -132,24 +132,26 @@ Usage:
132
132
  chagent
133
133
  ```
134
134
 
135
- | Option | Description | Type | Default |
136
- | ----------------------- | --------------------------------------------------------------------- | --------------------------------------------- | --------------------------------------------- |
137
- | `--cwd` | Repository directory | `string` | current directory |
138
- | `--agent` | Installed agent CLI | `"codex"` `"claude"` | `codex` |
139
- | `--model` | Agent model | `string` | gpt-6.1-sol (Codex); claude-opus-5-5 (Claude) |
140
- | `--effort` | Reasoning effort | `"low"` `"medium"` `"high"` `"xhigh"` `"max"` | `xhigh` |
141
- | `--interactive`<br>`-i` | Review a diff and optionally edit before writing | `boolean` | `false` |
142
- | `--editor` | Editor command for interactive review; configure GUI editors to wait | `string` | git var GIT_EDITOR |
143
- | `--dry-run` | Print a diff without applying changes | `boolean` | `false` |
144
- | `--rebuild` | Reconstruct all history, replacing existing release text | `boolean` | `false` |
145
- | `--amend` | Amend a verified unpublished release commit and matching local tags | `boolean` | `false` |
146
- | `--github` | Enrich Git evidence using gh when available; disable with --no-github | `boolean` | `true` |
147
- | `--cache` | Cache drafts and incremental state; disable with --no-cache | `boolean` | `true` |
148
- | `--config` | Configuration file path | `string` | auto-detected from repository root |
149
- | `--timeout` | Agent timeout in minutes | `number` | `20` |
150
- | `--verbose` | Log commands, cache decisions, and session details to stderr | `boolean` | `false` |
151
- | `--help`<br>`-h` | Show help | `boolean` | |
152
- | `--version`<br>`-v` | Show version number | `boolean` | |
135
+ | Option | Description | Type | Default |
136
+ | ----------------------- | --------------------------------------------------------------------------------------- | --------------------------------------------- | --------------------------------------------- |
137
+ | `--cwd` | Repository directory | `string` | current directory |
138
+ | `--agent` | Installed agent CLI | `"codex"` `"claude"` | `codex` |
139
+ | `--model` | Agent model | `string` | gpt-6.1-sol (Codex); claude-opus-5-5 (Claude) |
140
+ | `--effort` | Reasoning effort | `"low"` `"medium"` `"high"` `"xhigh"` `"max"` | `xhigh` |
141
+ | `--interactive`<br>`-i` | Review a diff and optionally edit before writing | `boolean` | `false` |
142
+ | `--editor` | Editor command for interactive review; configure GUI editors to wait | `string` | git var GIT_EDITOR |
143
+ | `--dry-run` | Print a diff without applying changes | `boolean` | `false` |
144
+ | `--rebuild` | Reconstruct all history, replacing existing release text | `boolean` | `false` |
145
+ | `--amend` | Amend a verified unpublished release commit and matching local tags | `boolean` | `false` |
146
+ | `--root-changelog` | Monorepo root changelog: a summary of package releases, the root package alone, or none | `"summary"` `"package"` `"none"` | `summary` |
147
+ | `--skip-package` | Workspace package directory glob to leave without a changelog; repeatable | `array` | `none` |
148
+ | `--github` | Enrich Git evidence using gh when available; disable with --no-github | `boolean` | `true` |
149
+ | `--cache` | Cache drafts and incremental state; disable with --no-cache | `boolean` | `true` |
150
+ | `--config` | Configuration file path | `string` | auto-detected from repository root |
151
+ | `--timeout` | Agent timeout in minutes | `number` | `20` |
152
+ | `--verbose` | Log commands, cache decisions, and session details to stderr | `boolean` | `false` |
153
+ | `--help`<br>`-h` | Show help | `boolean` | |
154
+ | `--version`<br>`-v` | Show version number | `boolean` | |
153
155
 
154
156
  <!-- /cli-help -->
155
157
 
@@ -178,9 +180,9 @@ chagent --dry-run --no-github
178
180
 
179
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.
180
182
 
181
- `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.
182
184
 
183
- 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.
184
186
 
185
187
  #### API Examples
186
188
 
@@ -208,7 +210,7 @@ bumpp --all --execute "chagent -i"
208
210
  This runs the following sequence:
209
211
 
210
212
  1. Bumpp updates the package version.
211
- 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.
212
214
  3. The `-i` flag displays the diff and lets you edit, accept, or cancel. Saved edits are included when you accept.
213
215
  4. Bumpp commits the version and changelog changes together, tags the release, and pushes.
214
216
 
@@ -240,15 +242,19 @@ Avoid putting changelogs in bumpp's version-replacement `files` option: it can r
240
242
 
241
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.
242
244
 
243
- 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.
244
246
 
245
247
  ### Monorepos
246
248
 
247
- 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
+
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
+
253
+ Use `skipPackage` directory globs, or repeat `--skip-package`, to leave workspace packages such as documentation sites or examples without changelogs. A skipped package is left out of the root changelog, and its changes are not counted among the root's own, but packages that depend on it still include its relevant changes. To count a directory's changes as the root's instead, `exclude` it from workspace discovery. A pattern that matches no workspace package is an error.
248
254
 
249
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.
250
256
 
251
- 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.
252
258
 
253
259
  GitHub links to package changelogs on the default branch remain usable when a root entry is extracted for GitHub release notes.
254
260
 
@@ -266,6 +272,7 @@ export default defineConfig({
266
272
  github: true,
267
273
  maxInputChars: 80_000,
268
274
  model: 'gpt-6.1-sol',
275
+ rootChangelog: 'summary',
269
276
  timeout: 20,
270
277
  })
271
278
  ```
@@ -274,23 +281,23 @@ Importing `defineConfig` requires chagent in the repository's own dependencies.
274
281
 
275
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.
276
283
 
277
- Use `packages` and `exclude` directory globs to customize workspace discovery. 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`.
278
285
 
279
286
  ## Background
280
287
 
281
288
  ### Implementation notes
282
289
 
283
- 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
+ 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.
284
291
 
285
- 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
+ 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.
286
293
 
287
294
  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.
288
295
 
289
- 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.
296
+ 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.
290
297
 
291
298
  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.
292
299
 
293
- 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.
300
+ 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.
294
301
 
295
302
  ## Maintainers
296
303