node-command 1.2.1 → 2.0.0
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/bin/nc.mjs +2011 -0
- package/lib/diagnostics-bundle.mjs +587 -0
- package/lib/setup.mjs +333 -0
- package/package.json +26 -27
- package/license +0 -21
- package/readme.md +0 -57
package/lib/setup.mjs
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
// nodecommand setup/remove shared logic.
|
|
2
|
+
//
|
|
3
|
+
// Pure, dependency-free helpers behind the `setup` / `remove` subcommands so
|
|
4
|
+
// the mode decision table and install-root detection stay unit-testable with
|
|
5
|
+
// injected platform/privilege probes (no process mocking needed).
|
|
6
|
+
|
|
7
|
+
import child_process from 'node:child_process';
|
|
8
|
+
import fs from 'node:fs';
|
|
9
|
+
import os from 'node:os';
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
|
|
12
|
+
/** Single-line notice printed when setup falls back to user mode. */
|
|
13
|
+
export const LIMITED_CAPS_WARNING =
|
|
14
|
+
'limited: privileged_shell_exec and container tools are off (re-run as administrator for full capabilities)';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Detects Windows administrator rights via `net session` (exit 0 ⇔ admin).
|
|
18
|
+
* Never throws: any failure means "not admin".
|
|
19
|
+
* @param {(cmd: string, args: string[]) => { status: number|null }} [run]
|
|
20
|
+
*/
|
|
21
|
+
export function detectWindowsAdmin(run = null) {
|
|
22
|
+
try {
|
|
23
|
+
const runner =
|
|
24
|
+
run ||
|
|
25
|
+
((cmd, args) => {
|
|
26
|
+
try {
|
|
27
|
+
const r = child_process.spawnSync(cmd, args, { stdio: 'ignore' });
|
|
28
|
+
return { status: typeof r.status === 'number' ? r.status : 1 };
|
|
29
|
+
} catch {
|
|
30
|
+
return { status: 1 };
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
return runner('net', ['session']).status === 0;
|
|
34
|
+
} catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* True when the current process can perform a machine-wide (system) install.
|
|
41
|
+
* Privilege probes are injectable for deterministic tests.
|
|
42
|
+
* @param {{ platform?: string, getuid?: (() => number)|null, isAdmin?: boolean|null, runAdminCheck?: (() => boolean)|null }} [options]
|
|
43
|
+
*/
|
|
44
|
+
export function isElevated({ platform = os.platform(), getuid = null, isAdmin = null, runAdminCheck = null } = {}) {
|
|
45
|
+
if (platform === 'win32') {
|
|
46
|
+
if (typeof isAdmin === 'boolean') return isAdmin;
|
|
47
|
+
if (typeof runAdminCheck === 'function') {
|
|
48
|
+
try {
|
|
49
|
+
return !!runAdminCheck();
|
|
50
|
+
} catch {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return detectWindowsAdmin();
|
|
55
|
+
}
|
|
56
|
+
const getter = typeof getuid === 'function' ? getuid : typeof process.getuid === 'function' ? process.getuid : null;
|
|
57
|
+
if (typeof getter !== 'function') return false;
|
|
58
|
+
try {
|
|
59
|
+
return getter() === 0;
|
|
60
|
+
} catch {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Automatic install-mode decision. The user is never asked: elevated
|
|
67
|
+
* processes install machine-wide, everything else installs per-user.
|
|
68
|
+
* @param {{ platform?: string, getuid?: (() => number)|null, isAdmin?: boolean|null, runAdminCheck?: (() => boolean)|null }} [options]
|
|
69
|
+
* @returns {'system'|'user'}
|
|
70
|
+
*/
|
|
71
|
+
export function decideInstallMode(options = {}) {
|
|
72
|
+
return isElevated(options) ? 'system' : 'user';
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* True when the current user CAN elevate to a machine-wide install even when
|
|
77
|
+
* the process is not root yet: an already-elevated process, a Windows
|
|
78
|
+
* standard shell (UAC `Start-Process -Verb RunAs` is always available), or
|
|
79
|
+
* POSIX admin groups (sudo/admin/wheel). Used so a non-root admin is asked
|
|
80
|
+
* for elevation instead of silently degrading to a per-user install
|
|
81
|
+
* (different root, service scope and no privileged helper).
|
|
82
|
+
* @param {{ platform?: string, getuid?: (() => number)|null, isAdmin?: boolean|null, runAdminCheck?: (() => boolean)|null }} [options]
|
|
83
|
+
*/
|
|
84
|
+
export function canElevate(options = {}) {
|
|
85
|
+
if (isElevated(options)) return true;
|
|
86
|
+
const platform = options.platform || os.platform();
|
|
87
|
+
// Windows: a non-elevated process can still relaunch itself through the
|
|
88
|
+
// UAC prompt, so elevation is available even when not administrator.
|
|
89
|
+
if (platform === 'win32') return true;
|
|
90
|
+
try {
|
|
91
|
+
const r = child_process.spawnSync('id', ['-nG'], { encoding: 'utf8' });
|
|
92
|
+
const groups = r && typeof r.stdout === 'string' ? r.stdout : '';
|
|
93
|
+
return /\b(sudo|admin|wheel)\b/.test(groups);
|
|
94
|
+
} catch {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Warning text for the given mode: a single line for user mode, null for
|
|
101
|
+
* system mode (callers assert presence/absence on this, not on stdout).
|
|
102
|
+
* @param {'system'|'user'} mode
|
|
103
|
+
*/
|
|
104
|
+
export function modeWarningFor(mode) {
|
|
105
|
+
return mode === 'user' ? LIMITED_CAPS_WARNING : null;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Environment additions forwarded to the OS installer scripts so the
|
|
110
|
+
* privileged/unprivileged layout matches the CLI mode decision. All three
|
|
111
|
+
* installers (linux/macos/windows) honor NC_MODE; the *_INSTALL flags force
|
|
112
|
+
* the matching branch even when auto-detection would disagree (e.g. a
|
|
113
|
+
* root-owned NC_ROOT reused by a test harness).
|
|
114
|
+
* @param {'system'|'user'} mode
|
|
115
|
+
*/
|
|
116
|
+
export function installerEnvForMode(mode) {
|
|
117
|
+
if (mode === 'user') return { NC_MODE: 'user', NC_USER_INSTALL: '1' };
|
|
118
|
+
return { NC_MODE: 'system', NC_SYSTEM_INSTALL: '1' };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Explicit NC_ROOT overrides the whole candidate list: when the caller names
|
|
123
|
+
* a target tree, only that tree is considered (deterministic for tests and
|
|
124
|
+
* for "remove exactly what I pointed at"). Otherwise both the machine-wide
|
|
125
|
+
* and the per-user tree are listed so `remove` finds installs made under a
|
|
126
|
+
* different privilege level than the current process.
|
|
127
|
+
* @param {{ platform?: string, env?: NodeJS.ProcessEnv, homedir?: string }} [options]
|
|
128
|
+
*/
|
|
129
|
+
export function candidateInstallRoots({ platform = os.platform(), env = process.env, homedir = os.homedir() } = {}) {
|
|
130
|
+
if (env.NC_ROOT) return [env.NC_ROOT];
|
|
131
|
+
const roots = [];
|
|
132
|
+
if (platform === 'win32') {
|
|
133
|
+
const programData = env.ProgramData || 'C:\\ProgramData';
|
|
134
|
+
const localAppData = env.LOCALAPPDATA || path.join(homedir, 'AppData', 'Local');
|
|
135
|
+
roots.push(path.join(programData, 'NC'), path.join(localAppData, 'nc'));
|
|
136
|
+
} else if (platform === 'darwin') {
|
|
137
|
+
roots.push('/opt/nc', path.join(homedir, 'Library', 'Application Support', 'nc'));
|
|
138
|
+
} else {
|
|
139
|
+
const dataHome = env.XDG_DATA_HOME || path.join(homedir, '.local', 'share');
|
|
140
|
+
roots.push('/opt/nc', path.join(dataHome, 'nc'));
|
|
141
|
+
}
|
|
142
|
+
return [...new Set(roots)];
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* True when the directory looks like a real agent tree. Mirrors the safety
|
|
147
|
+
* guard inside the uninstall scripts (config/nc-client.env or app/).
|
|
148
|
+
* @param {string} root
|
|
149
|
+
* @param {(p: string) => boolean} [existsSync]
|
|
150
|
+
*/
|
|
151
|
+
export function isInstallRoot(root, existsSync = fs.existsSync) {
|
|
152
|
+
try {
|
|
153
|
+
return (
|
|
154
|
+
existsSync(path.join(root, 'config', 'nc-client.env')) || existsSync(path.join(root, 'app'))
|
|
155
|
+
);
|
|
156
|
+
} catch {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Tri-state install-tree probe. A root-owned system tree (0750/0700) is
|
|
163
|
+
* unreadable to a non-root caller: a plain boolean would report "nothing to
|
|
164
|
+
* remove" for a machine-wide install that clearly exists, and the sudo path
|
|
165
|
+
* would never be reached. Distinguishes:
|
|
166
|
+
* - 'install' markers readable → normal removal path
|
|
167
|
+
* - 'absent' root directory does not exist
|
|
168
|
+
* - 'foreign' root exists and is traversable but carries no markers
|
|
169
|
+
* - 'unreadable' root exists but markers cannot be stat'ed (EACCES/EPERM)
|
|
170
|
+
* → needs elevation; the uninstaller's own safety guard
|
|
171
|
+
* still refuses non-NC trees when run under sudo.
|
|
172
|
+
* @param {string} root
|
|
173
|
+
* @param {{ statSync?: (p: string) => { isDirectory(): boolean }, accessSync?: (p: string, mode?: number) => void }} [io]
|
|
174
|
+
* @returns {'install'|'absent'|'foreign'|'unreadable'}
|
|
175
|
+
*/
|
|
176
|
+
export function probeInstallRoot(root, io = {}) {
|
|
177
|
+
const statSync = io.statSync || fs.statSync;
|
|
178
|
+
const accessSync = io.accessSync || fs.accessSync;
|
|
179
|
+
try {
|
|
180
|
+
const st = statSync(root);
|
|
181
|
+
if (!st.isDirectory()) return 'foreign';
|
|
182
|
+
} catch (err) {
|
|
183
|
+
return err && err.code === 'ENOENT' ? 'absent' : 'unreadable';
|
|
184
|
+
}
|
|
185
|
+
for (const marker of [path.join(root, 'config', 'nc-client.env'), path.join(root, 'app')]) {
|
|
186
|
+
try {
|
|
187
|
+
accessSync(marker);
|
|
188
|
+
return 'install';
|
|
189
|
+
} catch (err) {
|
|
190
|
+
if (err && (err.code === 'EACCES' || err.code === 'EPERM')) return 'unreadable';
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return 'foreign';
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Removal targets split by accessibility. `install` roots are removed by the
|
|
198
|
+
* local flow; `unreadable` roots (system installs seen from a non-root shell)
|
|
199
|
+
* are routed to the elevated runUninstallerScript path instead of being
|
|
200
|
+
* silently reported as "nothing to remove".
|
|
201
|
+
* @param {{ platform?: string, env?: NodeJS.ProcessEnv, homedir?: string, io?: object }} [options]
|
|
202
|
+
* @returns {{ install: string[], unreadable: string[] }}
|
|
203
|
+
*/
|
|
204
|
+
export function findRemovalTargets({ io = {}, ...rest } = {}) {
|
|
205
|
+
const install = [];
|
|
206
|
+
const unreadable = [];
|
|
207
|
+
for (const root of candidateInstallRoots(rest)) {
|
|
208
|
+
const status = probeInstallRoot(root, io);
|
|
209
|
+
if (status === 'install') install.push(root);
|
|
210
|
+
else if (status === 'unreadable') unreadable.push(root);
|
|
211
|
+
}
|
|
212
|
+
return { install, unreadable };
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Installed roots only, in candidate order.
|
|
217
|
+
* @param {{ platform?: string, env?: NodeJS.ProcessEnv, homedir?: string, existsSync?: (p: string) => boolean }} [options]
|
|
218
|
+
*/
|
|
219
|
+
export function findInstallations({ existsSync = fs.existsSync, ...rest } = {}) {
|
|
220
|
+
return candidateInstallRoots(rest).filter((r) => isInstallRoot(r, existsSync));
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Mode-aware install root. NC_ROOT still wins when set; otherwise the root
|
|
225
|
+
* mirrors the tree the OS installer builds for that mode — critically on
|
|
226
|
+
* win32, where system installs target %ProgramData%\NC while user installs
|
|
227
|
+
* target %LOCALAPPDATA%\nc (getNcRoot() has no notion of mode and would put
|
|
228
|
+
* an admin setup's credentials in the user tree the agent never reads).
|
|
229
|
+
* @param {'system'|'user'} mode
|
|
230
|
+
* @param {{ platform?: string, env?: NodeJS.ProcessEnv, homedir?: string }} [options]
|
|
231
|
+
*/
|
|
232
|
+
export function getNcRootForMode(mode, { platform = os.platform(), env = process.env, homedir = os.homedir() } = {}) {
|
|
233
|
+
if (env.NC_ROOT) return env.NC_ROOT;
|
|
234
|
+
if (platform === 'win32') {
|
|
235
|
+
if (mode === 'system') return path.join(env.ProgramData || 'C:\\ProgramData', 'NC');
|
|
236
|
+
const localAppData = env.LOCALAPPDATA || path.join(homedir, 'AppData', 'Local');
|
|
237
|
+
return path.join(localAppData, 'nc');
|
|
238
|
+
}
|
|
239
|
+
if (mode === 'system') return '/opt/nc';
|
|
240
|
+
if (platform === 'darwin') return path.join(homedir, 'Library', 'Application Support', 'nc');
|
|
241
|
+
const dataHome = env.XDG_DATA_HOME || path.join(homedir, '.local', 'share');
|
|
242
|
+
return path.join(dataHome, 'nc');
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Uninstaller script living inside an installed tree. The scripts are
|
|
247
|
+
* self-locating ($ROOT derived from their own path), so no root argument is
|
|
248
|
+
* passed — presence of the tree itself is the authorization.
|
|
249
|
+
* @param {string} root
|
|
250
|
+
* @param {string} [platform]
|
|
251
|
+
*/
|
|
252
|
+
export function uninstallerForRoot(root, platform = os.platform()) {
|
|
253
|
+
if (platform === 'win32') return path.join(root, 'uninstall.ps1');
|
|
254
|
+
return path.join(root, 'uninstall.sh');
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* Suggested-action line printed when an uninstaller fails. The unix text
|
|
259
|
+
* names the direct recovery command; win32 keeps the generic wording because
|
|
260
|
+
* the .ps1 uninstaller already runs with the caller's own rights (no sudo
|
|
261
|
+
* equivalent is attempted there).
|
|
262
|
+
* @param {string} [platform]
|
|
263
|
+
*/
|
|
264
|
+
export function uninstallFailureSuggestion(platform = os.platform()) {
|
|
265
|
+
const base = 'Re-run with administrator/root rights, then retry.';
|
|
266
|
+
if (platform === 'win32') return `suggested_action: ${base}`;
|
|
267
|
+
return `suggested_action: ${base} (or run: sudo nodecommand remove --yes)`;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Runs one uninstaller script, forwarding the inherited environment.
|
|
272
|
+
*
|
|
273
|
+
* Unix elevation: a system-wide tree is installed by root, so its
|
|
274
|
+
* uninstaller is root-owned (mode 0700) and a non-root caller cannot even
|
|
275
|
+
* read it — plain `bash <script>` always fails there with status 126. When
|
|
276
|
+
* the caller is not root the script is therefore run via `sudo -E bash`,
|
|
277
|
+
* keeping `stdio: 'inherit'` so the sudo password prompt stays visible.
|
|
278
|
+
* When sudo itself is missing (ENOENT) the direct call is retried once so
|
|
279
|
+
* user-owned trees stay removable without sudo; any other sudo failure
|
|
280
|
+
* propagates unchanged and the caller reports the usual [UNINSTALL_FAILED]
|
|
281
|
+
* guidance — behavior never gets worse, it only starts working when sudo
|
|
282
|
+
* exists. Already-root callers run the script directly (no sudo).
|
|
283
|
+
*
|
|
284
|
+
* Security boundary: the caller (runRemove) only ever passes the
|
|
285
|
+
* uninstallerForRoot() path of a tree that already passed the
|
|
286
|
+
* isInstallRoot() check inside findInstallations() — elevation is never
|
|
287
|
+
* applied to an arbitrary path. Windows is untouched: the .ps1 uninstaller
|
|
288
|
+
* runs with the caller's own rights, so no elevation is attempted there.
|
|
289
|
+
* @param {string} scriptPath
|
|
290
|
+
* @param {string|{ platform?: string, execFile?: (cmd: string, args: string[], opts?: object) => unknown, getuid?: (() => number)|null }} [platform]
|
|
291
|
+
* @param {{ execFile?: (cmd: string, args: string[], opts?: object) => unknown, getuid?: (() => number)|null }} [options]
|
|
292
|
+
*/
|
|
293
|
+
export function runUninstallerScript(scriptPath, platform = os.platform(), options = {}) {
|
|
294
|
+
let opts = options || {};
|
|
295
|
+
if (typeof platform !== 'string') {
|
|
296
|
+
opts = platform || {};
|
|
297
|
+
platform = opts.platform || os.platform();
|
|
298
|
+
}
|
|
299
|
+
const execFile = opts.execFile || child_process.execFileSync;
|
|
300
|
+
if (platform === 'win32') {
|
|
301
|
+
execFile(
|
|
302
|
+
'powershell.exe',
|
|
303
|
+
['-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', scriptPath],
|
|
304
|
+
{ stdio: 'inherit' }
|
|
305
|
+
);
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
const getuid =
|
|
309
|
+
typeof opts.getuid === 'function'
|
|
310
|
+
? opts.getuid
|
|
311
|
+
: typeof process.getuid === 'function'
|
|
312
|
+
? () => process.getuid()
|
|
313
|
+
: null;
|
|
314
|
+
let uid = null;
|
|
315
|
+
try {
|
|
316
|
+
uid = typeof getuid === 'function' ? getuid() : null;
|
|
317
|
+
} catch {
|
|
318
|
+
uid = null;
|
|
319
|
+
}
|
|
320
|
+
if (uid === 0) {
|
|
321
|
+
execFile('bash', [scriptPath], { stdio: 'inherit' });
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
try {
|
|
325
|
+
execFile('sudo', ['-E', 'bash', scriptPath], { stdio: 'inherit' });
|
|
326
|
+
} catch (err) {
|
|
327
|
+
// Without a sudo binary there is nothing to elevate with: retry the
|
|
328
|
+
// historical direct call so user-owned trees stay removable. Any other
|
|
329
|
+
// sudo failure (denied, wrong password, script error) propagates.
|
|
330
|
+
if (!err || err.code !== 'ENOENT') throw err;
|
|
331
|
+
execFile('bash', [scriptPath], { stdio: 'inherit' });
|
|
332
|
+
}
|
|
333
|
+
}
|
package/package.json
CHANGED
|
@@ -1,39 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-command",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
5
|
-
"
|
|
6
|
-
"
|
|
7
|
-
"test": "mocha test.js"
|
|
8
|
-
},
|
|
9
|
-
"engines": {
|
|
10
|
-
"node": ">=0.10.0"
|
|
11
|
-
},
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Node Command agent CLI — connect this machine to your AI assistant fleet",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "Apache-2.0",
|
|
12
7
|
"bin": {
|
|
13
|
-
"
|
|
8
|
+
"node-command": "./bin/nc.mjs",
|
|
9
|
+
"nodecommand": "./bin/nc.mjs",
|
|
10
|
+
"nc-agent": "./bin/nc.mjs",
|
|
11
|
+
"nc": "./bin/nc.mjs"
|
|
14
12
|
},
|
|
15
13
|
"files": [
|
|
16
|
-
"
|
|
14
|
+
"bin/",
|
|
15
|
+
"lib/"
|
|
17
16
|
],
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=20"
|
|
19
|
+
},
|
|
20
|
+
"keywords": [
|
|
21
|
+
"node-command",
|
|
22
|
+
"nodecommand",
|
|
23
|
+
"mcp",
|
|
24
|
+
"remote",
|
|
25
|
+
"ai-assistant",
|
|
26
|
+
"agent",
|
|
27
|
+
"cli"
|
|
28
|
+
],
|
|
29
|
+
"homepage": "https://github.com/huseyincig/NodeCommand",
|
|
18
30
|
"repository": {
|
|
19
31
|
"type": "git",
|
|
20
|
-
"url": "https://github.com/
|
|
32
|
+
"url": "git+https://github.com/huseyincig/NodeCommand.git"
|
|
21
33
|
},
|
|
22
|
-
"author": "legodude17 <legodudejb@gmail.com> (https://github.com/legodude17)",
|
|
23
|
-
"license": "MIT",
|
|
24
34
|
"bugs": {
|
|
25
|
-
"url": "https://github.com/
|
|
26
|
-
},
|
|
27
|
-
"homepage": "https://github.com/node-command",
|
|
28
|
-
"dependencies": {
|
|
29
|
-
"async": "^2.0.0-rc.6",
|
|
30
|
-
"asynquence": "^0.9.0",
|
|
31
|
-
"common-callback-names": "^1.0.2",
|
|
32
|
-
"function-args": "^1.0.2",
|
|
33
|
-
"is-executable": "^1.0.1",
|
|
34
|
-
"minimist": "^1.2.0"
|
|
35
|
+
"url": "https://github.com/huseyincig/NodeCommand/issues"
|
|
35
36
|
},
|
|
36
|
-
"
|
|
37
|
-
"mocha": "2.2.5"
|
|
38
|
-
}
|
|
37
|
+
"author": "Hüseyin Hadi Çığ <huseyincig@users.noreply.github.com>"
|
|
39
38
|
}
|
package/license
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
The MIT License (MIT)
|
|
2
|
-
|
|
3
|
-
Copyright (c) legodude17 <legodudejb@gmail.com> (https://github.com/)
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in
|
|
13
|
-
all copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
-
THE SOFTWARE.
|
package/readme.md
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
# node-command [![Build Status][travis-badge]][travis-link] [![Dependency Status][gemnasium-badge]][gemnasium-link]
|
|
2
|
-
> A command runner with node support.
|
|
3
|
-
|
|
4
|
-
## Install
|
|
5
|
-
|
|
6
|
-
```sh
|
|
7
|
-
$ npm install --save node-command
|
|
8
|
-
```
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
## Usage
|
|
12
|
-
|
|
13
|
-
```js
|
|
14
|
-
var nodeCommand = require('node-command');
|
|
15
|
-
|
|
16
|
-
nodeCommand(
|
|
17
|
-
name, // The name to try
|
|
18
|
-
args, // Arguments to pass
|
|
19
|
-
options, // The options
|
|
20
|
-
cb // Callback
|
|
21
|
-
);
|
|
22
|
-
```
|
|
23
|
-
### Options
|
|
24
|
-
#### Silent
|
|
25
|
-
Type: `boolean`
|
|
26
|
-
Default: `false`
|
|
27
|
-
Suppress all messages.
|
|
28
|
-
#### Error log
|
|
29
|
-
Type: `boolean`
|
|
30
|
-
Default: `false`
|
|
31
|
-
Show error messages from `child_process.execFile`.
|
|
32
|
-
## CLI
|
|
33
|
-
|
|
34
|
-
```sh
|
|
35
|
-
$ npm install -g node-command
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
```sh
|
|
39
|
-
$ nand --help
|
|
40
|
-
|
|
41
|
-
Usage: nand [options] -- <file> [args...]
|
|
42
|
-
|
|
43
|
-
Options:
|
|
44
|
-
-e | --error-log Log errors from child processes
|
|
45
|
-
-s | --silent Suppress all messages.
|
|
46
|
-
Example
|
|
47
|
-
nand -e -- node example.js
|
|
48
|
-
```
|
|
49
|
-
## License
|
|
50
|
-
|
|
51
|
-
MIT © [legodude17](https://github.com/legodude17)
|
|
52
|
-
|
|
53
|
-
[travis-badge]: http://img.shields.io/travis/node-command.svg?style=flat-square
|
|
54
|
-
[travis-link]: https://travis-ci.org/node-command
|
|
55
|
-
|
|
56
|
-
[gemnasium-badge]: http://img.shields.io/gemnasium/node-command.svg?style=flat-square
|
|
57
|
-
[gemnasium-link]: https://gemnasium.com/node-command
|