claude-code-hub 1.27.1 → 1.27.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.
@@ -23,10 +23,10 @@
23
23
  "tags": ["voice", "experimental"],
24
24
  "screenshots": [
25
25
  {
26
- "url": "https://nikiforovall.blog/claude-code-hub/shots/extensions/voice-live-new-session.webp",
27
- "alt": "Kanban's New session dialog opened by voice while the user still speaks: the Prompt field shows \"Fix the flaky login test and then run the\" and a Listening pill sits at the bottom of the hub window",
26
+ "url": "https://nikiforovall.blog/claude-code-hub/shots/extensions/voice-demo.webp",
27
+ "alt": "Animation: the user holds Ctrl+Shift+Space and says \"Hub, add a task, fix the login page redirect\". Kanban's Add task dialog fills as they speak, and Enter adds the task to the board. Then \"Hub, new session, fix the flaky login test and run the suite\" opens the New session dialog with that prompt",
28
28
  "title": "Words show up as you speak",
29
- "caption": "\"New session\" opens the dialog at once, and the rest of what you say fills the Prompt field.",
29
+ "caption": "\"Hub, add a task\" fills the Add task dialog, and \"Hub, new session\" opens New session with the rest as the prompt.",
30
30
  "card": true
31
31
  },
32
32
  {
@@ -4,6 +4,7 @@
4
4
  // partial text back. The bearer token and the stream's owner token stay in the hub.
5
5
  const fs = require('node:fs');
6
6
  const path = require('node:path');
7
+ const { hexDir } = require('./hex');
7
8
 
8
9
  const SAMPLE_RATE = 16000;
9
10
  // Hex drops a stream whose lease (10 s) runs out with no call.
@@ -20,7 +21,7 @@ function readApi(file) {
20
21
 
21
22
  const failOf = (r) => ({ ok: false, error: r.json.error || `Hex answered ${r.status}` });
22
23
 
23
- function createHexStream({ apiFile = path.join(process.env.APPDATA || '', 'hex', 'local-api.json'), fetchImpl = fetch } = {}) {
24
+ function createHexStream({ apiFile = path.join(hexDir(), 'local-api.json'), fetchImpl = fetch } = {}) {
24
25
  let live = null;
25
26
 
26
27
  async function call(method, url, { headers = {}, body, signal } = {}) {
package/lib/voice/hex.js CHANGED
@@ -2,21 +2,38 @@
2
2
 
3
3
  // Speech provider: the Hex app's CLI (https://github.com/anomalyco/hex).
4
4
  const fs = require('node:fs');
5
+ const os = require('node:os');
5
6
  const path = require('node:path');
6
7
  const { spawn } = require('node:child_process');
7
8
 
8
- // Hex keeps one folder per version and names the current one in current-version.
9
- function hexExe(root = path.join(process.env.APPDATA || '', 'hex')) {
10
- if (process.env.HEX_EXE) return process.env.HEX_EXE;
9
+ // Hex's data folder, as Hex's app_paths::support_dir resolves it (Rust dirs::data_dir). It holds
10
+ // local-api.json on every OS.
11
+ function hexDir({ env = process.env, platform = process.platform, home = os.homedir() } = {}) {
12
+ if (env.HEX_APPLICATION_SUPPORT_DIR) return env.HEX_APPLICATION_SUPPORT_DIR;
13
+ if (platform === 'win32') return path.join(env.APPDATA || path.join(home, 'AppData', 'Roaming'), 'hex');
14
+ if (platform === 'darwin') return path.join(home, 'Library', 'Application Support', 'hex');
15
+ return path.join(env.XDG_DATA_HOME || path.join(home, '.local', 'share'), 'hex');
16
+ }
17
+
18
+ // Where Hex's installers put the CLI: Windows keeps one folder per version and names the current one
19
+ // in current-version, Linux links `current` to it, and macOS has it inside Hex.app.
20
+ function hexCandidates({ platform, home, dir }) {
21
+ if (platform === 'darwin') return ['/Applications', path.join(home, 'Applications')].map((d) => path.join(d, 'Hex.app', 'Contents', 'MacOS', 'hex'));
22
+ if (platform !== 'win32') return [path.join(dir, 'current', 'hex')];
11
23
  try {
12
- const v = fs.readFileSync(path.join(root, 'current-version'), 'utf8').trim();
13
- const exe = path.join(root, 'versions', v, process.platform === 'win32' ? 'hex.exe' : 'hex');
14
- return fs.existsSync(exe) ? exe : null;
24
+ const v = fs.readFileSync(path.join(dir, 'current-version'), 'utf8').trim();
25
+ return [path.join(dir, 'versions', v, 'hex.exe')];
15
26
  } catch {
16
- return null;
27
+ return [];
17
28
  }
18
29
  }
19
30
 
31
+ function hexExe({ env = process.env, platform = process.platform, home = os.homedir() } = {}) {
32
+ if (env.HEX_EXE) return env.HEX_EXE;
33
+ const dir = hexDir({ env, platform, home });
34
+ return hexCandidates({ platform, home, dir }).find((f) => fs.existsSync(f)) ?? null;
35
+ }
36
+
20
37
  function run(cmd, args, timeoutMs) {
21
38
  return new Promise((resolve) => {
22
39
  const p = spawn(cmd, args, { windowsHide: true });
@@ -50,4 +67,4 @@ function createHex({ exe = hexExe() } = {}) {
50
67
  return { start: () => call('start'), stop: () => call('stop'), cancel: () => call('cancel') };
51
68
  }
52
69
 
53
- module.exports = { createHex, hexExe };
70
+ module.exports = { createHex, hexDir, hexExe };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-code-hub",
3
- "version": "1.27.1",
3
+ "version": "1.27.2",
4
4
  "description": "Unified hub for Claude Code tools — Marketplace + Kanban in one PWA",
5
5
  "main": "server.js",
6
6
  "bin": {