unitup 0.1.4 → 0.1.5

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/CHANGELOG.md CHANGED
@@ -16,6 +16,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
16
16
  - Biome (`@biomejs/biome`) developer tool integration for code linting and formatting (`npm run check`, `npm run format`, `npm run lint`).
17
17
  - `CHANGELOG.md` tracking project release history and changes.
18
18
 
19
+ ### Fixed
20
+ - Fixed script argument resolution in all runtime adapters (`node`, `python`, `ruby`, `php`, `bun`, `deno`, `shell`, `go`, `elixir`, `native`) to resolve relative script paths against `opts.cwd` instead of `process.cwd()`.
21
+
19
22
  ## [0.1.3] - 2026-07-31
20
23
 
21
24
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "unitup",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "Minimal, zero-dependency systemd-native service manager for any runtime, script, or executable",
5
5
  "main": "src/index.js",
6
6
  "types": "./index.d.ts",
@@ -3,11 +3,12 @@ import fs from 'node:fs';
3
3
  import { findRuntimeExecutable, getBinaryVersion } from './common.js';
4
4
 
5
5
  export async function createBunAdapter(opts = {}) {
6
+ const baseDir = opts.cwd || process.cwd();
6
7
  const customPath = opts.command;
7
8
  let execPath = null;
8
9
 
9
10
  if (customPath) {
10
- const absPath = path.resolve(process.cwd(), customPath);
11
+ const absPath = path.resolve(baseDir, customPath);
11
12
  if (fs.existsSync(absPath)) {
12
13
  try {
13
14
  fs.accessSync(absPath, fs.constants.X_OK);
@@ -27,7 +28,7 @@ export async function createBunAdapter(opts = {}) {
27
28
  }
28
29
 
29
30
  const version = await getBinaryVersion(execPath, '-v');
30
- const scriptPath = opts.script ? path.resolve(process.cwd(), opts.script) : null;
31
+ const scriptPath = opts.script ? path.resolve(baseDir, opts.script) : null;
31
32
  const runtimeArgs = Array.isArray(opts.runtimeArgs) ? opts.runtimeArgs : [];
32
33
  const scriptArgs = Array.isArray(opts.args) ? opts.args : [];
33
34
 
@@ -3,11 +3,12 @@ import fs from 'node:fs';
3
3
  import { findRuntimeExecutable, getBinaryVersion } from './common.js';
4
4
 
5
5
  export async function createDenoAdapter(opts = {}) {
6
+ const baseDir = opts.cwd || process.cwd();
6
7
  const customPath = opts.command;
7
8
  let execPath = null;
8
9
 
9
10
  if (customPath) {
10
- const absPath = path.resolve(process.cwd(), customPath);
11
+ const absPath = path.resolve(baseDir, customPath);
11
12
  if (fs.existsSync(absPath)) {
12
13
  try {
13
14
  fs.accessSync(absPath, fs.constants.X_OK);
@@ -27,7 +28,7 @@ export async function createDenoAdapter(opts = {}) {
27
28
  }
28
29
 
29
30
  const version = await getBinaryVersion(execPath, '--version');
30
- const scriptPath = opts.script ? path.resolve(process.cwd(), opts.script) : null;
31
+ const scriptPath = opts.script ? path.resolve(baseDir, opts.script) : null;
31
32
  const runtimeArgs = Array.isArray(opts.runtimeArgs) ? opts.runtimeArgs : [];
32
33
  const scriptArgs = Array.isArray(opts.args) ? opts.args : [];
33
34
 
@@ -3,11 +3,12 @@ import fs from 'node:fs';
3
3
  import { findRuntimeExecutable, getBinaryVersion } from './common.js';
4
4
 
5
5
  export async function createElixirAdapter(opts = {}) {
6
+ const baseDir = opts.cwd || process.cwd();
6
7
  const customPath = opts.command;
7
8
  let execPath = null;
8
9
 
9
10
  if (customPath) {
10
- const absPath = path.resolve(process.cwd(), customPath);
11
+ const absPath = path.resolve(baseDir, customPath);
11
12
  if (fs.existsSync(absPath)) {
12
13
  try {
13
14
  fs.accessSync(absPath, fs.constants.X_OK);
@@ -27,7 +28,7 @@ export async function createElixirAdapter(opts = {}) {
27
28
  }
28
29
 
29
30
  const version = await getBinaryVersion(execPath, '-v');
30
- const scriptPath = opts.script ? path.resolve(process.cwd(), opts.script) : null;
31
+ const scriptPath = opts.script ? path.resolve(baseDir, opts.script) : null;
31
32
  const runtimeArgs = Array.isArray(opts.runtimeArgs) ? opts.runtimeArgs : [];
32
33
  const scriptArgs = Array.isArray(opts.args) ? opts.args : [];
33
34
 
@@ -3,11 +3,12 @@ import fs from 'node:fs';
3
3
  import { findRuntimeExecutable, getBinaryVersion } from './common.js';
4
4
 
5
5
  export async function createGoAdapter(opts = {}) {
6
+ const baseDir = opts.cwd || process.cwd();
6
7
  const customPath = opts.command;
7
8
  let execPath = null;
8
9
 
9
10
  if (customPath) {
10
- const absPath = path.resolve(process.cwd(), customPath);
11
+ const absPath = path.resolve(baseDir, customPath);
11
12
  if (fs.existsSync(absPath)) {
12
13
  try {
13
14
  fs.accessSync(absPath, fs.constants.X_OK);
@@ -27,7 +28,7 @@ export async function createGoAdapter(opts = {}) {
27
28
  }
28
29
 
29
30
  const version = await getBinaryVersion(execPath, 'version');
30
- const scriptPath = opts.script ? path.resolve(process.cwd(), opts.script) : null;
31
+ const scriptPath = opts.script ? path.resolve(baseDir, opts.script) : null;
31
32
  const runtimeArgs = Array.isArray(opts.runtimeArgs) ? opts.runtimeArgs : [];
32
33
  const scriptArgs = Array.isArray(opts.args) ? opts.args : [];
33
34
 
@@ -11,7 +11,7 @@ import { createNativeAdapter } from './native.js';
11
11
  import { createGoAdapter } from './go.js';
12
12
  import { createElixirAdapter } from './elixir.js';
13
13
 
14
- export function detectRuntime(filepath) {
14
+ export function detectRuntime(filepath, opts = {}) {
15
15
  if (!filepath) {
16
16
  throw new Error('Script path or command is required for runtime detection.');
17
17
  }
@@ -42,7 +42,8 @@ export function detectRuntime(filepath) {
42
42
  }
43
43
 
44
44
  // Inspect shebang header if file exists
45
- const absPath = path.resolve(process.cwd(), filepath);
45
+ const baseDir = opts.cwd || process.cwd();
46
+ const absPath = path.resolve(baseDir, filepath);
46
47
  if (fs.existsSync(absPath)) {
47
48
  try {
48
49
  const fd = fs.openSync(absPath, 'r');
@@ -85,9 +86,11 @@ export function detectRuntime(filepath) {
85
86
  }
86
87
 
87
88
  export async function resolveRuntimeConfig(opts = {}) {
89
+ const baseDir = opts.cwd || process.cwd();
90
+
88
91
  // 1. If explicit --command is provided, bypass runtime auto-detection
89
92
  if (opts.command) {
90
- const absCommand = path.resolve(process.cwd(), opts.command);
93
+ const absCommand = path.resolve(baseDir, opts.command);
91
94
  if (!fs.existsSync(absCommand)) {
92
95
  // If binary doesn't exist as exact file path, check if it's in PATH or native executable
93
96
  const { findRuntimeExecutable } = await import('./common.js');
@@ -116,7 +119,7 @@ export async function resolveRuntimeConfig(opts = {}) {
116
119
  // 2. Resolve target runtime name
117
120
  let runtimeName = opts.runtime;
118
121
  if (!runtimeName) {
119
- runtimeName = detectRuntime(opts.script);
122
+ runtimeName = detectRuntime(opts.script, opts);
120
123
  }
121
124
 
122
125
  const cleanRuntime = runtimeName.toLowerCase();
@@ -2,13 +2,14 @@ import path from 'node:path';
2
2
  import fs from 'node:fs';
3
3
 
4
4
  export async function createNativeAdapter(opts = {}) {
5
+ const baseDir = opts.cwd || process.cwd();
5
6
  const targetPath = opts.script || opts.command;
6
7
 
7
8
  if (!targetPath) {
8
9
  throw new Error('Native executable path is required.');
9
10
  }
10
11
 
11
- const absPath = path.resolve(process.cwd(), targetPath);
12
+ const absPath = path.resolve(baseDir, targetPath);
12
13
 
13
14
  if (!fs.existsSync(absPath)) {
14
15
  throw new Error(`Executable file does not exist: ${absPath}`);
@@ -3,11 +3,12 @@ import fs from 'node:fs';
3
3
  import { findRuntimeExecutable, getBinaryVersion } from './common.js';
4
4
 
5
5
  export async function createNodeAdapter(opts = {}) {
6
+ const baseDir = opts.cwd || process.cwd();
6
7
  const customPath = opts.command || opts.nodePath;
7
8
  let execPath = null;
8
9
 
9
10
  if (customPath) {
10
- const absPath = path.resolve(process.cwd(), customPath);
11
+ const absPath = path.resolve(baseDir, customPath);
11
12
  if (fs.existsSync(absPath)) {
12
13
  try {
13
14
  fs.accessSync(absPath, fs.constants.X_OK);
@@ -38,7 +39,7 @@ export async function createNodeAdapter(opts = {}) {
38
39
  }
39
40
 
40
41
  const version = await getBinaryVersion(execPath, '-v');
41
- const scriptPath = opts.script ? path.resolve(process.cwd(), opts.script) : null;
42
+ const scriptPath = opts.script ? path.resolve(baseDir, opts.script) : null;
42
43
  const runtimeArgs = Array.isArray(opts.runtimeArgs) ? opts.runtimeArgs : [];
43
44
  const scriptArgs = Array.isArray(opts.args) ? opts.args : [];
44
45
 
@@ -3,11 +3,12 @@ import fs from 'node:fs';
3
3
  import { findRuntimeExecutable, getBinaryVersion } from './common.js';
4
4
 
5
5
  export async function createPhpAdapter(opts = {}) {
6
+ const baseDir = opts.cwd || process.cwd();
6
7
  const customPath = opts.command;
7
8
  let execPath = null;
8
9
 
9
10
  if (customPath) {
10
- const absPath = path.resolve(process.cwd(), customPath);
11
+ const absPath = path.resolve(baseDir, customPath);
11
12
  if (fs.existsSync(absPath)) {
12
13
  try {
13
14
  fs.accessSync(absPath, fs.constants.X_OK);
@@ -27,7 +28,7 @@ export async function createPhpAdapter(opts = {}) {
27
28
  }
28
29
 
29
30
  const version = await getBinaryVersion(execPath, '-v');
30
- const scriptPath = opts.script ? path.resolve(process.cwd(), opts.script) : null;
31
+ const scriptPath = opts.script ? path.resolve(baseDir, opts.script) : null;
31
32
  const runtimeArgs = Array.isArray(opts.runtimeArgs) ? opts.runtimeArgs : [];
32
33
  const scriptArgs = Array.isArray(opts.args) ? opts.args : [];
33
34
 
@@ -3,11 +3,12 @@ import fs from 'node:fs';
3
3
  import { findRuntimeExecutable, getBinaryVersion } from './common.js';
4
4
 
5
5
  export async function createPythonAdapter(opts = {}) {
6
+ const baseDir = opts.cwd || process.cwd();
6
7
  const customPath = opts.command;
7
8
  let execPath = null;
8
9
 
9
10
  if (customPath) {
10
- const absPath = path.resolve(process.cwd(), customPath);
11
+ const absPath = path.resolve(baseDir, customPath);
11
12
  if (fs.existsSync(absPath)) {
12
13
  try {
13
14
  fs.accessSync(absPath, fs.constants.X_OK);
@@ -27,7 +28,7 @@ export async function createPythonAdapter(opts = {}) {
27
28
  }
28
29
 
29
30
  const version = await getBinaryVersion(execPath, '--version');
30
- const scriptPath = opts.script ? path.resolve(process.cwd(), opts.script) : null;
31
+ const scriptPath = opts.script ? path.resolve(baseDir, opts.script) : null;
31
32
  const runtimeArgs = Array.isArray(opts.runtimeArgs) ? opts.runtimeArgs : [];
32
33
  const scriptArgs = Array.isArray(opts.args) ? opts.args : [];
33
34
 
@@ -3,11 +3,12 @@ import fs from 'node:fs';
3
3
  import { findRuntimeExecutable, getBinaryVersion } from './common.js';
4
4
 
5
5
  export async function createRubyAdapter(opts = {}) {
6
+ const baseDir = opts.cwd || process.cwd();
6
7
  const customPath = opts.command;
7
8
  let execPath = null;
8
9
 
9
10
  if (customPath) {
10
- const absPath = path.resolve(process.cwd(), customPath);
11
+ const absPath = path.resolve(baseDir, customPath);
11
12
  if (fs.existsSync(absPath)) {
12
13
  try {
13
14
  fs.accessSync(absPath, fs.constants.X_OK);
@@ -27,7 +28,7 @@ export async function createRubyAdapter(opts = {}) {
27
28
  }
28
29
 
29
30
  const version = await getBinaryVersion(execPath, '-v');
30
- const scriptPath = opts.script ? path.resolve(process.cwd(), opts.script) : null;
31
+ const scriptPath = opts.script ? path.resolve(baseDir, opts.script) : null;
31
32
  const runtimeArgs = Array.isArray(opts.runtimeArgs) ? opts.runtimeArgs : [];
32
33
  const scriptArgs = Array.isArray(opts.args) ? opts.args : [];
33
34
 
@@ -3,11 +3,12 @@ import fs from 'node:fs';
3
3
  import { findRuntimeExecutable, getBinaryVersion } from './common.js';
4
4
 
5
5
  export async function createShellAdapter(opts = {}) {
6
+ const baseDir = opts.cwd || process.cwd();
6
7
  const customPath = opts.command;
7
8
  let execPath = null;
8
9
 
9
10
  if (customPath) {
10
- const absPath = path.resolve(process.cwd(), customPath);
11
+ const absPath = path.resolve(baseDir, customPath);
11
12
  if (fs.existsSync(absPath)) {
12
13
  try {
13
14
  fs.accessSync(absPath, fs.constants.X_OK);
@@ -27,7 +28,7 @@ export async function createShellAdapter(opts = {}) {
27
28
  }
28
29
 
29
30
  const version = await getBinaryVersion(execPath, '--version');
30
- const scriptPath = opts.script ? path.resolve(process.cwd(), opts.script) : null;
31
+ const scriptPath = opts.script ? path.resolve(baseDir, opts.script) : null;
31
32
  const runtimeArgs = Array.isArray(opts.runtimeArgs) ? opts.runtimeArgs : [];
32
33
  const scriptArgs = Array.isArray(opts.args) ? opts.args : [];
33
34