@quikcommit/cli 4.2.0 → 4.3.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 (2) hide show
  1. package/dist/index.js +63 -25
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -46,7 +46,7 @@ var init_constants = __esm({
46
46
  CREDENTIALS_FILE = "credentials";
47
47
  CONFIG_FILE = "config.json";
48
48
  DEFAULT_API_URL = "https://api.quikcommit.dev";
49
- DEVICE_POLL_INTERVAL = 2e3;
49
+ DEVICE_POLL_INTERVAL = 1e3;
50
50
  DEVICE_FLOW_TIMEOUT = 6e5;
51
51
  }
52
52
  });
@@ -295,6 +295,15 @@ function hasStagedChanges() {
295
295
  });
296
296
  return output.trim().length > 0;
297
297
  }
298
+ function getUnstagedFiles() {
299
+ const output = (0, import_child_process.execFileSync)("git", ["status", "--porcelain"], {
300
+ encoding: "utf-8"
301
+ });
302
+ return output.trim().split("\n").filter(Boolean).filter((line) => !line.startsWith("??"));
303
+ }
304
+ function stageAll() {
305
+ (0, import_child_process.execFileSync)("git", ["add", "-u"], { stdio: "pipe" });
306
+ }
298
307
  function gitCommit(message) {
299
308
  const tmpDir = (0, import_fs2.mkdtempSync)((0, import_path2.join)((0, import_os2.tmpdir)(), "qc-"));
300
309
  const tmpFile = (0, import_path2.join)(tmpDir, "commit.txt");
@@ -574,26 +583,39 @@ async function runLogin() {
574
583
  console.log(authUrl);
575
584
  console.log("");
576
585
  }
586
+ let frame = 0;
587
+ const spinner = setInterval(() => {
588
+ const elapsed = Math.floor((Date.now() - startTime) / 1e3);
589
+ process.stderr.write(
590
+ `\r${SPINNER_FRAMES[frame++ % SPINNER_FRAMES.length]} Waiting for authorization... (${elapsed}s)`
591
+ );
592
+ }, 80);
577
593
  const startTime = Date.now();
578
- while (Date.now() - startTime < DEVICE_FLOW_TIMEOUT) {
579
- try {
580
- const res = await fetch(
581
- `${API_URL}/v1/auth/device/poll?code=${encodeURIComponent(code)}`
582
- );
583
- const data = await res.json();
584
- if (data.status === "complete" && data.api_key) {
585
- saveApiKey(data.api_key);
586
- console.log("Successfully logged in!");
587
- return;
594
+ try {
595
+ while (Date.now() - startTime < DEVICE_FLOW_TIMEOUT) {
596
+ try {
597
+ const res = await fetch(
598
+ `${API_URL}/v1/auth/device/poll?code=${encodeURIComponent(code)}`
599
+ );
600
+ const data = await res.json();
601
+ if (data.status === "complete" && data.api_key) {
602
+ saveApiKey(data.api_key);
603
+ process.stderr.write("\r\x1B[2K");
604
+ console.log("Successfully logged in!");
605
+ return;
606
+ }
607
+ } catch {
588
608
  }
589
- } catch {
609
+ await new Promise((r) => setTimeout(r, DEVICE_POLL_INTERVAL));
590
610
  }
591
- await new Promise((r) => setTimeout(r, DEVICE_POLL_INTERVAL));
611
+ process.stderr.write("\r\x1B[2K");
612
+ console.error("Login timed out. Please try again.");
613
+ process.exit(1);
614
+ } finally {
615
+ clearInterval(spinner);
592
616
  }
593
- console.error("Login timed out. Please try again.");
594
- process.exit(1);
595
617
  }
596
- var import_child_process3, import_os3, API_URL, DASHBOARD_URL;
618
+ var import_child_process3, import_os3, API_URL, DASHBOARD_URL, SPINNER_FRAMES;
597
619
  var init_login = __esm({
598
620
  "src/commands/login.ts"() {
599
621
  "use strict";
@@ -603,6 +625,7 @@ var init_login = __esm({
603
625
  init_dist();
604
626
  API_URL = process.env.QC_API_URL ?? DEFAULT_API_URL;
605
627
  DASHBOARD_URL = "https://app.quikcommit.dev";
628
+ SPINNER_FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
606
629
  }
607
630
  });
608
631
 
@@ -1319,7 +1342,7 @@ function config(args) {
1319
1342
  const value = args[2];
1320
1343
  if (!key || !value) {
1321
1344
  console.error("Usage: qc config set <key> <value>");
1322
- console.error(" Keys: model, api_url, provider");
1345
+ console.error(" Keys: model, api_url, provider, auto_stage");
1323
1346
  process.exit(1);
1324
1347
  }
1325
1348
  setConfig(key, value);
@@ -1339,8 +1362,9 @@ function showConfig() {
1339
1362
  console.log("Current configuration:");
1340
1363
  console.log(` model: ${cfg.model ?? "(default for plan)"}`);
1341
1364
  console.log(` api_url: ${cfg.apiUrl ?? DEFAULT_API_URL}`);
1342
- console.log(` provider: ${cfg.provider ?? "(default)"}`);
1343
- console.log(` auth: ${apiKey ? "****" : "not set"}`);
1365
+ console.log(` provider: ${cfg.provider ?? "(default)"}`);
1366
+ console.log(` auto_stage: ${cfg.autoStage ? "true" : "false"}`);
1367
+ console.log(` auth: ${apiKey ? "****" : "not set"}`);
1344
1368
  if (cfg.excludes?.length) {
1345
1369
  console.log(` excludes: ${cfg.excludes.join(", ")}`);
1346
1370
  }
@@ -1365,9 +1389,11 @@ function setConfig(key, value) {
1365
1389
  console.error("Invalid URL:", value);
1366
1390
  process.exit(1);
1367
1391
  }
1392
+ } else if (key === "auto_stage") {
1393
+ updates.autoStage = value === "true" || value === "1";
1368
1394
  } else {
1369
1395
  console.error(`Unknown key: ${key}`);
1370
- console.error(" Keys: model, api_url, provider");
1396
+ console.error(" Keys: model, api_url, provider, auto_stage");
1371
1397
  process.exit(1);
1372
1398
  }
1373
1399
  saveConfig({ ...cfg, ...updates });
@@ -1686,6 +1712,7 @@ Usage:
1686
1712
 
1687
1713
  Options:
1688
1714
  -h, --help Show this help
1715
+ -a, --all Stage all tracked changes before generating
1689
1716
  -m, --message-only Generate message only
1690
1717
  -p, --push Commit and push after generating
1691
1718
  --api-key <key> Use this API key (overrides credentials file)
@@ -1706,6 +1733,7 @@ Commands:
1706
1733
  `;
1707
1734
  function parseArgs(args) {
1708
1735
  let command = "commit";
1736
+ let all = false;
1709
1737
  let messageOnly = false;
1710
1738
  let push = false;
1711
1739
  let apiKey;
@@ -1723,6 +1751,8 @@ function parseArgs(args) {
1723
1751
  const arg = args[i];
1724
1752
  if (arg === "-h" || arg === "--help") {
1725
1753
  command = "help";
1754
+ } else if (arg === "-a" || arg === "--all") {
1755
+ all = true;
1726
1756
  } else if (arg === "-m" || arg === "--message-only") {
1727
1757
  messageOnly = true;
1728
1758
  } else if (arg === "-p" || arg === "--push") {
@@ -1788,17 +1818,26 @@ function parseArgs(args) {
1788
1818
  }
1789
1819
  }
1790
1820
  }
1791
- return { command, messageOnly, push, apiKey, base, create, from, to, write, version, uninstall, hookMode, model, local };
1821
+ return { command, all, messageOnly, push, apiKey, base, create, from, to, write, version, uninstall, hookMode, model, local };
1792
1822
  }
1793
- async function runCommit(messageOnly, push, apiKeyFlag, hookMode = false, modelFlag) {
1823
+ async function runCommit(messageOnly, push, apiKeyFlag, hookMode = false, modelFlag, stageAll_) {
1794
1824
  const log = hookMode ? () => {
1795
1825
  } : (msg) => console.error(msg);
1796
1826
  if (!isGitRepo()) {
1797
1827
  log("Error: Not a git repository.");
1798
1828
  process.exit(1);
1799
1829
  }
1830
+ const config2 = getConfig();
1831
+ if (stageAll_ || config2.autoStage) {
1832
+ stageAll();
1833
+ }
1800
1834
  if (!hasStagedChanges()) {
1801
- log("Error: No staged changes. Stage files with `git add` first.");
1835
+ const unstaged = getUnstagedFiles();
1836
+ if (unstaged.length > 0) {
1837
+ log("Error: No staged changes. Use `qc -a` to stage tracked files, or `git add` manually.");
1838
+ } else {
1839
+ log("Error: No changes to commit.");
1840
+ }
1802
1841
  process.exit(1);
1803
1842
  }
1804
1843
  const apiKey = apiKeyFlag ?? getApiKey();
@@ -1806,7 +1845,6 @@ async function runCommit(messageOnly, push, apiKeyFlag, hookMode = false, modelF
1806
1845
  log("Error: Not authenticated. Run `qc login` first.");
1807
1846
  process.exit(1);
1808
1847
  }
1809
- const config2 = getConfig();
1810
1848
  const model = modelFlag ?? config2.model;
1811
1849
  const excludes = config2.excludes ?? [];
1812
1850
  const diff = getStagedDiff(excludes);
@@ -1933,7 +1971,7 @@ async function main() {
1933
1971
  return;
1934
1972
  }
1935
1973
  }
1936
- await runCommit(messageOnly, push, apiKey, values.hookMode, values.model);
1974
+ await runCommit(messageOnly, push, apiKey, values.hookMode, values.model, values.all);
1937
1975
  }
1938
1976
  main().catch((err) => {
1939
1977
  const args = process.argv.slice(2);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quikcommit/cli",
3
- "version": "4.2.0",
3
+ "version": "4.3.0",
4
4
  "description": "AI-powered conventional commit messages",
5
5
  "bin": {
6
6
  "qc": "./dist/index.js"
@@ -30,7 +30,7 @@
30
30
  "esbuild": "^0.27.3",
31
31
  "typescript": "^5.9.3",
32
32
  "vitest": "^4.0.18",
33
- "@quikcommit/shared": "4.2.0"
33
+ "@quikcommit/shared": "4.3.0"
34
34
  },
35
35
  "scripts": {
36
36
  "build": "node build.mjs",