@rethinkingstudio/clawpilot 1.0.13 → 1.0.15

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.
@@ -5,8 +5,4 @@ export type LocalResult = {
5
5
  ok: false;
6
6
  error: string;
7
7
  };
8
- /**
9
- * Handles clawpilot-specific commands locally, without forwarding to the gateway.
10
- * Returns null if the method is not a local command (caller should forward to gateway).
11
- */
12
8
  export declare function handleLocalCommand(method: string): LocalResult | null;
@@ -1,68 +1,63 @@
1
1
  import { readdirSync, statSync, copyFileSync, existsSync, readFileSync } from "fs";
2
- import { join } from "path";
2
+ import { join, dirname } from "path";
3
3
  import { homedir } from "os";
4
4
  import { execSync } from "child_process";
5
5
  const OPENCLAW_DIR = join(homedir(), ".openclaw");
6
6
  const OPENCLAW_CONFIG = join(OPENCLAW_DIR, "openclaw.json");
7
7
  // ---------------------------------------------------------------------------
8
- // Resolve the openclaw binary path once at startup.
9
- // launchd services run with a minimal PATH — we try login shells (zsh first,
10
- // macOS default since Catalina) then fall back to common install locations.
8
+ // Subprocess environment
9
+ //
10
+ // launchd services run with a minimal PATH that lacks:
11
+ // - The node binary itself (breaks #!/usr/bin/env node shebangs)
12
+ // - Homebrew / local bins (breaks finding `openclaw`)
13
+ //
14
+ // Fix: build a rich PATH for every subprocess by prepending:
15
+ // 1. dirname(process.execPath) — the dir containing the node binary running
16
+ // this very process. Guarantees #!/usr/bin/env node always resolves.
17
+ // 2. Common package-manager bin dirs (homebrew, /usr/local).
11
18
  // ---------------------------------------------------------------------------
19
+ const NODE_BIN_DIR = dirname(process.execPath);
20
+ const SUBPROCESS_ENV = {
21
+ ...process.env,
22
+ HOME: homedir(),
23
+ PATH: [
24
+ NODE_BIN_DIR,
25
+ "/opt/homebrew/bin",
26
+ "/opt/homebrew/sbin",
27
+ "/usr/local/bin",
28
+ "/usr/local/sbin",
29
+ process.env.PATH ?? "/usr/bin:/bin",
30
+ ].join(":"),
31
+ };
12
32
  function resolveOpenclawBin() {
13
- for (const shell of ["/bin/zsh", "/bin/bash"]) {
14
- try {
15
- const p = execSync(`${shell} -lc 'which openclaw'`, { stdio: "pipe", timeout: 3000 })
16
- .toString().trim();
17
- if (p && existsSync(p)) {
18
- console.log(`[clawpilot] openclaw found at ${p} (via ${shell})`);
19
- return p;
20
- }
21
- }
22
- catch { /* try next */ }
23
- }
24
- // Common install locations as final fallback
25
- for (const p of [
26
- "/opt/homebrew/bin/openclaw",
27
- "/usr/local/bin/openclaw",
28
- join(homedir(), ".local/bin/openclaw"),
29
- ]) {
30
- if (existsSync(p)) {
31
- console.log(`[clawpilot] openclaw found at ${p} (fallback)`);
33
+ try {
34
+ const p = execSync("which openclaw", { stdio: "pipe", env: SUBPROCESS_ENV, timeout: 3000 })
35
+ .toString().trim();
36
+ if (p && existsSync(p)) {
37
+ console.log(`[clawpilot] openclaw resolved: ${p}`);
32
38
  return p;
33
39
  }
34
40
  }
35
- console.warn("[clawpilot] could not resolve openclaw path, using bare 'openclaw'");
41
+ catch { /* fall through */ }
42
+ console.warn("[clawpilot] could not resolve openclaw path, using bare name");
36
43
  return "openclaw";
37
44
  }
38
45
  const OPENCLAW_BIN = resolveOpenclawBin();
39
46
  // ---------------------------------------------------------------------------
40
- /**
41
- * Handles clawpilot-specific commands locally, without forwarding to the gateway.
42
- * Returns null if the method is not a local command (caller should forward to gateway).
43
- */
44
47
  export function handleLocalCommand(method) {
45
48
  switch (method) {
46
- case "clawpilot.restore.config":
47
- return restoreConfig();
48
- case "clawpilot.watchskill":
49
- return watchSkill();
50
- case "clawpilot.doctor":
51
- return runDoctor();
52
- case "clawpilot.logs":
53
- return readLogs();
54
- case "clawpilot.gateway.restart":
55
- return restartGateway();
56
- case "clawpilot.update":
57
- return updateOpenclaw();
58
- default:
59
- return null;
49
+ case "clawpilot.restore.config": return restoreConfig();
50
+ case "clawpilot.watchskill": return watchSkill();
51
+ case "clawpilot.doctor": return runDoctor();
52
+ case "clawpilot.logs": return readLogs();
53
+ case "clawpilot.gateway.restart": return restartGateway();
54
+ case "clawpilot.update": return updateOpenclaw();
55
+ default: return null;
60
56
  }
61
57
  }
62
58
  // ---------------------------------------------------------------------------
63
59
  // Helpers
64
60
  // ---------------------------------------------------------------------------
65
- /** Extracts combined stdout+stderr from an execSync error. */
66
61
  function execErrorOutput(err) {
67
62
  const e = err;
68
63
  const out = e.stdout?.toString() ?? "";
@@ -71,16 +66,13 @@ function execErrorOutput(err) {
71
66
  return `${out}\n${errStr}`;
72
67
  return out || errStr;
73
68
  }
74
- /** Run openclaw with the resolved binary path. */
69
+ /** Run openclaw with the resolved path and the enriched subprocess environment. */
75
70
  function openclaw(args) {
76
- return execSync(`"${OPENCLAW_BIN}" ${args}`, { stdio: "pipe" });
71
+ return execSync(`"${OPENCLAW_BIN}" ${args}`, { stdio: "pipe", env: SUBPROCESS_ENV });
77
72
  }
78
73
  // ---------------------------------------------------------------------------
79
74
  // Command implementations
80
75
  // ---------------------------------------------------------------------------
81
- /**
82
- * Finds the most recent openclaw.json.bak* file and copies it over openclaw.json.
83
- */
84
76
  function restoreConfig() {
85
77
  try {
86
78
  if (!existsSync(OPENCLAW_DIR)) {
@@ -105,9 +97,6 @@ function restoreConfig() {
105
97
  return { ok: false, error: String(err) };
106
98
  }
107
99
  }
108
- /**
109
- * Enables real-time skill file watching via openclaw CLI.
110
- */
111
100
  function watchSkill() {
112
101
  try {
113
102
  openclaw("config set skills.load.watch true");
@@ -118,9 +107,6 @@ function watchSkill() {
118
107
  return { ok: false, error: String(err) };
119
108
  }
120
109
  }
121
- /**
122
- * Runs openclaw doctor to check system health.
123
- */
124
110
  function runDoctor() {
125
111
  try {
126
112
  const output = openclaw("doctor").toString();
@@ -129,14 +115,9 @@ function runDoctor() {
129
115
  }
130
116
  catch (err) {
131
117
  const output = execErrorOutput(err);
132
- return output
133
- ? { ok: true, payload: { output } }
134
- : { ok: false, error: String(err) };
118
+ return output ? { ok: true, payload: { output } } : { ok: false, error: String(err) };
135
119
  }
136
120
  }
137
- /**
138
- * Reads the last 100 lines from log files in ~/.openclaw/logs/ or ~/.openclaw/*.log.
139
- */
140
121
  function readLogs() {
141
122
  try {
142
123
  const logsDir = join(OPENCLAW_DIR, "logs");
@@ -159,17 +140,13 @@ function readLogs() {
159
140
  const latest = logFilesWithMtime[0].path;
160
141
  const allLines = readFileSync(latest, "utf-8").split("\n");
161
142
  const last100 = allLines.slice(-100).join("\n");
162
- const output = `[${latest}]\n${last100}`;
163
143
  console.log(`[clawpilot] logs read from ${latest}`);
164
- return { ok: true, payload: { output } };
144
+ return { ok: true, payload: { output: `[${latest}]\n${last100}` } };
165
145
  }
166
146
  catch (err) {
167
147
  return { ok: false, error: String(err) };
168
148
  }
169
149
  }
170
- /**
171
- * Restarts the openclaw gateway process.
172
- */
173
150
  function restartGateway() {
174
151
  try {
175
152
  const output = openclaw("gateway restart").toString();
@@ -178,14 +155,9 @@ function restartGateway() {
178
155
  }
179
156
  catch (err) {
180
157
  const output = execErrorOutput(err);
181
- return output
182
- ? { ok: true, payload: { output } }
183
- : { ok: false, error: String(err) };
158
+ return output ? { ok: true, payload: { output } } : { ok: false, error: String(err) };
184
159
  }
185
160
  }
186
- /**
187
- * Updates openclaw to the latest version.
188
- */
189
161
  function updateOpenclaw() {
190
162
  try {
191
163
  const output = openclaw("update").toString();
@@ -194,9 +166,7 @@ function updateOpenclaw() {
194
166
  }
195
167
  catch (err) {
196
168
  const output = execErrorOutput(err);
197
- return output
198
- ? { ok: true, payload: { output } }
199
- : { ok: false, error: String(err) };
169
+ return output ? { ok: true, payload: { output } } : { ok: false, error: String(err) };
200
170
  }
201
171
  }
202
172
  //# sourceMappingURL=local-handlers.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"local-handlers.js","sourceRoot":"","sources":["../../src/commands/local-handlers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AACnF,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,MAAM,YAAY,GAAM,IAAI,CAAC,OAAO,EAAE,EAAE,WAAW,CAAC,CAAC;AACrD,MAAM,eAAe,GAAG,IAAI,CAAC,YAAY,EAAE,eAAe,CAAC,CAAC;AAM5D,8EAA8E;AAC9E,oDAAoD;AACpD,6EAA6E;AAC7E,4EAA4E;AAC5E,8EAA8E;AAE9E,SAAS,kBAAkB;IACzB,KAAK,MAAM,KAAK,IAAI,CAAC,UAAU,EAAE,WAAW,CAAC,EAAE,CAAC;QAC9C,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,KAAK,uBAAuB,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;iBAClF,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;YACrB,IAAI,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;gBACvB,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,SAAS,KAAK,GAAG,CAAC,CAAC;gBACjE,OAAO,CAAC,CAAC;YACX,CAAC;QACH,CAAC;QAAC,MAAM,CAAC,CAAC,cAAc,CAAC,CAAC;IAC5B,CAAC;IACD,6CAA6C;IAC7C,KAAK,MAAM,CAAC,IAAI;QACd,4BAA4B;QAC5B,yBAAyB;QACzB,IAAI,CAAC,OAAO,EAAE,EAAE,qBAAqB,CAAC;KACvC,EAAE,CAAC;QACF,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;YAClB,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,aAAa,CAAC,CAAC;YAC7D,OAAO,CAAC,CAAC;QACX,CAAC;IACH,CAAC;IACD,OAAO,CAAC,IAAI,CAAC,oEAAoE,CAAC,CAAC;IACnF,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,MAAM,YAAY,GAAG,kBAAkB,EAAE,CAAC;AAE1C,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAc;IAC/C,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,0BAA0B;YAC7B,OAAO,aAAa,EAAE,CAAC;QACzB,KAAK,sBAAsB;YACzB,OAAO,UAAU,EAAE,CAAC;QACtB,KAAK,kBAAkB;YACrB,OAAO,SAAS,EAAE,CAAC;QACrB,KAAK,gBAAgB;YACnB,OAAO,QAAQ,EAAE,CAAC;QACpB,KAAK,2BAA2B;YAC9B,OAAO,cAAc,EAAE,CAAC;QAC1B,KAAK,kBAAkB;YACrB,OAAO,cAAc,EAAE,CAAC;QAC1B;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E,8DAA8D;AAC9D,SAAS,eAAe,CAAC,GAAY;IACnC,MAAM,CAAC,GAAG,GAA6D,CAAC;IACxE,MAAM,GAAG,GAAG,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IACvC,MAAM,MAAM,GAAG,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;IAC1C,IAAI,GAAG,IAAI,MAAM;QAAE,OAAO,GAAG,GAAG,KAAK,MAAM,EAAE,CAAC;IAC9C,OAAO,GAAG,IAAI,MAAM,CAAC;AACvB,CAAC;AAED,kDAAkD;AAClD,SAAS,QAAQ,CAAC,IAAY;IAC5B,OAAO,QAAQ,CAAC,IAAI,YAAY,KAAK,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;AAClE,CAAC;AAED,8EAA8E;AAC9E,0BAA0B;AAC1B,8EAA8E;AAE9E;;GAEG;AACH,SAAS,aAAa;IACpB,IAAI,CAAC;QACH,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YAC9B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,kCAAkC,YAAY,EAAE,EAAE,CAAC;QAChF,CAAC;QAED,MAAM,QAAQ,GAAG,WAAW,CAAC,YAAY,CAAC;aACvC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,mBAAmB,CAAC,CAAC;aACpD,GAAG,CAAC,IAAI,CAAC,EAAE;YACV,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;YACtC,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;QACvD,CAAC,CAAC;aACD,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;QAErC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,uCAAuC,EAAE,CAAC;QACvE,CAAC;QAED,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;QAC3B,YAAY,CAAC,MAAM,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;QAE3C,OAAO,CAAC,GAAG,CAAC,oCAAoC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;QAC/D,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,YAAY,EAAE,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;IAC9D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;IAC3C,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,UAAU;IACjB,IAAI,CAAC;QACH,QAAQ,CAAC,mCAAmC,CAAC,CAAC;QAC9C,OAAO,CAAC,GAAG,CAAC,2CAA2C,CAAC,CAAC;QACzD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,OAAO,EAAE,2BAA2B,EAAE,EAAE,CAAC;IACzE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;IAC3C,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,SAAS;IAChB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC7C,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;QAC5C,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC;IAC3C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;QACpC,OAAO,MAAM;YACX,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE;YACnC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;IACxC,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,QAAQ;IACf,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;QAC3C,IAAI,QAAQ,GAAa,EAAE,CAAC;QAE5B,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YACxB,QAAQ,GAAG,WAAW,CAAC,OAAO,CAAC;iBAC5B,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;iBAC/B,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;QAChC,CAAC;aAAM,CAAC;YACN,QAAQ,GAAG,WAAW,CAAC,YAAY,CAAC;iBACjC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;iBAC/B,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,CAAC;QACrC,CAAC;QAED,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,qBAAqB,EAAE,EAAE,CAAC;QAClE,CAAC;QAED,MAAM,iBAAiB,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QACvF,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;QACpD,MAAM,MAAM,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACzC,MAAM,QAAQ,GAAG,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3D,MAAM,OAAO,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChD,MAAM,MAAM,GAAG,IAAI,MAAM,MAAM,OAAO,EAAE,CAAC;QAEzC,OAAO,CAAC,GAAG,CAAC,8BAA8B,MAAM,EAAE,CAAC,CAAC;QACpD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC;IAC3C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;IAC3C,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,cAAc;IACrB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,iBAAiB,CAAC,CAAC,QAAQ,EAAE,CAAC;QACtD,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;QAC7C,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,IAAI,iCAAiC,EAAE,EAAE,CAAC;IACxF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;QACpC,OAAO,MAAM;YACX,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE;YACnC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;IACxC,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,cAAc;IACrB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC7C,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;QAC5C,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,IAAI,gCAAgC,EAAE,EAAE,CAAC;IACvF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;QACpC,OAAO,MAAM;YACX,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE;YACnC,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;IACxC,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"local-handlers.js","sourceRoot":"","sources":["../../src/commands/local-handlers.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,17 @@
1
1
  import { hostname } from "os";
2
2
  import { execSync } from "child_process";
3
+ function sanitizeDisplayName(name) {
4
+ // Replace smart quotes and other problematic characters with regular ones
5
+ return name
6
+ .replace(/[\u2018\u2019\u201C\u201D]/g, "'") // Smart quotes → regular quotes
7
+ .replace(/[\u2013\u2014]/g, "-") // En/em dashes → regular dash
8
+ .replace(/[\u00A0]/g, " ") // Non-breaking space → regular space
9
+ .replace(/[^\x20-\x7E]/g, ""); // Remove any other non-ASCII characters
10
+ }
3
11
  function getDisplayName() {
4
12
  try {
5
- return execSync("scutil --get ComputerName", { encoding: "utf8" }).trim();
13
+ const raw = execSync("scutil --get ComputerName", { encoding: "utf8" }).trim();
14
+ return sanitizeDisplayName(raw);
6
15
  }
7
16
  catch {
8
17
  return hostname();
@@ -24,7 +33,7 @@ export async function pairCommand(opts) {
24
33
  const config = readConfig();
25
34
  gatewayId = config.gatewayId;
26
35
  relaySecret = config.relaySecret;
27
- displayName = opts.name ?? config.displayName;
36
+ displayName = opts.name ? sanitizeDisplayName(opts.name) : config.displayName;
28
37
  console.log(t("pair.alreadyRegistered", gatewayId));
29
38
  const res = await fetch(`${httpBase}/api/relay/accesscode`, {
30
39
  method: "POST",
@@ -43,7 +52,7 @@ export async function pairCommand(opts) {
43
52
  writeConfig({ ...config, relayServerUrl, displayName });
44
53
  }
45
54
  else {
46
- displayName = opts.name ?? getDisplayName();
55
+ displayName = opts.name ? sanitizeDisplayName(opts.name) : getDisplayName();
47
56
  console.log(t("pair.registering"));
48
57
  const res = await fetch(`${httpBase}/api/relay/register`, {
49
58
  method: "POST",
@@ -1 +1 @@
1
- {"version":3,"file":"pair.js","sourceRoot":"","sources":["../../src/commands/pair.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pair.js","sourceRoot":"","sources":["../../src/commands/pair.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import { runCommand } from "./commands/run.js";
5
5
  import { installCommand, uninstallCommand, stopCommand, restartCommand, resetCommand } from "./commands/install.js";
6
6
  import { statusCommand } from "./commands/status.js";
7
7
  import { setTokenCommand } from "./commands/set-token.js";
8
- const version = "1.0.13";
8
+ const version = "1.0.15";
9
9
  const program = new Command();
10
10
  program
11
11
  .name("clawpilot")
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rethinkingstudio/clawpilot",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
4
4
  "description": "ClawAI relay client for Mac mini",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,5 +1,5 @@
1
1
  import { readdirSync, statSync, copyFileSync, existsSync, readFileSync } from "fs";
2
- import { join } from "path";
2
+ import { join, dirname } from "path";
3
3
  import { homedir } from "os";
4
4
  import { execSync } from "child_process";
5
5
 
@@ -11,34 +11,43 @@ export type LocalResult =
11
11
  | { ok: false; error: string };
12
12
 
13
13
  // ---------------------------------------------------------------------------
14
- // Resolve the openclaw binary path once at startup.
15
- // launchd services run with a minimal PATH — we try login shells (zsh first,
16
- // macOS default since Catalina) then fall back to common install locations.
14
+ // Subprocess environment
15
+ //
16
+ // launchd services run with a minimal PATH that lacks:
17
+ // - The node binary itself (breaks #!/usr/bin/env node shebangs)
18
+ // - Homebrew / local bins (breaks finding `openclaw`)
19
+ //
20
+ // Fix: build a rich PATH for every subprocess by prepending:
21
+ // 1. dirname(process.execPath) — the dir containing the node binary running
22
+ // this very process. Guarantees #!/usr/bin/env node always resolves.
23
+ // 2. Common package-manager bin dirs (homebrew, /usr/local).
17
24
  // ---------------------------------------------------------------------------
18
25
 
26
+ const NODE_BIN_DIR = dirname(process.execPath);
27
+
28
+ const SUBPROCESS_ENV: NodeJS.ProcessEnv = {
29
+ ...process.env,
30
+ HOME: homedir(),
31
+ PATH: [
32
+ NODE_BIN_DIR,
33
+ "/opt/homebrew/bin",
34
+ "/opt/homebrew/sbin",
35
+ "/usr/local/bin",
36
+ "/usr/local/sbin",
37
+ process.env.PATH ?? "/usr/bin:/bin",
38
+ ].join(":"),
39
+ };
40
+
19
41
  function resolveOpenclawBin(): string {
20
- for (const shell of ["/bin/zsh", "/bin/bash"]) {
21
- try {
22
- const p = execSync(`${shell} -lc 'which openclaw'`, { stdio: "pipe", timeout: 3000 })
23
- .toString().trim();
24
- if (p && existsSync(p)) {
25
- console.log(`[clawpilot] openclaw found at ${p} (via ${shell})`);
26
- return p;
27
- }
28
- } catch { /* try next */ }
29
- }
30
- // Common install locations as final fallback
31
- for (const p of [
32
- "/opt/homebrew/bin/openclaw",
33
- "/usr/local/bin/openclaw",
34
- join(homedir(), ".local/bin/openclaw"),
35
- ]) {
36
- if (existsSync(p)) {
37
- console.log(`[clawpilot] openclaw found at ${p} (fallback)`);
42
+ try {
43
+ const p = execSync("which openclaw", { stdio: "pipe", env: SUBPROCESS_ENV, timeout: 3000 })
44
+ .toString().trim();
45
+ if (p && existsSync(p)) {
46
+ console.log(`[clawpilot] openclaw resolved: ${p}`);
38
47
  return p;
39
48
  }
40
- }
41
- console.warn("[clawpilot] could not resolve openclaw path, using bare 'openclaw'");
49
+ } catch { /* fall through */ }
50
+ console.warn("[clawpilot] could not resolve openclaw path, using bare name");
42
51
  return "openclaw";
43
52
  }
44
53
 
@@ -46,26 +55,15 @@ const OPENCLAW_BIN = resolveOpenclawBin();
46
55
 
47
56
  // ---------------------------------------------------------------------------
48
57
 
49
- /**
50
- * Handles clawpilot-specific commands locally, without forwarding to the gateway.
51
- * Returns null if the method is not a local command (caller should forward to gateway).
52
- */
53
58
  export function handleLocalCommand(method: string): LocalResult | null {
54
59
  switch (method) {
55
- case "clawpilot.restore.config":
56
- return restoreConfig();
57
- case "clawpilot.watchskill":
58
- return watchSkill();
59
- case "clawpilot.doctor":
60
- return runDoctor();
61
- case "clawpilot.logs":
62
- return readLogs();
63
- case "clawpilot.gateway.restart":
64
- return restartGateway();
65
- case "clawpilot.update":
66
- return updateOpenclaw();
67
- default:
68
- return null;
60
+ case "clawpilot.restore.config": return restoreConfig();
61
+ case "clawpilot.watchskill": return watchSkill();
62
+ case "clawpilot.doctor": return runDoctor();
63
+ case "clawpilot.logs": return readLogs();
64
+ case "clawpilot.gateway.restart": return restartGateway();
65
+ case "clawpilot.update": return updateOpenclaw();
66
+ default: return null;
69
67
  }
70
68
  }
71
69
 
@@ -73,7 +71,6 @@ export function handleLocalCommand(method: string): LocalResult | null {
73
71
  // Helpers
74
72
  // ---------------------------------------------------------------------------
75
73
 
76
- /** Extracts combined stdout+stderr from an execSync error. */
77
74
  function execErrorOutput(err: unknown): string {
78
75
  const e = err as { stdout?: Buffer | string; stderr?: Buffer | string };
79
76
  const out = e.stdout?.toString() ?? "";
@@ -82,24 +79,20 @@ function execErrorOutput(err: unknown): string {
82
79
  return out || errStr;
83
80
  }
84
81
 
85
- /** Run openclaw with the resolved binary path. */
82
+ /** Run openclaw with the resolved path and the enriched subprocess environment. */
86
83
  function openclaw(args: string): Buffer {
87
- return execSync(`"${OPENCLAW_BIN}" ${args}`, { stdio: "pipe" });
84
+ return execSync(`"${OPENCLAW_BIN}" ${args}`, { stdio: "pipe", env: SUBPROCESS_ENV });
88
85
  }
89
86
 
90
87
  // ---------------------------------------------------------------------------
91
88
  // Command implementations
92
89
  // ---------------------------------------------------------------------------
93
90
 
94
- /**
95
- * Finds the most recent openclaw.json.bak* file and copies it over openclaw.json.
96
- */
97
91
  function restoreConfig(): LocalResult {
98
92
  try {
99
93
  if (!existsSync(OPENCLAW_DIR)) {
100
94
  return { ok: false, error: `openclaw config dir not found: ${OPENCLAW_DIR}` };
101
95
  }
102
-
103
96
  const bakFiles = readdirSync(OPENCLAW_DIR)
104
97
  .filter(name => name.startsWith("openclaw.json.bak"))
105
98
  .map(name => {
@@ -111,10 +104,8 @@ function restoreConfig(): LocalResult {
111
104
  if (bakFiles.length === 0) {
112
105
  return { ok: false, error: "No backup files found in ~/.openclaw/" };
113
106
  }
114
-
115
107
  const latest = bakFiles[0];
116
108
  copyFileSync(latest.path, OPENCLAW_CONFIG);
117
-
118
109
  console.log(`[clawpilot] Config restored from ${latest.name}`);
119
110
  return { ok: true, payload: { restoredFrom: latest.name } };
120
111
  } catch (err) {
@@ -122,9 +113,6 @@ function restoreConfig(): LocalResult {
122
113
  }
123
114
  }
124
115
 
125
- /**
126
- * Enables real-time skill file watching via openclaw CLI.
127
- */
128
116
  function watchSkill(): LocalResult {
129
117
  try {
130
118
  openclaw("config set skills.load.watch true");
@@ -135,9 +123,6 @@ function watchSkill(): LocalResult {
135
123
  }
136
124
  }
137
125
 
138
- /**
139
- * Runs openclaw doctor to check system health.
140
- */
141
126
  function runDoctor(): LocalResult {
142
127
  try {
143
128
  const output = openclaw("doctor").toString();
@@ -145,15 +130,10 @@ function runDoctor(): LocalResult {
145
130
  return { ok: true, payload: { output } };
146
131
  } catch (err) {
147
132
  const output = execErrorOutput(err);
148
- return output
149
- ? { ok: true, payload: { output } }
150
- : { ok: false, error: String(err) };
133
+ return output ? { ok: true, payload: { output } } : { ok: false, error: String(err) };
151
134
  }
152
135
  }
153
136
 
154
- /**
155
- * Reads the last 100 lines from log files in ~/.openclaw/logs/ or ~/.openclaw/*.log.
156
- */
157
137
  function readLogs(): LocalResult {
158
138
  try {
159
139
  const logsDir = join(OPENCLAW_DIR, "logs");
@@ -178,18 +158,14 @@ function readLogs(): LocalResult {
178
158
  const latest = logFilesWithMtime[0].path;
179
159
  const allLines = readFileSync(latest, "utf-8").split("\n");
180
160
  const last100 = allLines.slice(-100).join("\n");
181
- const output = `[${latest}]\n${last100}`;
182
161
 
183
162
  console.log(`[clawpilot] logs read from ${latest}`);
184
- return { ok: true, payload: { output } };
163
+ return { ok: true, payload: { output: `[${latest}]\n${last100}` } };
185
164
  } catch (err) {
186
165
  return { ok: false, error: String(err) };
187
166
  }
188
167
  }
189
168
 
190
- /**
191
- * Restarts the openclaw gateway process.
192
- */
193
169
  function restartGateway(): LocalResult {
194
170
  try {
195
171
  const output = openclaw("gateway restart").toString();
@@ -197,15 +173,10 @@ function restartGateway(): LocalResult {
197
173
  return { ok: true, payload: { output: output || "Gateway restarted successfully." } };
198
174
  } catch (err) {
199
175
  const output = execErrorOutput(err);
200
- return output
201
- ? { ok: true, payload: { output } }
202
- : { ok: false, error: String(err) };
176
+ return output ? { ok: true, payload: { output } } : { ok: false, error: String(err) };
203
177
  }
204
178
  }
205
179
 
206
- /**
207
- * Updates openclaw to the latest version.
208
- */
209
180
  function updateOpenclaw(): LocalResult {
210
181
  try {
211
182
  const output = openclaw("update").toString();
@@ -213,8 +184,6 @@ function updateOpenclaw(): LocalResult {
213
184
  return { ok: true, payload: { output: output || "openclaw updated successfully." } };
214
185
  } catch (err) {
215
186
  const output = execErrorOutput(err);
216
- return output
217
- ? { ok: true, payload: { output } }
218
- : { ok: false, error: String(err) };
187
+ return output ? { ok: true, payload: { output } } : { ok: false, error: String(err) };
219
188
  }
220
189
  }
@@ -1,9 +1,19 @@
1
1
  import { hostname } from "os";
2
2
  import { execSync } from "child_process";
3
3
 
4
+ function sanitizeDisplayName(name: string): string {
5
+ // Replace smart quotes and other problematic characters with regular ones
6
+ return name
7
+ .replace(/[\u2018\u2019\u201C\u201D]/g, "'") // Smart quotes → regular quotes
8
+ .replace(/[\u2013\u2014]/g, "-") // En/em dashes → regular dash
9
+ .replace(/[\u00A0]/g, " ") // Non-breaking space → regular space
10
+ .replace(/[^\x20-\x7E]/g, ""); // Remove any other non-ASCII characters
11
+ }
12
+
4
13
  function getDisplayName(): string {
5
14
  try {
6
- return execSync("scutil --get ComputerName", { encoding: "utf8" }).trim();
15
+ const raw = execSync("scutil --get ComputerName", { encoding: "utf8" }).trim();
16
+ return sanitizeDisplayName(raw);
7
17
  } catch {
8
18
  return hostname();
9
19
  }
@@ -33,7 +43,7 @@ export async function pairCommand(opts: PairOptions): Promise<void> {
33
43
  const config = readConfig();
34
44
  gatewayId = config.gatewayId;
35
45
  relaySecret = config.relaySecret;
36
- displayName = opts.name ?? config.displayName;
46
+ displayName = opts.name ? sanitizeDisplayName(opts.name) : config.displayName;
37
47
 
38
48
  console.log(t("pair.alreadyRegistered", gatewayId));
39
49
 
@@ -56,7 +66,7 @@ export async function pairCommand(opts: PairOptions): Promise<void> {
56
66
 
57
67
  writeConfig({ ...config, relayServerUrl, displayName });
58
68
  } else {
59
- displayName = opts.name ?? getDisplayName();
69
+ displayName = opts.name ? sanitizeDisplayName(opts.name) : getDisplayName();
60
70
  console.log(t("pair.registering"));
61
71
 
62
72
  const res = await fetch(`${httpBase}/api/relay/register`, {
package/src/index.ts CHANGED
@@ -6,7 +6,7 @@ import { installCommand, uninstallCommand, stopCommand, restartCommand, resetCom
6
6
  import { statusCommand } from "./commands/status.js";
7
7
  import { setTokenCommand } from "./commands/set-token.js";
8
8
 
9
- const version = "1.0.13";
9
+ const version = "1.0.15";
10
10
 
11
11
  const program = new Command();
12
12