@kitschpatrol/chagent 0.1.0 → 0.2.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.
package/dist/bin/cli.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { C as version, S as maxTimeoutMs, b as defaultModels, i as generateChangelog, l as agentNames, n as previewChangelog, r as reviewChangelog, s as writeChangelog, t as assertReviewTerminal, u as efforts, x as defaults, y as setLogger } from "../review-LYSADnul.js";
3
- import { n as assertAmendable, t as amendRelease } from "../lib-CXMRRbJf.js";
2
+ import { C as version, S as maxTimeoutMinutes, b as defaultModels, i as generateChangelog, l as agentNames, n as previewChangelog, r as reviewChangelog, s as writeChangelog, t as assertReviewTerminal, u as efforts, x as defaults, y as setLogger } from "../review-BwgeC2dB.js";
3
+ import { n as assertAmendable, t as amendRelease } from "../lib-DTp3sA-Q.js";
4
4
  import { t as createProgressLine } from "../progress-DQtRnH1N.js";
5
5
  import { createLogger } from "lognow";
6
6
  import path from "node:path";
@@ -122,15 +122,15 @@ try {
122
122
  description: "Configuration file path",
123
123
  type: "string"
124
124
  }).option("timeout", {
125
- defaultDescription: String(defaults.timeoutMs / 1e3),
126
- description: "Agent timeout in seconds",
125
+ defaultDescription: String(defaults.timeout),
126
+ description: "Agent timeout in minutes",
127
127
  type: "number"
128
128
  }).option("verbose", {
129
129
  default: false,
130
130
  description: "Log commands, cache decisions, and session details to stderr",
131
131
  type: "boolean"
132
132
  }).check((args) => {
133
- if (args.timeout !== void 0 && (!Number.isFinite(args.timeout) || args.timeout <= 0 || args.timeout * 1e3 > 2147483647)) throw new Error(`--timeout must be a positive number of seconds, up to ${Math.floor(maxTimeoutMs / 1e3)}.`);
133
+ if (args.timeout !== void 0 && (!Number.isFinite(args.timeout) || args.timeout <= 0 || args.timeout > 35791.39411666667)) throw new Error(`--timeout must be a positive number of minutes, up to ${Math.floor(maxTimeoutMinutes)}.`);
134
134
  return true;
135
135
  }), async (args) => {
136
136
  if (!args.dryRun && args.interactive) assertReviewTerminal();
@@ -149,7 +149,7 @@ try {
149
149
  },
150
150
  rebuild: args.rebuild,
151
151
  signal: controller.signal,
152
- timeoutMs: args.timeout === void 0 ? void 0 : args.timeout * 1e3
152
+ timeout: args.timeout
153
153
  }));
154
154
  try {
155
155
  if (args.dryRun) {
@@ -1,4 +1,4 @@
1
- import { u as GenerateOptions } from "../types-Cms1Tu5k.js";
1
+ import { u as GenerateOptions } from "../types-COQP1I5w.js";
2
2
  import { VersionBumpOptions } from "bumpp";
3
3
  type ExecuteHook = Exclude<NonNullable<VersionBumpOptions['execute']>, string>;
4
4
  export type BumppHookOptions = Omit<GenerateOptions, 'cwd' | 'release'> & {
package/dist/lib/bumpp.js CHANGED
@@ -1,4 +1,4 @@
1
- import { g as git, i as generateChangelog, m as localDate, r as reviewChangelog, s as writeChangelog, t as assertReviewTerminal } from "../review-LYSADnul.js";
1
+ import { g as git, i as generateChangelog, m as localDate, r as reviewChangelog, s as writeChangelog, t as assertReviewTerminal } from "../review-BwgeC2dB.js";
2
2
  import { t as createProgressLine } from "../progress-DQtRnH1N.js";
3
3
 
4
4
  // src/lib/bumpp.ts
@@ -1,4 +1,4 @@
1
- import { _ as Config, a as ChangeSet, c as Evidence, d as GenerationRequest, f as GenerationResponse, g as RunSettings, h as ReleaseSummary, i as Change, l as FileEdit, m as ReleaseRequest, n as AgentName, o as ChangelogPlan, p as ReleaseContext, r as Category, s as Effort, t as AgentAdapter, u as GenerateOptions, v as defineConfig, y as loadConfig } from "../types-Cms1Tu5k.js";
1
+ import { _ as Config, a as ChangeSet, c as Evidence, d as GenerationRequest, f as GenerationResponse, g as RunSettings, h as ReleaseSummary, i as Change, l as FileEdit, m as ReleaseRequest, n as AgentName, o as ChangelogPlan, p as ReleaseContext, r as Category, s as Effort, t as AgentAdapter, u as GenerateOptions, v as defineConfig, y as loadConfig } from "../types-COQP1I5w.js";
2
2
  import { ILogBasic, ILogLayer } from "lognow";
3
3
  /** Create an adapter for an installed CLI using its existing authentication. */
4
4
  export declare function createAgent(name: AgentName): AgentAdapter;
package/dist/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as defineConfig, c as createAgent, i as generateChangelog, n as previewChangelog, o as loadConfig, r as reviewChangelog, s as writeChangelog, y as setLogger } from "../review-LYSADnul.js";
2
- import { t as amendRelease } from "../lib-CXMRRbJf.js";
1
+ import { a as defineConfig, c as createAgent, i as generateChangelog, n as previewChangelog, o as loadConfig, r as reviewChangelog, s as writeChangelog, y as setLogger } from "../review-BwgeC2dB.js";
2
+ import { t as amendRelease } from "../lib-DTp3sA-Q.js";
3
3
 
4
4
  export { amendRelease, createAgent, defineConfig, generateChangelog, loadConfig, previewChangelog, reviewChangelog, setLogger, writeChangelog };
@@ -1,4 +1,4 @@
1
- import { _ as isAncestor, d as LOCKFILE_PATH, f as inspectRepository, g as git, h as manifestAt, p as isVersionOnlyChange, s as writeChangelog, v as runCommand } from "./review-LYSADnul.js";
1
+ import { _ as isAncestor, d as LOCKFILE_PATH, f as inspectRepository, g as git, h as manifestAt, p as isVersionOnlyChange, s as writeChangelog, v as runCommand } from "./review-BwgeC2dB.js";
2
2
  import path from "node:path";
3
3
  import { realpath } from "node:fs/promises";
4
4
 
@@ -15,7 +15,7 @@ import { isCancel, select } from "@clack/prompts";
15
15
 
16
16
  // package.json
17
17
  var name = "@kitschpatrol/chagent";
18
- var version = "0.1.0";
18
+ var version = "0.2.0";
19
19
  var engines = { "node": "^24.16.0 || >=26.3.0" };
20
20
 
21
21
  // src/lib/defaults.ts
@@ -25,14 +25,14 @@ const defaults = {
25
25
  effort: "xhigh",
26
26
  github: true,
27
27
  maxInputChars: 8e4,
28
- timeoutMs: 12e5
28
+ timeout: 20
29
29
  };
30
30
  const defaultModels = {
31
31
  claude: "claude-opus-5-5",
32
32
  codex: "gpt-6.1-sol"
33
33
  };
34
34
  /** Node.js timers fire immediately when given a longer delay. */
35
- const maxTimeoutMs = 2147483647;
35
+ const maxTimeoutMinutes = 2147483647 / 6e4;
36
36
 
37
37
  // src/lib/log.ts
38
38
  /**
@@ -119,7 +119,8 @@ async function runCommand(command, args, options = {}) {
119
119
  detached,
120
120
  env: options.env ?? process.env,
121
121
  stdio: options.inherit === true ? "inherit" : "pipe",
122
- windowsHide: true
122
+ windowsHide: true,
123
+ windowsVerbatimArguments: options.windowsVerbatimArguments
123
124
  });
124
125
  const group = detached ? child.pid : void 0;
125
126
  if (group !== void 0) trackGroup(group);
@@ -1055,7 +1056,8 @@ const configSchema = z.strictObject({
1055
1056
  packages: z.array(z.string()).optional(),
1056
1057
  /** Templates containing {version} and optionally {name}. */
1057
1058
  tagPatterns: z.array(z.string().includes("{version}")).optional(),
1058
- timeoutMs: z.number().positive().max(maxTimeoutMs).optional()
1059
+ /** Minutes each agent session may run. */
1060
+ timeout: z.number().positive().max(maxTimeoutMinutes).optional()
1059
1061
  });
1060
1062
  const resolvedConfigSchema = configSchema.required({
1061
1063
  agent: true,
@@ -1063,8 +1065,11 @@ const resolvedConfigSchema = configSchema.required({
1063
1065
  effort: true,
1064
1066
  github: true,
1065
1067
  maxInputChars: true,
1066
- timeoutMs: true
1067
- });
1068
+ timeout: true
1069
+ }).transform(({ timeout, ...config }) => ({
1070
+ ...config,
1071
+ timeoutMs: timeout * 6e4
1072
+ }));
1068
1073
  function invalidConfig(source, error) {
1069
1074
  return new Error(`Invalid options in ${source}:\n${z.prettifyError(error)}`, { cause: error });
1070
1075
  }
@@ -1827,7 +1832,7 @@ function releaseContext(options, pkg) {
1827
1832
  return pkg.directory === options.releaseDirectory ? options.release : void 0;
1828
1833
  }
1829
1834
  /** Resolve a package's releases and prepare requests for those it still needs. */
1830
- async function preparePackage(context, pkg, aggregateHistory = false, aggregateContent) {
1835
+ async function preparePackage(context, pkg, aggregateHistory = false, recordedAtRoot) {
1831
1836
  const { repository } = context;
1832
1837
  const file = await findChangelog(path.join(repository.root, pkg.directory));
1833
1838
  const content = context.options.rebuild ? void 0 : file.content;
@@ -1854,7 +1859,7 @@ async function preparePackage(context, pkg, aggregateHistory = false, aggregateC
1854
1859
  version: release.version
1855
1860
  };
1856
1861
  summaries.push(summary);
1857
- if (!shouldWrite && aggregateContent !== void 0 && missingPackageSummaries([summary], aggregateContent).length === 0) continue;
1862
+ if (!shouldWrite && recordedAtRoot?.(summary) === true) continue;
1858
1863
  const existingBody = (draftPromoted ? release === newest : release.version === "Unreleased") ? draft?.body : void 0;
1859
1864
  const from = existingBody === void 0 ? void 0 : await incrementalBase(context, file.path, content, release);
1860
1865
  const request = await prepareRelease(context, pkg, release, existingBody ?? "", mode, from);
@@ -2078,9 +2083,12 @@ async function generateWorkspace(context) {
2078
2083
  const rootReleases = await resolveReleases(repository, repository.rootPackage, options, releaseContext(options, repository.rootPackage));
2079
2084
  const shared = rootReleases.some((release) => release.version !== "Unreleased");
2080
2085
  const rootFile = await findChangelog(repository.root);
2081
- const needsPackageHistory = !shared || missingReleases(rootReleases, options.rebuild ? void 0 : rootFile.content).some((release) => release.version !== "Unreleased");
2086
+ const rootContent = options.rebuild ? void 0 : rootFile.content;
2087
+ const rootMissing = shared ? new Set(missingReleases(rootReleases, rootContent).map((release) => release.version)) : void 0;
2088
+ const needsPackageHistory = rootMissing === void 0 || rootMissing.values().some((version) => version !== "Unreleased");
2089
+ const recordedAtRoot = (summary) => rootMissing === void 0 ? rootContent !== void 0 && missingPackageSummaries([summary], rootContent).length === 0 : !rootMissing.has(summary.version);
2082
2090
  const packages = [];
2083
- for (const pkg of repository.packages) packages.push(await preparePackage(context, pkg, needsPackageHistory, shared || options.rebuild ? void 0 : rootFile.content));
2091
+ for (const pkg of repository.packages) packages.push(await preparePackage(context, pkg, needsPackageHistory, recordedAtRoot));
2084
2092
  const root = shared ? await preparePackage(context, repository.rootPackage) : void 0;
2085
2093
  const independent = shared ? void 0 : await prepareIndependent(context, packages.flatMap((pkg) => pkg.summaries));
2086
2094
  const requests = [...packages, ...root === void 0 ? [] : [root]].flatMap((pkg) => pkg.work.map((item) => item.request));
@@ -2231,21 +2239,23 @@ function changelogProblem(plan) {
2231
2239
  }
2232
2240
  }
2233
2241
  async function openEditor(editor, file, cwd) {
2234
- const args = process.platform === "win32" ? [
2242
+ const windows = process.platform === "win32";
2243
+ const args = windows ? [
2235
2244
  "/d",
2236
2245
  "/s",
2237
2246
  "/c",
2238
- `${editor} "${file}"`
2247
+ `"${editor} "${file}""`
2239
2248
  ] : [
2240
2249
  "-c",
2241
2250
  `${editor} "$1"`,
2242
2251
  "chagent-editor",
2243
2252
  file
2244
2253
  ];
2245
- await runCommand(process.platform === "win32" ? "cmd.exe" : "sh", args, {
2254
+ await runCommand(windows ? "cmd.exe" : "sh", args, {
2246
2255
  cwd,
2247
2256
  inherit: true,
2248
- timeoutMs: 864e5
2257
+ timeoutMs: 864e5,
2258
+ windowsVerbatimArguments: windows
2249
2259
  });
2250
2260
  }
2251
2261
  /**
@@ -2307,4 +2317,4 @@ async function reviewChangelog(plan, options = {}) {
2307
2317
  }
2308
2318
  }
2309
2319
 
2310
- export { version as C, maxTimeoutMs as S, isAncestor as _, defineConfig as a, defaultModels as b, createAgent as c, LOCKFILE_PATH as d, inspectRepository as f, git as g, manifestAt as h, generateChangelog as i, agentNames as l, localDate as m, previewChangelog as n, loadConfig as o, isVersionOnlyChange as p, reviewChangelog as r, writeChangelog as s, assertReviewTerminal as t, efforts as u, runCommand as v, defaults as x, setLogger as y };
2320
+ export { version as C, maxTimeoutMinutes as S, isAncestor as _, defineConfig as a, defaultModels as b, createAgent as c, LOCKFILE_PATH as d, inspectRepository as f, git as g, manifestAt as h, generateChangelog as i, agentNames as l, localDate as m, previewChangelog as n, loadConfig as o, isVersionOnlyChange as p, reviewChangelog as r, writeChangelog as s, assertReviewTerminal as t, efforts as u, runCommand as v, defaults as x, setLogger as y };
@@ -18,7 +18,7 @@ declare const configSchema: z.ZodObject<{
18
18
  model: z.ZodOptional<z.ZodString>;
19
19
  packages: z.ZodOptional<z.ZodArray<z.ZodString>>;
20
20
  tagPatterns: z.ZodOptional<z.ZodArray<z.ZodString>>;
21
- timeoutMs: z.ZodOptional<z.ZodNumber>;
21
+ timeout: z.ZodOptional<z.ZodNumber>;
22
22
  }, z.core.$strict>;
23
23
  type Config = z.infer<typeof configSchema>;
24
24
  /** Define optional repository configuration with TypeScript completion. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kitschpatrol/chagent",
3
- "version": "0.1.0",
3
+ "version": "0.2.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",
@@ -90,7 +90,7 @@
90
90
  "clean-deep": "shx rm -f pnpm-lock.yaml && git clean -fdX",
91
91
  "fix": "pnpm build && ksc fix",
92
92
  "lint": "pnpm build && ksc lint",
93
- "release": "bumpp --all --commit 'Release: %s' --execute 'node dist/bin/cli.js' && pnpm build && pnpm publish --otp $(op item get npm --otp) && brewpub --tap kitschpatrol/tap --description 'Generate and update changelogs from Git history with Codex or Claude'",
93
+ "release": "pnpm build && bumpp --all --commit 'Release: %s' --execute 'node dist/bin/cli.js' && pnpm build && pnpm publish --otp $(op item get npm --otp) && brewpub --tap kitschpatrol/tap --description 'Generate and update changelogs from Git history with Codex or Claude'",
94
94
  "test": "pnpm build && vitest run"
95
95
  }
96
96
  }
package/readme.md CHANGED
@@ -15,6 +15,10 @@
15
15
 
16
16
  <!-- /short-description -->
17
17
 
18
+ > [!WARNING]
19
+ >
20
+ > **This project is under development. It should not be considered suitable for general use until a 1.0 release.**
21
+
18
22
  ## Overview
19
23
 
20
24
  Run `chagent` in a Git repository to either create a changelog where none previously existed, or update an existing changelog to capture recent changes.
@@ -142,7 +146,7 @@ chagent
142
146
  | `--github` | Enrich Git evidence using gh when available; disable with --no-github | `boolean` | `true` |
143
147
  | `--cache` | Cache drafts and incremental state; disable with --no-cache | `boolean` | `true` |
144
148
  | `--config` | Configuration file path | `string` | auto-detected from repository root |
145
- | `--timeout` | Agent timeout in seconds | `number` | `1200` |
149
+ | `--timeout` | Agent timeout in minutes | `number` | `20` |
146
150
  | `--verbose` | Log commands, cache decisions, and session details to stderr | `boolean` | `false` |
147
151
  | `--help`<br>`-h` | Show help | `boolean` | |
148
152
  | `--version`<br>`-v` | Show version number | `boolean` | |
@@ -262,7 +266,7 @@ export default defineConfig({
262
266
  github: true,
263
267
  maxInputChars: 80_000,
264
268
  model: 'gpt-6.1-sol',
265
- timeoutMs: 1_200_000,
269
+ timeout: 20,
266
270
  })
267
271
  ```
268
272
 
@@ -280,7 +284,7 @@ Chagent reads reachable version tags and commit history regardless of the projec
280
284
 
281
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.
282
286
 
283
- 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. `timeoutMs` applies to each agent session. Lockfile maintenance retains its commit intent, while pure npm version-bump bookkeeping is excluded.
287
+ 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. Lockfile maintenance retains its commit intent, while pure npm version-bump bookkeeping is excluded.
284
288
 
285
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.
286
290