@llblab/pi-telegram 0.6.3 → 0.7.1

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
  * Telegram attachment domain helpers
3
+ * Zones: telegram outbound, pi agent tool, filesystem
3
4
  * Owns telegram_attach registration, attachment queueing, and attachment delivery so Telegram file output stays in one domain module
4
5
  */
5
6
 
@@ -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,27 @@ 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 = {
214
+ stdout: "",
215
+ stderr: "",
216
+ code: 1,
217
+ killed: false,
218
+ };
219
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
220
+ const result = await execCommandTemplateOnce(command, args, options);
221
+ if (result.code === 0) return result;
222
+ lastResult = result;
223
+ }
224
+ return lastResult;
225
+ }
226
+
227
+ function execCommandTemplateOnce(
196
228
  command: string,
197
229
  args: string[],
198
230
  options: CommandTemplateExecOptions = {},
@@ -231,8 +263,10 @@ export function execCommandTemplate(
231
263
  else
232
264
  options.signal.addEventListener("abort", killProcess, { once: true });
233
265
  }
234
- if (options.timeout && options.timeout > 0)
266
+ if (options.timeout !== undefined && options.timeout > 0)
235
267
  timeoutId = setTimeout(killProcess, options.timeout);
268
+ else if (options.timeout === undefined)
269
+ timeoutId = setTimeout(killProcess, DEFAULT_COMMAND_TIMEOUT_MS);
236
270
  proc.stdout?.on("data", (data) => {
237
271
  stdout += data.toString();
238
272
  });