windsor-bot 0.2.6 → 0.2.7

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.
Files changed (2) hide show
  1. package/dist/server.js +37 -10
  2. package/package.json +1 -1
package/dist/server.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { createServer } from 'http';
2
2
  import { execFile } from 'child_process';
3
3
  import { build } from 'esbuild';
4
- import { access, readFile, stat } from 'fs/promises';
4
+ import { access, constants, readFile, stat } from 'fs/promises';
5
5
  import { promisify } from 'util';
6
6
  import { spawn } from 'child_process';
7
7
  import { dirname, join } from 'path';
@@ -65,7 +65,7 @@ async function readPackageVersion() {
65
65
  return packageJson.version;
66
66
  }
67
67
  async function updateGlobalBot() {
68
- const npmCandidates = [
68
+ const configuredCandidates = [
69
69
  process.env['npm_execpath'],
70
70
  join(dirname(process.execPath), '..', 'lib', 'node_modules', 'npm', 'bin', 'npm-cli.js'),
71
71
  join(dirname(process.execPath), 'npm'),
@@ -76,11 +76,17 @@ async function updateGlobalBot() {
76
76
  '/usr/local/bin/npm',
77
77
  '/opt/homebrew/bin/npm',
78
78
  '/usr/bin/npm',
79
- 'npm',
80
79
  ]
81
80
  .filter((candidate) => Boolean(candidate))
82
81
  .map(candidate => candidate.trim())
83
82
  .filter((candidate, index, candidates) => candidates.indexOf(candidate) === index);
83
+ const pathCandidates = (process.env['PATH'] ?? '')
84
+ .split(':')
85
+ .filter(Boolean)
86
+ .map(directory => join(directory, 'npm'));
87
+ const npmCandidates = [...configuredCandidates, ...pathCandidates]
88
+ .filter((candidate, index, candidates) => candidates.indexOf(candidate) === index);
89
+ logEvent('info', `Update requested; checking ${npmCandidates.length} npm candidate(s) (node=${process.execPath}, cwd=${process.cwd()})`);
84
90
  let npmCommand;
85
91
  for (const candidate of npmCandidates) {
86
92
  const command = candidate.endsWith('.js')
@@ -88,19 +94,40 @@ async function updateGlobalBot() {
88
94
  : { path: candidate, args: [] };
89
95
  try {
90
96
  // Validate the script itself, not just the Node executable used to run it.
91
- if (candidate !== 'npm')
92
- await access(candidate);
97
+ await access(candidate, constants.R_OK | (candidate.endsWith('.js') ? 0 : constants.X_OK));
93
98
  npmCommand = command;
99
+ logEvent('info', `Using npm candidate ${candidate}${command.args.length > 0 ? ` via ${command.path}` : ''}`);
94
100
  break;
95
101
  }
96
- catch {
97
- // Try the next known npm installation location.
102
+ catch (error) {
103
+ const code = error instanceof Error && 'code' in error ? String(error.code) : 'unknown';
104
+ logEvent('info', `npm candidate unavailable: ${candidate} (${code})`);
98
105
  }
99
106
  }
100
- if (!npmCommand)
101
- throw new Error('Unable to locate npm');
107
+ if (!npmCommand) {
108
+ const path = process.env['PATH'] ?? '(unset)';
109
+ logEvent('error', `Unable to locate an executable npm; PATH=${path}`);
110
+ throw new Error('Unable to locate an executable npm; see diagnostics');
111
+ }
102
112
  const npm = npmCommand;
103
- const runNpm = (args) => execFileAsync(npm.path, [...npm.args, ...args], { env: process.env });
113
+ const runNpm = async (args) => {
114
+ const commandArgs = [...npm.args, ...args];
115
+ logEvent('info', `Running npm: ${npm.path} ${commandArgs.join(' ')}`);
116
+ try {
117
+ const result = await execFileAsync(npm.path, commandArgs, { env: process.env });
118
+ logEvent('info', `npm completed successfully: ${args.join(' ')}`);
119
+ return result;
120
+ }
121
+ catch (error) {
122
+ const details = error instanceof Error ? error : new Error(String(error));
123
+ const code = 'code' in details ? String(details.code) : 'unknown';
124
+ const stderr = 'stderr' in details && typeof details.stderr === 'string'
125
+ ? details.stderr.trim().slice(-1000)
126
+ : '';
127
+ logEvent('error', `npm failed (code=${code}, path=${npm.path}, args=${commandArgs.join(' ')})${stderr ? ` stderr=${stderr}` : ''}`);
128
+ throw details;
129
+ }
130
+ };
104
131
  await runNpm(['install', '-g', 'windsor-bot@latest']);
105
132
  const { stdout } = await runNpm(['root', '-g']);
106
133
  const packageJsonPath = join(stdout.trim(), 'windsor-bot', 'package.json');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "windsor-bot",
3
- "version": "0.2.6",
3
+ "version": "0.2.7",
4
4
  "description": "Self-hosted Discord bot automation for household list and todo printing",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",