@llblab/pi-telegram 0.6.3 → 0.7.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.
@@ -1,5 +1,6 @@
1
1
  /**
2
2
  * Command-template standard helpers
3
+ * Zones: shared utils, local process execution, automation standard
3
4
  * Owns shell-free command-template splitting, placeholder defaults, composition expansion, executable path expansion, and direct execution
4
5
  */
5
6
 
@@ -7,12 +8,16 @@ import { spawn } from "node:child_process";
7
8
  import { homedir } from "node:os";
8
9
  import { isAbsolute, resolve } from "node:path";
9
10
 
11
+ export const DEFAULT_COMMAND_TIMEOUT_MS = 30_000;
12
+
10
13
  export interface CommandTemplateObjectConfig {
11
14
  template?: CommandTemplateValue;
12
15
  args?: string[];
13
16
  defaults?: Record<string, unknown>;
14
17
  timeout?: number;
15
18
  output?: string;
19
+ retry?: number;
20
+ critical?: boolean;
16
21
  }
17
22
 
18
23
  export type CommandTemplateValue = string | CommandTemplateConfig[];
@@ -34,6 +39,7 @@ export interface CommandTemplateExecOptions {
34
39
  signal?: AbortSignal;
35
40
  stdin?: string;
36
41
  killGrace?: number;
42
+ retry?: number;
37
43
  }
38
44
 
39
45
  export interface CommandTemplateExecResult {
@@ -100,7 +106,13 @@ export function expandCommandTemplateConfigs(
100
106
  }
101
107
  if (typeof normalizedConfig.template !== "string") return [];
102
108
  return [
103
- { ...normalizedConfig, ...context, template: normalizedConfig.template },
109
+ {
110
+ ...normalizedConfig,
111
+ ...context,
112
+ template: normalizedConfig.template,
113
+ retry: normalizedConfig.retry,
114
+ critical: normalizedConfig.critical,
115
+ },
104
116
  ];
105
117
  }
106
118
 
@@ -192,7 +204,22 @@ export function substituteCommandTemplateToken(
192
204
  );
193
205
  }
194
206
 
195
- export function execCommandTemplate(
207
+ export async function execCommandTemplate(
208
+ command: string,
209
+ args: string[],
210
+ options: CommandTemplateExecOptions = {},
211
+ ): Promise<CommandTemplateExecResult> {
212
+ const maxAttempts = options.retry ?? 1;
213
+ let lastResult: CommandTemplateExecResult = { stdout: "", stderr: "", code: 1, killed: false };
214
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
215
+ const result = await execCommandTemplateOnce(command, args, options);
216
+ if (result.code === 0) return result;
217
+ lastResult = result;
218
+ }
219
+ return lastResult;
220
+ }
221
+
222
+ function execCommandTemplateOnce(
196
223
  command: string,
197
224
  args: string[],
198
225
  options: CommandTemplateExecOptions = {},
@@ -231,8 +258,10 @@ export function execCommandTemplate(
231
258
  else
232
259
  options.signal.addEventListener("abort", killProcess, { once: true });
233
260
  }
234
- if (options.timeout && options.timeout > 0)
261
+ if (options.timeout !== undefined && options.timeout > 0)
235
262
  timeoutId = setTimeout(killProcess, options.timeout);
263
+ else if (options.timeout === undefined)
264
+ timeoutId = setTimeout(killProcess, DEFAULT_COMMAND_TIMEOUT_MS);
236
265
  proc.stdout?.on("data", (data) => {
237
266
  stdout += data.toString();
238
267
  });