contribute-now 0.7.2 → 0.7.3-dev.ed55e7b

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 (3) hide show
  1. package/README.md +67 -64
  2. package/dist/cli.js +474 -1739
  3. package/package.json +1 -3
package/dist/cli.js CHANGED
@@ -7540,6 +7540,9 @@ async function hasLocalWork(remote, branch) {
7540
7540
  async function deleteRemoteBranch(remote, branch) {
7541
7541
  return run(["push", remote, "--delete", branch]);
7542
7542
  }
7543
+ async function stashChanges(message) {
7544
+ return run(["stash", "push", "-m", `contrib-save: ${message}`]);
7545
+ }
7543
7546
  async function mergeSquash(branch) {
7544
7547
  return run(["merge", "--squash", branch]);
7545
7548
  }
@@ -10972,19 +10975,19 @@ async function checkCopilotAvailable2() {
10972
10975
  const aiConfig = resolveAIConfig();
10973
10976
  if (aiConfig.provider === "ollama-cloud") {
10974
10977
  if (!await hasOllamaCloudApiKey()) {
10975
- return "Ollama Cloud API key not found. Run `contrib setup` to save it.";
10978
+ return "Ollama Cloud API key not found. Run `cn setup` to save it.";
10976
10979
  }
10977
10980
  try {
10978
10981
  const apiKey = await getOllamaCloudApiKey();
10979
10982
  if (!apiKey) {
10980
- return "Ollama Cloud API key not found. Run `contrib setup` to save it.";
10983
+ return "Ollama Cloud API key not found. Run `cn setup` to save it.";
10981
10984
  }
10982
10985
  await fetchOllamaCloudModels(apiKey, aiConfig.host);
10983
10986
  return null;
10984
10987
  } catch (err) {
10985
10988
  const msg = err instanceof Error ? err.message : String(err);
10986
10989
  if (msg === "Ollama Cloud authentication failed") {
10987
- return "Ollama Cloud authentication failed. Update your saved API key with `contrib setup`.";
10990
+ return "Ollama Cloud authentication failed. Update your saved API key with `cn setup`.";
10988
10991
  }
10989
10992
  if (msg.startsWith("Ollama Cloud model lookup failed")) {
10990
10993
  return msg.replace("model lookup", "health check");
@@ -11877,7 +11880,7 @@ var clean_default = defineCommand({
11877
11880
  await assertCleanGitState("cleaning");
11878
11881
  const config = readConfig();
11879
11882
  if (!config) {
11880
- error("No repo config found. Run `contrib setup` first.");
11883
+ error("No repo config found. Run `cn setup` first.");
11881
11884
  process.exit(1);
11882
11885
  }
11883
11886
  const { origin } = config;
@@ -11983,13 +11986,121 @@ ${import_picocolors8.default.bold("Stale branches (remote deleted, likely squash
11983
11986
  const finalBranch = await getCurrentBranch();
11984
11987
  if (finalBranch && protectedBranches.has(finalBranch)) {
11985
11988
  console.log();
11986
- info(`You're on ${import_picocolors8.default.bold(finalBranch)}. Run ${import_picocolors8.default.bold("contrib start")} to begin a new feature.`);
11989
+ info(`You're on ${import_picocolors8.default.bold(finalBranch)}. Run ${import_picocolors8.default.bold("cn start")} to begin a new feature.`);
11987
11990
  }
11988
11991
  }
11989
11992
  });
11990
11993
 
11991
- // src/commands/commit.ts
11994
+ // src/commands/discard.ts
11992
11995
  var import_picocolors9 = __toESM(require_picocolors(), 1);
11996
+ var discard_default = defineCommand({
11997
+ meta: {
11998
+ name: "discard",
11999
+ description: "Discard the current feature branch and return to the base branch"
12000
+ },
12001
+ args: {
12002
+ force: {
12003
+ type: "boolean",
12004
+ alias: "f",
12005
+ description: "Skip confirmation and discard immediately",
12006
+ default: false
12007
+ }
12008
+ },
12009
+ async run({ args }) {
12010
+ if (!await isGitRepo()) {
12011
+ error("Not inside a git repository.");
12012
+ process.exit(1);
12013
+ }
12014
+ await assertCleanGitState("discarding a branch");
12015
+ const config = readConfig();
12016
+ if (!config) {
12017
+ error("No repo config found. Run `cn setup` first.");
12018
+ process.exit(1);
12019
+ }
12020
+ const currentBranch = await getCurrentBranch();
12021
+ const baseBranch = getBaseBranch(config);
12022
+ await projectHeading("discard", "\uD83D\uDDD1\uFE0F");
12023
+ if (isBranchProtected(currentBranch, config)) {
12024
+ error(`${import_picocolors9.default.bold(currentBranch)} is a protected branch and cannot be discarded.`);
12025
+ info(`Switch to a feature branch first, then run ${import_picocolors9.default.bold("cn discard")}.`);
12026
+ process.exit(1);
12027
+ }
12028
+ if (currentBranch === baseBranch) {
12029
+ info(`You are already on ${import_picocolors9.default.bold(baseBranch)}.`);
12030
+ process.exit(0);
12031
+ }
12032
+ const { origin } = config;
12033
+ const localWork = await hasLocalWork(origin, currentBranch);
12034
+ const hasWork = localWork.uncommitted || localWork.unpushedCommits > 0;
12035
+ if (hasWork) {
12036
+ if (localWork.uncommitted) {
12037
+ warn("You have uncommitted changes in your working tree.");
12038
+ }
12039
+ if (localWork.unpushedCommits > 0) {
12040
+ warn(`You have ${import_picocolors9.default.bold(String(localWork.unpushedCommits))} unpushed commit${localWork.unpushedCommits !== 1 ? "s" : ""} on this branch.`);
12041
+ }
12042
+ warn("Discarding this branch will permanently lose that work.");
12043
+ const SAVE_FIRST = "Save my changes first (cn save), then discard";
12044
+ const DISCARD_ANYWAY = "Discard anyway \u2014 I do not need this work";
12045
+ const CANCEL = "Keep the branch, take me back";
12046
+ const action = await selectPrompt("This branch has unsaved work. What would you like to do?", [SAVE_FIRST, DISCARD_ANYWAY, CANCEL]);
12047
+ if (action === CANCEL) {
12048
+ info("Discard cancelled. Your branch is untouched.");
12049
+ process.exit(0);
12050
+ }
12051
+ if (action === SAVE_FIRST) {
12052
+ if (!localWork.uncommitted) {
12053
+ info("No uncommitted changes to stash \u2014 unpushed commits will still be lost.");
12054
+ const confirm = await confirmPrompt("Continue discarding the branch?");
12055
+ if (!confirm) {
12056
+ info("Discard cancelled.");
12057
+ process.exit(0);
12058
+ }
12059
+ } else {
12060
+ const stashResult = await stashChanges(`work-in-progress on ${currentBranch}`);
12061
+ if (stashResult.exitCode !== 0) {
12062
+ error(`Failed to save changes: ${stashResult.stderr}`);
12063
+ process.exit(1);
12064
+ }
12065
+ success(`Changes saved. Use ${import_picocolors9.default.bold("cn save --restore")} to bring them back.`);
12066
+ }
12067
+ }
12068
+ } else if (!args.force) {
12069
+ const confirmed = await confirmPrompt(`Discard ${import_picocolors9.default.bold(currentBranch)} and return to ${import_picocolors9.default.bold(baseBranch)}?`);
12070
+ if (!confirmed) {
12071
+ info("Discard cancelled.");
12072
+ process.exit(0);
12073
+ }
12074
+ }
12075
+ const upstreamRef = await getUpstreamRef();
12076
+ let deleteRemote = false;
12077
+ if (upstreamRef) {
12078
+ deleteRemote = await confirmPrompt(`Also delete the remote branch ${import_picocolors9.default.bold(upstreamRef)}?`);
12079
+ }
12080
+ const checkoutResult = await checkoutBranch(baseBranch);
12081
+ if (checkoutResult.exitCode !== 0) {
12082
+ error(`Failed to switch to ${import_picocolors9.default.bold(baseBranch)}: ${checkoutResult.stderr}`);
12083
+ process.exit(1);
12084
+ }
12085
+ const deleteResult = await forceDeleteBranch(currentBranch);
12086
+ if (deleteResult.exitCode !== 0) {
12087
+ error(`Failed to delete branch ${import_picocolors9.default.bold(currentBranch)}: ${deleteResult.stderr}`);
12088
+ process.exit(1);
12089
+ }
12090
+ success(`Discarded ${import_picocolors9.default.bold(currentBranch)} and switched back to ${import_picocolors9.default.bold(baseBranch)}`);
12091
+ if (deleteRemote) {
12092
+ const remoteDeleteResult = await deleteRemoteBranch(origin, currentBranch);
12093
+ if (remoteDeleteResult.exitCode !== 0) {
12094
+ warn(`Could not delete remote branch: ${remoteDeleteResult.stderr.trim()}`);
12095
+ } else {
12096
+ success(`Deleted remote branch ${import_picocolors9.default.bold(`${origin}/${currentBranch}`)}`);
12097
+ }
12098
+ }
12099
+ }
12100
+ });
12101
+
12102
+ // src/commands/commit.ts
12103
+ var import_picocolors10 = __toESM(require_picocolors(), 1);
11993
12104
 
11994
12105
  // src/utils/convention.ts
11995
12106
  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 +12186,7 @@ var commit_default = defineCommand({
12075
12186
  await assertCleanGitState("committing");
12076
12187
  const config = readConfig();
12077
12188
  if (!config) {
12078
- error("No repo config found. Run `contrib setup` first.");
12189
+ error("No repo config found. Run `cn setup` first.");
12079
12190
  process.exit(1);
12080
12191
  }
12081
12192
  await projectHeading("commit", "\uD83D\uDCBE");
@@ -12096,9 +12207,9 @@ var commit_default = defineCommand({
12096
12207
  process.exit(1);
12097
12208
  }
12098
12209
  console.log(`
12099
- ${import_picocolors9.default.bold("Changed files:")}`);
12210
+ ${import_picocolors10.default.bold("Changed files:")}`);
12100
12211
  for (const f3 of changedFiles) {
12101
- console.log(` ${import_picocolors9.default.dim("\u2022")} ${f3}`);
12212
+ console.log(` ${import_picocolors10.default.dim("\u2022")} ${f3}`);
12102
12213
  }
12103
12214
  const stageAction = await selectPrompt("No staged changes. How would you like to stage?", [
12104
12215
  "Stage all changes",
@@ -12140,8 +12251,8 @@ ${import_picocolors9.default.bold("Changed files:")}`);
12140
12251
  const dirs = new Set(stagedFiles.map((f3) => f3.split("/")[0]));
12141
12252
  if (dirs.size > 1) {
12142
12253
  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."));
12254
+ 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.`);
12255
+ 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
12256
  const choice = await selectPrompt("How would you like to proceed?", [
12146
12257
  "Continue as single commit",
12147
12258
  "Switch to group mode (AI splits into atomic commits)",
@@ -12172,7 +12283,7 @@ ${import_picocolors9.default.bold("Changed files:")}`);
12172
12283
  if (commitMessage) {
12173
12284
  spinner.success("AI commit message generated.");
12174
12285
  console.log(`
12175
- ${import_picocolors9.default.dim("AI suggestion:")} ${import_picocolors9.default.bold(import_picocolors9.default.cyan(commitMessage))}`);
12286
+ ${import_picocolors10.default.dim("AI suggestion:")} ${import_picocolors10.default.bold(import_picocolors10.default.cyan(commitMessage))}`);
12176
12287
  } else {
12177
12288
  spinner.fail("AI did not return a commit message.");
12178
12289
  warn("Falling back to manual entry.");
@@ -12200,7 +12311,7 @@ ${import_picocolors9.default.bold("Changed files:")}`);
12200
12311
  if (regen) {
12201
12312
  spinner.success("Commit message regenerated.");
12202
12313
  console.log(`
12203
- ${import_picocolors9.default.dim("AI suggestion:")} ${import_picocolors9.default.bold(import_picocolors9.default.cyan(regen))}`);
12314
+ ${import_picocolors10.default.dim("AI suggestion:")} ${import_picocolors10.default.bold(import_picocolors10.default.cyan(regen))}`);
12204
12315
  const ok = await confirmPrompt("Use this message?");
12205
12316
  finalMessage = ok ? regen : await inputPrompt("Enter commit message manually");
12206
12317
  } else {
@@ -12215,7 +12326,7 @@ ${import_picocolors9.default.bold("Changed files:")}`);
12215
12326
  if (convention2 !== "none") {
12216
12327
  console.log();
12217
12328
  for (const hint of CONVENTION_FORMAT_HINTS[convention2]) {
12218
- console.log(import_picocolors9.default.dim(hint));
12329
+ console.log(import_picocolors10.default.dim(hint));
12219
12330
  }
12220
12331
  console.log();
12221
12332
  }
@@ -12239,7 +12350,7 @@ ${import_picocolors9.default.bold("Changed files:")}`);
12239
12350
  error(`Failed to commit: ${result.stderr}`);
12240
12351
  process.exit(1);
12241
12352
  }
12242
- success(`Committed: ${import_picocolors9.default.bold(finalMessage)}`);
12353
+ success(`Committed: ${import_picocolors10.default.bold(finalMessage)}`);
12243
12354
  }
12244
12355
  });
12245
12356
  async function runGroupCommit(model, config) {
@@ -12256,9 +12367,9 @@ async function runGroupCommit(model, config) {
12256
12367
  process.exit(1);
12257
12368
  }
12258
12369
  console.log(`
12259
- ${import_picocolors9.default.bold("Changed files:")}`);
12370
+ ${import_picocolors10.default.bold("Changed files:")}`);
12260
12371
  for (const f3 of changedFiles) {
12261
- console.log(` ${import_picocolors9.default.dim("\u2022")} ${f3}`);
12372
+ console.log(` ${import_picocolors10.default.dim("\u2022")} ${f3}`);
12262
12373
  }
12263
12374
  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
12375
  tips: LOADING_TIPS
@@ -12304,13 +12415,13 @@ ${import_picocolors9.default.bold("Changed files:")}`);
12304
12415
  let commitAll = false;
12305
12416
  while (!proceedToCommit) {
12306
12417
  console.log(`
12307
- ${import_picocolors9.default.bold(`AI suggested ${validGroups.length} commit group(s):`)}
12418
+ ${import_picocolors10.default.bold(`AI suggested ${validGroups.length} commit group(s):`)}
12308
12419
  `);
12309
12420
  for (let i2 = 0;i2 < validGroups.length; i2++) {
12310
12421
  const g3 = validGroups[i2];
12311
- console.log(` ${import_picocolors9.default.cyan(`Group ${i2 + 1}:`)} ${import_picocolors9.default.bold(g3.message)}`);
12422
+ console.log(` ${import_picocolors10.default.cyan(`Group ${i2 + 1}:`)} ${import_picocolors10.default.bold(g3.message)}`);
12312
12423
  for (const f3 of g3.files) {
12313
- console.log(` ${import_picocolors9.default.dim("\u2022")} ${f3}`);
12424
+ console.log(` ${import_picocolors10.default.dim("\u2022")} ${f3}`);
12314
12425
  }
12315
12426
  console.log();
12316
12427
  }
@@ -12376,16 +12487,16 @@ ${import_picocolors9.default.bold(`AI suggested ${validGroups.length} commit gro
12376
12487
  continue;
12377
12488
  }
12378
12489
  committed++;
12379
- success(`Committed group ${i2 + 1}: ${import_picocolors9.default.bold(group.message)}`);
12490
+ success(`Committed group ${i2 + 1}: ${import_picocolors10.default.bold(group.message)}`);
12380
12491
  }
12381
12492
  } else {
12382
12493
  for (let i2 = 0;i2 < validGroups.length; i2++) {
12383
12494
  const group = validGroups[i2];
12384
- console.log(import_picocolors9.default.bold(`
12495
+ console.log(import_picocolors10.default.bold(`
12385
12496
  \u2500\u2500 Group ${i2 + 1}/${validGroups.length} \u2500\u2500`));
12386
- console.log(` ${import_picocolors9.default.cyan(group.message)}`);
12497
+ console.log(` ${import_picocolors10.default.cyan(group.message)}`);
12387
12498
  for (const f3 of group.files) {
12388
- console.log(` ${import_picocolors9.default.dim("\u2022")} ${f3}`);
12499
+ console.log(` ${import_picocolors10.default.dim("\u2022")} ${f3}`);
12389
12500
  }
12390
12501
  let message = group.message;
12391
12502
  let actionDone = false;
@@ -12409,7 +12520,7 @@ ${import_picocolors9.default.bold(`AI suggested ${validGroups.length} commit gro
12409
12520
  if (newMsg) {
12410
12521
  message = newMsg;
12411
12522
  group.message = newMsg;
12412
- regenSpinner.success(`New message: ${import_picocolors9.default.bold(message)}`);
12523
+ regenSpinner.success(`New message: ${import_picocolors10.default.bold(message)}`);
12413
12524
  } else {
12414
12525
  regenSpinner.fail("AI could not generate a new message. Keeping current one.");
12415
12526
  }
@@ -12472,7 +12583,7 @@ ${import_picocolors9.default.bold(`AI suggested ${validGroups.length} commit gro
12472
12583
  continue;
12473
12584
  }
12474
12585
  committed++;
12475
- success(`Committed group ${i2 + 1}: ${import_picocolors9.default.bold(message)}`);
12586
+ success(`Committed group ${i2 + 1}: ${import_picocolors10.default.bold(message)}`);
12476
12587
  actionDone = true;
12477
12588
  }
12478
12589
  }
@@ -12487,7 +12598,7 @@ ${import_picocolors9.default.bold(`AI suggested ${validGroups.length} commit gro
12487
12598
  }
12488
12599
 
12489
12600
  // src/commands/config.ts
12490
- var import_picocolors10 = __toESM(require_picocolors(), 1);
12601
+ var import_picocolors11 = __toESM(require_picocolors(), 1);
12491
12602
  var WORKFLOW_OPTIONS = [
12492
12603
  { value: "clean-flow", label: WORKFLOW_DESCRIPTIONS["clean-flow"] },
12493
12604
  { value: "github-flow", label: WORKFLOW_DESCRIPTIONS["github-flow"] },
@@ -12703,7 +12814,7 @@ async function applyOllamaApiKeyEdit(result) {
12703
12814
  if (result.ollamaApiKeyAction === "set" && result.ollamaApiKey) {
12704
12815
  await setOllamaCloudApiKey(result.ollamaApiKey);
12705
12816
  success("Stored Ollama Cloud API key in the local secrets store.");
12706
- info(`Secrets path: ${import_picocolors10.default.bold(getSecretsStorePath())}`);
12817
+ info(`Secrets path: ${import_picocolors11.default.bold(getSecretsStorePath())}`);
12707
12818
  return;
12708
12819
  }
12709
12820
  if (result.ollamaApiKeyAction === "delete") {
@@ -12716,29 +12827,29 @@ async function applyOllamaApiKeyEdit(result) {
12716
12827
  }
12717
12828
  }
12718
12829
  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)}`);
12830
+ info(`Config source: ${import_picocolors11.default.bold(snapshot.source)}`);
12831
+ info(`Config path: ${import_picocolors11.default.bold(snapshot.location)}`);
12832
+ info(`Workflow: ${import_picocolors11.default.bold(snapshot.workflowLabel)}`);
12833
+ info(`Convention: ${import_picocolors11.default.bold(snapshot.commitConventionLabel)}`);
12834
+ info(`Role: ${import_picocolors11.default.bold(snapshot.role)}`);
12724
12835
  if (snapshot.devBranch) {
12725
- info(`Main: ${import_picocolors10.default.bold(snapshot.mainBranch)} | Dev: ${import_picocolors10.default.bold(snapshot.devBranch)}`);
12836
+ info(`Main: ${import_picocolors11.default.bold(snapshot.mainBranch)} | Dev: ${import_picocolors11.default.bold(snapshot.devBranch)}`);
12726
12837
  } else {
12727
- info(`Main: ${import_picocolors10.default.bold(snapshot.mainBranch)}`);
12838
+ info(`Main: ${import_picocolors11.default.bold(snapshot.mainBranch)}`);
12728
12839
  }
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")}`);
12840
+ info(`Origin: ${import_picocolors11.default.bold(snapshot.origin)} | Upstream: ${import_picocolors11.default.bold(snapshot.upstream)}`);
12841
+ info(`Branch prefixes: ${import_picocolors11.default.bold(snapshot.branchPrefixes.join(", "))}`);
12842
+ info(`Guides: ${import_picocolors11.default.bold(snapshot.showTips ? "shown" : "hidden")}`);
12843
+ info(`AI: ${import_picocolors11.default.bold(snapshot.ai.enabled ? "enabled" : "disabled")}`);
12733
12844
  if (snapshot.ai.enabled && snapshot.ai.providerLabel) {
12734
- info(`AI provider: ${import_picocolors10.default.bold(snapshot.ai.providerLabel)}`);
12845
+ info(`AI provider: ${import_picocolors11.default.bold(snapshot.ai.providerLabel)}`);
12735
12846
  if (snapshot.ai.model) {
12736
- info(`AI model: ${import_picocolors10.default.bold(snapshot.ai.model)}`);
12847
+ info(`AI model: ${import_picocolors11.default.bold(snapshot.ai.model)}`);
12737
12848
  }
12738
12849
  if (snapshot.ai.provider === "ollama-cloud") {
12739
- info(`Ollama Cloud API key: ${import_picocolors10.default.bold(snapshot.ai.ollamaCloudApiKeyPresent ? "stored" : "missing")}`);
12850
+ info(`Ollama Cloud API key: ${import_picocolors11.default.bold(snapshot.ai.ollamaCloudApiKeyPresent ? "stored" : "missing")}`);
12740
12851
  if (snapshot.ai.secretsPath) {
12741
- info(`Secrets path: ${import_picocolors10.default.bold(snapshot.ai.secretsPath)}`);
12852
+ info(`Secrets path: ${import_picocolors11.default.bold(snapshot.ai.secretsPath)}`);
12742
12853
  }
12743
12854
  }
12744
12855
  }
@@ -12771,12 +12882,12 @@ var config_default = defineCommand({
12771
12882
  }
12772
12883
  await projectHeading("config", "\u2699\uFE0F");
12773
12884
  if (!configExists()) {
12774
- error("No repo config found. Run `contrib setup` first.");
12885
+ error("No repo config found. Run `cn setup` first.");
12775
12886
  process.exit(1);
12776
12887
  }
12777
12888
  const config = readConfig();
12778
12889
  if (!config) {
12779
- error("Repo config exists but is invalid. Run `contrib setup` to repair it.");
12890
+ error("Repo config exists but is invalid. Run `cn setup` to repair it.");
12780
12891
  process.exit(1);
12781
12892
  }
12782
12893
  const source = getConfigSource();
@@ -12814,18 +12925,18 @@ var config_default = defineCommand({
12814
12925
  }
12815
12926
  printConfigSummary(snapshot);
12816
12927
  console.log();
12817
- console.log(` ${import_picocolors10.default.dim("Run `contrib config --edit` to update these settings.")}`);
12928
+ console.log(` ${import_picocolors11.default.dim("Run `cn config --edit` to update these settings.")}`);
12818
12929
  console.log();
12819
12930
  }
12820
12931
  });
12821
12932
 
12822
12933
  // src/commands/doctor.ts
12823
12934
  import { execFile as execFileCb3 } from "child_process";
12824
- var import_picocolors11 = __toESM(require_picocolors(), 1);
12935
+ var import_picocolors12 = __toESM(require_picocolors(), 1);
12825
12936
  // package.json
12826
12937
  var package_default = {
12827
12938
  name: "contribute-now",
12828
- version: "0.7.2",
12939
+ version: "0.7.3-dev.ed55e7b",
12829
12940
  description: "Developer CLI that automates git workflows \u2014 branching, syncing, committing, and PRs \u2014 with multi-workflow and commit convention support.",
12830
12941
  type: "module",
12831
12942
  bin: {
@@ -12874,13 +12985,11 @@ var package_default = {
12874
12985
  "@github/copilot-sdk": "^0.1.25",
12875
12986
  "@wgtechlabs/log-engine": "^2.3.1",
12876
12987
  citty: "^0.1.6",
12877
- figlet: "^1.10.0",
12878
12988
  picocolors: "^1.1.1"
12879
12989
  },
12880
12990
  devDependencies: {
12881
12991
  "@biomejs/biome": "^2.4.4",
12882
12992
  "@types/bun": "latest",
12883
- "@types/figlet": "^1.7.0",
12884
12993
  typescript: "^5.7.0"
12885
12994
  }
12886
12995
  };
@@ -12915,16 +13024,16 @@ async function getRepoInfoFromRemote(remote = "origin") {
12915
13024
  }
12916
13025
 
12917
13026
  // 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")} `;
13027
+ var PASS = ` ${import_picocolors12.default.green("\u2714")} `;
13028
+ var FAIL = ` ${import_picocolors12.default.red("\u2717")} `;
13029
+ var WARN = ` ${import_picocolors12.default.yellow("\u26A0")} `;
12921
13030
  function printReport(report) {
12922
13031
  for (const section of report.sections) {
12923
13032
  console.log(`
12924
- ${import_picocolors11.default.bold(import_picocolors11.default.underline(section.title))}`);
13033
+ ${import_picocolors12.default.bold(import_picocolors12.default.underline(section.title))}`);
12925
13034
  for (const check of section.checks) {
12926
13035
  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;
13036
+ const text = check.detail ? `${check.label} ${import_picocolors12.default.dim(`\u2014 ${check.detail}`)}` : check.label;
12928
13037
  console.log(`${prefix}${text}`);
12929
13038
  }
12930
13039
  }
@@ -12954,7 +13063,7 @@ function runCmd(cmd, args) {
12954
13063
  async function toolSection() {
12955
13064
  const checks = [];
12956
13065
  checks.push({
12957
- label: `contrib v${package_default.version ?? "unknown"}`,
13066
+ label: `cn v${package_default.version ?? "unknown"}`,
12958
13067
  ok: true
12959
13068
  });
12960
13069
  const runtime = typeof globalThis.Bun !== "undefined" ? `Bun ${globalThis.Bun.version ?? "?"}` : `Node ${process.version}`;
@@ -13009,7 +13118,7 @@ async function configSection() {
13009
13118
  checks.push({
13010
13119
  label: "Repo config not found",
13011
13120
  ok: false,
13012
- detail: "run `contrib setup` to create local config for this clone"
13121
+ detail: "run `cn setup` to create local config for this clone"
13013
13122
  });
13014
13123
  if (localStateLabel) {
13015
13124
  checks.push({
@@ -13077,7 +13186,7 @@ async function configSection() {
13077
13186
  label: hasApiKey ? "Ollama Cloud API key present" : "Ollama Cloud API key missing",
13078
13187
  ok: true,
13079
13188
  warning: !hasApiKey,
13080
- detail: hasSecretsStore() ? "stored in the local secrets store" : "run `contrib setup` to save it"
13189
+ detail: hasSecretsStore() ? "stored in the local secrets store" : "run `cn setup` to save it"
13081
13190
  });
13082
13191
  }
13083
13192
  }
@@ -13186,7 +13295,7 @@ async function workflowSection() {
13186
13295
  checks.push({
13187
13296
  label: "Cannot resolve workflow (no config)",
13188
13297
  ok: false,
13189
- detail: "run `contrib setup` first"
13298
+ detail: "run `cn setup` first"
13190
13299
  });
13191
13300
  return { title: "Workflow Resolution", checks };
13192
13301
  }
@@ -13256,14 +13365,14 @@ var doctor_default = defineCommand({
13256
13365
  const failures = total.filter((c3) => !c3.ok);
13257
13366
  const warnings = total.filter((c3) => c3.ok && c3.warning);
13258
13367
  if (failures.length === 0 && warnings.length === 0) {
13259
- console.log(` ${import_picocolors11.default.green("All checks passed!")} No issues detected.
13368
+ console.log(` ${import_picocolors12.default.green("All checks passed!")} No issues detected.
13260
13369
  `);
13261
13370
  } else {
13262
13371
  if (failures.length > 0) {
13263
- console.log(` ${import_picocolors11.default.red(`${failures.length} issue${failures.length !== 1 ? "s" : ""} found.`)}`);
13372
+ console.log(` ${import_picocolors12.default.red(`${failures.length} issue${failures.length !== 1 ? "s" : ""} found.`)}`);
13264
13373
  }
13265
13374
  if (warnings.length > 0) {
13266
- console.log(` ${import_picocolors11.default.yellow(`${warnings.length} warning${warnings.length !== 1 ? "s" : ""}.`)}`);
13375
+ console.log(` ${import_picocolors12.default.yellow(`${warnings.length} warning${warnings.length !== 1 ? "s" : ""}.`)}`);
13267
13376
  }
13268
13377
  console.log();
13269
13378
  }
@@ -13273,7 +13382,7 @@ var doctor_default = defineCommand({
13273
13382
  // src/commands/hook.ts
13274
13383
  import { existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync5, rmSync as rmSync2, writeFileSync as writeFileSync5 } from "fs";
13275
13384
  import { join as join6 } from "path";
13276
- var import_picocolors12 = __toESM(require_picocolors(), 1);
13385
+ var import_picocolors13 = __toESM(require_picocolors(), 1);
13277
13386
  var HOOK_MARKER = "# managed by contribute-now";
13278
13387
  function getHooksDir(cwd = process.cwd()) {
13279
13388
  return join6(cwd, ".git", "hooks");
@@ -13285,8 +13394,8 @@ function generateHookScript() {
13285
13394
  return `#!/bin/sh
13286
13395
  ${HOOK_MARKER}
13287
13396
  # Validates commit messages against your configured convention.
13288
- # Install: contrib hook install
13289
- # Uninstall: contrib hook uninstall
13397
+ # Install: cn hook install
13398
+ # Uninstall: cn hook uninstall
13290
13399
 
13291
13400
  commit_msg_file="$1"
13292
13401
  commit_msg=$(head -1 "$commit_msg_file")
@@ -13297,12 +13406,12 @@ case "$commit_msg" in
13297
13406
  esac
13298
13407
 
13299
13408
  # Detect available package runner
13300
- if command -v contrib >/dev/null 2>&1; then
13301
- contrib validate --file "$commit_msg_file"
13409
+ if command -v cn >/dev/null 2>&1; then
13410
+ cn validate --file "$commit_msg_file"
13302
13411
  elif command -v bunx >/dev/null 2>&1; then
13303
- bunx contrib validate --file "$commit_msg_file"
13412
+ bunx cn validate --file "$commit_msg_file"
13304
13413
  else
13305
- echo "Warning: Neither contrib nor bunx is available. Skipping commit message validation."
13414
+ echo "Warning: Neither cn nor bunx is available. Skipping commit message validation."
13306
13415
  exit 0
13307
13416
  fi
13308
13417
  `;
@@ -13340,12 +13449,12 @@ async function installHook() {
13340
13449
  await projectHeading("hook install", "\uD83E\uDE9D");
13341
13450
  const config = readConfig();
13342
13451
  if (!config) {
13343
- error("No repo config found. Run `contrib setup` first.");
13452
+ error("No repo config found. Run `cn setup` first.");
13344
13453
  process.exit(1);
13345
13454
  }
13346
13455
  if (config.commitConvention === "none") {
13347
13456
  warn('Commit convention is set to "none". No hook to install.');
13348
- info("Change your convention with `contrib setup` first.", "");
13457
+ info("Change your convention with `cn setup` first.", "");
13349
13458
  process.exit(0);
13350
13459
  }
13351
13460
  const hookPath = getHookPath();
@@ -13365,8 +13474,8 @@ async function installHook() {
13365
13474
  }
13366
13475
  writeFileSync5(hookPath, generateHookScript(), { mode: 493 });
13367
13476
  success(`commit-msg hook installed.`);
13368
- info(`Convention: ${import_picocolors12.default.bold(CONVENTION_LABELS[config.commitConvention])}`, "");
13369
- info(`Path: ${import_picocolors12.default.dim(hookPath)}`, "");
13477
+ info(`Convention: ${import_picocolors13.default.bold(CONVENTION_LABELS[config.commitConvention])}`, "");
13478
+ info(`Path: ${import_picocolors13.default.dim(hookPath)}`, "");
13370
13479
  warn("Note: hooks can be bypassed with `git commit --no-verify`.");
13371
13480
  }
13372
13481
  async function uninstallHook() {
@@ -13386,7 +13495,7 @@ async function uninstallHook() {
13386
13495
  }
13387
13496
 
13388
13497
  // src/commands/log.ts
13389
- var import_picocolors13 = __toESM(require_picocolors(), 1);
13498
+ var import_picocolors14 = __toESM(require_picocolors(), 1);
13390
13499
  function getDefaultOverviewRemoteCommitCount(hasLocalUnpushedCommits) {
13391
13500
  return hasLocalUnpushedCommits ? 10 : 20;
13392
13501
  }
@@ -13484,9 +13593,9 @@ var log_default = defineCommand({
13484
13593
  } else if (mode === "local") {
13485
13594
  if (!compareRef) {
13486
13595
  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.`));
13596
+ console.log(import_picocolors14.default.yellow(" \u26A0 Could not determine a comparison branch."));
13597
+ console.log(import_picocolors14.default.dim(" No upstream tracking set and no remote base branch found."));
13598
+ console.log(import_picocolors14.default.dim(` Use ${import_picocolors14.default.bold("cn log --full")} to see the full commit history instead.`));
13490
13599
  console.log();
13491
13600
  return;
13492
13601
  }
@@ -13505,8 +13614,8 @@ var log_default = defineCommand({
13505
13614
  const remoteBranch = compareRef ?? targetBranch;
13506
13615
  if (!remoteBranch) {
13507
13616
  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."));
13617
+ console.log(import_picocolors14.default.yellow(" \u26A0 Could not determine a remote branch to display."));
13618
+ console.log(import_picocolors14.default.dim(" Set an upstream tracking branch or configure your base branch first."));
13510
13619
  console.log();
13511
13620
  return;
13512
13621
  }
@@ -13565,31 +13674,31 @@ async function getOverviewRemoteCommitCount(currentBranch, compareRef) {
13565
13674
  }
13566
13675
  function printModeHeader(mode, currentBranch, compareRef, usingFallback = false) {
13567
13676
  const branch = currentBranch ?? "HEAD";
13568
- const fallbackNote = usingFallback ? import_picocolors13.default.yellow(" (no upstream \u2014 comparing against base branch)") : "";
13677
+ const fallbackNote = usingFallback ? import_picocolors14.default.yellow(" (no upstream \u2014 comparing against base branch)") : "";
13569
13678
  switch (mode) {
13570
13679
  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);
13680
+ 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
13681
  if (compareRef) {
13573
- console.log(import_picocolors13.default.dim(` remote source: ${import_picocolors13.default.bold(compareRef)}`));
13682
+ console.log(import_picocolors14.default.dim(` remote source: ${import_picocolors14.default.bold(compareRef)}`));
13574
13683
  }
13575
13684
  break;
13576
13685
  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);
13686
+ console.log(import_picocolors14.default.dim(` mode: ${import_picocolors14.default.bold("local")} \u2014 unpushed commits on ${import_picocolors14.default.bold(branch)}`) + fallbackNote);
13578
13687
  if (compareRef) {
13579
- console.log(import_picocolors13.default.dim(` comparing: ${import_picocolors13.default.bold(compareRef)} \u279C ${import_picocolors13.default.bold("HEAD")}`));
13688
+ console.log(import_picocolors14.default.dim(` comparing: ${import_picocolors14.default.bold(compareRef)} \u279C ${import_picocolors14.default.bold("HEAD")}`));
13580
13689
  }
13581
13690
  break;
13582
13691
  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);
13692
+ 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
13693
  if (compareRef) {
13585
- console.log(import_picocolors13.default.dim(` branch: ${import_picocolors13.default.bold(compareRef)}`));
13694
+ console.log(import_picocolors14.default.dim(` branch: ${import_picocolors14.default.bold(compareRef)}`));
13586
13695
  }
13587
13696
  break;
13588
13697
  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)}`));
13698
+ console.log(import_picocolors14.default.dim(` mode: ${import_picocolors14.default.bold("full")} \u2014 complete commit history for ${import_picocolors14.default.bold(branch)}`));
13590
13699
  break;
13591
13700
  case "all":
13592
- console.log(import_picocolors13.default.dim(` mode: ${import_picocolors13.default.bold("all")} \u2014 commits across all branches`));
13701
+ console.log(import_picocolors14.default.dim(` mode: ${import_picocolors14.default.bold("all")} \u2014 commits across all branches`));
13593
13702
  break;
13594
13703
  }
13595
13704
  }
@@ -13613,7 +13722,7 @@ async function renderScopedLog(options) {
13613
13722
  }
13614
13723
  console.log();
13615
13724
  for (const entry of entries) {
13616
- const hashStr = import_picocolors13.default.yellow(entry.hash);
13725
+ const hashStr = import_picocolors14.default.yellow(entry.hash);
13617
13726
  const refsStr = entry.refs ? ` ${colorizeRefs(entry.refs, protectedBranches, currentBranch)}` : "";
13618
13727
  const subjectStr = colorizeSubject(entry.subject);
13619
13728
  console.log(` ${hashStr}${refsStr} ${subjectStr}`);
@@ -13632,10 +13741,10 @@ async function renderOverviewLog(options) {
13632
13741
  usingFallback
13633
13742
  } = options;
13634
13743
  console.log();
13635
- console.log(import_picocolors13.default.bold(import_picocolors13.default.cyan(" Local Unpushed Commits")));
13744
+ console.log(import_picocolors14.default.bold(import_picocolors14.default.cyan(" Local Unpushed Commits")));
13636
13745
  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."));
13746
+ console.log(import_picocolors14.default.dim(" No comparison branch detected for local commit status."));
13747
+ console.log(import_picocolors14.default.dim(" Set an upstream tracking branch or run cn log --full to inspect the current branch history."));
13639
13748
  } else {
13640
13749
  await renderScopedLog({
13641
13750
  mode: "local",
@@ -13647,11 +13756,11 @@ async function renderOverviewLog(options) {
13647
13756
  });
13648
13757
  }
13649
13758
  console.log();
13650
- console.log(import_picocolors13.default.bold(import_picocolors13.default.cyan(" Remote Branch History")));
13759
+ console.log(import_picocolors14.default.bold(import_picocolors14.default.cyan(" Remote Branch History")));
13651
13760
  if (!compareRef) {
13652
- console.log(import_picocolors13.default.dim(" No remote branch detected."));
13761
+ console.log(import_picocolors14.default.dim(" No remote branch detected."));
13653
13762
  if (usingFallback) {
13654
- console.log(import_picocolors13.default.dim(" Configure your base branch or upstream tracking to enable the split view."));
13763
+ console.log(import_picocolors14.default.dim(" Configure your base branch or upstream tracking to enable the split view."));
13655
13764
  }
13656
13765
  return;
13657
13766
  }
@@ -13664,15 +13773,15 @@ async function renderOverviewLog(options) {
13664
13773
  currentBranch
13665
13774
  });
13666
13775
  if (!hasRemoteHistory) {
13667
- console.log(import_picocolors13.default.dim(" No remote history found for the selected branch."));
13776
+ console.log(import_picocolors14.default.dim(" No remote history found for the selected branch."));
13668
13777
  }
13669
13778
  }
13670
13779
  function printEmptyState(mode) {
13671
13780
  console.log();
13672
13781
  if (mode === "local") {
13673
- console.log(import_picocolors13.default.dim(" No local unpushed commits \u2014 you're up to date with remote!"));
13782
+ console.log(import_picocolors14.default.dim(" No local unpushed commits \u2014 you're up to date with remote!"));
13674
13783
  } else {
13675
- console.log(import_picocolors13.default.dim(" No remote-only commits \u2014 your local branch is up to date!"));
13784
+ console.log(import_picocolors14.default.dim(" No remote-only commits \u2014 your local branch is up to date!"));
13676
13785
  }
13677
13786
  console.log();
13678
13787
  }
@@ -13681,7 +13790,7 @@ async function renderFullLog(options) {
13681
13790
  if (showGraph) {
13682
13791
  const lines = await getLogGraph({ count, all, branch: targetBranch });
13683
13792
  if (lines.length === 0) {
13684
- console.log(import_picocolors13.default.dim(" No commits found."));
13793
+ console.log(import_picocolors14.default.dim(" No commits found."));
13685
13794
  console.log();
13686
13795
  return false;
13687
13796
  }
@@ -13692,13 +13801,13 @@ async function renderFullLog(options) {
13692
13801
  } else {
13693
13802
  const entries = await getLogEntries({ count, all, branch: targetBranch });
13694
13803
  if (entries.length === 0) {
13695
- console.log(import_picocolors13.default.dim(" No commits found."));
13804
+ console.log(import_picocolors14.default.dim(" No commits found."));
13696
13805
  console.log();
13697
13806
  return false;
13698
13807
  }
13699
13808
  console.log();
13700
13809
  for (const entry of entries) {
13701
- const hashStr = import_picocolors13.default.yellow(entry.hash);
13810
+ const hashStr = import_picocolors14.default.yellow(entry.hash);
13702
13811
  const refsStr = entry.refs ? ` ${colorizeRefs(entry.refs, protectedBranches, currentBranch)}` : "";
13703
13812
  const subjectStr = colorizeSubject(entry.subject);
13704
13813
  console.log(` ${hashStr}${refsStr} ${subjectStr}`);
@@ -13710,33 +13819,33 @@ function printFooter(mode, count, overviewRemoteCount, targetBranch) {
13710
13819
  console.log();
13711
13820
  switch (mode) {
13712
13821
  case "overview":
13713
- console.log(import_picocolors13.default.dim(` Showing up to ${count} local commits and ${overviewRemoteCount} remote commits`));
13822
+ console.log(import_picocolors14.default.dim(` Showing up to ${count} local commits and ${overviewRemoteCount} remote commits`));
13714
13823
  break;
13715
13824
  case "local":
13716
- console.log(import_picocolors13.default.dim(` Showing up to ${count} unpushed commits`));
13825
+ console.log(import_picocolors14.default.dim(` Showing up to ${count} unpushed commits`));
13717
13826
  break;
13718
13827
  case "remote":
13719
- console.log(import_picocolors13.default.dim(` Showing ${count} most recent commits from the remote branch`));
13828
+ console.log(import_picocolors14.default.dim(` Showing ${count} most recent commits from the remote branch`));
13720
13829
  break;
13721
13830
  case "full":
13722
- console.log(import_picocolors13.default.dim(` Showing ${count} most recent commits${targetBranch ? ` (${targetBranch})` : ""}`));
13831
+ console.log(import_picocolors14.default.dim(` Showing ${count} most recent commits${targetBranch ? ` (${targetBranch})` : ""}`));
13723
13832
  break;
13724
13833
  case "all":
13725
- console.log(import_picocolors13.default.dim(` Showing ${count} most recent commits (all branches)`));
13834
+ console.log(import_picocolors14.default.dim(` Showing ${count} most recent commits (all branches)`));
13726
13835
  break;
13727
13836
  }
13728
13837
  }
13729
13838
  function colorizeGraphLine(line, protectedBranches, currentBranch) {
13730
13839
  const match = line.match(/^([|/\\*\s_.-]*)([a-f0-9]{7,12})(\s+\(([^)]+)\))?\s*(.*)/);
13731
13840
  if (!match) {
13732
- return import_picocolors13.default.cyan(line);
13841
+ return import_picocolors14.default.cyan(line);
13733
13842
  }
13734
13843
  const [, graphPart = "", hash, , refs, subject = ""] = match;
13735
13844
  const parts = [];
13736
13845
  if (graphPart) {
13737
13846
  parts.push(colorizeGraphChars(graphPart));
13738
13847
  }
13739
- parts.push(import_picocolors13.default.yellow(hash));
13848
+ parts.push(import_picocolors14.default.yellow(hash));
13740
13849
  if (refs) {
13741
13850
  parts.push(` (${colorizeRefs(refs, protectedBranches, currentBranch)})`);
13742
13851
  }
@@ -13747,15 +13856,15 @@ function colorizeGraphChars(graphPart) {
13747
13856
  return graphPart.split("").map((ch) => {
13748
13857
  switch (ch) {
13749
13858
  case "*":
13750
- return import_picocolors13.default.green(ch);
13859
+ return import_picocolors14.default.green(ch);
13751
13860
  case "|":
13752
- return import_picocolors13.default.cyan(ch);
13861
+ return import_picocolors14.default.cyan(ch);
13753
13862
  case "/":
13754
13863
  case "\\":
13755
- return import_picocolors13.default.cyan(ch);
13864
+ return import_picocolors14.default.cyan(ch);
13756
13865
  case "-":
13757
13866
  case "_":
13758
- return import_picocolors13.default.cyan(ch);
13867
+ return import_picocolors14.default.cyan(ch);
13759
13868
  default:
13760
13869
  return ch;
13761
13870
  }
@@ -13767,46 +13876,46 @@ function colorizeRefs(refs, protectedBranches, currentBranch) {
13767
13876
  if (trimmed.startsWith("HEAD ->") || trimmed === "HEAD") {
13768
13877
  const branchName = trimmed.replace("HEAD -> ", "");
13769
13878
  if (trimmed === "HEAD") {
13770
- return import_picocolors13.default.bold(import_picocolors13.default.cyan("HEAD"));
13879
+ return import_picocolors14.default.bold(import_picocolors14.default.cyan("HEAD"));
13771
13880
  }
13772
- return `${import_picocolors13.default.bold(import_picocolors13.default.cyan("HEAD"))} ${import_picocolors13.default.dim("->")} ${colorizeRefName(branchName, protectedBranches, currentBranch)}`;
13881
+ return `${import_picocolors14.default.bold(import_picocolors14.default.cyan("HEAD"))} ${import_picocolors14.default.dim("->")} ${colorizeRefName(branchName, protectedBranches, currentBranch)}`;
13773
13882
  }
13774
13883
  if (trimmed.startsWith("tag:")) {
13775
- return import_picocolors13.default.bold(import_picocolors13.default.magenta(trimmed));
13884
+ return import_picocolors14.default.bold(import_picocolors14.default.magenta(trimmed));
13776
13885
  }
13777
13886
  return colorizeRefName(trimmed, protectedBranches, currentBranch);
13778
- }).join(import_picocolors13.default.dim(", "));
13887
+ }).join(import_picocolors14.default.dim(", "));
13779
13888
  }
13780
13889
  function colorizeRefName(name, protectedBranches, currentBranch) {
13781
13890
  const isRemote = name.includes("/");
13782
13891
  const localName = isRemote ? name.split("/").slice(1).join("/") : name;
13783
13892
  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));
13893
+ return isRemote ? import_picocolors14.default.bold(import_picocolors14.default.red(name)) : import_picocolors14.default.bold(import_picocolors14.default.red(name));
13785
13894
  }
13786
13895
  if (localName === currentBranch) {
13787
- return import_picocolors13.default.bold(import_picocolors13.default.green(name));
13896
+ return import_picocolors14.default.bold(import_picocolors14.default.green(name));
13788
13897
  }
13789
13898
  if (isRemote) {
13790
- return import_picocolors13.default.blue(name);
13899
+ return import_picocolors14.default.blue(name);
13791
13900
  }
13792
- return import_picocolors13.default.green(name);
13901
+ return import_picocolors14.default.green(name);
13793
13902
  }
13794
13903
  function colorizeSubject(subject) {
13795
13904
  const emojiMatch = subject.match(/^((?:\p{Emoji_Presentation}|\p{Emoji}\uFE0F)+\s*)/u);
13796
13905
  if (emojiMatch) {
13797
13906
  const emoji = emojiMatch[1];
13798
13907
  const rest = subject.slice(emoji.length);
13799
- return `${emoji}${import_picocolors13.default.white(rest)}`;
13908
+ return `${emoji}${import_picocolors14.default.white(rest)}`;
13800
13909
  }
13801
13910
  if (subject.startsWith("Merge ")) {
13802
- return import_picocolors13.default.dim(subject);
13911
+ return import_picocolors14.default.dim(subject);
13803
13912
  }
13804
- return import_picocolors13.default.white(subject);
13913
+ return import_picocolors14.default.white(subject);
13805
13914
  }
13806
13915
 
13807
13916
  // src/commands/save.ts
13808
13917
  import { execFile as execFileCb4 } from "child_process";
13809
- var import_picocolors14 = __toESM(require_picocolors(), 1);
13918
+ var import_picocolors15 = __toESM(require_picocolors(), 1);
13810
13919
  function gitRun(args) {
13811
13920
  return new Promise((resolve5) => {
13812
13921
  execFileCb4("git", args, (err, stdout2, stderr) => {
@@ -13880,8 +13989,8 @@ async function handleSave(message) {
13880
13989
  info("No uncommitted changes to save.");
13881
13990
  return;
13882
13991
  }
13883
- success(`Saved: ${import_picocolors14.default.dim(label)}`);
13884
- info(`Use ${import_picocolors14.default.bold("contrib save --restore")} to bring them back.`, "");
13992
+ success(`Saved: ${import_picocolors15.default.dim(label)}`);
13993
+ info(`Use ${import_picocolors15.default.bold("cn save --restore")} to bring them back.`, "");
13885
13994
  }
13886
13995
  async function handleRestore() {
13887
13996
  await projectHeading("save --restore", "\uD83D\uDCBE");
@@ -13897,7 +14006,7 @@ async function handleRestore() {
13897
14006
  warn("You may have conflicts. Resolve them and run `git stash drop` when done.");
13898
14007
  process.exit(1);
13899
14008
  }
13900
- success(`Restored: ${import_picocolors14.default.dim(stashes[0].message)}`);
14009
+ success(`Restored: ${import_picocolors15.default.dim(stashes[0].message)}`);
13901
14010
  return;
13902
14011
  }
13903
14012
  const choices = stashes.map((s2) => `${s2.index} ${s2.message}`);
@@ -13910,7 +14019,7 @@ async function handleRestore() {
13910
14019
  process.exit(1);
13911
14020
  }
13912
14021
  const match = stashes.find((s2) => String(s2.index) === idx);
13913
- success(`Restored: ${import_picocolors14.default.dim(match?.message ?? "saved changes")}`);
14022
+ success(`Restored: ${import_picocolors15.default.dim(match?.message ?? "saved changes")}`);
13914
14023
  }
13915
14024
  async function handleList() {
13916
14025
  await projectHeading("save --list", "\uD83D\uDCBE");
@@ -13921,13 +14030,13 @@ async function handleList() {
13921
14030
  }
13922
14031
  console.log();
13923
14032
  for (const s2 of stashes) {
13924
- const idx = import_picocolors14.default.dim(`[${s2.index}]`);
14033
+ const idx = import_picocolors15.default.dim(`[${s2.index}]`);
13925
14034
  const msg = s2.message;
13926
14035
  console.log(` ${idx} ${msg}`);
13927
14036
  }
13928
14037
  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.`, "");
14038
+ info(`Use ${import_picocolors15.default.bold("cn save --restore")} to bring changes back.`, "");
14039
+ info(`Use ${import_picocolors15.default.bold("cn save --drop")} to discard saved changes.`, "");
13931
14040
  }
13932
14041
  async function handleDrop() {
13933
14042
  await projectHeading("save --drop", "\uD83D\uDCBE");
@@ -13945,7 +14054,7 @@ async function handleDrop() {
13945
14054
  process.exit(1);
13946
14055
  }
13947
14056
  const match = stashes.find((s2) => String(s2.index) === idx);
13948
- success(`Dropped: ${import_picocolors14.default.dim(match?.message ?? "saved changes")}`);
14057
+ success(`Dropped: ${import_picocolors15.default.dim(match?.message ?? "saved changes")}`);
13949
14058
  }
13950
14059
  async function getStashList() {
13951
14060
  const result = await gitRun(["stash", "list"]);
@@ -13962,7 +14071,7 @@ async function getStashList() {
13962
14071
  }
13963
14072
 
13964
14073
  // src/commands/setup.ts
13965
- var import_picocolors15 = __toESM(require_picocolors(), 1);
14074
+ var import_picocolors16 = __toESM(require_picocolors(), 1);
13966
14075
  async function shouldContinueSetupWithExistingConfig(options) {
13967
14076
  const { existingConfig, hasConfigFile, confirm, onInfo, onWarn, onSuccess, summary } = options;
13968
14077
  if (existingConfig) {
@@ -14045,7 +14154,7 @@ var setup_default = defineCommand({
14045
14154
  workflow = "github-flow";
14046
14155
  else if (workflowChoice.startsWith("Git Flow"))
14047
14156
  workflow = "git-flow";
14048
- info(`Workflow: ${import_picocolors15.default.bold(WORKFLOW_DESCRIPTIONS[workflow])}`);
14157
+ info(`Workflow: ${import_picocolors16.default.bold(WORKFLOW_DESCRIPTIONS[workflow])}`);
14049
14158
  const conventionChoice = await selectPrompt("Which commit convention should this project use?", [
14050
14159
  `${CONVENTION_DESCRIPTIONS["clean-commit"]} (recommended)`,
14051
14160
  CONVENTION_DESCRIPTIONS.conventional,
@@ -14075,7 +14184,7 @@ var setup_default = defineCommand({
14075
14184
  try {
14076
14185
  await setOllamaCloudApiKey(apiKey);
14077
14186
  success("Stored Ollama Cloud API key in the local secrets store.");
14078
- info(`Secrets path: ${import_picocolors15.default.bold(getSecretsStorePath())}`);
14187
+ info(`Secrets path: ${import_picocolors16.default.bold(getSecretsStorePath())}`);
14079
14188
  } catch (err) {
14080
14189
  const message = err instanceof Error ? err.message : String(err);
14081
14190
  error(`Failed to store Ollama Cloud API key: ${message}`);
@@ -14137,15 +14246,15 @@ var setup_default = defineCommand({
14137
14246
  detectedRole = roleChoice;
14138
14247
  detectionSource = "user selection";
14139
14248
  } 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?`);
14249
+ info(`Detected role: ${import_picocolors16.default.bold(detectedRole)} (via ${detectionSource})`);
14250
+ const confirmed = await confirmPrompt(`Role detected as ${import_picocolors16.default.bold(detectedRole)}. Is this correct?`);
14142
14251
  if (!confirmed) {
14143
14252
  const roleChoice = await selectPrompt("Select your role:", ["maintainer", "contributor"]);
14144
14253
  detectedRole = roleChoice;
14145
14254
  }
14146
14255
  }
14147
14256
  const defaultConfig = getDefaultConfig();
14148
- info(import_picocolors15.default.dim("Tip: press Enter to keep the default branch name shown in each prompt."));
14257
+ info(import_picocolors16.default.dim("Tip: press Enter to keep the default branch name shown in each prompt."));
14149
14258
  const mainBranchDefault = defaultConfig.mainBranch;
14150
14259
  const mainBranch = await inputPrompt(`Main branch name (default: ${mainBranchDefault} \u2014 press Enter to keep)`, mainBranchDefault);
14151
14260
  let devBranch;
@@ -14171,7 +14280,7 @@ var setup_default = defineCommand({
14171
14280
  error("Setup cannot continue without the upstream remote for contributors.");
14172
14281
  process.exit(1);
14173
14282
  }
14174
- success(`Added remote ${import_picocolors15.default.bold(upstreamRemote)} \u2192 ${upstreamUrl}`);
14283
+ success(`Added remote ${import_picocolors16.default.bold(upstreamRemote)} \u2192 ${upstreamUrl}`);
14175
14284
  } else {
14176
14285
  error("An upstream remote URL is required for contributors.");
14177
14286
  info("Add it manually: git remote add upstream <url>", "");
@@ -14194,67 +14303,67 @@ var setup_default = defineCommand({
14194
14303
  showTips
14195
14304
  };
14196
14305
  writeConfig(config);
14197
- success(`Config written to ${import_picocolors15.default.bold(getConfigLocationLabel())}`);
14306
+ success(`Config written to ${import_picocolors16.default.bold(getConfigLocationLabel())}`);
14198
14307
  info("This setup is stored locally for this clone and does not modify tracked files.", "");
14199
14308
  const syncRemote = config.role === "contributor" ? config.upstream : config.origin;
14200
- info(`Fetching ${import_picocolors15.default.bold(syncRemote)} to verify branch configuration...`, "");
14309
+ info(`Fetching ${import_picocolors16.default.bold(syncRemote)} to verify branch configuration...`, "");
14201
14310
  await fetchRemote(syncRemote);
14202
14311
  const mainRef = `${syncRemote}/${config.mainBranch}`;
14203
14312
  if (!await refExists(mainRef)) {
14204
- warn(`Main branch ref ${import_picocolors15.default.bold(mainRef)} not found on remote.`);
14313
+ warn(`Main branch ref ${import_picocolors16.default.bold(mainRef)} not found on remote.`);
14205
14314
  warn("Config was saved \u2014 verify the branch name and re-run setup if needed.");
14206
14315
  }
14207
14316
  if (config.devBranch) {
14208
14317
  const devRef = `${syncRemote}/${config.devBranch}`;
14209
14318
  if (!await refExists(devRef)) {
14210
- warn(`Dev branch ref ${import_picocolors15.default.bold(devRef)} not found on remote.`);
14319
+ warn(`Dev branch ref ${import_picocolors16.default.bold(devRef)} not found on remote.`);
14211
14320
  warn("Config was saved \u2014 verify the branch name and re-run setup if needed.");
14212
14321
  }
14213
14322
  }
14214
14323
  console.log();
14215
14324
  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")}`);
14325
+ info(`Workflow: ${import_picocolors16.default.bold(WORKFLOW_DESCRIPTIONS[config.workflow])}`);
14326
+ info(`Convention: ${import_picocolors16.default.bold(CONVENTION_DESCRIPTIONS[config.commitConvention])}`);
14327
+ info(`AI: ${import_picocolors16.default.bold(isAIEnabled(config) ? "enabled" : "disabled")}`);
14219
14328
  if (isAIEnabled(config)) {
14220
- info(`AI provider: ${import_picocolors15.default.bold(resolvedAIConfig.providerLabel)}`);
14329
+ info(`AI provider: ${import_picocolors16.default.bold(resolvedAIConfig.providerLabel)}`);
14221
14330
  if (resolvedAIConfig.model) {
14222
- info(`AI model: ${import_picocolors15.default.bold(resolvedAIConfig.model)}`);
14331
+ info(`AI model: ${import_picocolors16.default.bold(resolvedAIConfig.model)}`);
14223
14332
  }
14224
14333
  }
14225
- info(`Guides: ${import_picocolors15.default.bold(shouldShowTips(config) ? "shown" : "hidden")}`);
14226
- info(`Role: ${import_picocolors15.default.bold(config.role)}`);
14334
+ info(`Guides: ${import_picocolors16.default.bold(shouldShowTips(config) ? "shown" : "hidden")}`);
14335
+ info(`Role: ${import_picocolors16.default.bold(config.role)}`);
14227
14336
  if (config.devBranch) {
14228
- info(`Main: ${import_picocolors15.default.bold(config.mainBranch)} | Dev: ${import_picocolors15.default.bold(config.devBranch)}`);
14337
+ info(`Main: ${import_picocolors16.default.bold(config.mainBranch)} | Dev: ${import_picocolors16.default.bold(config.devBranch)}`);
14229
14338
  } else {
14230
- info(`Main: ${import_picocolors15.default.bold(config.mainBranch)}`);
14339
+ info(`Main: ${import_picocolors16.default.bold(config.mainBranch)}`);
14231
14340
  }
14232
- info(`Origin: ${import_picocolors15.default.bold(config.origin)}${config.role === "contributor" ? ` | Upstream: ${import_picocolors15.default.bold(config.upstream)}` : ""}`);
14341
+ info(`Origin: ${import_picocolors16.default.bold(config.origin)}${config.role === "contributor" ? ` | Upstream: ${import_picocolors16.default.bold(config.upstream)}` : ""}`);
14233
14342
  }
14234
14343
  });
14235
14344
  function logConfigSummary(config) {
14236
14345
  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")}`);
14346
+ info(`Workflow: ${import_picocolors16.default.bold(WORKFLOW_DESCRIPTIONS[config.workflow])}`);
14347
+ info(`Convention: ${import_picocolors16.default.bold(CONVENTION_DESCRIPTIONS[config.commitConvention])}`);
14348
+ info(`AI: ${import_picocolors16.default.bold(isAIEnabled(config) ? "enabled" : "disabled")}`);
14240
14349
  if (isAIEnabled(config)) {
14241
- info(`AI provider: ${import_picocolors15.default.bold(aiConfig.providerLabel)}`);
14350
+ info(`AI provider: ${import_picocolors16.default.bold(aiConfig.providerLabel)}`);
14242
14351
  if (aiConfig.model) {
14243
- info(`AI model: ${import_picocolors15.default.bold(aiConfig.model)}`);
14352
+ info(`AI model: ${import_picocolors16.default.bold(aiConfig.model)}`);
14244
14353
  }
14245
14354
  }
14246
- info(`Guides: ${import_picocolors15.default.bold(shouldShowTips(config) ? "shown" : "hidden")}`);
14247
- info(`Role: ${import_picocolors15.default.bold(config.role)}`);
14355
+ info(`Guides: ${import_picocolors16.default.bold(shouldShowTips(config) ? "shown" : "hidden")}`);
14356
+ info(`Role: ${import_picocolors16.default.bold(config.role)}`);
14248
14357
  if (config.devBranch) {
14249
- info(`Main: ${import_picocolors15.default.bold(config.mainBranch)} | Dev: ${import_picocolors15.default.bold(config.devBranch)}`);
14358
+ info(`Main: ${import_picocolors16.default.bold(config.mainBranch)} | Dev: ${import_picocolors16.default.bold(config.devBranch)}`);
14250
14359
  } else {
14251
- info(`Main: ${import_picocolors15.default.bold(config.mainBranch)}`);
14360
+ info(`Main: ${import_picocolors16.default.bold(config.mainBranch)}`);
14252
14361
  }
14253
- info(`Origin: ${import_picocolors15.default.bold(config.origin)}${config.role === "contributor" ? ` | Upstream: ${import_picocolors15.default.bold(config.upstream)}` : ""}`);
14362
+ info(`Origin: ${import_picocolors16.default.bold(config.origin)}${config.role === "contributor" ? ` | Upstream: ${import_picocolors16.default.bold(config.upstream)}` : ""}`);
14254
14363
  }
14255
14364
 
14256
14365
  // src/commands/start.ts
14257
- var import_picocolors16 = __toESM(require_picocolors(), 1);
14366
+ var import_picocolors17 = __toESM(require_picocolors(), 1);
14258
14367
  var start_default = defineCommand({
14259
14368
  meta: {
14260
14369
  name: "start",
@@ -14284,7 +14393,7 @@ var start_default = defineCommand({
14284
14393
  await assertCleanGitState("starting a new branch");
14285
14394
  const config = readConfig();
14286
14395
  if (!config) {
14287
- error("No repo config found. Run `contrib setup` first.");
14396
+ error("No repo config found. Run `cn setup` first.");
14288
14397
  process.exit(1);
14289
14398
  }
14290
14399
  if (await hasUncommittedChanges()) {
@@ -14306,16 +14415,16 @@ var start_default = defineCommand({
14306
14415
  warn("Start cancelled.");
14307
14416
  process.exit(0);
14308
14417
  }
14309
- info(`Creating branch: ${import_picocolors16.default.bold(branchName)}`);
14418
+ info(`Creating branch: ${import_picocolors17.default.bold(branchName)}`);
14310
14419
  await fetchRemote(syncSource.remote);
14311
14420
  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)}.`);
14421
+ warn(`Remote ref ${import_picocolors17.default.bold(syncSource.ref)} not found. Creating branch from local ${import_picocolors17.default.bold(baseBranch)}.`);
14313
14422
  }
14314
14423
  const currentBranch = await getCurrentBranch();
14315
14424
  if (currentBranch === baseBranch && await refExists(syncSource.ref)) {
14316
14425
  const ahead = await countCommitsAhead(baseBranch, syncSource.ref);
14317
14426
  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)}.`);
14427
+ 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
14428
  info(" Syncing will discard those commits. Consider backing them up first (e.g. create a branch).");
14320
14429
  const proceed = await confirmPrompt("Discard local commits and sync to remote?");
14321
14430
  if (!proceed) {
@@ -14332,10 +14441,10 @@ var start_default = defineCommand({
14332
14441
  error(`Failed to create branch: ${result2.stderr}`);
14333
14442
  process.exit(1);
14334
14443
  }
14335
- success(`Created ${import_picocolors16.default.bold(branchName)} from ${import_picocolors16.default.bold(syncSource.ref)}`);
14444
+ success(`Created ${import_picocolors17.default.bold(branchName)} from ${import_picocolors17.default.bold(syncSource.ref)}`);
14336
14445
  return;
14337
14446
  }
14338
- error(`Failed to update ${import_picocolors16.default.bold(baseBranch)}: ${updateResult.stderr}`);
14447
+ error(`Failed to update ${import_picocolors17.default.bold(baseBranch)}: ${updateResult.stderr}`);
14339
14448
  info("Make sure your base branch exists locally or the remote ref is available.", "");
14340
14449
  process.exit(1);
14341
14450
  }
@@ -14344,12 +14453,12 @@ var start_default = defineCommand({
14344
14453
  error(`Failed to create branch: ${result.stderr}`);
14345
14454
  process.exit(1);
14346
14455
  }
14347
- success(`Created ${import_picocolors16.default.bold(branchName)} from latest ${import_picocolors16.default.bold(baseBranch)}`);
14456
+ success(`Created ${import_picocolors17.default.bold(branchName)} from latest ${import_picocolors17.default.bold(baseBranch)}`);
14348
14457
  }
14349
14458
  });
14350
14459
 
14351
14460
  // src/commands/status.ts
14352
- var import_picocolors17 = __toESM(require_picocolors(), 1);
14461
+ var import_picocolors18 = __toESM(require_picocolors(), 1);
14353
14462
  var status_default = defineCommand({
14354
14463
  meta: {
14355
14464
  name: "status",
@@ -14362,12 +14471,12 @@ var status_default = defineCommand({
14362
14471
  }
14363
14472
  const config = readConfig();
14364
14473
  if (!config) {
14365
- error("No repo config found. Run `contrib setup` first.");
14474
+ error("No repo config found. Run `cn setup` first.");
14366
14475
  process.exit(1);
14367
14476
  }
14368
14477
  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)}`);
14478
+ console.log(` ${import_picocolors18.default.dim("Workflow:")} ${import_picocolors18.default.bold(WORKFLOW_DESCRIPTIONS[config.workflow])}`);
14479
+ console.log(` ${import_picocolors18.default.dim("Role:")} ${import_picocolors18.default.bold(config.role)}`);
14371
14480
  console.log();
14372
14481
  await fetchAll();
14373
14482
  const currentBranch = await getCurrentBranch();
@@ -14376,7 +14485,7 @@ var status_default = defineCommand({
14376
14485
  const isContributor = config.role === "contributor";
14377
14486
  const [dirty, fileStatus] = await Promise.all([hasUncommittedChanges(), getFileStatus()]);
14378
14487
  if (dirty) {
14379
- console.log(` ${import_picocolors17.default.yellow("\u26A0")} ${import_picocolors17.default.yellow("Uncommitted changes in working tree")}`);
14488
+ console.log(` ${import_picocolors18.default.yellow("\u26A0")} ${import_picocolors18.default.yellow("Uncommitted changes in working tree")}`);
14380
14489
  console.log();
14381
14490
  }
14382
14491
  const mainRemote = `${origin}/${mainBranch}`;
@@ -14395,16 +14504,16 @@ var status_default = defineCommand({
14395
14504
  if (isFeatureBranch) {
14396
14505
  const branchDiv = await getDivergence(currentBranch, baseBranch);
14397
14506
  const branchLine = formatStatus(currentBranch, baseBranch, branchDiv.ahead, branchDiv.behind);
14398
- console.log(branchLine + import_picocolors17.default.dim(` (current ${import_picocolors17.default.green("*")})`));
14507
+ console.log(branchLine + import_picocolors18.default.dim(` (current ${import_picocolors18.default.green("*")})`));
14399
14508
  branchStatus = await detectBranchStatus(currentBranch, baseBranch);
14400
14509
  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")}`);
14510
+ 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
14511
  }
14403
14512
  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`)}`);
14513
+ 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
14514
  }
14406
14515
  } else if (currentBranch) {
14407
- console.log(import_picocolors17.default.dim(` (on ${import_picocolors17.default.bold(currentBranch)} branch)`));
14516
+ console.log(import_picocolors18.default.dim(` (on ${import_picocolors18.default.bold(currentBranch)} branch)`));
14408
14517
  }
14409
14518
  let branchesAligned = true;
14410
14519
  {
@@ -14441,20 +14550,20 @@ var status_default = defineCommand({
14441
14550
  }
14442
14551
  branchesAligned = groups.size === 1;
14443
14552
  console.log();
14444
- console.log(` ${import_picocolors17.default.bold("\uD83D\uDD17 Branch Alignment")}`);
14553
+ console.log(` ${import_picocolors18.default.bold("\uD83D\uDD17 Branch Alignment")}`);
14445
14554
  for (const [hash, names] of groups) {
14446
14555
  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}`);
14556
+ const nameStr = names.map((n2) => import_picocolors18.default.bold(n2)).join(import_picocolors18.default.dim(" \xB7 "));
14557
+ console.log(` ${import_picocolors18.default.yellow(short)} ${import_picocolors18.default.dim("\u2500\u2500")} ${nameStr}`);
14449
14558
  const subject = await getCommitSubject(hash);
14450
14559
  if (subject) {
14451
- console.log(` ${import_picocolors17.default.dim(subject)}`);
14560
+ console.log(` ${import_picocolors18.default.dim(subject)}`);
14452
14561
  }
14453
14562
  }
14454
14563
  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")}`);
14564
+ console.log(` ${import_picocolors18.default.green("\u2713")} ${import_picocolors18.default.green("All branches aligned")} ${import_picocolors18.default.dim("\u2014 ready to start")}`);
14456
14565
  } else {
14457
- console.log(` ${import_picocolors17.default.yellow("\u26A0")} ${import_picocolors17.default.yellow("Branches are not fully aligned")}`);
14566
+ console.log(` ${import_picocolors18.default.yellow("\u26A0")} ${import_picocolors18.default.yellow("Branches are not fully aligned")}`);
14458
14567
  }
14459
14568
  }
14460
14569
  }
@@ -14462,41 +14571,41 @@ var status_default = defineCommand({
14462
14571
  if (hasFiles) {
14463
14572
  console.log();
14464
14573
  if (fileStatus.staged.length > 0) {
14465
- console.log(` ${import_picocolors17.default.green("Staged for commit:")}`);
14574
+ console.log(` ${import_picocolors18.default.green("Staged for commit:")}`);
14466
14575
  for (const { file, status } of fileStatus.staged) {
14467
- console.log(` ${import_picocolors17.default.green("+")} ${import_picocolors17.default.dim(`${status}:`)} ${file}`);
14576
+ console.log(` ${import_picocolors18.default.green("+")} ${import_picocolors18.default.dim(`${status}:`)} ${file}`);
14468
14577
  }
14469
14578
  }
14470
14579
  if (fileStatus.modified.length > 0) {
14471
- console.log(` ${import_picocolors17.default.yellow("Unstaged changes:")}`);
14580
+ console.log(` ${import_picocolors18.default.yellow("Unstaged changes:")}`);
14472
14581
  for (const { file, status } of fileStatus.modified) {
14473
- console.log(` ${import_picocolors17.default.yellow("~")} ${import_picocolors17.default.dim(`${status}:`)} ${file}`);
14582
+ console.log(` ${import_picocolors18.default.yellow("~")} ${import_picocolors18.default.dim(`${status}:`)} ${file}`);
14474
14583
  }
14475
14584
  }
14476
14585
  if (fileStatus.untracked.length > 0) {
14477
- console.log(` ${import_picocolors17.default.red("Untracked files:")}`);
14586
+ console.log(` ${import_picocolors18.default.red("Untracked files:")}`);
14478
14587
  for (const file of fileStatus.untracked) {
14479
- console.log(` ${import_picocolors17.default.red("?")} ${file}`);
14588
+ console.log(` ${import_picocolors18.default.red("?")} ${file}`);
14480
14589
  }
14481
14590
  }
14482
14591
  } else if (!dirty) {
14483
- console.log(` ${import_picocolors17.default.green("\u2713")} ${import_picocolors17.default.dim("Working tree clean")}`);
14592
+ console.log(` ${import_picocolors18.default.green("\u2713")} ${import_picocolors18.default.dim("Working tree clean")}`);
14484
14593
  }
14485
14594
  console.log();
14486
14595
  }
14487
14596
  });
14488
14597
  function formatStatus(branch, base, ahead, behind) {
14489
- const label = import_picocolors17.default.bold(branch.padEnd(20));
14598
+ const label = import_picocolors18.default.bold(branch.padEnd(20));
14490
14599
  if (ahead === 0 && behind === 0) {
14491
- return ` ${import_picocolors17.default.green("\u2713")} ${label} ${import_picocolors17.default.dim(`in sync with ${base}`)}`;
14600
+ return ` ${import_picocolors18.default.green("\u2713")} ${label} ${import_picocolors18.default.dim(`in sync with ${base}`)}`;
14492
14601
  }
14493
14602
  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}`)}`;
14603
+ return ` ${import_picocolors18.default.yellow("\u2191")} ${label} ${import_picocolors18.default.yellow(`${ahead} commit${ahead !== 1 ? "s" : ""} ahead of ${base}`)}`;
14495
14604
  }
14496
14605
  if (behind > 0 && ahead === 0) {
14497
- return ` ${import_picocolors17.default.red("\u2193")} ${label} ${import_picocolors17.default.red(`${behind} commit${behind !== 1 ? "s" : ""} behind ${base}`)}`;
14606
+ return ` ${import_picocolors18.default.red("\u2193")} ${label} ${import_picocolors18.default.red(`${behind} commit${behind !== 1 ? "s" : ""} behind ${base}`)}`;
14498
14607
  }
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)}`;
14608
+ 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
14609
  }
14501
14610
  var STALE_THRESHOLD_DAYS = 14;
14502
14611
  async function detectBranchStatus(branch, baseBranch) {
@@ -14547,15 +14656,15 @@ async function detectBranchStatus(branch, baseBranch) {
14547
14656
  }
14548
14657
 
14549
14658
  // src/commands/submit.ts
14550
- var import_picocolors18 = __toESM(require_picocolors(), 1);
14659
+ var import_picocolors19 = __toESM(require_picocolors(), 1);
14551
14660
  async function performSquashMerge(origin, baseBranch, featureBranch, options) {
14552
- info(`Checking out ${import_picocolors18.default.bold(baseBranch)}...`);
14661
+ info(`Checking out ${import_picocolors19.default.bold(baseBranch)}...`);
14553
14662
  const coResult = await checkoutBranch(baseBranch);
14554
14663
  if (coResult.exitCode !== 0) {
14555
14664
  error(`Failed to checkout ${baseBranch}: ${coResult.stderr}`);
14556
14665
  process.exit(1);
14557
14666
  }
14558
- info(`Squash merging ${import_picocolors18.default.bold(featureBranch)} into ${import_picocolors18.default.bold(baseBranch)}...`);
14667
+ info(`Squash merging ${import_picocolors19.default.bold(featureBranch)} into ${import_picocolors19.default.bold(baseBranch)}...`);
14559
14668
  const mergeResult = await mergeSquash(featureBranch);
14560
14669
  if (mergeResult.exitCode !== 0) {
14561
14670
  error(`Squash merge failed: ${mergeResult.stderr}`);
@@ -14575,7 +14684,7 @@ async function performSquashMerge(origin, baseBranch, featureBranch, options) {
14575
14684
  message = aiMsg;
14576
14685
  spinner.success("AI commit message generated.");
14577
14686
  console.log(`
14578
- ${import_picocolors18.default.dim("AI suggestion:")} ${import_picocolors18.default.bold(import_picocolors18.default.cyan(message))}`);
14687
+ ${import_picocolors19.default.dim("AI suggestion:")} ${import_picocolors19.default.bold(import_picocolors19.default.cyan(message))}`);
14579
14688
  break;
14580
14689
  }
14581
14690
  spinner.fail("AI did not return a commit message.");
@@ -14615,7 +14724,7 @@ async function performSquashMerge(origin, baseBranch, featureBranch, options) {
14615
14724
  message = regen;
14616
14725
  spinner.success("Commit message regenerated.");
14617
14726
  console.log(`
14618
- ${import_picocolors18.default.dim("AI suggestion:")} ${import_picocolors18.default.bold(import_picocolors18.default.cyan(regen))}`);
14727
+ ${import_picocolors19.default.dim("AI suggestion:")} ${import_picocolors19.default.bold(import_picocolors19.default.cyan(regen))}`);
14619
14728
  } else {
14620
14729
  spinner.fail("Regeneration failed.");
14621
14730
  }
@@ -14631,13 +14740,13 @@ async function performSquashMerge(origin, baseBranch, featureBranch, options) {
14631
14740
  error(`Commit failed: ${commitResult.stderr}`);
14632
14741
  process.exit(1);
14633
14742
  }
14634
- info(`Pushing ${import_picocolors18.default.bold(baseBranch)} to ${origin}...`);
14743
+ info(`Pushing ${import_picocolors19.default.bold(baseBranch)} to ${origin}...`);
14635
14744
  const pushResult = await pushBranch(origin, baseBranch);
14636
14745
  if (pushResult.exitCode !== 0) {
14637
14746
  error(`Failed to push ${baseBranch}: ${pushResult.stderr}`);
14638
14747
  process.exit(1);
14639
14748
  }
14640
- info(`Deleting local branch ${import_picocolors18.default.bold(featureBranch)}...`);
14749
+ info(`Deleting local branch ${import_picocolors19.default.bold(featureBranch)}...`);
14641
14750
  const delLocal = await forceDeleteBranch(featureBranch);
14642
14751
  if (delLocal.exitCode !== 0) {
14643
14752
  warn(`Could not delete local branch: ${delLocal.stderr.trim()}`);
@@ -14645,14 +14754,14 @@ async function performSquashMerge(origin, baseBranch, featureBranch, options) {
14645
14754
  const remoteBranchRef = `${origin}/${featureBranch}`;
14646
14755
  const remoteExists = await branchExists(remoteBranchRef);
14647
14756
  if (remoteExists) {
14648
- info(`Deleting remote branch ${import_picocolors18.default.bold(featureBranch)}...`);
14757
+ info(`Deleting remote branch ${import_picocolors19.default.bold(featureBranch)}...`);
14649
14758
  const delRemote = await deleteRemoteBranch(origin, featureBranch);
14650
14759
  if (delRemote.exitCode !== 0) {
14651
14760
  warn(`Could not delete remote branch: ${delRemote.stderr.trim()}`);
14652
14761
  }
14653
14762
  }
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.`, "");
14763
+ success(`Squash merged ${import_picocolors19.default.bold(featureBranch)} into ${import_picocolors19.default.bold(baseBranch)} and pushed.`);
14764
+ info(`Run ${import_picocolors19.default.bold("cn start")} to begin a new feature.`, "");
14656
14765
  }
14657
14766
  var submit_default = defineCommand({
14658
14767
  meta: {
@@ -14695,7 +14804,7 @@ var submit_default = defineCommand({
14695
14804
  await assertCleanGitState("submitting");
14696
14805
  const config = readConfig();
14697
14806
  if (!config) {
14698
- error("No repo config found. Run `contrib setup` first.");
14807
+ error("No repo config found. Run `cn setup` first.");
14699
14808
  process.exit(1);
14700
14809
  }
14701
14810
  const { origin } = config;
@@ -14709,7 +14818,7 @@ var submit_default = defineCommand({
14709
14818
  }
14710
14819
  if (protectedBranches.includes(currentBranch)) {
14711
14820
  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.`);
14821
+ warn(`You're on ${import_picocolors19.default.bold(currentBranch)}, which is a protected branch. PRs should come from feature branches.`);
14713
14822
  await fetchAll();
14714
14823
  const remoteRef = `${origin}/${currentBranch}`;
14715
14824
  const localWork = await hasLocalWork(origin, currentBranch);
@@ -14718,11 +14827,11 @@ var submit_default = defineCommand({
14718
14827
  const hasAnything = hasCommits || dirty;
14719
14828
  if (!hasAnything) {
14720
14829
  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.`, "");
14830
+ info(` Run ${import_picocolors19.default.bold("cn start")} to create a new feature branch.`, "");
14722
14831
  process.exit(1);
14723
14832
  }
14724
14833
  if (hasCommits) {
14725
- info(`Found ${import_picocolors18.default.bold(String(localWork.unpushedCommits))} unpushed commit${localWork.unpushedCommits !== 1 ? "s" : ""} on ${import_picocolors18.default.bold(currentBranch)}.`);
14834
+ info(`Found ${import_picocolors19.default.bold(String(localWork.unpushedCommits))} unpushed commit${localWork.unpushedCommits !== 1 ? "s" : ""} on ${import_picocolors19.default.bold(currentBranch)}.`);
14726
14835
  }
14727
14836
  if (dirty) {
14728
14837
  info("You also have uncommitted changes in the working tree.");
@@ -14752,12 +14861,12 @@ var submit_default = defineCommand({
14752
14861
  error(`Failed to create branch: ${branchResult.stderr}`);
14753
14862
  process.exit(1);
14754
14863
  }
14755
- success(`Created ${import_picocolors18.default.bold(newBranchName)} with your changes.`);
14864
+ success(`Created ${import_picocolors19.default.bold(newBranchName)} with your changes.`);
14756
14865
  await updateLocalBranch(currentBranch, remoteRef);
14757
- info(`Reset ${import_picocolors18.default.bold(currentBranch)} back to ${import_picocolors18.default.bold(remoteRef)} \u2014 no damage done.`, "");
14866
+ info(`Reset ${import_picocolors19.default.bold(currentBranch)} back to ${import_picocolors19.default.bold(remoteRef)} \u2014 no damage done.`, "");
14758
14867
  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.`, "");
14868
+ success(`You're now on ${import_picocolors19.default.bold(newBranchName)} with all your work intact.`);
14869
+ info(`Run ${import_picocolors19.default.bold("cn submit")} again to push and create your PR.`, "");
14761
14870
  return;
14762
14871
  }
14763
14872
  await projectHeading("submit", "\uD83D\uDE80");
@@ -14766,7 +14875,7 @@ var submit_default = defineCommand({
14766
14875
  if (ghInstalled && ghAuthed) {
14767
14876
  const mergedPR = await getMergedPRForBranch(currentBranch);
14768
14877
  if (mergedPR) {
14769
- warn(`PR #${mergedPR.number} (${import_picocolors18.default.bold(mergedPR.title)}) was already merged.`);
14878
+ warn(`PR #${mergedPR.number} (${import_picocolors19.default.bold(mergedPR.title)}) was already merged.`);
14770
14879
  const localWork = await hasLocalWork(origin, currentBranch);
14771
14880
  const hasWork = localWork.uncommitted || localWork.unpushedCommits > 0;
14772
14881
  if (hasWork) {
@@ -14774,7 +14883,7 @@ var submit_default = defineCommand({
14774
14883
  warn("You have uncommitted changes in your working tree.");
14775
14884
  }
14776
14885
  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.`);
14886
+ warn(`You have ${import_picocolors19.default.bold(String(localWork.unpushedCommits))} local commit${localWork.unpushedCommits !== 1 ? "s" : ""} not in the merged PR.`);
14778
14887
  }
14779
14888
  const SAVE_NEW_BRANCH = "Save changes to a new branch";
14780
14889
  const DISCARD = "Discard all changes and clean up";
@@ -14801,10 +14910,10 @@ var submit_default = defineCommand({
14801
14910
  error(`Failed to rename branch: ${renameResult.stderr}`);
14802
14911
  process.exit(1);
14803
14912
  }
14804
- success(`Renamed ${import_picocolors18.default.bold(currentBranch)} \u2192 ${import_picocolors18.default.bold(newBranchName)}`);
14913
+ success(`Renamed ${import_picocolors19.default.bold(currentBranch)} \u2192 ${import_picocolors19.default.bold(newBranchName)}`);
14805
14914
  await unsetUpstream();
14806
14915
  const syncSource2 = getSyncSource(config);
14807
- info(`Syncing ${import_picocolors18.default.bold(newBranchName)} with latest ${import_picocolors18.default.bold(baseBranch)}...`);
14916
+ info(`Syncing ${import_picocolors19.default.bold(newBranchName)} with latest ${import_picocolors19.default.bold(baseBranch)}...`);
14808
14917
  await fetchRemote(syncSource2.remote);
14809
14918
  let rebaseResult;
14810
14919
  if (staleUpstreamHash) {
@@ -14815,17 +14924,17 @@ var submit_default = defineCommand({
14815
14924
  }
14816
14925
  if (rebaseResult.exitCode !== 0) {
14817
14926
  warn("Rebase encountered conflicts. Resolve them manually, then run:");
14818
- info(` ${import_picocolors18.default.bold("git rebase --continue")}`, "");
14927
+ info(` ${import_picocolors19.default.bold("git rebase --continue")}`, "");
14819
14928
  } else {
14820
- success(`Rebased ${import_picocolors18.default.bold(newBranchName)} onto ${import_picocolors18.default.bold(syncSource2.ref)}.`);
14929
+ success(`Rebased ${import_picocolors19.default.bold(newBranchName)} onto ${import_picocolors19.default.bold(syncSource2.ref)}.`);
14821
14930
  }
14822
- info(`All your changes are preserved. Run ${import_picocolors18.default.bold("contrib submit")} when ready to create a new PR.`, "");
14931
+ info(`All your changes are preserved. Run ${import_picocolors19.default.bold("cn submit")} when ready to create a new PR.`, "");
14823
14932
  return;
14824
14933
  }
14825
14934
  warn("Discarding local changes...");
14826
14935
  }
14827
14936
  const syncSource = getSyncSource(config);
14828
- info(`Switching to ${import_picocolors18.default.bold(baseBranch)} and syncing...`);
14937
+ info(`Switching to ${import_picocolors19.default.bold(baseBranch)} and syncing...`);
14829
14938
  await fetchRemote(syncSource.remote);
14830
14939
  await resetHard("HEAD");
14831
14940
  const coResult = await checkoutBranch(baseBranch);
@@ -14834,35 +14943,35 @@ var submit_default = defineCommand({
14834
14943
  process.exit(1);
14835
14944
  }
14836
14945
  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)}...`);
14946
+ success(`Synced ${import_picocolors19.default.bold(baseBranch)} with ${import_picocolors19.default.bold(syncSource.ref)}.`);
14947
+ info(`Deleting stale branch ${import_picocolors19.default.bold(currentBranch)}...`);
14839
14948
  const delResult = await forceDeleteBranch(currentBranch);
14840
14949
  if (delResult.exitCode === 0) {
14841
- success(`Deleted ${import_picocolors18.default.bold(currentBranch)}.`);
14950
+ success(`Deleted ${import_picocolors19.default.bold(currentBranch)}.`);
14842
14951
  } else {
14843
14952
  warn(`Could not delete branch: ${delResult.stderr.trim()}`);
14844
14953
  }
14845
14954
  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.`);
14955
+ info(`You're now on ${import_picocolors19.default.bold(baseBranch)}. Run ${import_picocolors19.default.bold("cn start")} to begin a new feature.`);
14847
14956
  return;
14848
14957
  }
14849
14958
  }
14850
14959
  if (ghInstalled && ghAuthed) {
14851
14960
  const existingPR = await getPRForBranch(currentBranch);
14852
14961
  if (existingPR) {
14853
- info(`Pushing ${import_picocolors18.default.bold(currentBranch)} to ${origin}...`);
14962
+ info(`Pushing ${import_picocolors19.default.bold(currentBranch)} to ${origin}...`);
14854
14963
  const pushResult2 = await pushSetUpstream(origin, currentBranch);
14855
14964
  if (pushResult2.exitCode !== 0) {
14856
14965
  error(`Failed to push: ${pushResult2.stderr}`);
14857
14966
  if (pushResult2.stderr.includes("rejected") || pushResult2.stderr.includes("non-fast-forward")) {
14858
14967
  warn("The remote branch has diverged. Try:");
14859
14968
  info(` git pull --rebase ${origin} ${currentBranch}`, "");
14860
- info(" Then run `contrib submit` again.", "");
14969
+ info(" Then run `cn submit` again.", "");
14861
14970
  }
14862
14971
  process.exit(1);
14863
14972
  }
14864
- success(`Pushed changes to existing PR #${existingPR.number}: ${import_picocolors18.default.bold(existingPR.title)}`);
14865
- console.log(` ${import_picocolors18.default.cyan(existingPR.url)}`);
14973
+ success(`Pushed changes to existing PR #${existingPR.number}: ${import_picocolors19.default.bold(existingPR.title)}`);
14974
+ console.log(` ${import_picocolors19.default.cyan(existingPR.url)}`);
14866
14975
  return;
14867
14976
  }
14868
14977
  }
@@ -14884,10 +14993,10 @@ var submit_default = defineCommand({
14884
14993
  prBody = result.body;
14885
14994
  spinner.success("PR description generated.");
14886
14995
  console.log(`
14887
- ${import_picocolors18.default.dim("AI title:")} ${import_picocolors18.default.bold(import_picocolors18.default.cyan(prTitle))}`);
14996
+ ${import_picocolors19.default.dim("AI title:")} ${import_picocolors19.default.bold(import_picocolors19.default.cyan(prTitle))}`);
14888
14997
  console.log(`
14889
- ${import_picocolors18.default.dim("AI body preview:")}`);
14890
- console.log(import_picocolors18.default.dim(prBody.slice(0, 300) + (prBody.length > 300 ? "..." : "")));
14998
+ ${import_picocolors19.default.dim("AI body preview:")}`);
14999
+ console.log(import_picocolors19.default.dim(prBody.slice(0, 300) + (prBody.length > 300 ? "..." : "")));
14891
15000
  } else {
14892
15001
  spinner.fail("AI did not return a PR description.");
14893
15002
  }
@@ -14998,14 +15107,14 @@ ${import_picocolors18.default.dim("AI body preview:")}`);
14998
15107
  warn("Submit cancelled.");
14999
15108
  return;
15000
15109
  }
15001
- info(`Pushing ${import_picocolors18.default.bold(currentBranch)} to ${origin}...`);
15110
+ info(`Pushing ${import_picocolors19.default.bold(currentBranch)} to ${origin}...`);
15002
15111
  const pushResult = await pushSetUpstream(origin, currentBranch);
15003
15112
  if (pushResult.exitCode !== 0) {
15004
15113
  error(`Failed to push: ${pushResult.stderr}`);
15005
15114
  if (pushResult.stderr.includes("rejected") || pushResult.stderr.includes("non-fast-forward")) {
15006
15115
  warn("The remote branch has diverged. Try:");
15007
15116
  info(` git pull --rebase ${origin} ${currentBranch}`, "");
15008
- info(" Then run `contrib submit` again.", "");
15117
+ info(" Then run `cn submit` again.", "");
15009
15118
  info("If you need to force push (use with caution):", "");
15010
15119
  info(` git push --force-with-lease ${origin} ${currentBranch}`, "");
15011
15120
  }
@@ -15017,7 +15126,7 @@ ${import_picocolors18.default.dim("AI body preview:")}`);
15017
15126
  const prUrl = `https://github.com/${repoInfo.owner}/${repoInfo.repo}/compare/${baseBranch}...${currentBranch}?expand=1`;
15018
15127
  console.log();
15019
15128
  info("Create your PR manually:", "");
15020
- console.log(` ${import_picocolors18.default.cyan(prUrl)}`);
15129
+ console.log(` ${import_picocolors19.default.cyan(prUrl)}`);
15021
15130
  } else {
15022
15131
  info("gh CLI not available. Create your PR manually on GitHub.", "");
15023
15132
  }
@@ -15051,7 +15160,7 @@ ${import_picocolors18.default.dim("AI body preview:")}`);
15051
15160
  });
15052
15161
 
15053
15162
  // src/commands/switch.ts
15054
- var import_picocolors19 = __toESM(require_picocolors(), 1);
15163
+ var import_picocolors20 = __toESM(require_picocolors(), 1);
15055
15164
  var switch_default = defineCommand({
15056
15165
  meta: {
15057
15166
  name: "switch",
@@ -15083,11 +15192,11 @@ var switch_default = defineCommand({
15083
15192
  const choices = localBranches.filter((b2) => b2.name !== currentBranch).map((b2) => {
15084
15193
  const labels = [];
15085
15194
  if (protectedBranches.includes(b2.name))
15086
- labels.push(import_picocolors19.default.red("protected"));
15195
+ labels.push(import_picocolors20.default.red("protected"));
15087
15196
  if (b2.upstream)
15088
- labels.push(import_picocolors19.default.dim(`\u2192 ${b2.upstream}`));
15197
+ labels.push(import_picocolors20.default.dim(`\u2192 ${b2.upstream}`));
15089
15198
  if (b2.gone)
15090
- labels.push(import_picocolors19.default.red("remote gone"));
15199
+ labels.push(import_picocolors20.default.red("remote gone"));
15091
15200
  const suffix = labels.length > 0 ? ` ${labels.join(" \xB7 ")}` : "";
15092
15201
  return `${b2.name}${suffix}`;
15093
15202
  });
@@ -15099,7 +15208,7 @@ var switch_default = defineCommand({
15099
15208
  targetBranch = selected.split(/\s{2,}/)[0].trim();
15100
15209
  }
15101
15210
  if (targetBranch === currentBranch) {
15102
- info(`Already on ${import_picocolors19.default.bold(targetBranch)}.`);
15211
+ info(`Already on ${import_picocolors20.default.bold(targetBranch)}.`);
15103
15212
  return;
15104
15213
  }
15105
15214
  if (await hasUncommittedChanges()) {
@@ -15118,7 +15227,7 @@ var switch_default = defineCommand({
15118
15227
  const stashMsg = `contrib-save: auto-save from ${currentBranch}`;
15119
15228
  try {
15120
15229
  await exec("git", ["stash", "push", "-m", stashMsg]);
15121
- info(`Saved changes: ${import_picocolors19.default.dim(stashMsg)}`);
15230
+ info(`Saved changes: ${import_picocolors20.default.dim(stashMsg)}`);
15122
15231
  } catch {
15123
15232
  error("Failed to save changes. Please commit or save manually.");
15124
15233
  process.exit(1);
@@ -15130,13 +15239,13 @@ var switch_default = defineCommand({
15130
15239
  await exec("git", ["stash", "pop"]);
15131
15240
  info("Restored saved changes.");
15132
15241
  } catch {
15133
- warn("Could not restore save automatically. Use `contrib save --restore` to recover.");
15242
+ warn("Could not restore save automatically. Use `cn save --restore` to recover.");
15134
15243
  }
15135
15244
  process.exit(1);
15136
15245
  }
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.`, "");
15246
+ success(`Switched to ${import_picocolors20.default.bold(targetBranch)}`);
15247
+ info(`Your changes from ${import_picocolors20.default.bold(currentBranch ?? "previous branch")} are saved.`, "");
15248
+ info(`Use ${import_picocolors20.default.bold("cn save --restore")} to bring them back.`, "");
15140
15249
  return;
15141
15250
  }
15142
15251
  const result = await checkoutBranch(targetBranch);
@@ -15144,12 +15253,12 @@ var switch_default = defineCommand({
15144
15253
  error(`Failed to switch to ${targetBranch}: ${result.stderr}`);
15145
15254
  process.exit(1);
15146
15255
  }
15147
- success(`Switched to ${import_picocolors19.default.bold(targetBranch)}`);
15256
+ success(`Switched to ${import_picocolors20.default.bold(targetBranch)}`);
15148
15257
  }
15149
15258
  });
15150
15259
 
15151
15260
  // src/commands/sync.ts
15152
- var import_picocolors20 = __toESM(require_picocolors(), 1);
15261
+ var import_picocolors21 = __toESM(require_picocolors(), 1);
15153
15262
  var sync_default = defineCommand({
15154
15263
  meta: {
15155
15264
  name: "sync",
@@ -15180,7 +15289,7 @@ var sync_default = defineCommand({
15180
15289
  await assertCleanGitState("syncing");
15181
15290
  const config = readConfig();
15182
15291
  if (!config) {
15183
- error("No repo config found. Run `contrib setup` first.");
15292
+ error("No repo config found. Run `cn setup` first.");
15184
15293
  process.exit(1);
15185
15294
  }
15186
15295
  const { workflow, role, origin } = config;
@@ -15201,24 +15310,24 @@ var sync_default = defineCommand({
15201
15310
  await fetchRemote(origin);
15202
15311
  }
15203
15312
  if (!await refExists(syncSource.ref)) {
15204
- error(`Remote ref ${import_picocolors20.default.bold(syncSource.ref)} does not exist.`);
15313
+ error(`Remote ref ${import_picocolors21.default.bold(syncSource.ref)} does not exist.`);
15205
15314
  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")}.`, "");
15315
+ info(`Check your config: the base branch may need updating via ${import_picocolors21.default.bold("cn setup")}.`, "");
15207
15316
  process.exit(1);
15208
15317
  }
15209
15318
  let allowMergeCommit = false;
15210
15319
  const div = await getDivergence(baseBranch, syncSource.ref);
15211
15320
  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}`);
15321
+ 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
15322
  } else {
15214
- info(`${import_picocolors20.default.bold(baseBranch)} is already in sync with ${syncSource.ref}`);
15323
+ info(`${import_picocolors21.default.bold(baseBranch)} is already in sync with ${syncSource.ref}`);
15215
15324
  }
15216
15325
  if (div.ahead > 0) {
15217
15326
  const currentBranch = await getCurrentBranch();
15218
15327
  const protectedBranches = getProtectedBranches(config);
15219
15328
  const isOnProtected = currentBranch && protectedBranches.includes(currentBranch);
15220
15329
  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.`);
15330
+ 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
15331
  info("Pulling now could create a merge commit, which breaks clean history.");
15223
15332
  console.log();
15224
15333
  const MOVE_BRANCH = "Move my commits to a new feature branch, then sync";
@@ -15248,7 +15357,7 @@ var sync_default = defineCommand({
15248
15357
  error(`Failed to create branch: ${branchResult.stderr}`);
15249
15358
  process.exit(1);
15250
15359
  }
15251
- success(`Created ${import_picocolors20.default.bold(newBranchName)} with your commits.`);
15360
+ success(`Created ${import_picocolors21.default.bold(newBranchName)} with your commits.`);
15252
15361
  const coResult2 = await checkoutBranch(baseBranch);
15253
15362
  if (coResult2.exitCode !== 0) {
15254
15363
  error(`Failed to checkout ${baseBranch}: ${coResult2.stderr}`);
@@ -15256,11 +15365,11 @@ var sync_default = defineCommand({
15256
15365
  }
15257
15366
  const remoteRef = syncSource.ref;
15258
15367
  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}`);
15368
+ success(`Reset ${import_picocolors21.default.bold(baseBranch)} to ${import_picocolors21.default.bold(remoteRef)}.`);
15369
+ success(`${import_picocolors21.default.bold(baseBranch)} is now in sync with ${syncSource.ref}`);
15261
15370
  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)}.`, "");
15371
+ info(`Your commits are safe on ${import_picocolors21.default.bold(newBranchName)}.`, "");
15372
+ 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
15373
  return;
15265
15374
  }
15266
15375
  allowMergeCommit = true;
@@ -15268,7 +15377,7 @@ var sync_default = defineCommand({
15268
15377
  }
15269
15378
  }
15270
15379
  if (!args.yes) {
15271
- const ok = await confirmPrompt(`This will pull ${import_picocolors20.default.bold(syncSource.ref)} into local ${import_picocolors20.default.bold(baseBranch)}.`);
15380
+ const ok = await confirmPrompt(`This will pull ${import_picocolors21.default.bold(syncSource.ref)} into local ${import_picocolors21.default.bold(baseBranch)}.`);
15272
15381
  if (!ok)
15273
15382
  process.exit(0);
15274
15383
  }
@@ -15282,8 +15391,8 @@ var sync_default = defineCommand({
15282
15391
  if (allowMergeCommit) {
15283
15392
  error(`Pull failed: ${pullResult.stderr.trim()}`);
15284
15393
  } 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.`, "");
15394
+ error(`Fast-forward pull failed. Your local ${import_picocolors21.default.bold(baseBranch)} may have diverged.`);
15395
+ info(`Use ${import_picocolors21.default.bold("cn sync")} again and choose "Move my commits to a new feature branch" to fix this.`, "");
15287
15396
  }
15288
15397
  process.exit(1);
15289
15398
  }
@@ -15291,7 +15400,7 @@ var sync_default = defineCommand({
15291
15400
  if (hasDevBranch(workflow) && role === "maintainer") {
15292
15401
  const mainDiv = await getDivergence(config.mainBranch, `${origin}/${config.mainBranch}`);
15293
15402
  if (mainDiv.behind > 0) {
15294
- info(`Also syncing ${import_picocolors20.default.bold(config.mainBranch)}...`);
15403
+ info(`Also syncing ${import_picocolors21.default.bold(config.mainBranch)}...`);
15295
15404
  const mainCoResult = await checkoutBranch(config.mainBranch);
15296
15405
  if (mainCoResult.exitCode === 0) {
15297
15406
  const mainPullResult = await pullFastForwardOnly(origin, config.mainBranch);
@@ -15332,20 +15441,20 @@ var sync_default = defineCommand({
15332
15441
  }
15333
15442
  }
15334
15443
  console.log();
15335
- console.log(` ${import_picocolors20.default.bold("\uD83D\uDD17 Branch Alignment")}`);
15444
+ console.log(` ${import_picocolors21.default.bold("\uD83D\uDD17 Branch Alignment")}`);
15336
15445
  for (const [hash, names] of groups) {
15337
15446
  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}`);
15447
+ const nameStr = names.map((n2) => import_picocolors21.default.bold(n2)).join(import_picocolors21.default.dim(" \xB7 "));
15448
+ console.log(` ${import_picocolors21.default.yellow(short)} ${import_picocolors21.default.dim("\u2500\u2500")} ${nameStr}`);
15340
15449
  const subject = await getCommitSubject(hash);
15341
15450
  if (subject) {
15342
- console.log(` ${import_picocolors20.default.dim(subject)}`);
15451
+ console.log(` ${import_picocolors21.default.dim(subject)}`);
15343
15452
  }
15344
15453
  }
15345
15454
  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")}`);
15455
+ console.log(` ${import_picocolors21.default.green("\u2713")} ${import_picocolors21.default.green("All branches aligned")} ${import_picocolors21.default.dim("\u2014 ready to start")}`);
15347
15456
  } else {
15348
- console.log(` ${import_picocolors20.default.yellow("\u26A0")} ${import_picocolors20.default.yellow("Branches are not fully aligned")}`);
15457
+ console.log(` ${import_picocolors21.default.yellow("\u26A0")} ${import_picocolors21.default.yellow("Branches are not fully aligned")}`);
15349
15458
  }
15350
15459
  }
15351
15460
  }
@@ -15354,7 +15463,7 @@ var sync_default = defineCommand({
15354
15463
 
15355
15464
  // src/commands/update.ts
15356
15465
  import { readFileSync as readFileSync6 } from "fs";
15357
- var import_picocolors21 = __toESM(require_picocolors(), 1);
15466
+ var import_picocolors22 = __toESM(require_picocolors(), 1);
15358
15467
  function hasStaleBranchWorkToPreserve(uniqueCommitsAheadOfBase, hasUncommittedChanges2) {
15359
15468
  return hasUncommittedChanges2 || uniqueCommitsAheadOfBase > 0;
15360
15469
  }
@@ -15382,7 +15491,7 @@ var update_default = defineCommand({
15382
15491
  await assertCleanGitState("updating");
15383
15492
  const config = readConfig();
15384
15493
  if (!config) {
15385
- error("No repo config found. Run `contrib setup` first.");
15494
+ error("No repo config found. Run `cn setup` first.");
15386
15495
  process.exit(1);
15387
15496
  }
15388
15497
  const baseBranch = getBaseBranch(config);
@@ -15395,7 +15504,7 @@ var update_default = defineCommand({
15395
15504
  }
15396
15505
  if (protectedBranches.includes(currentBranch)) {
15397
15506
  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.`);
15507
+ warn(`You're on ${import_picocolors22.default.bold(currentBranch)}, which is a protected branch. Updates (rebase) apply to feature branches.`);
15399
15508
  await fetchAll();
15400
15509
  const { origin } = config;
15401
15510
  const remoteRef = `${origin}/${currentBranch}`;
@@ -15404,12 +15513,12 @@ var update_default = defineCommand({
15404
15513
  const hasCommits = localWork.unpushedCommits > 0;
15405
15514
  const hasAnything = hasCommits || dirty;
15406
15515
  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.`);
15516
+ info(`No local changes found on ${import_picocolors22.default.bold(currentBranch)}.`);
15517
+ 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
15518
  process.exit(1);
15410
15519
  }
15411
15520
  if (hasCommits) {
15412
- info(`Found ${import_picocolors21.default.bold(String(localWork.unpushedCommits))} unpushed commit${localWork.unpushedCommits !== 1 ? "s" : ""} on ${import_picocolors21.default.bold(currentBranch)}.`);
15521
+ info(`Found ${import_picocolors22.default.bold(String(localWork.unpushedCommits))} unpushed commit${localWork.unpushedCommits !== 1 ? "s" : ""} on ${import_picocolors22.default.bold(currentBranch)}.`);
15413
15522
  }
15414
15523
  if (dirty) {
15415
15524
  info("You also have uncommitted changes in the working tree.");
@@ -15439,12 +15548,12 @@ var update_default = defineCommand({
15439
15548
  error(`Failed to create branch: ${branchResult.stderr}`);
15440
15549
  process.exit(1);
15441
15550
  }
15442
- success(`Created ${import_picocolors21.default.bold(newBranchName)} with your changes.`);
15551
+ success(`Created ${import_picocolors22.default.bold(newBranchName)} with your changes.`);
15443
15552
  await updateLocalBranch(currentBranch, remoteRef);
15444
- info(`Reset ${import_picocolors21.default.bold(currentBranch)} back to ${import_picocolors21.default.bold(remoteRef)} \u2014 no damage done.`, "");
15553
+ info(`Reset ${import_picocolors22.default.bold(currentBranch)} back to ${import_picocolors22.default.bold(remoteRef)} \u2014 no damage done.`, "");
15445
15554
  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)}.`, "");
15555
+ success(`You're now on ${import_picocolors22.default.bold(newBranchName)} with all your work intact.`);
15556
+ info(`Run ${import_picocolors22.default.bold("cn update")} again to rebase onto latest ${import_picocolors22.default.bold(baseBranch)}.`, "");
15448
15557
  return;
15449
15558
  }
15450
15559
  if (await hasUncommittedChanges()) {
@@ -15454,8 +15563,8 @@ var update_default = defineCommand({
15454
15563
  await projectHeading("update", "\uD83D\uDD03");
15455
15564
  const mergedPR = await getMergedPRForBranch(currentBranch);
15456
15565
  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)}`, "");
15566
+ warn(`PR #${mergedPR.number} (${import_picocolors22.default.bold(mergedPR.title)}) has already been merged.`);
15567
+ info(`Link: ${import_picocolors22.default.underline(mergedPR.url)}`, "");
15459
15568
  const uniqueCommitsAheadOfBase = await countCommitsAhead(currentBranch, syncSource.ref);
15460
15569
  const dirty = await hasUncommittedChanges();
15461
15570
  const hasWork = hasStaleBranchWorkToPreserve(uniqueCommitsAheadOfBase, dirty);
@@ -15464,12 +15573,12 @@ var update_default = defineCommand({
15464
15573
  info("You have uncommitted local changes.");
15465
15574
  }
15466
15575
  if (uniqueCommitsAheadOfBase > 0) {
15467
- info(`You have ${uniqueCommitsAheadOfBase} local commit(s) not in ${import_picocolors21.default.bold(syncSource.ref)}.`);
15576
+ info(`You have ${uniqueCommitsAheadOfBase} local commit(s) not in ${import_picocolors22.default.bold(syncSource.ref)}.`);
15468
15577
  }
15469
15578
  const SAVE_NEW_BRANCH = "Save changes to a new branch";
15470
15579
  const DISCARD = "Discard all changes and clean up";
15471
15580
  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]);
15581
+ 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
15582
  if (action === CANCEL) {
15474
15583
  info("No changes made. You are still on your current branch.");
15475
15584
  return;
@@ -15491,7 +15600,7 @@ var update_default = defineCommand({
15491
15600
  error(`Failed to rename branch: ${renameResult.stderr}`);
15492
15601
  process.exit(1);
15493
15602
  }
15494
- success(`Renamed ${import_picocolors21.default.bold(currentBranch)} \u2192 ${import_picocolors21.default.bold(newBranchName)}`);
15603
+ success(`Renamed ${import_picocolors22.default.bold(currentBranch)} \u2192 ${import_picocolors22.default.bold(newBranchName)}`);
15495
15604
  await unsetUpstream();
15496
15605
  await fetchRemote(syncSource.remote);
15497
15606
  let rebaseResult2;
@@ -15503,11 +15612,11 @@ var update_default = defineCommand({
15503
15612
  }
15504
15613
  if (rebaseResult2.exitCode !== 0) {
15505
15614
  warn("Rebase encountered conflicts. Resolve them manually, then run:");
15506
- info(` ${import_picocolors21.default.bold("git rebase --continue")}`, "");
15615
+ info(` ${import_picocolors22.default.bold("git rebase --continue")}`, "");
15507
15616
  } else {
15508
- success(`Rebased ${import_picocolors21.default.bold(newBranchName)} onto ${import_picocolors21.default.bold(syncSource.ref)}.`);
15617
+ success(`Rebased ${import_picocolors22.default.bold(newBranchName)} onto ${import_picocolors22.default.bold(syncSource.ref)}.`);
15509
15618
  }
15510
- info(`All your changes are preserved. Run ${import_picocolors21.default.bold("contrib submit")} when ready to create a new PR.`, "");
15619
+ info(`All your changes are preserved. Run ${import_picocolors22.default.bold("cn submit")} when ready to create a new PR.`, "");
15511
15620
  return;
15512
15621
  }
15513
15622
  warn("Discarding local changes...");
@@ -15526,24 +15635,24 @@ var update_default = defineCommand({
15526
15635
  process.exit(1);
15527
15636
  }
15528
15637
  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)}...`);
15638
+ success(`Synced ${import_picocolors22.default.bold(baseBranch)} with ${import_picocolors22.default.bold(syncSource.ref)}.`);
15639
+ info(`Deleting stale branch ${import_picocolors22.default.bold(currentBranch)}...`);
15531
15640
  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.`, "");
15641
+ success(`Deleted ${import_picocolors22.default.bold(currentBranch)}.`);
15642
+ info(`Run ${import_picocolors22.default.bold("cn start")} to begin a new feature branch.`, "");
15534
15643
  return;
15535
15644
  }
15536
- info(`Updating ${import_picocolors21.default.bold(currentBranch)} with latest ${import_picocolors21.default.bold(baseBranch)}...`);
15645
+ info(`Updating ${import_picocolors22.default.bold(currentBranch)} with latest ${import_picocolors22.default.bold(baseBranch)}...`);
15537
15646
  await fetchRemote(syncSource.remote);
15538
15647
  if (!await refExists(syncSource.ref)) {
15539
- error(`Remote ref ${import_picocolors21.default.bold(syncSource.ref)} does not exist.`);
15648
+ error(`Remote ref ${import_picocolors22.default.bold(syncSource.ref)} does not exist.`);
15540
15649
  error("Run `git fetch --all` and verify your remote configuration.");
15541
15650
  process.exit(1);
15542
15651
  }
15543
15652
  await updateLocalBranch(baseBranch, syncSource.ref);
15544
15653
  const rebaseStrategy = await determineRebaseStrategy(currentBranch, syncSource.ref);
15545
15654
  if (rebaseStrategy.strategy === "onto" && rebaseStrategy.ontoOldBase) {
15546
- info(import_picocolors21.default.dim(`Using --onto rebase (branch was based on a different ref)`));
15655
+ info(import_picocolors22.default.dim(`Using --onto rebase (branch was based on a different ref)`));
15547
15656
  }
15548
15657
  const rebaseResult = rebaseStrategy.strategy === "onto" && rebaseStrategy.ontoOldBase ? await rebaseOnto(syncSource.ref, rebaseStrategy.ontoOldBase) : await rebase(syncSource.ref);
15549
15658
  if (rebaseResult.exitCode !== 0) {
@@ -15574,10 +15683,10 @@ ${content.slice(0, 2000)}
15574
15683
  if (suggestion) {
15575
15684
  spinner.success("AI conflict guidance ready.");
15576
15685
  console.log(`
15577
- ${import_picocolors21.default.bold("\uD83D\uDCA1 AI Conflict Resolution Guidance:")}`);
15578
- console.log(import_picocolors21.default.dim("\u2500".repeat(60)));
15686
+ ${import_picocolors22.default.bold("\uD83D\uDCA1 AI Conflict Resolution Guidance:")}`);
15687
+ console.log(import_picocolors22.default.dim("\u2500".repeat(60)));
15579
15688
  console.log(suggestion);
15580
- console.log(import_picocolors21.default.dim("\u2500".repeat(60)));
15689
+ console.log(import_picocolors22.default.dim("\u2500".repeat(60)));
15581
15690
  console.log();
15582
15691
  } else {
15583
15692
  spinner.fail("AI could not analyze the conflicts.");
@@ -15585,21 +15694,21 @@ ${import_picocolors21.default.bold("\uD83D\uDCA1 AI Conflict Resolution Guidance
15585
15694
  }
15586
15695
  }
15587
15696
  }
15588
- console.log(import_picocolors21.default.bold("To resolve:"));
15697
+ console.log(import_picocolors22.default.bold("To resolve:"));
15589
15698
  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")}`);
15699
+ console.log(` 2. ${import_picocolors22.default.cyan("git add <resolved-files>")}`);
15700
+ console.log(` 3. ${import_picocolors22.default.cyan("git rebase --continue")}`);
15592
15701
  console.log();
15593
- console.log(` Or abort: ${import_picocolors21.default.cyan("git rebase --abort")}`);
15702
+ console.log(` Or abort: ${import_picocolors22.default.cyan("git rebase --abort")}`);
15594
15703
  process.exit(1);
15595
15704
  }
15596
- success(`${import_picocolors21.default.bold(currentBranch)} has been rebased onto latest ${import_picocolors21.default.bold(baseBranch)}`);
15705
+ success(`${import_picocolors22.default.bold(currentBranch)} has been rebased onto latest ${import_picocolors22.default.bold(baseBranch)}`);
15597
15706
  }
15598
15707
  });
15599
15708
 
15600
15709
  // src/commands/validate.ts
15601
15710
  import { readFileSync as readFileSync7 } from "fs";
15602
- var import_picocolors22 = __toESM(require_picocolors(), 1);
15711
+ var import_picocolors23 = __toESM(require_picocolors(), 1);
15603
15712
  var validate_default = defineCommand({
15604
15713
  meta: {
15605
15714
  name: "validate",
@@ -15619,7 +15728,7 @@ var validate_default = defineCommand({
15619
15728
  async run({ args }) {
15620
15729
  const config = readConfig();
15621
15730
  if (!config) {
15622
- error("No repo config found. Run `contrib setup` first.");
15731
+ error("No repo config found. Run `cn setup` first.");
15623
15732
  process.exit(1);
15624
15733
  }
15625
15734
  await projectHeading("validate", "\u2705");
@@ -15639,1402 +15748,14 @@ var validate_default = defineCommand({
15639
15748
  }
15640
15749
  const errors = getValidationError(convention);
15641
15750
  for (const line of errors) {
15642
- console.error(import_picocolors22.default.red(` \u2717 ${line}`));
15751
+ console.error(import_picocolors23.default.red(` \u2717 ${line}`));
15643
15752
  }
15644
15753
  process.exit(1);
15645
15754
  }
15646
15755
  });
15647
15756
 
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
15757
  // src/ui/banner.ts
17037
- var import_picocolors23 = __toESM(require_picocolors(), 1);
15758
+ var import_picocolors24 = __toESM(require_picocolors(), 1);
17038
15759
 
17039
15760
  // src/data/announcements.json
17040
15761
  var announcements_default = [
@@ -17044,6 +15765,13 @@ var announcements_default = [
17044
15765
  title: "Legacy Config Detected",
17045
15766
  message: "Run cn setup to migrate this clone to local Git config, then delete .contributerc.json.",
17046
15767
  when: "legacy-config-present"
15768
+ },
15769
+ {
15770
+ id: "contrib-command-deprecation",
15771
+ kind: "info",
15772
+ title: "Heads up: `contrib` will retire",
15773
+ message: "The `contrib` command is being phased out. Please switch to `contribute` (primary) or the shorter `cn` shortcut \u2014 same features either way.",
15774
+ when: "contrib-command-used"
17047
15775
  }
17048
15776
  ];
17049
15777
 
@@ -17059,25 +15787,28 @@ function shouldShowAnnouncement(announcement, cwd) {
17059
15787
  switch (announcement.when) {
17060
15788
  case "legacy-config-present":
17061
15789
  return hasLegacyConfig(cwd);
15790
+ case "contrib-command-used":
15791
+ return isLegacyCommandInvocation();
17062
15792
  default:
17063
15793
  return false;
17064
15794
  }
17065
15795
  }
15796
+ function isLegacyCommandInvocation() {
15797
+ const entry = process.argv[1];
15798
+ if (!entry)
15799
+ return false;
15800
+ const basename = entry.split(/[\\/]/).pop() ?? "";
15801
+ const name = basename.replace(/\.(cmd|exe|ps1|bat|js|mjs|cjs)$/i, "").toLowerCase();
15802
+ return name === "contrib";
15803
+ }
17066
15804
 
17067
15805
  // 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
- }
15806
+ var LOGO = String.raw` ______ __ _ __ __ _ __
15807
+ / ____/___ ____ / /______(_) /_ __ __/ /____ / | / /___ _ __
15808
+ / / / __ \/ __ \/ __/ ___/ / __ \/ / / / __/ _ \ / |/ / __ \ | /| / /
15809
+ / /___/ /_/ / / / / /_/ / / / /_/ / /_/ / /_/ __/ / /| / /_/ / |/ |/ /
15810
+ \____/\____/_/ /_/\__/_/ /_/_.___/\__,_/\__/\___/ /_/ |_/\____/|__/|__/
15811
+ `;
17081
15812
  function getVersion() {
17082
15813
  return package_default.version ?? "unknown";
17083
15814
  }
@@ -17085,10 +15816,9 @@ function getAuthor() {
17085
15816
  return typeof package_default.author === "string" ? package_default.author : "unknown";
17086
15817
  }
17087
15818
  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()}`)}`);
15819
+ console.log(import_picocolors24.default.cyan(`
15820
+ ${LOGO}`));
15821
+ console.log(` ${import_picocolors24.default.dim(`v${getVersion()}`)} ${import_picocolors24.default.dim("\u2014")} ${import_picocolors24.default.dim(`Built by ${getAuthor()}`)}`);
17092
15822
  const announcements = getActiveAnnouncements();
17093
15823
  if (announcements.length > 0) {
17094
15824
  console.log();
@@ -17097,27 +15827,27 @@ ${logo}`));
17097
15827
  if (variant === "big") {
17098
15828
  const panelLines = [
17099
15829
  {
17100
- label: import_picocolors23.default.bold(import_picocolors23.default.cyan("Getting Started")),
15830
+ label: import_picocolors24.default.bold(import_picocolors24.default.cyan("Getting Started")),
17101
15831
  rawLabel: "Getting Started",
17102
15832
  value: "",
17103
15833
  rawValue: ""
17104
15834
  },
17105
15835
  {
17106
- label: import_picocolors23.default.cyan("cn setup"),
15836
+ label: import_picocolors24.default.cyan("cn setup"),
17107
15837
  rawLabel: "cn setup",
17108
- value: import_picocolors23.default.dim("configure workflow, remotes, and defaults"),
15838
+ value: import_picocolors24.default.dim("configure workflow, remotes, and defaults"),
17109
15839
  rawValue: "configure workflow, remotes, and defaults"
17110
15840
  },
17111
15841
  {
17112
- label: import_picocolors23.default.cyan("cn doctor"),
15842
+ label: import_picocolors24.default.cyan("cn doctor"),
17113
15843
  rawLabel: "cn doctor",
17114
- value: import_picocolors23.default.dim("verify your environment before doing any work"),
15844
+ value: import_picocolors24.default.dim("verify your environment before doing any work"),
17115
15845
  rawValue: "verify your environment before doing any work"
17116
15846
  },
17117
15847
  {
17118
- label: import_picocolors23.default.cyan("cn start"),
15848
+ label: import_picocolors24.default.cyan("cn start"),
17119
15849
  rawLabel: "cn start",
17120
- value: import_picocolors23.default.dim("create a branch and begin the next task"),
15850
+ value: import_picocolors24.default.dim("create a branch and begin the next task"),
17121
15851
  rawValue: "create a branch and begin the next task"
17122
15852
  },
17123
15853
  {
@@ -17127,13 +15857,13 @@ ${logo}`));
17127
15857
  rawValue: ""
17128
15858
  },
17129
15859
  {
17130
- label: import_picocolors23.default.bold(import_picocolors23.default.cyan("Workflow")),
15860
+ label: import_picocolors24.default.bold(import_picocolors24.default.cyan("Workflow")),
17131
15861
  rawLabel: "Workflow",
17132
15862
  value: "",
17133
15863
  rawValue: ""
17134
15864
  },
17135
15865
  {
17136
- label: import_picocolors23.default.dim("cn setup \u2192 cn commit \u2192 cn update \u2192 cn submit"),
15866
+ label: import_picocolors24.default.dim("cn setup \u2192 cn commit \u2192 cn update \u2192 cn submit"),
17137
15867
  rawLabel: "cn setup \u2192 cn commit \u2192 cn update \u2192 cn submit",
17138
15868
  value: "",
17139
15869
  rawValue: ""
@@ -17158,22 +15888,22 @@ ${logo}`));
17158
15888
  return Math.max(max, lineLength);
17159
15889
  }, 0));
17160
15890
  console.log();
17161
- console.log(` ${import_picocolors23.default.dim(`\u250C${"\u2500".repeat(contentWidth + 2)}\u2510`)}`);
15891
+ console.log(` ${import_picocolors24.default.dim(`\u250C${"\u2500".repeat(contentWidth + 2)}\u2510`)}`);
17162
15892
  for (const line of rows) {
17163
15893
  if (!line.rawLabel && !line.rawValue) {
17164
- console.log(` ${import_picocolors23.default.dim("\u2502")} ${" ".repeat(contentWidth)} ${import_picocolors23.default.dim("\u2502")}`);
15894
+ console.log(` ${import_picocolors24.default.dim("\u2502")} ${" ".repeat(contentWidth)} ${import_picocolors24.default.dim("\u2502")}`);
17165
15895
  continue;
17166
15896
  }
17167
15897
  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) : "";
15898
+ const value = line.rawValue ? import_picocolors24.default.dim(line.rawValue) : "";
17169
15899
  const rawLength = line.rawValue ? labelWidth + 2 + line.rawValue.length : line.rawLabel.length;
17170
15900
  const trailing = " ".repeat(Math.max(0, contentWidth - rawLength));
17171
- console.log(` ${import_picocolors23.default.dim("\u2502")} ${left}${value}${trailing} ${import_picocolors23.default.dim("\u2502")}`);
15901
+ console.log(` ${import_picocolors24.default.dim("\u2502")} ${left}${value}${trailing} ${import_picocolors24.default.dim("\u2502")}`);
17172
15902
  }
17173
- console.log(` ${import_picocolors23.default.dim(`\u2514${"\u2500".repeat(contentWidth + 2)}\u2518`)}`);
15903
+ console.log(` ${import_picocolors24.default.dim(`\u2514${"\u2500".repeat(contentWidth + 2)}\u2518`)}`);
17174
15904
  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"))}`);
15905
+ 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"))}`);
15906
+ console.log(` ${import_picocolors24.default.dim("Sponsor:")} ${import_picocolors24.default.dim(linkify("warengonzaga.com/sponsor", "https://warengonzaga.com/sponsor"))}`);
17177
15907
  }
17178
15908
  console.log();
17179
15909
  }
@@ -17205,7 +15935,7 @@ function renderAnnouncementBanner(announcement) {
17205
15935
  console.log(` ${tone.border(`\u250C${"\u2500".repeat(rawWidth + 2)}\u2510`)}`);
17206
15936
  for (const line of lines) {
17207
15937
  const trailing = " ".repeat(Math.max(0, rawWidth - line.length));
17208
- const content = line === title ? tone.title(line) : import_picocolors23.default.dim(line);
15938
+ const content = line === title ? tone.title(line) : import_picocolors24.default.dim(line);
17209
15939
  console.log(` ${tone.border("\u2502")} ${content}${trailing} ${tone.border("\u2502")}`);
17210
15940
  }
17211
15941
  console.log(` ${tone.border(`\u2514${"\u2500".repeat(rawWidth + 2)}\u2518`)}`);
@@ -17241,20 +15971,20 @@ function getAnnouncementTone(kind) {
17241
15971
  case "info":
17242
15972
  return {
17243
15973
  emoji: "\u2139",
17244
- border: import_picocolors23.default.blue,
17245
- title: (value) => import_picocolors23.default.bold(import_picocolors23.default.blue(value))
15974
+ border: import_picocolors24.default.blue,
15975
+ title: (value) => import_picocolors24.default.bold(import_picocolors24.default.blue(value))
17246
15976
  };
17247
15977
  case "warning":
17248
15978
  return {
17249
15979
  emoji: "\uD83D\uDEA8",
17250
- border: import_picocolors23.default.red,
17251
- title: (value) => import_picocolors23.default.bold(import_picocolors23.default.red(value))
15980
+ border: import_picocolors24.default.red,
15981
+ title: (value) => import_picocolors24.default.bold(import_picocolors24.default.red(value))
17252
15982
  };
17253
15983
  default:
17254
15984
  return {
17255
15985
  emoji: "\u26A0",
17256
- border: import_picocolors23.default.yellow,
17257
- title: (value) => import_picocolors23.default.bold(import_picocolors23.default.yellow(value))
15986
+ border: import_picocolors24.default.yellow,
15987
+ title: (value) => import_picocolors24.default.bold(import_picocolors24.default.yellow(value))
17258
15988
  };
17259
15989
  }
17260
15990
  }
@@ -17285,6 +16015,7 @@ if (!isVersion) {
17285
16015
  "update",
17286
16016
  "submit",
17287
16017
  "switch",
16018
+ "discard",
17288
16019
  "save",
17289
16020
  "clean",
17290
16021
  "status",
@@ -17301,7 +16032,7 @@ if (!isVersion) {
17301
16032
  }
17302
16033
  var main = defineCommand({
17303
16034
  meta: {
17304
- name: "contrib",
16035
+ name: "cn",
17305
16036
  version: getVersion(),
17306
16037
  description: "Git workflow CLI that guides contributors through clean branching, commits, and PRs."
17307
16038
  },
@@ -17321,6 +16052,7 @@ var main = defineCommand({
17321
16052
  update: update_default,
17322
16053
  submit: submit_default,
17323
16054
  switch: switch_default,
16055
+ discard: discard_default,
17324
16056
  save: save_default,
17325
16057
  branch: branch_default,
17326
16058
  clean: clean_default,
@@ -17332,8 +16064,11 @@ var main = defineCommand({
17332
16064
  },
17333
16065
  run({ args }) {
17334
16066
  if (args.version) {
17335
- console.log(`contrib v${getVersion()}`);
16067
+ console.log(`cn v${getVersion()}`);
17336
16068
  }
17337
16069
  }
17338
16070
  });
17339
- runMain(main);
16071
+ runMain(main).then(() => process.exit(process.exitCode ?? 0)).catch((err) => {
16072
+ console.error(err);
16073
+ process.exit(1);
16074
+ });