@foxden-app/foxclaw 0.3.14 → 0.3.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.
package/dist/main.js CHANGED
@@ -9,7 +9,7 @@ import { APP_HOME, DEFAULT_ENV_PATH, DEFAULT_LOG_PATH, DEFAULT_STATUS_PATH, getL
9
9
  import { acquireProcessLock, LockHeldError } from './lock.js';
10
10
  import { readRuntimeStatus, writeRuntimeStatus } from './runtime.js';
11
11
  import { refreshFoxclawExecStartDropIns, removeFoxclawExecStartDropIns } from './systemd.js';
12
- import { createSelfUpdateRuntime, performSelfUpdate } from './update.js';
12
+ import { createSelfUpdateRuntime, inferPnpmHomeFromEntryPoint, performSelfUpdate } from './update.js';
13
13
  const rawCommand = process.argv[2];
14
14
  const command = rawCommand || 'serve';
15
15
  loadEnv();
@@ -776,9 +776,17 @@ function stopLaunchd() {
776
776
  console.log(`Stopped ${plist}`);
777
777
  }
778
778
  function buildServicePath(nodeDir) {
779
+ const pnpmPath = resolveCommand('pnpm');
780
+ const inferredPnpmHome = inferPnpmHomeFromEntryPoint(entryPoint) || '';
781
+ const configuredPnpmHome = process.env.PNPM_HOME?.trim() || '';
779
782
  const parts = [
780
783
  path.join(process.env.HOME || '', '.local', 'bin'),
781
784
  nodeDir,
785
+ inferredPnpmHome,
786
+ inferredPnpmHome ? path.join(inferredPnpmHome, 'bin') : '',
787
+ configuredPnpmHome,
788
+ configuredPnpmHome ? path.join(configuredPnpmHome, 'bin') : '',
789
+ pnpmPath ? path.dirname(pnpmPath) : '',
782
790
  '/usr/local/sbin',
783
791
  '/usr/local/bin',
784
792
  '/usr/sbin',
package/dist/update.d.ts CHANGED
@@ -41,7 +41,8 @@ export interface SelfUpdateOutcome {
41
41
  error: string | null;
42
42
  }
43
43
  export declare function selfUpdateStatusPath(statusPath: string): string;
44
- export declare function resolveSelfUpdateInstaller(entryPoint: string, nodePath?: string, exists?: (target: string) => boolean): SelfUpdateInstaller;
44
+ export declare function inferPnpmHomeFromEntryPoint(entryPoint: string): string | null;
45
+ export declare function resolveSelfUpdateInstaller(entryPoint: string, nodePath?: string, exists?: (target: string) => boolean, env?: NodeJS.ProcessEnv): SelfUpdateInstaller;
45
46
  export declare function readSelfUpdateStatus(statusFile: string): SelfUpdateStatus | null;
46
47
  export declare function writeSelfUpdateStatus(statusFile: string, status: SelfUpdateStatus): void;
47
48
  export declare function createSelfUpdateRuntime(options: CreateSelfUpdateRuntimeOptions): SelfUpdateRuntime;
package/dist/update.js CHANGED
@@ -7,21 +7,42 @@ const UPDATE_STATUS_FILENAME = 'self-update.json';
7
7
  export function selfUpdateStatusPath(statusPath) {
8
8
  return path.join(path.dirname(statusPath), UPDATE_STATUS_FILENAME);
9
9
  }
10
- export function resolveSelfUpdateInstaller(entryPoint, nodePath = process.execPath, exists = fs.existsSync) {
10
+ export function inferPnpmHomeFromEntryPoint(entryPoint) {
11
11
  const normalizedEntryPoint = entryPoint.replace(/\\/g, '/');
12
12
  const globalMarker = '/global/';
13
13
  const globalIndex = normalizedEntryPoint.indexOf(globalMarker);
14
- if (globalIndex > 0 && normalizedEntryPoint.includes('/.pnpm/')) {
15
- const pnpmHome = normalizedEntryPoint.slice(0, globalIndex);
16
- const pnpmCommand = path.join(pnpmHome, process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm');
17
- if (!exists(pnpmCommand)) {
18
- throw new Error(`Current installation is managed by pnpm, but pnpm was not found at ${pnpmCommand}.`);
14
+ if (globalIndex <= 0 || !normalizedEntryPoint.includes('/.pnpm/')) {
15
+ return null;
16
+ }
17
+ return normalizedEntryPoint.slice(0, globalIndex);
18
+ }
19
+ export function resolveSelfUpdateInstaller(entryPoint, nodePath = process.execPath, exists = fs.existsSync, env = process.env) {
20
+ const pnpmHome = inferPnpmHomeFromEntryPoint(entryPoint);
21
+ if (pnpmHome) {
22
+ const commandName = process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm';
23
+ const candidates = executableCandidates(commandName, nodePath, env, [
24
+ path.join(pnpmHome, commandName),
25
+ path.join(pnpmHome, 'bin', commandName),
26
+ env.PNPM_HOME?.trim() ? path.join(env.PNPM_HOME.trim(), commandName) : '',
27
+ env.PNPM_HOME?.trim() ? path.join(env.PNPM_HOME.trim(), 'bin', commandName) : '',
28
+ ]);
29
+ const pnpmCommand = candidates.find((candidate) => exists(candidate));
30
+ if (pnpmCommand) {
31
+ return {
32
+ manager: 'pnpm',
33
+ command: pnpmCommand,
34
+ installArgs: ['add', '--global', PACKAGE_SPEC],
35
+ rootArgs: ['root', '--global'],
36
+ };
19
37
  }
38
+ const npmCommandName = process.platform === 'win32' ? 'npm.cmd' : 'npm';
39
+ const npmCommand = executableCandidates(npmCommandName, nodePath, env)
40
+ .find((candidate) => exists(candidate)) ?? npmCommandName;
20
41
  return {
21
42
  manager: 'pnpm',
22
- command: pnpmCommand,
23
- installArgs: ['add', '--global', PACKAGE_SPEC],
24
- rootArgs: ['root', '--global'],
43
+ command: npmCommand,
44
+ installArgs: ['exec', '--yes', '--package=pnpm@latest', '--', 'pnpm', 'add', '--global', PACKAGE_SPEC],
45
+ rootArgs: ['exec', '--yes', '--package=pnpm@latest', '--', 'pnpm', 'root', '--global'],
25
46
  };
26
47
  }
27
48
  const adjacentNpm = path.join(path.dirname(nodePath), process.platform === 'win32' ? 'npm.cmd' : 'npm');
@@ -117,13 +138,14 @@ export function performSelfUpdate(options) {
117
138
  const env = options.env ?? process.env;
118
139
  let toVersion = null;
119
140
  try {
120
- const installer = resolveSelfUpdateInstaller(options.entryPoint, options.nodePath);
141
+ const installer = resolveSelfUpdateInstaller(options.entryPoint, options.nodePath, fs.existsSync, env);
142
+ const installerEnv = buildInstallerEnv(options.entryPoint, installer, env);
121
143
  console.log(`[UPDATE] Installing ${PACKAGE_SPEC} with ${installer.manager}...`);
122
- runInherited(installer.command, installer.installArgs, env);
123
- const updatedEntryPoint = resolveUpdatedEntryPoint(installer, env);
144
+ runInherited(installer.command, installer.installArgs, installerEnv);
145
+ const updatedEntryPoint = resolveUpdatedEntryPoint(installer, installerEnv);
124
146
  toVersion = readInstalledPackageVersion(updatedEntryPoint);
125
147
  console.log('[UPDATE] Running checks and restarting the FoxClaw service...');
126
- runInherited(options.nodePath, [updatedEntryPoint, 'start'], env);
148
+ runInherited(options.nodePath, [updatedEntryPoint, 'start'], installerEnv);
127
149
  completeNotification(options.notificationFile, 'succeeded', toVersion, null);
128
150
  console.log(`[OK] FoxClaw updated and restarted: ${options.version} -> ${toVersion}`);
129
151
  return {
@@ -145,6 +167,32 @@ export function performSelfUpdate(options) {
145
167
  };
146
168
  }
147
169
  }
170
+ function executableCandidates(commandName, nodePath, env, preferred = []) {
171
+ return [
172
+ ...preferred,
173
+ path.join(path.dirname(nodePath), commandName),
174
+ ...(env.PATH || '').split(path.delimiter).filter(Boolean).map((dir) => path.join(dir, commandName)),
175
+ ].filter((candidate, index, all) => candidate && all.indexOf(candidate) === index);
176
+ }
177
+ function buildInstallerEnv(entryPoint, installer, env) {
178
+ const pnpmHome = installer.manager === 'pnpm' ? inferPnpmHomeFromEntryPoint(entryPoint) : null;
179
+ if (!pnpmHome) {
180
+ return env;
181
+ }
182
+ const configuredPnpmHome = env.PNPM_HOME?.trim() || pnpmHome;
183
+ const pathEntries = [
184
+ configuredPnpmHome,
185
+ path.join(configuredPnpmHome, 'bin'),
186
+ pnpmHome,
187
+ path.join(pnpmHome, 'bin'),
188
+ ...(env.PATH || '').split(path.delimiter).filter(Boolean),
189
+ ];
190
+ return {
191
+ ...env,
192
+ PNPM_HOME: configuredPnpmHome,
193
+ PATH: pathEntries.filter((entry, index, all) => all.indexOf(entry) === index).join(path.delimiter),
194
+ };
195
+ }
148
196
  function runInherited(command, args, env) {
149
197
  const result = spawnSync(command, args, { stdio: 'inherit', env });
150
198
  if (result.error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@foxden-app/foxclaw",
3
- "version": "0.3.14",
3
+ "version": "0.3.15",
4
4
  "description": "Foxden local execution claw for controlling Codex from trusted chat interfaces.",
5
5
  "type": "module",
6
6
  "main": "dist/main.js",