@kud/ai-conventional-commit-cli 3.2.7 → 3.2.9

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.
@@ -209,31 +209,34 @@ var pdbg = (msg, pairs = {}) => {
209
209
  const kvStr = Object.entries(pairs).map(([k, v]) => chalk2.dim(k + "=") + chalk2.yellow(String(v))).join(" ");
210
210
  console.error(pTag, chalk2.white(msg), kvStr || "");
211
211
  };
212
- var killWithFallback = async (pid) => {
212
+ var killProcessGroup = (pid, signal) => {
213
213
  try {
214
- process.kill(pid, "SIGTERM");
215
- } catch {
216
- return;
217
- }
218
- const deadline = Date.now() + 1e3;
219
- while (Date.now() < deadline) {
220
- await new Promise((r) => setTimeout(r, 100));
221
- try {
222
- process.kill(pid, 0);
223
- } catch {
224
- return;
225
- }
226
- }
227
- try {
228
- process.kill(pid, "SIGKILL");
229
- console.warn(
230
- chalk2.yellow("\n\u26A0 [ai-cc]") + " opencode server did not shut down cleanly and had to be force-killed." + chalk2.dim(
231
- " Please report this at https://github.com/kud/ai-conventional-commit-cli/issues/new"
232
- )
233
- );
214
+ process.kill(-pid, signal);
234
215
  } catch {
235
216
  }
236
217
  };
218
+ var gracefulKill = (proc) => {
219
+ if (proc.exitCode !== null || !proc.pid) return Promise.resolve();
220
+ const pgid = proc.pid;
221
+ return new Promise((resolve) => {
222
+ const onExit = () => {
223
+ clearTimeout(timer);
224
+ resolve();
225
+ };
226
+ proc.once("exit", onExit);
227
+ killProcessGroup(pgid, "SIGTERM");
228
+ const timer = setTimeout(() => {
229
+ proc.off("exit", onExit);
230
+ proc.once("exit", () => resolve());
231
+ killProcessGroup(pgid, "SIGKILL");
232
+ console.warn(
233
+ chalk2.yellow("\n\u26A0 [ai-cc]") + " opencode server did not shut down cleanly and had to be force-killed." + chalk2.dim(
234
+ " Please report this at https://github.com/kud/ai-conventional-commit-cli/issues/new"
235
+ )
236
+ );
237
+ }, 1e3);
238
+ });
239
+ };
237
240
  function findFreePort() {
238
241
  return new Promise((resolve, reject) => {
239
242
  const server = createServer();
@@ -264,14 +267,16 @@ var OpenCodeProvider = class {
264
267
  debug;
265
268
  exitHandler;
266
269
  syncClose = null;
267
- serverPid = null;
270
+ serverProc = null;
268
271
  async _closeServer() {
269
272
  try {
270
- if (this.serverPid !== null) {
271
- await killWithFallback(this.serverPid);
272
- this.serverPid = null;
273
+ if (this.serverProc) {
274
+ await gracefulKill(this.serverProc);
275
+ this.serverProc = null;
273
276
  }
274
277
  this.ac.abort();
278
+ this.warmPromise?.catch(() => {
279
+ });
275
280
  } finally {
276
281
  process.off("exit", this.exitHandler);
277
282
  process.off("SIGINT", this.exitHandler);
@@ -298,16 +303,11 @@ var OpenCodeProvider = class {
298
303
  const originalXDG = process.env.XDG_CONFIG_HOME;
299
304
  process.env.XDG_CONFIG_HOME = join(tmpdir(), `aicc-${process.pid}`);
300
305
  const proc = spawn("opencode", ["serve", `--hostname=127.0.0.1`, `--port=${port}`], {
306
+ detached: true,
301
307
  env: { ...process.env, OPENCODE_CONFIG_CONTENT: JSON.stringify({ mcp: {} }) }
302
308
  });
303
- this.serverPid = proc.pid;
304
- const killProc = () => {
305
- try {
306
- process.kill(proc.pid, "SIGTERM");
307
- } catch {
308
- }
309
- };
310
- this.syncClose = killProc;
309
+ this.serverProc = proc;
310
+ this.syncClose = () => killProcessGroup(proc.pid, "SIGKILL");
311
311
  if (originalXDG === void 0) delete process.env.XDG_CONFIG_HOME;
312
312
  else process.env.XDG_CONFIG_HOME = originalXDG;
313
313
  const url = await new Promise((resolve, reject) => {
@@ -344,7 +344,7 @@ ${output}`));
344
344
  });
345
345
  this.ac.signal.addEventListener("abort", () => {
346
346
  clearTimeout(id);
347
- killProc();
347
+ killProcessGroup(proc.pid, "SIGKILL");
348
348
  reject(new Error("Aborted"));
349
349
  });
350
350
  });
@@ -361,7 +361,7 @@ ${output}`));
361
361
  if (this.debug) pdbg("session created", { id: sessionResult.data.id });
362
362
  return {
363
363
  client,
364
- server: { url, close: killProc, closeAsync: () => killWithFallback(proc.pid) },
364
+ server: { url },
365
365
  sessionID: sessionResult.data.id
366
366
  };
367
367
  }
package/dist/index.js CHANGED
@@ -16,7 +16,7 @@ import {
16
16
  formatCommitTitle,
17
17
  renderCommitBlock,
18
18
  sectionTitle
19
- } from "./chunk-A33HJRW3.js";
19
+ } from "./chunk-HFLQMZT6.js";
20
20
 
21
21
  // src/index.ts
22
22
  import { Cli, Command, Option } from "clipanion";
@@ -1079,7 +1079,7 @@ var RewordCommand = class extends Command {
1079
1079
  description: "Auto-confirm commit without prompting"
1080
1080
  });
1081
1081
  async execute() {
1082
- const { runReword } = await import("./reword-3F66V55Y.js");
1082
+ const { runReword } = await import("./reword-DJVPI7TM.js");
1083
1083
  const config = await loadConfig();
1084
1084
  if (this.style) config.style = this.style;
1085
1085
  if (this.model) config.model = this.model;
@@ -10,7 +10,7 @@ import {
10
10
  formatCommitTitle,
11
11
  renderCommitBlock,
12
12
  sectionTitle
13
- } from "./chunk-GZ5XLAI5.js";
13
+ } from "./chunk-HFLQMZT6.js";
14
14
 
15
15
  // src/workflow/reword.ts
16
16
  import chalk from "chalk";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kud/ai-conventional-commit-cli",
3
- "version": "3.2.7",
3
+ "version": "3.2.9",
4
4
  "type": "module",
5
5
  "description": "Opinionated, style-aware AI assistant for crafting and splitting git commits (opencode-based, provider-agnostic).",
6
6
  "bin": {
@@ -1,95 +0,0 @@
1
- // src/config.ts
2
- import { cosmiconfig } from "cosmiconfig";
3
- import { resolve, dirname, join } from "path";
4
- import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
5
- import { homedir } from "os";
6
- var DEFAULTS = {
7
- model: process.env.AICC_MODEL || "github-copilot/gpt-4.1",
8
- privacy: process.env.AICC_PRIVACY || "low",
9
- style: process.env.AICC_STYLE || "standard",
10
- styleSamples: parseInt(process.env.AICC_STYLE_SAMPLES || "120", 10),
11
- maxTokens: parseInt(process.env.AICC_MAX_TOKENS || "512", 10),
12
- cacheDir: ".git/.aicc-cache",
13
- plugins: [],
14
- verbose: process.env.AICC_VERBOSE === "true"
15
- };
16
- function getGlobalConfigPath() {
17
- const base = process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
18
- return resolve(base, "ai-conventional-commit-cli", "aicc.json");
19
- }
20
- function saveGlobalConfig(partial) {
21
- const filePath = getGlobalConfigPath();
22
- const dir = dirname(filePath);
23
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
24
- let existing = {};
25
- if (existsSync(filePath)) {
26
- try {
27
- existing = JSON.parse(readFileSync(filePath, "utf8")) || {};
28
- } catch (e) {
29
- if (process.env.AICC_VERBOSE === "true") {
30
- console.error("[ai-cc] Failed to parse existing global config, overwriting.");
31
- }
32
- }
33
- }
34
- const merged = { ...existing, ...partial };
35
- writeFileSync(filePath, JSON.stringify(merged, null, 2) + "\n", "utf8");
36
- return filePath;
37
- }
38
- async function loadConfig(cwd = process.cwd()) {
39
- return (await loadConfigDetailed(cwd)).config;
40
- }
41
- async function loadConfigDetailed(cwd = process.cwd()) {
42
- let globalCfg = {};
43
- const globalPath = getGlobalConfigPath();
44
- if (existsSync(globalPath)) {
45
- try {
46
- globalCfg = JSON.parse(readFileSync(globalPath, "utf8")) || {};
47
- } catch (e) {
48
- if (process.env.AICC_VERBOSE === "true") {
49
- console.error("[ai-cc] Failed to parse global config, ignoring.");
50
- }
51
- }
52
- }
53
- const explorer = cosmiconfig("aicc");
54
- const result = await explorer.search(cwd);
55
- const projectCfg = result?.config || {};
56
- const envCfg = {};
57
- if (process.env.AICC_MODEL) envCfg.model = process.env.AICC_MODEL;
58
- if (process.env.AICC_PRIVACY) envCfg.privacy = process.env.AICC_PRIVACY;
59
- if (process.env.AICC_STYLE) envCfg.style = process.env.AICC_STYLE;
60
- if (process.env.AICC_STYLE_SAMPLES)
61
- envCfg.styleSamples = parseInt(process.env.AICC_STYLE_SAMPLES, 10);
62
- if (process.env.AICC_MAX_TOKENS) envCfg.maxTokens = parseInt(process.env.AICC_MAX_TOKENS, 10);
63
- if (process.env.AICC_VERBOSE) envCfg.verbose = process.env.AICC_VERBOSE === "true";
64
- const merged = {
65
- ...DEFAULTS,
66
- ...globalCfg,
67
- ...projectCfg,
68
- ...envCfg
69
- };
70
- merged.plugins = (merged.plugins || []).filter((p) => {
71
- const abs = resolve(cwd, p);
72
- return existsSync(abs);
73
- });
74
- const sources = Object.keys(merged).reduce((acc, key) => {
75
- const k = key;
76
- let src = "default";
77
- if (k in globalCfg) src = "global";
78
- if (k in projectCfg) src = "project";
79
- if (k in envCfg) src = "env";
80
- acc[k] = src;
81
- return acc;
82
- }, {});
83
- const withMeta = Object.assign(merged, { _sources: sources });
84
- return {
85
- config: withMeta,
86
- raw: { defaults: DEFAULTS, global: globalCfg, project: projectCfg, env: envCfg }
87
- };
88
- }
89
-
90
- export {
91
- getGlobalConfigPath,
92
- saveGlobalConfig,
93
- loadConfig,
94
- loadConfigDetailed
95
- };