contribute-now 0.4.1-dev.f9d0aaa → 0.4.1-pr.f338a8f

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 +8 -6
  2. package/dist/index.js +281 -32
  3. package/package.json +5 -4
package/README.md CHANGED
@@ -204,17 +204,19 @@ Checks include:
204
204
 
205
205
  ### `contrib log`
206
206
 
207
- Show a colorized, workflow-aware commit log with graph visualization.
207
+ Show a colorized, workflow-aware commit log. By default it shows only **local unpushed commits** — the changes you've made since the last push (or since branching off the base branch). Use flags to switch between different views.
208
208
 
209
209
  ```bash
210
- contrib log # last 20 commits with graph
211
- contrib log -n 50 # last 50 commits
212
- contrib log --all # all branches
213
- contrib log --no-graph # flat view without graph lines
210
+ contrib log # local unpushed commits (default)
211
+ contrib log --remote # commits on remote not yet pulled
212
+ contrib log --full # full history for the current branch
213
+ contrib log --all # commits across all branches
214
+ contrib log -n 50 # change the commit limit (default: 20)
214
215
  contrib log -b feature/x # log for a specific branch
216
+ contrib log --no-graph # flat view without graph lines
215
217
  ```
216
218
 
217
- Protected branches (main, dev) are highlighted, and the current branch is color-coded for quick orientation.
219
+ When no upstream tracking is set (branch hasn't been pushed yet), the command automatically compares against the base branch from your config (e.g., `origin/dev`). Protected branches are highlighted, and the current branch is color-coded for quick orientation.
218
220
 
219
221
  ---
220
222
 
package/dist/index.js CHANGED
@@ -547,6 +547,76 @@ async function getLogEntries(options) {
547
547
  return { hash: hash.trim(), subject: subject.trim(), refs: refs.trim() };
548
548
  });
549
549
  }
550
+ async function getLocalCommitsGraph(options) {
551
+ const count = options?.count ?? 20;
552
+ const upstream = options?.upstream;
553
+ if (!upstream)
554
+ return [];
555
+ const args = [
556
+ "log",
557
+ "--oneline",
558
+ "--graph",
559
+ "--decorate",
560
+ `--max-count=${count}`,
561
+ "--color=never",
562
+ `${upstream}..HEAD`
563
+ ];
564
+ const { exitCode, stdout } = await run(args);
565
+ if (exitCode !== 0)
566
+ return [];
567
+ return stdout.trimEnd().split(`
568
+ `).filter(Boolean);
569
+ }
570
+ async function getLocalCommitsEntries(options) {
571
+ const count = options?.count ?? 20;
572
+ const upstream = options?.upstream;
573
+ if (!upstream)
574
+ return [];
575
+ const args = ["log", `--format=%h||%s||%D`, `--max-count=${count}`, `${upstream}..HEAD`];
576
+ const { exitCode, stdout } = await run(args);
577
+ if (exitCode !== 0)
578
+ return [];
579
+ return stdout.trimEnd().split(`
580
+ `).filter(Boolean).map((line) => {
581
+ const [hash = "", subject = "", refs = ""] = line.split("||");
582
+ return { hash: hash.trim(), subject: subject.trim(), refs: refs.trim() };
583
+ });
584
+ }
585
+ async function getRemoteOnlyCommitsGraph(options) {
586
+ const count = options?.count ?? 20;
587
+ const upstream = options?.upstream;
588
+ if (!upstream)
589
+ return [];
590
+ const args = [
591
+ "log",
592
+ "--oneline",
593
+ "--graph",
594
+ "--decorate",
595
+ `--max-count=${count}`,
596
+ "--color=never",
597
+ `HEAD..${upstream}`
598
+ ];
599
+ const { exitCode, stdout } = await run(args);
600
+ if (exitCode !== 0)
601
+ return [];
602
+ return stdout.trimEnd().split(`
603
+ `).filter(Boolean);
604
+ }
605
+ async function getRemoteOnlyCommitsEntries(options) {
606
+ const count = options?.count ?? 20;
607
+ const upstream = options?.upstream;
608
+ if (!upstream)
609
+ return [];
610
+ const args = ["log", `--format=%h||%s||%D`, `--max-count=${count}`, `HEAD..${upstream}`];
611
+ const { exitCode, stdout } = await run(args);
612
+ if (exitCode !== 0)
613
+ return [];
614
+ return stdout.trimEnd().split(`
615
+ `).filter(Boolean).map((line) => {
616
+ const [hash = "", subject = "", refs = ""] = line.split("||");
617
+ return { hash: hash.trim(), subject: subject.trim(), refs: refs.trim() };
618
+ });
619
+ }
550
620
  async function getLocalBranches() {
551
621
  const { exitCode, stdout } = await run(["branch", "-vv", "--no-color"]);
552
622
  if (exitCode !== 0)
@@ -2163,7 +2233,7 @@ import pc7 from "picocolors";
2163
2233
  // package.json
2164
2234
  var package_default = {
2165
2235
  name: "contribute-now",
2166
- version: "0.4.1-dev.f9d0aaa",
2236
+ version: "0.4.1-pr.f338a8f",
2167
2237
  description: "Developer CLI that automates git workflows — branching, syncing, committing, and PRs — with multi-workflow and commit convention support.",
2168
2238
  type: "module",
2169
2239
  bin: {
@@ -2181,9 +2251,10 @@ var package_default = {
2181
2251
  lint: "biome check .",
2182
2252
  "lint:fix": "biome check --write .",
2183
2253
  format: "biome format --write .",
2184
- "www:dev": "bun run --cwd www dev",
2185
- "www:build": "bun run --cwd www build",
2186
- "www:preview": "bun run --cwd www preview"
2254
+ "landing:install": "bun install --cwd landing",
2255
+ "landing:dev": "bun run --cwd landing dev",
2256
+ "landing:build": "bun run --cwd landing build",
2257
+ "landing:preview": "bun run --cwd landing preview"
2187
2258
  },
2188
2259
  engines: {
2189
2260
  node: ">=18",
@@ -2681,7 +2752,19 @@ var log_default = defineCommand6({
2681
2752
  all: {
2682
2753
  type: "boolean",
2683
2754
  alias: "a",
2684
- description: "Show all branches, not just current",
2755
+ description: "Show commits from all branches",
2756
+ default: false
2757
+ },
2758
+ remote: {
2759
+ type: "boolean",
2760
+ alias: "r",
2761
+ description: "Show only remote commits not yet pulled locally",
2762
+ default: false
2763
+ },
2764
+ full: {
2765
+ type: "boolean",
2766
+ alias: "f",
2767
+ description: "Show full commit history for the current branch",
2685
2768
  default: false
2686
2769
  },
2687
2770
  graph: {
@@ -2703,44 +2786,197 @@ var log_default = defineCommand6({
2703
2786
  }
2704
2787
  const config = readConfig();
2705
2788
  const count = args.count ? Number.parseInt(args.count, 10) : 20;
2706
- const showAll = args.all;
2707
2789
  const showGraph = args.graph;
2708
2790
  const targetBranch = args.branch;
2791
+ let mode = "local";
2792
+ if (args.all)
2793
+ mode = "all";
2794
+ else if (args.remote)
2795
+ mode = "remote";
2796
+ else if (args.full || targetBranch)
2797
+ mode = "full";
2709
2798
  const protectedBranches = config ? getProtectedBranches(config) : ["main", "master"];
2710
2799
  const currentBranch = await getCurrentBranch();
2800
+ const upstream = await getUpstreamRef();
2801
+ let compareRef = upstream;
2802
+ let usingFallback = false;
2803
+ if (!compareRef) {
2804
+ const fallback = await resolveBaseBranchRef(config);
2805
+ if (fallback) {
2806
+ compareRef = fallback;
2807
+ usingFallback = true;
2808
+ }
2809
+ }
2711
2810
  heading("\uD83D\uDCDC commit log");
2712
- if (showGraph) {
2713
- const lines = await getLogGraph({ count, all: showAll, branch: targetBranch });
2714
- if (lines.length === 0) {
2715
- console.log(pc9.dim(" No commits found."));
2811
+ printModeHeader(mode, currentBranch, compareRef, usingFallback);
2812
+ if (mode === "local" || mode === "remote") {
2813
+ if (!compareRef) {
2716
2814
  console.log();
2815
+ console.log(pc9.yellow(" ⚠ Could not determine a comparison branch."));
2816
+ console.log(pc9.dim(" No upstream tracking set and no remote base branch found."));
2817
+ console.log(pc9.dim(` Use ${pc9.bold("contrib log --full")} to see the full commit history instead.`));
2818
+ console.log();
2819
+ printGuidance();
2717
2820
  return;
2718
2821
  }
2719
- console.log();
2720
- for (const line of lines) {
2721
- console.log(` ${colorizeGraphLine(line, protectedBranches, currentBranch)}`);
2822
+ const hasCommits = await renderScopedLog({ mode, count, upstream: compareRef, showGraph, protectedBranches, currentBranch });
2823
+ if (!hasCommits) {
2824
+ printGuidance();
2825
+ return;
2722
2826
  }
2723
2827
  } else {
2724
- const entries = await getLogEntries({ count, all: showAll, branch: targetBranch });
2725
- if (entries.length === 0) {
2726
- console.log(pc9.dim(" No commits found."));
2727
- console.log();
2828
+ const hasCommits = await renderFullLog({ count, all: mode === "all", showGraph, targetBranch, protectedBranches, currentBranch });
2829
+ if (!hasCommits) {
2830
+ printGuidance();
2728
2831
  return;
2729
2832
  }
2730
- console.log();
2731
- for (const entry of entries) {
2732
- const hashStr = pc9.yellow(entry.hash);
2733
- const refsStr = entry.refs ? ` ${colorizeRefs(entry.refs, protectedBranches, currentBranch)}` : "";
2734
- const subjectStr = colorizeSubject(entry.subject);
2735
- console.log(` ${hashStr}${refsStr} ${subjectStr}`);
2833
+ }
2834
+ printFooter(mode, count, targetBranch);
2835
+ printGuidance();
2836
+ }
2837
+ });
2838
+ async function resolveBaseBranchRef(config) {
2839
+ if (!config) {
2840
+ for (const candidate2 of ["origin/main", "origin/master"]) {
2841
+ if (await branchExists(candidate2))
2842
+ return candidate2;
2843
+ }
2844
+ return null;
2845
+ }
2846
+ const baseBranch = getBaseBranch(config);
2847
+ const remote = config.origin ?? "origin";
2848
+ const candidate = `${remote}/${baseBranch}`;
2849
+ if (await branchExists(candidate))
2850
+ return candidate;
2851
+ for (const fallback of ["origin/main", "origin/master"]) {
2852
+ if (fallback !== candidate && await branchExists(fallback))
2853
+ return fallback;
2854
+ }
2855
+ return null;
2856
+ }
2857
+ function printModeHeader(mode, currentBranch, compareRef, usingFallback = false) {
2858
+ const branch = currentBranch ?? "HEAD";
2859
+ const fallbackNote = usingFallback ? pc9.yellow(" (no upstream — comparing against base branch)") : "";
2860
+ console.log();
2861
+ switch (mode) {
2862
+ case "local":
2863
+ console.log(pc9.dim(` mode: ${pc9.bold("local")} — unpushed commits on ${pc9.bold(branch)}`) + fallbackNote);
2864
+ if (compareRef) {
2865
+ console.log(pc9.dim(` comparing: ${pc9.bold(compareRef)} ➜ ${pc9.bold("HEAD")}`));
2866
+ }
2867
+ break;
2868
+ case "remote":
2869
+ console.log(pc9.dim(` mode: ${pc9.bold("remote")} — commits on remote not yet pulled into ${pc9.bold(branch)}`) + fallbackNote);
2870
+ if (compareRef) {
2871
+ console.log(pc9.dim(` comparing: ${pc9.bold("HEAD")} ➜ ${pc9.bold(compareRef)}`));
2736
2872
  }
2873
+ break;
2874
+ case "full":
2875
+ console.log(pc9.dim(` mode: ${pc9.bold("full")} — complete commit history for ${pc9.bold(branch)}`));
2876
+ break;
2877
+ case "all":
2878
+ console.log(pc9.dim(` mode: ${pc9.bold("all")} — commits across all branches`));
2879
+ break;
2880
+ }
2881
+ }
2882
+ async function renderScopedLog(options) {
2883
+ const { mode, count, upstream, showGraph, protectedBranches, currentBranch } = options;
2884
+ if (showGraph) {
2885
+ const graphFn = mode === "local" ? getLocalCommitsGraph : getRemoteOnlyCommitsGraph;
2886
+ const lines = await graphFn({ count, upstream });
2887
+ if (lines.length === 0) {
2888
+ printEmptyState(mode);
2889
+ return false;
2737
2890
  }
2738
2891
  console.log();
2739
- console.log(pc9.dim(` Showing ${count} most recent commits${showAll ? " (all branches)" : targetBranch ? ` (${targetBranch})` : ""}`));
2740
- console.log(pc9.dim(` Use ${pc9.bold("contrib log -n 50")} for more, or ${pc9.bold("contrib log --all")} for all branches`));
2892
+ for (const line of lines) {
2893
+ console.log(` ${colorizeGraphLine(line, protectedBranches, currentBranch)}`);
2894
+ }
2895
+ } else {
2896
+ const entryFn = mode === "local" ? getLocalCommitsEntries : getRemoteOnlyCommitsEntries;
2897
+ const entries = await entryFn({ count, upstream });
2898
+ if (entries.length === 0) {
2899
+ printEmptyState(mode);
2900
+ return false;
2901
+ }
2741
2902
  console.log();
2903
+ for (const entry of entries) {
2904
+ const hashStr = pc9.yellow(entry.hash);
2905
+ const refsStr = entry.refs ? ` ${colorizeRefs(entry.refs, protectedBranches, currentBranch)}` : "";
2906
+ const subjectStr = colorizeSubject(entry.subject);
2907
+ console.log(` ${hashStr}${refsStr} ${subjectStr}`);
2908
+ }
2742
2909
  }
2743
- });
2910
+ return true;
2911
+ }
2912
+ function printEmptyState(mode) {
2913
+ console.log();
2914
+ if (mode === "local") {
2915
+ console.log(pc9.dim(" No local unpushed commits — you're up to date with remote!"));
2916
+ } else {
2917
+ console.log(pc9.dim(" No remote-only commits — your local branch is up to date!"));
2918
+ }
2919
+ console.log();
2920
+ }
2921
+ async function renderFullLog(options) {
2922
+ const { count, all, showGraph, targetBranch, protectedBranches, currentBranch } = options;
2923
+ if (showGraph) {
2924
+ const lines = await getLogGraph({ count, all, branch: targetBranch });
2925
+ if (lines.length === 0) {
2926
+ console.log(pc9.dim(" No commits found."));
2927
+ console.log();
2928
+ return false;
2929
+ }
2930
+ console.log();
2931
+ for (const line of lines) {
2932
+ console.log(` ${colorizeGraphLine(line, protectedBranches, currentBranch)}`);
2933
+ }
2934
+ } else {
2935
+ const entries = await getLogEntries({ count, all, branch: targetBranch });
2936
+ if (entries.length === 0) {
2937
+ console.log(pc9.dim(" No commits found."));
2938
+ console.log();
2939
+ return false;
2940
+ }
2941
+ console.log();
2942
+ for (const entry of entries) {
2943
+ const hashStr = pc9.yellow(entry.hash);
2944
+ const refsStr = entry.refs ? ` ${colorizeRefs(entry.refs, protectedBranches, currentBranch)}` : "";
2945
+ const subjectStr = colorizeSubject(entry.subject);
2946
+ console.log(` ${hashStr}${refsStr} ${subjectStr}`);
2947
+ }
2948
+ }
2949
+ return true;
2950
+ }
2951
+ function printFooter(mode, count, targetBranch) {
2952
+ console.log();
2953
+ switch (mode) {
2954
+ case "local":
2955
+ console.log(pc9.dim(` Showing up to ${count} unpushed commits`));
2956
+ break;
2957
+ case "remote":
2958
+ console.log(pc9.dim(` Showing up to ${count} remote-only commits`));
2959
+ break;
2960
+ case "full":
2961
+ console.log(pc9.dim(` Showing ${count} most recent commits${targetBranch ? ` (${targetBranch})` : ""}`));
2962
+ break;
2963
+ case "all":
2964
+ console.log(pc9.dim(` Showing ${count} most recent commits (all branches)`));
2965
+ break;
2966
+ }
2967
+ }
2968
+ function printGuidance() {
2969
+ console.log();
2970
+ console.log(pc9.dim(" ─── quick guide ───"));
2971
+ console.log(pc9.dim(` ${pc9.bold("contrib log")} local unpushed commits (default)`));
2972
+ console.log(pc9.dim(` ${pc9.bold("contrib log --remote")} commits on remote not yet pulled`));
2973
+ console.log(pc9.dim(` ${pc9.bold("contrib log --full")} full history for the current branch`));
2974
+ console.log(pc9.dim(` ${pc9.bold("contrib log --all")} commits across all branches`));
2975
+ console.log(pc9.dim(` ${pc9.bold("contrib log -n 50")} change the commit limit (default: 20)`));
2976
+ console.log(pc9.dim(` ${pc9.bold("contrib log -b dev")} view log for a specific branch`));
2977
+ console.log(pc9.dim(` ${pc9.bold("contrib log --no-graph")} flat list without graph lines`));
2978
+ console.log();
2979
+ }
2744
2980
  function colorizeGraphLine(line, protectedBranches, currentBranch) {
2745
2981
  const match = line.match(/^([|/\\*\s_.-]*)([a-f0-9]{7,12})(\s+\(([^)]+)\))?\s*(.*)/);
2746
2982
  if (!match) {
@@ -3581,6 +3817,25 @@ var submit_default = defineCommand10({
3581
3817
  return;
3582
3818
  }
3583
3819
  }
3820
+ if (ghInstalled && ghAuthed) {
3821
+ const existingPR = await getPRForBranch(currentBranch);
3822
+ if (existingPR) {
3823
+ info(`Pushing ${pc13.bold(currentBranch)} to ${origin}...`);
3824
+ const pushResult2 = await pushSetUpstream(origin, currentBranch);
3825
+ if (pushResult2.exitCode !== 0) {
3826
+ error(`Failed to push: ${pushResult2.stderr}`);
3827
+ if (pushResult2.stderr.includes("rejected") || pushResult2.stderr.includes("non-fast-forward")) {
3828
+ warn("The remote branch has diverged. Try:");
3829
+ info(` git pull --rebase ${origin} ${currentBranch}`);
3830
+ info(" Then run `contrib submit` again.");
3831
+ }
3832
+ process.exit(1);
3833
+ }
3834
+ success(`Pushed changes to existing PR #${existingPR.number}: ${pc13.bold(existingPR.title)}`);
3835
+ console.log(` ${pc13.cyan(existingPR.url)}`);
3836
+ return;
3837
+ }
3838
+ }
3584
3839
  let prTitle = null;
3585
3840
  let prBody = null;
3586
3841
  async function tryGenerateAI() {
@@ -3714,12 +3969,6 @@ ${pc13.dim("AI body preview:")}`);
3714
3969
  }
3715
3970
  return;
3716
3971
  }
3717
- const existingPR = await getPRForBranch(currentBranch);
3718
- if (existingPR) {
3719
- success(`Pushed changes to existing PR #${existingPR.number}: ${pc13.bold(existingPR.title)}`);
3720
- console.log(` ${pc13.cyan(existingPR.url)}`);
3721
- return;
3722
- }
3723
3972
  if (submitAction === "fill") {
3724
3973
  const fillResult = await createPRFill(baseBranch, args.draft);
3725
3974
  if (fillResult.exitCode !== 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "contribute-now",
3
- "version": "0.4.1-dev.f9d0aaa",
3
+ "version": "0.4.1-pr.f338a8f",
4
4
  "description": "Developer CLI that automates git workflows — branching, syncing, committing, and PRs — with multi-workflow and commit convention support.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -18,9 +18,10 @@
18
18
  "lint": "biome check .",
19
19
  "lint:fix": "biome check --write .",
20
20
  "format": "biome format --write .",
21
- "www:dev": "bun run --cwd www dev",
22
- "www:build": "bun run --cwd www build",
23
- "www:preview": "bun run --cwd www preview"
21
+ "landing:install": "bun install --cwd landing",
22
+ "landing:dev": "bun run --cwd landing dev",
23
+ "landing:build": "bun run --cwd landing build",
24
+ "landing:preview": "bun run --cwd landing preview"
24
25
  },
25
26
  "engines": {
26
27
  "node": ">=18",