zapdev 1.18.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/cli.js +30 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -114,7 +114,7 @@ Stages all changes, scans them with Gitleaks when installed, generates Conventio
|
|
|
114
114
|
- **Unified review:** generates messages in parallel, then presents every message with its repository name and branch. Repositories with pending changes are shown in bold when terminal styling is enabled.
|
|
115
115
|
- **Actions:** commit all, commit only a named repository, edit a named repository's message, or cancel. Editing returns to the review menu.
|
|
116
116
|
|
|
117
|
-
Only repositories successfully committed during the current run are offered for push or pushed with `--push`. Unselected or cancelled changes remain staged; failed or unselected commit drafts are not pushed. The branch is chosen before committing, never when pushing. Push confirmation is asked once, only for repositories with a
|
|
117
|
+
Only repositories successfully committed during the current run are offered for push or pushed with `--push`. Unselected or cancelled changes remain staged; failed or unselected commit drafts are not pushed. The branch is chosen before committing, never when pushing. Push confirmation is asked once, only for repositories with a resolved push remote; it is omitted when none have one.
|
|
118
118
|
|
|
119
119
|
```bash
|
|
120
120
|
zapdev commit
|
|
@@ -149,7 +149,7 @@ Each step uses one spinner: start, wait, stop. Normal Git and hook output is cap
|
|
|
149
149
|
|
|
150
150
|
Immediately before each selected commit, zapdev asks for a local branch only when the current name exactly matches `main`, `master`, `principal`, `dev`, or `development`, including with `--yes`. The first prompt starts empty; subsequent prompts reuse the previous input across repositories. Press Enter to accept the prefilled name; an empty or cleared input keeps the current branch and leaves the next prompt empty. A different name switches to the existing local branch or creates it from HEAD, without forcing or discarding pending changes. Other branches and repositories with nothing to commit never trigger this prompt. Cancelling stops the remaining commits and all pushes; earlier commits remain local.
|
|
151
151
|
|
|
152
|
-
Pushes always target a remote branch with the current local branch's name, with no destination input.
|
|
152
|
+
Pushes always target a remote branch with the current local branch's name, with no destination input. The remote is the branch's configured upstream remote, otherwise `origin`, otherwise the only configured remote. With no remote or multiple remotes and no `origin`, push is skipped with a warning. The first successful push sets the upstream when none exists; existing upstreams are preserved. Pushes run directly, without a preliminary fetch or history comparison; Git handles up-to-date branches and rejects non-fast-forward updates. No rebase, merge, retry, or force-push.
|
|
153
153
|
|
|
154
154
|
Without a TTY, zapdev commits prepared repositories on nonprotected branches automatically; protected-branch commits are refused and changes remain staged. `--push` can publish without a TTY; without it, commits stay local. Repositories without new changes do not trigger an LLM call, branch prompt, or new commit.
|
|
155
155
|
|
package/dist/cli.js
CHANGED
|
@@ -1736,7 +1736,7 @@ function _getBuiltinFlags(long, short, userNames, userAliases) {
|
|
|
1736
1736
|
// package.json
|
|
1737
1737
|
var package_default = {
|
|
1738
1738
|
name: "zapdev",
|
|
1739
|
-
version: "
|
|
1739
|
+
version: "2.0.0",
|
|
1740
1740
|
description: "Fast, performant and lightweight git chores and dev tools using your terminal and an OpenAI-compatible LLM endpoint.",
|
|
1741
1741
|
type: "module",
|
|
1742
1742
|
bin: {
|
|
@@ -2323,13 +2323,24 @@ async function getRepoStatus(repo) {
|
|
|
2323
2323
|
};
|
|
2324
2324
|
}
|
|
2325
2325
|
async function getUpstreamRemote(repo, branch) {
|
|
2326
|
-
const remotes =
|
|
2326
|
+
const remotes = await getRemotes(repo);
|
|
2327
2327
|
const upstream = (await git(["for-each-ref", "--format=%(upstream:remotename)", `refs/heads/${branch}`], repo)).trim();
|
|
2328
2328
|
return remotes.includes(upstream) ? upstream : null;
|
|
2329
2329
|
}
|
|
2330
|
+
async function getPushRemote(repo, branch) {
|
|
2331
|
+
const upstream = await getUpstreamRemote(repo, branch);
|
|
2332
|
+
if (upstream) return upstream;
|
|
2333
|
+
const remotes = await getRemotes(repo);
|
|
2334
|
+
return remotes.includes("origin") ? "origin" : remotes.length === 1 ? remotes[0] : null;
|
|
2335
|
+
}
|
|
2336
|
+
async function getRemotes(repo) {
|
|
2337
|
+
return (await git(["remote"], repo)).trim().split("\n").filter(Boolean);
|
|
2338
|
+
}
|
|
2330
2339
|
async function push(repo, remote, branch, onHook, onOutput) {
|
|
2331
2340
|
await git(["check-ref-format", "--branch", branch], repo);
|
|
2332
|
-
|
|
2341
|
+
const current = await currentBranch(repo);
|
|
2342
|
+
const upstream = (await git(["for-each-ref", "--format=%(upstream)", `refs/heads/${current}`], repo)).trim();
|
|
2343
|
+
await git(["push", ...!upstream ? ["--set-upstream"] : [], "--", remote, `HEAD:refs/heads/${branch}`], repo, onHook, onOutput);
|
|
2333
2344
|
}
|
|
2334
2345
|
async function findRepos(path) {
|
|
2335
2346
|
const root = await repoRoot(path);
|
|
@@ -2464,9 +2475,9 @@ var COMMIT_TYPES = [
|
|
|
2464
2475
|
];
|
|
2465
2476
|
|
|
2466
2477
|
// src/commands/git-task.ts
|
|
2467
|
-
async function runTask(title, successMessage, run) {
|
|
2478
|
+
async function runTask(title, successMessage, run, withGuide = true) {
|
|
2468
2479
|
const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
2469
|
-
const loader = interactive ? spinner({ withGuide
|
|
2480
|
+
const loader = interactive ? spinner({ withGuide }) : void 0;
|
|
2470
2481
|
const wasRaw = Boolean(process.stdin.isRaw);
|
|
2471
2482
|
loader?.start(title);
|
|
2472
2483
|
if (loader) {
|
|
@@ -2476,7 +2487,7 @@ async function runTask(title, successMessage, run) {
|
|
|
2476
2487
|
try {
|
|
2477
2488
|
const result = await run(() => void 0);
|
|
2478
2489
|
if (loader) loader.stop(successMessage);
|
|
2479
|
-
else log.success(successMessage);
|
|
2490
|
+
else log.success(successMessage, { spacing: 0 });
|
|
2480
2491
|
return result;
|
|
2481
2492
|
} catch (error) {
|
|
2482
2493
|
loader?.clear();
|
|
@@ -2541,7 +2552,7 @@ var commitCommand = defineCommand({
|
|
|
2541
2552
|
effort: args.effort
|
|
2542
2553
|
});
|
|
2543
2554
|
} catch (error) {
|
|
2544
|
-
log.error(errorMessage(error));
|
|
2555
|
+
log.error(errorMessage(error), { spacing: 0 });
|
|
2545
2556
|
process.exitCode = 1;
|
|
2546
2557
|
return;
|
|
2547
2558
|
}
|
|
@@ -2572,7 +2583,7 @@ var commitCommand = defineCommand({
|
|
|
2572
2583
|
return results2;
|
|
2573
2584
|
});
|
|
2574
2585
|
for (const result of pulls) {
|
|
2575
|
-
if (result.status === "fulfilled" && result.value) log.warn(result.value);
|
|
2586
|
+
if (result.status === "fulfilled" && result.value) log.warn(result.value, { spacing: 0 });
|
|
2576
2587
|
}
|
|
2577
2588
|
}
|
|
2578
2589
|
const repositories = repos.map((repo) => ({ repo, label: basename(repo), pendingLabel: basename(repo) }));
|
|
@@ -2597,12 +2608,12 @@ var commitCommand = defineCommand({
|
|
|
2597
2608
|
}
|
|
2598
2609
|
return { results: results2, scan: scan2 };
|
|
2599
2610
|
});
|
|
2600
|
-
if (!scan) log.info("Gitleaks not found, skipping secret scan.");
|
|
2611
|
+
if (!scan) log.info("Gitleaks not found, skipping secret scan.", { spacing: 0 });
|
|
2601
2612
|
const drafts = [];
|
|
2602
2613
|
for (const [index, result] of results.entries()) {
|
|
2603
2614
|
if (result.status === "fulfilled") {
|
|
2604
2615
|
if (result.value) drafts.push(result.value);
|
|
2605
|
-
else log.info(`${repositories[index].pendingLabel}: nothing to commit
|
|
2616
|
+
else log.info(`${repositories[index].pendingLabel}: nothing to commit.`, { spacing: 0 });
|
|
2606
2617
|
}
|
|
2607
2618
|
}
|
|
2608
2619
|
const selected = drafts.length ? await reviewMessages(drafts, interactive && !args.yes) : [];
|
|
@@ -2613,6 +2624,7 @@ var commitCommand = defineCommand({
|
|
|
2613
2624
|
const toSend = [];
|
|
2614
2625
|
let previousBranchInput = "";
|
|
2615
2626
|
for (const draft of selected) {
|
|
2627
|
+
let withGuide = true;
|
|
2616
2628
|
const current = await currentBranch(draft.repo);
|
|
2617
2629
|
if (/^(main|master|principal|dev|development)$/.test(current)) {
|
|
2618
2630
|
if (!interactive) throw new Error("Committing on a protected branch requires a terminal to choose a branch. Changes remain staged.");
|
|
@@ -2625,6 +2637,7 @@ var commitCommand = defineCommand({
|
|
|
2625
2637
|
return;
|
|
2626
2638
|
}
|
|
2627
2639
|
previousBranchInput = answer.trim();
|
|
2640
|
+
withGuide = Boolean(previousBranchInput);
|
|
2628
2641
|
const branch = previousBranchInput || current;
|
|
2629
2642
|
if (branch !== current) {
|
|
2630
2643
|
await switchBranch(draft.repo, branch);
|
|
@@ -2632,7 +2645,7 @@ var commitCommand = defineCommand({
|
|
|
2632
2645
|
draft.pendingLabel = styleText3("bold", draft.label);
|
|
2633
2646
|
}
|
|
2634
2647
|
}
|
|
2635
|
-
await runTask(`${draft.label}: commit`, `${draft.label}: committed ${draft.message}`, (onOutput) => commit(draft.repo, draft.message, void 0, onOutput));
|
|
2648
|
+
await runTask(`${draft.label}: commit`, `${draft.label}: committed ${draft.message}`, (onOutput) => commit(draft.repo, draft.message, void 0, onOutput), withGuide);
|
|
2636
2649
|
toSend.push(draft);
|
|
2637
2650
|
}
|
|
2638
2651
|
if (toSend.length === 0) return;
|
|
@@ -2640,9 +2653,9 @@ var commitCommand = defineCommand({
|
|
|
2640
2653
|
const destinations = [];
|
|
2641
2654
|
for (const { repo, label } of toSend) {
|
|
2642
2655
|
const branch = await currentBranch(repo);
|
|
2643
|
-
const remote = await
|
|
2656
|
+
const remote = await getPushRemote(repo, branch);
|
|
2644
2657
|
if (remote) destinations.push({ repo, label, branch, remote });
|
|
2645
|
-
else log.warn(`${label}: no
|
|
2658
|
+
else log.warn(`${label}: no unambiguous push remote. Skipping push; commit remains local.`, { spacing: 0 });
|
|
2646
2659
|
}
|
|
2647
2660
|
let shouldPush = Boolean(args.push);
|
|
2648
2661
|
if (!shouldPush && interactive && destinations.length) {
|
|
@@ -2651,7 +2664,7 @@ var commitCommand = defineCommand({
|
|
|
2651
2664
|
initialValue: false
|
|
2652
2665
|
});
|
|
2653
2666
|
if (isCancel(answer)) {
|
|
2654
|
-
|
|
2667
|
+
cancel("Committed. Not pushed.");
|
|
2655
2668
|
return;
|
|
2656
2669
|
}
|
|
2657
2670
|
shouldPush = answer;
|
|
@@ -2663,15 +2676,15 @@ var commitCommand = defineCommand({
|
|
|
2663
2676
|
}
|
|
2664
2677
|
if (interactive) outro("Done.");
|
|
2665
2678
|
} catch (error) {
|
|
2666
|
-
log.error(errorMessage(error));
|
|
2679
|
+
log.error(errorMessage(error), { spacing: 0 });
|
|
2667
2680
|
process.exitCode = 1;
|
|
2668
2681
|
}
|
|
2669
2682
|
}
|
|
2670
2683
|
});
|
|
2671
2684
|
async function reviewMessages(drafts, canPrompt) {
|
|
2672
2685
|
while (true) {
|
|
2673
|
-
for (const { stats, pendingLabel, message } of drafts) {
|
|
2674
|
-
log.message(`(${styleText3("green", `+${stats.additions}`)} ${styleText3("red", `-${stats.deletions}`)}) ${pendingLabel}: ${message}
|
|
2686
|
+
for (const [index, { stats, pendingLabel, message }] of drafts.entries()) {
|
|
2687
|
+
log.message(`(${styleText3("green", `+${stats.additions}`)} ${styleText3("red", `-${stats.deletions}`)}) ${pendingLabel}: ${message}`, { spacing: index === 0 ? 1 : 0 });
|
|
2675
2688
|
}
|
|
2676
2689
|
if (!canPrompt) return drafts;
|
|
2677
2690
|
const action = await select({
|