claude-scope 0.8.12 → 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 -46
  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,24 +7770,12 @@ var DevServerWidget = class {
7652
7770
  _lineOverride;
7653
7771
  styleFn = devServerStyles.balanced;
7654
7772
  cwd = null;
7655
- processPatterns = [
7656
- // Generic server patterns (checked first to catch simple servers)
7657
- { regex: /(npm|npx)\s+exec\s+serve/i, name: "Server", icon: "\u{1F310}" },
7658
- { regex: /(python|python3)\s+-m\s+http\.server/i, name: "HTTP", icon: "\u{1F310}" },
7659
- { regex: /serve\s+\.?-l?\s*\d+/i, name: "Server", icon: "\u{1F310}" },
7660
- // Generic dev/build patterns
7661
- { regex: /(npm|yarn|pnpm|bun)\s+run\s+dev/i, name: "Dev", icon: "\u{1F680}" },
7662
- { regex: /(npm|yarn|pnpm|bun)\s+run\s+build/i, name: "Build", icon: "\u{1F528}" },
7663
- // Framework-specific patterns
7664
- { regex: /nuxt\s+dev/i, name: "Nuxt", icon: "\u26A1" },
7665
- { regex: /next\s+dev/i, name: "Next.js", icon: "\u25B2" },
7666
- { regex: /vite($|\s)/i, name: "Vite", icon: "\u26A1" },
7667
- { regex: /svelte-kit\s+dev|svelte\s+dev/i, name: "Svelte", icon: "\u{1F525}" },
7668
- { regex: /astro\s+dev/i, name: "Astro", icon: "\u{1F680}" },
7669
- { regex: /remix\s+dev|remix\s+watch/i, name: "Remix", icon: "\u{1F4BF}" }
7670
- ];
7773
+ portDetector;
7774
+ processDetector;
7671
7775
  constructor(colors2) {
7672
7776
  this.colors = colors2 ?? DEFAULT_THEME;
7777
+ this.portDetector = new PortDetector();
7778
+ this.processDetector = new ProcessDetector();
7673
7779
  }
7674
7780
  /**
7675
7781
  * Set display style
@@ -7738,35 +7844,30 @@ var DevServerWidget = class {
7738
7844
  return this.styleFn(renderData, this.colors.devServer);
7739
7845
  }
7740
7846
  /**
7741
- * 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
+ *
7742
7852
  * @returns Detected server status or null
7743
7853
  */
7744
7854
  async detectDevServer() {
7745
- try {
7746
- const { stdout } = await execFileAsync2("ps", ["aux"], {
7747
- timeout: 1e3
7748
- });
7749
- for (const pattern of this.processPatterns) {
7750
- if (pattern.regex.test(stdout)) {
7751
- const isBuilding = pattern.name.toLowerCase().includes("build");
7752
- const isRunning = !isBuilding;
7753
- return {
7754
- name: pattern.name,
7755
- icon: pattern.icon,
7756
- isRunning,
7757
- isBuilding
7758
- };
7759
- }
7760
- }
7761
- } 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
+ };
7762
7863
  }
7763
- return null;
7864
+ return await this.processDetector.detect();
7764
7865
  }
7765
7866
  };
7766
7867
 
7767
7868
  // src/widgets/docker/docker-widget.ts
7768
- var import_node_child_process3 = require("node:child_process");
7769
- 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");
7770
7871
  init_widget_types();
7771
7872
  init_theme();
7772
7873
 
@@ -7833,7 +7934,7 @@ var dockerStyles = {
7833
7934
  };
7834
7935
 
7835
7936
  // src/widgets/docker/docker-widget.ts
7836
- 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);
7837
7938
  var DockerWidget = class {
7838
7939
  id = "docker";
7839
7940
  metadata = createWidgetMetadata(
@@ -7893,12 +7994,12 @@ var DockerWidget = class {
7893
7994
  }
7894
7995
  async getDockerStatus() {
7895
7996
  try {
7896
- await execFileAsync3("docker", ["info"], { timeout: 2e3 });
7897
- const { stdout: runningOutput } = await execFileAsync3("docker", ["ps", "-q"], {
7997
+ await execFileAsync4("docker", ["info"], { timeout: 2e3 });
7998
+ const { stdout: runningOutput } = await execFileAsync4("docker", ["ps", "-q"], {
7898
7999
  timeout: 1e3
7899
8000
  });
7900
8001
  const running = runningOutput.trim().split("\n").filter((line) => line).length;
7901
- const { stdout: allOutput } = await execFileAsync3("docker", ["ps", "-aq"], {
8002
+ const { stdout: allOutput } = await execFileAsync4("docker", ["ps", "-aq"], {
7902
8003
  timeout: 1e3
7903
8004
  });
7904
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.12",
3
+ "version": "0.8.14",
4
4
  "description": "Claude Code plugin for session status and analytics",
5
5
  "license": "MIT",
6
6
  "type": "module",