@staff0rd/assist 0.147.3 → 0.148.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 CHANGED
@@ -152,6 +152,7 @@ After installation, the `assist` command will be available globally. You can als
152
152
  - `assist seq query <filter> --json` - Output raw JSON
153
153
  - `assist seq query <filter> -n <count>` - Fetch a specific number of events (default 50)
154
154
  - `assist screenshot <process>` - Capture a screenshot of a running application window (e.g. `assist screenshot notepad`). Output directory is configurable via `screenshot.outputDir` (default `./screenshots`)
155
+ - `assist coverage` - Print global statement coverage percentage
155
156
  - `assist complexity <pattern>` - Analyze a file (all metrics if single match, maintainability if multiple)
156
157
  - `assist complexity cyclomatic [pattern]` - Calculate cyclomatic complexity per function
157
158
  - `assist complexity halstead [pattern]` - Calculate Halstead metrics per function
@@ -7,7 +7,9 @@ You are increasing test coverage for this project. Your goal is to pick the high
7
7
 
8
8
  ## Step 1: Measure current coverage
9
9
 
10
- Run coverage against all source files to identify what is untested:
10
+ Run `assist coverage` to get the current global statement coverage percentage.
11
+
12
+ Then run coverage with JSON output to identify what is untested:
11
13
 
12
14
  ```
13
15
  npx vitest run --coverage --coverage.include='src/**/*.ts' --coverage.all --coverage.reporter=json 2>&1
@@ -116,4 +118,4 @@ File | Before | After
116
118
  <file path> | 0% | 95%
117
119
  ```
118
120
 
119
- And the new repo-wide coverage number.
121
+ And the new repo-wide coverage number (run `assist coverage`).
@@ -49,6 +49,7 @@
49
49
  "Bash(assist ravendb auth list:*)",
50
50
  "Bash(assist seq query:*)",
51
51
  "Bash(assist seq auth list:*)",
52
+ "Bash(assist coverage:*)",
52
53
  "Bash(assist screenshot:*)",
53
54
  "Bash(assist roam show-claude-code-icon:*)",
54
55
  "SlashCommand(/verify)",
package/dist/index.js CHANGED
@@ -6,7 +6,7 @@ import { Command } from "commander";
6
6
  // package.json
7
7
  var package_default = {
8
8
  name: "@staff0rd/assist",
9
- version: "0.147.3",
9
+ version: "0.148.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -483,6 +483,21 @@ function configList() {
483
483
  console.log(stringifyYaml2(config, { lineWidth: 0 }).trimEnd());
484
484
  }
485
485
 
486
+ // src/commands/coverage.ts
487
+ import { execSync as execSync2 } from "child_process";
488
+ function coverage() {
489
+ const output = execSync2(
490
+ "npx vitest run --coverage --coverage.include='src/**/*.ts' --coverage.all --coverage.reporter=text 2>&1",
491
+ { encoding: "utf-8", timeout: 12e4 }
492
+ );
493
+ const match = output.match(/All files\s*\|\s*([\d.]+)/);
494
+ if (!match) {
495
+ console.error("Could not determine coverage from vitest output.");
496
+ process.exit(1);
497
+ }
498
+ console.log(`${match[1]}%`);
499
+ }
500
+
486
501
  // src/commands/verify/init/index.ts
487
502
  import chalk17 from "chalk";
488
503
 
@@ -555,7 +570,7 @@ function findPackageJsonWithVerifyScripts(startDir) {
555
570
  }
556
571
 
557
572
  // src/commands/verify/installPackage.ts
558
- import { execSync as execSync2 } from "child_process";
573
+ import { execSync as execSync3 } from "child_process";
559
574
  import { writeFileSync as writeFileSync2 } from "fs";
560
575
  import chalk5 from "chalk";
561
576
  function writePackageJson(filePath, pkg) {
@@ -574,7 +589,7 @@ function addScript(pkg, name, command) {
574
589
  function installPackage(name, cwd) {
575
590
  console.log(chalk5.dim(`Installing ${name}...`));
576
591
  try {
577
- execSync2(`npm install -D ${name}`, { stdio: "inherit", cwd });
592
+ execSync3(`npm install -D ${name}`, { stdio: "inherit", cwd });
578
593
  return true;
579
594
  } catch {
580
595
  console.error(chalk5.red(`Failed to install ${name}`));
@@ -720,7 +735,7 @@ import * as path5 from "path";
720
735
  import chalk13 from "chalk";
721
736
 
722
737
  // src/commands/lint/init.ts
723
- import { execSync as execSync4 } from "child_process";
738
+ import { execSync as execSync5 } from "child_process";
724
739
  import { existsSync as existsSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
725
740
  import { dirname as dirname6, join as join4 } from "path";
726
741
  import { fileURLToPath } from "url";
@@ -744,7 +759,7 @@ async function promptConfirm(message, initial = true) {
744
759
  }
745
760
 
746
761
  // src/shared/removeEslint/index.ts
747
- import { execSync as execSync3 } from "child_process";
762
+ import { execSync as execSync4 } from "child_process";
748
763
  import { existsSync as existsSync6, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
749
764
 
750
765
  // src/shared/removeEslint/removeEslintConfigFiles.ts
@@ -779,7 +794,7 @@ function removeEslint(options2 = {}) {
779
794
  const removedConfigFiles = removeEslintConfigFiles();
780
795
  if (removedFromPackageJson || removedConfigFiles) {
781
796
  console.log("Running npm install...");
782
- execSync3("npm install", { stdio: "inherit" });
797
+ execSync4("npm install", { stdio: "inherit" });
783
798
  return true;
784
799
  }
785
800
  return false;
@@ -861,7 +876,7 @@ async function init() {
861
876
  const biomeConfigPath = "biome.json";
862
877
  if (!existsSync7(biomeConfigPath)) {
863
878
  console.log("Initializing Biome...");
864
- execSync4("npx @biomejs/biome init", { stdio: "inherit" });
879
+ execSync5("npx @biomejs/biome init", { stdio: "inherit" });
865
880
  }
866
881
  if (!existsSync7(biomeConfigPath)) {
867
882
  console.log("No biome.json found, skipping linter config");
@@ -1615,17 +1630,17 @@ function lint(options2 = {}) {
1615
1630
  }
1616
1631
 
1617
1632
  // src/commands/new/registerNew/newCli/index.ts
1618
- import { execSync as execSync10 } from "child_process";
1633
+ import { execSync as execSync11 } from "child_process";
1619
1634
  import { basename as basename2, resolve } from "path";
1620
1635
 
1621
1636
  // src/commands/verify/hardcodedColors.ts
1622
- import { execSync as execSync5 } from "child_process";
1637
+ import { execSync as execSync6 } from "child_process";
1623
1638
  import { minimatch } from "minimatch";
1624
1639
  var pattern = "0x[0-9a-fA-F]{6}|#[0-9a-fA-F]{3,6}";
1625
1640
  function hardcodedColors() {
1626
1641
  const ignoreGlobs = loadConfig().hardcodedColors?.ignore ?? [];
1627
1642
  try {
1628
- const output = execSync5(`grep -rEnH '${pattern}' src/`, {
1643
+ const output = execSync6(`grep -rEnH '${pattern}' src/`, {
1629
1644
  encoding: "utf-8"
1630
1645
  });
1631
1646
  const lines = output.trim().split("\n").filter((line) => {
@@ -1704,10 +1719,10 @@ function list() {
1704
1719
  }
1705
1720
 
1706
1721
  // src/commands/verify/noVenv.ts
1707
- import { execSync as execSync6 } from "child_process";
1722
+ import { execSync as execSync7 } from "child_process";
1708
1723
  function noVenv() {
1709
1724
  try {
1710
- const output = execSync6(
1725
+ const output = execSync7(
1711
1726
  "find . -type d -name venv -not -path '*/node_modules/*'",
1712
1727
  {
1713
1728
  encoding: "utf-8"
@@ -1739,9 +1754,9 @@ Total: ${folders.length} venv folder(s)`);
1739
1754
  import { minimatch as minimatch2 } from "minimatch";
1740
1755
 
1741
1756
  // src/commands/verify/run/getChangedFiles.ts
1742
- import { execSync as execSync7 } from "child_process";
1757
+ import { execSync as execSync8 } from "child_process";
1743
1758
  function getChangedFiles() {
1744
- const output = execSync7("git diff --name-only HEAD", {
1759
+ const output = execSync8("git diff --name-only HEAD", {
1745
1760
  encoding: "utf-8"
1746
1761
  }).trim();
1747
1762
  if (output === "") return [];
@@ -1903,25 +1918,25 @@ async function run(options2 = {}) {
1903
1918
  }
1904
1919
 
1905
1920
  // src/commands/new/registerNew/initGit.ts
1906
- import { execSync as execSync8 } from "child_process";
1921
+ import { execSync as execSync9 } from "child_process";
1907
1922
  import { writeFileSync as writeFileSync7 } from "fs";
1908
1923
  function initGit() {
1909
1924
  console.log("Initializing git repository...");
1910
- execSync8("git init", { stdio: "inherit" });
1925
+ execSync9("git init", { stdio: "inherit" });
1911
1926
  writeFileSync7(".gitignore", "dist\nnode_modules\n");
1912
1927
  }
1913
1928
 
1914
1929
  // src/commands/new/registerNew/newCli/initPackageJson.ts
1915
- import { execSync as execSync9 } from "child_process";
1930
+ import { execSync as execSync10 } from "child_process";
1916
1931
  function initPackageJson(name) {
1917
1932
  console.log("Initializing package.json...");
1918
- execSync9("npm init -y", { stdio: "inherit" });
1933
+ execSync10("npm init -y", { stdio: "inherit" });
1919
1934
  console.log("Configuring package.json...");
1920
- execSync9("npm pkg delete main", { stdio: "inherit" });
1921
- execSync9("npm pkg set type=module", { stdio: "inherit" });
1922
- execSync9(`npm pkg set bin.${name}=./dist/index.js`, { stdio: "inherit" });
1923
- execSync9("npm pkg set scripts.build=tsup", { stdio: "inherit" });
1924
- execSync9('npm pkg set scripts.start="node dist/index.js"', {
1935
+ execSync10("npm pkg delete main", { stdio: "inherit" });
1936
+ execSync10("npm pkg set type=module", { stdio: "inherit" });
1937
+ execSync10(`npm pkg set bin.${name}=./dist/index.js`, { stdio: "inherit" });
1938
+ execSync10("npm pkg set scripts.build=tsup", { stdio: "inherit" });
1939
+ execSync10('npm pkg set scripts.start="node dist/index.js"', {
1925
1940
  stdio: "inherit"
1926
1941
  });
1927
1942
  }
@@ -1986,8 +2001,8 @@ async function newCli() {
1986
2001
  initGit();
1987
2002
  initPackageJson(name);
1988
2003
  console.log("Installing dependencies...");
1989
- execSync10("npm install commander", { stdio: "inherit" });
1990
- execSync10("npm install -D tsup typescript @types/node", {
2004
+ execSync11("npm install commander", { stdio: "inherit" });
2005
+ execSync11("npm install -D tsup typescript @types/node", {
1991
2006
  stdio: "inherit"
1992
2007
  });
1993
2008
  writeCliTemplate(name);
@@ -1996,11 +2011,11 @@ async function newCli() {
1996
2011
  }
1997
2012
 
1998
2013
  // src/commands/new/registerNew/newProject.ts
1999
- import { execSync as execSync12 } from "child_process";
2014
+ import { execSync as execSync13 } from "child_process";
2000
2015
  import { existsSync as existsSync11, readFileSync as readFileSync9, writeFileSync as writeFileSync10 } from "fs";
2001
2016
 
2002
2017
  // src/commands/deploy/init/index.ts
2003
- import { execSync as execSync11 } from "child_process";
2018
+ import { execSync as execSync12 } from "child_process";
2004
2019
  import chalk24 from "chalk";
2005
2020
  import enquirer3 from "enquirer";
2006
2021
 
@@ -2053,7 +2068,7 @@ Created ${WORKFLOW_PATH}`));
2053
2068
  // src/commands/deploy/init/index.ts
2054
2069
  async function ensureNetlifyCli() {
2055
2070
  try {
2056
- execSync11("netlify sites:create --disable-linking", { stdio: "inherit" });
2071
+ execSync12("netlify sites:create --disable-linking", { stdio: "inherit" });
2057
2072
  } catch (error) {
2058
2073
  if (!(error instanceof Error) || !error.message.includes("command not found"))
2059
2074
  throw error;
@@ -2068,9 +2083,9 @@ async function ensureNetlifyCli() {
2068
2083
  process.exit(1);
2069
2084
  }
2070
2085
  console.log(chalk24.dim("\nInstalling netlify-cli...\n"));
2071
- execSync11("npm install -g netlify-cli", { stdio: "inherit" });
2086
+ execSync12("npm install -g netlify-cli", { stdio: "inherit" });
2072
2087
  console.log();
2073
- execSync11("netlify sites:create --disable-linking", { stdio: "inherit" });
2088
+ execSync12("netlify sites:create --disable-linking", { stdio: "inherit" });
2074
2089
  }
2075
2090
  }
2076
2091
  function printSetupInstructions() {
@@ -2113,7 +2128,7 @@ async function init5() {
2113
2128
  // src/commands/new/registerNew/newProject.ts
2114
2129
  async function newProject() {
2115
2130
  console.log("Initializing Vite with react-ts template...");
2116
- execSync12("npm create vite@latest . -- --template react-ts", {
2131
+ execSync13("npm create vite@latest . -- --template react-ts", {
2117
2132
  stdio: "inherit"
2118
2133
  });
2119
2134
  initGit();
@@ -2893,6 +2908,12 @@ async function next() {
2893
2908
  await spawnClaude("/draft");
2894
2909
  return;
2895
2910
  }
2911
+ if (todo.length === 1) {
2912
+ const only = todo[0];
2913
+ console.log(chalk36.bold(`Starting #${only.id}: ${only.name}`));
2914
+ await run2(String(only.id));
2915
+ return;
2916
+ }
2896
2917
  const choices = todo.map((i) => ({
2897
2918
  name: `${typeLabel(i.type)} #${i.id}: ${i.name}`,
2898
2919
  value: String(i.id)
@@ -3471,7 +3492,7 @@ import { homedir as homedir4 } from "os";
3471
3492
  import { join as join13 } from "path";
3472
3493
 
3473
3494
  // src/shared/getInstallDir.ts
3474
- import { execSync as execSync13 } from "child_process";
3495
+ import { execSync as execSync14 } from "child_process";
3475
3496
  import { dirname as dirname15, resolve as resolve4 } from "path";
3476
3497
  import { fileURLToPath as fileURLToPath5 } from "url";
3477
3498
  var __filename3 = fileURLToPath5(import.meta.url);
@@ -3481,7 +3502,7 @@ function getInstallDir() {
3481
3502
  }
3482
3503
  function isGitRepo(dir) {
3483
3504
  try {
3484
- const result = execSync13("git rev-parse --show-toplevel", {
3505
+ const result = execSync14("git rev-parse --show-toplevel", {
3485
3506
  cwd: dir,
3486
3507
  stdio: "pipe"
3487
3508
  }).toString().trim();
@@ -3492,7 +3513,7 @@ function isGitRepo(dir) {
3492
3513
  }
3493
3514
 
3494
3515
  // src/commands/permitCliReads/assertCliExists.ts
3495
- import { execSync as execSync14 } from "child_process";
3516
+ import { execSync as execSync15 } from "child_process";
3496
3517
  function assertCliExists(cli) {
3497
3518
  const binary = cli.split(/\s+/)[0];
3498
3519
  const opts = {
@@ -3500,10 +3521,10 @@ function assertCliExists(cli) {
3500
3521
  stdio: ["ignore", "pipe", "pipe"]
3501
3522
  };
3502
3523
  try {
3503
- execSync14(`command -v ${binary}`, opts);
3524
+ execSync15(`command -v ${binary}`, opts);
3504
3525
  } catch {
3505
3526
  try {
3506
- execSync14(`where ${binary}`, opts);
3527
+ execSync15(`where ${binary}`, opts);
3507
3528
  } catch {
3508
3529
  console.error(`CLI "${cli}" not found in PATH`);
3509
3530
  process.exit(1);
@@ -4359,7 +4380,7 @@ function registerDeploy(program2) {
4359
4380
  }
4360
4381
 
4361
4382
  // src/commands/devlog/list/index.ts
4362
- import { execSync as execSync16 } from "child_process";
4383
+ import { execSync as execSync17 } from "child_process";
4363
4384
  import { basename as basename3 } from "path";
4364
4385
 
4365
4386
  // src/commands/devlog/loadBlogSkipDays.ts
@@ -4374,7 +4395,7 @@ function loadBlogSkipDays(repoName) {
4374
4395
  }
4375
4396
 
4376
4397
  // src/commands/devlog/shared.ts
4377
- import { execSync as execSync15 } from "child_process";
4398
+ import { execSync as execSync16 } from "child_process";
4378
4399
  import chalk48 from "chalk";
4379
4400
 
4380
4401
  // src/commands/devlog/loadDevlogEntries.ts
@@ -4444,7 +4465,7 @@ function loadAllDevlogLatestDates() {
4444
4465
  // src/commands/devlog/shared.ts
4445
4466
  function getCommitFiles(hash) {
4446
4467
  try {
4447
- const output = execSync15(`git show --name-only --format="" ${hash}`, {
4468
+ const output = execSync16(`git show --name-only --format="" ${hash}`, {
4448
4469
  encoding: "utf-8"
4449
4470
  });
4450
4471
  return output.trim().split("\n").filter(Boolean);
@@ -4515,7 +4536,7 @@ function list3(options2) {
4515
4536
  const devlogEntries = loadDevlogEntries(repoName);
4516
4537
  const reverseFlag = options2.reverse ? "--reverse " : "";
4517
4538
  const limitFlag = options2.reverse ? "" : "-n 500 ";
4518
- const output = execSync16(
4539
+ const output = execSync17(
4519
4540
  `git log ${reverseFlag}${limitFlag}--pretty=format:'%ad|%h|%s' --date=short`,
4520
4541
  { encoding: "utf-8" }
4521
4542
  );
@@ -4541,11 +4562,11 @@ function list3(options2) {
4541
4562
  }
4542
4563
 
4543
4564
  // src/commands/devlog/getLastVersionInfo.ts
4544
- import { execSync as execSync17 } from "child_process";
4565
+ import { execSync as execSync18 } from "child_process";
4545
4566
  import semver from "semver";
4546
4567
  function getVersionAtCommit(hash) {
4547
4568
  try {
4548
- const content = execSync17(`git show ${hash}:package.json`, {
4569
+ const content = execSync18(`git show ${hash}:package.json`, {
4549
4570
  encoding: "utf-8"
4550
4571
  });
4551
4572
  const pkg = JSON.parse(content);
@@ -4560,7 +4581,7 @@ function stripToMinor(version2) {
4560
4581
  }
4561
4582
  function getLastVersionInfoFromGit() {
4562
4583
  try {
4563
- const output = execSync17(
4584
+ const output = execSync18(
4564
4585
  "git log -1 --pretty=format:'%ad|%h' --date=short",
4565
4586
  {
4566
4587
  encoding: "utf-8"
@@ -4603,7 +4624,7 @@ function bumpVersion(version2, type) {
4603
4624
  }
4604
4625
 
4605
4626
  // src/commands/devlog/next/displayNextEntry/index.ts
4606
- import { execSync as execSync18 } from "child_process";
4627
+ import { execSync as execSync19 } from "child_process";
4607
4628
  import chalk51 from "chalk";
4608
4629
 
4609
4630
  // src/commands/devlog/next/displayNextEntry/displayVersion.ts
@@ -4637,7 +4658,7 @@ function findTargetDate(commitsByDate, skipDays) {
4637
4658
  return Array.from(commitsByDate.keys()).filter((d) => !skipDays.has(d)).sort()[0];
4638
4659
  }
4639
4660
  function fetchCommitsByDate(ignore2, lastDate) {
4640
- const output = execSync18(
4661
+ const output = execSync19(
4641
4662
  "git log --pretty=format:'%ad|%h|%s' --date=short -n 500",
4642
4663
  { encoding: "utf-8" }
4643
4664
  );
@@ -4715,7 +4736,7 @@ function next2(options2) {
4715
4736
  }
4716
4737
 
4717
4738
  // src/commands/devlog/repos/index.ts
4718
- import { execSync as execSync19 } from "child_process";
4739
+ import { execSync as execSync20 } from "child_process";
4719
4740
 
4720
4741
  // src/commands/devlog/repos/printReposTable.ts
4721
4742
  import chalk52 from "chalk";
@@ -4750,7 +4771,7 @@ function getStatus(lastPush, lastDevlog) {
4750
4771
  return lastDevlog < lastPush ? "outdated" : "ok";
4751
4772
  }
4752
4773
  function fetchRepos(days, all) {
4753
- const json = execSync19(
4774
+ const json = execSync20(
4754
4775
  "gh repo list staff0rd --json name,pushedAt,isArchived --limit 200",
4755
4776
  { encoding: "utf-8" }
4756
4777
  );
@@ -5110,7 +5131,7 @@ async function deps(csprojPath, options2) {
5110
5131
  }
5111
5132
 
5112
5133
  // src/commands/dotnet/getChangedCsFiles.ts
5113
- import { execSync as execSync20 } from "child_process";
5134
+ import { execSync as execSync21 } from "child_process";
5114
5135
  var SCOPE_ALL = "all";
5115
5136
  var SCOPE_BASE = "base:";
5116
5137
  var SCOPE_COMMIT = "commit:";
@@ -5134,7 +5155,7 @@ function getChangedCsFiles(scope) {
5134
5155
  } else {
5135
5156
  cmd = "git diff --name-only HEAD";
5136
5157
  }
5137
- const output = execSync20(cmd, { encoding: "utf-8" }).trim();
5158
+ const output = execSync21(cmd, { encoding: "utf-8" }).trim();
5138
5159
  if (output === "") return [];
5139
5160
  return output.split("\n").filter((f) => f.toLowerCase().endsWith(".cs"));
5140
5161
  }
@@ -5332,14 +5353,14 @@ function parseInspectReport(json) {
5332
5353
  }
5333
5354
 
5334
5355
  // src/commands/dotnet/runInspectCode.ts
5335
- import { execSync as execSync21 } from "child_process";
5356
+ import { execSync as execSync22 } from "child_process";
5336
5357
  import { existsSync as existsSync25, readFileSync as readFileSync20, unlinkSync as unlinkSync4 } from "fs";
5337
5358
  import { tmpdir as tmpdir2 } from "os";
5338
5359
  import path26 from "path";
5339
5360
  import chalk62 from "chalk";
5340
5361
  function assertJbInstalled() {
5341
5362
  try {
5342
- execSync21("jb inspectcode --version", { stdio: "pipe" });
5363
+ execSync22("jb inspectcode --version", { stdio: "pipe" });
5343
5364
  } catch {
5344
5365
  console.error(chalk62.red("jb is not installed. Install with:"));
5345
5366
  console.error(
@@ -5353,7 +5374,7 @@ function runInspectCode(slnPath, include, swea) {
5353
5374
  const includeFlag = include ? ` --include="${include}"` : "";
5354
5375
  const sweaFlag = swea ? " --swea" : "";
5355
5376
  try {
5356
- execSync21(
5377
+ execSync22(
5357
5378
  `jb inspectcode "${slnPath}" -o="${reportPath}"${includeFlag}${sweaFlag} --verbosity=OFF`,
5358
5379
  { stdio: "pipe" }
5359
5380
  );
@@ -5374,7 +5395,7 @@ function runInspectCode(slnPath, include, swea) {
5374
5395
  }
5375
5396
 
5376
5397
  // src/commands/dotnet/runRoslynInspect.ts
5377
- import { execSync as execSync22 } from "child_process";
5398
+ import { execSync as execSync23 } from "child_process";
5378
5399
  import chalk63 from "chalk";
5379
5400
  function resolveMsbuildPath() {
5380
5401
  const config = loadConfig();
@@ -5384,7 +5405,7 @@ function resolveMsbuildPath() {
5384
5405
  function assertMsbuildInstalled() {
5385
5406
  const msbuild = resolveMsbuildPath();
5386
5407
  try {
5387
- execSync22(`"${msbuild}" -version`, { stdio: "pipe" });
5408
+ execSync23(`"${msbuild}" -version`, { stdio: "pipe" });
5388
5409
  } catch {
5389
5410
  console.error(chalk63.red(`msbuild not found at: ${msbuild}`));
5390
5411
  console.error(
@@ -5410,7 +5431,7 @@ function runRoslynInspect(slnPath) {
5410
5431
  const msbuild = resolveMsbuildPath();
5411
5432
  let output;
5412
5433
  try {
5413
- output = execSync22(
5434
+ output = execSync23(
5414
5435
  `"${msbuild}" "${slnPath}" -t:Build -v:minimal -maxcpucount -p:EnforceCodeStyleInBuild=true -p:RunAnalyzersDuringBuild=true 2>&1`,
5415
5436
  { encoding: "utf-8", stdio: "pipe", maxBuffer: 50 * 1024 * 1024 }
5416
5437
  );
@@ -5542,12 +5563,12 @@ function adfToText(doc) {
5542
5563
  }
5543
5564
 
5544
5565
  // src/commands/jira/fetchIssue.ts
5545
- import { execSync as execSync23 } from "child_process";
5566
+ import { execSync as execSync24 } from "child_process";
5546
5567
  import chalk65 from "chalk";
5547
5568
  function fetchIssue(issueKey, fields) {
5548
5569
  let result;
5549
5570
  try {
5550
- result = execSync23(
5571
+ result = execSync24(
5551
5572
  `acli jira workitem view ${issueKey} -f ${fields} --json`,
5552
5573
  { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
5553
5574
  );
@@ -5593,7 +5614,7 @@ function acceptanceCriteria(issueKey) {
5593
5614
  }
5594
5615
 
5595
5616
  // src/commands/jira/jiraAuth.ts
5596
- import { execSync as execSync24 } from "child_process";
5617
+ import { execSync as execSync25 } from "child_process";
5597
5618
 
5598
5619
  // src/shared/loadJson.ts
5599
5620
  import { existsSync as existsSync26, mkdirSync as mkdirSync5, readFileSync as readFileSync21, writeFileSync as writeFileSync18 } from "fs";
@@ -5657,7 +5678,7 @@ async function jiraAuth() {
5657
5678
  console.error("All fields are required.");
5658
5679
  process.exit(1);
5659
5680
  }
5660
- execSync24(`acli jira auth login --site ${site} --email "${email}" --token`, {
5681
+ execSync25(`acli jira auth login --site ${site} --email "${email}" --token`, {
5661
5682
  encoding: "utf-8",
5662
5683
  input: token,
5663
5684
  stdio: ["pipe", "inherit", "inherit"]
@@ -5938,7 +5959,7 @@ import { tmpdir as tmpdir3 } from "os";
5938
5959
  import { join as join20 } from "path";
5939
5960
 
5940
5961
  // src/commands/prs/shared.ts
5941
- import { execSync as execSync25 } from "child_process";
5962
+ import { execSync as execSync26 } from "child_process";
5942
5963
  function isGhNotInstalled(error) {
5943
5964
  if (error instanceof Error) {
5944
5965
  const msg = error.message.toLowerCase();
@@ -5954,14 +5975,14 @@ function isNotFound(error) {
5954
5975
  }
5955
5976
  function getRepoInfo() {
5956
5977
  const repoInfo = JSON.parse(
5957
- execSync25("gh repo view --json owner,name", { encoding: "utf-8" })
5978
+ execSync26("gh repo view --json owner,name", { encoding: "utf-8" })
5958
5979
  );
5959
5980
  return { org: repoInfo.owner.login, repo: repoInfo.name };
5960
5981
  }
5961
5982
  function getCurrentPrNumber() {
5962
5983
  try {
5963
5984
  const prInfo = JSON.parse(
5964
- execSync25("gh pr view --json number", { encoding: "utf-8" })
5985
+ execSync26("gh pr view --json number", { encoding: "utf-8" })
5965
5986
  );
5966
5987
  return prInfo.number;
5967
5988
  } catch (error) {
@@ -5975,7 +5996,7 @@ function getCurrentPrNumber() {
5975
5996
  function getCurrentPrNodeId() {
5976
5997
  try {
5977
5998
  const prInfo = JSON.parse(
5978
- execSync25("gh pr view --json id", { encoding: "utf-8" })
5999
+ execSync26("gh pr view --json id", { encoding: "utf-8" })
5979
6000
  );
5980
6001
  return prInfo.id;
5981
6002
  } catch (error) {
@@ -6046,10 +6067,10 @@ function comment(path49, line, body) {
6046
6067
  }
6047
6068
 
6048
6069
  // src/commands/prs/fixed.ts
6049
- import { execSync as execSync27 } from "child_process";
6070
+ import { execSync as execSync28 } from "child_process";
6050
6071
 
6051
6072
  // src/commands/prs/resolveCommentWithReply.ts
6052
- import { execSync as execSync26 } from "child_process";
6073
+ import { execSync as execSync27 } from "child_process";
6053
6074
  import { unlinkSync as unlinkSync7, writeFileSync as writeFileSync20 } from "fs";
6054
6075
  import { tmpdir as tmpdir4 } from "os";
6055
6076
  import { join as join22 } from "path";
@@ -6079,7 +6100,7 @@ function deleteCommentsCache(prNumber) {
6079
6100
 
6080
6101
  // src/commands/prs/resolveCommentWithReply.ts
6081
6102
  function replyToComment(org, repo, prNumber, commentId, message) {
6082
- execSync26(
6103
+ execSync27(
6083
6104
  `gh api repos/${org}/${repo}/pulls/${prNumber}/comments -f body="${message.replace(/"/g, '\\"')}" -F in_reply_to=${commentId}`,
6084
6105
  { stdio: ["inherit", "pipe", "inherit"] }
6085
6106
  );
@@ -6089,7 +6110,7 @@ function resolveThread(threadId) {
6089
6110
  const queryFile = join22(tmpdir4(), `gh-mutation-${Date.now()}.graphql`);
6090
6111
  writeFileSync20(queryFile, mutation);
6091
6112
  try {
6092
- execSync26(
6113
+ execSync27(
6093
6114
  `gh api graphql -F query=@${queryFile} -f threadId="${threadId}"`,
6094
6115
  { stdio: ["inherit", "pipe", "inherit"] }
6095
6116
  );
@@ -6141,7 +6162,7 @@ function resolveCommentWithReply(commentId, message) {
6141
6162
  // src/commands/prs/fixed.ts
6142
6163
  function verifySha(sha) {
6143
6164
  try {
6144
- return execSync27(`git rev-parse --verify ${sha}`, {
6165
+ return execSync28(`git rev-parse --verify ${sha}`, {
6145
6166
  encoding: "utf-8"
6146
6167
  }).trim();
6147
6168
  } catch {
@@ -6155,7 +6176,7 @@ function fixed(commentId, sha) {
6155
6176
  const { org, repo } = getRepoInfo();
6156
6177
  const repoUrl = `https://github.com/${org}/${repo}`;
6157
6178
  const message = `Fixed in [${fullSha}](${repoUrl}/commit/${fullSha})`;
6158
- execSync27("git push", { stdio: "inherit" });
6179
+ execSync28("git push", { stdio: "inherit" });
6159
6180
  resolveCommentWithReply(commentId, message);
6160
6181
  } catch (error) {
6161
6182
  if (isGhNotInstalled(error)) {
@@ -6173,7 +6194,7 @@ import { join as join24 } from "path";
6173
6194
  import { stringify } from "yaml";
6174
6195
 
6175
6196
  // src/commands/prs/fetchThreadIds.ts
6176
- import { execSync as execSync28 } from "child_process";
6197
+ import { execSync as execSync29 } from "child_process";
6177
6198
  import { unlinkSync as unlinkSync8, writeFileSync as writeFileSync21 } from "fs";
6178
6199
  import { tmpdir as tmpdir5 } from "os";
6179
6200
  import { join as join23 } from "path";
@@ -6182,7 +6203,7 @@ function fetchThreadIds(org, repo, prNumber) {
6182
6203
  const queryFile = join23(tmpdir5(), `gh-query-${Date.now()}.graphql`);
6183
6204
  writeFileSync21(queryFile, THREAD_QUERY);
6184
6205
  try {
6185
- const result = execSync28(
6206
+ const result = execSync29(
6186
6207
  `gh api graphql -F query=@${queryFile} -F owner="${org}" -F repo="${repo}" -F prNumber=${prNumber}`,
6187
6208
  { encoding: "utf-8" }
6188
6209
  );
@@ -6204,9 +6225,9 @@ function fetchThreadIds(org, repo, prNumber) {
6204
6225
  }
6205
6226
 
6206
6227
  // src/commands/prs/listComments/fetchReviewComments.ts
6207
- import { execSync as execSync29 } from "child_process";
6228
+ import { execSync as execSync30 } from "child_process";
6208
6229
  function fetchJson(endpoint) {
6209
- const result = execSync29(`gh api --paginate ${endpoint}`, {
6230
+ const result = execSync30(`gh api --paginate ${endpoint}`, {
6210
6231
  encoding: "utf-8"
6211
6232
  });
6212
6233
  if (!result.trim()) return [];
@@ -6345,7 +6366,7 @@ async function listComments() {
6345
6366
  }
6346
6367
 
6347
6368
  // src/commands/prs/prs/index.ts
6348
- import { execSync as execSync30 } from "child_process";
6369
+ import { execSync as execSync31 } from "child_process";
6349
6370
 
6350
6371
  // src/commands/prs/prs/displayPaginated/index.ts
6351
6372
  import enquirer8 from "enquirer";
@@ -6451,7 +6472,7 @@ async function displayPaginated(pullRequests) {
6451
6472
  async function prs(options2) {
6452
6473
  const state = options2.open ? "open" : options2.closed ? "closed" : "all";
6453
6474
  try {
6454
- const result = execSync30(
6475
+ const result = execSync31(
6455
6476
  `gh pr list --state ${state} --json number,title,url,author,createdAt,mergedAt,closedAt,state,changedFiles --limit 100`,
6456
6477
  { encoding: "utf-8" }
6457
6478
  );
@@ -6474,7 +6495,7 @@ async function prs(options2) {
6474
6495
  }
6475
6496
 
6476
6497
  // src/commands/prs/wontfix.ts
6477
- import { execSync as execSync31 } from "child_process";
6498
+ import { execSync as execSync32 } from "child_process";
6478
6499
  function validateReason(reason) {
6479
6500
  const lowerReason = reason.toLowerCase();
6480
6501
  if (lowerReason.includes("claude") || lowerReason.includes("opus")) {
@@ -6491,7 +6512,7 @@ function validateShaReferences(reason) {
6491
6512
  const invalidShas = [];
6492
6513
  for (const sha of shas) {
6493
6514
  try {
6494
- execSync31(`git cat-file -t ${sha}`, { stdio: "pipe" });
6515
+ execSync32(`git cat-file -t ${sha}`, { stdio: "pipe" });
6495
6516
  } catch {
6496
6517
  invalidShas.push(sha);
6497
6518
  }
@@ -6605,10 +6626,10 @@ import chalk74 from "chalk";
6605
6626
  import Enquirer2 from "enquirer";
6606
6627
 
6607
6628
  // src/commands/ravendb/searchItems.ts
6608
- import { execSync as execSync32 } from "child_process";
6629
+ import { execSync as execSync33 } from "child_process";
6609
6630
  import chalk73 from "chalk";
6610
6631
  function opExec(args) {
6611
- return execSync32(`op ${args}`, {
6632
+ return execSync33(`op ${args}`, {
6612
6633
  encoding: "utf-8",
6613
6634
  stdio: ["pipe", "pipe", "pipe"]
6614
6635
  }).trim();
@@ -6760,7 +6781,7 @@ ${errorText}`
6760
6781
  }
6761
6782
 
6762
6783
  // src/commands/ravendb/resolveOpSecret.ts
6763
- import { execSync as execSync33 } from "child_process";
6784
+ import { execSync as execSync34 } from "child_process";
6764
6785
  import chalk78 from "chalk";
6765
6786
  function resolveOpSecret(reference) {
6766
6787
  if (!reference.startsWith("op://")) {
@@ -6768,7 +6789,7 @@ function resolveOpSecret(reference) {
6768
6789
  process.exit(1);
6769
6790
  }
6770
6791
  try {
6771
- return execSync33(`op read "${reference}"`, {
6792
+ return execSync34(`op read "${reference}"`, {
6772
6793
  encoding: "utf-8",
6773
6794
  stdio: ["pipe", "pipe", "pipe"]
6774
6795
  }).trim();
@@ -7017,7 +7038,7 @@ Refactor check failed:
7017
7038
  }
7018
7039
 
7019
7040
  // src/commands/refactor/check/getViolations/index.ts
7020
- import { execSync as execSync34 } from "child_process";
7041
+ import { execSync as execSync35 } from "child_process";
7021
7042
  import fs16 from "fs";
7022
7043
  import { minimatch as minimatch4 } from "minimatch";
7023
7044
 
@@ -7067,7 +7088,7 @@ function getGitFiles(options2) {
7067
7088
  }
7068
7089
  const files = /* @__PURE__ */ new Set();
7069
7090
  if (options2.staged || options2.modified) {
7070
- const staged = execSync34("git diff --cached --name-only", {
7091
+ const staged = execSync35("git diff --cached --name-only", {
7071
7092
  encoding: "utf-8"
7072
7093
  });
7073
7094
  for (const file of staged.trim().split("\n").filter(Boolean)) {
@@ -7075,7 +7096,7 @@ function getGitFiles(options2) {
7075
7096
  }
7076
7097
  }
7077
7098
  if (options2.unstaged || options2.modified) {
7078
- const unstaged = execSync34("git diff --name-only", { encoding: "utf-8" });
7099
+ const unstaged = execSync35("git diff --name-only", { encoding: "utf-8" });
7079
7100
  for (const file of unstaged.trim().split("\n").filter(Boolean)) {
7080
7101
  files.add(file);
7081
7102
  }
@@ -9370,7 +9391,7 @@ import { mkdirSync as mkdirSync10 } from "fs";
9370
9391
  import { join as join34 } from "path";
9371
9392
 
9372
9393
  // src/commands/voice/checkLockFile.ts
9373
- import { execSync as execSync35 } from "child_process";
9394
+ import { execSync as execSync36 } from "child_process";
9374
9395
  import { existsSync as existsSync35, mkdirSync as mkdirSync9, readFileSync as readFileSync26, writeFileSync as writeFileSync24 } from "fs";
9375
9396
  import { join as join33 } from "path";
9376
9397
  function isProcessAlive(pid) {
@@ -9399,7 +9420,7 @@ function bootstrapVenv() {
9399
9420
  if (existsSync35(getVenvPython())) return;
9400
9421
  console.log("Setting up Python environment...");
9401
9422
  const pythonDir = getPythonDir();
9402
- execSync35(
9423
+ execSync36(
9403
9424
  `uv sync --project "${pythonDir}" --extra runtime --no-install-project`,
9404
9425
  {
9405
9426
  stdio: "inherit",
@@ -9566,11 +9587,11 @@ import { randomBytes } from "crypto";
9566
9587
  import chalk101 from "chalk";
9567
9588
 
9568
9589
  // src/lib/openBrowser.ts
9569
- import { execSync as execSync36 } from "child_process";
9590
+ import { execSync as execSync37 } from "child_process";
9570
9591
  function tryExec(commands) {
9571
9592
  for (const cmd of commands) {
9572
9593
  try {
9573
- execSync36(cmd);
9594
+ execSync37(cmd);
9574
9595
  return true;
9575
9596
  } catch {
9576
9597
  }
@@ -9796,7 +9817,7 @@ function registerRoam(program2) {
9796
9817
  }
9797
9818
 
9798
9819
  // src/commands/run/index.ts
9799
- import { execSync as execSync37 } from "child_process";
9820
+ import { execSync as execSync38 } from "child_process";
9800
9821
 
9801
9822
  // src/commands/run/resolveParams.ts
9802
9823
  function resolveParams(params, cliArgs) {
@@ -9959,7 +9980,7 @@ function listRunConfigs() {
9959
9980
  function runPreCommands(pre) {
9960
9981
  for (const cmd of pre) {
9961
9982
  try {
9962
- execSync37(cmd, { stdio: "inherit" });
9983
+ execSync38(cmd, { stdio: "inherit" });
9963
9984
  } catch (err) {
9964
9985
  const code = err && typeof err === "object" && "status" in err ? err.status : 1;
9965
9986
  process.exit(code);
@@ -9977,7 +9998,7 @@ function run3(name, args) {
9977
9998
  }
9978
9999
 
9979
10000
  // src/commands/screenshot/index.ts
9980
- import { execSync as execSync38 } from "child_process";
10001
+ import { execSync as execSync39 } from "child_process";
9981
10002
  import { existsSync as existsSync38, mkdirSync as mkdirSync13, unlinkSync as unlinkSync10, writeFileSync as writeFileSync27 } from "fs";
9982
10003
  import { tmpdir as tmpdir6 } from "os";
9983
10004
  import { join as join38, resolve as resolve5 } from "path";
@@ -10120,7 +10141,7 @@ function runPowerShellScript(processName, outputPath) {
10120
10141
  const scriptPath = join38(tmpdir6(), `assist-screenshot-${Date.now()}.ps1`);
10121
10142
  writeFileSync27(scriptPath, captureWindowPs1, "utf-8");
10122
10143
  try {
10123
- execSync38(
10144
+ execSync39(
10124
10145
  `powershell -NoProfile -ExecutionPolicy Bypass -File "${scriptPath}" -ProcessName "${processName}" -OutputPath "${outputPath}"`,
10125
10146
  { stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }
10126
10147
  );
@@ -10319,7 +10340,7 @@ function syncCommands(claudeDir, targetBase) {
10319
10340
  }
10320
10341
 
10321
10342
  // src/commands/update.ts
10322
- import { execSync as execSync39 } from "child_process";
10343
+ import { execSync as execSync40 } from "child_process";
10323
10344
  import * as path48 from "path";
10324
10345
  function isGlobalNpmInstall(dir) {
10325
10346
  try {
@@ -10327,7 +10348,7 @@ function isGlobalNpmInstall(dir) {
10327
10348
  if (resolved.split(path48.sep).includes("node_modules")) {
10328
10349
  return true;
10329
10350
  }
10330
- const globalPrefix = execSync39("npm prefix -g", { stdio: "pipe" }).toString().trim();
10351
+ const globalPrefix = execSync40("npm prefix -g", { stdio: "pipe" }).toString().trim();
10331
10352
  return resolved.toLowerCase().startsWith(path48.resolve(globalPrefix).toLowerCase());
10332
10353
  } catch {
10333
10354
  return false;
@@ -10338,18 +10359,18 @@ async function update() {
10338
10359
  console.log(`Assist is installed at: ${installDir}`);
10339
10360
  if (isGitRepo(installDir)) {
10340
10361
  console.log("Detected git repo installation, pulling latest...");
10341
- execSync39("git pull", { cwd: installDir, stdio: "inherit" });
10362
+ execSync40("git pull", { cwd: installDir, stdio: "inherit" });
10342
10363
  console.log("Installing dependencies...");
10343
- execSync39("npm i", { cwd: installDir, stdio: "inherit" });
10364
+ execSync40("npm i", { cwd: installDir, stdio: "inherit" });
10344
10365
  console.log("Building...");
10345
- execSync39("npm run build", { cwd: installDir, stdio: "inherit" });
10366
+ execSync40("npm run build", { cwd: installDir, stdio: "inherit" });
10346
10367
  console.log("Syncing commands...");
10347
- execSync39("assist sync", { stdio: "inherit" });
10368
+ execSync40("assist sync", { stdio: "inherit" });
10348
10369
  } else if (isGlobalNpmInstall(installDir)) {
10349
10370
  console.log("Detected global npm installation, updating...");
10350
- execSync39("npm i -g @staff0rd/assist@latest", { stdio: "inherit" });
10371
+ execSync40("npm i -g @staff0rd/assist@latest", { stdio: "inherit" });
10351
10372
  console.log("Syncing commands...");
10352
- execSync39("assist sync", { stdio: "inherit" });
10373
+ execSync40("assist sync", { stdio: "inherit" });
10353
10374
  } else {
10354
10375
  console.error(
10355
10376
  "Could not determine installation method. Expected a git repo or global npm install."
@@ -10386,6 +10407,7 @@ program.command("notify").description(
10386
10407
  "Show notification from Claude Code hook (reads JSON from stdin)"
10387
10408
  ).action(notify);
10388
10409
  program.command("update").description("Update assist to the latest version and sync commands").action(update);
10410
+ program.command("coverage").description("Print global statement coverage percentage").action(coverage);
10389
10411
  program.command("screenshot").description("Capture a screenshot of a running application window").argument("<process>", "Name of the running process (e.g. notepad, code)").action(screenshot);
10390
10412
  registerCliHook(program);
10391
10413
  registerJira(program);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@staff0rd/assist",
3
- "version": "0.147.3",
3
+ "version": "0.148.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "bin": {