coding-usage-bar 0.2.1 → 0.2.2

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/dist/doctor.js CHANGED
@@ -7,7 +7,7 @@ import { isDir, isFile } from "./fs-util.js";
7
7
  import { resolveKimiConfig } from "./kimi.js";
8
8
  import { buildPaths, providerLatestPath } from "./paths.js";
9
9
  import { notificationBackend } from "./notifier.js";
10
- import { isSwiftBarInstalled, swiftBarPluginPath } from "./menubar.js";
10
+ import { isSwiftBarInstalled, isSwiftBarRunning, swiftBarPluginPath } from "./menubar.js";
11
11
  function stableClaudeIngestHint() {
12
12
  const paths = buildPaths();
13
13
  return `printf "%s" "$input" | node "${paths.stateDir}/app/dist/cli.js" ingest claude-statusline >/dev/null`;
@@ -236,12 +236,16 @@ export function runDoctor(options = {}) {
236
236
  });
237
237
  const swiftBarInstalled = isSwiftBarInstalled();
238
238
  const swiftBarPlugin = swiftBarPluginPath(paths);
239
+ const pluginPresent = swiftBarInstalled && isFile(swiftBarPlugin.file);
240
+ const swiftBarRunning = pluginPresent && isSwiftBarRunning();
239
241
  checks.push({
240
242
  name: "Menu bar",
241
- ok: swiftBarInstalled && isFile(swiftBarPlugin.file),
243
+ ok: pluginPresent,
242
244
  message: swiftBarInstalled
243
245
  ? isFile(swiftBarPlugin.file)
244
- ? `SwiftBar plugin installed: ${swiftBarPlugin.file}`
246
+ ? swiftBarRunning
247
+ ? `SwiftBar plugin installed and SwiftBar running: ${swiftBarPlugin.file}`
248
+ : `SwiftBar plugin installed but SwiftBar is not running (menu bar item hidden); run: open -a SwiftBar`
245
249
  : `SwiftBar found; run coding-usage-bar menubar install`
246
250
  : "SwiftBar not found; install SwiftBar, then run coding-usage-bar menubar install",
247
251
  });
package/dist/menubar.d.ts CHANGED
@@ -9,6 +9,7 @@ export declare function isSwiftBarInstalled(): boolean;
9
9
  export declare function ensureSwiftBarInstalled(options?: {
10
10
  dryRun?: boolean;
11
11
  }): string[];
12
+ export declare function isSwiftBarRunning(): boolean;
12
13
  export declare function openSwiftBar(): string[];
13
14
  export declare function addSwiftBarToLoginItems(options?: {
14
15
  dryRun?: boolean;
package/dist/menubar.js CHANGED
@@ -333,25 +333,69 @@ export function ensureSwiftBarInstalled(options = {}) {
333
333
  });
334
334
  return ["Installed SwiftBar with Homebrew cask."];
335
335
  }
336
+ export function isSwiftBarRunning() {
337
+ try {
338
+ execFileSync("pgrep", ["-x", "SwiftBar"], { stdio: "ignore" });
339
+ return true;
340
+ }
341
+ catch {
342
+ return false;
343
+ }
344
+ }
345
+ // Poll until SwiftBar reaches the desired running state, or the timeout elapses.
346
+ // Synchronous on purpose: openSwiftBar runs inside the synchronous installer flow.
347
+ function waitForSwiftBar(wantRunning, timeoutMs) {
348
+ const deadline = Date.now() + timeoutMs;
349
+ while (Date.now() < deadline) {
350
+ if (isSwiftBarRunning() === wantRunning) {
351
+ return true;
352
+ }
353
+ try {
354
+ execFileSync("sleep", ["0.2"], { stdio: "ignore" });
355
+ }
356
+ catch {
357
+ // sleep should not fail; fall through to re-check.
358
+ }
359
+ }
360
+ return isSwiftBarRunning() === wantRunning;
361
+ }
336
362
  export function openSwiftBar() {
337
363
  const appPath = swiftBarAppPath();
338
364
  if (!appPath) {
339
365
  return ["SwiftBar is not installed; skipping launch."];
340
366
  }
341
- try {
342
- execFileSync("osascript", ["-e", 'quit app "SwiftBar"'], { stdio: "ignore" });
343
- }
344
- catch {
345
- // SwiftBar may not be running yet.
367
+ const messages = [];
368
+ // 1. Quit and wait until the old instance is actually gone. `quit app` is
369
+ // async; launching again before it finishes terminating can coalesce into
370
+ // a no-op, and the visibility cleanup below only sticks while SwiftBar is
371
+ // not running (cfprefsd lets a live SwiftBar rewrite the keys on quit).
372
+ if (isSwiftBarRunning()) {
373
+ try {
374
+ execFileSync("osascript", ["-e", 'quit app "SwiftBar"'], { stdio: "ignore" });
375
+ }
376
+ catch {
377
+ // Ignore; the wait below reports the real state.
378
+ }
379
+ waitForSwiftBar(false, 5000);
346
380
  }
381
+ // 2. Clear any stale "hidden" status-item cache while SwiftBar is stopped so
382
+ // the change survives the next launch instead of being clobbered.
383
+ messages.push(...clearSwiftBarStatusItemVisibility());
384
+ // 3. Launch and verify the process actually comes up before claiming success.
347
385
  try {
348
386
  execFileSync("open", [appPath], { stdio: "ignore" });
349
- execFileSync("sleep", ["1"], { stdio: "ignore" });
350
- return ["Opened SwiftBar.", ...clearSwiftBarStatusItemVisibility()];
351
387
  }
352
388
  catch (error) {
353
- return [`SwiftBar installed, but launch failed: ${error instanceof Error ? error.message : String(error)}`];
389
+ messages.push(`SwiftBar installed, but launch failed: ${error instanceof Error ? error.message : String(error)}`);
390
+ return messages;
391
+ }
392
+ if (waitForSwiftBar(true, 8000)) {
393
+ messages.push("Opened SwiftBar.");
394
+ }
395
+ else {
396
+ messages.push("Launched SwiftBar, but it did not start within 8s. Open SwiftBar manually; if macOS prompts for Automation/Accessibility permission, allow it.");
354
397
  }
398
+ return messages;
355
399
  }
356
400
  export function addSwiftBarToLoginItems(options = {}) {
357
401
  const dryRun = options.dryRun ?? false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coding-usage-bar",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "macOS menu bar usage monitor for Claude Code, Codex, GLM, DeepSeek, and MiniMax.",
5
5
  "author": "hanzhangzzz",
6
6
  "license": "MIT",