@botcord/daemon 0.2.82 → 0.2.83

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.
@@ -1,5 +1,6 @@
1
1
  import { execFileSync } from "node:child_process";
2
- import { existsSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
2
+ import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
3
+ import path from "node:path";
3
4
  import { PID_PATH } from "./config.js";
4
5
  const noopLogger = {
5
6
  info() {
@@ -137,7 +138,17 @@ export function ensureNoOtherDaemonFromPidFile(opts = {}) {
137
138
  return null;
138
139
  }
139
140
  export function writeCurrentPid(opts = {}) {
140
- writeFileSync(opts.pidPath ?? PID_PATH, String(opts.currentPid ?? process.pid), { mode: 0o600 });
141
+ const pidPath = opts.pidPath ?? PID_PATH;
142
+ // Cloud-mode startup writes the PID file before `saveConfig` runs, so
143
+ // the daemon dir may not exist yet. mkdir its parent (0700) so the
144
+ // first write doesn't crash with ENOENT.
145
+ try {
146
+ mkdirSync(path.dirname(pidPath), { recursive: true, mode: 0o700 });
147
+ }
148
+ catch {
149
+ // best-effort — writeFileSync below will surface the real error
150
+ }
151
+ writeFileSync(pidPath, String(opts.currentPid ?? process.pid), { mode: 0o600 });
141
152
  }
142
153
  export function removePidFile(pidPath = PID_PATH) {
143
154
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botcord/daemon",
3
- "version": "0.2.82",
3
+ "version": "0.2.83",
4
4
  "description": "BotCord local daemon — bridges Hub inbox push to local Claude Code / Codex / Gemini CLIs",
5
5
  "type": "module",
6
6
  "bin": {
@@ -45,6 +45,17 @@ describe("daemon singleton pid helpers", () => {
45
45
  expect(readFileSync(pidPath, "utf8")).toBe("12345");
46
46
  });
47
47
 
48
+ it("creates the parent directory if missing (cloud-mode first boot)", () => {
49
+ // Cloud-mode start writes the PID file before `saveConfig` runs, so
50
+ // ~/.botcord/daemon/ may not exist yet. Without the mkdir the daemon
51
+ // crashes immediately with ENOENT.
52
+ const pidPath = path.join(tmpDir, "fresh-cloud-home", "daemon", "daemon.pid");
53
+
54
+ writeCurrentPid({ pidPath, currentPid: 7890 });
55
+
56
+ expect(readPid(pidPath)).toBe(7890);
57
+ });
58
+
48
59
  it("does not report the current process as another daemon", () => {
49
60
  const pidPath = path.join(tmpDir, "daemon.pid");
50
61
  writeCurrentPid({ pidPath, currentPid: process.pid });
@@ -1,5 +1,6 @@
1
1
  import { execFileSync } from "node:child_process";
2
- import { existsSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
2
+ import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
3
+ import path from "node:path";
3
4
  import { PID_PATH } from "./config.js";
4
5
 
5
6
  export interface SingletonLogger {
@@ -182,7 +183,16 @@ export function writeCurrentPid(
182
183
  currentPid?: number;
183
184
  } = {},
184
185
  ): void {
185
- writeFileSync(opts.pidPath ?? PID_PATH, String(opts.currentPid ?? process.pid), { mode: 0o600 });
186
+ const pidPath = opts.pidPath ?? PID_PATH;
187
+ // Cloud-mode startup writes the PID file before `saveConfig` runs, so
188
+ // the daemon dir may not exist yet. mkdir its parent (0700) so the
189
+ // first write doesn't crash with ENOENT.
190
+ try {
191
+ mkdirSync(path.dirname(pidPath), { recursive: true, mode: 0o700 });
192
+ } catch {
193
+ // best-effort — writeFileSync below will surface the real error
194
+ }
195
+ writeFileSync(pidPath, String(opts.currentPid ?? process.pid), { mode: 0o600 });
186
196
  }
187
197
 
188
198
  export function removePidFile(pidPath = PID_PATH): void {