contribute-now 0.7.3 → 0.7.4-dev.ac68df0

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.
Files changed (4) hide show
  1. package/README.md +67 -64
  2. package/dist/cli.js +477 -1744
  3. package/package.json +7 -9
  4. package/dist/index.js +0 -35
package/dist/cli.js CHANGED
@@ -1,3 +1,4 @@
1
+ #!/usr/bin/env bun
1
2
  // @bun
2
3
  var __create = Object.create;
3
4
  var __getProtoOf = Object.getPrototypeOf;
@@ -7540,6 +7541,9 @@ async function hasLocalWork(remote, branch) {
7540
7541
  async function deleteRemoteBranch(remote, branch) {
7541
7542
  return run(["push", remote, "--delete", branch]);
7542
7543
  }
7544
+ async function stashChanges(message) {
7545
+ return run(["stash", "push", "-m", `contrib-save: ${message}`]);
7546
+ }
7543
7547
  async function mergeSquash(branch) {
7544
7548
  return run(["merge", "--squash", branch]);
7545
7549
  }
@@ -10972,19 +10976,19 @@ async function checkCopilotAvailable2() {
10972
10976
  const aiConfig = resolveAIConfig();
10973
10977
  if (aiConfig.provider === "ollama-cloud") {
10974
10978
  if (!await hasOllamaCloudApiKey()) {
10975
- return "Ollama Cloud API key not found. Run `contrib setup` to save it.";
10979
+ return "Ollama Cloud API key not found. Run `cn setup` to save it.";
10976
10980
  }
10977
10981
  try {
10978
10982
  const apiKey = await getOllamaCloudApiKey();
10979
10983
  if (!apiKey) {
10980
- return "Ollama Cloud API key not found. Run `contrib setup` to save it.";
10984
+ return "Ollama Cloud API key not found. Run `cn setup` to save it.";
10981
10985
  }
10982
10986
  await fetchOllamaCloudModels(apiKey, aiConfig.host);
10983
10987
  return null;
10984
10988
  } catch (err) {
10985
10989
  const msg = err instanceof Error ? err.message : String(err);
10986
10990
  if (msg === "Ollama Cloud authentication failed") {
10987
- return "Ollama Cloud authentication failed. Update your saved API key with `contrib setup`.";
10991
+ return "Ollama Cloud authentication failed. Update your saved API key with `cn setup`.";
10988
10992
  }
10989
10993
  if (msg.startsWith("Ollama Cloud model lookup failed")) {
10990
10994
  return msg.replace("model lookup", "health check");
@@ -11877,7 +11881,7 @@ var clean_default = defineCommand({
11877
11881
  await assertCleanGitState("cleaning");
11878
11882
  const config = readConfig();
11879
11883
  if (!config) {
11880
- error("No repo config found. Run `contrib setup` first.");
11884
+ error("No repo config found. Run `cn setup` first.");
11881
11885
  process.exit(1);
11882
11886
  }
11883
11887
  const { origin } = config;
@@ -11983,13 +11987,121 @@ ${import_picocolors8.default.bold("Stale branches (remote deleted, likely squash
11983
11987
  const finalBranch = await getCurrentBranch();
11984
11988
  if (finalBranch && protectedBranches.has(finalBranch)) {
11985
11989
  console.log();
11986
- info(`You're on ${import_picocolors8.default.bold(finalBranch)}. Run ${import_picocolors8.default.bold("contrib start")} to begin a new feature.`);
11990
+ info(`You're on ${import_picocolors8.default.bold(finalBranch)}. Run ${import_picocolors8.default.bold("cn start")} to begin a new feature.`);
11987
11991
  }
11988
11992
  }
11989
11993
  });
11990
11994
 
11991
- // src/commands/commit.ts
11995
+ // src/commands/discard.ts
11992
11996
  var import_picocolors9 = __toESM(require_picocolors(), 1);
11997
+ var discard_default = defineCommand({
11998
+ meta: {
11999
+ name: "discard",
12000
+ description: "Discard the current feature branch and return to the base branch"
12001
+ },
12002
+ args: {
12003
+ force: {
12004
+ type: "boolean",
12005
+ alias: "f",
12006
+ description: "Skip confirmation and discard immediately",
12007
+ default: false
12008
+ }
12009
+ },
12010
+ async run({ args }) {
12011
+ if (!await isGitRepo()) {
12012
+ error("Not inside a git repository.");
12013
+ process.exit(1);
12014
+ }
12015
+ await assertCleanGitState("discarding a branch");
12016
+ const config = readConfig();
12017
+ if (!config) {
12018
+ error("No repo config found. Run `cn setup` first.");
12019
+ process.exit(1);
12020
+ }
12021
+ const currentBranch = await getCurrentBranch();
12022
+ const baseBranch = getBaseBranch(config);
12023
+ await projectHeading("discard", "\uD83D\uDDD1\uFE0F");
12024
+ if (isBranchProtected(currentBranch, config)) {
12025
+ error(`${import_picocolors9.default.bold(currentBranch)} is a protected branch and cannot be discarded.`);
12026
+ info(`Switch to a feature branch first, then run ${import_picocolors9.default.bold("cn discard")}.`);
12027
+ process.exit(1);
12028
+ }
12029
+ if (currentBranch === baseBranch) {
12030
+ info(`You are already on ${import_picocolors9.default.bold(baseBranch)}.`);
12031
+ process.exit(0);
12032
+ }
12033
+ const { origin } = config;
12034
+ const localWork = await hasLocalWork(origin, currentBranch);
12035
+ const hasWork = localWork.uncommitted || localWork.unpushedCommits > 0;
12036
+ if (hasWork) {
12037
+ if (localWork.uncommitted) {
12038
+ warn("You have uncommitted changes in your working tree.");
12039
+ }
12040
+ if (localWork.unpushedCommits > 0) {
12041
+ warn(`You have ${import_picocolors9.default.bold(String(localWork.unpushedCommits))} unpushed commit${localWork.unpushedCommits !== 1 ? "s" : ""} on this branch.`);
12042
+ }
12043
+ warn("Discarding this branch will permanently lose that work.");
12044
+ const SAVE_FIRST = "Save my changes first (cn save), then discard";
12045
+ const DISCARD_ANYWAY = "Discard anyway \u2014 I do not need this work";
12046
+ const CANCEL = "Keep the branch, take me back";
12047
+ const action = await selectPrompt("This branch has unsaved work. What would you like to do?", [SAVE_FIRST, DISCARD_ANYWAY, CANCEL]);
12048
+ if (action === CANCEL) {
12049
+ info("Discard cancelled. Your branch is untouched.");
12050
+ process.exit(0);
12051
+ }
12052
+ if (action === SAVE_FIRST) {
12053
+ if (!localWork.uncommitted) {
12054
+ info("No uncommitted changes to stash \u2014 unpushed commits will still be lost.");
12055
+ const confirm = await confirmPrompt("Continue discarding the branch?");
12056
+ if (!confirm) {
12057
+ info("Discard cancelled.");
12058
+ process.exit(0);
12059
+ }
12060
+ } else {
12061
+ const stashResult = await stashChanges(`work-in-progress on ${currentBranch}`);
12062
+ if (stashResult.exitCode !== 0) {
12063
+ error(`Failed to save changes: ${stashResult.stderr}`);
12064
+ process.exit(1);
12065
+ }
12066
+ success(`Changes saved. Use ${import_picocolors9.default.bold("cn save --restore")} to bring them back.`);
12067
+ }
12068
+ }
12069
+ } else if (!args.force) {
12070
+ const confirmed = await confirmPrompt(`Discard ${import_picocolors9.default.bold(currentBranch)} and return to ${import_picocolors9.default.bold(baseBranch)}?`);
12071
+ if (!confirmed) {
12072
+ info("Discard cancelled.");
12073
+ process.exit(0);
12074
+ }
12075
+ }
12076
+ const upstreamRef = await getUpstreamRef();
12077
+ let deleteRemote = false;
12078
+ if (upstreamRef) {
12079
+ deleteRemote = await confirmPrompt(`Also delete the remote branch ${import_picocolors9.default.bold(upstreamRef)}?`);
12080
+ }
12081
+ const checkoutResult = await checkoutBranch(baseBranch);
12082
+ if (checkoutResult.exitCode !== 0) {
12083
+ error(`Failed to switch to ${import_picocolors9.default.bold(baseBranch)}: ${checkoutResult.stderr}`);
12084
+ process.exit(1);
12085
+ }
12086
+ const deleteResult = await forceDeleteBranch(currentBranch);
12087
+ if (deleteResult.exitCode !== 0) {
12088
+ error(`Failed to delete branch ${import_picocolors9.default.bold(currentBranch)}: ${deleteResult.stderr}`);
12089
+ process.exit(1);
12090
+ }
12091
+ success(`Discarded ${import_picocolors9.default.bold(currentBranch)} and switched back to ${import_picocolors9.default.bold(baseBranch)}`);
12092
+ if (deleteRemote) {
12093
+ const remoteDeleteResult = await deleteRemoteBranch(origin, currentBranch);
12094
+ if (remoteDeleteResult.exitCode !== 0) {
12095
+ warn(`Could not delete remote branch: ${remoteDeleteResult.stderr.trim()}`);
12096
+ } else {
12097
+ success(`Deleted remote branch ${import_picocolors9.default.bold(`${origin}/${currentBranch}`)}`);
12098
+ }
12099
+ }
12100
+ }
12101
+ });
12102
+
12103
+ // src/commands/commit.ts
12104
+ var import_picocolors10 = __toESM(require_picocolors(), 1);
11993
12105
 
11994
12106
  // src/utils/convention.ts
11995
12107
  var CLEAN_COMMIT_PATTERN = /^(\uD83D\uDCE6|\uD83D\uDD27|\uD83D\uDDD1\uFE0F?|\uD83D\uDD12|\u2699\uFE0F?|\u2615|\uD83E\uDDEA|\uD83D\uDCD6|\uD83D\uDE80) (new|update|remove|security|setup|chore|test|docs|release)(!?)( \([a-zA-Z0-9][a-zA-Z0-9-]*\))?: .{1,72}$/u;
@@ -12075,7 +12187,7 @@ var commit_default = defineCommand({
12075
12187
  await assertCleanGitState("committing");
12076
12188
  const config = readConfig();
12077
12189
  if (!config) {
12078
- error("No repo config found. Run `contrib setup` first.");
12190
+ error("No repo config found. Run `cn setup` first.");
12079
12191
  process.exit(1);
12080
12192
  }
12081
12193
  await projectHeading("commit", "\uD83D\uDCBE");
@@ -12096,9 +12208,9 @@ var commit_default = defineCommand({
12096
12208
  process.exit(1);
12097
12209
  }
12098
12210
  console.log(`
12099
- ${import_picocolors9.default.bold("Changed files:")}`);
12211
+ ${import_picocolors10.default.bold("Changed files:")}`);
12100
12212
  for (const f3 of changedFiles) {
12101
- console.log(` ${import_picocolors9.default.dim("\u2022")} ${f3}`);
12213
+ console.log(` ${import_picocolors10.default.dim("\u2022")} ${f3}`);
12102
12214
  }
12103
12215
  const stageAction = await selectPrompt("No staged changes. How would you like to stage?", [
12104
12216
  "Stage all changes",
@@ -12140,8 +12252,8 @@ ${import_picocolors9.default.bold("Changed files:")}`);
12140
12252
  const dirs = new Set(stagedFiles.map((f3) => f3.split("/")[0]));
12141
12253
  if (dirs.size > 1) {
12142
12254
  console.log();
12143
- warn(`You're staging ${import_picocolors9.default.bold(String(stagedFiles.length))} files across ${import_picocolors9.default.bold(String(dirs.size))} directories in a single commit.`);
12144
- info(import_picocolors9.default.dim("Large commits mixing different topics make history harder to read and bisect. " + "For cleaner history, consider splitting into atomic commits."));
12255
+ warn(`You're staging ${import_picocolors10.default.bold(String(stagedFiles.length))} files across ${import_picocolors10.default.bold(String(dirs.size))} directories in a single commit.`);
12256
+ info(import_picocolors10.default.dim("Large commits mixing different topics make history harder to read and bisect. " + "For cleaner history, consider splitting into atomic commits."));
12145
12257
  const choice = await selectPrompt("How would you like to proceed?", [
12146
12258
  "Continue as single commit",
12147
12259
  "Switch to group mode (AI splits into atomic commits)",
@@ -12172,7 +12284,7 @@ ${import_picocolors9.default.bold("Changed files:")}`);
12172
12284
  if (commitMessage) {
12173
12285
  spinner.success("AI commit message generated.");
12174
12286
  console.log(`
12175
- ${import_picocolors9.default.dim("AI suggestion:")} ${import_picocolors9.default.bold(import_picocolors9.default.cyan(commitMessage))}`);
12287
+ ${import_picocolors10.default.dim("AI suggestion:")} ${import_picocolors10.default.bold(import_picocolors10.default.cyan(commitMessage))}`);
12176
12288
  } else {
12177
12289
  spinner.fail("AI did not return a commit message.");
12178
12290
  warn("Falling back to manual entry.");
@@ -12200,7 +12312,7 @@ ${import_picocolors9.default.bold("Changed files:")}`);
12200
12312
  if (regen) {
12201
12313
  spinner.success("Commit message regenerated.");
12202
12314
  console.log(`
12203
- ${import_picocolors9.default.dim("AI suggestion:")} ${import_picocolors9.default.bold(import_picocolors9.default.cyan(regen))}`);
12315
+ ${import_picocolors10.default.dim("AI suggestion:")} ${import_picocolors10.default.bold(import_picocolors10.default.cyan(regen))}`);
12204
12316
  const ok = await confirmPrompt("Use this message?");
12205
12317
  finalMessage = ok ? regen : await inputPrompt("Enter commit message manually");
12206
12318
  } else {
@@ -12215,7 +12327,7 @@ ${import_picocolors9.default.bold("Changed files:")}`);
12215
12327
  if (convention2 !== "none") {
12216
12328
  console.log();
12217
12329
  for (const hint of CONVENTION_FORMAT_HINTS[convention2]) {
12218
- console.log(import_picocolors9.default.dim(hint));
12330
+ console.log(import_picocolors10.default.dim(hint));
12219
12331
  }
12220
12332
  console.log();
12221
12333
  }
@@ -12239,7 +12351,7 @@ ${import_picocolors9.default.bold("Changed files:")}`);
12239
12351
  error(`Failed to commit: ${result.stderr}`);
12240
12352
  process.exit(1);
12241
12353
  }
12242
- success(`Committed: ${import_picocolors9.default.bold(finalMessage)}`);
12354
+ success(`Committed: ${import_picocolors10.default.bold(finalMessage)}`);
12243
12355
  }
12244
12356
  });
12245
12357
  async function runGroupCommit(model, config) {
@@ -12256,9 +12368,9 @@ async function runGroupCommit(model, config) {
12256
12368
  process.exit(1);
12257
12369
  }
12258
12370
  console.log(`
12259
- ${import_picocolors9.default.bold("Changed files:")}`);
12371
+ ${import_picocolors10.default.bold("Changed files:")}`);
12260
12372
  for (const f3 of changedFiles) {
12261
- console.log(` ${import_picocolors9.default.dim("\u2022")} ${f3}`);
12373
+ console.log(` ${import_picocolors10.default.dim("\u2022")} ${f3}`);
12262
12374
  }
12263
12375
  const spinner = createSpinner(changedFiles.length >= BATCH_CONFIG.LARGE_CHANGESET_THRESHOLD ? `Asking AI to group ${changedFiles.length} file(s) into logical commits (using optimized batching)...` : `Asking AI to group ${changedFiles.length} file(s) into logical commits...`, {
12264
12376
  tips: LOADING_TIPS
@@ -12304,13 +12416,13 @@ ${import_picocolors9.default.bold("Changed files:")}`);
12304
12416
  let commitAll = false;
12305
12417
  while (!proceedToCommit) {
12306
12418
  console.log(`
12307
- ${import_picocolors9.default.bold(`AI suggested ${validGroups.length} commit group(s):`)}
12419
+ ${import_picocolors10.default.bold(`AI suggested ${validGroups.length} commit group(s):`)}
12308
12420
  `);
12309
12421
  for (let i2 = 0;i2 < validGroups.length; i2++) {
12310
12422
  const g3 = validGroups[i2];
12311
- console.log(` ${import_picocolors9.default.cyan(`Group ${i2 + 1}:`)} ${import_picocolors9.default.bold(g3.message)}`);
12423
+ console.log(` ${import_picocolors10.default.cyan(`Group ${i2 + 1}:`)} ${import_picocolors10.default.bold(g3.message)}`);
12312
12424
  for (const f3 of g3.files) {
12313
- console.log(` ${import_picocolors9.default.dim("\u2022")} ${f3}`);
12425
+ console.log(` ${import_picocolors10.default.dim("\u2022")} ${f3}`);
12314
12426
  }
12315
12427
  console.log();
12316
12428
  }
@@ -12376,16 +12488,16 @@ ${import_picocolors9.default.bold(`AI suggested ${validGroups.length} commit gro
12376
12488
  continue;
12377
12489
  }
12378
12490
  committed++;
12379
- success(`Committed group ${i2 + 1}: ${import_picocolors9.default.bold(group.message)}`);
12491
+ success(`Committed group ${i2 + 1}: ${import_picocolors10.default.bold(group.message)}`);
12380
12492
  }
12381
12493
  } else {
12382
12494
  for (let i2 = 0;i2 < validGroups.length; i2++) {
12383
12495
  const group = validGroups[i2];
12384
- console.log(import_picocolors9.default.bold(`
12496
+ console.log(import_picocolors10.default.bold(`
12385
12497
  \u2500\u2500 Group ${i2 + 1}/${validGroups.length} \u2500\u2500`));
12386
- console.log(` ${import_picocolors9.default.cyan(group.message)}`);
12498
+ console.log(` ${import_picocolors10.default.cyan(group.message)}`);
12387
12499
  for (const f3 of group.files) {
12388
- console.log(` ${import_picocolors9.default.dim("\u2022")} ${f3}`);
12500
+ console.log(` ${import_picocolors10.default.dim("\u2022")} ${f3}`);
12389
12501
  }
12390
12502
  let message = group.message;
12391
12503
  let actionDone = false;
@@ -12409,7 +12521,7 @@ ${import_picocolors9.default.bold(`AI suggested ${validGroups.length} commit gro
12409
12521
  if (newMsg) {
12410
12522
  message = newMsg;
12411
12523
  group.message = newMsg;
12412
- regenSpinner.success(`New message: ${import_picocolors9.default.bold(message)}`);
12524
+ regenSpinner.success(`New message: ${import_picocolors10.default.bold(message)}`);
12413
12525
  } else {
12414
12526
  regenSpinner.fail("AI could not generate a new message. Keeping current one.");
12415
12527
  }
@@ -12472,7 +12584,7 @@ ${import_picocolors9.default.bold(`AI suggested ${validGroups.length} commit gro
12472
12584
  continue;
12473
12585
  }
12474
12586
  committed++;
12475
- success(`Committed group ${i2 + 1}: ${import_picocolors9.default.bold(message)}`);
12587
+ success(`Committed group ${i2 + 1}: ${import_picocolors10.default.bold(message)}`);
12476
12588
  actionDone = true;
12477
12589
  }
12478
12590
  }
@@ -12487,7 +12599,7 @@ ${import_picocolors9.default.bold(`AI suggested ${validGroups.length} commit gro
12487
12599
  }
12488
12600
 
12489
12601
  // src/commands/config.ts
12490
- var import_picocolors10 = __toESM(require_picocolors(), 1);
12602
+ var import_picocolors11 = __toESM(require_picocolors(), 1);
12491
12603
  var WORKFLOW_OPTIONS = [
12492
12604
  { value: "clean-flow", label: WORKFLOW_DESCRIPTIONS["clean-flow"] },
12493
12605
  { value: "github-flow", label: WORKFLOW_DESCRIPTIONS["github-flow"] },
@@ -12703,7 +12815,7 @@ async function applyOllamaApiKeyEdit(result) {
12703
12815
  if (result.ollamaApiKeyAction === "set" && result.ollamaApiKey) {
12704
12816
  await setOllamaCloudApiKey(result.ollamaApiKey);
12705
12817
  success("Stored Ollama Cloud API key in the local secrets store.");
12706
- info(`Secrets path: ${import_picocolors10.default.bold(getSecretsStorePath())}`);
12818
+ info(`Secrets path: ${import_picocolors11.default.bold(getSecretsStorePath())}`);
12707
12819
  return;
12708
12820
  }
12709
12821
  if (result.ollamaApiKeyAction === "delete") {
@@ -12716,29 +12828,29 @@ async function applyOllamaApiKeyEdit(result) {
12716
12828
  }
12717
12829
  }
12718
12830
  function printConfigSummary(snapshot) {
12719
- info(`Config source: ${import_picocolors10.default.bold(snapshot.source)}`);
12720
- info(`Config path: ${import_picocolors10.default.bold(snapshot.location)}`);
12721
- info(`Workflow: ${import_picocolors10.default.bold(snapshot.workflowLabel)}`);
12722
- info(`Convention: ${import_picocolors10.default.bold(snapshot.commitConventionLabel)}`);
12723
- info(`Role: ${import_picocolors10.default.bold(snapshot.role)}`);
12831
+ info(`Config source: ${import_picocolors11.default.bold(snapshot.source)}`);
12832
+ info(`Config path: ${import_picocolors11.default.bold(snapshot.location)}`);
12833
+ info(`Workflow: ${import_picocolors11.default.bold(snapshot.workflowLabel)}`);
12834
+ info(`Convention: ${import_picocolors11.default.bold(snapshot.commitConventionLabel)}`);
12835
+ info(`Role: ${import_picocolors11.default.bold(snapshot.role)}`);
12724
12836
  if (snapshot.devBranch) {
12725
- info(`Main: ${import_picocolors10.default.bold(snapshot.mainBranch)} | Dev: ${import_picocolors10.default.bold(snapshot.devBranch)}`);
12837
+ info(`Main: ${import_picocolors11.default.bold(snapshot.mainBranch)} | Dev: ${import_picocolors11.default.bold(snapshot.devBranch)}`);
12726
12838
  } else {
12727
- info(`Main: ${import_picocolors10.default.bold(snapshot.mainBranch)}`);
12839
+ info(`Main: ${import_picocolors11.default.bold(snapshot.mainBranch)}`);
12728
12840
  }
12729
- info(`Origin: ${import_picocolors10.default.bold(snapshot.origin)} | Upstream: ${import_picocolors10.default.bold(snapshot.upstream)}`);
12730
- info(`Branch prefixes: ${import_picocolors10.default.bold(snapshot.branchPrefixes.join(", "))}`);
12731
- info(`Guides: ${import_picocolors10.default.bold(snapshot.showTips ? "shown" : "hidden")}`);
12732
- info(`AI: ${import_picocolors10.default.bold(snapshot.ai.enabled ? "enabled" : "disabled")}`);
12841
+ info(`Origin: ${import_picocolors11.default.bold(snapshot.origin)} | Upstream: ${import_picocolors11.default.bold(snapshot.upstream)}`);
12842
+ info(`Branch prefixes: ${import_picocolors11.default.bold(snapshot.branchPrefixes.join(", "))}`);
12843
+ info(`Guides: ${import_picocolors11.default.bold(snapshot.showTips ? "shown" : "hidden")}`);
12844
+ info(`AI: ${import_picocolors11.default.bold(snapshot.ai.enabled ? "enabled" : "disabled")}`);
12733
12845
  if (snapshot.ai.enabled && snapshot.ai.providerLabel) {
12734
- info(`AI provider: ${import_picocolors10.default.bold(snapshot.ai.providerLabel)}`);
12846
+ info(`AI provider: ${import_picocolors11.default.bold(snapshot.ai.providerLabel)}`);
12735
12847
  if (snapshot.ai.model) {
12736
- info(`AI model: ${import_picocolors10.default.bold(snapshot.ai.model)}`);
12848
+ info(`AI model: ${import_picocolors11.default.bold(snapshot.ai.model)}`);
12737
12849
  }
12738
12850
  if (snapshot.ai.provider === "ollama-cloud") {
12739
- info(`Ollama Cloud API key: ${import_picocolors10.default.bold(snapshot.ai.ollamaCloudApiKeyPresent ? "stored" : "missing")}`);
12851
+ info(`Ollama Cloud API key: ${import_picocolors11.default.bold(snapshot.ai.ollamaCloudApiKeyPresent ? "stored" : "missing")}`);
12740
12852
  if (snapshot.ai.secretsPath) {
12741
- info(`Secrets path: ${import_picocolors10.default.bold(snapshot.ai.secretsPath)}`);
12853
+ info(`Secrets path: ${import_picocolors11.default.bold(snapshot.ai.secretsPath)}`);
12742
12854
  }
12743
12855
  }
12744
12856
  }
@@ -12771,12 +12883,12 @@ var config_default = defineCommand({
12771
12883
  }
12772
12884
  await projectHeading("config", "\u2699\uFE0F");
12773
12885
  if (!configExists()) {
12774
- error("No repo config found. Run `contrib setup` first.");
12886
+ error("No repo config found. Run `cn setup` first.");
12775
12887
  process.exit(1);
12776
12888
  }
12777
12889
  const config = readConfig();
12778
12890
  if (!config) {
12779
- error("Repo config exists but is invalid. Run `contrib setup` to repair it.");
12891
+ error("Repo config exists but is invalid. Run `cn setup` to repair it.");
12780
12892
  process.exit(1);
12781
12893
  }
12782
12894
  const source = getConfigSource();
@@ -12814,32 +12926,32 @@ var config_default = defineCommand({
12814
12926
  }
12815
12927
  printConfigSummary(snapshot);
12816
12928
  console.log();
12817
- console.log(` ${import_picocolors10.default.dim("Run `contrib config --edit` to update these settings.")}`);
12929
+ console.log(` ${import_picocolors11.default.dim("Run `cn config --edit` to update these settings.")}`);
12818
12930
  console.log();
12819
12931
  }
12820
12932
  });
12821
12933
 
12822
12934
  // src/commands/doctor.ts
12823
12935
  import { execFile as execFileCb3 } from "child_process";
12824
- var import_picocolors11 = __toESM(require_picocolors(), 1);
12936
+ var import_picocolors12 = __toESM(require_picocolors(), 1);
12825
12937
  // package.json
12826
12938
  var package_default = {
12827
12939
  name: "contribute-now",
12828
- version: "0.7.3",
12940
+ version: "0.7.4-dev.ac68df0",
12829
12941
  description: "Developer CLI that automates git workflows \u2014 branching, syncing, committing, and PRs \u2014 with multi-workflow and commit convention support.",
12830
12942
  type: "module",
12831
12943
  bin: {
12832
- contrib: "dist/index.js",
12833
- contribute: "dist/index.js",
12834
- cn: "dist/index.js"
12944
+ contrib: "dist/cli.js",
12945
+ contribute: "dist/cli.js",
12946
+ cn: "dist/cli.js"
12835
12947
  },
12836
12948
  files: [
12837
12949
  "dist"
12838
12950
  ],
12839
12951
  scripts: {
12840
- build: "bun build src/cli.ts --outfile dist/cli.js --target bun && bun build src/index.ts --outfile dist/index.js --target node --no-bundle",
12841
- cli: "bun run src/index.ts --",
12842
- dev: "bun src/index.ts",
12952
+ build: "bun build src/cli.ts --outfile dist/cli.js --target bun && bun run scripts/add-shebang.mjs",
12953
+ cli: "bun run src/cli.ts --",
12954
+ dev: "bun src/cli.ts",
12843
12955
  test: "bun test",
12844
12956
  lint: "biome check .",
12845
12957
  "lint:fix": "biome check --write .",
@@ -12874,13 +12986,11 @@ var package_default = {
12874
12986
  "@github/copilot-sdk": "^0.1.25",
12875
12987
  "@wgtechlabs/log-engine": "^2.3.1",
12876
12988
  citty: "^0.1.6",
12877
- figlet: "^1.10.0",
12878
12989
  picocolors: "^1.1.1"
12879
12990
  },
12880
12991
  devDependencies: {
12881
12992
  "@biomejs/biome": "^2.4.4",
12882
12993
  "@types/bun": "latest",
12883
- "@types/figlet": "^1.7.0",
12884
12994
  typescript: "^5.7.0"
12885
12995
  }
12886
12996
  };
@@ -12915,16 +13025,16 @@ async function getRepoInfoFromRemote(remote = "origin") {
12915
13025
  }
12916
13026
 
12917
13027
  // src/commands/doctor.ts
12918
- var PASS = ` ${import_picocolors11.default.green("\u2714")} `;
12919
- var FAIL = ` ${import_picocolors11.default.red("\u2717")} `;
12920
- var WARN = ` ${import_picocolors11.default.yellow("\u26A0")} `;
13028
+ var PASS = ` ${import_picocolors12.default.green("\u2714")} `;
13029
+ var FAIL = ` ${import_picocolors12.default.red("\u2717")} `;
13030
+ var WARN = ` ${import_picocolors12.default.yellow("\u26A0")} `;
12921
13031
  function printReport(report) {
12922
13032
  for (const section of report.sections) {
12923
13033
  console.log(`
12924
- ${import_picocolors11.default.bold(import_picocolors11.default.underline(section.title))}`);
13034
+ ${import_picocolors12.default.bold(import_picocolors12.default.underline(section.title))}`);
12925
13035
  for (const check of section.checks) {
12926
13036
  const prefix = check.ok ? check.warning ? WARN : PASS : FAIL;
12927
- const text = check.detail ? `${check.label} ${import_picocolors11.default.dim(`\u2014 ${check.detail}`)}` : check.label;
13037
+ const text = check.detail ? `${check.label} ${import_picocolors12.default.dim(`\u2014 ${check.detail}`)}` : check.label;
12928
13038
  console.log(`${prefix}${text}`);
12929
13039
  }
12930
13040
  }
@@ -12954,7 +13064,7 @@ function runCmd(cmd, args) {
12954
13064
  async function toolSection() {
12955
13065
  const checks = [];
12956
13066
  checks.push({
12957
- label: `contrib v${package_default.version ?? "unknown"}`,
13067
+ label: `cn v${package_default.version ?? "unknown"}`,
12958
13068
  ok: true
12959
13069
  });
12960
13070
  const runtime = typeof globalThis.Bun !== "undefined" ? `Bun ${globalThis.Bun.version ?? "?"}` : `Node ${process.version}`;
@@ -13009,7 +13119,7 @@ async function configSection() {
13009
13119
  checks.push({
13010
13120
  label: "Repo config not found",
13011
13121
  ok: false,
13012
- detail: "run `contrib setup` to create local config for this clone"
13122
+ detail: "run `cn setup` to create local config for this clone"
13013
13123
  });
13014
13124
  if (localStateLabel) {
13015
13125
  checks.push({
@@ -13077,7 +13187,7 @@ async function configSection() {
13077
13187
  label: hasApiKey ? "Ollama Cloud API key present" : "Ollama Cloud API key missing",
13078
13188
  ok: true,
13079
13189
  warning: !hasApiKey,
13080
- detail: hasSecretsStore() ? "stored in the local secrets store" : "run `contrib setup` to save it"
13190
+ detail: hasSecretsStore() ? "stored in the local secrets store" : "run `cn setup` to save it"
13081
13191
  });
13082
13192
  }
13083
13193
  }
@@ -13186,7 +13296,7 @@ async function workflowSection() {
13186
13296
  checks.push({
13187
13297
  label: "Cannot resolve workflow (no config)",
13188
13298
  ok: false,
13189
- detail: "run `contrib setup` first"
13299
+ detail: "run `cn setup` first"
13190
13300
  });
13191
13301
  return { title: "Workflow Resolution", checks };
13192
13302
  }
@@ -13256,14 +13366,14 @@ var doctor_default = defineCommand({
13256
13366
  const failures = total.filter((c3) => !c3.ok);
13257
13367
  const warnings = total.filter((c3) => c3.ok && c3.warning);
13258
13368
  if (failures.length === 0 && warnings.length === 0) {
13259
- console.log(` ${import_picocolors11.default.green("All checks passed!")} No issues detected.
13369
+ console.log(` ${import_picocolors12.default.green("All checks passed!")} No issues detected.
13260
13370
  `);
13261
13371
  } else {
13262
13372
  if (failures.length > 0) {
13263
- console.log(` ${import_picocolors11.default.red(`${failures.length} issue${failures.length !== 1 ? "s" : ""} found.`)}`);
13373
+ console.log(` ${import_picocolors12.default.red(`${failures.length} issue${failures.length !== 1 ? "s" : ""} found.`)}`);
13264
13374
  }
13265
13375
  if (warnings.length > 0) {
13266
- console.log(` ${import_picocolors11.default.yellow(`${warnings.length} warning${warnings.length !== 1 ? "s" : ""}.`)}`);
13376
+ console.log(` ${import_picocolors12.default.yellow(`${warnings.length} warning${warnings.length !== 1 ? "s" : ""}.`)}`);
13267
13377
  }
13268
13378
  console.log();
13269
13379
  }
@@ -13273,7 +13383,7 @@ var doctor_default = defineCommand({
13273
13383
  // src/commands/hook.ts
13274
13384
  import { existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync5, rmSync as rmSync2, writeFileSync as writeFileSync5 } from "fs";
13275
13385
  import { join as join6 } from "path";
13276
- var import_picocolors12 = __toESM(require_picocolors(), 1);
13386
+ var import_picocolors13 = __toESM(require_picocolors(), 1);
13277
13387
  var HOOK_MARKER = "# managed by contribute-now";
13278
13388
  function getHooksDir(cwd = process.cwd()) {
13279
13389
  return join6(cwd, ".git", "hooks");
@@ -13285,8 +13395,8 @@ function generateHookScript() {
13285
13395
  return `#!/bin/sh
13286
13396
  ${HOOK_MARKER}
13287
13397
  # Validates commit messages against your configured convention.
13288
- # Install: contrib hook install
13289
- # Uninstall: contrib hook uninstall
13398
+ # Install: cn hook install
13399
+ # Uninstall: cn hook uninstall
13290
13400
 
13291
13401
  commit_msg_file="$1"
13292
13402
  commit_msg=$(head -1 "$commit_msg_file")
@@ -13297,12 +13407,12 @@ case "$commit_msg" in
13297
13407
  esac
13298
13408
 
13299
13409
  # Detect available package runner
13300
- if command -v contrib >/dev/null 2>&1; then
13301
- contrib validate --file "$commit_msg_file"
13410
+ if command -v cn >/dev/null 2>&1; then
13411
+ cn validate --file "$commit_msg_file"
13302
13412
  elif command -v bunx >/dev/null 2>&1; then
13303
- bunx contrib validate --file "$commit_msg_file"
13413
+ bunx cn validate --file "$commit_msg_file"
13304
13414
  else
13305
- echo "Warning: Neither contrib nor bunx is available. Skipping commit message validation."
13415
+ echo "Warning: Neither cn nor bunx is available. Skipping commit message validation."
13306
13416
  exit 0
13307
13417
  fi
13308
13418
  `;
@@ -13340,12 +13450,12 @@ async function installHook() {
13340
13450
  await projectHeading("hook install", "\uD83E\uDE9D");
13341
13451
  const config = readConfig();
13342
13452
  if (!config) {
13343
- error("No repo config found. Run `contrib setup` first.");
13453
+ error("No repo config found. Run `cn setup` first.");
13344
13454
  process.exit(1);
13345
13455
  }
13346
13456
  if (config.commitConvention === "none") {
13347
13457
  warn('Commit convention is set to "none". No hook to install.');
13348
- info("Change your convention with `contrib setup` first.", "");
13458
+ info("Change your convention with `cn setup` first.", "");
13349
13459
  process.exit(0);
13350
13460
  }
13351
13461
  const hookPath = getHookPath();
@@ -13365,8 +13475,8 @@ async function installHook() {
13365
13475
  }
13366
13476
  writeFileSync5(hookPath, generateHookScript(), { mode: 493 });
13367
13477
  success(`commit-msg hook installed.`);
13368
- info(`Convention: ${import_picocolors12.default.bold(CONVENTION_LABELS[config.commitConvention])}`, "");
13369
- info(`Path: ${import_picocolors12.default.dim(hookPath)}`, "");
13478
+ info(`Convention: ${import_picocolors13.default.bold(CONVENTION_LABELS[config.commitConvention])}`, "");
13479
+ info(`Path: ${import_picocolors13.default.dim(hookPath)}`, "");
13370
13480
  warn("Note: hooks can be bypassed with `git commit --no-verify`.");
13371
13481
  }
13372
13482
  async function uninstallHook() {
@@ -13386,7 +13496,7 @@ async function uninstallHook() {
13386
13496
  }
13387
13497
 
13388
13498
  // src/commands/log.ts
13389
- var import_picocolors13 = __toESM(require_picocolors(), 1);
13499
+ var import_picocolors14 = __toESM(require_picocolors(), 1);
13390
13500
  function getDefaultOverviewRemoteCommitCount(hasLocalUnpushedCommits) {
13391
13501
  return hasLocalUnpushedCommits ? 10 : 20;
13392
13502
  }
@@ -13484,9 +13594,9 @@ var log_default = defineCommand({
13484
13594
  } else if (mode === "local") {
13485
13595
  if (!compareRef) {
13486
13596
  console.log();
13487
- console.log(import_picocolors13.default.yellow(" \u26A0 Could not determine a comparison branch."));
13488
- console.log(import_picocolors13.default.dim(" No upstream tracking set and no remote base branch found."));
13489
- console.log(import_picocolors13.default.dim(` Use ${import_picocolors13.default.bold("contrib log --full")} to see the full commit history instead.`));
13597
+ console.log(import_picocolors14.default.yellow(" \u26A0 Could not determine a comparison branch."));
13598
+ console.log(import_picocolors14.default.dim(" No upstream tracking set and no remote base branch found."));
13599
+ console.log(import_picocolors14.default.dim(` Use ${import_picocolors14.default.bold("cn log --full")} to see the full commit history instead.`));
13490
13600
  console.log();
13491
13601
  return;
13492
13602
  }
@@ -13505,8 +13615,8 @@ var log_default = defineCommand({
13505
13615
  const remoteBranch = compareRef ?? targetBranch;
13506
13616
  if (!remoteBranch) {
13507
13617
  console.log();
13508
- console.log(import_picocolors13.default.yellow(" \u26A0 Could not determine a remote branch to display."));
13509
- console.log(import_picocolors13.default.dim(" Set an upstream tracking branch or configure your base branch first."));
13618
+ console.log(import_picocolors14.default.yellow(" \u26A0 Could not determine a remote branch to display."));
13619
+ console.log(import_picocolors14.default.dim(" Set an upstream tracking branch or configure your base branch first."));
13510
13620
  console.log();
13511
13621
  return;
13512
13622
  }
@@ -13565,31 +13675,31 @@ async function getOverviewRemoteCommitCount(currentBranch, compareRef) {
13565
13675
  }
13566
13676
  function printModeHeader(mode, currentBranch, compareRef, usingFallback = false) {
13567
13677
  const branch = currentBranch ?? "HEAD";
13568
- const fallbackNote = usingFallback ? import_picocolors13.default.yellow(" (no upstream \u2014 comparing against base branch)") : "";
13678
+ const fallbackNote = usingFallback ? import_picocolors14.default.yellow(" (no upstream \u2014 comparing against base branch)") : "";
13569
13679
  switch (mode) {
13570
13680
  case "overview":
13571
- console.log(import_picocolors13.default.dim(` mode: ${import_picocolors13.default.bold("overview")} \u2014 local unpushed commits and remote branch history for ${import_picocolors13.default.bold(branch)}`) + fallbackNote);
13681
+ console.log(import_picocolors14.default.dim(` mode: ${import_picocolors14.default.bold("overview")} \u2014 local unpushed commits and remote branch history for ${import_picocolors14.default.bold(branch)}`) + fallbackNote);
13572
13682
  if (compareRef) {
13573
- console.log(import_picocolors13.default.dim(` remote source: ${import_picocolors13.default.bold(compareRef)}`));
13683
+ console.log(import_picocolors14.default.dim(` remote source: ${import_picocolors14.default.bold(compareRef)}`));
13574
13684
  }
13575
13685
  break;
13576
13686
  case "local":
13577
- console.log(import_picocolors13.default.dim(` mode: ${import_picocolors13.default.bold("local")} \u2014 unpushed commits on ${import_picocolors13.default.bold(branch)}`) + fallbackNote);
13687
+ console.log(import_picocolors14.default.dim(` mode: ${import_picocolors14.default.bold("local")} \u2014 unpushed commits on ${import_picocolors14.default.bold(branch)}`) + fallbackNote);
13578
13688
  if (compareRef) {
13579
- console.log(import_picocolors13.default.dim(` comparing: ${import_picocolors13.default.bold(compareRef)} \u279C ${import_picocolors13.default.bold("HEAD")}`));
13689
+ console.log(import_picocolors14.default.dim(` comparing: ${import_picocolors14.default.bold(compareRef)} \u279C ${import_picocolors14.default.bold("HEAD")}`));
13580
13690
  }
13581
13691
  break;
13582
13692
  case "remote":
13583
- console.log(import_picocolors13.default.dim(` mode: ${import_picocolors13.default.bold("remote")} \u2014 remote branch history relevant to ${import_picocolors13.default.bold(branch)}`) + fallbackNote);
13693
+ console.log(import_picocolors14.default.dim(` mode: ${import_picocolors14.default.bold("remote")} \u2014 remote branch history relevant to ${import_picocolors14.default.bold(branch)}`) + fallbackNote);
13584
13694
  if (compareRef) {
13585
- console.log(import_picocolors13.default.dim(` branch: ${import_picocolors13.default.bold(compareRef)}`));
13695
+ console.log(import_picocolors14.default.dim(` branch: ${import_picocolors14.default.bold(compareRef)}`));
13586
13696
  }
13587
13697
  break;
13588
13698
  case "full":
13589
- console.log(import_picocolors13.default.dim(` mode: ${import_picocolors13.default.bold("full")} \u2014 complete commit history for ${import_picocolors13.default.bold(branch)}`));
13699
+ console.log(import_picocolors14.default.dim(` mode: ${import_picocolors14.default.bold("full")} \u2014 complete commit history for ${import_picocolors14.default.bold(branch)}`));
13590
13700
  break;
13591
13701
  case "all":
13592
- console.log(import_picocolors13.default.dim(` mode: ${import_picocolors13.default.bold("all")} \u2014 commits across all branches`));
13702
+ console.log(import_picocolors14.default.dim(` mode: ${import_picocolors14.default.bold("all")} \u2014 commits across all branches`));
13593
13703
  break;
13594
13704
  }
13595
13705
  }
@@ -13613,7 +13723,7 @@ async function renderScopedLog(options) {
13613
13723
  }
13614
13724
  console.log();
13615
13725
  for (const entry of entries) {
13616
- const hashStr = import_picocolors13.default.yellow(entry.hash);
13726
+ const hashStr = import_picocolors14.default.yellow(entry.hash);
13617
13727
  const refsStr = entry.refs ? ` ${colorizeRefs(entry.refs, protectedBranches, currentBranch)}` : "";
13618
13728
  const subjectStr = colorizeSubject(entry.subject);
13619
13729
  console.log(` ${hashStr}${refsStr} ${subjectStr}`);
@@ -13632,10 +13742,10 @@ async function renderOverviewLog(options) {
13632
13742
  usingFallback
13633
13743
  } = options;
13634
13744
  console.log();
13635
- console.log(import_picocolors13.default.bold(import_picocolors13.default.cyan(" Local Unpushed Commits")));
13745
+ console.log(import_picocolors14.default.bold(import_picocolors14.default.cyan(" Local Unpushed Commits")));
13636
13746
  if (!compareRef) {
13637
- console.log(import_picocolors13.default.dim(" No comparison branch detected for local commit status."));
13638
- console.log(import_picocolors13.default.dim(" Set an upstream tracking branch or run cn log --full to inspect the current branch history."));
13747
+ console.log(import_picocolors14.default.dim(" No comparison branch detected for local commit status."));
13748
+ console.log(import_picocolors14.default.dim(" Set an upstream tracking branch or run cn log --full to inspect the current branch history."));
13639
13749
  } else {
13640
13750
  await renderScopedLog({
13641
13751
  mode: "local",
@@ -13647,11 +13757,11 @@ async function renderOverviewLog(options) {
13647
13757
  });
13648
13758
  }
13649
13759
  console.log();
13650
- console.log(import_picocolors13.default.bold(import_picocolors13.default.cyan(" Remote Branch History")));
13760
+ console.log(import_picocolors14.default.bold(import_picocolors14.default.cyan(" Remote Branch History")));
13651
13761
  if (!compareRef) {
13652
- console.log(import_picocolors13.default.dim(" No remote branch detected."));
13762
+ console.log(import_picocolors14.default.dim(" No remote branch detected."));
13653
13763
  if (usingFallback) {
13654
- console.log(import_picocolors13.default.dim(" Configure your base branch or upstream tracking to enable the split view."));
13764
+ console.log(import_picocolors14.default.dim(" Configure your base branch or upstream tracking to enable the split view."));
13655
13765
  }
13656
13766
  return;
13657
13767
  }
@@ -13664,15 +13774,15 @@ async function renderOverviewLog(options) {
13664
13774
  currentBranch
13665
13775
  });
13666
13776
  if (!hasRemoteHistory) {
13667
- console.log(import_picocolors13.default.dim(" No remote history found for the selected branch."));
13777
+ console.log(import_picocolors14.default.dim(" No remote history found for the selected branch."));
13668
13778
  }
13669
13779
  }
13670
13780
  function printEmptyState(mode) {
13671
13781
  console.log();
13672
13782
  if (mode === "local") {
13673
- console.log(import_picocolors13.default.dim(" No local unpushed commits \u2014 you're up to date with remote!"));
13783
+ console.log(import_picocolors14.default.dim(" No local unpushed commits \u2014 you're up to date with remote!"));
13674
13784
  } else {
13675
- console.log(import_picocolors13.default.dim(" No remote-only commits \u2014 your local branch is up to date!"));
13785
+ console.log(import_picocolors14.default.dim(" No remote-only commits \u2014 your local branch is up to date!"));
13676
13786
  }
13677
13787
  console.log();
13678
13788
  }
@@ -13681,7 +13791,7 @@ async function renderFullLog(options) {
13681
13791
  if (showGraph) {
13682
13792
  const lines = await getLogGraph({ count, all, branch: targetBranch });
13683
13793
  if (lines.length === 0) {
13684
- console.log(import_picocolors13.default.dim(" No commits found."));
13794
+ console.log(import_picocolors14.default.dim(" No commits found."));
13685
13795
  console.log();
13686
13796
  return false;
13687
13797
  }
@@ -13692,13 +13802,13 @@ async function renderFullLog(options) {
13692
13802
  } else {
13693
13803
  const entries = await getLogEntries({ count, all, branch: targetBranch });
13694
13804
  if (entries.length === 0) {
13695
- console.log(import_picocolors13.default.dim(" No commits found."));
13805
+ console.log(import_picocolors14.default.dim(" No commits found."));
13696
13806
  console.log();
13697
13807
  return false;
13698
13808
  }
13699
13809
  console.log();
13700
13810
  for (const entry of entries) {
13701
- const hashStr = import_picocolors13.default.yellow(entry.hash);
13811
+ const hashStr = import_picocolors14.default.yellow(entry.hash);
13702
13812
  const refsStr = entry.refs ? ` ${colorizeRefs(entry.refs, protectedBranches, currentBranch)}` : "";
13703
13813
  const subjectStr = colorizeSubject(entry.subject);
13704
13814
  console.log(` ${hashStr}${refsStr} ${subjectStr}`);
@@ -13710,33 +13820,33 @@ function printFooter(mode, count, overviewRemoteCount, targetBranch) {
13710
13820
  console.log();
13711
13821
  switch (mode) {
13712
13822
  case "overview":
13713
- console.log(import_picocolors13.default.dim(` Showing up to ${count} local commits and ${overviewRemoteCount} remote commits`));
13823
+ console.log(import_picocolors14.default.dim(` Showing up to ${count} local commits and ${overviewRemoteCount} remote commits`));
13714
13824
  break;
13715
13825
  case "local":
13716
- console.log(import_picocolors13.default.dim(` Showing up to ${count} unpushed commits`));
13826
+ console.log(import_picocolors14.default.dim(` Showing up to ${count} unpushed commits`));
13717
13827
  break;
13718
13828
  case "remote":
13719
- console.log(import_picocolors13.default.dim(` Showing ${count} most recent commits from the remote branch`));
13829
+ console.log(import_picocolors14.default.dim(` Showing ${count} most recent commits from the remote branch`));
13720
13830
  break;
13721
13831
  case "full":
13722
- console.log(import_picocolors13.default.dim(` Showing ${count} most recent commits${targetBranch ? ` (${targetBranch})` : ""}`));
13832
+ console.log(import_picocolors14.default.dim(` Showing ${count} most recent commits${targetBranch ? ` (${targetBranch})` : ""}`));
13723
13833
  break;
13724
13834
  case "all":
13725
- console.log(import_picocolors13.default.dim(` Showing ${count} most recent commits (all branches)`));
13835
+ console.log(import_picocolors14.default.dim(` Showing ${count} most recent commits (all branches)`));
13726
13836
  break;
13727
13837
  }
13728
13838
  }
13729
13839
  function colorizeGraphLine(line, protectedBranches, currentBranch) {
13730
13840
  const match = line.match(/^([|/\\*\s_.-]*)([a-f0-9]{7,12})(\s+\(([^)]+)\))?\s*(.*)/);
13731
13841
  if (!match) {
13732
- return import_picocolors13.default.cyan(line);
13842
+ return import_picocolors14.default.cyan(line);
13733
13843
  }
13734
13844
  const [, graphPart = "", hash, , refs, subject = ""] = match;
13735
13845
  const parts = [];
13736
13846
  if (graphPart) {
13737
13847
  parts.push(colorizeGraphChars(graphPart));
13738
13848
  }
13739
- parts.push(import_picocolors13.default.yellow(hash));
13849
+ parts.push(import_picocolors14.default.yellow(hash));
13740
13850
  if (refs) {
13741
13851
  parts.push(` (${colorizeRefs(refs, protectedBranches, currentBranch)})`);
13742
13852
  }
@@ -13747,15 +13857,15 @@ function colorizeGraphChars(graphPart) {
13747
13857
  return graphPart.split("").map((ch) => {
13748
13858
  switch (ch) {
13749
13859
  case "*":
13750
- return import_picocolors13.default.green(ch);
13860
+ return import_picocolors14.default.green(ch);
13751
13861
  case "|":
13752
- return import_picocolors13.default.cyan(ch);
13862
+ return import_picocolors14.default.cyan(ch);
13753
13863
  case "/":
13754
13864
  case "\\":
13755
- return import_picocolors13.default.cyan(ch);
13865
+ return import_picocolors14.default.cyan(ch);
13756
13866
  case "-":
13757
13867
  case "_":
13758
- return import_picocolors13.default.cyan(ch);
13868
+ return import_picocolors14.default.cyan(ch);
13759
13869
  default:
13760
13870
  return ch;
13761
13871
  }
@@ -13767,46 +13877,46 @@ function colorizeRefs(refs, protectedBranches, currentBranch) {
13767
13877
  if (trimmed.startsWith("HEAD ->") || trimmed === "HEAD") {
13768
13878
  const branchName = trimmed.replace("HEAD -> ", "");
13769
13879
  if (trimmed === "HEAD") {
13770
- return import_picocolors13.default.bold(import_picocolors13.default.cyan("HEAD"));
13880
+ return import_picocolors14.default.bold(import_picocolors14.default.cyan("HEAD"));
13771
13881
  }
13772
- return `${import_picocolors13.default.bold(import_picocolors13.default.cyan("HEAD"))} ${import_picocolors13.default.dim("->")} ${colorizeRefName(branchName, protectedBranches, currentBranch)}`;
13882
+ return `${import_picocolors14.default.bold(import_picocolors14.default.cyan("HEAD"))} ${import_picocolors14.default.dim("->")} ${colorizeRefName(branchName, protectedBranches, currentBranch)}`;
13773
13883
  }
13774
13884
  if (trimmed.startsWith("tag:")) {
13775
- return import_picocolors13.default.bold(import_picocolors13.default.magenta(trimmed));
13885
+ return import_picocolors14.default.bold(import_picocolors14.default.magenta(trimmed));
13776
13886
  }
13777
13887
  return colorizeRefName(trimmed, protectedBranches, currentBranch);
13778
- }).join(import_picocolors13.default.dim(", "));
13888
+ }).join(import_picocolors14.default.dim(", "));
13779
13889
  }
13780
13890
  function colorizeRefName(name, protectedBranches, currentBranch) {
13781
13891
  const isRemote = name.includes("/");
13782
13892
  const localName = isRemote ? name.split("/").slice(1).join("/") : name;
13783
13893
  if (protectedBranches.includes(localName)) {
13784
- return isRemote ? import_picocolors13.default.bold(import_picocolors13.default.red(name)) : import_picocolors13.default.bold(import_picocolors13.default.red(name));
13894
+ return isRemote ? import_picocolors14.default.bold(import_picocolors14.default.red(name)) : import_picocolors14.default.bold(import_picocolors14.default.red(name));
13785
13895
  }
13786
13896
  if (localName === currentBranch) {
13787
- return import_picocolors13.default.bold(import_picocolors13.default.green(name));
13897
+ return import_picocolors14.default.bold(import_picocolors14.default.green(name));
13788
13898
  }
13789
13899
  if (isRemote) {
13790
- return import_picocolors13.default.blue(name);
13900
+ return import_picocolors14.default.blue(name);
13791
13901
  }
13792
- return import_picocolors13.default.green(name);
13902
+ return import_picocolors14.default.green(name);
13793
13903
  }
13794
13904
  function colorizeSubject(subject) {
13795
13905
  const emojiMatch = subject.match(/^((?:\p{Emoji_Presentation}|\p{Emoji}\uFE0F)+\s*)/u);
13796
13906
  if (emojiMatch) {
13797
13907
  const emoji = emojiMatch[1];
13798
13908
  const rest = subject.slice(emoji.length);
13799
- return `${emoji}${import_picocolors13.default.white(rest)}`;
13909
+ return `${emoji}${import_picocolors14.default.white(rest)}`;
13800
13910
  }
13801
13911
  if (subject.startsWith("Merge ")) {
13802
- return import_picocolors13.default.dim(subject);
13912
+ return import_picocolors14.default.dim(subject);
13803
13913
  }
13804
- return import_picocolors13.default.white(subject);
13914
+ return import_picocolors14.default.white(subject);
13805
13915
  }
13806
13916
 
13807
13917
  // src/commands/save.ts
13808
13918
  import { execFile as execFileCb4 } from "child_process";
13809
- var import_picocolors14 = __toESM(require_picocolors(), 1);
13919
+ var import_picocolors15 = __toESM(require_picocolors(), 1);
13810
13920
  function gitRun(args) {
13811
13921
  return new Promise((resolve5) => {
13812
13922
  execFileCb4("git", args, (err, stdout2, stderr) => {
@@ -13880,8 +13990,8 @@ async function handleSave(message) {
13880
13990
  info("No uncommitted changes to save.");
13881
13991
  return;
13882
13992
  }
13883
- success(`Saved: ${import_picocolors14.default.dim(label)}`);
13884
- info(`Use ${import_picocolors14.default.bold("contrib save --restore")} to bring them back.`, "");
13993
+ success(`Saved: ${import_picocolors15.default.dim(label)}`);
13994
+ info(`Use ${import_picocolors15.default.bold("cn save --restore")} to bring them back.`, "");
13885
13995
  }
13886
13996
  async function handleRestore() {
13887
13997
  await projectHeading("save --restore", "\uD83D\uDCBE");
@@ -13897,7 +14007,7 @@ async function handleRestore() {
13897
14007
  warn("You may have conflicts. Resolve them and run `git stash drop` when done.");
13898
14008
  process.exit(1);
13899
14009
  }
13900
- success(`Restored: ${import_picocolors14.default.dim(stashes[0].message)}`);
14010
+ success(`Restored: ${import_picocolors15.default.dim(stashes[0].message)}`);
13901
14011
  return;
13902
14012
  }
13903
14013
  const choices = stashes.map((s2) => `${s2.index} ${s2.message}`);
@@ -13910,7 +14020,7 @@ async function handleRestore() {
13910
14020
  process.exit(1);
13911
14021
  }
13912
14022
  const match = stashes.find((s2) => String(s2.index) === idx);
13913
- success(`Restored: ${import_picocolors14.default.dim(match?.message ?? "saved changes")}`);
14023
+ success(`Restored: ${import_picocolors15.default.dim(match?.message ?? "saved changes")}`);
13914
14024
  }
13915
14025
  async function handleList() {
13916
14026
  await projectHeading("save --list", "\uD83D\uDCBE");
@@ -13921,13 +14031,13 @@ async function handleList() {
13921
14031
  }
13922
14032
  console.log();
13923
14033
  for (const s2 of stashes) {
13924
- const idx = import_picocolors14.default.dim(`[${s2.index}]`);
14034
+ const idx = import_picocolors15.default.dim(`[${s2.index}]`);
13925
14035
  const msg = s2.message;
13926
14036
  console.log(` ${idx} ${msg}`);
13927
14037
  }
13928
14038
  console.log();
13929
- info(`Use ${import_picocolors14.default.bold("contrib save --restore")} to bring changes back.`, "");
13930
- info(`Use ${import_picocolors14.default.bold("contrib save --drop")} to discard saved changes.`, "");
14039
+ info(`Use ${import_picocolors15.default.bold("cn save --restore")} to bring changes back.`, "");
14040
+ info(`Use ${import_picocolors15.default.bold("cn save --drop")} to discard saved changes.`, "");
13931
14041
  }
13932
14042
  async function handleDrop() {
13933
14043
  await projectHeading("save --drop", "\uD83D\uDCBE");
@@ -13945,7 +14055,7 @@ async function handleDrop() {
13945
14055
  process.exit(1);
13946
14056
  }
13947
14057
  const match = stashes.find((s2) => String(s2.index) === idx);
13948
- success(`Dropped: ${import_picocolors14.default.dim(match?.message ?? "saved changes")}`);
14058
+ success(`Dropped: ${import_picocolors15.default.dim(match?.message ?? "saved changes")}`);
13949
14059
  }
13950
14060
  async function getStashList() {
13951
14061
  const result = await gitRun(["stash", "list"]);
@@ -13962,7 +14072,7 @@ async function getStashList() {
13962
14072
  }
13963
14073
 
13964
14074
  // src/commands/setup.ts
13965
- var import_picocolors15 = __toESM(require_picocolors(), 1);
14075
+ var import_picocolors16 = __toESM(require_picocolors(), 1);
13966
14076
  async function shouldContinueSetupWithExistingConfig(options) {
13967
14077
  const { existingConfig, hasConfigFile, confirm, onInfo, onWarn, onSuccess, summary } = options;
13968
14078
  if (existingConfig) {
@@ -14045,7 +14155,7 @@ var setup_default = defineCommand({
14045
14155
  workflow = "github-flow";
14046
14156
  else if (workflowChoice.startsWith("Git Flow"))
14047
14157
  workflow = "git-flow";
14048
- info(`Workflow: ${import_picocolors15.default.bold(WORKFLOW_DESCRIPTIONS[workflow])}`);
14158
+ info(`Workflow: ${import_picocolors16.default.bold(WORKFLOW_DESCRIPTIONS[workflow])}`);
14049
14159
  const conventionChoice = await selectPrompt("Which commit convention should this project use?", [
14050
14160
  `${CONVENTION_DESCRIPTIONS["clean-commit"]} (recommended)`,
14051
14161
  CONVENTION_DESCRIPTIONS.conventional,
@@ -14075,7 +14185,7 @@ var setup_default = defineCommand({
14075
14185
  try {
14076
14186
  await setOllamaCloudApiKey(apiKey);
14077
14187
  success("Stored Ollama Cloud API key in the local secrets store.");
14078
- info(`Secrets path: ${import_picocolors15.default.bold(getSecretsStorePath())}`);
14188
+ info(`Secrets path: ${import_picocolors16.default.bold(getSecretsStorePath())}`);
14079
14189
  } catch (err) {
14080
14190
  const message = err instanceof Error ? err.message : String(err);
14081
14191
  error(`Failed to store Ollama Cloud API key: ${message}`);
@@ -14137,15 +14247,15 @@ var setup_default = defineCommand({
14137
14247
  detectedRole = roleChoice;
14138
14248
  detectionSource = "user selection";
14139
14249
  } else {
14140
- info(`Detected role: ${import_picocolors15.default.bold(detectedRole)} (via ${detectionSource})`);
14141
- const confirmed = await confirmPrompt(`Role detected as ${import_picocolors15.default.bold(detectedRole)}. Is this correct?`);
14250
+ info(`Detected role: ${import_picocolors16.default.bold(detectedRole)} (via ${detectionSource})`);
14251
+ const confirmed = await confirmPrompt(`Role detected as ${import_picocolors16.default.bold(detectedRole)}. Is this correct?`);
14142
14252
  if (!confirmed) {
14143
14253
  const roleChoice = await selectPrompt("Select your role:", ["maintainer", "contributor"]);
14144
14254
  detectedRole = roleChoice;
14145
14255
  }
14146
14256
  }
14147
14257
  const defaultConfig = getDefaultConfig();
14148
- info(import_picocolors15.default.dim("Tip: press Enter to keep the default branch name shown in each prompt."));
14258
+ info(import_picocolors16.default.dim("Tip: press Enter to keep the default branch name shown in each prompt."));
14149
14259
  const mainBranchDefault = defaultConfig.mainBranch;
14150
14260
  const mainBranch = await inputPrompt(`Main branch name (default: ${mainBranchDefault} \u2014 press Enter to keep)`, mainBranchDefault);
14151
14261
  let devBranch;
@@ -14171,7 +14281,7 @@ var setup_default = defineCommand({
14171
14281
  error("Setup cannot continue without the upstream remote for contributors.");
14172
14282
  process.exit(1);
14173
14283
  }
14174
- success(`Added remote ${import_picocolors15.default.bold(upstreamRemote)} \u2192 ${upstreamUrl}`);
14284
+ success(`Added remote ${import_picocolors16.default.bold(upstreamRemote)} \u2192 ${upstreamUrl}`);
14175
14285
  } else {
14176
14286
  error("An upstream remote URL is required for contributors.");
14177
14287
  info("Add it manually: git remote add upstream <url>", "");
@@ -14194,67 +14304,67 @@ var setup_default = defineCommand({
14194
14304
  showTips
14195
14305
  };
14196
14306
  writeConfig(config);
14197
- success(`Config written to ${import_picocolors15.default.bold(getConfigLocationLabel())}`);
14307
+ success(`Config written to ${import_picocolors16.default.bold(getConfigLocationLabel())}`);
14198
14308
  info("This setup is stored locally for this clone and does not modify tracked files.", "");
14199
14309
  const syncRemote = config.role === "contributor" ? config.upstream : config.origin;
14200
- info(`Fetching ${import_picocolors15.default.bold(syncRemote)} to verify branch configuration...`, "");
14310
+ info(`Fetching ${import_picocolors16.default.bold(syncRemote)} to verify branch configuration...`, "");
14201
14311
  await fetchRemote(syncRemote);
14202
14312
  const mainRef = `${syncRemote}/${config.mainBranch}`;
14203
14313
  if (!await refExists(mainRef)) {
14204
- warn(`Main branch ref ${import_picocolors15.default.bold(mainRef)} not found on remote.`);
14314
+ warn(`Main branch ref ${import_picocolors16.default.bold(mainRef)} not found on remote.`);
14205
14315
  warn("Config was saved \u2014 verify the branch name and re-run setup if needed.");
14206
14316
  }
14207
14317
  if (config.devBranch) {
14208
14318
  const devRef = `${syncRemote}/${config.devBranch}`;
14209
14319
  if (!await refExists(devRef)) {
14210
- warn(`Dev branch ref ${import_picocolors15.default.bold(devRef)} not found on remote.`);
14320
+ warn(`Dev branch ref ${import_picocolors16.default.bold(devRef)} not found on remote.`);
14211
14321
  warn("Config was saved \u2014 verify the branch name and re-run setup if needed.");
14212
14322
  }
14213
14323
  }
14214
14324
  console.log();
14215
14325
  const resolvedAIConfig = resolveAIConfig(config);
14216
- info(`Workflow: ${import_picocolors15.default.bold(WORKFLOW_DESCRIPTIONS[config.workflow])}`);
14217
- info(`Convention: ${import_picocolors15.default.bold(CONVENTION_DESCRIPTIONS[config.commitConvention])}`);
14218
- info(`AI: ${import_picocolors15.default.bold(isAIEnabled(config) ? "enabled" : "disabled")}`);
14326
+ info(`Workflow: ${import_picocolors16.default.bold(WORKFLOW_DESCRIPTIONS[config.workflow])}`);
14327
+ info(`Convention: ${import_picocolors16.default.bold(CONVENTION_DESCRIPTIONS[config.commitConvention])}`);
14328
+ info(`AI: ${import_picocolors16.default.bold(isAIEnabled(config) ? "enabled" : "disabled")}`);
14219
14329
  if (isAIEnabled(config)) {
14220
- info(`AI provider: ${import_picocolors15.default.bold(resolvedAIConfig.providerLabel)}`);
14330
+ info(`AI provider: ${import_picocolors16.default.bold(resolvedAIConfig.providerLabel)}`);
14221
14331
  if (resolvedAIConfig.model) {
14222
- info(`AI model: ${import_picocolors15.default.bold(resolvedAIConfig.model)}`);
14332
+ info(`AI model: ${import_picocolors16.default.bold(resolvedAIConfig.model)}`);
14223
14333
  }
14224
14334
  }
14225
- info(`Guides: ${import_picocolors15.default.bold(shouldShowTips(config) ? "shown" : "hidden")}`);
14226
- info(`Role: ${import_picocolors15.default.bold(config.role)}`);
14335
+ info(`Guides: ${import_picocolors16.default.bold(shouldShowTips(config) ? "shown" : "hidden")}`);
14336
+ info(`Role: ${import_picocolors16.default.bold(config.role)}`);
14227
14337
  if (config.devBranch) {
14228
- info(`Main: ${import_picocolors15.default.bold(config.mainBranch)} | Dev: ${import_picocolors15.default.bold(config.devBranch)}`);
14338
+ info(`Main: ${import_picocolors16.default.bold(config.mainBranch)} | Dev: ${import_picocolors16.default.bold(config.devBranch)}`);
14229
14339
  } else {
14230
- info(`Main: ${import_picocolors15.default.bold(config.mainBranch)}`);
14340
+ info(`Main: ${import_picocolors16.default.bold(config.mainBranch)}`);
14231
14341
  }
14232
- info(`Origin: ${import_picocolors15.default.bold(config.origin)}${config.role === "contributor" ? ` | Upstream: ${import_picocolors15.default.bold(config.upstream)}` : ""}`);
14342
+ info(`Origin: ${import_picocolors16.default.bold(config.origin)}${config.role === "contributor" ? ` | Upstream: ${import_picocolors16.default.bold(config.upstream)}` : ""}`);
14233
14343
  }
14234
14344
  });
14235
14345
  function logConfigSummary(config) {
14236
14346
  const aiConfig = resolveAIConfig(config);
14237
- info(`Workflow: ${import_picocolors15.default.bold(WORKFLOW_DESCRIPTIONS[config.workflow])}`);
14238
- info(`Convention: ${import_picocolors15.default.bold(CONVENTION_DESCRIPTIONS[config.commitConvention])}`);
14239
- info(`AI: ${import_picocolors15.default.bold(isAIEnabled(config) ? "enabled" : "disabled")}`);
14347
+ info(`Workflow: ${import_picocolors16.default.bold(WORKFLOW_DESCRIPTIONS[config.workflow])}`);
14348
+ info(`Convention: ${import_picocolors16.default.bold(CONVENTION_DESCRIPTIONS[config.commitConvention])}`);
14349
+ info(`AI: ${import_picocolors16.default.bold(isAIEnabled(config) ? "enabled" : "disabled")}`);
14240
14350
  if (isAIEnabled(config)) {
14241
- info(`AI provider: ${import_picocolors15.default.bold(aiConfig.providerLabel)}`);
14351
+ info(`AI provider: ${import_picocolors16.default.bold(aiConfig.providerLabel)}`);
14242
14352
  if (aiConfig.model) {
14243
- info(`AI model: ${import_picocolors15.default.bold(aiConfig.model)}`);
14353
+ info(`AI model: ${import_picocolors16.default.bold(aiConfig.model)}`);
14244
14354
  }
14245
14355
  }
14246
- info(`Guides: ${import_picocolors15.default.bold(shouldShowTips(config) ? "shown" : "hidden")}`);
14247
- info(`Role: ${import_picocolors15.default.bold(config.role)}`);
14356
+ info(`Guides: ${import_picocolors16.default.bold(shouldShowTips(config) ? "shown" : "hidden")}`);
14357
+ info(`Role: ${import_picocolors16.default.bold(config.role)}`);
14248
14358
  if (config.devBranch) {
14249
- info(`Main: ${import_picocolors15.default.bold(config.mainBranch)} | Dev: ${import_picocolors15.default.bold(config.devBranch)}`);
14359
+ info(`Main: ${import_picocolors16.default.bold(config.mainBranch)} | Dev: ${import_picocolors16.default.bold(config.devBranch)}`);
14250
14360
  } else {
14251
- info(`Main: ${import_picocolors15.default.bold(config.mainBranch)}`);
14361
+ info(`Main: ${import_picocolors16.default.bold(config.mainBranch)}`);
14252
14362
  }
14253
- info(`Origin: ${import_picocolors15.default.bold(config.origin)}${config.role === "contributor" ? ` | Upstream: ${import_picocolors15.default.bold(config.upstream)}` : ""}`);
14363
+ info(`Origin: ${import_picocolors16.default.bold(config.origin)}${config.role === "contributor" ? ` | Upstream: ${import_picocolors16.default.bold(config.upstream)}` : ""}`);
14254
14364
  }
14255
14365
 
14256
14366
  // src/commands/start.ts
14257
- var import_picocolors16 = __toESM(require_picocolors(), 1);
14367
+ var import_picocolors17 = __toESM(require_picocolors(), 1);
14258
14368
  var start_default = defineCommand({
14259
14369
  meta: {
14260
14370
  name: "start",
@@ -14284,7 +14394,7 @@ var start_default = defineCommand({
14284
14394
  await assertCleanGitState("starting a new branch");
14285
14395
  const config = readConfig();
14286
14396
  if (!config) {
14287
- error("No repo config found. Run `contrib setup` first.");
14397
+ error("No repo config found. Run `cn setup` first.");
14288
14398
  process.exit(1);
14289
14399
  }
14290
14400
  if (await hasUncommittedChanges()) {
@@ -14306,16 +14416,16 @@ var start_default = defineCommand({
14306
14416
  warn("Start cancelled.");
14307
14417
  process.exit(0);
14308
14418
  }
14309
- info(`Creating branch: ${import_picocolors16.default.bold(branchName)}`);
14419
+ info(`Creating branch: ${import_picocolors17.default.bold(branchName)}`);
14310
14420
  await fetchRemote(syncSource.remote);
14311
14421
  if (!await refExists(syncSource.ref)) {
14312
- warn(`Remote ref ${import_picocolors16.default.bold(syncSource.ref)} not found. Creating branch from local ${import_picocolors16.default.bold(baseBranch)}.`);
14422
+ warn(`Remote ref ${import_picocolors17.default.bold(syncSource.ref)} not found. Creating branch from local ${import_picocolors17.default.bold(baseBranch)}.`);
14313
14423
  }
14314
14424
  const currentBranch = await getCurrentBranch();
14315
14425
  if (currentBranch === baseBranch && await refExists(syncSource.ref)) {
14316
14426
  const ahead = await countCommitsAhead(baseBranch, syncSource.ref);
14317
14427
  if (ahead > 0) {
14318
- warn(`You are on ${import_picocolors16.default.bold(baseBranch)} with ${import_picocolors16.default.bold(String(ahead))} local commit${ahead > 1 ? "s" : ""} not in ${import_picocolors16.default.bold(syncSource.ref)}.`);
14428
+ warn(`You are on ${import_picocolors17.default.bold(baseBranch)} with ${import_picocolors17.default.bold(String(ahead))} local commit${ahead > 1 ? "s" : ""} not in ${import_picocolors17.default.bold(syncSource.ref)}.`);
14319
14429
  info(" Syncing will discard those commits. Consider backing them up first (e.g. create a branch).");
14320
14430
  const proceed = await confirmPrompt("Discard local commits and sync to remote?");
14321
14431
  if (!proceed) {
@@ -14332,10 +14442,10 @@ var start_default = defineCommand({
14332
14442
  error(`Failed to create branch: ${result2.stderr}`);
14333
14443
  process.exit(1);
14334
14444
  }
14335
- success(`Created ${import_picocolors16.default.bold(branchName)} from ${import_picocolors16.default.bold(syncSource.ref)}`);
14445
+ success(`Created ${import_picocolors17.default.bold(branchName)} from ${import_picocolors17.default.bold(syncSource.ref)}`);
14336
14446
  return;
14337
14447
  }
14338
- error(`Failed to update ${import_picocolors16.default.bold(baseBranch)}: ${updateResult.stderr}`);
14448
+ error(`Failed to update ${import_picocolors17.default.bold(baseBranch)}: ${updateResult.stderr}`);
14339
14449
  info("Make sure your base branch exists locally or the remote ref is available.", "");
14340
14450
  process.exit(1);
14341
14451
  }
@@ -14344,12 +14454,12 @@ var start_default = defineCommand({
14344
14454
  error(`Failed to create branch: ${result.stderr}`);
14345
14455
  process.exit(1);
14346
14456
  }
14347
- success(`Created ${import_picocolors16.default.bold(branchName)} from latest ${import_picocolors16.default.bold(baseBranch)}`);
14457
+ success(`Created ${import_picocolors17.default.bold(branchName)} from latest ${import_picocolors17.default.bold(baseBranch)}`);
14348
14458
  }
14349
14459
  });
14350
14460
 
14351
14461
  // src/commands/status.ts
14352
- var import_picocolors17 = __toESM(require_picocolors(), 1);
14462
+ var import_picocolors18 = __toESM(require_picocolors(), 1);
14353
14463
  var status_default = defineCommand({
14354
14464
  meta: {
14355
14465
  name: "status",
@@ -14362,12 +14472,12 @@ var status_default = defineCommand({
14362
14472
  }
14363
14473
  const config = readConfig();
14364
14474
  if (!config) {
14365
- error("No repo config found. Run `contrib setup` first.");
14475
+ error("No repo config found. Run `cn setup` first.");
14366
14476
  process.exit(1);
14367
14477
  }
14368
14478
  await projectHeading("status", "\uD83D\uDCCA");
14369
- console.log(` ${import_picocolors17.default.dim("Workflow:")} ${import_picocolors17.default.bold(WORKFLOW_DESCRIPTIONS[config.workflow])}`);
14370
- console.log(` ${import_picocolors17.default.dim("Role:")} ${import_picocolors17.default.bold(config.role)}`);
14479
+ console.log(` ${import_picocolors18.default.dim("Workflow:")} ${import_picocolors18.default.bold(WORKFLOW_DESCRIPTIONS[config.workflow])}`);
14480
+ console.log(` ${import_picocolors18.default.dim("Role:")} ${import_picocolors18.default.bold(config.role)}`);
14371
14481
  console.log();
14372
14482
  await fetchAll();
14373
14483
  const currentBranch = await getCurrentBranch();
@@ -14376,7 +14486,7 @@ var status_default = defineCommand({
14376
14486
  const isContributor = config.role === "contributor";
14377
14487
  const [dirty, fileStatus] = await Promise.all([hasUncommittedChanges(), getFileStatus()]);
14378
14488
  if (dirty) {
14379
- console.log(` ${import_picocolors17.default.yellow("\u26A0")} ${import_picocolors17.default.yellow("Uncommitted changes in working tree")}`);
14489
+ console.log(` ${import_picocolors18.default.yellow("\u26A0")} ${import_picocolors18.default.yellow("Uncommitted changes in working tree")}`);
14380
14490
  console.log();
14381
14491
  }
14382
14492
  const mainRemote = `${origin}/${mainBranch}`;
@@ -14395,16 +14505,16 @@ var status_default = defineCommand({
14395
14505
  if (isFeatureBranch) {
14396
14506
  const branchDiv = await getDivergence(currentBranch, baseBranch);
14397
14507
  const branchLine = formatStatus(currentBranch, baseBranch, branchDiv.ahead, branchDiv.behind);
14398
- console.log(branchLine + import_picocolors17.default.dim(` (current ${import_picocolors17.default.green("*")})`));
14508
+ console.log(branchLine + import_picocolors18.default.dim(` (current ${import_picocolors18.default.green("*")})`));
14399
14509
  branchStatus = await detectBranchStatus(currentBranch, baseBranch);
14400
14510
  if (branchStatus.merged) {
14401
- console.log(` ${import_picocolors17.default.green("\u2713")} ${import_picocolors17.default.green("Branch merged")} \u2014 ${import_picocolors17.default.dim(branchStatus.mergedReason ?? "all commits reachable from base")}`);
14511
+ console.log(` ${import_picocolors18.default.green("\u2713")} ${import_picocolors18.default.green("Branch merged")} \u2014 ${import_picocolors18.default.dim(branchStatus.mergedReason ?? "all commits reachable from base")}`);
14402
14512
  }
14403
14513
  if (branchStatus.stale) {
14404
- console.log(` ${import_picocolors17.default.yellow("\u23F3")} ${import_picocolors17.default.yellow("Branch is stale")} \u2014 ${import_picocolors17.default.dim(`last commit ${branchStatus.staleDaysAgo} days ago`)}`);
14514
+ console.log(` ${import_picocolors18.default.yellow("\u23F3")} ${import_picocolors18.default.yellow("Branch is stale")} \u2014 ${import_picocolors18.default.dim(`last commit ${branchStatus.staleDaysAgo} days ago`)}`);
14405
14515
  }
14406
14516
  } else if (currentBranch) {
14407
- console.log(import_picocolors17.default.dim(` (on ${import_picocolors17.default.bold(currentBranch)} branch)`));
14517
+ console.log(import_picocolors18.default.dim(` (on ${import_picocolors18.default.bold(currentBranch)} branch)`));
14408
14518
  }
14409
14519
  let branchesAligned = true;
14410
14520
  {
@@ -14441,20 +14551,20 @@ var status_default = defineCommand({
14441
14551
  }
14442
14552
  branchesAligned = groups.size === 1;
14443
14553
  console.log();
14444
- console.log(` ${import_picocolors17.default.bold("\uD83D\uDD17 Branch Alignment")}`);
14554
+ console.log(` ${import_picocolors18.default.bold("\uD83D\uDD17 Branch Alignment")}`);
14445
14555
  for (const [hash, names] of groups) {
14446
14556
  const short = hash.slice(0, 7);
14447
- const nameStr = names.map((n2) => import_picocolors17.default.bold(n2)).join(import_picocolors17.default.dim(" \xB7 "));
14448
- console.log(` ${import_picocolors17.default.yellow(short)} ${import_picocolors17.default.dim("\u2500\u2500")} ${nameStr}`);
14557
+ const nameStr = names.map((n2) => import_picocolors18.default.bold(n2)).join(import_picocolors18.default.dim(" \xB7 "));
14558
+ console.log(` ${import_picocolors18.default.yellow(short)} ${import_picocolors18.default.dim("\u2500\u2500")} ${nameStr}`);
14449
14559
  const subject = await getCommitSubject(hash);
14450
14560
  if (subject) {
14451
- console.log(` ${import_picocolors17.default.dim(subject)}`);
14561
+ console.log(` ${import_picocolors18.default.dim(subject)}`);
14452
14562
  }
14453
14563
  }
14454
14564
  if (branchesAligned) {
14455
- console.log(` ${import_picocolors17.default.green("\u2713")} ${import_picocolors17.default.green("All branches aligned")} ${import_picocolors17.default.dim("\u2014 ready to start")}`);
14565
+ console.log(` ${import_picocolors18.default.green("\u2713")} ${import_picocolors18.default.green("All branches aligned")} ${import_picocolors18.default.dim("\u2014 ready to start")}`);
14456
14566
  } else {
14457
- console.log(` ${import_picocolors17.default.yellow("\u26A0")} ${import_picocolors17.default.yellow("Branches are not fully aligned")}`);
14567
+ console.log(` ${import_picocolors18.default.yellow("\u26A0")} ${import_picocolors18.default.yellow("Branches are not fully aligned")}`);
14458
14568
  }
14459
14569
  }
14460
14570
  }
@@ -14462,41 +14572,41 @@ var status_default = defineCommand({
14462
14572
  if (hasFiles) {
14463
14573
  console.log();
14464
14574
  if (fileStatus.staged.length > 0) {
14465
- console.log(` ${import_picocolors17.default.green("Staged for commit:")}`);
14575
+ console.log(` ${import_picocolors18.default.green("Staged for commit:")}`);
14466
14576
  for (const { file, status } of fileStatus.staged) {
14467
- console.log(` ${import_picocolors17.default.green("+")} ${import_picocolors17.default.dim(`${status}:`)} ${file}`);
14577
+ console.log(` ${import_picocolors18.default.green("+")} ${import_picocolors18.default.dim(`${status}:`)} ${file}`);
14468
14578
  }
14469
14579
  }
14470
14580
  if (fileStatus.modified.length > 0) {
14471
- console.log(` ${import_picocolors17.default.yellow("Unstaged changes:")}`);
14581
+ console.log(` ${import_picocolors18.default.yellow("Unstaged changes:")}`);
14472
14582
  for (const { file, status } of fileStatus.modified) {
14473
- console.log(` ${import_picocolors17.default.yellow("~")} ${import_picocolors17.default.dim(`${status}:`)} ${file}`);
14583
+ console.log(` ${import_picocolors18.default.yellow("~")} ${import_picocolors18.default.dim(`${status}:`)} ${file}`);
14474
14584
  }
14475
14585
  }
14476
14586
  if (fileStatus.untracked.length > 0) {
14477
- console.log(` ${import_picocolors17.default.red("Untracked files:")}`);
14587
+ console.log(` ${import_picocolors18.default.red("Untracked files:")}`);
14478
14588
  for (const file of fileStatus.untracked) {
14479
- console.log(` ${import_picocolors17.default.red("?")} ${file}`);
14589
+ console.log(` ${import_picocolors18.default.red("?")} ${file}`);
14480
14590
  }
14481
14591
  }
14482
14592
  } else if (!dirty) {
14483
- console.log(` ${import_picocolors17.default.green("\u2713")} ${import_picocolors17.default.dim("Working tree clean")}`);
14593
+ console.log(` ${import_picocolors18.default.green("\u2713")} ${import_picocolors18.default.dim("Working tree clean")}`);
14484
14594
  }
14485
14595
  console.log();
14486
14596
  }
14487
14597
  });
14488
14598
  function formatStatus(branch, base, ahead, behind) {
14489
- const label = import_picocolors17.default.bold(branch.padEnd(20));
14599
+ const label = import_picocolors18.default.bold(branch.padEnd(20));
14490
14600
  if (ahead === 0 && behind === 0) {
14491
- return ` ${import_picocolors17.default.green("\u2713")} ${label} ${import_picocolors17.default.dim(`in sync with ${base}`)}`;
14601
+ return ` ${import_picocolors18.default.green("\u2713")} ${label} ${import_picocolors18.default.dim(`in sync with ${base}`)}`;
14492
14602
  }
14493
14603
  if (ahead > 0 && behind === 0) {
14494
- return ` ${import_picocolors17.default.yellow("\u2191")} ${label} ${import_picocolors17.default.yellow(`${ahead} commit${ahead !== 1 ? "s" : ""} ahead of ${base}`)}`;
14604
+ return ` ${import_picocolors18.default.yellow("\u2191")} ${label} ${import_picocolors18.default.yellow(`${ahead} commit${ahead !== 1 ? "s" : ""} ahead of ${base}`)}`;
14495
14605
  }
14496
14606
  if (behind > 0 && ahead === 0) {
14497
- return ` ${import_picocolors17.default.red("\u2193")} ${label} ${import_picocolors17.default.red(`${behind} commit${behind !== 1 ? "s" : ""} behind ${base}`)}`;
14607
+ return ` ${import_picocolors18.default.red("\u2193")} ${label} ${import_picocolors18.default.red(`${behind} commit${behind !== 1 ? "s" : ""} behind ${base}`)}`;
14498
14608
  }
14499
- return ` ${import_picocolors17.default.red("\u26A1")} ${label} ${import_picocolors17.default.yellow(`${ahead} ahead`)}${import_picocolors17.default.dim(", ")}${import_picocolors17.default.red(`${behind} behind`)} ${import_picocolors17.default.dim(base)}`;
14609
+ return ` ${import_picocolors18.default.red("\u26A1")} ${label} ${import_picocolors18.default.yellow(`${ahead} ahead`)}${import_picocolors18.default.dim(", ")}${import_picocolors18.default.red(`${behind} behind`)} ${import_picocolors18.default.dim(base)}`;
14500
14610
  }
14501
14611
  var STALE_THRESHOLD_DAYS = 14;
14502
14612
  async function detectBranchStatus(branch, baseBranch) {
@@ -14547,15 +14657,15 @@ async function detectBranchStatus(branch, baseBranch) {
14547
14657
  }
14548
14658
 
14549
14659
  // src/commands/submit.ts
14550
- var import_picocolors18 = __toESM(require_picocolors(), 1);
14660
+ var import_picocolors19 = __toESM(require_picocolors(), 1);
14551
14661
  async function performSquashMerge(origin, baseBranch, featureBranch, options) {
14552
- info(`Checking out ${import_picocolors18.default.bold(baseBranch)}...`);
14662
+ info(`Checking out ${import_picocolors19.default.bold(baseBranch)}...`);
14553
14663
  const coResult = await checkoutBranch(baseBranch);
14554
14664
  if (coResult.exitCode !== 0) {
14555
14665
  error(`Failed to checkout ${baseBranch}: ${coResult.stderr}`);
14556
14666
  process.exit(1);
14557
14667
  }
14558
- info(`Squash merging ${import_picocolors18.default.bold(featureBranch)} into ${import_picocolors18.default.bold(baseBranch)}...`);
14668
+ info(`Squash merging ${import_picocolors19.default.bold(featureBranch)} into ${import_picocolors19.default.bold(baseBranch)}...`);
14559
14669
  const mergeResult = await mergeSquash(featureBranch);
14560
14670
  if (mergeResult.exitCode !== 0) {
14561
14671
  error(`Squash merge failed: ${mergeResult.stderr}`);
@@ -14575,7 +14685,7 @@ async function performSquashMerge(origin, baseBranch, featureBranch, options) {
14575
14685
  message = aiMsg;
14576
14686
  spinner.success("AI commit message generated.");
14577
14687
  console.log(`
14578
- ${import_picocolors18.default.dim("AI suggestion:")} ${import_picocolors18.default.bold(import_picocolors18.default.cyan(message))}`);
14688
+ ${import_picocolors19.default.dim("AI suggestion:")} ${import_picocolors19.default.bold(import_picocolors19.default.cyan(message))}`);
14579
14689
  break;
14580
14690
  }
14581
14691
  spinner.fail("AI did not return a commit message.");
@@ -14615,7 +14725,7 @@ async function performSquashMerge(origin, baseBranch, featureBranch, options) {
14615
14725
  message = regen;
14616
14726
  spinner.success("Commit message regenerated.");
14617
14727
  console.log(`
14618
- ${import_picocolors18.default.dim("AI suggestion:")} ${import_picocolors18.default.bold(import_picocolors18.default.cyan(regen))}`);
14728
+ ${import_picocolors19.default.dim("AI suggestion:")} ${import_picocolors19.default.bold(import_picocolors19.default.cyan(regen))}`);
14619
14729
  } else {
14620
14730
  spinner.fail("Regeneration failed.");
14621
14731
  }
@@ -14631,13 +14741,13 @@ async function performSquashMerge(origin, baseBranch, featureBranch, options) {
14631
14741
  error(`Commit failed: ${commitResult.stderr}`);
14632
14742
  process.exit(1);
14633
14743
  }
14634
- info(`Pushing ${import_picocolors18.default.bold(baseBranch)} to ${origin}...`);
14744
+ info(`Pushing ${import_picocolors19.default.bold(baseBranch)} to ${origin}...`);
14635
14745
  const pushResult = await pushBranch(origin, baseBranch);
14636
14746
  if (pushResult.exitCode !== 0) {
14637
14747
  error(`Failed to push ${baseBranch}: ${pushResult.stderr}`);
14638
14748
  process.exit(1);
14639
14749
  }
14640
- info(`Deleting local branch ${import_picocolors18.default.bold(featureBranch)}...`);
14750
+ info(`Deleting local branch ${import_picocolors19.default.bold(featureBranch)}...`);
14641
14751
  const delLocal = await forceDeleteBranch(featureBranch);
14642
14752
  if (delLocal.exitCode !== 0) {
14643
14753
  warn(`Could not delete local branch: ${delLocal.stderr.trim()}`);
@@ -14645,14 +14755,14 @@ async function performSquashMerge(origin, baseBranch, featureBranch, options) {
14645
14755
  const remoteBranchRef = `${origin}/${featureBranch}`;
14646
14756
  const remoteExists = await branchExists(remoteBranchRef);
14647
14757
  if (remoteExists) {
14648
- info(`Deleting remote branch ${import_picocolors18.default.bold(featureBranch)}...`);
14758
+ info(`Deleting remote branch ${import_picocolors19.default.bold(featureBranch)}...`);
14649
14759
  const delRemote = await deleteRemoteBranch(origin, featureBranch);
14650
14760
  if (delRemote.exitCode !== 0) {
14651
14761
  warn(`Could not delete remote branch: ${delRemote.stderr.trim()}`);
14652
14762
  }
14653
14763
  }
14654
- success(`Squash merged ${import_picocolors18.default.bold(featureBranch)} into ${import_picocolors18.default.bold(baseBranch)} and pushed.`);
14655
- info(`Run ${import_picocolors18.default.bold("contrib start")} to begin a new feature.`, "");
14764
+ success(`Squash merged ${import_picocolors19.default.bold(featureBranch)} into ${import_picocolors19.default.bold(baseBranch)} and pushed.`);
14765
+ info(`Run ${import_picocolors19.default.bold("cn start")} to begin a new feature.`, "");
14656
14766
  }
14657
14767
  var submit_default = defineCommand({
14658
14768
  meta: {
@@ -14695,7 +14805,7 @@ var submit_default = defineCommand({
14695
14805
  await assertCleanGitState("submitting");
14696
14806
  const config = readConfig();
14697
14807
  if (!config) {
14698
- error("No repo config found. Run `contrib setup` first.");
14808
+ error("No repo config found. Run `cn setup` first.");
14699
14809
  process.exit(1);
14700
14810
  }
14701
14811
  const { origin } = config;
@@ -14709,7 +14819,7 @@ var submit_default = defineCommand({
14709
14819
  }
14710
14820
  if (protectedBranches.includes(currentBranch)) {
14711
14821
  await projectHeading("submit", "\uD83D\uDE80");
14712
- warn(`You're on ${import_picocolors18.default.bold(currentBranch)}, which is a protected branch. PRs should come from feature branches.`);
14822
+ warn(`You're on ${import_picocolors19.default.bold(currentBranch)}, which is a protected branch. PRs should come from feature branches.`);
14713
14823
  await fetchAll();
14714
14824
  const remoteRef = `${origin}/${currentBranch}`;
14715
14825
  const localWork = await hasLocalWork(origin, currentBranch);
@@ -14718,11 +14828,11 @@ var submit_default = defineCommand({
14718
14828
  const hasAnything = hasCommits || dirty;
14719
14829
  if (!hasAnything) {
14720
14830
  error("No local changes or commits to move. Switch to a feature branch first.");
14721
- info(` Run ${import_picocolors18.default.bold("contrib start")} to create a new feature branch.`, "");
14831
+ info(` Run ${import_picocolors19.default.bold("cn start")} to create a new feature branch.`, "");
14722
14832
  process.exit(1);
14723
14833
  }
14724
14834
  if (hasCommits) {
14725
- info(`Found ${import_picocolors18.default.bold(String(localWork.unpushedCommits))} unpushed commit${localWork.unpushedCommits !== 1 ? "s" : ""} on ${import_picocolors18.default.bold(currentBranch)}.`);
14835
+ info(`Found ${import_picocolors19.default.bold(String(localWork.unpushedCommits))} unpushed commit${localWork.unpushedCommits !== 1 ? "s" : ""} on ${import_picocolors19.default.bold(currentBranch)}.`);
14726
14836
  }
14727
14837
  if (dirty) {
14728
14838
  info("You also have uncommitted changes in the working tree.");
@@ -14752,12 +14862,12 @@ var submit_default = defineCommand({
14752
14862
  error(`Failed to create branch: ${branchResult.stderr}`);
14753
14863
  process.exit(1);
14754
14864
  }
14755
- success(`Created ${import_picocolors18.default.bold(newBranchName)} with your changes.`);
14865
+ success(`Created ${import_picocolors19.default.bold(newBranchName)} with your changes.`);
14756
14866
  await updateLocalBranch(currentBranch, remoteRef);
14757
- info(`Reset ${import_picocolors18.default.bold(currentBranch)} back to ${import_picocolors18.default.bold(remoteRef)} \u2014 no damage done.`, "");
14867
+ info(`Reset ${import_picocolors19.default.bold(currentBranch)} back to ${import_picocolors19.default.bold(remoteRef)} \u2014 no damage done.`, "");
14758
14868
  console.log();
14759
- success(`You're now on ${import_picocolors18.default.bold(newBranchName)} with all your work intact.`);
14760
- info(`Run ${import_picocolors18.default.bold("contrib submit")} again to push and create your PR.`, "");
14869
+ success(`You're now on ${import_picocolors19.default.bold(newBranchName)} with all your work intact.`);
14870
+ info(`Run ${import_picocolors19.default.bold("cn submit")} again to push and create your PR.`, "");
14761
14871
  return;
14762
14872
  }
14763
14873
  await projectHeading("submit", "\uD83D\uDE80");
@@ -14766,7 +14876,7 @@ var submit_default = defineCommand({
14766
14876
  if (ghInstalled && ghAuthed) {
14767
14877
  const mergedPR = await getMergedPRForBranch(currentBranch);
14768
14878
  if (mergedPR) {
14769
- warn(`PR #${mergedPR.number} (${import_picocolors18.default.bold(mergedPR.title)}) was already merged.`);
14879
+ warn(`PR #${mergedPR.number} (${import_picocolors19.default.bold(mergedPR.title)}) was already merged.`);
14770
14880
  const localWork = await hasLocalWork(origin, currentBranch);
14771
14881
  const hasWork = localWork.uncommitted || localWork.unpushedCommits > 0;
14772
14882
  if (hasWork) {
@@ -14774,7 +14884,7 @@ var submit_default = defineCommand({
14774
14884
  warn("You have uncommitted changes in your working tree.");
14775
14885
  }
14776
14886
  if (localWork.unpushedCommits > 0) {
14777
- warn(`You have ${import_picocolors18.default.bold(String(localWork.unpushedCommits))} local commit${localWork.unpushedCommits !== 1 ? "s" : ""} not in the merged PR.`);
14887
+ warn(`You have ${import_picocolors19.default.bold(String(localWork.unpushedCommits))} local commit${localWork.unpushedCommits !== 1 ? "s" : ""} not in the merged PR.`);
14778
14888
  }
14779
14889
  const SAVE_NEW_BRANCH = "Save changes to a new branch";
14780
14890
  const DISCARD = "Discard all changes and clean up";
@@ -14801,10 +14911,10 @@ var submit_default = defineCommand({
14801
14911
  error(`Failed to rename branch: ${renameResult.stderr}`);
14802
14912
  process.exit(1);
14803
14913
  }
14804
- success(`Renamed ${import_picocolors18.default.bold(currentBranch)} \u2192 ${import_picocolors18.default.bold(newBranchName)}`);
14914
+ success(`Renamed ${import_picocolors19.default.bold(currentBranch)} \u2192 ${import_picocolors19.default.bold(newBranchName)}`);
14805
14915
  await unsetUpstream();
14806
14916
  const syncSource2 = getSyncSource(config);
14807
- info(`Syncing ${import_picocolors18.default.bold(newBranchName)} with latest ${import_picocolors18.default.bold(baseBranch)}...`);
14917
+ info(`Syncing ${import_picocolors19.default.bold(newBranchName)} with latest ${import_picocolors19.default.bold(baseBranch)}...`);
14808
14918
  await fetchRemote(syncSource2.remote);
14809
14919
  let rebaseResult;
14810
14920
  if (staleUpstreamHash) {
@@ -14815,17 +14925,17 @@ var submit_default = defineCommand({
14815
14925
  }
14816
14926
  if (rebaseResult.exitCode !== 0) {
14817
14927
  warn("Rebase encountered conflicts. Resolve them manually, then run:");
14818
- info(` ${import_picocolors18.default.bold("git rebase --continue")}`, "");
14928
+ info(` ${import_picocolors19.default.bold("git rebase --continue")}`, "");
14819
14929
  } else {
14820
- success(`Rebased ${import_picocolors18.default.bold(newBranchName)} onto ${import_picocolors18.default.bold(syncSource2.ref)}.`);
14930
+ success(`Rebased ${import_picocolors19.default.bold(newBranchName)} onto ${import_picocolors19.default.bold(syncSource2.ref)}.`);
14821
14931
  }
14822
- info(`All your changes are preserved. Run ${import_picocolors18.default.bold("contrib submit")} when ready to create a new PR.`, "");
14932
+ info(`All your changes are preserved. Run ${import_picocolors19.default.bold("cn submit")} when ready to create a new PR.`, "");
14823
14933
  return;
14824
14934
  }
14825
14935
  warn("Discarding local changes...");
14826
14936
  }
14827
14937
  const syncSource = getSyncSource(config);
14828
- info(`Switching to ${import_picocolors18.default.bold(baseBranch)} and syncing...`);
14938
+ info(`Switching to ${import_picocolors19.default.bold(baseBranch)} and syncing...`);
14829
14939
  await fetchRemote(syncSource.remote);
14830
14940
  await resetHard("HEAD");
14831
14941
  const coResult = await checkoutBranch(baseBranch);
@@ -14834,35 +14944,35 @@ var submit_default = defineCommand({
14834
14944
  process.exit(1);
14835
14945
  }
14836
14946
  await updateLocalBranch(baseBranch, syncSource.ref);
14837
- success(`Synced ${import_picocolors18.default.bold(baseBranch)} with ${import_picocolors18.default.bold(syncSource.ref)}.`);
14838
- info(`Deleting stale branch ${import_picocolors18.default.bold(currentBranch)}...`);
14947
+ success(`Synced ${import_picocolors19.default.bold(baseBranch)} with ${import_picocolors19.default.bold(syncSource.ref)}.`);
14948
+ info(`Deleting stale branch ${import_picocolors19.default.bold(currentBranch)}...`);
14839
14949
  const delResult = await forceDeleteBranch(currentBranch);
14840
14950
  if (delResult.exitCode === 0) {
14841
- success(`Deleted ${import_picocolors18.default.bold(currentBranch)}.`);
14951
+ success(`Deleted ${import_picocolors19.default.bold(currentBranch)}.`);
14842
14952
  } else {
14843
14953
  warn(`Could not delete branch: ${delResult.stderr.trim()}`);
14844
14954
  }
14845
14955
  console.log();
14846
- info(`You're now on ${import_picocolors18.default.bold(baseBranch)}. Run ${import_picocolors18.default.bold("contrib start")} to begin a new feature.`);
14956
+ info(`You're now on ${import_picocolors19.default.bold(baseBranch)}. Run ${import_picocolors19.default.bold("cn start")} to begin a new feature.`);
14847
14957
  return;
14848
14958
  }
14849
14959
  }
14850
14960
  if (ghInstalled && ghAuthed) {
14851
14961
  const existingPR = await getPRForBranch(currentBranch);
14852
14962
  if (existingPR) {
14853
- info(`Pushing ${import_picocolors18.default.bold(currentBranch)} to ${origin}...`);
14963
+ info(`Pushing ${import_picocolors19.default.bold(currentBranch)} to ${origin}...`);
14854
14964
  const pushResult2 = await pushSetUpstream(origin, currentBranch);
14855
14965
  if (pushResult2.exitCode !== 0) {
14856
14966
  error(`Failed to push: ${pushResult2.stderr}`);
14857
14967
  if (pushResult2.stderr.includes("rejected") || pushResult2.stderr.includes("non-fast-forward")) {
14858
14968
  warn("The remote branch has diverged. Try:");
14859
14969
  info(` git pull --rebase ${origin} ${currentBranch}`, "");
14860
- info(" Then run `contrib submit` again.", "");
14970
+ info(" Then run `cn submit` again.", "");
14861
14971
  }
14862
14972
  process.exit(1);
14863
14973
  }
14864
- success(`Pushed changes to existing PR #${existingPR.number}: ${import_picocolors18.default.bold(existingPR.title)}`);
14865
- console.log(` ${import_picocolors18.default.cyan(existingPR.url)}`);
14974
+ success(`Pushed changes to existing PR #${existingPR.number}: ${import_picocolors19.default.bold(existingPR.title)}`);
14975
+ console.log(` ${import_picocolors19.default.cyan(existingPR.url)}`);
14866
14976
  return;
14867
14977
  }
14868
14978
  }
@@ -14884,10 +14994,10 @@ var submit_default = defineCommand({
14884
14994
  prBody = result.body;
14885
14995
  spinner.success("PR description generated.");
14886
14996
  console.log(`
14887
- ${import_picocolors18.default.dim("AI title:")} ${import_picocolors18.default.bold(import_picocolors18.default.cyan(prTitle))}`);
14997
+ ${import_picocolors19.default.dim("AI title:")} ${import_picocolors19.default.bold(import_picocolors19.default.cyan(prTitle))}`);
14888
14998
  console.log(`
14889
- ${import_picocolors18.default.dim("AI body preview:")}`);
14890
- console.log(import_picocolors18.default.dim(prBody.slice(0, 300) + (prBody.length > 300 ? "..." : "")));
14999
+ ${import_picocolors19.default.dim("AI body preview:")}`);
15000
+ console.log(import_picocolors19.default.dim(prBody.slice(0, 300) + (prBody.length > 300 ? "..." : "")));
14891
15001
  } else {
14892
15002
  spinner.fail("AI did not return a PR description.");
14893
15003
  }
@@ -14998,14 +15108,14 @@ ${import_picocolors18.default.dim("AI body preview:")}`);
14998
15108
  warn("Submit cancelled.");
14999
15109
  return;
15000
15110
  }
15001
- info(`Pushing ${import_picocolors18.default.bold(currentBranch)} to ${origin}...`);
15111
+ info(`Pushing ${import_picocolors19.default.bold(currentBranch)} to ${origin}...`);
15002
15112
  const pushResult = await pushSetUpstream(origin, currentBranch);
15003
15113
  if (pushResult.exitCode !== 0) {
15004
15114
  error(`Failed to push: ${pushResult.stderr}`);
15005
15115
  if (pushResult.stderr.includes("rejected") || pushResult.stderr.includes("non-fast-forward")) {
15006
15116
  warn("The remote branch has diverged. Try:");
15007
15117
  info(` git pull --rebase ${origin} ${currentBranch}`, "");
15008
- info(" Then run `contrib submit` again.", "");
15118
+ info(" Then run `cn submit` again.", "");
15009
15119
  info("If you need to force push (use with caution):", "");
15010
15120
  info(` git push --force-with-lease ${origin} ${currentBranch}`, "");
15011
15121
  }
@@ -15017,7 +15127,7 @@ ${import_picocolors18.default.dim("AI body preview:")}`);
15017
15127
  const prUrl = `https://github.com/${repoInfo.owner}/${repoInfo.repo}/compare/${baseBranch}...${currentBranch}?expand=1`;
15018
15128
  console.log();
15019
15129
  info("Create your PR manually:", "");
15020
- console.log(` ${import_picocolors18.default.cyan(prUrl)}`);
15130
+ console.log(` ${import_picocolors19.default.cyan(prUrl)}`);
15021
15131
  } else {
15022
15132
  info("gh CLI not available. Create your PR manually on GitHub.", "");
15023
15133
  }
@@ -15051,7 +15161,7 @@ ${import_picocolors18.default.dim("AI body preview:")}`);
15051
15161
  });
15052
15162
 
15053
15163
  // src/commands/switch.ts
15054
- var import_picocolors19 = __toESM(require_picocolors(), 1);
15164
+ var import_picocolors20 = __toESM(require_picocolors(), 1);
15055
15165
  var switch_default = defineCommand({
15056
15166
  meta: {
15057
15167
  name: "switch",
@@ -15083,11 +15193,11 @@ var switch_default = defineCommand({
15083
15193
  const choices = localBranches.filter((b2) => b2.name !== currentBranch).map((b2) => {
15084
15194
  const labels = [];
15085
15195
  if (protectedBranches.includes(b2.name))
15086
- labels.push(import_picocolors19.default.red("protected"));
15196
+ labels.push(import_picocolors20.default.red("protected"));
15087
15197
  if (b2.upstream)
15088
- labels.push(import_picocolors19.default.dim(`\u2192 ${b2.upstream}`));
15198
+ labels.push(import_picocolors20.default.dim(`\u2192 ${b2.upstream}`));
15089
15199
  if (b2.gone)
15090
- labels.push(import_picocolors19.default.red("remote gone"));
15200
+ labels.push(import_picocolors20.default.red("remote gone"));
15091
15201
  const suffix = labels.length > 0 ? ` ${labels.join(" \xB7 ")}` : "";
15092
15202
  return `${b2.name}${suffix}`;
15093
15203
  });
@@ -15099,7 +15209,7 @@ var switch_default = defineCommand({
15099
15209
  targetBranch = selected.split(/\s{2,}/)[0].trim();
15100
15210
  }
15101
15211
  if (targetBranch === currentBranch) {
15102
- info(`Already on ${import_picocolors19.default.bold(targetBranch)}.`);
15212
+ info(`Already on ${import_picocolors20.default.bold(targetBranch)}.`);
15103
15213
  return;
15104
15214
  }
15105
15215
  if (await hasUncommittedChanges()) {
@@ -15118,7 +15228,7 @@ var switch_default = defineCommand({
15118
15228
  const stashMsg = `contrib-save: auto-save from ${currentBranch}`;
15119
15229
  try {
15120
15230
  await exec("git", ["stash", "push", "-m", stashMsg]);
15121
- info(`Saved changes: ${import_picocolors19.default.dim(stashMsg)}`);
15231
+ info(`Saved changes: ${import_picocolors20.default.dim(stashMsg)}`);
15122
15232
  } catch {
15123
15233
  error("Failed to save changes. Please commit or save manually.");
15124
15234
  process.exit(1);
@@ -15130,13 +15240,13 @@ var switch_default = defineCommand({
15130
15240
  await exec("git", ["stash", "pop"]);
15131
15241
  info("Restored saved changes.");
15132
15242
  } catch {
15133
- warn("Could not restore save automatically. Use `contrib save --restore` to recover.");
15243
+ warn("Could not restore save automatically. Use `cn save --restore` to recover.");
15134
15244
  }
15135
15245
  process.exit(1);
15136
15246
  }
15137
- success(`Switched to ${import_picocolors19.default.bold(targetBranch)}`);
15138
- info(`Your changes from ${import_picocolors19.default.bold(currentBranch ?? "previous branch")} are saved.`, "");
15139
- info(`Use ${import_picocolors19.default.bold("contrib save --restore")} to bring them back.`, "");
15247
+ success(`Switched to ${import_picocolors20.default.bold(targetBranch)}`);
15248
+ info(`Your changes from ${import_picocolors20.default.bold(currentBranch ?? "previous branch")} are saved.`, "");
15249
+ info(`Use ${import_picocolors20.default.bold("cn save --restore")} to bring them back.`, "");
15140
15250
  return;
15141
15251
  }
15142
15252
  const result = await checkoutBranch(targetBranch);
@@ -15144,12 +15254,12 @@ var switch_default = defineCommand({
15144
15254
  error(`Failed to switch to ${targetBranch}: ${result.stderr}`);
15145
15255
  process.exit(1);
15146
15256
  }
15147
- success(`Switched to ${import_picocolors19.default.bold(targetBranch)}`);
15257
+ success(`Switched to ${import_picocolors20.default.bold(targetBranch)}`);
15148
15258
  }
15149
15259
  });
15150
15260
 
15151
15261
  // src/commands/sync.ts
15152
- var import_picocolors20 = __toESM(require_picocolors(), 1);
15262
+ var import_picocolors21 = __toESM(require_picocolors(), 1);
15153
15263
  var sync_default = defineCommand({
15154
15264
  meta: {
15155
15265
  name: "sync",
@@ -15180,7 +15290,7 @@ var sync_default = defineCommand({
15180
15290
  await assertCleanGitState("syncing");
15181
15291
  const config = readConfig();
15182
15292
  if (!config) {
15183
- error("No repo config found. Run `contrib setup` first.");
15293
+ error("No repo config found. Run `cn setup` first.");
15184
15294
  process.exit(1);
15185
15295
  }
15186
15296
  const { workflow, role, origin } = config;
@@ -15201,24 +15311,24 @@ var sync_default = defineCommand({
15201
15311
  await fetchRemote(origin);
15202
15312
  }
15203
15313
  if (!await refExists(syncSource.ref)) {
15204
- error(`Remote ref ${import_picocolors20.default.bold(syncSource.ref)} does not exist.`);
15314
+ error(`Remote ref ${import_picocolors21.default.bold(syncSource.ref)} does not exist.`);
15205
15315
  info("This can happen if the branch was renamed or deleted on the remote.", "");
15206
- info(`Check your config: the base branch may need updating via ${import_picocolors20.default.bold("contrib setup")}.`, "");
15316
+ info(`Check your config: the base branch may need updating via ${import_picocolors21.default.bold("cn setup")}.`, "");
15207
15317
  process.exit(1);
15208
15318
  }
15209
15319
  let allowMergeCommit = false;
15210
15320
  const div = await getDivergence(baseBranch, syncSource.ref);
15211
15321
  if (div.ahead > 0 || div.behind > 0) {
15212
- info(`${import_picocolors20.default.bold(baseBranch)} is ${import_picocolors20.default.yellow(`${div.ahead} ahead`)} and ${import_picocolors20.default.red(`${div.behind} behind`)} ${syncSource.ref}`);
15322
+ info(`${import_picocolors21.default.bold(baseBranch)} is ${import_picocolors21.default.yellow(`${div.ahead} ahead`)} and ${import_picocolors21.default.red(`${div.behind} behind`)} ${syncSource.ref}`);
15213
15323
  } else {
15214
- info(`${import_picocolors20.default.bold(baseBranch)} is already in sync with ${syncSource.ref}`);
15324
+ info(`${import_picocolors21.default.bold(baseBranch)} is already in sync with ${syncSource.ref}`);
15215
15325
  }
15216
15326
  if (div.ahead > 0) {
15217
15327
  const currentBranch = await getCurrentBranch();
15218
15328
  const protectedBranches = getProtectedBranches(config);
15219
15329
  const isOnProtected = currentBranch && protectedBranches.includes(currentBranch);
15220
15330
  if (isOnProtected) {
15221
- warn(`You have ${import_picocolors20.default.bold(String(div.ahead))} local commit${div.ahead !== 1 ? "s" : ""} on ${import_picocolors20.default.bold(baseBranch)} that aren't on the remote.`);
15331
+ warn(`You have ${import_picocolors21.default.bold(String(div.ahead))} local commit${div.ahead !== 1 ? "s" : ""} on ${import_picocolors21.default.bold(baseBranch)} that aren't on the remote.`);
15222
15332
  info("Pulling now could create a merge commit, which breaks clean history.");
15223
15333
  console.log();
15224
15334
  const MOVE_BRANCH = "Move my commits to a new feature branch, then sync";
@@ -15248,7 +15358,7 @@ var sync_default = defineCommand({
15248
15358
  error(`Failed to create branch: ${branchResult.stderr}`);
15249
15359
  process.exit(1);
15250
15360
  }
15251
- success(`Created ${import_picocolors20.default.bold(newBranchName)} with your commits.`);
15361
+ success(`Created ${import_picocolors21.default.bold(newBranchName)} with your commits.`);
15252
15362
  const coResult2 = await checkoutBranch(baseBranch);
15253
15363
  if (coResult2.exitCode !== 0) {
15254
15364
  error(`Failed to checkout ${baseBranch}: ${coResult2.stderr}`);
@@ -15256,11 +15366,11 @@ var sync_default = defineCommand({
15256
15366
  }
15257
15367
  const remoteRef = syncSource.ref;
15258
15368
  await updateLocalBranch(baseBranch, remoteRef);
15259
- success(`Reset ${import_picocolors20.default.bold(baseBranch)} to ${import_picocolors20.default.bold(remoteRef)}.`);
15260
- success(`${import_picocolors20.default.bold(baseBranch)} is now in sync with ${syncSource.ref}`);
15369
+ success(`Reset ${import_picocolors21.default.bold(baseBranch)} to ${import_picocolors21.default.bold(remoteRef)}.`);
15370
+ success(`${import_picocolors21.default.bold(baseBranch)} is now in sync with ${syncSource.ref}`);
15261
15371
  console.log();
15262
- info(`Your commits are safe on ${import_picocolors20.default.bold(newBranchName)}.`, "");
15263
- info(`Run ${import_picocolors20.default.bold(`git checkout ${newBranchName}`)} then ${import_picocolors20.default.bold("contrib update")} to rebase onto the synced ${import_picocolors20.default.bold(baseBranch)}.`, "");
15372
+ info(`Your commits are safe on ${import_picocolors21.default.bold(newBranchName)}.`, "");
15373
+ info(`Run ${import_picocolors21.default.bold(`git checkout ${newBranchName}`)} then ${import_picocolors21.default.bold("cn update")} to rebase onto the synced ${import_picocolors21.default.bold(baseBranch)}.`, "");
15264
15374
  return;
15265
15375
  }
15266
15376
  allowMergeCommit = true;
@@ -15268,7 +15378,7 @@ var sync_default = defineCommand({
15268
15378
  }
15269
15379
  }
15270
15380
  if (!args.yes) {
15271
- const ok = await confirmPrompt(`This will pull ${import_picocolors20.default.bold(syncSource.ref)} into local ${import_picocolors20.default.bold(baseBranch)}.`);
15381
+ const ok = await confirmPrompt(`This will pull ${import_picocolors21.default.bold(syncSource.ref)} into local ${import_picocolors21.default.bold(baseBranch)}.`);
15272
15382
  if (!ok)
15273
15383
  process.exit(0);
15274
15384
  }
@@ -15282,8 +15392,8 @@ var sync_default = defineCommand({
15282
15392
  if (allowMergeCommit) {
15283
15393
  error(`Pull failed: ${pullResult.stderr.trim()}`);
15284
15394
  } else {
15285
- error(`Fast-forward pull failed. Your local ${import_picocolors20.default.bold(baseBranch)} may have diverged.`);
15286
- info(`Use ${import_picocolors20.default.bold("contrib sync")} again and choose "Move my commits to a new feature branch" to fix this.`, "");
15395
+ error(`Fast-forward pull failed. Your local ${import_picocolors21.default.bold(baseBranch)} may have diverged.`);
15396
+ info(`Use ${import_picocolors21.default.bold("cn sync")} again and choose "Move my commits to a new feature branch" to fix this.`, "");
15287
15397
  }
15288
15398
  process.exit(1);
15289
15399
  }
@@ -15291,7 +15401,7 @@ var sync_default = defineCommand({
15291
15401
  if (hasDevBranch(workflow) && role === "maintainer") {
15292
15402
  const mainDiv = await getDivergence(config.mainBranch, `${origin}/${config.mainBranch}`);
15293
15403
  if (mainDiv.behind > 0) {
15294
- info(`Also syncing ${import_picocolors20.default.bold(config.mainBranch)}...`);
15404
+ info(`Also syncing ${import_picocolors21.default.bold(config.mainBranch)}...`);
15295
15405
  const mainCoResult = await checkoutBranch(config.mainBranch);
15296
15406
  if (mainCoResult.exitCode === 0) {
15297
15407
  const mainPullResult = await pullFastForwardOnly(origin, config.mainBranch);
@@ -15332,20 +15442,20 @@ var sync_default = defineCommand({
15332
15442
  }
15333
15443
  }
15334
15444
  console.log();
15335
- console.log(` ${import_picocolors20.default.bold("\uD83D\uDD17 Branch Alignment")}`);
15445
+ console.log(` ${import_picocolors21.default.bold("\uD83D\uDD17 Branch Alignment")}`);
15336
15446
  for (const [hash, names] of groups) {
15337
15447
  const short = hash.slice(0, 7);
15338
- const nameStr = names.map((n2) => import_picocolors20.default.bold(n2)).join(import_picocolors20.default.dim(" \xB7 "));
15339
- console.log(` ${import_picocolors20.default.yellow(short)} ${import_picocolors20.default.dim("\u2500\u2500")} ${nameStr}`);
15448
+ const nameStr = names.map((n2) => import_picocolors21.default.bold(n2)).join(import_picocolors21.default.dim(" \xB7 "));
15449
+ console.log(` ${import_picocolors21.default.yellow(short)} ${import_picocolors21.default.dim("\u2500\u2500")} ${nameStr}`);
15340
15450
  const subject = await getCommitSubject(hash);
15341
15451
  if (subject) {
15342
- console.log(` ${import_picocolors20.default.dim(subject)}`);
15452
+ console.log(` ${import_picocolors21.default.dim(subject)}`);
15343
15453
  }
15344
15454
  }
15345
15455
  if (groups.size === 1) {
15346
- console.log(` ${import_picocolors20.default.green("\u2713")} ${import_picocolors20.default.green("All branches aligned")} ${import_picocolors20.default.dim("\u2014 ready to start")}`);
15456
+ console.log(` ${import_picocolors21.default.green("\u2713")} ${import_picocolors21.default.green("All branches aligned")} ${import_picocolors21.default.dim("\u2014 ready to start")}`);
15347
15457
  } else {
15348
- console.log(` ${import_picocolors20.default.yellow("\u26A0")} ${import_picocolors20.default.yellow("Branches are not fully aligned")}`);
15458
+ console.log(` ${import_picocolors21.default.yellow("\u26A0")} ${import_picocolors21.default.yellow("Branches are not fully aligned")}`);
15349
15459
  }
15350
15460
  }
15351
15461
  }
@@ -15354,7 +15464,7 @@ var sync_default = defineCommand({
15354
15464
 
15355
15465
  // src/commands/update.ts
15356
15466
  import { readFileSync as readFileSync6 } from "fs";
15357
- var import_picocolors21 = __toESM(require_picocolors(), 1);
15467
+ var import_picocolors22 = __toESM(require_picocolors(), 1);
15358
15468
  function hasStaleBranchWorkToPreserve(uniqueCommitsAheadOfBase, hasUncommittedChanges2) {
15359
15469
  return hasUncommittedChanges2 || uniqueCommitsAheadOfBase > 0;
15360
15470
  }
@@ -15382,7 +15492,7 @@ var update_default = defineCommand({
15382
15492
  await assertCleanGitState("updating");
15383
15493
  const config = readConfig();
15384
15494
  if (!config) {
15385
- error("No repo config found. Run `contrib setup` first.");
15495
+ error("No repo config found. Run `cn setup` first.");
15386
15496
  process.exit(1);
15387
15497
  }
15388
15498
  const baseBranch = getBaseBranch(config);
@@ -15395,7 +15505,7 @@ var update_default = defineCommand({
15395
15505
  }
15396
15506
  if (protectedBranches.includes(currentBranch)) {
15397
15507
  await projectHeading("update", "\uD83D\uDD03");
15398
- warn(`You're on ${import_picocolors21.default.bold(currentBranch)}, which is a protected branch. Updates (rebase) apply to feature branches.`);
15508
+ warn(`You're on ${import_picocolors22.default.bold(currentBranch)}, which is a protected branch. Updates (rebase) apply to feature branches.`);
15399
15509
  await fetchAll();
15400
15510
  const { origin } = config;
15401
15511
  const remoteRef = `${origin}/${currentBranch}`;
@@ -15404,12 +15514,12 @@ var update_default = defineCommand({
15404
15514
  const hasCommits = localWork.unpushedCommits > 0;
15405
15515
  const hasAnything = hasCommits || dirty;
15406
15516
  if (!hasAnything) {
15407
- info(`No local changes found on ${import_picocolors21.default.bold(currentBranch)}.`);
15408
- info(`Use ${import_picocolors21.default.bold("contrib sync")} to sync protected branches, or ${import_picocolors21.default.bold("contrib start")} to create a feature branch.`);
15517
+ info(`No local changes found on ${import_picocolors22.default.bold(currentBranch)}.`);
15518
+ info(`Use ${import_picocolors22.default.bold("cn sync")} to sync protected branches, or ${import_picocolors22.default.bold("cn start")} to create a feature branch.`);
15409
15519
  process.exit(1);
15410
15520
  }
15411
15521
  if (hasCommits) {
15412
- info(`Found ${import_picocolors21.default.bold(String(localWork.unpushedCommits))} unpushed commit${localWork.unpushedCommits !== 1 ? "s" : ""} on ${import_picocolors21.default.bold(currentBranch)}.`);
15522
+ info(`Found ${import_picocolors22.default.bold(String(localWork.unpushedCommits))} unpushed commit${localWork.unpushedCommits !== 1 ? "s" : ""} on ${import_picocolors22.default.bold(currentBranch)}.`);
15413
15523
  }
15414
15524
  if (dirty) {
15415
15525
  info("You also have uncommitted changes in the working tree.");
@@ -15439,12 +15549,12 @@ var update_default = defineCommand({
15439
15549
  error(`Failed to create branch: ${branchResult.stderr}`);
15440
15550
  process.exit(1);
15441
15551
  }
15442
- success(`Created ${import_picocolors21.default.bold(newBranchName)} with your changes.`);
15552
+ success(`Created ${import_picocolors22.default.bold(newBranchName)} with your changes.`);
15443
15553
  await updateLocalBranch(currentBranch, remoteRef);
15444
- info(`Reset ${import_picocolors21.default.bold(currentBranch)} back to ${import_picocolors21.default.bold(remoteRef)} \u2014 no damage done.`, "");
15554
+ info(`Reset ${import_picocolors22.default.bold(currentBranch)} back to ${import_picocolors22.default.bold(remoteRef)} \u2014 no damage done.`, "");
15445
15555
  console.log();
15446
- success(`You're now on ${import_picocolors21.default.bold(newBranchName)} with all your work intact.`);
15447
- info(`Run ${import_picocolors21.default.bold("contrib update")} again to rebase onto latest ${import_picocolors21.default.bold(baseBranch)}.`, "");
15556
+ success(`You're now on ${import_picocolors22.default.bold(newBranchName)} with all your work intact.`);
15557
+ info(`Run ${import_picocolors22.default.bold("cn update")} again to rebase onto latest ${import_picocolors22.default.bold(baseBranch)}.`, "");
15448
15558
  return;
15449
15559
  }
15450
15560
  if (await hasUncommittedChanges()) {
@@ -15454,8 +15564,8 @@ var update_default = defineCommand({
15454
15564
  await projectHeading("update", "\uD83D\uDD03");
15455
15565
  const mergedPR = await getMergedPRForBranch(currentBranch);
15456
15566
  if (mergedPR) {
15457
- warn(`PR #${mergedPR.number} (${import_picocolors21.default.bold(mergedPR.title)}) has already been merged.`);
15458
- info(`Link: ${import_picocolors21.default.underline(mergedPR.url)}`, "");
15567
+ warn(`PR #${mergedPR.number} (${import_picocolors22.default.bold(mergedPR.title)}) has already been merged.`);
15568
+ info(`Link: ${import_picocolors22.default.underline(mergedPR.url)}`, "");
15459
15569
  const uniqueCommitsAheadOfBase = await countCommitsAhead(currentBranch, syncSource.ref);
15460
15570
  const dirty = await hasUncommittedChanges();
15461
15571
  const hasWork = hasStaleBranchWorkToPreserve(uniqueCommitsAheadOfBase, dirty);
@@ -15464,12 +15574,12 @@ var update_default = defineCommand({
15464
15574
  info("You have uncommitted local changes.");
15465
15575
  }
15466
15576
  if (uniqueCommitsAheadOfBase > 0) {
15467
- info(`You have ${uniqueCommitsAheadOfBase} local commit(s) not in ${import_picocolors21.default.bold(syncSource.ref)}.`);
15577
+ info(`You have ${uniqueCommitsAheadOfBase} local commit(s) not in ${import_picocolors22.default.bold(syncSource.ref)}.`);
15468
15578
  }
15469
15579
  const SAVE_NEW_BRANCH = "Save changes to a new branch";
15470
15580
  const DISCARD = "Discard all changes and clean up";
15471
15581
  const CANCEL = "Cancel";
15472
- const action = await selectPrompt(`${import_picocolors21.default.bold(currentBranch)} is stale but has local work. What would you like to do?`, [SAVE_NEW_BRANCH, DISCARD, CANCEL]);
15582
+ const action = await selectPrompt(`${import_picocolors22.default.bold(currentBranch)} is stale but has local work. What would you like to do?`, [SAVE_NEW_BRANCH, DISCARD, CANCEL]);
15473
15583
  if (action === CANCEL) {
15474
15584
  info("No changes made. You are still on your current branch.");
15475
15585
  return;
@@ -15491,7 +15601,7 @@ var update_default = defineCommand({
15491
15601
  error(`Failed to rename branch: ${renameResult.stderr}`);
15492
15602
  process.exit(1);
15493
15603
  }
15494
- success(`Renamed ${import_picocolors21.default.bold(currentBranch)} \u2192 ${import_picocolors21.default.bold(newBranchName)}`);
15604
+ success(`Renamed ${import_picocolors22.default.bold(currentBranch)} \u2192 ${import_picocolors22.default.bold(newBranchName)}`);
15495
15605
  await unsetUpstream();
15496
15606
  await fetchRemote(syncSource.remote);
15497
15607
  let rebaseResult2;
@@ -15503,11 +15613,11 @@ var update_default = defineCommand({
15503
15613
  }
15504
15614
  if (rebaseResult2.exitCode !== 0) {
15505
15615
  warn("Rebase encountered conflicts. Resolve them manually, then run:");
15506
- info(` ${import_picocolors21.default.bold("git rebase --continue")}`, "");
15616
+ info(` ${import_picocolors22.default.bold("git rebase --continue")}`, "");
15507
15617
  } else {
15508
- success(`Rebased ${import_picocolors21.default.bold(newBranchName)} onto ${import_picocolors21.default.bold(syncSource.ref)}.`);
15618
+ success(`Rebased ${import_picocolors22.default.bold(newBranchName)} onto ${import_picocolors22.default.bold(syncSource.ref)}.`);
15509
15619
  }
15510
- info(`All your changes are preserved. Run ${import_picocolors21.default.bold("contrib submit")} when ready to create a new PR.`, "");
15620
+ info(`All your changes are preserved. Run ${import_picocolors22.default.bold("cn submit")} when ready to create a new PR.`, "");
15511
15621
  return;
15512
15622
  }
15513
15623
  warn("Discarding local changes...");
@@ -15526,24 +15636,24 @@ var update_default = defineCommand({
15526
15636
  process.exit(1);
15527
15637
  }
15528
15638
  await updateLocalBranch(baseBranch, syncSource.ref);
15529
- success(`Synced ${import_picocolors21.default.bold(baseBranch)} with ${import_picocolors21.default.bold(syncSource.ref)}.`);
15530
- info(`Deleting stale branch ${import_picocolors21.default.bold(currentBranch)}...`);
15639
+ success(`Synced ${import_picocolors22.default.bold(baseBranch)} with ${import_picocolors22.default.bold(syncSource.ref)}.`);
15640
+ info(`Deleting stale branch ${import_picocolors22.default.bold(currentBranch)}...`);
15531
15641
  await forceDeleteBranch(currentBranch);
15532
- success(`Deleted ${import_picocolors21.default.bold(currentBranch)}.`);
15533
- info(`Run ${import_picocolors21.default.bold("contrib start")} to begin a new feature branch.`, "");
15642
+ success(`Deleted ${import_picocolors22.default.bold(currentBranch)}.`);
15643
+ info(`Run ${import_picocolors22.default.bold("cn start")} to begin a new feature branch.`, "");
15534
15644
  return;
15535
15645
  }
15536
- info(`Updating ${import_picocolors21.default.bold(currentBranch)} with latest ${import_picocolors21.default.bold(baseBranch)}...`);
15646
+ info(`Updating ${import_picocolors22.default.bold(currentBranch)} with latest ${import_picocolors22.default.bold(baseBranch)}...`);
15537
15647
  await fetchRemote(syncSource.remote);
15538
15648
  if (!await refExists(syncSource.ref)) {
15539
- error(`Remote ref ${import_picocolors21.default.bold(syncSource.ref)} does not exist.`);
15649
+ error(`Remote ref ${import_picocolors22.default.bold(syncSource.ref)} does not exist.`);
15540
15650
  error("Run `git fetch --all` and verify your remote configuration.");
15541
15651
  process.exit(1);
15542
15652
  }
15543
15653
  await updateLocalBranch(baseBranch, syncSource.ref);
15544
15654
  const rebaseStrategy = await determineRebaseStrategy(currentBranch, syncSource.ref);
15545
15655
  if (rebaseStrategy.strategy === "onto" && rebaseStrategy.ontoOldBase) {
15546
- info(import_picocolors21.default.dim(`Using --onto rebase (branch was based on a different ref)`));
15656
+ info(import_picocolors22.default.dim(`Using --onto rebase (branch was based on a different ref)`));
15547
15657
  }
15548
15658
  const rebaseResult = rebaseStrategy.strategy === "onto" && rebaseStrategy.ontoOldBase ? await rebaseOnto(syncSource.ref, rebaseStrategy.ontoOldBase) : await rebase(syncSource.ref);
15549
15659
  if (rebaseResult.exitCode !== 0) {
@@ -15574,10 +15684,10 @@ ${content.slice(0, 2000)}
15574
15684
  if (suggestion) {
15575
15685
  spinner.success("AI conflict guidance ready.");
15576
15686
  console.log(`
15577
- ${import_picocolors21.default.bold("\uD83D\uDCA1 AI Conflict Resolution Guidance:")}`);
15578
- console.log(import_picocolors21.default.dim("\u2500".repeat(60)));
15687
+ ${import_picocolors22.default.bold("\uD83D\uDCA1 AI Conflict Resolution Guidance:")}`);
15688
+ console.log(import_picocolors22.default.dim("\u2500".repeat(60)));
15579
15689
  console.log(suggestion);
15580
- console.log(import_picocolors21.default.dim("\u2500".repeat(60)));
15690
+ console.log(import_picocolors22.default.dim("\u2500".repeat(60)));
15581
15691
  console.log();
15582
15692
  } else {
15583
15693
  spinner.fail("AI could not analyze the conflicts.");
@@ -15585,21 +15695,21 @@ ${import_picocolors21.default.bold("\uD83D\uDCA1 AI Conflict Resolution Guidance
15585
15695
  }
15586
15696
  }
15587
15697
  }
15588
- console.log(import_picocolors21.default.bold("To resolve:"));
15698
+ console.log(import_picocolors22.default.bold("To resolve:"));
15589
15699
  console.log(` 1. Fix conflicts in the affected files`);
15590
- console.log(` 2. ${import_picocolors21.default.cyan("git add <resolved-files>")}`);
15591
- console.log(` 3. ${import_picocolors21.default.cyan("git rebase --continue")}`);
15700
+ console.log(` 2. ${import_picocolors22.default.cyan("git add <resolved-files>")}`);
15701
+ console.log(` 3. ${import_picocolors22.default.cyan("git rebase --continue")}`);
15592
15702
  console.log();
15593
- console.log(` Or abort: ${import_picocolors21.default.cyan("git rebase --abort")}`);
15703
+ console.log(` Or abort: ${import_picocolors22.default.cyan("git rebase --abort")}`);
15594
15704
  process.exit(1);
15595
15705
  }
15596
- success(`${import_picocolors21.default.bold(currentBranch)} has been rebased onto latest ${import_picocolors21.default.bold(baseBranch)}`);
15706
+ success(`${import_picocolors22.default.bold(currentBranch)} has been rebased onto latest ${import_picocolors22.default.bold(baseBranch)}`);
15597
15707
  }
15598
15708
  });
15599
15709
 
15600
15710
  // src/commands/validate.ts
15601
15711
  import { readFileSync as readFileSync7 } from "fs";
15602
- var import_picocolors22 = __toESM(require_picocolors(), 1);
15712
+ var import_picocolors23 = __toESM(require_picocolors(), 1);
15603
15713
  var validate_default = defineCommand({
15604
15714
  meta: {
15605
15715
  name: "validate",
@@ -15619,7 +15729,7 @@ var validate_default = defineCommand({
15619
15729
  async run({ args }) {
15620
15730
  const config = readConfig();
15621
15731
  if (!config) {
15622
- error("No repo config found. Run `contrib setup` first.");
15732
+ error("No repo config found. Run `cn setup` first.");
15623
15733
  process.exit(1);
15624
15734
  }
15625
15735
  await projectHeading("validate", "\u2705");
@@ -15639,1402 +15749,14 @@ var validate_default = defineCommand({
15639
15749
  }
15640
15750
  const errors = getValidationError(convention);
15641
15751
  for (const line of errors) {
15642
- console.error(import_picocolors22.default.red(` \u2717 ${line}`));
15752
+ console.error(import_picocolors23.default.red(` \u2717 ${line}`));
15643
15753
  }
15644
15754
  process.exit(1);
15645
15755
  }
15646
15756
  });
15647
15757
 
15648
- // node_modules/figlet/dist/node-figlet.mjs
15649
- import * as fs2 from "fs";
15650
- import * as path2 from "path";
15651
-
15652
- // node_modules/figlet/dist/figlet-B0EdFl3_.js
15653
- var LAYOUT = {
15654
- FULL_WIDTH: 0,
15655
- FITTING: 1,
15656
- SMUSHING: 2,
15657
- CONTROLLED_SMUSHING: 3
15658
- };
15659
-
15660
- class FigletFont {
15661
- constructor() {
15662
- this.comment = "";
15663
- this.numChars = 0;
15664
- this.options = {};
15665
- }
15666
- }
15667
- var fontList = [
15668
- "1Row",
15669
- "3-D",
15670
- "3D Diagonal",
15671
- "3D-ASCII",
15672
- "3x5",
15673
- "4Max",
15674
- "5 Line Oblique",
15675
- "AMC 3 Line",
15676
- "AMC 3 Liv1",
15677
- "AMC AAA01",
15678
- "AMC Neko",
15679
- "AMC Razor",
15680
- "AMC Razor2",
15681
- "AMC Slash",
15682
- "AMC Slider",
15683
- "AMC Thin",
15684
- "AMC Tubes",
15685
- "AMC Untitled",
15686
- "ANSI Compact",
15687
- "ANSI Regular",
15688
- "ANSI Shadow",
15689
- "ASCII 12",
15690
- "ASCII 9",
15691
- "ASCII New Roman",
15692
- "Acrobatic",
15693
- "Alligator",
15694
- "Alligator2",
15695
- "Alpha",
15696
- "Alphabet",
15697
- "Arrows",
15698
- "Avatar",
15699
- "B1FF",
15700
- "Babyface Lame",
15701
- "Babyface Leet",
15702
- "Banner",
15703
- "Banner3-D",
15704
- "Banner3",
15705
- "Banner4",
15706
- "Barbwire",
15707
- "Basic",
15708
- "Bear",
15709
- "Bell",
15710
- "Benjamin",
15711
- "Big ASCII 12",
15712
- "Big ASCII 9",
15713
- "Big Chief",
15714
- "Big Money-ne",
15715
- "Big Money-nw",
15716
- "Big Money-se",
15717
- "Big Money-sw",
15718
- "Big Mono 12",
15719
- "Big Mono 9",
15720
- "Big",
15721
- "Bigfig",
15722
- "Binary",
15723
- "Block",
15724
- "Blocks",
15725
- "Bloody",
15726
- "BlurVision ASCII",
15727
- "Bolger",
15728
- "Braced",
15729
- "Bright",
15730
- "Broadway KB",
15731
- "Broadway",
15732
- "Bubble",
15733
- "Bulbhead",
15734
- "Caligraphy",
15735
- "Caligraphy2",
15736
- "Calvin S",
15737
- "Cards",
15738
- "Catwalk",
15739
- "Chiseled",
15740
- "Chunky",
15741
- "Circle",
15742
- "Classy",
15743
- "Coder Mini",
15744
- "Coinstak",
15745
- "Cola",
15746
- "Colossal",
15747
- "Computer",
15748
- "Contessa",
15749
- "Contrast",
15750
- "Cosmike",
15751
- "Cosmike2",
15752
- "Crawford",
15753
- "Crawford2",
15754
- "Crazy",
15755
- "Cricket",
15756
- "Cursive",
15757
- "Cyberlarge",
15758
- "Cybermedium",
15759
- "Cybersmall",
15760
- "Cygnet",
15761
- "DANC4",
15762
- "DOS Rebel",
15763
- "DWhistled",
15764
- "Dancing Font",
15765
- "Decimal",
15766
- "Def Leppard",
15767
- "Delta Corps Priest 1",
15768
- "DiamFont",
15769
- "Diamond",
15770
- "Diet Cola",
15771
- "Digital",
15772
- "Doh",
15773
- "Doom",
15774
- "Dot Matrix",
15775
- "Double Shorts",
15776
- "Double",
15777
- "Dr Pepper",
15778
- "Efti Chess",
15779
- "Efti Font",
15780
- "Efti Italic",
15781
- "Efti Piti",
15782
- "Efti Robot",
15783
- "Efti Wall",
15784
- "Efti Water",
15785
- "Electronic",
15786
- "Elite",
15787
- "Emboss 2",
15788
- "Emboss",
15789
- "Epic",
15790
- "Fender",
15791
- "Filter",
15792
- "Fire Font-k",
15793
- "Fire Font-s",
15794
- "Flipped",
15795
- "Flower Power",
15796
- "Font Font",
15797
- "Four Tops",
15798
- "Fraktur",
15799
- "Fun Face",
15800
- "Fun Faces",
15801
- "Future",
15802
- "Fuzzy",
15803
- "Georgi16",
15804
- "Georgia11",
15805
- "Ghost",
15806
- "Ghoulish",
15807
- "Glenyn",
15808
- "Goofy",
15809
- "Gothic",
15810
- "Graceful",
15811
- "Gradient",
15812
- "Graffiti",
15813
- "Greek",
15814
- "Heart Left",
15815
- "Heart Right",
15816
- "Henry 3D",
15817
- "Hex",
15818
- "Hieroglyphs",
15819
- "Hollywood",
15820
- "Horizontal Left",
15821
- "Horizontal Right",
15822
- "ICL-1900",
15823
- "Impossible",
15824
- "Invita",
15825
- "Isometric1",
15826
- "Isometric2",
15827
- "Isometric3",
15828
- "Isometric4",
15829
- "Italic",
15830
- "Ivrit",
15831
- "JS Block Letters",
15832
- "JS Bracket Letters",
15833
- "JS Capital Curves",
15834
- "JS Cursive",
15835
- "JS Stick Letters",
15836
- "Jacky",
15837
- "Jazmine",
15838
- "Jerusalem",
15839
- "Katakana",
15840
- "Kban",
15841
- "Keyboard",
15842
- "Knob",
15843
- "Konto Slant",
15844
- "Konto",
15845
- "LCD",
15846
- "Larry 3D 2",
15847
- "Larry 3D",
15848
- "Lean",
15849
- "Letter",
15850
- "Letters",
15851
- "Lil Devil",
15852
- "Line Blocks",
15853
- "Linux",
15854
- "Lockergnome",
15855
- "Madrid",
15856
- "Marquee",
15857
- "Maxfour",
15858
- "Merlin1",
15859
- "Merlin2",
15860
- "Mike",
15861
- "Mini",
15862
- "Mirror",
15863
- "Mnemonic",
15864
- "Modular",
15865
- "Mono 12",
15866
- "Mono 9",
15867
- "Morse",
15868
- "Morse2",
15869
- "Moscow",
15870
- "Mshebrew210",
15871
- "Muzzle",
15872
- "NScript",
15873
- "NT Greek",
15874
- "NV Script",
15875
- "Nancyj-Fancy",
15876
- "Nancyj-Improved",
15877
- "Nancyj-Underlined",
15878
- "Nancyj",
15879
- "Nipples",
15880
- "O8",
15881
- "OS2",
15882
- "Octal",
15883
- "Ogre",
15884
- "Old Banner",
15885
- "Pagga",
15886
- "Patorjk's Cheese",
15887
- "Patorjk-HeX",
15888
- "Pawp",
15889
- "Peaks Slant",
15890
- "Peaks",
15891
- "Pebbles",
15892
- "Pepper",
15893
- "Poison",
15894
- "Puffy",
15895
- "Puzzle",
15896
- "Pyramid",
15897
- "Rammstein",
15898
- "Rebel",
15899
- "Rectangles",
15900
- "Red Phoenix",
15901
- "Relief",
15902
- "Relief2",
15903
- "Reverse",
15904
- "Roman",
15905
- "Rot13",
15906
- "Rotated",
15907
- "Rounded",
15908
- "Rowan Cap",
15909
- "Rozzo",
15910
- "RubiFont",
15911
- "Runic",
15912
- "Runyc",
15913
- "S Blood",
15914
- "SL Script",
15915
- "Santa Clara",
15916
- "Script",
15917
- "Serifcap",
15918
- "Shaded Blocky",
15919
- "Shadow",
15920
- "Shimrod",
15921
- "Short",
15922
- "Slant Relief",
15923
- "Slant",
15924
- "Slide",
15925
- "Small ASCII 12",
15926
- "Small ASCII 9",
15927
- "Small Block",
15928
- "Small Braille",
15929
- "Small Caps",
15930
- "Small Isometric1",
15931
- "Small Keyboard",
15932
- "Small Mono 12",
15933
- "Small Mono 9",
15934
- "Small Poison",
15935
- "Small Script",
15936
- "Small Shadow",
15937
- "Small Slant",
15938
- "Small Tengwar",
15939
- "Small",
15940
- "Soft",
15941
- "Speed",
15942
- "Spliff",
15943
- "Stacey",
15944
- "Stampate",
15945
- "Stampatello",
15946
- "Standard",
15947
- "Star Strips",
15948
- "Star Wars",
15949
- "Stellar",
15950
- "Stforek",
15951
- "Stick Letters",
15952
- "Stop",
15953
- "Straight",
15954
- "Stronger Than All",
15955
- "Sub-Zero",
15956
- "Swamp Land",
15957
- "Swan",
15958
- "Sweet",
15959
- "THIS",
15960
- "Tanja",
15961
- "Tengwar",
15962
- "Term",
15963
- "Terrace",
15964
- "Test1",
15965
- "The Edge",
15966
- "Thick",
15967
- "Thin",
15968
- "Thorned",
15969
- "Three Point",
15970
- "Ticks Slant",
15971
- "Ticks",
15972
- "Tiles",
15973
- "Tinker-Toy",
15974
- "Tmplr",
15975
- "Tombstone",
15976
- "Train",
15977
- "Trek",
15978
- "Tsalagi",
15979
- "Tubular",
15980
- "Twisted",
15981
- "Two Point",
15982
- "USA Flag",
15983
- "Univers",
15984
- "Upside Down Text",
15985
- "Varsity",
15986
- "Wavescape",
15987
- "Wavy",
15988
- "Weird",
15989
- "Wet Letter",
15990
- "Whimsy",
15991
- "WideTerm",
15992
- "Wow",
15993
- "miniwi"
15994
- ];
15995
- var renamedFonts = {
15996
- "ANSI-Compact": "ANSI Compact"
15997
- };
15998
- var getFontName = (name) => {
15999
- return renamedFonts[name] ? renamedFonts[name] : name;
16000
- };
16001
- function escapeRegExpChar(char) {
16002
- const specialChars = /[.*+?^${}()|[\]\\]/;
16003
- return specialChars.test(char) ? "\\" + char : char;
16004
- }
16005
- var figlet = (() => {
16006
- const { FULL_WIDTH = 0, FITTING, SMUSHING, CONTROLLED_SMUSHING } = LAYOUT;
16007
- const figFonts = {};
16008
- const figDefaults = {
16009
- font: "Standard",
16010
- fontPath: "./fonts",
16011
- fetchFontIfMissing: true
16012
- };
16013
- function removeEndChar(line, lineNum, fontHeight) {
16014
- const endChar = escapeRegExpChar(line.trim().slice(-1)) || "@";
16015
- const endCharRegEx = lineNum === fontHeight - 1 ? new RegExp(endChar + endChar + "?\\s*$") : new RegExp(endChar + "\\s*$");
16016
- return line.replace(endCharRegEx, "");
16017
- }
16018
- function getSmushingRules(oldLayout = -1, newLayout = null) {
16019
- let rules = {};
16020
- let val;
16021
- let codes = [
16022
- [16384, "vLayout", SMUSHING],
16023
- [8192, "vLayout", FITTING],
16024
- [4096, "vRule5", true],
16025
- [2048, "vRule4", true],
16026
- [1024, "vRule3", true],
16027
- [512, "vRule2", true],
16028
- [256, "vRule1", true],
16029
- [128, "hLayout", SMUSHING],
16030
- [64, "hLayout", FITTING],
16031
- [32, "hRule6", true],
16032
- [16, "hRule5", true],
16033
- [8, "hRule4", true],
16034
- [4, "hRule3", true],
16035
- [2, "hRule2", true],
16036
- [1, "hRule1", true]
16037
- ];
16038
- val = newLayout !== null ? newLayout : oldLayout;
16039
- for (const [code, rule, value] of codes) {
16040
- if (val >= code) {
16041
- val -= code;
16042
- if (rules[rule] === undefined) {
16043
- rules[rule] = value;
16044
- }
16045
- } else if (rule !== "vLayout" && rule !== "hLayout") {
16046
- rules[rule] = false;
16047
- }
16048
- }
16049
- if (typeof rules["hLayout"] === "undefined") {
16050
- if (oldLayout === 0) {
16051
- rules["hLayout"] = FITTING;
16052
- } else if (oldLayout === -1) {
16053
- rules["hLayout"] = FULL_WIDTH;
16054
- } else {
16055
- if (rules["hRule1"] || rules["hRule2"] || rules["hRule3"] || rules["hRule4"] || rules["hRule5"] || rules["hRule6"]) {
16056
- rules["hLayout"] = CONTROLLED_SMUSHING;
16057
- } else {
16058
- rules["hLayout"] = SMUSHING;
16059
- }
16060
- }
16061
- } else if (rules["hLayout"] === SMUSHING) {
16062
- if (rules["hRule1"] || rules["hRule2"] || rules["hRule3"] || rules["hRule4"] || rules["hRule5"] || rules["hRule6"]) {
16063
- rules["hLayout"] = CONTROLLED_SMUSHING;
16064
- }
16065
- }
16066
- if (typeof rules["vLayout"] === "undefined") {
16067
- if (rules["vRule1"] || rules["vRule2"] || rules["vRule3"] || rules["vRule4"] || rules["vRule5"]) {
16068
- rules["vLayout"] = CONTROLLED_SMUSHING;
16069
- } else {
16070
- rules["vLayout"] = FULL_WIDTH;
16071
- }
16072
- } else if (rules["vLayout"] === SMUSHING) {
16073
- if (rules["vRule1"] || rules["vRule2"] || rules["vRule3"] || rules["vRule4"] || rules["vRule5"]) {
16074
- rules["vLayout"] = CONTROLLED_SMUSHING;
16075
- }
16076
- }
16077
- return rules;
16078
- }
16079
- function hRule1_Smush(ch1, ch2, hardBlank = "") {
16080
- if (ch1 === ch2 && ch1 !== hardBlank) {
16081
- return ch1;
16082
- }
16083
- return false;
16084
- }
16085
- function hRule2_Smush(ch1, ch2) {
16086
- let rule2Str = "|/\\[]{}()<>";
16087
- if (ch1 === "_") {
16088
- if (rule2Str.indexOf(ch2) !== -1) {
16089
- return ch2;
16090
- }
16091
- } else if (ch2 === "_") {
16092
- if (rule2Str.indexOf(ch1) !== -1) {
16093
- return ch1;
16094
- }
16095
- }
16096
- return false;
16097
- }
16098
- function hRule3_Smush(ch1, ch2) {
16099
- let rule3Classes = "| /\\ [] {} () <>";
16100
- let r3_pos1 = rule3Classes.indexOf(ch1);
16101
- let r3_pos2 = rule3Classes.indexOf(ch2);
16102
- if (r3_pos1 !== -1 && r3_pos2 !== -1) {
16103
- if (r3_pos1 !== r3_pos2 && Math.abs(r3_pos1 - r3_pos2) !== 1) {
16104
- const startPos = Math.max(r3_pos1, r3_pos2);
16105
- const endPos = startPos + 1;
16106
- return rule3Classes.substring(startPos, endPos);
16107
- }
16108
- }
16109
- return false;
16110
- }
16111
- function hRule4_Smush(ch1, ch2) {
16112
- let rule4Str = "[] {} ()";
16113
- let r4_pos1 = rule4Str.indexOf(ch1);
16114
- let r4_pos2 = rule4Str.indexOf(ch2);
16115
- if (r4_pos1 !== -1 && r4_pos2 !== -1) {
16116
- if (Math.abs(r4_pos1 - r4_pos2) <= 1) {
16117
- return "|";
16118
- }
16119
- }
16120
- return false;
16121
- }
16122
- function hRule5_Smush(ch1, ch2) {
16123
- const patterns = {
16124
- "/\\": "|",
16125
- "\\/": "Y",
16126
- "><": "X"
16127
- };
16128
- return patterns[ch1 + ch2] || false;
16129
- }
16130
- function hRule6_Smush(ch1, ch2, hardBlank = "") {
16131
- if (ch1 === hardBlank && ch2 === hardBlank) {
16132
- return hardBlank;
16133
- }
16134
- return false;
16135
- }
16136
- function vRule1_Smush(ch1, ch2) {
16137
- if (ch1 === ch2) {
16138
- return ch1;
16139
- }
16140
- return false;
16141
- }
16142
- function vRule2_Smush(ch1, ch2) {
16143
- return hRule2_Smush(ch1, ch2);
16144
- }
16145
- function vRule3_Smush(ch1, ch2) {
16146
- return hRule3_Smush(ch1, ch2);
16147
- }
16148
- function vRule4_Smush(ch1, ch2) {
16149
- if (ch1 === "-" && ch2 === "_" || ch1 === "_" && ch2 === "-") {
16150
- return "=";
16151
- }
16152
- return false;
16153
- }
16154
- function vRule5_Smush(ch1, ch2) {
16155
- if (ch1 === "|" && ch2 === "|") {
16156
- return "|";
16157
- }
16158
- return false;
16159
- }
16160
- function uni_Smush(ch1, ch2, hardBlank) {
16161
- if (ch2 === " " || ch2 === "") {
16162
- return ch1;
16163
- } else if (ch2 === hardBlank && ch1 !== " ") {
16164
- return ch1;
16165
- } else {
16166
- return ch2;
16167
- }
16168
- }
16169
- function canVerticalSmush(txt1, txt2, opts) {
16170
- if (opts.fittingRules && opts.fittingRules.vLayout === FULL_WIDTH) {
16171
- return "invalid";
16172
- }
16173
- let ii, len = Math.min(txt1.length, txt2.length), ch1, ch2, endSmush = false, validSmush;
16174
- if (len === 0) {
16175
- return "invalid";
16176
- }
16177
- for (ii = 0;ii < len; ii++) {
16178
- ch1 = txt1.substring(ii, ii + 1);
16179
- ch2 = txt2.substring(ii, ii + 1);
16180
- if (ch1 !== " " && ch2 !== " ") {
16181
- if (opts.fittingRules && opts.fittingRules.vLayout === FITTING) {
16182
- return "invalid";
16183
- } else if (opts.fittingRules && opts.fittingRules.vLayout === SMUSHING) {
16184
- return "end";
16185
- } else {
16186
- if (vRule5_Smush(ch1, ch2)) {
16187
- endSmush = endSmush || false;
16188
- continue;
16189
- }
16190
- validSmush = false;
16191
- validSmush = opts.fittingRules && opts.fittingRules.vRule1 ? vRule1_Smush(ch1, ch2) : validSmush;
16192
- validSmush = !validSmush && opts.fittingRules && opts.fittingRules.vRule2 ? vRule2_Smush(ch1, ch2) : validSmush;
16193
- validSmush = !validSmush && opts.fittingRules && opts.fittingRules.vRule3 ? vRule3_Smush(ch1, ch2) : validSmush;
16194
- validSmush = !validSmush && opts.fittingRules && opts.fittingRules.vRule4 ? vRule4_Smush(ch1, ch2) : validSmush;
16195
- endSmush = true;
16196
- if (!validSmush) {
16197
- return "invalid";
16198
- }
16199
- }
16200
- }
16201
- }
16202
- if (endSmush) {
16203
- return "end";
16204
- } else {
16205
- return "valid";
16206
- }
16207
- }
16208
- function getVerticalSmushDist(lines1, lines2, opts) {
16209
- let maxDist = lines1.length;
16210
- let len1 = lines1.length;
16211
- let subLines1, subLines2, slen;
16212
- let curDist = 1;
16213
- let ii, ret, result;
16214
- while (curDist <= maxDist) {
16215
- subLines1 = lines1.slice(Math.max(0, len1 - curDist), len1);
16216
- subLines2 = lines2.slice(0, Math.min(maxDist, curDist));
16217
- slen = subLines2.length;
16218
- result = "";
16219
- for (ii = 0;ii < slen; ii++) {
16220
- ret = canVerticalSmush(subLines1[ii], subLines2[ii], opts);
16221
- if (ret === "end") {
16222
- result = ret;
16223
- } else if (ret === "invalid") {
16224
- result = ret;
16225
- break;
16226
- } else {
16227
- if (result === "") {
16228
- result = "valid";
16229
- }
16230
- }
16231
- }
16232
- if (result === "invalid") {
16233
- curDist--;
16234
- break;
16235
- }
16236
- if (result === "end") {
16237
- break;
16238
- }
16239
- if (result === "valid") {
16240
- curDist++;
16241
- }
16242
- }
16243
- return Math.min(maxDist, curDist);
16244
- }
16245
- function verticallySmushLines(line1, line2, opts) {
16246
- let ii, len = Math.min(line1.length, line2.length);
16247
- let ch1, ch2, result = "", validSmush;
16248
- const fittingRules = opts.fittingRules || {};
16249
- for (ii = 0;ii < len; ii++) {
16250
- ch1 = line1.substring(ii, ii + 1);
16251
- ch2 = line2.substring(ii, ii + 1);
16252
- if (ch1 !== " " && ch2 !== " ") {
16253
- if (fittingRules.vLayout === FITTING) {
16254
- result += uni_Smush(ch1, ch2);
16255
- } else if (fittingRules.vLayout === SMUSHING) {
16256
- result += uni_Smush(ch1, ch2);
16257
- } else {
16258
- validSmush = false;
16259
- validSmush = fittingRules.vRule5 ? vRule5_Smush(ch1, ch2) : validSmush;
16260
- validSmush = !validSmush && fittingRules.vRule1 ? vRule1_Smush(ch1, ch2) : validSmush;
16261
- validSmush = !validSmush && fittingRules.vRule2 ? vRule2_Smush(ch1, ch2) : validSmush;
16262
- validSmush = !validSmush && fittingRules.vRule3 ? vRule3_Smush(ch1, ch2) : validSmush;
16263
- validSmush = !validSmush && fittingRules.vRule4 ? vRule4_Smush(ch1, ch2) : validSmush;
16264
- result += validSmush;
16265
- }
16266
- } else {
16267
- result += uni_Smush(ch1, ch2);
16268
- }
16269
- }
16270
- return result;
16271
- }
16272
- function verticalSmush(lines1, lines2, overlap, opts) {
16273
- let len1 = lines1.length;
16274
- let len2 = lines2.length;
16275
- let piece1 = lines1.slice(0, Math.max(0, len1 - overlap));
16276
- let piece2_1 = lines1.slice(Math.max(0, len1 - overlap), len1);
16277
- let piece2_2 = lines2.slice(0, Math.min(overlap, len2));
16278
- let ii, len, line, piece2 = [], piece3;
16279
- len = piece2_1.length;
16280
- for (ii = 0;ii < len; ii++) {
16281
- if (ii >= len2) {
16282
- line = piece2_1[ii];
16283
- } else {
16284
- line = verticallySmushLines(piece2_1[ii], piece2_2[ii], opts);
16285
- }
16286
- piece2.push(line);
16287
- }
16288
- piece3 = lines2.slice(Math.min(overlap, len2), len2);
16289
- return [...piece1, ...piece2, ...piece3];
16290
- }
16291
- function padLines(lines, numSpaces) {
16292
- const padding = " ".repeat(numSpaces);
16293
- return lines.map((line) => line + padding);
16294
- }
16295
- function smushVerticalFigLines(output, lines, opts) {
16296
- let len1 = output[0].length;
16297
- let len2 = lines[0].length;
16298
- let overlap;
16299
- if (len1 > len2) {
16300
- lines = padLines(lines, len1 - len2);
16301
- } else if (len2 > len1) {
16302
- output = padLines(output, len2 - len1);
16303
- }
16304
- overlap = getVerticalSmushDist(output, lines, opts);
16305
- return verticalSmush(output, lines, overlap, opts);
16306
- }
16307
- function getHorizontalSmushLength(txt1, txt2, opts) {
16308
- const fittingRules = opts.fittingRules || {};
16309
- if (fittingRules.hLayout === FULL_WIDTH) {
16310
- return 0;
16311
- }
16312
- let ii, len1 = txt1.length, len2 = txt2.length;
16313
- let maxDist = len1;
16314
- let curDist = 1;
16315
- let breakAfter = false;
16316
- let seg1, seg2, ch1, ch2;
16317
- if (len1 === 0) {
16318
- return 0;
16319
- }
16320
- distCal:
16321
- while (curDist <= maxDist) {
16322
- const seg1StartPos = len1 - curDist;
16323
- seg1 = txt1.substring(seg1StartPos, seg1StartPos + curDist);
16324
- seg2 = txt2.substring(0, Math.min(curDist, len2));
16325
- for (ii = 0;ii < Math.min(curDist, len2); ii++) {
16326
- ch1 = seg1.substring(ii, ii + 1);
16327
- ch2 = seg2.substring(ii, ii + 1);
16328
- if (ch1 !== " " && ch2 !== " ") {
16329
- if (fittingRules.hLayout === FITTING) {
16330
- curDist = curDist - 1;
16331
- break distCal;
16332
- } else if (fittingRules.hLayout === SMUSHING) {
16333
- if (ch1 === opts.hardBlank || ch2 === opts.hardBlank) {
16334
- curDist = curDist - 1;
16335
- }
16336
- break distCal;
16337
- } else {
16338
- breakAfter = true;
16339
- const validSmush = fittingRules.hRule1 && hRule1_Smush(ch1, ch2, opts.hardBlank) || fittingRules.hRule2 && hRule2_Smush(ch1, ch2) || fittingRules.hRule3 && hRule3_Smush(ch1, ch2) || fittingRules.hRule4 && hRule4_Smush(ch1, ch2) || fittingRules.hRule5 && hRule5_Smush(ch1, ch2) || fittingRules.hRule6 && hRule6_Smush(ch1, ch2, opts.hardBlank);
16340
- if (!validSmush) {
16341
- curDist = curDist - 1;
16342
- break distCal;
16343
- }
16344
- }
16345
- }
16346
- }
16347
- if (breakAfter) {
16348
- break;
16349
- }
16350
- curDist++;
16351
- }
16352
- return Math.min(maxDist, curDist);
16353
- }
16354
- function horizontalSmush(textBlock1, textBlock2, overlap, opts) {
16355
- let ii, jj, outputFig = [], overlapStart, piece1, piece2, piece3, len1, len2, txt1, txt2;
16356
- const fittingRules = opts.fittingRules || {};
16357
- if (typeof opts.height !== "number") {
16358
- throw new Error("height is not defined.");
16359
- }
16360
- for (ii = 0;ii < opts.height; ii++) {
16361
- txt1 = textBlock1[ii];
16362
- txt2 = textBlock2[ii];
16363
- len1 = txt1.length;
16364
- len2 = txt2.length;
16365
- overlapStart = len1 - overlap;
16366
- piece1 = txt1.slice(0, Math.max(0, overlapStart));
16367
- piece2 = "";
16368
- const seg1StartPos = Math.max(0, len1 - overlap);
16369
- let seg1 = txt1.substring(seg1StartPos, seg1StartPos + overlap);
16370
- let seg2 = txt2.substring(0, Math.min(overlap, len2));
16371
- for (jj = 0;jj < overlap; jj++) {
16372
- let ch1 = jj < len1 ? seg1.substring(jj, jj + 1) : " ";
16373
- let ch2 = jj < len2 ? seg2.substring(jj, jj + 1) : " ";
16374
- if (ch1 !== " " && ch2 !== " ") {
16375
- if (fittingRules.hLayout === FITTING || fittingRules.hLayout === SMUSHING) {
16376
- piece2 += uni_Smush(ch1, ch2, opts.hardBlank);
16377
- } else {
16378
- const nextCh = fittingRules.hRule1 && hRule1_Smush(ch1, ch2, opts.hardBlank) || fittingRules.hRule2 && hRule2_Smush(ch1, ch2) || fittingRules.hRule3 && hRule3_Smush(ch1, ch2) || fittingRules.hRule4 && hRule4_Smush(ch1, ch2) || fittingRules.hRule5 && hRule5_Smush(ch1, ch2) || fittingRules.hRule6 && hRule6_Smush(ch1, ch2, opts.hardBlank) || uni_Smush(ch1, ch2, opts.hardBlank);
16379
- piece2 += nextCh;
16380
- }
16381
- } else {
16382
- piece2 += uni_Smush(ch1, ch2, opts.hardBlank);
16383
- }
16384
- }
16385
- if (overlap >= len2) {
16386
- piece3 = "";
16387
- } else {
16388
- piece3 = txt2.substring(overlap, overlap + Math.max(0, len2 - overlap));
16389
- }
16390
- outputFig[ii] = piece1 + piece2 + piece3;
16391
- }
16392
- return outputFig;
16393
- }
16394
- function newFigChar(len) {
16395
- return new Array(len).fill("");
16396
- }
16397
- const figLinesWidth = function(textLines) {
16398
- return Math.max(...textLines.map((line) => line.length));
16399
- };
16400
- function joinFigArray(array, len, opts) {
16401
- return array.reduce(function(acc, data) {
16402
- return horizontalSmush(acc, data.fig, data.overlap || 0, opts);
16403
- }, newFigChar(len));
16404
- }
16405
- function breakWord(figChars, len, opts) {
16406
- for (let i2 = figChars.length - 1;i2 > 0; i2--) {
16407
- const w2 = joinFigArray(figChars.slice(0, i2), len, opts);
16408
- if (figLinesWidth(w2) <= opts.width) {
16409
- return {
16410
- outputFigText: w2,
16411
- chars: figChars.slice(i2)
16412
- };
16413
- }
16414
- }
16415
- return { outputFigText: newFigChar(len), chars: figChars };
16416
- }
16417
- function generateFigTextLines(txt, figChars, opts) {
16418
- let charIndex, figChar, overlap = 0, row, outputFigText, len, height = opts.height, outputFigLines = [], maxWidth, nextFigChars = {
16419
- chars: [],
16420
- overlap
16421
- }, figWords = [], char, isSpace, textFigWord, textFigLine, tmpBreak;
16422
- if (typeof height !== "number") {
16423
- throw new Error("height is not defined.");
16424
- }
16425
- outputFigText = newFigChar(height);
16426
- const fittingRules = opts.fittingRules || {};
16427
- if (opts.printDirection === 1) {
16428
- txt = txt.split("").reverse().join("");
16429
- }
16430
- len = txt.length;
16431
- for (charIndex = 0;charIndex < len; charIndex++) {
16432
- char = txt.substring(charIndex, charIndex + 1);
16433
- isSpace = char.match(/\s/);
16434
- figChar = figChars[char.charCodeAt(0)];
16435
- textFigLine = null;
16436
- if (figChar) {
16437
- if (fittingRules.hLayout !== FULL_WIDTH) {
16438
- overlap = 1e4;
16439
- for (row = 0;row < height; row++) {
16440
- overlap = Math.min(overlap, getHorizontalSmushLength(outputFigText[row], figChar[row], opts));
16441
- }
16442
- overlap = overlap === 1e4 ? 0 : overlap;
16443
- }
16444
- if (opts.width > 0) {
16445
- if (opts.whitespaceBreak) {
16446
- textFigWord = joinFigArray(nextFigChars.chars.concat([
16447
- {
16448
- fig: figChar,
16449
- overlap
16450
- }
16451
- ]), height, opts);
16452
- textFigLine = joinFigArray(figWords.concat([
16453
- {
16454
- fig: textFigWord,
16455
- overlap: nextFigChars.overlap
16456
- }
16457
- ]), height, opts);
16458
- maxWidth = figLinesWidth(textFigLine);
16459
- } else {
16460
- textFigLine = horizontalSmush(outputFigText, figChar, overlap, opts);
16461
- maxWidth = figLinesWidth(textFigLine);
16462
- }
16463
- if (maxWidth >= opts.width && charIndex > 0) {
16464
- if (opts.whitespaceBreak) {
16465
- outputFigText = joinFigArray(figWords.slice(0, -1), height, opts);
16466
- if (figWords.length > 1) {
16467
- outputFigLines.push(outputFigText);
16468
- outputFigText = newFigChar(height);
16469
- }
16470
- figWords = [];
16471
- } else {
16472
- outputFigLines.push(outputFigText);
16473
- outputFigText = newFigChar(height);
16474
- }
16475
- }
16476
- }
16477
- if (opts.width > 0 && opts.whitespaceBreak) {
16478
- if (!isSpace || charIndex === len - 1) {
16479
- nextFigChars.chars.push({ fig: figChar, overlap });
16480
- }
16481
- if (isSpace || charIndex === len - 1) {
16482
- tmpBreak = null;
16483
- while (true) {
16484
- textFigLine = joinFigArray(nextFigChars.chars, height, opts);
16485
- maxWidth = figLinesWidth(textFigLine);
16486
- if (maxWidth >= opts.width) {
16487
- tmpBreak = breakWord(nextFigChars.chars, height, opts);
16488
- nextFigChars = { chars: tmpBreak.chars };
16489
- outputFigLines.push(tmpBreak.outputFigText);
16490
- } else {
16491
- break;
16492
- }
16493
- }
16494
- if (maxWidth > 0) {
16495
- if (tmpBreak) {
16496
- figWords.push({ fig: textFigLine, overlap: 1 });
16497
- } else {
16498
- figWords.push({
16499
- fig: textFigLine,
16500
- overlap: nextFigChars.overlap
16501
- });
16502
- }
16503
- }
16504
- if (isSpace) {
16505
- figWords.push({ fig: figChar, overlap });
16506
- outputFigText = newFigChar(height);
16507
- }
16508
- if (charIndex === len - 1) {
16509
- outputFigText = joinFigArray(figWords, height, opts);
16510
- }
16511
- nextFigChars = {
16512
- chars: [],
16513
- overlap
16514
- };
16515
- continue;
16516
- }
16517
- }
16518
- outputFigText = horizontalSmush(outputFigText, figChar, overlap, opts);
16519
- }
16520
- }
16521
- if (figLinesWidth(outputFigText) > 0) {
16522
- outputFigLines.push(outputFigText);
16523
- }
16524
- if (!opts.showHardBlanks) {
16525
- outputFigLines.forEach(function(outputFigText2) {
16526
- len = outputFigText2.length;
16527
- for (row = 0;row < len; row++) {
16528
- outputFigText2[row] = outputFigText2[row].replace(new RegExp("\\" + opts.hardBlank, "g"), " ");
16529
- }
16530
- });
16531
- }
16532
- if (txt === "" && outputFigLines.length === 0) {
16533
- outputFigLines.push(new Array(height).fill(""));
16534
- }
16535
- return outputFigLines;
16536
- }
16537
- const getHorizontalFittingRules = function(layout, options) {
16538
- let params;
16539
- const fittingRules = options.fittingRules || {};
16540
- if (layout === "default") {
16541
- params = {
16542
- hLayout: fittingRules.hLayout,
16543
- hRule1: fittingRules.hRule1,
16544
- hRule2: fittingRules.hRule2,
16545
- hRule3: fittingRules.hRule3,
16546
- hRule4: fittingRules.hRule4,
16547
- hRule5: fittingRules.hRule5,
16548
- hRule6: fittingRules.hRule6
16549
- };
16550
- } else if (layout === "full") {
16551
- params = {
16552
- hLayout: FULL_WIDTH,
16553
- hRule1: false,
16554
- hRule2: false,
16555
- hRule3: false,
16556
- hRule4: false,
16557
- hRule5: false,
16558
- hRule6: false
16559
- };
16560
- } else if (layout === "fitted") {
16561
- params = {
16562
- hLayout: FITTING,
16563
- hRule1: false,
16564
- hRule2: false,
16565
- hRule3: false,
16566
- hRule4: false,
16567
- hRule5: false,
16568
- hRule6: false
16569
- };
16570
- } else if (layout === "controlled smushing") {
16571
- params = {
16572
- hLayout: CONTROLLED_SMUSHING,
16573
- hRule1: true,
16574
- hRule2: true,
16575
- hRule3: true,
16576
- hRule4: true,
16577
- hRule5: true,
16578
- hRule6: true
16579
- };
16580
- } else if (layout === "universal smushing") {
16581
- params = {
16582
- hLayout: SMUSHING,
16583
- hRule1: false,
16584
- hRule2: false,
16585
- hRule3: false,
16586
- hRule4: false,
16587
- hRule5: false,
16588
- hRule6: false
16589
- };
16590
- } else {
16591
- return;
16592
- }
16593
- return params;
16594
- };
16595
- const getVerticalFittingRules = function(layout, options) {
16596
- let params = {};
16597
- const fittingRules = options.fittingRules || {};
16598
- if (layout === "default") {
16599
- params = {
16600
- vLayout: fittingRules.vLayout,
16601
- vRule1: fittingRules.vRule1,
16602
- vRule2: fittingRules.vRule2,
16603
- vRule3: fittingRules.vRule3,
16604
- vRule4: fittingRules.vRule4,
16605
- vRule5: fittingRules.vRule5
16606
- };
16607
- } else if (layout === "full") {
16608
- params = {
16609
- vLayout: FULL_WIDTH,
16610
- vRule1: false,
16611
- vRule2: false,
16612
- vRule3: false,
16613
- vRule4: false,
16614
- vRule5: false
16615
- };
16616
- } else if (layout === "fitted") {
16617
- params = {
16618
- vLayout: FITTING,
16619
- vRule1: false,
16620
- vRule2: false,
16621
- vRule3: false,
16622
- vRule4: false,
16623
- vRule5: false
16624
- };
16625
- } else if (layout === "controlled smushing") {
16626
- params = {
16627
- vLayout: CONTROLLED_SMUSHING,
16628
- vRule1: true,
16629
- vRule2: true,
16630
- vRule3: true,
16631
- vRule4: true,
16632
- vRule5: true
16633
- };
16634
- } else if (layout === "universal smushing") {
16635
- params = {
16636
- vLayout: SMUSHING,
16637
- vRule1: false,
16638
- vRule2: false,
16639
- vRule3: false,
16640
- vRule4: false,
16641
- vRule5: false
16642
- };
16643
- } else {
16644
- return;
16645
- }
16646
- return params;
16647
- };
16648
- const generateText = function(fontName, options, txt) {
16649
- txt = txt.replace(/\r\n/g, `
16650
- `).replace(/\r/g, `
16651
- `);
16652
- const actualFontName = getFontName(fontName);
16653
- let lines = txt.split(`
16654
- `);
16655
- let figLines = [];
16656
- let ii, len, output;
16657
- len = lines.length;
16658
- for (ii = 0;ii < len; ii++) {
16659
- figLines = figLines.concat(generateFigTextLines(lines[ii], figFonts[actualFontName], options));
16660
- }
16661
- len = figLines.length;
16662
- output = figLines[0];
16663
- for (ii = 1;ii < len; ii++) {
16664
- output = smushVerticalFigLines(output, figLines[ii], options);
16665
- }
16666
- return output ? output.join(`
16667
- `) : "";
16668
- };
16669
- function _reworkFontOpts(fontMeta, options) {
16670
- let myOpts;
16671
- if (typeof structuredClone !== "undefined") {
16672
- myOpts = structuredClone(fontMeta);
16673
- } else {
16674
- myOpts = JSON.parse(JSON.stringify(fontMeta));
16675
- }
16676
- myOpts.showHardBlanks = options.showHardBlanks || false;
16677
- myOpts.width = options.width || -1;
16678
- myOpts.whitespaceBreak = options.whitespaceBreak || false;
16679
- if (options.horizontalLayout) {
16680
- const params = getHorizontalFittingRules(options.horizontalLayout, fontMeta);
16681
- if (params) {
16682
- Object.assign(myOpts.fittingRules, params);
16683
- }
16684
- }
16685
- if (options.verticalLayout) {
16686
- const params = getVerticalFittingRules(options.verticalLayout, fontMeta);
16687
- if (params) {
16688
- Object.assign(myOpts.fittingRules, params);
16689
- }
16690
- }
16691
- myOpts.printDirection = options.printDirection !== null && options.printDirection !== undefined ? options.printDirection : fontMeta.printDirection;
16692
- return myOpts;
16693
- }
16694
- const me2 = async function(txt, optionsOrFontOrCallback, callback) {
16695
- return me2.text(txt, optionsOrFontOrCallback, callback);
16696
- };
16697
- me2.text = async function(txt, optionsOrFontOrCallback, callback) {
16698
- txt = txt + "";
16699
- let options, next;
16700
- if (typeof optionsOrFontOrCallback === "function") {
16701
- next = optionsOrFontOrCallback;
16702
- options = { font: figDefaults.font };
16703
- } else if (typeof optionsOrFontOrCallback === "string") {
16704
- options = { font: optionsOrFontOrCallback };
16705
- next = callback;
16706
- } else if (optionsOrFontOrCallback) {
16707
- options = optionsOrFontOrCallback;
16708
- next = callback;
16709
- } else {
16710
- options = { font: figDefaults.font };
16711
- next = callback;
16712
- }
16713
- const fontName = options.font || figDefaults.font;
16714
- try {
16715
- const fontOpts = await me2.loadFont(fontName);
16716
- const generatedTxt = fontOpts ? generateText(fontName, _reworkFontOpts(fontOpts, options), txt) : "";
16717
- if (next) {
16718
- next(null, generatedTxt);
16719
- }
16720
- return generatedTxt;
16721
- } catch (err) {
16722
- const error2 = err instanceof Error ? err : new Error(String(err));
16723
- if (next) {
16724
- next(error2);
16725
- return "";
16726
- }
16727
- throw error2;
16728
- }
16729
- };
16730
- me2.textSync = function(txt, options) {
16731
- txt = txt + "";
16732
- if (typeof options === "string") {
16733
- options = { font: options };
16734
- } else {
16735
- options = options || {};
16736
- }
16737
- const fontName = options.font || figDefaults.font;
16738
- let fontOpts = _reworkFontOpts(me2.loadFontSync(fontName), options);
16739
- return generateText(fontName, fontOpts, txt);
16740
- };
16741
- me2.metadata = async function(fontName, callback) {
16742
- fontName = fontName + "";
16743
- try {
16744
- const fontOpts = await me2.loadFont(fontName);
16745
- if (!fontOpts) {
16746
- throw new Error("Error loading font.");
16747
- }
16748
- const actualFontName = getFontName(fontName);
16749
- const font = figFonts[actualFontName] || {};
16750
- const result = [fontOpts, font.comment || ""];
16751
- if (callback) {
16752
- callback(null, fontOpts, font.comment);
16753
- }
16754
- return result;
16755
- } catch (err) {
16756
- const error2 = err instanceof Error ? err : new Error(String(err));
16757
- if (callback) {
16758
- callback(error2);
16759
- return null;
16760
- }
16761
- throw error2;
16762
- }
16763
- };
16764
- me2.defaults = function(opts) {
16765
- if (opts && typeof opts === "object") {
16766
- Object.assign(figDefaults, opts);
16767
- }
16768
- if (typeof structuredClone !== "undefined") {
16769
- return structuredClone(figDefaults);
16770
- } else {
16771
- return JSON.parse(JSON.stringify(figDefaults));
16772
- }
16773
- };
16774
- me2.parseFont = function(fontName, data, override = true) {
16775
- if (figFonts[fontName] && !override) {
16776
- return figFonts[fontName].options;
16777
- }
16778
- data = data.replace(/\r\n/g, `
16779
- `).replace(/\r/g, `
16780
- `);
16781
- const font = new FigletFont;
16782
- const lines = data.split(`
16783
- `);
16784
- const headerLine = lines.shift();
16785
- if (!headerLine) {
16786
- throw new Error("Invalid font file: missing header");
16787
- }
16788
- const headerData = headerLine.split(" ");
16789
- const opts = {
16790
- hardBlank: headerData[0].substring(5, 6),
16791
- height: parseInt(headerData[1], 10),
16792
- baseline: parseInt(headerData[2], 10),
16793
- maxLength: parseInt(headerData[3], 10),
16794
- oldLayout: parseInt(headerData[4], 10),
16795
- numCommentLines: parseInt(headerData[5], 10),
16796
- printDirection: headerData[6] ? parseInt(headerData[6], 10) : 0,
16797
- fullLayout: headerData[7] ? parseInt(headerData[7], 10) : null,
16798
- codeTagCount: headerData[8] ? parseInt(headerData[8], 10) : null
16799
- };
16800
- const hardBlank = opts.hardBlank || "";
16801
- if (hardBlank.length !== 1 || [
16802
- opts.height,
16803
- opts.baseline,
16804
- opts.maxLength,
16805
- opts.oldLayout,
16806
- opts.numCommentLines
16807
- ].some((val) => val === null || val === undefined || isNaN(val))) {
16808
- throw new Error("FIGlet header contains invalid values.");
16809
- }
16810
- if (opts.height == null || opts.numCommentLines == null) {
16811
- throw new Error("FIGlet header contains invalid values.");
16812
- }
16813
- opts.fittingRules = getSmushingRules(opts.oldLayout, opts.fullLayout);
16814
- font.options = opts;
16815
- const charNums = [];
16816
- for (let i2 = 32;i2 <= 126; i2++) {
16817
- charNums.push(i2);
16818
- }
16819
- charNums.push(196, 214, 220, 228, 246, 252, 223);
16820
- if (lines.length < opts.numCommentLines + opts.height * charNums.length) {
16821
- throw new Error(`FIGlet file is missing data. Line length: ${lines.length}. Comment lines: ${opts.numCommentLines}. Height: ${opts.height}. Num chars: ${charNums.length}.`);
16822
- }
16823
- font.comment = lines.splice(0, opts.numCommentLines).join(`
16824
- `);
16825
- font.numChars = 0;
16826
- while (lines.length > 0 && font.numChars < charNums.length) {
16827
- const cNum = charNums[font.numChars];
16828
- font[cNum] = lines.splice(0, opts.height);
16829
- for (let i2 = 0;i2 < opts.height; i2++) {
16830
- if (typeof font[cNum][i2] === "undefined") {
16831
- font[cNum][i2] = "";
16832
- } else {
16833
- font[cNum][i2] = removeEndChar(font[cNum][i2], i2, opts.height);
16834
- }
16835
- }
16836
- font.numChars++;
16837
- }
16838
- while (lines.length > 0) {
16839
- const cNumLine = lines.shift();
16840
- if (!cNumLine || cNumLine.trim() === "")
16841
- break;
16842
- let cNum = cNumLine.split(" ")[0];
16843
- let parsedNum;
16844
- if (/^-?0[xX][0-9a-fA-F]+$/.test(cNum)) {
16845
- parsedNum = parseInt(cNum, 16);
16846
- } else if (/^-?0[0-7]+$/.test(cNum)) {
16847
- parsedNum = parseInt(cNum, 8);
16848
- } else if (/^-?[0-9]+$/.test(cNum)) {
16849
- parsedNum = parseInt(cNum, 10);
16850
- } else {
16851
- throw new Error(`Error parsing data. Invalid data: ${cNum}`);
16852
- }
16853
- if (parsedNum === -1 || parsedNum < -2147483648 || parsedNum > 2147483647) {
16854
- const msg = parsedNum === -1 ? "The char code -1 is not permitted." : `The char code cannot be ${parsedNum < -2147483648 ? "less than -2147483648" : "greater than 2147483647"}.`;
16855
- throw new Error(`Error parsing data. ${msg}`);
16856
- }
16857
- font[parsedNum] = lines.splice(0, opts.height);
16858
- for (let i2 = 0;i2 < opts.height; i2++) {
16859
- if (typeof font[parsedNum][i2] === "undefined") {
16860
- font[parsedNum][i2] = "";
16861
- } else {
16862
- font[parsedNum][i2] = removeEndChar(font[parsedNum][i2], i2, opts.height);
16863
- }
16864
- }
16865
- font.numChars++;
16866
- }
16867
- figFonts[fontName] = font;
16868
- return opts;
16869
- };
16870
- me2.loadedFonts = () => {
16871
- return Object.keys(figFonts);
16872
- };
16873
- me2.clearLoadedFonts = () => {
16874
- Object.keys(figFonts).forEach((key) => {
16875
- delete figFonts[key];
16876
- });
16877
- };
16878
- me2.loadFont = async function(fontName, callback) {
16879
- const actualFontName = getFontName(fontName);
16880
- if (figFonts[actualFontName]) {
16881
- const result = figFonts[actualFontName].options;
16882
- if (callback) {
16883
- callback(null, result);
16884
- }
16885
- return Promise.resolve(result);
16886
- }
16887
- try {
16888
- if (!figDefaults.fetchFontIfMissing) {
16889
- throw new Error(`Font is not loaded: ${actualFontName}`);
16890
- }
16891
- const response = await fetch(`${figDefaults.fontPath}/${actualFontName}.flf`);
16892
- if (!response.ok) {
16893
- throw new Error(`Network response was not ok: ${response.status}`);
16894
- }
16895
- const text = await response.text();
16896
- const result = me2.parseFont(actualFontName, text);
16897
- if (callback) {
16898
- callback(null, result);
16899
- }
16900
- return result;
16901
- } catch (error2) {
16902
- const err = error2 instanceof Error ? error2 : new Error(String(error2));
16903
- if (callback) {
16904
- callback(err);
16905
- return null;
16906
- }
16907
- throw err;
16908
- }
16909
- };
16910
- me2.loadFontSync = function(name) {
16911
- const actualFontName = getFontName(name);
16912
- if (figFonts[actualFontName]) {
16913
- return figFonts[actualFontName].options;
16914
- }
16915
- throw new Error("Synchronous font loading is not implemented for the browser, it will only work for fonts already loaded.");
16916
- };
16917
- me2.preloadFonts = async function(fonts, callback) {
16918
- try {
16919
- for (const name of fonts) {
16920
- const actualFontName = getFontName(name);
16921
- const response = await fetch(`${figDefaults.fontPath}/${actualFontName}.flf`);
16922
- if (!response.ok) {
16923
- throw new Error(`Failed to preload fonts. Error fetching font: ${actualFontName}, status code: ${response.statusText}`);
16924
- }
16925
- const data = await response.text();
16926
- me2.parseFont(actualFontName, data);
16927
- }
16928
- if (callback) {
16929
- callback();
16930
- }
16931
- } catch (error2) {
16932
- const err = error2 instanceof Error ? error2 : new Error(String(error2));
16933
- if (callback) {
16934
- callback(err);
16935
- return;
16936
- }
16937
- throw error2;
16938
- }
16939
- };
16940
- me2.fonts = function(callback) {
16941
- return new Promise(function(resolve5, reject) {
16942
- resolve5(fontList);
16943
- if (callback) {
16944
- callback(null, fontList);
16945
- }
16946
- });
16947
- };
16948
- me2.fontsSync = function() {
16949
- return fontList;
16950
- };
16951
- me2.figFonts = figFonts;
16952
- return me2;
16953
- })();
16954
-
16955
- // node_modules/figlet/dist/node-figlet.mjs
16956
- import { fileURLToPath as fileURLToPath2 } from "url";
16957
- var __filename2 = fileURLToPath2(import.meta.url);
16958
- var __dirname2 = path2.dirname(__filename2);
16959
- var fontPath = path2.join(__dirname2, "/../fonts/");
16960
- var nodeFiglet = figlet;
16961
- nodeFiglet.defaults({ fontPath });
16962
- nodeFiglet.loadFont = function(name, callback) {
16963
- const actualFontName = getFontName(name);
16964
- return new Promise((resolve5, reject) => {
16965
- if (nodeFiglet.figFonts[actualFontName]) {
16966
- if (callback) {
16967
- callback(null, nodeFiglet.figFonts[actualFontName].options);
16968
- }
16969
- resolve5(nodeFiglet.figFonts[actualFontName].options);
16970
- return;
16971
- }
16972
- fs2.readFile(path2.join(nodeFiglet.defaults().fontPath, actualFontName + ".flf"), { encoding: "utf-8" }, (err, fontData) => {
16973
- if (err) {
16974
- if (callback) {
16975
- callback(err);
16976
- }
16977
- reject(err);
16978
- return;
16979
- }
16980
- fontData = fontData + "";
16981
- try {
16982
- const font = nodeFiglet.parseFont(actualFontName, fontData);
16983
- if (callback) {
16984
- callback(null, font);
16985
- }
16986
- resolve5(font);
16987
- } catch (error2) {
16988
- const typedError = error2 instanceof Error ? error2 : new Error(String(error2));
16989
- if (callback) {
16990
- callback(typedError);
16991
- }
16992
- reject(typedError);
16993
- }
16994
- });
16995
- });
16996
- };
16997
- nodeFiglet.loadFontSync = function(font) {
16998
- const actualFontName = getFontName(font);
16999
- if (nodeFiglet.figFonts[actualFontName]) {
17000
- return nodeFiglet.figFonts[actualFontName].options;
17001
- }
17002
- const fontData = fs2.readFileSync(path2.join(nodeFiglet.defaults().fontPath, actualFontName + ".flf"), {
17003
- encoding: "utf-8"
17004
- }) + "";
17005
- return nodeFiglet.parseFont(actualFontName, fontData);
17006
- };
17007
- nodeFiglet.fonts = function(next) {
17008
- return new Promise((resolve5, reject) => {
17009
- const fontList2 = [];
17010
- fs2.readdir(nodeFiglet.defaults().fontPath, (err, files) => {
17011
- if (err) {
17012
- next && next(err);
17013
- reject(err);
17014
- return;
17015
- }
17016
- files.forEach((file) => {
17017
- if (/\.flf$/.test(file)) {
17018
- fontList2.push(file.replace(/\.flf$/, ""));
17019
- }
17020
- });
17021
- next && next(null, fontList2);
17022
- resolve5(fontList2);
17023
- });
17024
- });
17025
- };
17026
- nodeFiglet.fontsSync = function() {
17027
- const fontList2 = [];
17028
- fs2.readdirSync(nodeFiglet.defaults().fontPath).forEach((file) => {
17029
- if (/\.flf$/.test(file)) {
17030
- fontList2.push(file.replace(/\.flf$/, ""));
17031
- }
17032
- });
17033
- return fontList2;
17034
- };
17035
-
17036
15758
  // src/ui/banner.ts
17037
- var import_picocolors23 = __toESM(require_picocolors(), 1);
15759
+ var import_picocolors24 = __toESM(require_picocolors(), 1);
17038
15760
 
17039
15761
  // src/data/announcements.json
17040
15762
  var announcements_default = [
@@ -17044,6 +15766,13 @@ var announcements_default = [
17044
15766
  title: "Legacy Config Detected",
17045
15767
  message: "Run cn setup to migrate this clone to local Git config, then delete .contributerc.json.",
17046
15768
  when: "legacy-config-present"
15769
+ },
15770
+ {
15771
+ id: "contrib-command-deprecation",
15772
+ kind: "info",
15773
+ title: "Heads up: `contrib` will retire",
15774
+ message: "The `contrib` command is being phased out. Please switch to `contribute` (primary) or the shorter `cn` shortcut \u2014 same features either way.",
15775
+ when: "contrib-command-used"
17047
15776
  }
17048
15777
  ];
17049
15778
 
@@ -17059,25 +15788,28 @@ function shouldShowAnnouncement(announcement, cwd) {
17059
15788
  switch (announcement.when) {
17060
15789
  case "legacy-config-present":
17061
15790
  return hasLegacyConfig(cwd);
15791
+ case "contrib-command-used":
15792
+ return isLegacyCommandInvocation();
17062
15793
  default:
17063
15794
  return false;
17064
15795
  }
17065
15796
  }
15797
+ function isLegacyCommandInvocation() {
15798
+ const entry = process.argv[1];
15799
+ if (!entry)
15800
+ return false;
15801
+ const basename = entry.split(/[\\/]/).pop() ?? "";
15802
+ const name = basename.replace(/\.(cmd|exe|ps1|bat|js|mjs|cjs)$/i, "").toLowerCase();
15803
+ return name === "contrib";
15804
+ }
17066
15805
 
17067
15806
  // src/ui/banner.ts
17068
- var LOGO_BIG;
17069
- try {
17070
- LOGO_BIG = nodeFiglet.textSync(`Contribute
17071
- Now`, { font: "ANSI Shadow" });
17072
- } catch {
17073
- LOGO_BIG = "Contribute Now";
17074
- }
17075
- var LOGO_SMALL;
17076
- try {
17077
- LOGO_SMALL = nodeFiglet.textSync("Contribute Now", { font: "Slant" });
17078
- } catch {
17079
- LOGO_SMALL = "Contribute Now";
17080
- }
15807
+ var LOGO = String.raw` ______ __ _ __ __ _ __
15808
+ / ____/___ ____ / /______(_) /_ __ __/ /____ / | / /___ _ __
15809
+ / / / __ \/ __ \/ __/ ___/ / __ \/ / / / __/ _ \ / |/ / __ \ | /| / /
15810
+ / /___/ /_/ / / / / /_/ / / / /_/ / /_/ / /_/ __/ / /| / /_/ / |/ |/ /
15811
+ \____/\____/_/ /_/\__/_/ /_/_.___/\__,_/\__/\___/ /_/ |_/\____/|__/|__/
15812
+ `;
17081
15813
  function getVersion() {
17082
15814
  return package_default.version ?? "unknown";
17083
15815
  }
@@ -17085,10 +15817,9 @@ function getAuthor() {
17085
15817
  return typeof package_default.author === "string" ? package_default.author : "unknown";
17086
15818
  }
17087
15819
  function showBanner(variant = "small") {
17088
- const logo = variant === "big" ? LOGO_BIG : LOGO_SMALL;
17089
- console.log(import_picocolors23.default.cyan(`
17090
- ${logo}`));
17091
- console.log(` ${import_picocolors23.default.dim(`v${getVersion()}`)} ${import_picocolors23.default.dim("\u2014")} ${import_picocolors23.default.dim(`Built by ${getAuthor()}`)}`);
15820
+ console.log(import_picocolors24.default.cyan(`
15821
+ ${LOGO}`));
15822
+ console.log(` ${import_picocolors24.default.dim(`v${getVersion()}`)} ${import_picocolors24.default.dim("\u2014")} ${import_picocolors24.default.dim(`Built by ${getAuthor()}`)}`);
17092
15823
  const announcements = getActiveAnnouncements();
17093
15824
  if (announcements.length > 0) {
17094
15825
  console.log();
@@ -17097,27 +15828,27 @@ ${logo}`));
17097
15828
  if (variant === "big") {
17098
15829
  const panelLines = [
17099
15830
  {
17100
- label: import_picocolors23.default.bold(import_picocolors23.default.cyan("Getting Started")),
15831
+ label: import_picocolors24.default.bold(import_picocolors24.default.cyan("Getting Started")),
17101
15832
  rawLabel: "Getting Started",
17102
15833
  value: "",
17103
15834
  rawValue: ""
17104
15835
  },
17105
15836
  {
17106
- label: import_picocolors23.default.cyan("cn setup"),
15837
+ label: import_picocolors24.default.cyan("cn setup"),
17107
15838
  rawLabel: "cn setup",
17108
- value: import_picocolors23.default.dim("configure workflow, remotes, and defaults"),
15839
+ value: import_picocolors24.default.dim("configure workflow, remotes, and defaults"),
17109
15840
  rawValue: "configure workflow, remotes, and defaults"
17110
15841
  },
17111
15842
  {
17112
- label: import_picocolors23.default.cyan("cn doctor"),
15843
+ label: import_picocolors24.default.cyan("cn doctor"),
17113
15844
  rawLabel: "cn doctor",
17114
- value: import_picocolors23.default.dim("verify your environment before doing any work"),
15845
+ value: import_picocolors24.default.dim("verify your environment before doing any work"),
17115
15846
  rawValue: "verify your environment before doing any work"
17116
15847
  },
17117
15848
  {
17118
- label: import_picocolors23.default.cyan("cn start"),
15849
+ label: import_picocolors24.default.cyan("cn start"),
17119
15850
  rawLabel: "cn start",
17120
- value: import_picocolors23.default.dim("create a branch and begin the next task"),
15851
+ value: import_picocolors24.default.dim("create a branch and begin the next task"),
17121
15852
  rawValue: "create a branch and begin the next task"
17122
15853
  },
17123
15854
  {
@@ -17127,13 +15858,13 @@ ${logo}`));
17127
15858
  rawValue: ""
17128
15859
  },
17129
15860
  {
17130
- label: import_picocolors23.default.bold(import_picocolors23.default.cyan("Workflow")),
15861
+ label: import_picocolors24.default.bold(import_picocolors24.default.cyan("Workflow")),
17131
15862
  rawLabel: "Workflow",
17132
15863
  value: "",
17133
15864
  rawValue: ""
17134
15865
  },
17135
15866
  {
17136
- label: import_picocolors23.default.dim("cn setup \u2192 cn commit \u2192 cn update \u2192 cn submit"),
15867
+ label: import_picocolors24.default.dim("cn setup \u2192 cn commit \u2192 cn update \u2192 cn submit"),
17137
15868
  rawLabel: "cn setup \u2192 cn commit \u2192 cn update \u2192 cn submit",
17138
15869
  value: "",
17139
15870
  rawValue: ""
@@ -17158,22 +15889,22 @@ ${logo}`));
17158
15889
  return Math.max(max, lineLength);
17159
15890
  }, 0));
17160
15891
  console.log();
17161
- console.log(` ${import_picocolors23.default.dim(`\u250C${"\u2500".repeat(contentWidth + 2)}\u2510`)}`);
15892
+ console.log(` ${import_picocolors24.default.dim(`\u250C${"\u2500".repeat(contentWidth + 2)}\u2510`)}`);
17162
15893
  for (const line of rows) {
17163
15894
  if (!line.rawLabel && !line.rawValue) {
17164
- console.log(` ${import_picocolors23.default.dim("\u2502")} ${" ".repeat(contentWidth)} ${import_picocolors23.default.dim("\u2502")}`);
15895
+ console.log(` ${import_picocolors24.default.dim("\u2502")} ${" ".repeat(contentWidth)} ${import_picocolors24.default.dim("\u2502")}`);
17165
15896
  continue;
17166
15897
  }
17167
15898
  const left = line.rawValue ? `${line.label}${" ".repeat(Math.max(0, labelWidth - line.rawLabel.length + 2))}` : line.label;
17168
- const value = line.rawValue ? import_picocolors23.default.dim(line.rawValue) : "";
15899
+ const value = line.rawValue ? import_picocolors24.default.dim(line.rawValue) : "";
17169
15900
  const rawLength = line.rawValue ? labelWidth + 2 + line.rawValue.length : line.rawLabel.length;
17170
15901
  const trailing = " ".repeat(Math.max(0, contentWidth - rawLength));
17171
- console.log(` ${import_picocolors23.default.dim("\u2502")} ${left}${value}${trailing} ${import_picocolors23.default.dim("\u2502")}`);
15902
+ console.log(` ${import_picocolors24.default.dim("\u2502")} ${left}${value}${trailing} ${import_picocolors24.default.dim("\u2502")}`);
17172
15903
  }
17173
- console.log(` ${import_picocolors23.default.dim(`\u2514${"\u2500".repeat(contentWidth + 2)}\u2518`)}`);
15904
+ console.log(` ${import_picocolors24.default.dim(`\u2514${"\u2500".repeat(contentWidth + 2)}\u2518`)}`);
17174
15905
  console.log();
17175
- console.log(` ${import_picocolors23.default.dim("Star or contribute:")} ${import_picocolors23.default.dim(linkify("gh.waren.build/contribute-now", "https://gh.waren.build/contribute-now"))}`);
17176
- console.log(` ${import_picocolors23.default.dim("Sponsor:")} ${import_picocolors23.default.dim(linkify("warengonzaga.com/sponsor", "https://warengonzaga.com/sponsor"))}`);
15906
+ console.log(` ${import_picocolors24.default.dim("Star or contribute:")} ${import_picocolors24.default.dim(linkify("gh.waren.build/contribute-now", "https://gh.waren.build/contribute-now"))}`);
15907
+ console.log(` ${import_picocolors24.default.dim("Sponsor:")} ${import_picocolors24.default.dim(linkify("warengonzaga.com/sponsor", "https://warengonzaga.com/sponsor"))}`);
17177
15908
  }
17178
15909
  console.log();
17179
15910
  }
@@ -17205,7 +15936,7 @@ function renderAnnouncementBanner(announcement) {
17205
15936
  console.log(` ${tone.border(`\u250C${"\u2500".repeat(rawWidth + 2)}\u2510`)}`);
17206
15937
  for (const line of lines) {
17207
15938
  const trailing = " ".repeat(Math.max(0, rawWidth - line.length));
17208
- const content = line === title ? tone.title(line) : import_picocolors23.default.dim(line);
15939
+ const content = line === title ? tone.title(line) : import_picocolors24.default.dim(line);
17209
15940
  console.log(` ${tone.border("\u2502")} ${content}${trailing} ${tone.border("\u2502")}`);
17210
15941
  }
17211
15942
  console.log(` ${tone.border(`\u2514${"\u2500".repeat(rawWidth + 2)}\u2518`)}`);
@@ -17241,20 +15972,20 @@ function getAnnouncementTone(kind) {
17241
15972
  case "info":
17242
15973
  return {
17243
15974
  emoji: "\u2139",
17244
- border: import_picocolors23.default.blue,
17245
- title: (value) => import_picocolors23.default.bold(import_picocolors23.default.blue(value))
15975
+ border: import_picocolors24.default.blue,
15976
+ title: (value) => import_picocolors24.default.bold(import_picocolors24.default.blue(value))
17246
15977
  };
17247
15978
  case "warning":
17248
15979
  return {
17249
15980
  emoji: "\uD83D\uDEA8",
17250
- border: import_picocolors23.default.red,
17251
- title: (value) => import_picocolors23.default.bold(import_picocolors23.default.red(value))
15981
+ border: import_picocolors24.default.red,
15982
+ title: (value) => import_picocolors24.default.bold(import_picocolors24.default.red(value))
17252
15983
  };
17253
15984
  default:
17254
15985
  return {
17255
15986
  emoji: "\u26A0",
17256
- border: import_picocolors23.default.yellow,
17257
- title: (value) => import_picocolors23.default.bold(import_picocolors23.default.yellow(value))
15987
+ border: import_picocolors24.default.yellow,
15988
+ title: (value) => import_picocolors24.default.bold(import_picocolors24.default.yellow(value))
17258
15989
  };
17259
15990
  }
17260
15991
  }
@@ -17285,6 +16016,7 @@ if (!isVersion) {
17285
16016
  "update",
17286
16017
  "submit",
17287
16018
  "switch",
16019
+ "discard",
17288
16020
  "save",
17289
16021
  "clean",
17290
16022
  "status",
@@ -17301,7 +16033,7 @@ if (!isVersion) {
17301
16033
  }
17302
16034
  var main = defineCommand({
17303
16035
  meta: {
17304
- name: "contrib",
16036
+ name: "cn",
17305
16037
  version: getVersion(),
17306
16038
  description: "Git workflow CLI that guides contributors through clean branching, commits, and PRs."
17307
16039
  },
@@ -17321,6 +16053,7 @@ var main = defineCommand({
17321
16053
  update: update_default,
17322
16054
  submit: submit_default,
17323
16055
  switch: switch_default,
16056
+ discard: discard_default,
17324
16057
  save: save_default,
17325
16058
  branch: branch_default,
17326
16059
  clean: clean_default,
@@ -17332,7 +16065,7 @@ var main = defineCommand({
17332
16065
  },
17333
16066
  run({ args }) {
17334
16067
  if (args.version) {
17335
- console.log(`contrib v${getVersion()}`);
16068
+ console.log(`cn v${getVersion()}`);
17336
16069
  }
17337
16070
  }
17338
16071
  });