@staff0rd/assist 0.133.0 → 0.134.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
@@ -46,6 +46,7 @@ After installation, the `assist` command will be available globally. You can als
46
46
  - `/standup` - Summarise recent journal entries as a standup update
47
47
  - `/sync` - Sync commands and settings to ~/.claude
48
48
  - `/inspect` - Run .NET code inspections on changed files
49
+ - `/screenshot` - Capture a screenshot of a running application window
49
50
  - `/seq` - Query Seq logs from a URL or filter expression
50
51
  - `/verify` - Run all verification commands in parallel
51
52
  - `/transcript-format` - Format meeting transcripts from VTT files
@@ -142,6 +143,7 @@ After installation, the `assist` command will be available globally. You can als
142
143
  - `assist seq query <filter> -c <connection>` - Query using a specific connection
143
144
  - `assist seq query <filter> --json` - Output raw JSON
144
145
  - `assist seq query <filter> -n <count>` - Fetch a specific number of events (default 50)
146
+ - `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`)
145
147
  - `assist complexity <pattern>` - Analyze a file (all metrics if single match, maintainability if multiple)
146
148
  - `assist complexity cyclomatic [pattern]` - Calculate cyclomatic complexity per function
147
149
  - `assist complexity halstead [pattern]` - Calculate Halstead metrics per function
@@ -0,0 +1,9 @@
1
+ ---
2
+ description: Capture a screenshot of a running application window
3
+ ---
4
+
5
+ Take a screenshot of a running application window. Ask the user which process to capture if not specified.
6
+
7
+ Run `assist screenshot <process>` where `<process>` is the name of the running process (e.g. notepad, code, chrome).
8
+
9
+ The screenshot is saved to the configured output directory (default `./screenshots`).
@@ -46,6 +46,7 @@
46
46
  "Bash(assist ravendb auth list:*)",
47
47
  "Bash(assist seq query:*)",
48
48
  "Bash(assist seq auth list:*)",
49
+ "Bash(assist screenshot:*)",
49
50
  "Bash(assist roam show-claude-code-icon:*)",
50
51
  "SlashCommand(/next-backlog-item)",
51
52
  "SlashCommand(/verify)",
@@ -83,6 +84,8 @@
83
84
  "SlashCommand(/seq)",
84
85
  "Skill(inspect)",
85
86
  "SlashCommand(/inspect)",
87
+ "Skill(screenshot)",
88
+ "SlashCommand(/screenshot)",
86
89
  "WebFetch(domain:staffordwilliams.com)"
87
90
  ],
88
91
  "deny": ["Bash(git commit:*)", "Bash(npm run:*)", "Bash(npx assist:*)"]
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.133.0",
9
+ version: "0.134.0",
10
10
  type: "module",
11
11
  main: "dist/index.js",
12
12
  bin: {
@@ -189,6 +189,9 @@ var assistConfigSchema = z.strictObject({
189
189
  ).default([]),
190
190
  defaultConnection: z.string().optional()
191
191
  }).optional(),
192
+ screenshot: z.strictObject({
193
+ outputDir: z.string().default("./screenshots")
194
+ }).default({ outputDir: "./screenshots" }),
192
195
  voice: z.strictObject({
193
196
  wakeWords: z.array(z.string()).default(DEFAULT_WAKE_WORDS),
194
197
  mic: z.string().optional(),
@@ -1841,14 +1844,14 @@ function flushIfFailed(exitCode, chunks) {
1841
1844
 
1842
1845
  // src/commands/verify/run/runAllEntries.ts
1843
1846
  function runEntry(entry, onComplete) {
1844
- return new Promise((resolve6) => {
1847
+ return new Promise((resolve7) => {
1845
1848
  const child = spawnCommand(entry.fullCommand, entry.cwd, entry.env);
1846
1849
  const chunks = collectOutput(child);
1847
1850
  child.on("close", (code) => {
1848
1851
  const exitCode = code ?? 1;
1849
1852
  flushIfFailed(exitCode, chunks);
1850
1853
  onComplete?.(exitCode);
1851
- resolve6({ script: entry.name, code: exitCode });
1854
+ resolve7({ script: entry.name, code: exitCode });
1852
1855
  });
1853
1856
  });
1854
1857
  }
@@ -2635,12 +2638,12 @@ function getHtml() {
2635
2638
 
2636
2639
  // src/commands/backlog/web/parseItemBody.ts
2637
2640
  function readBody(req) {
2638
- return new Promise((resolve6, reject) => {
2641
+ return new Promise((resolve7, reject) => {
2639
2642
  let body = "";
2640
2643
  req.on("data", (chunk) => {
2641
2644
  body += chunk.toString();
2642
2645
  });
2643
- req.on("end", () => resolve6(body));
2646
+ req.on("end", () => resolve7(body));
2644
2647
  req.on("error", reject);
2645
2648
  });
2646
2649
  }
@@ -3197,12 +3200,12 @@ function hasSubcommands(helpText) {
3197
3200
  // src/commands/permitCliReads/runHelp.ts
3198
3201
  import { exec as exec2 } from "child_process";
3199
3202
  function runHelp(args) {
3200
- return new Promise((resolve6) => {
3203
+ return new Promise((resolve7) => {
3201
3204
  exec2(
3202
3205
  `${args.join(" ")} --help`,
3203
3206
  { encoding: "utf-8", timeout: 3e4 },
3204
3207
  (_err, stdout, stderr) => {
3205
- resolve6(stdout || stderr || "");
3208
+ resolve7(stdout || stderr || "");
3206
3209
  }
3207
3210
  );
3208
3211
  });
@@ -6704,7 +6707,7 @@ function getViolations(pattern2, options2 = {}, maxLines = DEFAULT_MAX_LINES) {
6704
6707
 
6705
6708
  // src/commands/refactor/check/index.ts
6706
6709
  function runScript(script, cwd) {
6707
- return new Promise((resolve6) => {
6710
+ return new Promise((resolve7) => {
6708
6711
  const child = spawn3("npm", ["run", script], {
6709
6712
  stdio: "pipe",
6710
6713
  shell: true,
@@ -6718,7 +6721,7 @@ function runScript(script, cwd) {
6718
6721
  output += data.toString();
6719
6722
  });
6720
6723
  child.on("close", (code) => {
6721
- resolve6({ script, code: code ?? 1, output });
6724
+ resolve7({ script, code: code ?? 1, output });
6722
6725
  });
6723
6726
  });
6724
6727
  }
@@ -7662,9 +7665,9 @@ function createReadlineInterface() {
7662
7665
  });
7663
7666
  }
7664
7667
  function askQuestion(rl, question) {
7665
- return new Promise((resolve6) => {
7668
+ return new Promise((resolve7) => {
7666
7669
  rl.question(question, (answer) => {
7667
- resolve6(answer.trim());
7670
+ resolve7(answer.trim());
7668
7671
  });
7669
7672
  });
7670
7673
  }
@@ -8605,7 +8608,7 @@ function extractCode(url, expectedState) {
8605
8608
  return code;
8606
8609
  }
8607
8610
  function waitForCallback(port, expectedState) {
8608
- return new Promise((resolve6, reject) => {
8611
+ return new Promise((resolve7, reject) => {
8609
8612
  const timeout = setTimeout(() => {
8610
8613
  server.close();
8611
8614
  reject(new Error("Authorization timed out after 120 seconds"));
@@ -8622,7 +8625,7 @@ function waitForCallback(port, expectedState) {
8622
8625
  const code = extractCode(url, expectedState);
8623
8626
  respondHtml(res, 200, "Authorization successful!");
8624
8627
  server.close();
8625
- resolve6(code);
8628
+ resolve7(code);
8626
8629
  } catch (err) {
8627
8630
  respondHtml(res, 400, err.message);
8628
8631
  server.close();
@@ -8953,11 +8956,178 @@ function run2(name, args) {
8953
8956
  );
8954
8957
  }
8955
8958
 
8959
+ // src/commands/screenshot/index.ts
8960
+ import { execSync as execSync38 } from "child_process";
8961
+ import { existsSync as existsSync36, mkdirSync as mkdirSync13, unlinkSync as unlinkSync9, writeFileSync as writeFileSync26 } from "fs";
8962
+ import { tmpdir as tmpdir6 } from "os";
8963
+ import { join as join37, resolve as resolve5 } from "path";
8964
+ import chalk92 from "chalk";
8965
+
8966
+ // src/commands/screenshot/captureWindowPs1.ts
8967
+ var captureWindowPs1 = `
8968
+ param([string]$ProcessName, [string]$OutputPath)
8969
+
8970
+ Add-Type -AssemblyName System.Drawing
8971
+
8972
+ Add-Type @"
8973
+ using System;
8974
+ using System.Runtime.InteropServices;
8975
+ public class Win32Window {
8976
+ [DllImport("user32.dll")]
8977
+ [return: MarshalAs(UnmanagedType.Bool)]
8978
+ public static extern bool SetProcessDPIAware();
8979
+
8980
+ [DllImport("user32.dll")]
8981
+ [return: MarshalAs(UnmanagedType.Bool)]
8982
+ public static extern bool IsIconic(IntPtr hWnd);
8983
+
8984
+ [DllImport("user32.dll")]
8985
+ [return: MarshalAs(UnmanagedType.Bool)]
8986
+ public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
8987
+
8988
+ [DllImport("dwmapi.dll")]
8989
+ public static extern int DwmGetWindowAttribute(
8990
+ IntPtr hwnd, int dwAttribute, out RECT pvAttribute, int cbAttribute);
8991
+
8992
+ [DllImport("user32.dll")]
8993
+ public static extern IntPtr GetDC(IntPtr hWnd);
8994
+
8995
+ [DllImport("user32.dll")]
8996
+ public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
8997
+
8998
+ [DllImport("gdi32.dll")]
8999
+ public static extern IntPtr CreateCompatibleDC(IntPtr hdc);
9000
+
9001
+ [DllImport("gdi32.dll")]
9002
+ public static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int w, int h);
9003
+
9004
+ [DllImport("gdi32.dll")]
9005
+ public static extern IntPtr SelectObject(IntPtr hdc, IntPtr h);
9006
+
9007
+ [DllImport("gdi32.dll")]
9008
+ [return: MarshalAs(UnmanagedType.Bool)]
9009
+ public static extern bool BitBlt(
9010
+ IntPtr hdc, int x, int y, int cx, int cy,
9011
+ IntPtr hdcSrc, int x1, int y1, uint rop);
9012
+
9013
+ [DllImport("gdi32.dll")]
9014
+ [return: MarshalAs(UnmanagedType.Bool)]
9015
+ public static extern bool DeleteObject(IntPtr ho);
9016
+
9017
+ [DllImport("gdi32.dll")]
9018
+ [return: MarshalAs(UnmanagedType.Bool)]
9019
+ public static extern bool DeleteDC(IntPtr hdc);
9020
+
9021
+ [StructLayout(LayoutKind.Sequential)]
9022
+ public struct RECT {
9023
+ public int Left;
9024
+ public int Top;
9025
+ public int Right;
9026
+ public int Bottom;
9027
+ }
9028
+ }
9029
+ "@
9030
+
9031
+ # DPI awareness ensures all coordinates are in physical pixels
9032
+ [Win32Window]::SetProcessDPIAware() | Out-Null
9033
+
9034
+ $procs = Get-Process -Name $ProcessName -ErrorAction SilentlyContinue |
9035
+ Where-Object { $_.MainWindowHandle -ne [IntPtr]::Zero }
9036
+
9037
+ if (-not $procs) {
9038
+ Write-Error "No visible window found for process '$ProcessName'"
9039
+ exit 1
9040
+ }
9041
+
9042
+ $proc = $procs | Select-Object -First 1
9043
+ $hwnd = $proc.MainWindowHandle
9044
+
9045
+ if ([Win32Window]::IsIconic($hwnd)) {
9046
+ [Win32Window]::ShowWindow($hwnd, 9) | Out-Null # SW_RESTORE
9047
+ Start-Sleep -Milliseconds 300
9048
+ }
9049
+
9050
+ # DWMWA_EXTENDED_FRAME_BOUNDS (9) = visible bounds excluding invisible DWM shadow
9051
+ $rect = New-Object Win32Window+RECT
9052
+ $hr = [Win32Window]::DwmGetWindowAttribute(
9053
+ $hwnd, 9, [ref]$rect,
9054
+ [System.Runtime.InteropServices.Marshal]::SizeOf($rect))
9055
+
9056
+ if ($hr -ne 0) {
9057
+ Write-Error "Failed to get window bounds (HRESULT: $hr)"
9058
+ exit 1
9059
+ }
9060
+
9061
+ $width = $rect.Right - $rect.Left
9062
+ $height = $rect.Bottom - $rect.Top
9063
+
9064
+ if ($width -le 0 -or $height -le 0) {
9065
+ Write-Error "Window has invalid dimensions ($width x $height)"
9066
+ exit 1
9067
+ }
9068
+
9069
+ # BitBlt from screen DC \u2014 both coords and capture use physical pixels
9070
+ $hdcScreen = [Win32Window]::GetDC([IntPtr]::Zero)
9071
+ $hdcMem = [Win32Window]::CreateCompatibleDC($hdcScreen)
9072
+ $hBitmap = [Win32Window]::CreateCompatibleBitmap($hdcScreen, $width, $height)
9073
+ $hOld = [Win32Window]::SelectObject($hdcMem, $hBitmap)
9074
+
9075
+ $SRCCOPY = 0x00CC0020
9076
+ [Win32Window]::BitBlt($hdcMem, 0, 0, $width, $height,
9077
+ $hdcScreen, $rect.Left, $rect.Top, $SRCCOPY) | Out-Null
9078
+
9079
+ $bitmap = [System.Drawing.Image]::FromHbitmap($hBitmap)
9080
+ $bitmap.Save($OutputPath, [System.Drawing.Imaging.ImageFormat]::Png)
9081
+ $bitmap.Dispose()
9082
+
9083
+ [Win32Window]::SelectObject($hdcMem, $hOld) | Out-Null
9084
+ [Win32Window]::DeleteObject($hBitmap) | Out-Null
9085
+ [Win32Window]::DeleteDC($hdcMem) | Out-Null
9086
+ [Win32Window]::ReleaseDC([IntPtr]::Zero, $hdcScreen) | Out-Null
9087
+
9088
+ Write-Output $OutputPath
9089
+ `;
9090
+
9091
+ // src/commands/screenshot/index.ts
9092
+ function buildOutputPath(outputDir, processName) {
9093
+ if (!existsSync36(outputDir)) {
9094
+ mkdirSync13(outputDir, { recursive: true });
9095
+ }
9096
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
9097
+ return resolve5(outputDir, `${processName}-${timestamp}.png`);
9098
+ }
9099
+ function runPowerShellScript(processName, outputPath) {
9100
+ const scriptPath = join37(tmpdir6(), `assist-screenshot-${Date.now()}.ps1`);
9101
+ writeFileSync26(scriptPath, captureWindowPs1, "utf-8");
9102
+ try {
9103
+ execSync38(
9104
+ `powershell -NoProfile -ExecutionPolicy Bypass -File "${scriptPath}" -ProcessName "${processName}" -OutputPath "${outputPath}"`,
9105
+ { stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }
9106
+ );
9107
+ } finally {
9108
+ unlinkSync9(scriptPath);
9109
+ }
9110
+ }
9111
+ function screenshot(processName) {
9112
+ const config = loadConfig();
9113
+ const outputDir = resolve5(config.screenshot.outputDir);
9114
+ const outputPath = buildOutputPath(outputDir, processName);
9115
+ console.log(chalk92.gray(`Capturing window for process "${processName}" ...`));
9116
+ try {
9117
+ runPowerShellScript(processName, outputPath);
9118
+ console.log(chalk92.green(`Screenshot saved: ${outputPath}`));
9119
+ } catch (error) {
9120
+ const msg = error instanceof Error ? error.message : String(error);
9121
+ console.error(chalk92.red(`Failed to capture screenshot: ${msg}`));
9122
+ process.exit(1);
9123
+ }
9124
+ }
9125
+
8956
9126
  // src/commands/statusLine.ts
8957
- import chalk93 from "chalk";
9127
+ import chalk94 from "chalk";
8958
9128
 
8959
9129
  // src/commands/buildLimitsSegment.ts
8960
- import chalk92 from "chalk";
9130
+ import chalk93 from "chalk";
8961
9131
  var FIVE_HOUR_SECONDS = 5 * 3600;
8962
9132
  var SEVEN_DAY_SECONDS = 7 * 86400;
8963
9133
  function formatTimeLeft(resetsAt) {
@@ -8980,10 +9150,10 @@ function projectUsage(pct, resetsAt, windowSeconds) {
8980
9150
  function colorizeRateLimit(pct, resetsAt, windowSeconds) {
8981
9151
  const label2 = `${Math.round(pct)}%`;
8982
9152
  const projected = projectUsage(pct, resetsAt, windowSeconds);
8983
- if (projected == null) return chalk92.green(label2);
8984
- if (projected > 100) return chalk92.red(label2);
8985
- if (projected > 75) return chalk92.yellow(label2);
8986
- return chalk92.green(label2);
9153
+ if (projected == null) return chalk93.green(label2);
9154
+ if (projected > 100) return chalk93.red(label2);
9155
+ if (projected > 75) return chalk93.yellow(label2);
9156
+ return chalk93.green(label2);
8987
9157
  }
8988
9158
  function formatLimit(pct, resetsAt, windowSeconds, fallbackLabel) {
8989
9159
  const timeLabel = resetsAt ? formatTimeLeft(resetsAt) : fallbackLabel;
@@ -9009,14 +9179,14 @@ function buildLimitsSegment(rateLimits) {
9009
9179
  }
9010
9180
 
9011
9181
  // src/commands/statusLine.ts
9012
- chalk93.level = 3;
9182
+ chalk94.level = 3;
9013
9183
  function formatNumber(num) {
9014
9184
  return num.toLocaleString("en-US");
9015
9185
  }
9016
9186
  function colorizePercent(pct) {
9017
9187
  const label2 = `${Math.round(pct)}%`;
9018
- if (pct > 80) return chalk93.red(label2);
9019
- if (pct > 40) return chalk93.yellow(label2);
9188
+ if (pct > 80) return chalk94.red(label2);
9189
+ if (pct > 40) return chalk94.yellow(label2);
9020
9190
  return label2;
9021
9191
  }
9022
9192
  async function statusLine() {
@@ -9039,7 +9209,7 @@ import { fileURLToPath as fileURLToPath7 } from "url";
9039
9209
  // src/commands/sync/syncClaudeMd.ts
9040
9210
  import * as fs22 from "fs";
9041
9211
  import * as path40 from "path";
9042
- import chalk94 from "chalk";
9212
+ import chalk95 from "chalk";
9043
9213
  async function syncClaudeMd(claudeDir, targetBase) {
9044
9214
  const source = path40.join(claudeDir, "CLAUDE.md");
9045
9215
  const target = path40.join(targetBase, "CLAUDE.md");
@@ -9048,12 +9218,12 @@ async function syncClaudeMd(claudeDir, targetBase) {
9048
9218
  const targetContent = fs22.readFileSync(target, "utf-8");
9049
9219
  if (sourceContent !== targetContent) {
9050
9220
  console.log(
9051
- chalk94.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
9221
+ chalk95.yellow("\n\u26A0\uFE0F Warning: CLAUDE.md differs from existing file")
9052
9222
  );
9053
9223
  console.log();
9054
9224
  printDiff(targetContent, sourceContent);
9055
9225
  const confirm = await promptConfirm(
9056
- chalk94.red("Overwrite existing CLAUDE.md?"),
9226
+ chalk95.red("Overwrite existing CLAUDE.md?"),
9057
9227
  false
9058
9228
  );
9059
9229
  if (!confirm) {
@@ -9069,7 +9239,7 @@ async function syncClaudeMd(claudeDir, targetBase) {
9069
9239
  // src/commands/sync/syncSettings.ts
9070
9240
  import * as fs23 from "fs";
9071
9241
  import * as path41 from "path";
9072
- import chalk95 from "chalk";
9242
+ import chalk96 from "chalk";
9073
9243
  async function syncSettings(claudeDir, targetBase, options2) {
9074
9244
  const source = path41.join(claudeDir, "settings.json");
9075
9245
  const target = path41.join(targetBase, "settings.json");
@@ -9085,14 +9255,14 @@ async function syncSettings(claudeDir, targetBase, options2) {
9085
9255
  if (mergedContent !== normalizedTarget) {
9086
9256
  if (!options2?.yes) {
9087
9257
  console.log(
9088
- chalk95.yellow(
9258
+ chalk96.yellow(
9089
9259
  "\n\u26A0\uFE0F Warning: settings.json differs from existing file"
9090
9260
  )
9091
9261
  );
9092
9262
  console.log();
9093
9263
  printDiff(targetContent, mergedContent);
9094
9264
  const confirm = await promptConfirm(
9095
- chalk95.red("Overwrite existing settings.json?"),
9265
+ chalk96.red("Overwrite existing settings.json?"),
9096
9266
  false
9097
9267
  );
9098
9268
  if (!confirm) {
@@ -9129,7 +9299,7 @@ function syncCommands(claudeDir, targetBase) {
9129
9299
  }
9130
9300
 
9131
9301
  // src/commands/update.ts
9132
- import { execSync as execSync38 } from "child_process";
9302
+ import { execSync as execSync39 } from "child_process";
9133
9303
  import * as path43 from "path";
9134
9304
  function isGlobalNpmInstall(dir) {
9135
9305
  try {
@@ -9137,7 +9307,7 @@ function isGlobalNpmInstall(dir) {
9137
9307
  if (resolved.split(path43.sep).includes("node_modules")) {
9138
9308
  return true;
9139
9309
  }
9140
- const globalPrefix = execSync38("npm prefix -g", { stdio: "pipe" }).toString().trim();
9310
+ const globalPrefix = execSync39("npm prefix -g", { stdio: "pipe" }).toString().trim();
9141
9311
  return resolved.toLowerCase().startsWith(path43.resolve(globalPrefix).toLowerCase());
9142
9312
  } catch {
9143
9313
  return false;
@@ -9148,18 +9318,18 @@ async function update() {
9148
9318
  console.log(`Assist is installed at: ${installDir}`);
9149
9319
  if (isGitRepo(installDir)) {
9150
9320
  console.log("Detected git repo installation, pulling latest...");
9151
- execSync38("git pull", { cwd: installDir, stdio: "inherit" });
9321
+ execSync39("git pull", { cwd: installDir, stdio: "inherit" });
9152
9322
  console.log("Installing dependencies...");
9153
- execSync38("npm i", { cwd: installDir, stdio: "inherit" });
9323
+ execSync39("npm i", { cwd: installDir, stdio: "inherit" });
9154
9324
  console.log("Building...");
9155
- execSync38("npm run build", { cwd: installDir, stdio: "inherit" });
9325
+ execSync39("npm run build", { cwd: installDir, stdio: "inherit" });
9156
9326
  console.log("Syncing commands...");
9157
- execSync38("assist sync", { stdio: "inherit" });
9327
+ execSync39("assist sync", { stdio: "inherit" });
9158
9328
  } else if (isGlobalNpmInstall(installDir)) {
9159
9329
  console.log("Detected global npm installation, updating...");
9160
- execSync38("npm i -g @staff0rd/assist@latest", { stdio: "inherit" });
9330
+ execSync39("npm i -g @staff0rd/assist@latest", { stdio: "inherit" });
9161
9331
  console.log("Syncing commands...");
9162
- execSync38("assist sync", { stdio: "inherit" });
9332
+ execSync39("assist sync", { stdio: "inherit" });
9163
9333
  } else {
9164
9334
  console.error(
9165
9335
  "Could not determine installation method. Expected a git repo or global npm install."
@@ -9196,6 +9366,7 @@ program.command("notify").description(
9196
9366
  "Show notification from Claude Code hook (reads JSON from stdin)"
9197
9367
  ).action(notify);
9198
9368
  program.command("update").description("Update assist to the latest version and sync commands").action(update);
9369
+ 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);
9199
9370
  registerCliHook(program);
9200
9371
  registerJira(program);
9201
9372
  registerPrs(program);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@staff0rd/assist",
3
- "version": "0.133.0",
3
+ "version": "0.134.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "bin": {