zapdev 1.16.0 → 1.18.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.
Files changed (3) hide show
  1. package/README.md +4 -4
  2. package/dist/cli.js +100 -273
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -139,13 +139,13 @@ zapdev commit -yp # skip review and push confirmation; choose a branch
139
139
  zapdev commit --pull # pull first, then follow the normal commit flow
140
140
  ```
141
141
 
142
- Before contacting the LLM endpoint, zapdev runs `gitleaks git --staged --verbose` in each changed repository when Gitleaks is installed. A failed scan skips that repository without sending its diff; when Gitleaks is absent, the scan is skipped. The staged diff is sent to the configured endpoint, which may be remote.
142
+ Before contacting the LLM endpoint, zapdev runs `gitleaks git --staged --verbose` in each changed repository when Gitleaks is installed. A failed scan never sends that repository's diff to the LLM and stops the flow before any commit; when Gitleaks is absent, the scan is skipped. The staged diff is sent to the configured endpoint, which may be remote.
143
143
 
144
- Preparation and commit failures are reported per repository while the others continue. A push failure stops all remaining sends. Any failure produces a nonzero exit code.
144
+ Any error stops the flow with a nonzero exit code. Parallel work already in flight finishes before exiting; later steps never start. Earlier successful pulls or commits remain applied.
145
145
 
146
- With `--pull`, only repositories with local changes are pulled, one at a time before any staging, secret scan, or message generation. With `--staged`, only repositories with a staged diff are pulled. Git uses each current branch's configured upstream. Repositories without a configured upstream remote are skipped with a warning, even if they have a single remote. Divergent history, a missing upstream branch, or conflicting local changes stop the entire flow before staging; no rebase, merge commit, or automatic stash is performed. Earlier successful pulls remain applied.
146
+ With `--pull`, only repositories with local changes are pulled, in parallel. With `--staged`, only repositories with a staged diff are pulled. All pulls must finish successfully before preparation and message generation start in parallel. Git uses each current branch's configured upstream. Repositories without a configured upstream remote are skipped with a warning, even if they have a single remote. Divergent history, a missing upstream branch, or conflicting local changes stop the flow before staging, after all in-flight pulls finish; no rebase, merge commit, or automatic stash is performed. Successful pulls remain applied.
147
147
 
148
- In a terminal, commit, pull, and push output is streamed into Clack task logs; silent commands create no output block. Git keeps terminal input, but stdout/stderr are pipes: hooks requiring a TTY on those streams are not supported. Git controls hook stdin; hooks can read from `/dev/tty`, although prompts written there appear outside the blocks. `--yes` skips commit review, not native prompts. Without a terminal, stdout/stderr are streamed directly. Each hook has a 60-second deadline, including time spent answering prompts; override it with `ZD_HOOK_TIMEOUT=120 zapdev commit`.
148
+ Each step uses one spinner: start, wait, stop. Normal Git and hook output is captured without live task logs; failure diagnostics are displayed once. Without a terminal, steps print plain progress messages instead. Git keeps terminal input, but interactive hooks must read and write through `/dev/tty`; prompts on captured stdout/stderr are not displayed. Each hook retains a 60-second deadline; override it with `ZD_HOOK_TIMEOUT=120 zapdev commit`. `--yes` skips commit review, not native prompts.
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
 
package/dist/cli.js CHANGED
@@ -830,7 +830,6 @@ function isUnicodeSupported() {
830
830
  }
831
831
  var unicode = isUnicodeSupported();
832
832
  var isCI = () => process.env.CI === "true";
833
- var isTTY = (o2) => o2.isTTY === true;
834
833
  var unicodeOr = (o2, e2) => unicode ? o2 : e2;
835
834
  var S_STEP_ACTIVE = unicodeOr("\u25C6", "*");
836
835
  var S_STEP_CANCEL = unicodeOr("\u25A0", "x");
@@ -1076,7 +1075,7 @@ var spinner = ({
1076
1075
  const x2 = getColumns(n4), k2 = I3?.styleFrame ?? W, g2 = (e2) => {
1077
1076
  const r3 = e2 > 1 ? O2 ?? settings.messages.error : G ?? settings.messages.cancel;
1078
1077
  S2 = e2 === 1, d2 && (a3(r3, e2), S2 && typeof h3 == "function" && h3());
1079
- }, f2 = () => g2(2), i3 = () => g2(1), A2 = () => {
1078
+ }, f2 = () => g2(2), i3 = () => g2(1), A = () => {
1080
1079
  process.on("uncaughtExceptionMonitor", f2), process.on("unhandledRejection", f2), process.on("SIGINT", i3), process.on("SIGTERM", i3), process.on("exit", g2), m2 && m2.addEventListener("abort", i3);
1081
1080
  }, H = () => {
1082
1081
  process.removeListener("uncaughtExceptionMonitor", f2), process.removeListener("unhandledRejection", f2), process.removeListener("SIGINT", i3), process.removeListener("SIGTERM", i3), process.removeListener("exit", g2), m2 && m2.removeEventListener("abort", i3);
@@ -1097,7 +1096,7 @@ var spinner = ({
1097
1096
  d2 = true, M = block({ output: n4 }), s2 = C2(e2), w2 = performance.now(), N2 && n4.write(`${styleText2("gray", S_BAR)}
1098
1097
  `);
1099
1098
  let r3 = 0, t3 = 0;
1100
- A2(), T2 = setInterval(() => {
1099
+ A(), T2 = setInterval(() => {
1101
1100
  if (u4 && s2 === p2)
1102
1101
  return;
1103
1102
  y2(), p2 = s2;
@@ -1225,123 +1224,6 @@ ${b2}
1225
1224
  }).prompt();
1226
1225
  };
1227
1226
  var i = `${styleText2("gray", S_BAR)} `;
1228
- var A = (l3) => l3.replace(/\x1b\[(?:\d+;)*\d*[ABCDEFGHfJKSTsu]|\x1b\[(s|u)/g, "");
1229
- var taskLog = (l3) => {
1230
- const r3 = l3.output ?? process.stdout, O2 = getColumns(r3), i3 = styleText2("gray", S_BAR), p2 = l3.spacing ?? 1, k2 = 3, m2 = l3.retainLog === true, d2 = !isCI() && isTTY(r3);
1231
- r3.write(`${i3}
1232
- `), r3.write(`${styleText2("green", S_STEP_SUBMIT)} ${l3.title}
1233
- `);
1234
- for (let e2 = 0; e2 < p2; e2++)
1235
- r3.write(`${i3}
1236
- `);
1237
- const n4 = [
1238
- {
1239
- value: "",
1240
- full: ""
1241
- }
1242
- ];
1243
- let v2 = false;
1244
- const f2 = (e2) => {
1245
- if (n4.length === 0)
1246
- return;
1247
- let s2 = 0;
1248
- e2 && (s2 += p2 + 2);
1249
- for (const t3 of n4) {
1250
- const { value: o2, result: a3 } = t3;
1251
- let g2 = a3?.message ?? o2;
1252
- if (g2.length === 0)
1253
- continue;
1254
- a3 === void 0 && t3.header !== void 0 && t3.header !== "" && (g2 += `
1255
- ${t3.header}`);
1256
- const E2 = g2.split(`
1257
- `).reduce((b2, w2) => w2 === "" ? b2 + 1 : b2 + Math.ceil((w2.length + k2) / O2), 0);
1258
- s2 += E2;
1259
- }
1260
- s2 > 0 && (s2 += 1, r3.write(import_sisteransi2.erase.lines(s2)));
1261
- }, h3 = (e2, s2, t3) => {
1262
- const o2 = t3 ? `${e2.full}
1263
- ${e2.value}` : e2.value;
1264
- e2.header !== void 0 && e2.header !== "" && log.message(
1265
- e2.header.split(`
1266
- `).map((a3) => styleText2("bold", a3)),
1267
- {
1268
- output: r3,
1269
- secondarySymbol: i3,
1270
- symbol: i3,
1271
- spacing: 0
1272
- }
1273
- ), log.message(
1274
- o2.split(`
1275
- `).map((a3) => styleText2("dim", a3)),
1276
- {
1277
- output: r3,
1278
- secondarySymbol: i3,
1279
- symbol: i3,
1280
- spacing: s2 ?? p2
1281
- }
1282
- );
1283
- }, T2 = () => {
1284
- for (const e2 of n4) {
1285
- const { header: s2, value: t3, full: o2 } = e2;
1286
- (s2 === void 0 || s2.length === 0) && t3.length === 0 || h3(e2, void 0, m2 === true && o2.length > 0);
1287
- }
1288
- }, L = (e2, s2, t3) => {
1289
- if (f2(false), (t3?.raw !== true || !v2) && e2.value !== "" && (e2.value += `
1290
- `), e2.value += A(s2), v2 = t3?.raw === true, l3.limit !== void 0) {
1291
- const o2 = e2.value.split(`
1292
- `), a3 = o2.length - l3.limit;
1293
- if (a3 > 0) {
1294
- const g2 = o2.splice(0, a3);
1295
- m2 && (e2.full += (e2.full === "" ? "" : `
1296
- `) + g2.join(`
1297
- `));
1298
- }
1299
- e2.value = o2.join(`
1300
- `);
1301
- }
1302
- d2 && y2();
1303
- }, y2 = () => {
1304
- for (const e2 of n4)
1305
- e2.result ? e2.result.status === "error" ? log.error(e2.result.message, { output: r3, secondarySymbol: i3, spacing: 0 }) : log.success(e2.result.message, { output: r3, secondarySymbol: i3, spacing: 0 }) : e2.value !== "" && h3(e2, 0);
1306
- }, B = (e2, s2) => {
1307
- f2(false), e2.result = s2, d2 && y2();
1308
- };
1309
- return {
1310
- message(e2, s2) {
1311
- L(n4[0], e2, s2);
1312
- },
1313
- group(e2) {
1314
- const s2 = {
1315
- header: e2,
1316
- value: "",
1317
- full: ""
1318
- };
1319
- return n4.push(s2), {
1320
- message(t3, o2) {
1321
- L(s2, t3, o2);
1322
- },
1323
- error(t3) {
1324
- B(s2, {
1325
- status: "error",
1326
- message: t3
1327
- });
1328
- },
1329
- success(t3) {
1330
- B(s2, {
1331
- status: "success",
1332
- message: t3
1333
- });
1334
- }
1335
- };
1336
- },
1337
- error(e2, s2) {
1338
- f2(true), log.error(e2, { output: r3, secondarySymbol: i3, spacing: 1 }), s2?.showLog !== false && T2(), n4.splice(1, n4.length - 1), n4[0].value = "", n4[0].full = "";
1339
- },
1340
- success(e2, s2) {
1341
- f2(true), log.success(e2, { output: r3, secondarySymbol: i3, spacing: 1 }), s2?.showLog === true && T2(), n4.splice(1, n4.length - 1), n4[0].value = "", n4[0].full = "";
1342
- }
1343
- };
1344
- };
1345
1227
  var text = (e2) => new n2({
1346
1228
  validate: e2.validate,
1347
1229
  placeholder: e2.placeholder,
@@ -1854,7 +1736,7 @@ function _getBuiltinFlags(long, short, userNames, userAliases) {
1854
1736
  // package.json
1855
1737
  var package_default = {
1856
1738
  name: "zapdev",
1857
- version: "1.16.0",
1739
+ version: "1.18.0",
1858
1740
  description: "Fast, performant and lightweight git chores and dev tools using your terminal and an OpenAI-compatible LLM endpoint.",
1859
1741
  type: "module",
1860
1742
  bin: {
@@ -1914,7 +1796,7 @@ var package_default = {
1914
1796
 
1915
1797
  // src/commands/commit.ts
1916
1798
  import { basename } from "node:path";
1917
- import { styleText as styleText4 } from "node:util";
1799
+ import { styleText as styleText3 } from "node:util";
1918
1800
 
1919
1801
  // src/lib/config.ts
1920
1802
  function resolveHookTimeout(env = process.env) {
@@ -2582,53 +2464,23 @@ var COMMIT_TYPES = [
2582
2464
  ];
2583
2465
 
2584
2466
  // src/commands/git-task.ts
2585
- import { styleText as styleText3 } from "node:util";
2586
- async function runGitTask(label, operation, successMessage, run) {
2587
- const title = `${label}: ${operation}`;
2467
+ async function runTask(title, successMessage, run) {
2588
2468
  const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
2589
2469
  const loader = interactive ? spinner({ withGuide: false }) : void 0;
2590
- const startLoading = () => {
2591
- if (!loader) return;
2592
- const wasRaw = Boolean(process.stdin.isRaw);
2593
- loader.start(title);
2470
+ const wasRaw = Boolean(process.stdin.isRaw);
2471
+ loader?.start(title);
2472
+ if (loader) {
2594
2473
  process.stdin.setRawMode?.(wasRaw);
2595
2474
  process.stdin.pause();
2596
- };
2597
- let task;
2598
- const onOutput = (chunk, stream) => {
2599
- if (!interactive) {
2600
- process[stream].write(chunk);
2601
- return;
2602
- }
2603
- if (!task) loader?.clear();
2604
- task ??= taskLog({ title: `${title}: running\u2026`, limit: 10, retainLog: true });
2605
- task.message(chunk, { raw: true });
2606
- };
2607
- const onHook = (event) => {
2608
- loader?.clear();
2609
- if (event.phase === "start" || event.exitCode !== 0) {
2610
- const hook = `${label}: ${event.name}`;
2611
- const message = event.phase === "start" ? `${hook}: running\u2026` : `${hook}: failed (exit ${event.exitCode})`;
2612
- if (task) task.message(message);
2613
- else if (event.phase === "start") log.step(styleText3("bold", message));
2614
- else log.error(message);
2615
- }
2616
- if (event.phase === "exit" && !task) startLoading();
2617
- };
2618
- if (!interactive) log.info(title);
2619
- startLoading();
2475
+ } else log.info(title);
2620
2476
  try {
2621
- await run(onHook, onOutput);
2622
- loader?.clear();
2623
- if (task) task.success(successMessage, { showLog: true });
2477
+ const result = await run(() => void 0);
2478
+ if (loader) loader.stop(successMessage);
2624
2479
  else log.success(successMessage);
2625
- return true;
2480
+ return result;
2626
2481
  } catch (error) {
2627
2482
  loader?.clear();
2628
- const message = `${label}: ${operation} failed${error instanceof GitOutputError ? "" : `: ${errorMessage(error)}`}`;
2629
- if (task) task.error(message);
2630
- else if (!(error instanceof GitOutputError && error.hookFailureReported)) log.error(message);
2631
- return false;
2483
+ throw new Error(`${title} failed: ${errorMessage(error)}`, { cause: error });
2632
2484
  }
2633
2485
  }
2634
2486
 
@@ -2694,81 +2546,73 @@ var commitCommand = defineCommand({
2694
2546
  return;
2695
2547
  }
2696
2548
  if (interactive) intro("zapdev commit");
2697
- const repos = await findRepos(process.cwd());
2698
- if (repos.length === 0) {
2699
- log.warn("No git repository found here or in direct children.");
2700
- if (interactive) outro("Nothing to do.");
2701
- return;
2702
- }
2703
- if (args.pull) {
2704
- for (const repo of repos) {
2705
- const label = basename(repo);
2706
- try {
2707
- const hasChanges = args.staged ? Boolean((await getStagedDiff(repo)).trim()) : (await getRepoStatus(repo)).hasChanges;
2708
- if (!hasChanges) continue;
2709
- const branch = await currentBranch(repo);
2710
- if (!await getUpstreamRemote(repo, branch)) {
2711
- log.warn(`${label}: no configured upstream remote. Skipping pull.`);
2712
- continue;
2549
+ try {
2550
+ const repos = await findRepos(process.cwd());
2551
+ if (repos.length === 0) {
2552
+ log.warn("No git repository found here or in direct children.");
2553
+ if (interactive) outro("Nothing to do.");
2554
+ return;
2555
+ }
2556
+ if (args.pull) {
2557
+ const pulls = await runTask("Pulling repositories in parallel", "Repositories pulled", async (onOutput) => {
2558
+ const results2 = await Promise.allSettled(repos.map(async (repo) => {
2559
+ const label = basename(repo);
2560
+ const hasChanges = args.staged ? Boolean((await getStagedDiff(repo)).trim()) : (await getRepoStatus(repo)).hasChanges;
2561
+ if (!hasChanges) return null;
2562
+ const branch = await currentBranch(repo);
2563
+ if (!await getUpstreamRemote(repo, branch)) {
2564
+ return `${label}: no configured upstream remote. Skipping pull.`;
2565
+ }
2566
+ await git(["pull", "--ff-only", "--no-rebase", "--no-autostash"], repo, void 0, onOutput);
2567
+ return null;
2568
+ }));
2569
+ for (const [index, result] of results2.entries()) {
2570
+ if (result.status === "rejected") throw new Error(`${basename(repos[index])}: ${errorMessage(result.reason)}`);
2713
2571
  }
2714
- } catch (error) {
2715
- reportGitFailure(`${label}: pull failed`, error);
2716
- process.exitCode = 1;
2717
- return;
2572
+ return results2;
2573
+ });
2574
+ for (const result of pulls) {
2575
+ if (result.status === "fulfilled" && result.value) log.warn(result.value);
2718
2576
  }
2719
- if (!await runGitTask(label, "pull", `${label}: pulled`, (onHook, onOutput) => git(["pull", "--ff-only", "--no-rebase", "--no-autostash"], repo, onHook, onOutput))) {
2720
- process.exitCode = 1;
2721
- return;
2577
+ }
2578
+ const repositories = repos.map((repo) => ({ repo, label: basename(repo), pendingLabel: basename(repo) }));
2579
+ const { results, scan } = await runTask("Preparing repositories and generating commit messages in parallel", "Repositories prepared", async () => {
2580
+ const scan2 = await hasGitleaks();
2581
+ const results2 = await Promise.allSettled(repositories.map(async (repository) => {
2582
+ const { repo } = repository;
2583
+ const { branch, hasChanges } = await getRepoStatus(repo);
2584
+ repository.label = `${basename(repo)} (${branch})`;
2585
+ repository.pendingLabel = hasChanges ? styleText3("bold", repository.label) : repository.label;
2586
+ if (!args.staged) await stageAll(repo);
2587
+ const diff = await getStagedDiff(repo);
2588
+ if (!diff.trim()) return null;
2589
+ const stats = await getStagedDiffStats(repo);
2590
+ if (scan2) await scanStagedChanges(repo);
2591
+ const message = await generateCommitMessage(diff, config, args.type);
2592
+ if (!message) throw new Error("The model returned an empty message.");
2593
+ return { ...repository, message, stats };
2594
+ }));
2595
+ for (const [index, result] of results2.entries()) {
2596
+ if (result.status === "rejected") throw new Error(`${repositories[index].pendingLabel}: ${errorMessage(result.reason)}`);
2597
+ }
2598
+ return { results: results2, scan: scan2 };
2599
+ });
2600
+ if (!scan) log.info("Gitleaks not found, skipping secret scan.");
2601
+ const drafts = [];
2602
+ for (const [index, result] of results.entries()) {
2603
+ if (result.status === "fulfilled") {
2604
+ if (result.value) drafts.push(result.value);
2605
+ else log.info(`${repositories[index].pendingLabel}: nothing to commit.`);
2722
2606
  }
2723
2607
  }
2724
- }
2725
- let scan;
2726
- try {
2727
- scan = await hasGitleaks();
2728
- } catch (error) {
2729
- log.error(`Gitleaks check failed: ${errorMessage(error)}`);
2730
- process.exitCode = 1;
2731
- return;
2732
- }
2733
- if (!scan) log.info("Gitleaks not found, skipping secret scan.");
2734
- const loader = interactive ? spinner() : void 0;
2735
- loader?.start("Preparing repositories and generating commit messages in parallel");
2736
- const repositories = repos.map((repo) => ({ repo, label: basename(repo), pendingLabel: basename(repo) }));
2737
- const results = await Promise.allSettled(repositories.map(async (repository) => {
2738
- const { repo } = repository;
2739
- const { branch, hasChanges } = await getRepoStatus(repo);
2740
- repository.label = `${basename(repo)} (${branch})`;
2741
- repository.pendingLabel = hasChanges ? styleText4("bold", repository.label) : repository.label;
2742
- if (!args.staged) await stageAll(repo);
2743
- const diff = await getStagedDiff(repo);
2744
- if (!diff.trim()) return null;
2745
- const stats = await getStagedDiffStats(repo);
2746
- if (scan) await scanStagedChanges(repo);
2747
- const message = await generateCommitMessage(diff, config, args.type);
2748
- if (!message) throw new Error("The model returned an empty message.");
2749
- return { ...repository, message, stats };
2750
- }));
2751
- loader?.stop("Repositories prepared");
2752
- const drafts = [];
2753
- for (const [index, result] of results.entries()) {
2754
- if (result.status === "rejected") {
2755
- log.error(`${repositories[index].pendingLabel}: ${errorMessage(result.reason)}`);
2756
- process.exitCode = 1;
2757
- } else if (result.value) {
2758
- drafts.push(result.value);
2759
- } else {
2760
- log.info(`${repositories[index].pendingLabel}: nothing to commit.`);
2608
+ const selected = drafts.length ? await reviewMessages(drafts, interactive && !args.yes) : [];
2609
+ if (!selected) {
2610
+ cancel("Cancelled (changes left staged).");
2611
+ return;
2761
2612
  }
2762
- }
2763
- const selected = drafts.length ? await reviewMessages(drafts, interactive && !args.yes) : [];
2764
- if (!selected) {
2765
- cancel("Cancelled (changes left staged).");
2766
- return;
2767
- }
2768
- const toSend = [];
2769
- let previousBranchInput = "";
2770
- for (const draft of selected) {
2771
- try {
2613
+ const toSend = [];
2614
+ let previousBranchInput = "";
2615
+ for (const draft of selected) {
2772
2616
  const current = await currentBranch(draft.repo);
2773
2617
  if (/^(main|master|principal|dev|development)$/.test(current)) {
2774
2618
  if (!interactive) throw new Error("Committing on a protected branch requires a terminal to choose a branch. Changes remain staged.");
@@ -2785,66 +2629,49 @@ var commitCommand = defineCommand({
2785
2629
  if (branch !== current) {
2786
2630
  await switchBranch(draft.repo, branch);
2787
2631
  draft.label = `${basename(draft.repo)} (${branch})`;
2788
- draft.pendingLabel = styleText4("bold", draft.label);
2632
+ draft.pendingLabel = styleText3("bold", draft.label);
2789
2633
  }
2790
2634
  }
2791
- if (!await runGitTask(draft.label, "commit", `${draft.label}: committed ${draft.message}`, (onHook, onOutput) => commit(draft.repo, draft.message, onHook, onOutput))) {
2792
- process.exitCode = 1;
2793
- continue;
2794
- }
2635
+ await runTask(`${draft.label}: commit`, `${draft.label}: committed ${draft.message}`, (onOutput) => commit(draft.repo, draft.message, void 0, onOutput));
2795
2636
  toSend.push(draft);
2796
- } catch (error) {
2797
- reportGitFailure(`${draft.pendingLabel}: commit failed`, error);
2798
- process.exitCode = 1;
2799
2637
  }
2800
- }
2801
- if (toSend.length === 0) return;
2802
- if (!interactive && !args.push) return;
2803
- const destinations = [];
2804
- for (const { repo, label } of toSend) {
2805
- try {
2638
+ if (toSend.length === 0) return;
2639
+ if (!interactive && !args.push) return;
2640
+ const destinations = [];
2641
+ for (const { repo, label } of toSend) {
2806
2642
  const branch = await currentBranch(repo);
2807
2643
  const remote = await getUpstreamRemote(repo, branch);
2808
2644
  if (remote) destinations.push({ repo, label, branch, remote });
2809
2645
  else log.warn(`${label}: no configured upstream remote. Skipping push; commit remains local.`);
2810
- } catch (error) {
2811
- reportGitFailure(`${label}: push failed`, error);
2812
- process.exitCode = 1;
2813
- return;
2814
2646
  }
2815
- }
2816
- let shouldPush = Boolean(args.push);
2817
- if (!shouldPush && interactive && destinations.length) {
2818
- const answer = await confirm({
2819
- message: `Push ${destinations.map(({ label }) => label).join(", ")}?`,
2820
- initialValue: false
2821
- });
2822
- if (isCancel(answer)) {
2823
- outro("Committed. Not pushed.");
2824
- return;
2825
- }
2826
- shouldPush = answer;
2827
- }
2828
- if (shouldPush) {
2829
- for (const { repo, label, branch, remote } of destinations) {
2830
- if (!await runGitTask(label, "push", `${label}: pushed to ${remote}/${branch}`, (onHook, onOutput) => push(repo, remote, branch, onHook, onOutput))) {
2831
- process.exitCode = 1;
2832
- outro("Sending stopped after a Git failure.");
2647
+ let shouldPush = Boolean(args.push);
2648
+ if (!shouldPush && interactive && destinations.length) {
2649
+ const answer = await confirm({
2650
+ message: `Push ${destinations.map(({ label }) => label).join(", ")}?`,
2651
+ initialValue: false
2652
+ });
2653
+ if (isCancel(answer)) {
2654
+ outro("Committed. Not pushed.");
2833
2655
  return;
2834
2656
  }
2657
+ shouldPush = answer;
2658
+ }
2659
+ if (shouldPush) {
2660
+ for (const { repo, label, branch, remote } of destinations) {
2661
+ await runTask(`${label}: push`, `${label}: pushed to ${remote}/${branch}`, (onOutput) => push(repo, remote, branch, void 0, onOutput));
2662
+ }
2835
2663
  }
2664
+ if (interactive) outro("Done.");
2665
+ } catch (error) {
2666
+ log.error(errorMessage(error));
2667
+ process.exitCode = 1;
2836
2668
  }
2837
- if (interactive) outro(process.exitCode ? "Finished with errors." : "Done.");
2838
2669
  }
2839
2670
  });
2840
- function reportGitFailure(message, error) {
2841
- if (error instanceof GitOutputError && error.hookFailureReported) return;
2842
- log.error(error instanceof GitOutputError ? message : `${message}: ${errorMessage(error)}`);
2843
- }
2844
2671
  async function reviewMessages(drafts, canPrompt) {
2845
2672
  while (true) {
2846
2673
  for (const { stats, pendingLabel, message } of drafts) {
2847
- log.message(`(${styleText4("green", `+${stats.additions}`)} ${styleText4("red", `-${stats.deletions}`)}) ${pendingLabel}: ${message}`);
2674
+ log.message(`(${styleText3("green", `+${stats.additions}`)} ${styleText3("red", `-${stats.deletions}`)}) ${pendingLabel}: ${message}`);
2848
2675
  }
2849
2676
  if (!canPrompt) return drafts;
2850
2677
  const action = await select({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zapdev",
3
- "version": "1.16.0",
3
+ "version": "1.18.0",
4
4
  "description": "Fast, performant and lightweight git chores and dev tools using your terminal and an OpenAI-compatible LLM endpoint.",
5
5
  "type": "module",
6
6
  "bin": {