@kyubiware/commit-mint 0.10.2 → 0.11.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.mjs CHANGED
@@ -33,7 +33,7 @@ var __exportAll = (all, no_symbols) => {
33
33
  //#region package.json
34
34
  var package_default = {
35
35
  name: "@kyubiware/commit-mint",
36
- version: "0.10.2",
36
+ version: "0.11.0",
37
37
  description: "🌿 AI-powered git commit tool — auto-group changed files, generate messages, run pre-commit checks",
38
38
  type: "module",
39
39
  bin: { "cmint": "./dist/bin.mjs" },
@@ -4081,7 +4081,8 @@ async function handleStaging(changedFiles, flags) {
4081
4081
  }
4082
4082
  return {
4083
4083
  changedFiles: currentFiles,
4084
- skipStaging
4084
+ skipStaging,
4085
+ stagedAll: stageAllFlag
4085
4086
  };
4086
4087
  }
4087
4088
  /** Run user-defined pre-commit checks from cmint config */
@@ -4129,6 +4130,7 @@ async function commitCommand(flags, version) {
4129
4130
  let changedFiles = await getChangedFiles();
4130
4131
  debug("Changed files:", changedFiles.length);
4131
4132
  const s = spinner();
4133
+ let stagedAll = true;
4132
4134
  try {
4133
4135
  if (flags.single) {
4134
4136
  debug("Single-commit mode: staging all files");
@@ -4144,6 +4146,7 @@ async function commitCommand(flags, version) {
4144
4146
  const result = await handleStaging(changedFiles, flags);
4145
4147
  if (!result) return;
4146
4148
  changedFiles = result.changedFiles;
4149
+ stagedAll = result.stagedAll;
4147
4150
  }
4148
4151
  } catch (err) {
4149
4152
  s.stop(red("Staging failed."));
@@ -4152,106 +4155,115 @@ async function commitCommand(flags, version) {
4152
4155
  outro(red(`Failed to stage files: ${msg}`));
4153
4156
  process.exit(1);
4154
4157
  }
4155
- changedFiles = await getChangedFiles();
4156
- if (!flags.noCheck && await getRunChecks()) await runPreCommitChecks(changedFiles, false);
4157
- const diffResult = await getStagedDiff();
4158
- if (!diffResult) {
4159
- debug("No staged changes found after staging");
4160
- outro(red("No staged changes found."));
4161
- process.exit(1);
4162
- }
4163
- if ("excludedFiles" in diffResult) {
4164
- debug("All staged files are excluded:", diffResult.excludedFiles);
4165
- const message = buildExcludedFilesMessage(diffResult.excludedFiles);
4166
- log.info(diffResult.excludedFiles.map((f) => ` ${f}`).join("\n"));
4167
- await saveCachedCommit(repoRoot, message);
4168
- s.start("Running pre-commit hooks...");
4169
- const result = await commitWithRecovery(message, s, await getHead());
4170
- if (result === "committed") {
4171
- outro(green("Done."));
4172
- return;
4158
+ while (true) {
4159
+ changedFiles = await getChangedFiles();
4160
+ if (!flags.noCheck && await getRunChecks()) await runPreCommitChecks(changedFiles, false);
4161
+ const diffResult = await getStagedDiff();
4162
+ if (!diffResult) {
4163
+ debug("No staged changes found after staging");
4164
+ outro(red("No staged changes found."));
4165
+ process.exit(1);
4173
4166
  }
4174
- if (result === "cancelled") process.exit(1);
4175
- return;
4176
- }
4177
- debug("Staged files:", diffResult.files);
4178
- debug("Diff length:", diffResult.diff.length, "chars");
4179
- log.info(diffResult.files.map((f) => ` ${f}`).join("\n"));
4180
- let message;
4181
- if (flags.message) {
4182
- debug("Using provided message:", flags.message);
4183
- message = flags.message;
4184
- } else {
4185
- const config = await readConfig();
4186
- const provider = isValidProvider(config.provider ?? "groq") ? config.provider : "groq";
4187
- try {
4188
- await getProviderApiKey(provider);
4189
- debug("API key found");
4190
- } catch {
4191
- debug("No API key found, prompting user");
4192
- const { text: promptText } = await import("@clack/prompts");
4193
- const configKey = PROVIDER_ENV_KEYS[provider];
4194
- const key = await promptText({
4195
- message: `Enter your ${formatProviderName(provider)} API key:`,
4196
- placeholder: provider === "groq" ? "gsk_..." : "...",
4197
- validate: (v) => v?.trim() ? void 0 : "API key is required"
4198
- });
4199
- if (isCancel(key)) {
4200
- outro(dim("Cancelled."));
4201
- return;
4167
+ let commitResult;
4168
+ if ("excludedFiles" in diffResult) {
4169
+ debug("All staged files are excluded:", diffResult.excludedFiles);
4170
+ const message = buildExcludedFilesMessage(diffResult.excludedFiles);
4171
+ log.info(diffResult.excludedFiles.map((f) => ` ${f}`).join("\n"));
4172
+ await saveCachedCommit(repoRoot, message);
4173
+ s.start("Running pre-commit hooks...");
4174
+ commitResult = await commitWithRecovery(message, s, await getHead());
4175
+ } else {
4176
+ debug("Staged files:", diffResult.files);
4177
+ debug("Diff length:", diffResult.diff.length, "chars");
4178
+ log.info(diffResult.files.map((f) => ` ${f}`).join("\n"));
4179
+ let message;
4180
+ if (flags.message) {
4181
+ debug("Using provided message:", flags.message);
4182
+ message = flags.message;
4183
+ } else {
4184
+ const config = await readConfig();
4185
+ const provider = isValidProvider(config.provider ?? "groq") ? config.provider : "groq";
4186
+ try {
4187
+ await getProviderApiKey(provider);
4188
+ debug("API key found");
4189
+ } catch {
4190
+ debug("No API key found, prompting user");
4191
+ const { text: promptText } = await import("@clack/prompts");
4192
+ const configKey = PROVIDER_ENV_KEYS[provider];
4193
+ const key = await promptText({
4194
+ message: `Enter your ${formatProviderName(provider)} API key:`,
4195
+ placeholder: provider === "groq" ? "gsk_..." : "...",
4196
+ validate: (v) => v?.trim() ? void 0 : "API key is required"
4197
+ });
4198
+ if (isCancel(key)) {
4199
+ outro(dim("Cancelled."));
4200
+ return;
4201
+ }
4202
+ await setConfigValue(configKey, String(key).trim());
4203
+ debug("API key saved to config");
4204
+ }
4205
+ s.start("Generating commit message...");
4206
+ try {
4207
+ const genStart = Date.now();
4208
+ message = await generateMessage(diffResult.diff, flags.hint);
4209
+ debug("generateMessage took %d ms", Date.now() - genStart);
4210
+ debug("Generated message:", message);
4211
+ } catch (err) {
4212
+ s.stop(red("Failed to generate message."));
4213
+ debug("Message generation failed:", err instanceof Error ? err.message : String(err));
4214
+ outro(red(err instanceof Error ? err.message : String(err)));
4215
+ return;
4216
+ }
4217
+ s.stop("Message generated");
4202
4218
  }
4203
- await setConfigValue(configKey, String(key).trim());
4204
- debug("API key saved to config");
4219
+ if (flags.single || await getAutoAccept()) {
4220
+ debug("Auto-accept ON: skipping review step");
4221
+ log.info(message);
4222
+ } else {
4223
+ const reviewed = await reviewCommitMessage(message, { regenerate: async (hint) => {
4224
+ const combinedHint = flags.hint ? `${flags.hint}\n${hint}` : hint;
4225
+ debug("Regenerating with combined hint:", combinedHint);
4226
+ s.start("Regenerating commit message...");
4227
+ try {
4228
+ const newMessage = await generateMessage(diffResult.diff, combinedHint);
4229
+ s.stop("Message regenerated");
4230
+ return newMessage;
4231
+ } catch (err) {
4232
+ s.stop(red("Regeneration failed"));
4233
+ throw err;
4234
+ }
4235
+ } });
4236
+ if (reviewed === null) {
4237
+ outro(dim("Cancelled."));
4238
+ return;
4239
+ }
4240
+ message = reviewed;
4241
+ }
4242
+ await saveCachedCommit(repoRoot, message);
4243
+ debug("Message cached for repo:", repoRoot);
4244
+ s.start("Running pre-commit hooks...");
4245
+ const headBefore = await getHead();
4246
+ debug("HEAD before commit:", headBefore);
4247
+ commitResult = await commitWithRecovery(message, s, headBefore);
4248
+ debug("Commit result:", commitResult);
4205
4249
  }
4206
- s.start("Generating commit message...");
4207
- try {
4208
- const genStart = Date.now();
4209
- message = await generateMessage(diffResult.diff, flags.hint);
4210
- debug("generateMessage took %d ms", Date.now() - genStart);
4211
- debug("Generated message:", message);
4212
- } catch (err) {
4213
- s.stop(red("Failed to generate message."));
4214
- debug("Message generation failed:", err instanceof Error ? err.message : String(err));
4215
- outro(red(err instanceof Error ? err.message : String(err)));
4250
+ if (commitResult === "cancelled") process.exit(1);
4251
+ if (stagedAll) {
4252
+ outro(green("Done."));
4216
4253
  return;
4217
4254
  }
4218
- s.stop("Message generated");
4219
- }
4220
- if (flags.single || await getAutoAccept()) {
4221
- debug("Auto-accept ON: skipping review step");
4222
- log.info(message);
4223
- } else {
4224
- const reviewed = await reviewCommitMessage(message, { regenerate: async (hint) => {
4225
- const combinedHint = flags.hint ? `${flags.hint}\n${hint}` : hint;
4226
- debug("Regenerating with combined hint:", combinedHint);
4227
- s.start("Regenerating commit message...");
4228
- try {
4229
- const newMessage = await generateMessage(diffResult.diff, combinedHint);
4230
- s.stop("Message regenerated");
4231
- return newMessage;
4232
- } catch (err) {
4233
- s.stop(red("Regeneration failed"));
4234
- throw err;
4235
- }
4236
- } });
4237
- if (reviewed === null) {
4238
- outro(dim("Cancelled."));
4255
+ const remaining = await getChangedFiles();
4256
+ if (remaining.length === 0) {
4257
+ outro(green("Done."));
4239
4258
  return;
4240
4259
  }
4241
- message = reviewed;
4242
- }
4243
- await saveCachedCommit(repoRoot, message);
4244
- debug("Message cached for repo:", repoRoot);
4245
- s.start("Running pre-commit hooks...");
4246
- const headBefore = await getHead();
4247
- debug("HEAD before commit:", headBefore);
4248
- const result = await commitWithRecovery(message, s, headBefore);
4249
- debug("Commit result:", result);
4250
- if (result === "committed") {
4251
- outro(green("Done."));
4252
- return;
4260
+ debug("Uncommitted files remain after commit:", remaining.length);
4261
+ log.info(`${remaining.length} file${remaining.length !== 1 ? "s" : ""} remaining — continuing with the staging menu`);
4262
+ const stagingResult = await handleStaging(remaining, flags);
4263
+ if (!stagingResult) return;
4264
+ changedFiles = stagingResult.changedFiles;
4265
+ stagedAll = stagingResult.stagedAll;
4253
4266
  }
4254
- if (result === "cancelled") process.exit(1);
4255
4267
  }
4256
4268
  //#endregion
4257
4269
  //#region src/cli.ts