clyops-jobs 0.6.0 → 0.8.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/README.md CHANGED
@@ -63,7 +63,7 @@ record = transitionJobRecord(record, { status: 'done', completedAt: timestampIso
63
63
  `runScriptFunction` options: `configRoot` (relative path options resolve against it),
64
64
  `context`, `controlled` (options the trigger sets itself, default `['help']`), `defaultPositional`
65
65
  (a template for the first argument when the config gives none, e.g. `'${media.path}'`),
66
- `timeoutMs`, `env`, `cwd`, `signal`, `onStderr`, `onProgress`, `onLog`. Its `command` shows secret options as `***`.
66
+ `timeoutMs`, `killGraceMs`, `env`, `cwd`, `signal`, `onStderr`, `onProgress`, `onLog`. Its `command` shows secret options as `***`.
67
67
 
68
68
  When the tool declares the well-known [roles](https://github.com/wankdanker/clyops/blob/main/spec/SPEC.md#14-roles-on-file-descriptors),
69
69
  the run wires them up: each `progress` object goes to `onProgress` (and the last one is the run's
package/clyops-jobs.cjs CHANGED
@@ -230,6 +230,9 @@ var InputError = class extends Error {
230
230
  function isPathValued(validation, type) {
231
231
  return type === "path" || validation === "path" || validation.startsWith("file:") || validation.startsWith("dir:");
232
232
  }
233
+ function isBareProgram(validation, value) {
234
+ return validation === "file:executable" && value !== "" && !value.includes("/") && !(process.platform === "win32" && value.includes("\\"));
235
+ }
233
236
  var TRUE = /^(true|1|yes|on)$/i;
234
237
  var FALSE = /^(false|0|no|off)$/i;
235
238
  function toArgv(schema, input, opts = {}) {
@@ -244,9 +247,10 @@ function toArgv(schema, input, opts = {}) {
244
247
  }
245
248
  return void 0;
246
249
  };
247
- const text = (value, pathValued, name = "") => {
250
+ const text = (value, pathValued, name = "", validation = "") => {
248
251
  let s = typeof value === "object" ? JSON.stringify(value) : String(value);
249
252
  if (opts.render) s = opts.render(s);
253
+ if (isBareProgram(validation, s)) return s;
250
254
  if (pathValued && opts.base && !["", "-", "disabled", "false"].includes(s) && !(0, import_node_path2.isAbsolute)(s) && !/^[a-z][a-z0-9+.-]*:\/\//i.test(s)) {
251
255
  s = (0, import_node_path2.resolve)(opts.base, s);
252
256
  }
@@ -273,11 +277,11 @@ function toArgv(schema, input, opts = {}) {
273
277
  continue;
274
278
  }
275
279
  if (opts.secretEnv && option.secret && !option.isArray) {
276
- out.env[option.variableName] = text(found.value, isPathValued(option.validation, option.type), `--${option.name}`);
280
+ out.env[option.variableName] = text(found.value, isPathValued(option.validation, option.type), `--${option.name}`, option.validation);
277
281
  continue;
278
282
  }
279
283
  for (const item of Array.isArray(found.value) ? found.value : [found.value]) {
280
- out.argv.push(`--${option.name}`, text(item, isPathValued(option.validation, option.type), `--${option.name}`));
284
+ out.argv.push(`--${option.name}`, text(item, isPathValued(option.validation, option.type), `--${option.name}`, option.validation));
281
285
  }
282
286
  }
283
287
  const explicit = Array.isArray(opts.positionals) ? opts.positionals : void 0;
@@ -288,6 +292,11 @@ function toArgv(schema, input, opts = {}) {
288
292
  let skipped = [];
289
293
  for (const argument of schema.arguments) {
290
294
  const found = pick(argument);
295
+ if (found && opts.controlled?.includes(argument.name)) {
296
+ out.controlled.push(found.key);
297
+ skipped.push(argument);
298
+ continue;
299
+ }
291
300
  if (!found || found.value === null || found.value === void 0) {
292
301
  skipped.push(argument);
293
302
  continue;
@@ -298,7 +307,7 @@ function toArgv(schema, input, opts = {}) {
298
307
  }
299
308
  skipped = [];
300
309
  const values = Array.isArray(found.value) ? found.value : [found.value];
301
- positionals.push(...values.map((v) => text(v, isPathValued(argument.validation), argument.name)));
310
+ positionals.push(...values.map((v) => text(v, isPathValued(argument.validation), argument.name, argument.validation)));
302
311
  }
303
312
  }
304
313
  if (positionals.some((p) => p.startsWith("-"))) out.argv.push("--", ...positionals);
@@ -345,8 +354,9 @@ var import_node_child_process2 = require("node:child_process");
345
354
  var import_node_stream = require("node:stream");
346
355
  var import_node_string_decoder = require("node:string_decoder");
347
356
  var ROLE_NAME = /^[A-Za-z][A-Za-z0-9_.-]*$/;
348
- var ABORT_GRACE_MS = 200;
357
+ var KILL_GRACE_MS = 200;
349
358
  var STOP_WAIT_MS = 1e3;
359
+ var MAX_DELAY_MS = 2 ** 31 - 1;
350
360
  function terminateTree(child, signal) {
351
361
  const pid = child.pid;
352
362
  if (!pid || pid <= 0) return Promise.resolve();
@@ -381,6 +391,8 @@ function start(file, argv, opts = {}) {
381
391
  windowsHide: true
382
392
  });
383
393
  const limit = opts.maxOutput || Infinity;
394
+ const grace = Number(opts.killGraceMs ?? KILL_GRACE_MS);
395
+ const killGraceMs = Number.isNaN(grace) ? KILL_GRACE_MS : Math.min(Math.max(0, grace), MAX_DELAY_MS - STOP_WAIT_MS);
384
396
  let truncated = false;
385
397
  const collect = (stream, onChunk) => {
386
398
  const chunks = [];
@@ -489,10 +501,11 @@ function start(file, argv, opts = {}) {
489
501
  clearTimeout(timer);
490
502
  treeStopped = terminateTree(child, signal);
491
503
  closeInput();
504
+ const grace2 = signal === "SIGTERM" ? killGraceMs : 0;
492
505
  if (signal === "SIGTERM") {
493
506
  escalation = setTimeout(() => {
494
507
  treeStopped = terminateTree(child, "SIGKILL");
495
- }, ABORT_GRACE_MS);
508
+ }, grace2);
496
509
  }
497
510
  deadline = setTimeout(() => {
498
511
  treeStopped = terminateTree(child, "SIGKILL");
@@ -504,7 +517,7 @@ function start(file, argv, opts = {}) {
504
517
  }
505
518
  }
506
519
  void finish(child.exitCode, child.signalCode);
507
- }, STOP_WAIT_MS);
520
+ }, grace2 + STOP_WAIT_MS);
508
521
  };
509
522
  const abort = () => stop("SIGTERM");
510
523
  const inputError = (err) => {
@@ -525,7 +538,7 @@ function start(file, argv, opts = {}) {
525
538
  });
526
539
  timer = opts.timeoutMs ? setTimeout(() => {
527
540
  timedOut = true;
528
- stop("SIGKILL");
541
+ stop("SIGTERM");
529
542
  }, opts.timeoutMs) : void 0;
530
543
  opts.signal?.addEventListener("abort", abort, { once: true });
531
544
  if (opts.stdin !== void 0 && child.stdin) {
@@ -646,6 +659,7 @@ async function runScriptFunction(fn, opts) {
646
659
  cwd: opts.cwd,
647
660
  env: opts.env,
648
661
  timeoutMs: opts.timeoutMs,
662
+ killGraceMs: opts.killGraceMs,
649
663
  signal: opts.signal,
650
664
  onStderr: opts.onStderr,
651
665
  stdin: stdinPath ? (0, import_node_fs4.createReadStream)(stdinPath) : void 0,
@@ -83,6 +83,7 @@ export declare function parseRoleJson(text: string | undefined): unknown;
83
83
  */
84
84
  export declare function runScriptFunction(fn: ResolvedFunction, opts: CommandOptions & {
85
85
  timeoutMs?: number;
86
+ /** How long a stopped tool (abort or timeout) has after SIGTERM before SIGKILL; default 200. */ killGraceMs?: number;
86
87
  /** Environment supplied to the process or read for option defaults. */ env?: NodeJS.ProcessEnv;
87
88
  /** Working directory used to resolve command-line paths and execute tools. */ cwd?: string;
88
89
  /** AbortSignal used to cancel execution and terminate the tool process tree. */ signal?: AbortSignal;
@@ -1 +1 @@
1
- {"version":3,"file":"functions.d.ts","sourceRoot":"","sources":["../src/functions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"functions.d.ts","sourceRoot":"","sources":["../src/functions.ts"],"names":[],"mappings":"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"}
package/dist/functions.js CHANGED
@@ -123,7 +123,7 @@ export async function runScriptFunction(fn, opts) {
123
123
  log: { onLine: opts.onLog },
124
124
  };
125
125
  const started = start(file, argv, {
126
- cwd: opts.cwd, env: opts.env, timeoutMs: opts.timeoutMs, signal: opts.signal, onStderr: opts.onStderr,
126
+ cwd: opts.cwd, env: opts.env, timeoutMs: opts.timeoutMs, killGraceMs: opts.killGraceMs, signal: opts.signal, onStderr: opts.onStderr,
127
127
  stdin: stdinPath ? createReadStream(stdinPath) : undefined,
128
128
  stdout: stdoutPath ? 'stream' : 'text',
129
129
  roles: declaredRoles({ schema }, roles),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clyops-jobs",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "description": "Run clyops tools as jobs: config-bound functions, templated invocation, artifacts, job records and a queue.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -38,7 +38,7 @@
38
38
  "typescript": "^5.6.0"
39
39
  },
40
40
  "dependencies": {
41
- "clyops-tools": "0.6.0"
41
+ "clyops-tools": "0.8.0"
42
42
  },
43
43
  "homepage": "https://clyops.io/node-tools.html",
44
44
  "scripts": {
package/src/functions.ts CHANGED
@@ -162,6 +162,7 @@ export async function runScriptFunction(
162
162
  fn: ResolvedFunction,
163
163
  opts: CommandOptions & {
164
164
  timeoutMs?: number;
165
+ /** How long a stopped tool (abort or timeout) has after SIGTERM before SIGKILL; default 200. */ killGraceMs?: number;
165
166
  /** Environment supplied to the process or read for option defaults. */ env?: NodeJS.ProcessEnv;
166
167
  /** Working directory used to resolve command-line paths and execute tools. */ cwd?: string;
167
168
  /** AbortSignal used to cancel execution and terminate the tool process tree. */ signal?: AbortSignal;
@@ -193,7 +194,7 @@ export async function runScriptFunction(
193
194
  log: { onLine: opts.onLog },
194
195
  };
195
196
  const started = start(file, argv, {
196
- cwd: opts.cwd, env: opts.env, timeoutMs: opts.timeoutMs, signal: opts.signal, onStderr: opts.onStderr,
197
+ cwd: opts.cwd, env: opts.env, timeoutMs: opts.timeoutMs, killGraceMs: opts.killGraceMs, signal: opts.signal, onStderr: opts.onStderr,
197
198
  stdin: stdinPath ? createReadStream(stdinPath) : undefined,
198
199
  stdout: stdoutPath ? 'stream' : 'text',
199
200
  roles: declaredRoles({ schema }, roles),