chat-heimerdinger 0.1.4 → 0.1.6

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/cli.js CHANGED
@@ -118151,15 +118151,40 @@ var logsCommand = new Command("logs").description("View service logs").option("-
118151
118151
  import { existsSync as existsSync4 } from "node:fs";
118152
118152
 
118153
118153
  // src/services/claude-code.ts
118154
- import { spawn as spawn2 } from "node:child_process";
118154
+ import { execSync, spawn as spawn2 } from "node:child_process";
118155
118155
  import { existsSync as existsSync3, readFileSync as readFileSync3, readdirSync } from "node:fs";
118156
118156
  import { basename, join as join2 } from "node:path";
118157
118157
  class ClaudeCodeService {
118158
118158
  claudeConfigPath;
118159
118159
  projectsDir;
118160
+ claudeBinaryPath;
118160
118161
  constructor(claudeConfigPath = CLAUDE_CONFIG_FILE) {
118161
118162
  this.claudeConfigPath = claudeConfigPath;
118162
118163
  this.projectsDir = CLAUDE_PROJECTS_DIR;
118164
+ this.claudeBinaryPath = this.findClaudeBinary();
118165
+ }
118166
+ findClaudeBinary() {
118167
+ try {
118168
+ const path = execSync("which claude", { encoding: "utf-8" }).trim();
118169
+ if (path && existsSync3(path)) {
118170
+ consola.debug("Found claude binary at:", path);
118171
+ return path;
118172
+ }
118173
+ } catch {}
118174
+ const commonPaths = [
118175
+ "/usr/local/bin/claude",
118176
+ "/usr/bin/claude",
118177
+ `${process.env.HOME}/.local/bin/claude`,
118178
+ `${process.env.HOME}/.nvm/versions/node/${process.version}/bin/claude`
118179
+ ];
118180
+ for (const p2 of commonPaths) {
118181
+ if (existsSync3(p2)) {
118182
+ consola.debug("Found claude binary at:", p2);
118183
+ return p2;
118184
+ }
118185
+ }
118186
+ consola.warn('Could not find claude binary, using "claude" and relying on PATH');
118187
+ return "claude";
118163
118188
  }
118164
118189
  async isAvailable() {
118165
118190
  return existsSync3(this.claudeConfigPath);
@@ -118248,7 +118273,8 @@ class ClaudeCodeService {
118248
118273
  }
118249
118274
  args.push(prompt2);
118250
118275
  consola.debug("Spawning claude with args:", args.join(" "));
118251
- const proc = spawn2("claude", args, {
118276
+ consola.debug("Using claude binary:", this.claudeBinaryPath);
118277
+ const proc = spawn2(this.claudeBinaryPath, args, {
118252
118278
  cwd: projectDir,
118253
118279
  stdio: ["ignore", "pipe", "pipe"],
118254
118280
  env: { ...process.env },
@@ -118324,7 +118350,7 @@ class ClaudeCodeService {
118324
118350
  const path = encodedPath.replace(/^-/, "");
118325
118351
  const parts = path.split("-");
118326
118352
  const result = this.findValidPath("", parts, 0);
118327
- return result || "/" + path.replace(/-/g, "/");
118353
+ return result || `/${path.replace(/-/g, "/")}`;
118328
118354
  }
118329
118355
  findValidPath(current, parts, index) {
118330
118356
  if (index >= parts.length) {
@@ -118332,7 +118358,7 @@ class ClaudeCodeService {
118332
118358
  }
118333
118359
  for (let i2 = index;i2 < parts.length; i2++) {
118334
118360
  const segment = parts.slice(index, i2 + 1).join("-");
118335
- const newPath = current + "/" + segment;
118361
+ const newPath = `${current}/${segment}`;
118336
118362
  if (i2 === parts.length - 1) {
118337
118363
  if (existsSync3(newPath)) {
118338
118364
  return newPath;
@@ -118513,7 +118539,7 @@ import { spawnSync } from "node:child_process";
118513
118539
  import { dirname as dirname3, join as join5 } from "node:path";
118514
118540
 
118515
118541
  // src/services/service-manager.ts
118516
- import { spawn as spawn4 } from "node:child_process";
118542
+ import { execSync as execSync3, spawn as spawn4 } from "node:child_process";
118517
118543
  import { existsSync as existsSync8, mkdirSync as mkdirSync3, readFileSync as readFileSync5, unlinkSync as unlinkSync3, writeFileSync as writeFileSync5 } from "node:fs";
118518
118544
  import { dirname as dirname2, join as join4 } from "node:path";
118519
118545
 
@@ -119609,25 +119635,59 @@ class SlackAdapter {
119609
119635
  import { existsSync as existsSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "node:fs";
119610
119636
 
119611
119637
  // src/services/whisper.ts
119612
- import { spawn as spawn3 } from "node:child_process";
119638
+ import { execSync as execSync2, spawn as spawn3 } from "node:child_process";
119613
119639
  import { existsSync as existsSync5, mkdirSync as mkdirSync2, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
119614
119640
  import { tmpdir } from "node:os";
119615
119641
  import { join as join3 } from "node:path";
119616
119642
  var WHISPER_MODEL_PATH = join3(process.env.HOME || "/home/dev", ".local/share/whisper/ggml-small.bin");
119617
- var WHISPER_CLI = "whisper-cli";
119618
119643
 
119619
119644
  class WhisperService {
119620
119645
  modelPath;
119646
+ whisperBinaryPath;
119647
+ ffmpegBinaryPath;
119621
119648
  constructor(modelPath = WHISPER_MODEL_PATH) {
119622
119649
  this.modelPath = modelPath;
119650
+ consola.debug(`WhisperService init: HOME=${process.env.HOME}, modelPath=${this.modelPath}`);
119651
+ this.whisperBinaryPath = this.findBinary("whisper-cli", [
119652
+ "/usr/local/bin/whisper-cli",
119653
+ "/usr/bin/whisper-cli",
119654
+ `${process.env.HOME}/.local/bin/whisper-cli`
119655
+ ]);
119656
+ this.ffmpegBinaryPath = this.findBinary("ffmpeg", [
119657
+ "/usr/bin/ffmpeg",
119658
+ "/usr/local/bin/ffmpeg"
119659
+ ]);
119660
+ }
119661
+ findBinary(name, commonPaths) {
119662
+ try {
119663
+ const path = execSync2(`which ${name}`, { encoding: "utf-8" }).trim();
119664
+ if (path && existsSync5(path)) {
119665
+ consola.debug(`Found ${name} at:`, path);
119666
+ return path;
119667
+ }
119668
+ } catch {}
119669
+ for (const p2 of commonPaths) {
119670
+ if (existsSync5(p2)) {
119671
+ consola.debug(`Found ${name} at:`, p2);
119672
+ return p2;
119673
+ }
119674
+ }
119675
+ consola.warn(`Could not find ${name} binary`);
119676
+ return name;
119623
119677
  }
119624
119678
  async isAvailable() {
119679
+ consola.debug(`Checking whisper availability: model=${this.modelPath}, binary=${this.whisperBinaryPath}`);
119625
119680
  if (!existsSync5(this.modelPath)) {
119626
119681
  consola.warn(`Whisper model not found at ${this.modelPath}`);
119627
119682
  return false;
119628
119683
  }
119684
+ if (this.whisperBinaryPath.startsWith("/")) {
119685
+ const exists = existsSync5(this.whisperBinaryPath);
119686
+ consola.debug(`Whisper binary exists: ${exists}`);
119687
+ return exists;
119688
+ }
119629
119689
  return new Promise((resolve) => {
119630
- const proc = spawn3(WHISPER_CLI, ["-h"], { stdio: "ignore" });
119690
+ const proc = spawn3(this.whisperBinaryPath, ["-h"], { stdio: "ignore" });
119631
119691
  proc.on("close", (code) => resolve(code === 0));
119632
119692
  proc.on("error", () => resolve(false));
119633
119693
  });
@@ -119667,7 +119727,7 @@ class WhisperService {
119667
119727
  "-y",
119668
119728
  outputFile
119669
119729
  ];
119670
- const proc = spawn3("ffmpeg", args, { stdio: ["ignore", "pipe", "pipe"] });
119730
+ const proc = spawn3(this.ffmpegBinaryPath, args, { stdio: ["ignore", "pipe", "pipe"] });
119671
119731
  let stderr = "";
119672
119732
  proc.stderr.on("data", (data) => {
119673
119733
  stderr += data.toString();
@@ -119696,8 +119756,8 @@ class WhisperService {
119696
119756
  "-f",
119697
119757
  wavFile
119698
119758
  ];
119699
- consola.debug(`Running whisper: ${WHISPER_CLI} ${args.join(" ")}`);
119700
- const proc = spawn3(WHISPER_CLI, args, { stdio: ["ignore", "pipe", "pipe"] });
119759
+ consola.debug(`Running whisper: ${this.whisperBinaryPath} ${args.join(" ")}`);
119760
+ const proc = spawn3(this.whisperBinaryPath, args, { stdio: ["ignore", "pipe", "pipe"] });
119701
119761
  let stdout2 = "";
119702
119762
  let stderr = "";
119703
119763
  proc.stdout.on("data", (data) => {
@@ -120873,6 +120933,7 @@ Shutting down...`);
120873
120933
  await server.start();
120874
120934
  }
120875
120935
  async startDaemon() {
120936
+ await this.killOrphanedProcesses();
120876
120937
  if (!existsSync8(LOG_DIR)) {
120877
120938
  mkdirSync3(LOG_DIR, { recursive: true });
120878
120939
  }
@@ -120900,27 +120961,40 @@ Shutting down...`);
120900
120961
  }
120901
120962
  async stop() {
120902
120963
  const pid = await this.getPid();
120903
- if (!pid)
120964
+ if (!pid) {
120965
+ await this.killOrphanedProcesses();
120904
120966
  return;
120967
+ }
120905
120968
  process.kill(pid, "SIGTERM");
120906
- const maxWait = 1e4;
120969
+ const maxWait = 5000;
120907
120970
  const interval = 100;
120908
120971
  let waited = 0;
120909
120972
  while (waited < maxWait) {
120910
120973
  await new Promise((resolve) => setTimeout(resolve, interval));
120911
120974
  waited += interval;
120912
120975
  if (!await this.isRunning()) {
120976
+ await this.killOrphanedProcesses();
120913
120977
  return;
120914
120978
  }
120915
120979
  }
120916
- throw new Error("Service did not stop gracefully. Use --force to kill.");
120980
+ consola.warn("Graceful shutdown timed out, forcing stop...");
120981
+ await this.forceStop();
120917
120982
  }
120918
120983
  async forceStop() {
120919
120984
  const pid = await this.getPid();
120920
- if (!pid)
120921
- return;
120922
- process.kill(pid, "SIGKILL");
120985
+ if (pid) {
120986
+ try {
120987
+ process.kill(pid, "SIGKILL");
120988
+ } catch {}
120989
+ }
120923
120990
  await this.removePidFile();
120991
+ await this.killOrphanedProcesses();
120992
+ }
120993
+ async killOrphanedProcesses() {
120994
+ try {
120995
+ execSync3('pkill -f "node.*daemon-entry\\.js" 2>/dev/null || true', { encoding: "utf-8" });
120996
+ execSync3('pkill -f "tsx.*daemon-entry" 2>/dev/null || true', { encoding: "utf-8" });
120997
+ } catch {}
120924
120998
  }
120925
120999
  async writePidFile(pid) {
120926
121000
  const dir = dirname2(this.pidFile);
@@ -116093,15 +116093,40 @@ class SlackAdapter {
116093
116093
  import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "node:fs";
116094
116094
 
116095
116095
  // src/services/claude-code.ts
116096
- import { spawn } from "node:child_process";
116096
+ import { execSync, spawn } from "node:child_process";
116097
116097
  import { existsSync as existsSync2, readFileSync as readFileSync2, readdirSync } from "node:fs";
116098
116098
  import { basename, join as join2 } from "node:path";
116099
116099
  class ClaudeCodeService {
116100
116100
  claudeConfigPath;
116101
116101
  projectsDir;
116102
+ claudeBinaryPath;
116102
116103
  constructor(claudeConfigPath = CLAUDE_CONFIG_FILE) {
116103
116104
  this.claudeConfigPath = claudeConfigPath;
116104
116105
  this.projectsDir = CLAUDE_PROJECTS_DIR;
116106
+ this.claudeBinaryPath = this.findClaudeBinary();
116107
+ }
116108
+ findClaudeBinary() {
116109
+ try {
116110
+ const path = execSync("which claude", { encoding: "utf-8" }).trim();
116111
+ if (path && existsSync2(path)) {
116112
+ consola.debug("Found claude binary at:", path);
116113
+ return path;
116114
+ }
116115
+ } catch {}
116116
+ const commonPaths = [
116117
+ "/usr/local/bin/claude",
116118
+ "/usr/bin/claude",
116119
+ `${process.env.HOME}/.local/bin/claude`,
116120
+ `${process.env.HOME}/.nvm/versions/node/${process.version}/bin/claude`
116121
+ ];
116122
+ for (const p of commonPaths) {
116123
+ if (existsSync2(p)) {
116124
+ consola.debug("Found claude binary at:", p);
116125
+ return p;
116126
+ }
116127
+ }
116128
+ consola.warn('Could not find claude binary, using "claude" and relying on PATH');
116129
+ return "claude";
116105
116130
  }
116106
116131
  async isAvailable() {
116107
116132
  return existsSync2(this.claudeConfigPath);
@@ -116190,7 +116215,8 @@ class ClaudeCodeService {
116190
116215
  }
116191
116216
  args.push(prompt2);
116192
116217
  consola.debug("Spawning claude with args:", args.join(" "));
116193
- const proc = spawn("claude", args, {
116218
+ consola.debug("Using claude binary:", this.claudeBinaryPath);
116219
+ const proc = spawn(this.claudeBinaryPath, args, {
116194
116220
  cwd: projectDir,
116195
116221
  stdio: ["ignore", "pipe", "pipe"],
116196
116222
  env: { ...process.env },
@@ -116266,7 +116292,7 @@ class ClaudeCodeService {
116266
116292
  const path = encodedPath.replace(/^-/, "");
116267
116293
  const parts = path.split("-");
116268
116294
  const result = this.findValidPath("", parts, 0);
116269
- return result || "/" + path.replace(/-/g, "/");
116295
+ return result || `/${path.replace(/-/g, "/")}`;
116270
116296
  }
116271
116297
  findValidPath(current, parts, index) {
116272
116298
  if (index >= parts.length) {
@@ -116274,7 +116300,7 @@ class ClaudeCodeService {
116274
116300
  }
116275
116301
  for (let i2 = index;i2 < parts.length; i2++) {
116276
116302
  const segment = parts.slice(index, i2 + 1).join("-");
116277
- const newPath = current + "/" + segment;
116303
+ const newPath = `${current}/${segment}`;
116278
116304
  if (i2 === parts.length - 1) {
116279
116305
  if (existsSync2(newPath)) {
116280
116306
  return newPath;
@@ -116347,25 +116373,59 @@ class ClaudeCodeService {
116347
116373
  }
116348
116374
 
116349
116375
  // src/services/whisper.ts
116350
- import { spawn as spawn2 } from "node:child_process";
116376
+ import { execSync as execSync2, spawn as spawn2 } from "node:child_process";
116351
116377
  import { existsSync as existsSync3, mkdirSync as mkdirSync2, unlinkSync, writeFileSync as writeFileSync2 } from "node:fs";
116352
116378
  import { tmpdir } from "node:os";
116353
116379
  import { join as join3 } from "node:path";
116354
116380
  var WHISPER_MODEL_PATH = join3(process.env.HOME || "/home/dev", ".local/share/whisper/ggml-small.bin");
116355
- var WHISPER_CLI = "whisper-cli";
116356
116381
 
116357
116382
  class WhisperService {
116358
116383
  modelPath;
116384
+ whisperBinaryPath;
116385
+ ffmpegBinaryPath;
116359
116386
  constructor(modelPath = WHISPER_MODEL_PATH) {
116360
116387
  this.modelPath = modelPath;
116388
+ consola.debug(`WhisperService init: HOME=${process.env.HOME}, modelPath=${this.modelPath}`);
116389
+ this.whisperBinaryPath = this.findBinary("whisper-cli", [
116390
+ "/usr/local/bin/whisper-cli",
116391
+ "/usr/bin/whisper-cli",
116392
+ `${process.env.HOME}/.local/bin/whisper-cli`
116393
+ ]);
116394
+ this.ffmpegBinaryPath = this.findBinary("ffmpeg", [
116395
+ "/usr/bin/ffmpeg",
116396
+ "/usr/local/bin/ffmpeg"
116397
+ ]);
116398
+ }
116399
+ findBinary(name, commonPaths) {
116400
+ try {
116401
+ const path = execSync2(`which ${name}`, { encoding: "utf-8" }).trim();
116402
+ if (path && existsSync3(path)) {
116403
+ consola.debug(`Found ${name} at:`, path);
116404
+ return path;
116405
+ }
116406
+ } catch {}
116407
+ for (const p of commonPaths) {
116408
+ if (existsSync3(p)) {
116409
+ consola.debug(`Found ${name} at:`, p);
116410
+ return p;
116411
+ }
116412
+ }
116413
+ consola.warn(`Could not find ${name} binary`);
116414
+ return name;
116361
116415
  }
116362
116416
  async isAvailable() {
116417
+ consola.debug(`Checking whisper availability: model=${this.modelPath}, binary=${this.whisperBinaryPath}`);
116363
116418
  if (!existsSync3(this.modelPath)) {
116364
116419
  consola.warn(`Whisper model not found at ${this.modelPath}`);
116365
116420
  return false;
116366
116421
  }
116422
+ if (this.whisperBinaryPath.startsWith("/")) {
116423
+ const exists = existsSync3(this.whisperBinaryPath);
116424
+ consola.debug(`Whisper binary exists: ${exists}`);
116425
+ return exists;
116426
+ }
116367
116427
  return new Promise((resolve) => {
116368
- const proc = spawn2(WHISPER_CLI, ["-h"], { stdio: "ignore" });
116428
+ const proc = spawn2(this.whisperBinaryPath, ["-h"], { stdio: "ignore" });
116369
116429
  proc.on("close", (code) => resolve(code === 0));
116370
116430
  proc.on("error", () => resolve(false));
116371
116431
  });
@@ -116405,7 +116465,7 @@ class WhisperService {
116405
116465
  "-y",
116406
116466
  outputFile
116407
116467
  ];
116408
- const proc = spawn2("ffmpeg", args, { stdio: ["ignore", "pipe", "pipe"] });
116468
+ const proc = spawn2(this.ffmpegBinaryPath, args, { stdio: ["ignore", "pipe", "pipe"] });
116409
116469
  let stderr = "";
116410
116470
  proc.stderr.on("data", (data) => {
116411
116471
  stderr += data.toString();
@@ -116434,8 +116494,8 @@ class WhisperService {
116434
116494
  "-f",
116435
116495
  wavFile
116436
116496
  ];
116437
- consola.debug(`Running whisper: ${WHISPER_CLI} ${args.join(" ")}`);
116438
- const proc = spawn2(WHISPER_CLI, args, { stdio: ["ignore", "pipe", "pipe"] });
116497
+ consola.debug(`Running whisper: ${this.whisperBinaryPath} ${args.join(" ")}`);
116498
+ const proc = spawn2(this.whisperBinaryPath, args, { stdio: ["ignore", "pipe", "pipe"] });
116439
116499
  let stdout2 = "";
116440
116500
  let stderr = "";
116441
116501
  proc.stdout.on("data", (data) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chat-heimerdinger",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Bridge IM tools (Slack/Lark) with Claude Code for vibe coding",
5
5
  "type": "module",
6
6
  "bin": {
@@ -19,7 +19,8 @@
19
19
  "lint": "biome check .",
20
20
  "lint:fix": "biome check . --write",
21
21
  "format": "biome format . --write",
22
- "prepublishOnly": "npm run build"
22
+ "prepublishOnly": "npm run build",
23
+ "release": "npm version patch && npm publish --registry https://registry.npmjs.org --access public"
23
24
  },
24
25
  "dependencies": {
25
26
  "@clack/prompts": "^0.9.1",