claude-scope 0.8.13 → 0.8.14

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/claude-scope.cjs +147 -44
  2. package/package.json +1 -1
@@ -7581,11 +7581,130 @@ init_context_widget();
7581
7581
  init_cost_widget();
7582
7582
 
7583
7583
  // src/widgets/dev-server/dev-server-widget.ts
7584
- var import_node_child_process2 = require("node:child_process");
7585
- var import_node_util3 = require("node:util");
7586
7584
  init_widget_types();
7587
7585
  init_theme();
7588
7586
 
7587
+ // src/widgets/dev-server/port-detector.ts
7588
+ var import_node_child_process2 = require("node:child_process");
7589
+ var import_node_util3 = require("node:util");
7590
+ var execFileAsync2 = (0, import_node_util3.promisify)(import_node_child_process2.execFile);
7591
+ var PORT_MAPPING = {
7592
+ 5173: { name: "Vite", icon: "\u26A1" },
7593
+ 4200: { name: "Angular", icon: "\u25B2" },
7594
+ 3e3: { name: "Dev", icon: "\u{1F680}" },
7595
+ 8080: { name: "Webpack", icon: "\u{1F4E6}" },
7596
+ 8e3: { name: "Dev", icon: "\u{1F680}" },
7597
+ 8888: { name: "Dev", icon: "\u{1F680}" }
7598
+ };
7599
+ var DEV_PORTS = [5173, 4200, 3e3, 8080, 8e3, 8888];
7600
+ var PortDetector = class {
7601
+ execFn;
7602
+ /**
7603
+ * Create a new PortDetector
7604
+ * @param execFn - Optional execFile function for testing (dependency injection)
7605
+ */
7606
+ constructor(execFn) {
7607
+ this.execFn = execFn ?? execFileAsync2;
7608
+ }
7609
+ /**
7610
+ * Detect running dev servers by checking listening ports
7611
+ * @returns Detected server info or null
7612
+ */
7613
+ async detect() {
7614
+ try {
7615
+ const args = [
7616
+ "-nP",
7617
+ // No host names, no port names
7618
+ "-iTCP",
7619
+ // Internet TCP
7620
+ "-sTCP:LISTEN"
7621
+ // TCP LISTEN state only
7622
+ ];
7623
+ for (const port of DEV_PORTS) {
7624
+ args.push("-i", `:${port}`);
7625
+ }
7626
+ const { stdout } = await this.execFn("lsof", args, {
7627
+ timeout: 2e3
7628
+ });
7629
+ const lines = stdout.trim().split("\n");
7630
+ for (const line of lines) {
7631
+ if (!line || line.startsWith("COMMAND")) continue;
7632
+ const match = line.match(/:(\d+)\s*\(LISTEN\)/);
7633
+ if (match) {
7634
+ const port = parseInt(match[1], 10);
7635
+ const mapping = PORT_MAPPING[port];
7636
+ if (mapping) {
7637
+ return {
7638
+ name: mapping.name,
7639
+ icon: mapping.icon,
7640
+ port,
7641
+ isRunning: true,
7642
+ isBuilding: false
7643
+ };
7644
+ }
7645
+ }
7646
+ }
7647
+ return null;
7648
+ } catch {
7649
+ return null;
7650
+ }
7651
+ }
7652
+ };
7653
+
7654
+ // src/widgets/dev-server/process-detector.ts
7655
+ var import_node_child_process3 = require("node:child_process");
7656
+ var import_node_util4 = require("node:util");
7657
+ var execFileAsync3 = (0, import_node_util4.promisify)(import_node_child_process3.execFile);
7658
+ var ProcessDetector = class {
7659
+ execFn;
7660
+ processPatterns = [
7661
+ // Generic server patterns - more specific to avoid shell history false positives
7662
+ { regex: /^[\w\s]+\/npm\s+(exec|run)\s+serve/i, name: "Server", icon: "\u{1F310}" },
7663
+ { regex: /^[\w\s]+\/npx\s+serve\s+-/i, name: "Server", icon: "\u{1F310}" },
7664
+ { regex: /^[\w\s]+\/(python|python3)\s+-m\s+http\.server/i, name: "HTTP", icon: "\u{1F310}" },
7665
+ // Generic dev/build patterns - require full command path
7666
+ { regex: /^[\w\s]+\/(npm|yarn|pnpm|bun)\s+run\s+dev\s*$/i, name: "Dev", icon: "\u{1F680}" },
7667
+ { regex: /^[\w\s]+\/(npm|yarn|pnpm|bun)\s+run\s+build\s*$/i, name: "Build", icon: "\u{1F528}" },
7668
+ // Framework-specific patterns - require executable path
7669
+ { regex: /\/(nuxt|next|astro|remix|svelte)\s+dev/i, name: "Framework", icon: "\u26A1" },
7670
+ { regex: /\/node.*\/vite\s*$/i, name: "Vite", icon: "\u26A1" },
7671
+ // Fallback: simpler patterns but checked last
7672
+ { regex: /\s(nuxt|next|vite)\s+dev\s/i, name: "DevServer", icon: "\u26A1" }
7673
+ ];
7674
+ /**
7675
+ * Create a new ProcessDetector
7676
+ * @param execFn - Optional execFile function for testing (dependency injection)
7677
+ */
7678
+ constructor(execFn) {
7679
+ this.execFn = execFn ?? execFileAsync3;
7680
+ }
7681
+ /**
7682
+ * Detect running dev server by parsing system process list
7683
+ * @returns Detected server status or null
7684
+ */
7685
+ async detect() {
7686
+ try {
7687
+ const { stdout } = await this.execFn("ps", ["aux"], {
7688
+ timeout: 1e3
7689
+ });
7690
+ for (const pattern of this.processPatterns) {
7691
+ if (pattern.regex.test(stdout)) {
7692
+ const isBuilding = pattern.name.toLowerCase().includes("build");
7693
+ const isRunning = !isBuilding;
7694
+ return {
7695
+ name: pattern.name,
7696
+ icon: pattern.icon,
7697
+ isRunning,
7698
+ isBuilding
7699
+ };
7700
+ }
7701
+ }
7702
+ } catch {
7703
+ }
7704
+ return null;
7705
+ }
7706
+ };
7707
+
7589
7708
  // src/widgets/dev-server/styles.ts
7590
7709
  init_colors();
7591
7710
  var devServerStyles = {
@@ -7637,13 +7756,12 @@ var devServerStyles = {
7637
7756
  };
7638
7757
 
7639
7758
  // src/widgets/dev-server/dev-server-widget.ts
7640
- var execFileAsync2 = (0, import_node_util3.promisify)(import_node_child_process2.execFile);
7641
7759
  var DevServerWidget = class {
7642
7760
  id = "dev-server";
7643
7761
  metadata = createWidgetMetadata(
7644
7762
  "Dev Server",
7645
- "Detects running dev server processes",
7646
- "1.0.0",
7763
+ "Detects running dev server processes using hybrid port+process detection",
7764
+ "1.1.0",
7647
7765
  "claude-scope",
7648
7766
  0
7649
7767
  );
@@ -7652,22 +7770,12 @@ var DevServerWidget = class {
7652
7770
  _lineOverride;
7653
7771
  styleFn = devServerStyles.balanced;
7654
7772
  cwd = null;
7655
- processPatterns = [
7656
- // Generic server patterns - more specific to avoid shell history false positives
7657
- { regex: /^[\w\s]+\/npm\s+(exec|run)\s+serve/i, name: "Server", icon: "\u{1F310}" },
7658
- { regex: /^[\w\s]+\/npx\s+serve\s+-/i, name: "Server", icon: "\u{1F310}" },
7659
- { regex: /^[\w\s]+\/(python|python3)\s+-m\s+http\.server/i, name: "HTTP", icon: "\u{1F310}" },
7660
- // Generic dev/build patterns - require full command path
7661
- { regex: /^[\w\s]+\/(npm|yarn|pnpm|bun)\s+run\s+dev\s*$/i, name: "Dev", icon: "\u{1F680}" },
7662
- { regex: /^[\w\s]+\/(npm|yarn|pnpm|bun)\s+run\s+build\s*$/i, name: "Build", icon: "\u{1F528}" },
7663
- // Framework-specific patterns - require executable path
7664
- { regex: /\/(nuxt|next|astro|remix|svelte)\s+dev/i, name: "Framework", icon: "\u26A1" },
7665
- { regex: /\/node.*\/vite\s*$/i, name: "Vite", icon: "\u26A1" },
7666
- // Fallback: simpler patterns but checked last
7667
- { regex: /\s(nuxt|next|vite)\s+dev\s/i, name: "DevServer", icon: "\u26A1" }
7668
- ];
7773
+ portDetector;
7774
+ processDetector;
7669
7775
  constructor(colors2) {
7670
7776
  this.colors = colors2 ?? DEFAULT_THEME;
7777
+ this.portDetector = new PortDetector();
7778
+ this.processDetector = new ProcessDetector();
7671
7779
  }
7672
7780
  /**
7673
7781
  * Set display style
@@ -7736,35 +7844,30 @@ var DevServerWidget = class {
7736
7844
  return this.styleFn(renderData, this.colors.devServer);
7737
7845
  }
7738
7846
  /**
7739
- * Detect running dev server by parsing system process list
7847
+ * Detect running dev server using hybrid approach
7848
+ *
7849
+ * 1. Try port-based detection first (more reliable)
7850
+ * 2. Fall back to process-based detection
7851
+ *
7740
7852
  * @returns Detected server status or null
7741
7853
  */
7742
7854
  async detectDevServer() {
7743
- try {
7744
- const { stdout } = await execFileAsync2("ps", ["aux"], {
7745
- timeout: 1e3
7746
- });
7747
- for (const pattern of this.processPatterns) {
7748
- if (pattern.regex.test(stdout)) {
7749
- const isBuilding = pattern.name.toLowerCase().includes("build");
7750
- const isRunning = !isBuilding;
7751
- return {
7752
- name: pattern.name,
7753
- icon: pattern.icon,
7754
- isRunning,
7755
- isBuilding
7756
- };
7757
- }
7758
- }
7759
- } catch {
7855
+ const portResult = await this.portDetector.detect();
7856
+ if (portResult) {
7857
+ return {
7858
+ name: portResult.name,
7859
+ icon: portResult.icon,
7860
+ isRunning: portResult.isRunning,
7861
+ isBuilding: portResult.isBuilding
7862
+ };
7760
7863
  }
7761
- return null;
7864
+ return await this.processDetector.detect();
7762
7865
  }
7763
7866
  };
7764
7867
 
7765
7868
  // src/widgets/docker/docker-widget.ts
7766
- var import_node_child_process3 = require("node:child_process");
7767
- var import_node_util4 = require("node:util");
7869
+ var import_node_child_process4 = require("node:child_process");
7870
+ var import_node_util5 = require("node:util");
7768
7871
  init_widget_types();
7769
7872
  init_theme();
7770
7873
 
@@ -7831,7 +7934,7 @@ var dockerStyles = {
7831
7934
  };
7832
7935
 
7833
7936
  // src/widgets/docker/docker-widget.ts
7834
- var execFileAsync3 = (0, import_node_util4.promisify)(import_node_child_process3.execFile);
7937
+ var execFileAsync4 = (0, import_node_util5.promisify)(import_node_child_process4.execFile);
7835
7938
  var DockerWidget = class {
7836
7939
  id = "docker";
7837
7940
  metadata = createWidgetMetadata(
@@ -7891,12 +7994,12 @@ var DockerWidget = class {
7891
7994
  }
7892
7995
  async getDockerStatus() {
7893
7996
  try {
7894
- await execFileAsync3("docker", ["info"], { timeout: 2e3 });
7895
- const { stdout: runningOutput } = await execFileAsync3("docker", ["ps", "-q"], {
7997
+ await execFileAsync4("docker", ["info"], { timeout: 2e3 });
7998
+ const { stdout: runningOutput } = await execFileAsync4("docker", ["ps", "-q"], {
7896
7999
  timeout: 1e3
7897
8000
  });
7898
8001
  const running = runningOutput.trim().split("\n").filter((line) => line).length;
7899
- const { stdout: allOutput } = await execFileAsync3("docker", ["ps", "-aq"], {
8002
+ const { stdout: allOutput } = await execFileAsync4("docker", ["ps", "-aq"], {
7900
8003
  timeout: 1e3
7901
8004
  });
7902
8005
  const total = allOutput.trim().split("\n").filter((line) => line).length;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-scope",
3
- "version": "0.8.13",
3
+ "version": "0.8.14",
4
4
  "description": "Claude Code plugin for session status and analytics",
5
5
  "license": "MIT",
6
6
  "type": "module",