@craftsamo/whatsapp-tools 0.1.0 → 0.1.2

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/dist/cli.js CHANGED
@@ -26,6 +26,12 @@ var PROJECT = {
26
26
  toolsets: ["account", "chats", "contacts", "history", "files", "sends", "actions"],
27
27
  /** The toolsets on when a setting names none. */
28
28
  defaultToolsets: ["account", "chats", "contacts", "history", "sends"],
29
+ /** The package's own settings, which the tools themselves read: each snake_case name and its type, with bounds when it needs them. */
30
+ options: {
31
+ state_dir: "path",
32
+ download_dir: "path",
33
+ send_dirs: "paths"
34
+ },
29
35
  /** The environment variables the tools read besides the settings, which Codex forwards to the server after them. */
30
36
  toolVariables: []
31
37
  };
@@ -5100,7 +5106,7 @@ var recursive = /* @__PURE__ */ new WeakMap();
5100
5106
  var NONE = 0;
5101
5107
  var ASSUMED = 1;
5102
5108
  var PROVEN = 2;
5103
- function isRecursive(inst, stack, resolve8) {
5109
+ function isRecursive(inst, stack, resolve6) {
5104
5110
  const cached2 = recursive.get(inst);
5105
5111
  if (cached2 !== void 0)
5106
5112
  return cached2 ? PROVEN : NONE;
@@ -5110,7 +5116,7 @@ function isRecursive(inst, stack, resolve8) {
5110
5116
  let result = NONE;
5111
5117
  const check2 = (child) => {
5112
5118
  if (result !== PROVEN && child?._zod) {
5113
- const answer = isRecursive(child, stack, resolve8);
5119
+ const answer = isRecursive(child, stack, resolve6);
5114
5120
  if (answer > result)
5115
5121
  result = answer;
5116
5122
  }
@@ -5121,7 +5127,7 @@ function isRecursive(inst, stack, resolve8) {
5121
5127
  const desc = Object.getOwnPropertyDescriptor(sh, key);
5122
5128
  if (spread && !desc.enumerable)
5123
5129
  continue;
5124
- const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve8) : NONE;
5130
+ const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve6) : NONE;
5125
5131
  if (child > answer)
5126
5132
  answer = child;
5127
5133
  }
@@ -5185,7 +5191,7 @@ function isRecursive(inst, stack, resolve8) {
5185
5191
  break;
5186
5192
  // `$ZodLazy` caches its inner on the def, so a resolved edge is followed exactly
5187
5193
  case "lazy": {
5188
- const inner = def._cachedInner ?? (resolve8 ? inst._zod.innerType : void 0);
5194
+ const inner = def._cachedInner ?? (resolve6 ? inst._zod.innerType : void 0);
5189
5195
  merge2(inner ? isRecursive(inner, stack, false) : ASSUMED);
5190
5196
  break;
5191
5197
  }
@@ -20147,7 +20153,7 @@ function abortError(signal) {
20147
20153
  }
20148
20154
  function exec(argv, options) {
20149
20155
  const { signal } = options;
20150
- return new Promise((resolve8, reject) => {
20156
+ return new Promise((resolve6, reject) => {
20151
20157
  if (signal?.aborted) {
20152
20158
  reject(abortError(signal));
20153
20159
  return;
@@ -20206,7 +20212,7 @@ function exec(argv, options) {
20206
20212
  }
20207
20213
  const finish = () => settle3(() => {
20208
20214
  const { code, killedBy } = exitedWith ?? { code: null, killedBy: null };
20209
- resolve8({
20215
+ resolve6({
20210
20216
  code: code ?? -1,
20211
20217
  stdout,
20212
20218
  stderr,
@@ -22709,7 +22715,7 @@ function callService(paths, op, args, { mode, signal, timeoutMs: requestedMs = D
22709
22715
  if (signal?.aborted) return Promise.reject(abortError(signal));
22710
22716
  const timeoutMs = Number.isNaN(requestedMs) ? DEFAULT_TIMEOUT_MS2 : Math.min(Math.max(Math.ceil(requestedMs), 1), MAX_DEADLINE_MS);
22711
22717
  const request = encodeLine({ op, args, deadline_ms: timeoutMs });
22712
- return new Promise((resolve8, reject) => {
22718
+ return new Promise((resolve6, reject) => {
22713
22719
  const socket = createConnection(paths.socket);
22714
22720
  socket.setEncoding("utf8");
22715
22721
  let sent = false;
@@ -22754,7 +22760,7 @@ function callService(paths, op, args, { mode, signal, timeoutMs: requestedMs = D
22754
22760
  if (end === -1) return;
22755
22761
  const response = parseResponse(received.slice(0, end));
22756
22762
  if (!response) return unknownOutcome2("The sync service's answer could not be read");
22757
- if (response.ok) return finish(() => resolve8(response.data));
22763
+ if (response.ok) return finish(() => resolve6(response.data));
22758
22764
  fail(new ToolError(response.error.code, response.error.message));
22759
22765
  });
22760
22766
  socket.on("error", (error62) => {
@@ -27798,6 +27804,35 @@ var ALL_TRANSLATIONS = mergeTranslations(
27798
27804
  FACT_TRANSLATIONS
27799
27805
  );
27800
27806
 
27807
+ // src/entry/directory.ts
27808
+ import { homedir as homedir3 } from "node:os";
27809
+ import { isAbsolute as isAbsolute6, resolve as resolve4 } from "node:path";
27810
+ var DOWNLOADS_DIR = "Downloads";
27811
+ function homeDir(env7) {
27812
+ const envHome = env7.HOME;
27813
+ if (envHome && isAbsolute6(envHome)) return envHome;
27814
+ return homedir3();
27815
+ }
27816
+ function pathOf(value) {
27817
+ return typeof value === "string" ? value : void 0;
27818
+ }
27819
+ function pathsOf(value) {
27820
+ return typeof value === "object" ? value : [];
27821
+ }
27822
+ function directorySettings(options, env7, profile) {
27823
+ const home = homeDir(env7);
27824
+ const xdg = env7.XDG_STATE_HOME;
27825
+ const stateHome = xdg && isAbsolute6(xdg) ? xdg : resolve4(home, ".local", "state");
27826
+ return {
27827
+ state_dir: pathOf(options.state_dir) ?? resolve4(stateHome, profile.name),
27828
+ download_dir: pathOf(options.download_dir) ?? resolve4(home, DOWNLOADS_DIR, profile.name),
27829
+ send_dirs: [...new Set(pathsOf(options.send_dirs))]
27830
+ };
27831
+ }
27832
+ function toolDirectories(settings) {
27833
+ return { stateDir: settings.state_dir, downloadDir: settings.download_dir, sendDirs: settings.send_dirs };
27834
+ }
27835
+
27801
27836
  // src/entry/errors.ts
27802
27837
  function errorBody(code, message, details) {
27803
27838
  return { code, message, ...details !== void 0 && { details } };
@@ -27903,9 +27938,9 @@ async function timedCallDescription(spec, args, ctx, timeoutMs = DESCRIBE_TIMEOU
27903
27938
  let timer;
27904
27939
  let onAbort;
27905
27940
  try {
27906
- const timedOut = new Promise((resolve8) => {
27941
+ const timedOut = new Promise((resolve6) => {
27907
27942
  timer = setTimeout(() => {
27908
- resolve8(void 0);
27943
+ resolve6(void 0);
27909
27944
  controller.abort();
27910
27945
  }, timeoutMs);
27911
27946
  });
@@ -27955,63 +27990,13 @@ async function checkPin(spec, args, ctx, pin, timeoutMs = DESCRIBE_TIMEOUT_MS) {
27955
27990
  var PROJECT_PROFILE = {
27956
27991
  name: PROJECT.name,
27957
27992
  envPrefix: PROJECT.envPrefix,
27958
- toolsets: { names: PROJECT.toolsets, defaults: PROJECT.defaultToolsets }
27993
+ toolsets: { names: PROJECT.toolsets, defaults: PROJECT.defaultToolsets },
27994
+ options: PROJECT.options
27959
27995
  };
27960
27996
 
27961
- // src/entry/directory.ts
27962
- import { homedir as homedir3 } from "node:os";
27963
- import { isAbsolute as isAbsolute6, join as join12, resolve as resolve4, sep as sep4 } from "node:path";
27964
- function homeDir(env7) {
27965
- const envHome = env7.HOME;
27966
- if (envHome && isAbsolute6(envHome)) return envHome;
27967
- return homedir3();
27968
- }
27969
- function expandTilde(text2, home) {
27970
- if (text2 === "~") return home;
27971
- if (text2.startsWith("~/") || text2.startsWith(`~${sep4}`)) {
27972
- return join12(home, text2.slice(2));
27973
- }
27974
- return text2;
27975
- }
27976
- function resolveGivenDirectory(given, home) {
27977
- const text2 = given.text.trim();
27978
- const expanded = expandTilde(text2, home);
27979
- if (!text2 || !isAbsolute6(expanded)) {
27980
- throw new ToolError("invalid_argument", `${given.source} must be an absolute path.`);
27981
- }
27982
- return resolve4(expanded);
27983
- }
27984
- function toolDirectories(settings) {
27985
- return { stateDir: settings.state_dir, downloadDir: settings.download_dir, sendDirs: settings.send_dirs };
27986
- }
27987
-
27988
- // src/entry/download-dir.ts
27989
- import { resolve as resolve5 } from "node:path";
27990
- var DOWNLOADS_DIR = "Downloads";
27991
- function resolveDownloadDir(given, env7, profile) {
27992
- const home = homeDir(env7);
27993
- return given !== void 0 ? resolveGivenDirectory(given, home) : resolve5(home, DOWNLOADS_DIR, profile.name);
27994
- }
27995
-
27996
- // src/entry/send-dirs.ts
27997
- function resolveSendDirs(given, env7) {
27998
- const home = homeDir(env7);
27999
- return [...new Set(given.map((directory) => resolveGivenDirectory(directory, home)))];
28000
- }
28001
-
28002
- // src/entry/state-dir.ts
28003
- import { isAbsolute as isAbsolute7, resolve as resolve6 } from "node:path";
28004
- function resolveStateDir(given, env7, profile) {
28005
- const home = homeDir(env7);
28006
- if (given !== void 0) return resolveGivenDirectory(given, home);
28007
- const xdg = env7.XDG_STATE_HOME;
28008
- if (xdg && isAbsolute7(xdg)) {
28009
- return resolve6(xdg, profile.name);
28010
- }
28011
- return resolve6(home, ".local", "state", profile.name);
28012
- }
28013
-
28014
27997
  // src/entry/settings.ts
27998
+ import { homedir as homedir4 } from "node:os";
27999
+ import { isAbsolute as isAbsolute7, join as join12, resolve as resolvePath, sep as sep4 } from "node:path";
28015
28000
  var CONFIRM_MODES = ["harness", "elicitation"];
28016
28001
  var ALL_TOOLSETS = "all";
28017
28002
  var TRUE_VALUES = ["1", "true"];
@@ -28021,17 +28006,28 @@ var OPTIONS = {
28021
28006
  read_only: { flag: "--read-only", envSuffix: "READ_ONLY", boolean: true },
28022
28007
  tools: { flag: "--tools", envSuffix: "TOOLS" },
28023
28008
  exclude_tools: { flag: "--exclude-tools", envSuffix: "EXCLUDE_TOOLS" },
28024
- confirm: { flag: "--confirm", envSuffix: "CONFIRM" },
28025
- state_dir: { flag: "--state-dir", envSuffix: "STATE_DIR" },
28026
- download_dir: { flag: "--download-dir", envSuffix: "DOWNLOAD_DIR" },
28027
- send_dirs: { flag: "--send-dirs", envSuffix: "SEND_DIRS" }
28009
+ confirm: { flag: "--confirm", envSuffix: "CONFIRM" }
28028
28010
  };
28011
+ function profileOptions(profile) {
28012
+ return profile.options ?? {};
28013
+ }
28014
+ function settingOptions(profile) {
28015
+ const toolOptions = Object.entries(profileOptions(profile)).map(([name, spec]) => [
28016
+ name,
28017
+ {
28018
+ flag: `--${name.replace(/_/g, "-")}`,
28019
+ envSuffix: name.toUpperCase(),
28020
+ ...optionType(spec) === "boolean" && { boolean: true }
28021
+ }
28022
+ ]);
28023
+ return { ...OPTIONS, ...Object.fromEntries(toolOptions) };
28024
+ }
28029
28025
  function envName(name, profile) {
28030
- return `${profile.envPrefix}_${OPTIONS[name].envSuffix}`;
28026
+ return `${profile.envPrefix}_${settingOptions(profile)[name].envSuffix}`;
28031
28027
  }
28032
- function readFlags(argv) {
28028
+ function readFlags(argv, profile) {
28033
28029
  const byFlag = new Map(
28034
- Object.keys(OPTIONS).map((name) => [OPTIONS[name].flag, { name, ...OPTIONS[name] }])
28030
+ Object.entries(settingOptions(profile)).map(([name, option]) => [option.flag, { name, ...option }])
28035
28031
  );
28036
28032
  const given = {};
28037
28033
  for (let i = 0; i < argv.length; i++) {
@@ -28056,9 +28052,6 @@ function readFlags(argv) {
28056
28052
  function splitList(value) {
28057
28053
  return value.split(",").map((item) => item.trim()).filter((item) => item !== "");
28058
28054
  }
28059
- function listedDirectories(given) {
28060
- return given === void 0 ? [] : splitList(given.text).map((text2) => ({ text: text2, source: given.source }));
28061
- }
28062
28055
  function checkToolsets(names, source, toolsets) {
28063
28056
  if (names.includes(ALL_TOOLSETS)) return ALL_TOOLSETS;
28064
28057
  const unknown2 = names.find((name) => !toolsets.names.includes(name));
@@ -28087,20 +28080,108 @@ function parseConfirm(value, source) {
28087
28080
  }
28088
28081
  return mode;
28089
28082
  }
28083
+ function parseNumber2(value, source) {
28084
+ const trimmed = value.trim();
28085
+ const parsed = trimmed === "" ? Number.NaN : Number(trimmed);
28086
+ if (!Number.isFinite(parsed)) {
28087
+ throw new ToolError("invalid_argument", `Unknown number "${value}" in ${source}; use a finite number.`);
28088
+ }
28089
+ return parsed;
28090
+ }
28091
+ function absolutePath(text2, source, env7) {
28092
+ const home = env7.HOME !== void 0 && isAbsolute7(env7.HOME) ? env7.HOME : homedir4();
28093
+ const expanded = text2 === "~" || text2.startsWith("~/") || text2.startsWith(`~${sep4}`) ? join12(home, text2.slice(1)) : text2;
28094
+ if (!isAbsolute7(expanded)) throw new ToolError("invalid_argument", `${source} must be an absolute path.`);
28095
+ return resolvePath(expanded);
28096
+ }
28097
+ function absolutePaths(items, source, env7) {
28098
+ return items.length > 0 ? items.map((item) => absolutePath(item, source, env7)) : void 0;
28099
+ }
28090
28100
  function envText(name, env7, profile) {
28091
28101
  const variable = envName(name, profile);
28092
28102
  const text2 = env7[variable];
28093
28103
  return text2 === void 0 || text2.trim() === "" ? void 0 : { text: text2, source: variable };
28094
28104
  }
28105
+ function optionType(spec) {
28106
+ return typeof spec === "string" ? spec : spec.type;
28107
+ }
28108
+ function itemCount(count) {
28109
+ return count === 1 ? "1 item" : `${count} items`;
28110
+ }
28111
+ function numberBoundsError({ integer: integer2, min, max }, source) {
28112
+ const range = min !== void 0 && max !== void 0 ? ` from ${min} to ${max}` : min !== void 0 ? ` of at least ${min}` : max !== void 0 ? ` of at most ${max}` : "";
28113
+ return new ToolError("invalid_argument", `${source} must be ${integer2 ? "a whole number" : "a number"}${range}.`);
28114
+ }
28115
+ function countBoundsError({ min, max }, source) {
28116
+ const range = min !== void 0 && max !== void 0 ? `from ${min} to ${max} items` : min !== void 0 ? `at least ${itemCount(min)}` : `at most ${itemCount(max)}`;
28117
+ return new ToolError("invalid_argument", `${source} must list ${range}.`);
28118
+ }
28119
+ function withinBounds(spec, value, source) {
28120
+ if (value === void 0 || typeof spec === "string") return value;
28121
+ const bounds = spec;
28122
+ const { integer: integer2, min, max } = bounds;
28123
+ if (typeof value === "number") {
28124
+ if (integer2 && !Number.isInteger(value) || min !== void 0 && value < min || max !== void 0 && value > max) {
28125
+ throw numberBoundsError(bounds, source);
28126
+ }
28127
+ } else if (typeof value === "object" && (min !== void 0 && value.length < min || max !== void 0 && value.length > max)) {
28128
+ throw countBoundsError(bounds, source);
28129
+ }
28130
+ return value;
28131
+ }
28132
+ function parseOptionText(spec, given, env7) {
28133
+ return withinBounds(spec, parseTypedText(optionType(spec), given, env7), given.source);
28134
+ }
28135
+ function parseTypedText(kind, given, env7) {
28136
+ switch (kind) {
28137
+ case "text":
28138
+ return nonBlank(given.text);
28139
+ case "boolean":
28140
+ return parseBoolean(given.text, given.source);
28141
+ case "number":
28142
+ return parseNumber2(given.text, given.source);
28143
+ case "list": {
28144
+ const items = splitList(given.text);
28145
+ return items.length > 0 ? items : void 0;
28146
+ }
28147
+ case "path": {
28148
+ const text2 = nonBlank(given.text);
28149
+ return text2 === void 0 ? void 0 : absolutePath(text2, given.source, env7);
28150
+ }
28151
+ case "paths":
28152
+ return absolutePaths(splitList(given.text), given.source, env7);
28153
+ }
28154
+ }
28155
+ function optionsFrom(flags, env7, profile) {
28156
+ const options = {};
28157
+ for (const [name, spec] of Object.entries(profileOptions(profile))) {
28158
+ if (flags[name] !== void 0) {
28159
+ const parsed = parseOptionText(spec, { text: flags[name], source: settingOptions(profile)[name].flag }, env7);
28160
+ if (parsed !== void 0) options[name] = parsed;
28161
+ continue;
28162
+ }
28163
+ const fromEnv = envText(name, env7, profile);
28164
+ if (fromEnv !== void 0) {
28165
+ const parsed = parseOptionText(spec, fromEnv, env7);
28166
+ if (parsed !== void 0) options[name] = parsed;
28167
+ }
28168
+ }
28169
+ return options;
28170
+ }
28171
+ function parseToolOptions(argv, env7, profile = PROJECT_PROFILE) {
28172
+ const flags = readFlags(argv, profile);
28173
+ const known = profileOptions(profile);
28174
+ const other = Object.keys(flags).find((name) => !(name in known));
28175
+ if (other !== void 0) {
28176
+ throw new ToolError("invalid_argument", `Unknown option "${settingOptions(profile)[other].flag}".`);
28177
+ }
28178
+ return optionsFrom(flags, env7, profile);
28179
+ }
28095
28180
  function parseSettings(argv, env7, profile = PROJECT_PROFILE) {
28096
- const flags = readFlags(argv);
28181
+ const flags = readFlags(argv, profile);
28097
28182
  const value = (name) => flags[name] !== void 0 ? { text: flags[name], source: OPTIONS[name].flag } : envText(name, env7, profile);
28098
- const settings = {
28099
- confirm: "harness",
28100
- state_dir: resolveStateDir(value("state_dir"), env7, profile),
28101
- download_dir: resolveDownloadDir(value("download_dir"), env7, profile),
28102
- send_dirs: resolveSendDirs(listedDirectories(value("send_dirs")), env7)
28103
- };
28183
+ const options = optionsFrom(flags, env7, profile);
28184
+ const settings = { confirm: "harness", ...directorySettings(options, env7, profile), options };
28104
28185
  const toolsets = value("toolsets");
28105
28186
  if (toolsets) settings.toolsets = checkToolsets(splitList(toolsets.text), toolsets.source, profile.toolsets);
28106
28187
  const readOnly = value("read_only");
@@ -28125,38 +28206,6 @@ function parseToolSettings(argv, env7, profile = PROJECT_PROFILE) {
28125
28206
  );
28126
28207
  return settings;
28127
28208
  }
28128
- function parseStateDir(argv, env7, profile = PROJECT_PROFILE) {
28129
- const flags = readFlags(argv);
28130
- const other = Object.keys(flags).find((name) => name !== "state_dir");
28131
- if (other !== void 0)
28132
- throw new ToolError("invalid_argument", `Option ${OPTIONS[other].flag} is not available here.`);
28133
- const given = flags.state_dir !== void 0 ? { text: flags.state_dir, source: OPTIONS.state_dir.flag } : void 0;
28134
- return resolveStateDir(given ?? envText("state_dir", env7, profile), env7, profile);
28135
- }
28136
- var DIRECTORY_OPTION_NAMES = ["state_dir", "download_dir", "send_dirs"];
28137
- function parseDirectorySettings(argv, env7, profile = PROJECT_PROFILE) {
28138
- const flags = readFlags(argv);
28139
- const other = Object.keys(flags).find((name) => !DIRECTORY_OPTION_NAMES.includes(name));
28140
- if (other !== void 0)
28141
- throw new ToolError("invalid_argument", `Option ${OPTIONS[other].flag} is not available here.`);
28142
- const value = (name) => flags[name] !== void 0 ? { text: flags[name], source: OPTIONS[name].flag } : envText(name, env7, profile);
28143
- return {
28144
- state_dir: resolveStateDir(value("state_dir"), env7, profile),
28145
- download_dir: resolveDownloadDir(value("download_dir"), env7, profile),
28146
- send_dirs: resolveSendDirs(listedDirectories(value("send_dirs")), env7)
28147
- };
28148
- }
28149
- var TOOL_OPTION_NAMES = [
28150
- "toolsets",
28151
- "read_only",
28152
- "tools",
28153
- "exclude_tools",
28154
- "state_dir",
28155
- "download_dir",
28156
- "send_dirs"
28157
- ];
28158
- var LANGUAGE_OPTION = "language";
28159
- var PLUGIN_OPTION_NAMES = [...TOOL_OPTION_NAMES, LANGUAGE_OPTION];
28160
28209
  function languageVariable(profile = PROJECT_PROFILE) {
28161
28210
  return `${profile.envPrefix}_LANGUAGE`;
28162
28211
  }
@@ -28183,6 +28232,7 @@ async function defaultReadLine(prompt) {
28183
28232
  }
28184
28233
 
28185
28234
  // src/cli/command-args.ts
28235
+ var STATE_DIR_OPTION = "state_dir";
28186
28236
  function usageError(message) {
28187
28237
  return new ToolError("invalid_argument", message);
28188
28238
  }
@@ -28231,7 +28281,10 @@ function parseFlagArgs(argv, spec) {
28231
28281
  return { values, switches, rest };
28232
28282
  }
28233
28283
  function parseCommandStateDir(rest, io) {
28234
- return parseStateDir(rest, io.env, io.profile ?? PROJECT_PROFILE);
28284
+ const profile = io.profile ?? PROJECT_PROFILE;
28285
+ const options = Object.entries(profile.options ?? {}).filter(([name]) => name === STATE_DIR_OPTION);
28286
+ const stateOnly = { ...profile, options: Object.fromEntries(options) };
28287
+ return directorySettings(parseToolOptions(rest, io.env, stateOnly), io.env, profile).state_dir;
28235
28288
  }
28236
28289
 
28237
28290
  // src/core/whatsapp/pairing.ts
@@ -28283,9 +28336,9 @@ function spawnError(error62) {
28283
28336
  }
28284
28337
  function spawnWacli(program, args, { env: env7, onStdoutLine, onStderrLine, onRawStderrLine, stopGraceMs = DEFAULT_STOP_GRACE_MS }) {
28285
28338
  const child = spawn2(program, args, { env: env7, shell: false, stdio: ["ignore", "pipe", "pipe"] });
28286
- const spawned = new Promise((resolve8) => {
28287
- child.once("spawn", () => resolve8(true));
28288
- child.once("error", () => resolve8(false));
28339
+ const spawned = new Promise((resolve6) => {
28340
+ child.once("spawn", () => resolve6(true));
28341
+ child.once("error", () => resolve6(false));
28289
28342
  });
28290
28343
  const stdout = lineSplitter((line) => onStdoutLine?.(line));
28291
28344
  const stderr = lineSplitter((line) => {
@@ -28297,14 +28350,14 @@ function spawnWacli(program, args, { env: env7, onStdoutLine, onStderrLine, onRa
28297
28350
  let killTimer;
28298
28351
  let drainTimer;
28299
28352
  let ended2;
28300
- const exited = new Promise((resolve8, reject) => {
28353
+ const exited = new Promise((resolve6, reject) => {
28301
28354
  const finish = () => {
28302
28355
  clearTimeout(drainTimer);
28303
28356
  child.stdout.destroy();
28304
28357
  child.stderr.destroy();
28305
28358
  stdout.flush();
28306
28359
  stderr.flush();
28307
- resolve8(ended2);
28360
+ resolve6(ended2);
28308
28361
  };
28309
28362
  child.on("error", (error62) => {
28310
28363
  clearTimeout(killTimer);
@@ -28431,9 +28484,9 @@ async function runAuth(program, paths, phone, options) {
28431
28484
  });
28432
28485
  let timer;
28433
28486
  let onAbort;
28434
- const interrupted = new Promise((resolve8) => {
28435
- timer = setTimeout(() => resolve8("timeout"), timeoutMs);
28436
- onAbort = () => resolve8("abort");
28487
+ const interrupted = new Promise((resolve6) => {
28488
+ timer = setTimeout(() => resolve6("timeout"), timeoutMs);
28489
+ onAbort = () => resolve6("abort");
28437
28490
  if (signal.aborted) onAbort();
28438
28491
  else signal.addEventListener("abort", onAbort, { once: true });
28439
28492
  });
@@ -29633,7 +29686,7 @@ import { realpathSync } from "node:fs";
29633
29686
 
29634
29687
  // src/cli/service-program.ts
29635
29688
  import { access as access2, constants as constants6, realpath as realpath7, stat as stat5 } from "node:fs/promises";
29636
- import { isAbsolute as isAbsolute8, join as join16, resolve as resolve7, sep as sep5 } from "node:path";
29689
+ import { isAbsolute as isAbsolute8, join as join16, resolve as resolve5, sep as sep5 } from "node:path";
29637
29690
  var PROBE_TIMEOUT_MS = 1e4;
29638
29691
  var PROGRAM_NAME2 = "node";
29639
29692
  var PROBE_ARGS = ["-p", "process.execPath"];
@@ -29666,7 +29719,7 @@ async function resolveRoots(roots) {
29666
29719
  const resolved = /* @__PURE__ */ new Set();
29667
29720
  for (const root of roots) {
29668
29721
  if (root === "" || !isAbsolute8(root)) continue;
29669
- resolved.add(resolve7(root));
29722
+ resolved.add(resolve5(root));
29670
29723
  try {
29671
29724
  resolved.add(await realpath7(root));
29672
29725
  } catch {
@@ -29697,7 +29750,7 @@ async function pickStableProgram(options) {
29697
29750
  if (dir !== "" && isAbsolute8(dir)) candidates.add(join16(dir, PROGRAM_NAME2));
29698
29751
  }
29699
29752
  for (const candidate of candidates) {
29700
- if (pathHoldsVersion(candidate, version2) || isUnder(resolve7(candidate), volatileRoots)) continue;
29753
+ if (pathHoldsVersion(candidate, version2) || isUnder(resolve5(candidate), volatileRoots)) continue;
29701
29754
  if (!await isExecutableFile2(candidate)) continue;
29702
29755
  let started;
29703
29756
  try {
@@ -29959,8 +30012,10 @@ import { setTimeout as delay3 } from "node:timers/promises";
29959
30012
  // src/core/whatsapp/service-socket.ts
29960
30013
  import { chmod as chmod5, rm as rm6 } from "node:fs/promises";
29961
30014
  import { createServer } from "node:net";
30015
+ import { clearTimeout as clearTimeout2, setTimeout as setTimeout4 } from "node:timers";
29962
30016
  var MAX_REQUEST_BYTES = 1048576;
29963
30017
  var REQUEST_READ_TIMEOUT_MS = 1e4;
30018
+ var CLOSE_GRACE_MS = 1e3;
29964
30019
  var MAX_QUOTED_OP = 40;
29965
30020
  var MAX_LOGGED_ERROR = 200;
29966
30021
  var SOCKET_MODE = 384;
@@ -30079,11 +30134,11 @@ async function listenOnServiceSocket(path, options) {
30079
30134
  });
30080
30135
  });
30081
30136
  await rm6(path, { force: true });
30082
- await new Promise((resolve8, reject) => {
30137
+ await new Promise((resolve6, reject) => {
30083
30138
  server.once("error", reject);
30084
30139
  server.listen(path, () => {
30085
30140
  server.off("error", reject);
30086
- resolve8();
30141
+ resolve6();
30087
30142
  });
30088
30143
  });
30089
30144
  try {
@@ -30097,9 +30152,16 @@ async function listenOnServiceSocket(path, options) {
30097
30152
  close() {
30098
30153
  closing ??= (async () => {
30099
30154
  shutdown.abort();
30100
- const closed = new Promise((resolve8) => server.close(() => resolve8()));
30155
+ const closed = new Promise((resolve6) => server.close(() => resolve6()));
30101
30156
  await queue;
30102
30157
  for (const socket of sockets) socket.end(() => socket.destroy());
30158
+ let timer;
30159
+ const grace = new Promise((resolve6) => {
30160
+ timer = setTimeout4(resolve6, CLOSE_GRACE_MS).unref();
30161
+ });
30162
+ await Promise.race([closed, grace]);
30163
+ clearTimeout2(timer);
30164
+ for (const socket of sockets) socket.destroy();
30103
30165
  await closed;
30104
30166
  await rm6(path, { force: true });
30105
30167
  })();
@@ -30127,7 +30189,7 @@ var Ending = class {
30127
30189
  };
30128
30190
  result;
30129
30191
  constructor() {
30130
- this.promise = new Promise((resolve8) => this.resolve = resolve8);
30192
+ this.promise = new Promise((resolve6) => this.resolve = resolve6);
30131
30193
  }
30132
30194
  /** Aborts once the run has ended, so waits and operations still going give up. */
30133
30195
  get signal() {
@@ -30186,7 +30248,7 @@ function startSyncChild(options) {
30186
30248
  let stoppedByService = false;
30187
30249
  let markReady = () => {
30188
30250
  };
30189
- const ready = new Promise((resolve8) => markReady = resolve8);
30251
+ const ready = new Promise((resolve6) => markReady = resolve6);
30190
30252
  const wacli2 = spawnWacli(program, syncArgv(paths), {
30191
30253
  env: wacliEnv(env7, paths),
30192
30254
  stopGraceMs,
@@ -30213,11 +30275,11 @@ function startSyncChild(options) {
30213
30275
  };
30214
30276
  }
30215
30277
  function waitUntilReady(child, signal) {
30216
- return new Promise((resolve8) => {
30217
- if (signal.aborted) return resolve8(false);
30278
+ return new Promise((resolve6) => {
30279
+ if (signal.aborted) return resolve6(false);
30218
30280
  const finish = (ready) => {
30219
30281
  signal.removeEventListener("abort", onAbort);
30220
- resolve8(ready);
30282
+ resolve6(ready);
30221
30283
  };
30222
30284
  const onAbort = () => finish(false);
30223
30285
  signal.addEventListener("abort", onAbort, { once: true });
@@ -30526,9 +30588,17 @@ function takeFlag(argv, flag2) {
30526
30588
  }
30527
30589
  function parseCommand(argv, io) {
30528
30590
  const profile = io.profile ?? PROJECT_PROFILE;
30591
+ const select = (flags) => {
30592
+ const settings = parseToolSettings(flags, io.env, profile);
30593
+ return {
30594
+ selected: selectTools(io.specs, settings, profile.toolsets),
30595
+ directories: toolDirectories(settings),
30596
+ options: settings.options
30597
+ };
30598
+ };
30529
30599
  const [name, ...args] = argv;
30530
30600
  if (name === "list") {
30531
- return { name, selected: selectTools(io.specs, parseToolSettings(args, io.env, profile), profile.toolsets) };
30601
+ return { name, selected: select(args).selected };
30532
30602
  }
30533
30603
  if (name !== "run" && name !== "target") {
30534
30604
  const given = name === void 0 ? "No command given" : `Unknown command "${name}"`;
@@ -30542,28 +30612,22 @@ function parseCommand(argv, io) {
30542
30612
  if (cwd === void 0) throw usageError(`Command ${name} needs ${CWD_FLAG} <dir>.`);
30543
30613
  if (name === "target") {
30544
30614
  const { value: language, rest: afterLanguage } = takeFlag(rest, LANGUAGE_FLAG);
30545
- const { value: harnessLanguage, rest: directoryOptions } = takeFlag(afterLanguage, HARNESS_LANGUAGE_FLAG);
30615
+ const { value: harnessLanguage, rest: targetSettings } = takeFlag(afterLanguage, HARNESS_LANGUAGE_FLAG);
30616
+ const toolOptions = parseToolOptions(targetSettings, io.env, profile);
30546
30617
  return {
30547
30618
  name,
30548
30619
  toolId,
30549
30620
  cwd,
30550
- directories: toolDirectories(parseDirectorySettings(directoryOptions, io.env, profile)),
30551
- language: promptLanguage(language, io.env, harnessLanguage, profile)
30621
+ directories: toolDirectories(directorySettings(toolOptions, io.env, profile)),
30622
+ language: promptLanguage(language, io.env, harnessLanguage, profile),
30623
+ options: toolOptions
30552
30624
  };
30553
30625
  }
30554
30626
  const { value: pin, rest: selection } = takeFlag(rest, PIN_FLAG);
30555
30627
  if (pin !== void 0 && !PIN_PATTERN.test(pin)) {
30556
30628
  throw usageError(`Option ${PIN_FLAG} needs the 64 lowercase hexadecimal digits \`target\` answered with.`);
30557
30629
  }
30558
- const settings = parseToolSettings(selection, io.env, profile);
30559
- return {
30560
- name,
30561
- toolId,
30562
- cwd,
30563
- pin,
30564
- selected: selectTools(io.specs, settings, profile.toolsets),
30565
- directories: toolDirectories(settings)
30566
- };
30630
+ return { name, toolId, cwd, pin, ...select(selection) };
30567
30631
  }
30568
30632
  function describeSpec(spec) {
30569
30633
  return {
@@ -30605,6 +30669,7 @@ async function runTool(command, io) {
30605
30669
  ownDir: io.ownDir,
30606
30670
  ...command.directories,
30607
30671
  programName: PROJECT.name,
30672
+ options: command.options,
30608
30673
  signal: io.signal
30609
30674
  };
30610
30675
  await checkPin(spec, args, ctx, command.pin, io.describeTimeoutMs);
@@ -30629,6 +30694,7 @@ async function targetOf5(command, io) {
30629
30694
  ownDir: io.ownDir,
30630
30695
  ...command.directories,
30631
30696
  programName: PROJECT.name,
30697
+ options: command.options,
30632
30698
  signal: io.signal
30633
30699
  };
30634
30700
  const t = promptTranslator(io.translations ?? {}, command.language);