@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/mcp.js CHANGED
@@ -2984,7 +2984,7 @@ var require_compile = __commonJS({
2984
2984
  const schOrFunc = root.refs[ref];
2985
2985
  if (schOrFunc)
2986
2986
  return schOrFunc;
2987
- let _sch = resolve7.call(this, root, ref);
2987
+ let _sch = resolve5.call(this, root, ref);
2988
2988
  if (_sch === void 0) {
2989
2989
  const schema = (_a3 = root.localRefs) === null || _a3 === void 0 ? void 0 : _a3[ref];
2990
2990
  const { schemaId } = this.opts;
@@ -3011,7 +3011,7 @@ var require_compile = __commonJS({
3011
3011
  function sameSchemaEnv(s1, s2) {
3012
3012
  return s1.schema === s2.schema && s1.root === s2.root && s1.baseId === s2.baseId;
3013
3013
  }
3014
- function resolve7(root, ref) {
3014
+ function resolve5(root, ref) {
3015
3015
  let sch;
3016
3016
  while (typeof (sch = this.refs[ref]) == "string")
3017
3017
  ref = sch;
@@ -3875,7 +3875,7 @@ var require_fast_uri = __commonJS({
3875
3875
  }
3876
3876
  return uri;
3877
3877
  }
3878
- function resolve7(baseURI, relativeURI, options) {
3878
+ function resolve5(baseURI, relativeURI, options) {
3879
3879
  const schemelessOptions = options ? Object.assign({ scheme: "null" }, options) : { scheme: "null" };
3880
3880
  const {
3881
3881
  parsed: baseParsed,
@@ -4266,7 +4266,7 @@ var require_fast_uri = __commonJS({
4266
4266
  var fastUri = {
4267
4267
  SCHEMES,
4268
4268
  normalize,
4269
- resolve: resolve7,
4269
+ resolve: resolve5,
4270
4270
  resolveComponent,
4271
4271
  equal,
4272
4272
  serialize,
@@ -12325,7 +12325,7 @@ var recursive = /* @__PURE__ */ new WeakMap();
12325
12325
  var NONE = 0;
12326
12326
  var ASSUMED = 1;
12327
12327
  var PROVEN = 2;
12328
- function isRecursive(inst, stack, resolve7) {
12328
+ function isRecursive(inst, stack, resolve5) {
12329
12329
  const cached2 = recursive.get(inst);
12330
12330
  if (cached2 !== void 0)
12331
12331
  return cached2 ? PROVEN : NONE;
@@ -12335,7 +12335,7 @@ function isRecursive(inst, stack, resolve7) {
12335
12335
  let result = NONE;
12336
12336
  const check2 = (child) => {
12337
12337
  if (result !== PROVEN && child?._zod) {
12338
- const answer = isRecursive(child, stack, resolve7);
12338
+ const answer = isRecursive(child, stack, resolve5);
12339
12339
  if (answer > result)
12340
12340
  result = answer;
12341
12341
  }
@@ -12346,7 +12346,7 @@ function isRecursive(inst, stack, resolve7) {
12346
12346
  const desc = Object.getOwnPropertyDescriptor(sh, key);
12347
12347
  if (spread && !desc.enumerable)
12348
12348
  continue;
12349
- const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve7) : NONE;
12349
+ const child = desc.get ? ASSUMED : desc.value?._zod ? isRecursive(desc.value, stack, resolve5) : NONE;
12350
12350
  if (child > answer)
12351
12351
  answer = child;
12352
12352
  }
@@ -12410,7 +12410,7 @@ function isRecursive(inst, stack, resolve7) {
12410
12410
  break;
12411
12411
  // `$ZodLazy` caches its inner on the def, so a resolved edge is followed exactly
12412
12412
  case "lazy": {
12413
- const inner = def._cachedInner ?? (resolve7 ? inst._zod.innerType : void 0);
12413
+ const inner = def._cachedInner ?? (resolve5 ? inst._zod.innerType : void 0);
12414
12414
  merge2(inner ? isRecursive(inner, stack, false) : ASSUMED);
12415
12415
  break;
12416
12416
  }
@@ -28587,12 +28587,12 @@ var StdioServerTransport = class {
28587
28587
  this.onclose?.();
28588
28588
  }
28589
28589
  send(message) {
28590
- return new Promise((resolve7) => {
28590
+ return new Promise((resolve5) => {
28591
28591
  const json2 = serializeMessage(message);
28592
28592
  if (this._stdout.write(json2)) {
28593
- resolve7();
28593
+ resolve5();
28594
28594
  } else {
28595
- this._stdout.once("drain", resolve7);
28595
+ this._stdout.once("drain", resolve5);
28596
28596
  }
28597
28597
  });
28598
28598
  }
@@ -28639,7 +28639,7 @@ function abortError(signal) {
28639
28639
  }
28640
28640
  function exec(argv, options) {
28641
28641
  const { signal } = options;
28642
- return new Promise((resolve7, reject) => {
28642
+ return new Promise((resolve5, reject) => {
28643
28643
  if (signal?.aborted) {
28644
28644
  reject(abortError(signal));
28645
28645
  return;
@@ -28698,7 +28698,7 @@ function exec(argv, options) {
28698
28698
  }
28699
28699
  const finish = () => settle2(() => {
28700
28700
  const { code, killedBy } = exitedWith ?? { code: null, killedBy: null };
28701
- resolve7({
28701
+ resolve5({
28702
28702
  code: code ?? -1,
28703
28703
  stdout,
28704
28704
  stderr,
@@ -28882,6 +28882,10 @@ function packageRoot(bundleUrl) {
28882
28882
  return dirname(dirname(fileURLToPath(bundleUrl)));
28883
28883
  }
28884
28884
 
28885
+ // src/entry/settings.ts
28886
+ import { homedir as homedir2 } from "node:os";
28887
+ import { isAbsolute as isAbsolute3, join, resolve as resolvePath, sep as sep2 } from "node:path";
28888
+
28885
28889
  // src/project.ts
28886
28890
  var PROJECT = {
28887
28891
  /** The plugin, MCP server and program name. */
@@ -28896,70 +28900,53 @@ var PROJECT = {
28896
28900
  toolsets: ["account", "chats", "contacts", "history", "files", "sends", "actions"],
28897
28901
  /** The toolsets on when a setting names none. */
28898
28902
  defaultToolsets: ["account", "chats", "contacts", "history", "sends"],
28903
+ /** The package's own settings, which the tools themselves read: each snake_case name and its type, with bounds when it needs them. */
28904
+ options: {
28905
+ state_dir: "path",
28906
+ download_dir: "path",
28907
+ send_dirs: "paths"
28908
+ },
28899
28909
  /** The environment variables the tools read besides the settings, which Codex forwards to the server after them. */
28900
28910
  toolVariables: []
28901
28911
  };
28902
28912
 
28903
28913
  // src/entry/directory.ts
28904
28914
  import { homedir } from "node:os";
28905
- import { isAbsolute as isAbsolute2, join, resolve, sep as sep2 } from "node:path";
28915
+ import { isAbsolute as isAbsolute2, resolve } from "node:path";
28916
+ var DOWNLOADS_DIR = "Downloads";
28906
28917
  function homeDir(env7) {
28907
28918
  const envHome = env7.HOME;
28908
28919
  if (envHome && isAbsolute2(envHome)) return envHome;
28909
28920
  return homedir();
28910
28921
  }
28911
- function expandTilde(text2, home) {
28912
- if (text2 === "~") return home;
28913
- if (text2.startsWith("~/") || text2.startsWith(`~${sep2}`)) {
28914
- return join(home, text2.slice(2));
28915
- }
28916
- return text2;
28922
+ function pathOf(value) {
28923
+ return typeof value === "string" ? value : void 0;
28917
28924
  }
28918
- function resolveGivenDirectory(given, home) {
28919
- const text2 = given.text.trim();
28920
- const expanded = expandTilde(text2, home);
28921
- if (!text2 || !isAbsolute2(expanded)) {
28922
- throw new ToolError("invalid_argument", `${given.source} must be an absolute path.`);
28923
- }
28924
- return resolve(expanded);
28925
+ function pathsOf(value) {
28926
+ return typeof value === "object" ? value : [];
28927
+ }
28928
+ function directorySettings(options, env7, profile) {
28929
+ const home = homeDir(env7);
28930
+ const xdg = env7.XDG_STATE_HOME;
28931
+ const stateHome = xdg && isAbsolute2(xdg) ? xdg : resolve(home, ".local", "state");
28932
+ return {
28933
+ state_dir: pathOf(options.state_dir) ?? resolve(stateHome, profile.name),
28934
+ download_dir: pathOf(options.download_dir) ?? resolve(home, DOWNLOADS_DIR, profile.name),
28935
+ send_dirs: [...new Set(pathsOf(options.send_dirs))]
28936
+ };
28925
28937
  }
28926
28938
  function toolDirectories(settings) {
28927
28939
  return { stateDir: settings.state_dir, downloadDir: settings.download_dir, sendDirs: settings.send_dirs };
28928
28940
  }
28929
28941
 
28930
- // src/entry/download-dir.ts
28931
- import { resolve as resolve2 } from "node:path";
28932
- var DOWNLOADS_DIR = "Downloads";
28933
- function resolveDownloadDir(given, env7, profile) {
28934
- const home = homeDir(env7);
28935
- return given !== void 0 ? resolveGivenDirectory(given, home) : resolve2(home, DOWNLOADS_DIR, profile.name);
28936
- }
28937
-
28938
28942
  // src/entry/profile.ts
28939
28943
  var PROJECT_PROFILE = {
28940
28944
  name: PROJECT.name,
28941
28945
  envPrefix: PROJECT.envPrefix,
28942
- toolsets: { names: PROJECT.toolsets, defaults: PROJECT.defaultToolsets }
28946
+ toolsets: { names: PROJECT.toolsets, defaults: PROJECT.defaultToolsets },
28947
+ options: PROJECT.options
28943
28948
  };
28944
28949
 
28945
- // src/entry/send-dirs.ts
28946
- function resolveSendDirs(given, env7) {
28947
- const home = homeDir(env7);
28948
- return [...new Set(given.map((directory) => resolveGivenDirectory(directory, home)))];
28949
- }
28950
-
28951
- // src/entry/state-dir.ts
28952
- import { isAbsolute as isAbsolute3, resolve as resolve3 } from "node:path";
28953
- function resolveStateDir(given, env7, profile) {
28954
- const home = homeDir(env7);
28955
- if (given !== void 0) return resolveGivenDirectory(given, home);
28956
- const xdg = env7.XDG_STATE_HOME;
28957
- if (xdg && isAbsolute3(xdg)) {
28958
- return resolve3(xdg, profile.name);
28959
- }
28960
- return resolve3(home, ".local", "state", profile.name);
28961
- }
28962
-
28963
28950
  // src/entry/settings.ts
28964
28951
  var CONFIRM_MODES = ["harness", "elicitation"];
28965
28952
  var ALL_TOOLSETS = "all";
@@ -28970,17 +28957,28 @@ var OPTIONS = {
28970
28957
  read_only: { flag: "--read-only", envSuffix: "READ_ONLY", boolean: true },
28971
28958
  tools: { flag: "--tools", envSuffix: "TOOLS" },
28972
28959
  exclude_tools: { flag: "--exclude-tools", envSuffix: "EXCLUDE_TOOLS" },
28973
- confirm: { flag: "--confirm", envSuffix: "CONFIRM" },
28974
- state_dir: { flag: "--state-dir", envSuffix: "STATE_DIR" },
28975
- download_dir: { flag: "--download-dir", envSuffix: "DOWNLOAD_DIR" },
28976
- send_dirs: { flag: "--send-dirs", envSuffix: "SEND_DIRS" }
28960
+ confirm: { flag: "--confirm", envSuffix: "CONFIRM" }
28977
28961
  };
28962
+ function profileOptions(profile) {
28963
+ return profile.options ?? {};
28964
+ }
28965
+ function settingOptions(profile) {
28966
+ const toolOptions = Object.entries(profileOptions(profile)).map(([name, spec]) => [
28967
+ name,
28968
+ {
28969
+ flag: `--${name.replace(/_/g, "-")}`,
28970
+ envSuffix: name.toUpperCase(),
28971
+ ...optionType(spec) === "boolean" && { boolean: true }
28972
+ }
28973
+ ]);
28974
+ return { ...OPTIONS, ...Object.fromEntries(toolOptions) };
28975
+ }
28978
28976
  function envName(name, profile) {
28979
- return `${profile.envPrefix}_${OPTIONS[name].envSuffix}`;
28977
+ return `${profile.envPrefix}_${settingOptions(profile)[name].envSuffix}`;
28980
28978
  }
28981
- function readFlags(argv) {
28979
+ function readFlags(argv, profile) {
28982
28980
  const byFlag = new Map(
28983
- Object.keys(OPTIONS).map((name) => [OPTIONS[name].flag, { name, ...OPTIONS[name] }])
28981
+ Object.entries(settingOptions(profile)).map(([name, option]) => [option.flag, { name, ...option }])
28984
28982
  );
28985
28983
  const given = {};
28986
28984
  for (let i = 0; i < argv.length; i++) {
@@ -29005,9 +29003,6 @@ function readFlags(argv) {
29005
29003
  function splitList(value) {
29006
29004
  return value.split(",").map((item) => item.trim()).filter((item) => item !== "");
29007
29005
  }
29008
- function listedDirectories(given) {
29009
- return given === void 0 ? [] : splitList(given.text).map((text2) => ({ text: text2, source: given.source }));
29010
- }
29011
29006
  function checkToolsets(names, source, toolsets) {
29012
29007
  if (names.includes(ALL_TOOLSETS)) return ALL_TOOLSETS;
29013
29008
  const unknown2 = names.find((name) => !toolsets.names.includes(name));
@@ -29036,20 +29031,99 @@ function parseConfirm(value, source) {
29036
29031
  }
29037
29032
  return mode;
29038
29033
  }
29034
+ function parseNumber(value, source) {
29035
+ const trimmed = value.trim();
29036
+ const parsed = trimmed === "" ? Number.NaN : Number(trimmed);
29037
+ if (!Number.isFinite(parsed)) {
29038
+ throw new ToolError("invalid_argument", `Unknown number "${value}" in ${source}; use a finite number.`);
29039
+ }
29040
+ return parsed;
29041
+ }
29042
+ function absolutePath(text2, source, env7) {
29043
+ const home = env7.HOME !== void 0 && isAbsolute3(env7.HOME) ? env7.HOME : homedir2();
29044
+ const expanded = text2 === "~" || text2.startsWith("~/") || text2.startsWith(`~${sep2}`) ? join(home, text2.slice(1)) : text2;
29045
+ if (!isAbsolute3(expanded)) throw new ToolError("invalid_argument", `${source} must be an absolute path.`);
29046
+ return resolvePath(expanded);
29047
+ }
29048
+ function absolutePaths(items, source, env7) {
29049
+ return items.length > 0 ? items.map((item) => absolutePath(item, source, env7)) : void 0;
29050
+ }
29039
29051
  function envText(name, env7, profile) {
29040
29052
  const variable = envName(name, profile);
29041
29053
  const text2 = env7[variable];
29042
29054
  return text2 === void 0 || text2.trim() === "" ? void 0 : { text: text2, source: variable };
29043
29055
  }
29056
+ function optionType(spec) {
29057
+ return typeof spec === "string" ? spec : spec.type;
29058
+ }
29059
+ function itemCount(count) {
29060
+ return count === 1 ? "1 item" : `${count} items`;
29061
+ }
29062
+ function numberBoundsError({ integer: integer2, min, max }, source) {
29063
+ 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}` : "";
29064
+ return new ToolError("invalid_argument", `${source} must be ${integer2 ? "a whole number" : "a number"}${range}.`);
29065
+ }
29066
+ function countBoundsError({ min, max }, source) {
29067
+ const range = min !== void 0 && max !== void 0 ? `from ${min} to ${max} items` : min !== void 0 ? `at least ${itemCount(min)}` : `at most ${itemCount(max)}`;
29068
+ return new ToolError("invalid_argument", `${source} must list ${range}.`);
29069
+ }
29070
+ function withinBounds(spec, value, source) {
29071
+ if (value === void 0 || typeof spec === "string") return value;
29072
+ const bounds = spec;
29073
+ const { integer: integer2, min, max } = bounds;
29074
+ if (typeof value === "number") {
29075
+ if (integer2 && !Number.isInteger(value) || min !== void 0 && value < min || max !== void 0 && value > max) {
29076
+ throw numberBoundsError(bounds, source);
29077
+ }
29078
+ } else if (typeof value === "object" && (min !== void 0 && value.length < min || max !== void 0 && value.length > max)) {
29079
+ throw countBoundsError(bounds, source);
29080
+ }
29081
+ return value;
29082
+ }
29083
+ function parseOptionText(spec, given, env7) {
29084
+ return withinBounds(spec, parseTypedText(optionType(spec), given, env7), given.source);
29085
+ }
29086
+ function parseTypedText(kind, given, env7) {
29087
+ switch (kind) {
29088
+ case "text":
29089
+ return nonBlank(given.text);
29090
+ case "boolean":
29091
+ return parseBoolean(given.text, given.source);
29092
+ case "number":
29093
+ return parseNumber(given.text, given.source);
29094
+ case "list": {
29095
+ const items = splitList(given.text);
29096
+ return items.length > 0 ? items : void 0;
29097
+ }
29098
+ case "path": {
29099
+ const text2 = nonBlank(given.text);
29100
+ return text2 === void 0 ? void 0 : absolutePath(text2, given.source, env7);
29101
+ }
29102
+ case "paths":
29103
+ return absolutePaths(splitList(given.text), given.source, env7);
29104
+ }
29105
+ }
29106
+ function optionsFrom(flags, env7, profile) {
29107
+ const options = {};
29108
+ for (const [name, spec] of Object.entries(profileOptions(profile))) {
29109
+ if (flags[name] !== void 0) {
29110
+ const parsed = parseOptionText(spec, { text: flags[name], source: settingOptions(profile)[name].flag }, env7);
29111
+ if (parsed !== void 0) options[name] = parsed;
29112
+ continue;
29113
+ }
29114
+ const fromEnv = envText(name, env7, profile);
29115
+ if (fromEnv !== void 0) {
29116
+ const parsed = parseOptionText(spec, fromEnv, env7);
29117
+ if (parsed !== void 0) options[name] = parsed;
29118
+ }
29119
+ }
29120
+ return options;
29121
+ }
29044
29122
  function parseSettings(argv, env7, profile = PROJECT_PROFILE) {
29045
- const flags = readFlags(argv);
29123
+ const flags = readFlags(argv, profile);
29046
29124
  const value = (name) => flags[name] !== void 0 ? { text: flags[name], source: OPTIONS[name].flag } : envText(name, env7, profile);
29047
- const settings = {
29048
- confirm: "harness",
29049
- state_dir: resolveStateDir(value("state_dir"), env7, profile),
29050
- download_dir: resolveDownloadDir(value("download_dir"), env7, profile),
29051
- send_dirs: resolveSendDirs(listedDirectories(value("send_dirs")), env7)
29052
- };
29125
+ const options = optionsFrom(flags, env7, profile);
29126
+ const settings = { confirm: "harness", ...directorySettings(options, env7, profile), options };
29053
29127
  const toolsets = value("toolsets");
29054
29128
  if (toolsets) settings.toolsets = checkToolsets(splitList(toolsets.text), toolsets.source, profile.toolsets);
29055
29129
  const readOnly = value("read_only");
@@ -29062,17 +29136,10 @@ function parseSettings(argv, env7, profile = PROJECT_PROFILE) {
29062
29136
  if (confirm) settings.confirm = parseConfirm(confirm.text.trim(), confirm.source);
29063
29137
  return settings;
29064
29138
  }
29065
- var TOOL_OPTION_NAMES = [
29066
- "toolsets",
29067
- "read_only",
29068
- "tools",
29069
- "exclude_tools",
29070
- "state_dir",
29071
- "download_dir",
29072
- "send_dirs"
29073
- ];
29074
- var LANGUAGE_OPTION = "language";
29075
- var PLUGIN_OPTION_NAMES = [...TOOL_OPTION_NAMES, LANGUAGE_OPTION];
29139
+ function nonBlank(text2) {
29140
+ const trimmed = text2?.trim();
29141
+ return trimmed === "" ? void 0 : trimmed;
29142
+ }
29076
29143
 
29077
29144
  // src/core/account/read.ts
29078
29145
  import { env as env2 } from "node:process";
@@ -30815,7 +30882,7 @@ var deleteResult = external_exports.object({
30815
30882
  var deleteAnswer = deleteResult.extend({ service_running: external_exports.boolean() });
30816
30883
 
30817
30884
  // src/core/whatsapp/file-send.ts
30818
- import { isAbsolute as isAbsolute5, resolve as resolve4 } from "node:path";
30885
+ import { isAbsolute as isAbsolute5, resolve as resolve2 } from "node:path";
30819
30886
  var FILE_SEND_OP = "file_send";
30820
30887
  var SEND_AS = ["image", "video", "audio", "document"];
30821
30888
  var FILE_CAPTION_MAX_CHARACTERS = 1024;
@@ -30954,7 +31021,7 @@ function callService(paths, op, args, { mode, signal, timeoutMs: requestedMs = D
30954
31021
  if (signal?.aborted) return Promise.reject(abortError(signal));
30955
31022
  const timeoutMs = Number.isNaN(requestedMs) ? DEFAULT_TIMEOUT_MS2 : Math.min(Math.max(Math.ceil(requestedMs), 1), MAX_DEADLINE_MS);
30956
31023
  const request = encodeLine({ op, args, deadline_ms: timeoutMs });
30957
- return new Promise((resolve7, reject) => {
31024
+ return new Promise((resolve5, reject) => {
30958
31025
  const socket = createConnection(paths.socket);
30959
31026
  socket.setEncoding("utf8");
30960
31027
  let sent = false;
@@ -30999,7 +31066,7 @@ function callService(paths, op, args, { mode, signal, timeoutMs: requestedMs = D
30999
31066
  if (end === -1) return;
31000
31067
  const response = parseResponse(received.slice(0, end));
31001
31068
  if (!response) return unknownOutcome2("The sync service's answer could not be read");
31002
- if (response.ok) return finish(() => resolve7(response.data));
31069
+ if (response.ok) return finish(() => resolve5(response.data));
31003
31070
  fail(new ToolError(response.error.code, response.error.message));
31004
31071
  });
31005
31072
  socket.on("error", (error62) => {
@@ -32421,7 +32488,7 @@ function parseOctal(field) {
32421
32488
  }
32422
32489
  return digits > 0 ? value : void 0;
32423
32490
  }
32424
- function parseNumber(field) {
32491
+ function parseNumber2(field) {
32425
32492
  const first = field[0];
32426
32493
  if (first === void 0 || (first & BASE256_FLAG) === 0) return parseOctal(field);
32427
32494
  if (first === BASE256_NEGATIVE) return void 0;
@@ -32460,7 +32527,7 @@ function parseHeader(block) {
32460
32527
  path[prefix.length] = "/".charCodeAt(0);
32461
32528
  path.set(name, prefix.length + 1);
32462
32529
  }
32463
- return { path, size: parseNumber(block.subarray(SIZE_START, SIZE_END)), type: block[TYPE_OFFSET] };
32530
+ return { path, size: parseNumber2(block.subarray(SIZE_START, SIZE_END)), type: block[TYPE_OFFSET] };
32464
32531
  }
32465
32532
  function parseDecimal(text2) {
32466
32533
  if (!/^[0-9]{1,15}$/.test(text2)) return void 0;
@@ -34086,7 +34153,7 @@ var whatsappFileSave = createFileSave();
34086
34153
 
34087
34154
  // src/core/file/send/tool.ts
34088
34155
  import { realpath as realpath5 } from "node:fs/promises";
34089
- import { resolve as resolve6 } from "node:path";
34156
+ import { resolve as resolve4 } from "node:path";
34090
34157
 
34091
34158
  // src/core/outgoing/limits.ts
34092
34159
  var MAX_FILES = 10;
@@ -34317,7 +34384,7 @@ function kindOf(name, head, { asDocument = false } = {}) {
34317
34384
  }
34318
34385
 
34319
34386
  // src/core/file/send/resolve-files.ts
34320
- import { homedir as homedir2 } from "node:os";
34387
+ import { homedir as homedir3 } from "node:os";
34321
34388
 
34322
34389
  // src/core/outgoing/roots.ts
34323
34390
  import { realpath as realpath3 } from "node:fs/promises";
@@ -34355,7 +34422,7 @@ async function allowedRoots({ cwd, sendDirs, home, forbidden }) {
34355
34422
 
34356
34423
  // src/core/outgoing/resolve.ts
34357
34424
  import { lstat as lstat5, realpath as realpath4 } from "node:fs/promises";
34358
- import { basename as basename2, resolve as resolve5, sep as sep4 } from "node:path";
34425
+ import { basename as basename2, resolve as resolve3, sep as sep4 } from "node:path";
34359
34426
 
34360
34427
  // src/core/outgoing/deny-lists.ts
34361
34428
  import { sep as sep3 } from "node:path";
@@ -34441,7 +34508,7 @@ async function realPathOf(path, shown) {
34441
34508
  }
34442
34509
  async function resolveOutgoing(path, { cwd, roots, forbidden, home }) {
34443
34510
  const shown = JSON.stringify(path);
34444
- const real = await realPathOf(resolve5(cwd, path), shown);
34511
+ const real = await realPathOf(resolve3(cwd, path), shown);
34445
34512
  const stats = await lstat5(real, { bigint: true });
34446
34513
  if (!stats.isFile()) throw new ToolError("invalid_argument", `${shown} is not a regular file.`);
34447
34514
  if (stats.nlink > 1n) throw hardLinked(shown);
@@ -34472,7 +34539,7 @@ async function resolveOutgoing(path, { cwd, roots, forbidden, home }) {
34472
34539
  // src/core/file/send/resolve-files.ts
34473
34540
  async function resolveFiles(files, ctx) {
34474
34541
  const forbidden = [ctx.stateDir, ctx.ownDir].filter((directory) => directory !== void 0);
34475
- const home = homedir2();
34542
+ const home = homedir3();
34476
34543
  const roots = await allowedRoots({ cwd: ctx.cwd, sendDirs: ctx.sendDirs ?? [], home, forbidden });
34477
34544
  const seen = /* @__PURE__ */ new Set();
34478
34545
  const resolvedFiles = [];
@@ -34953,7 +35020,7 @@ var CAPTION_RULES = {
34953
35020
  };
34954
35021
  var CAPTION_ON_AUDIO = "A caption on an audio file is dropped by WhatsApp without a word, so it is refused. Send the audio without text, send it as a document with as_document, or put the text in a message of its own with whatsapp_message_send if the user wants that. Nothing was sent.";
34955
35022
  async function fileTarget(path, cwd) {
34956
- const absolute = resolve6(cwd, path);
35023
+ const absolute = resolve4(cwd, path);
34957
35024
  return realpath5(absolute).catch(() => absolute);
34958
35025
  }
34959
35026
  async function sendTargets(args, ctx) {
@@ -36367,7 +36434,7 @@ var Protocol = class {
36367
36434
  return;
36368
36435
  }
36369
36436
  const pollInterval = task2.pollInterval ?? this._options?.defaultTaskPollInterval ?? 1e3;
36370
- await new Promise((resolve7) => setTimeout(resolve7, pollInterval));
36437
+ await new Promise((resolve5) => setTimeout(resolve5, pollInterval));
36371
36438
  options?.signal?.throwIfAborted();
36372
36439
  }
36373
36440
  } catch (error62) {
@@ -36384,7 +36451,7 @@ var Protocol = class {
36384
36451
  */
36385
36452
  request(request, resultSchema, options) {
36386
36453
  const { relatedRequestId, resumptionToken, onresumptiontoken, task, relatedTask } = options ?? {};
36387
- return new Promise((resolve7, reject) => {
36454
+ return new Promise((resolve5, reject) => {
36388
36455
  const earlyReject = (error62) => {
36389
36456
  reject(error62);
36390
36457
  };
@@ -36462,7 +36529,7 @@ var Protocol = class {
36462
36529
  if (!parseResult.success) {
36463
36530
  reject(parseResult.error);
36464
36531
  } else {
36465
- resolve7(parseResult.data);
36532
+ resolve5(parseResult.data);
36466
36533
  }
36467
36534
  } catch (error62) {
36468
36535
  reject(error62);
@@ -36724,12 +36791,12 @@ var Protocol = class {
36724
36791
  }
36725
36792
  } catch {
36726
36793
  }
36727
- return new Promise((resolve7, reject) => {
36794
+ return new Promise((resolve5, reject) => {
36728
36795
  if (signal.aborted) {
36729
36796
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
36730
36797
  return;
36731
36798
  }
36732
- const timeoutId = setTimeout(resolve7, interval);
36799
+ const timeoutId = setTimeout(resolve5, interval);
36733
36800
  signal.addEventListener("abort", () => {
36734
36801
  clearTimeout(timeoutId);
36735
36802
  reject(new McpError(ErrorCode.InvalidRequest, "Request cancelled"));
@@ -37545,23 +37612,52 @@ function elicitationConfirm(server, signal) {
37545
37612
 
37546
37613
  // src/mcp/roots.ts
37547
37614
  import { statSync } from "node:fs";
37615
+ import { isAbsolute as isAbsolute7 } from "node:path";
37548
37616
  import { fileURLToPath as fileURLToPath2 } from "node:url";
37549
37617
  var FILE_URI_PROTOCOL = "file:";
37618
+ var SANDBOX_STATE_META = "codex/sandbox-state-meta";
37619
+ var TURN_METADATA = "x-codex-turn-metadata";
37620
+ function existingDirectory(dir) {
37621
+ try {
37622
+ return statSync(dir, { throwIfNoEntry: false })?.isDirectory() ? dir : void 0;
37623
+ } catch {
37624
+ return void 0;
37625
+ }
37626
+ }
37550
37627
  function localDirectory(uri) {
37551
37628
  try {
37552
37629
  const url2 = new URL(uri);
37553
- if (url2.protocol !== FILE_URI_PROTOCOL) return void 0;
37554
- const dir = fileURLToPath2(url2);
37555
- return statSync(dir, { throwIfNoEntry: false })?.isDirectory() ? dir : void 0;
37630
+ return url2.protocol === FILE_URI_PROTOCOL ? existingDirectory(fileURLToPath2(url2)) : void 0;
37556
37631
  } catch {
37557
37632
  return void 0;
37558
37633
  }
37559
37634
  }
37635
+ function isRecord2(value) {
37636
+ return typeof value === "object" && value !== null && !Array.isArray(value);
37637
+ }
37638
+ async function usableDirectory(candidate, ownDir, allowPath = false) {
37639
+ if (typeof candidate !== "string") return void 0;
37640
+ const dir = allowPath && isAbsolute7(candidate) ? existingDirectory(candidate) : localDirectory(candidate);
37641
+ if (dir === void 0 || ownDir !== void 0 && await isWithin(dir, ownDir)) return void 0;
37642
+ return dir;
37643
+ }
37644
+ async function callDirectory(meta3, ownDir) {
37645
+ if (!isRecord2(meta3)) return void 0;
37646
+ const sandbox = meta3[SANDBOX_STATE_META];
37647
+ if (isRecord2(sandbox)) {
37648
+ const dir = await usableDirectory(sandbox.sandboxCwd, ownDir, true);
37649
+ if (dir !== void 0) return dir;
37650
+ }
37651
+ const turn = meta3[TURN_METADATA];
37652
+ if (!isRecord2(turn) || !isRecord2(turn.workspaces)) return void 0;
37653
+ const workspaces = Object.keys(turn.workspaces);
37654
+ return workspaces.length === 1 ? usableDirectory(workspaces[0], ownDir, true) : void 0;
37655
+ }
37560
37656
  async function firstUsableRoot(server, ownDir, signal) {
37561
37657
  const { roots } = await server.listRoots(void 0, { signal });
37562
37658
  for (const root of roots) {
37563
- const dir = localDirectory(root.uri);
37564
- if (dir !== void 0 && !(ownDir !== void 0 && await isWithin(dir, ownDir))) return dir;
37659
+ const dir = await usableDirectory(root.uri, ownDir);
37660
+ if (dir !== void 0) return dir;
37565
37661
  }
37566
37662
  return void 0;
37567
37663
  }
@@ -37572,7 +37668,9 @@ function createWorkingDirResolver(server, fallback, ownDir) {
37572
37668
  cached2 = void 0;
37573
37669
  generation++;
37574
37670
  });
37575
- return async (signal) => {
37671
+ return async (signal, meta3) => {
37672
+ const callDir = await callDirectory(meta3, ownDir);
37673
+ if (callDir !== void 0) return callDir;
37576
37674
  if (!server.getClientCapabilities()?.roots) return fallback();
37577
37675
  if (cached2 !== void 0) return cached2;
37578
37676
  const started = generation;
@@ -37613,7 +37711,7 @@ function createServer(specs, settings, options = {}) {
37613
37711
  `));
37614
37712
  const server = new Server(
37615
37713
  { name: PROJECT.name, version: options.version ?? DEFAULT_VERSION },
37616
- { capabilities: { tools: {} } }
37714
+ { capabilities: { tools: {}, experimental: { [SANDBOX_STATE_META]: {} } } }
37617
37715
  );
37618
37716
  const workingDir = createWorkingDirResolver(server, options.cwd ?? (() => process.cwd()), options.ownDir);
37619
37717
  const toolsets = options.toolsets ?? PROJECT_PROFILE.toolsets;
@@ -37626,10 +37724,11 @@ function createServer(specs, settings, options = {}) {
37626
37724
  try {
37627
37725
  const confirm = settings.confirm === "elicitation" ? elicitationConfirm(server, extra.signal) : void 0;
37628
37726
  const ctx = {
37629
- cwd: await workingDir(extra.signal),
37727
+ cwd: await workingDir(extra.signal, request.params._meta),
37630
37728
  ownDir: options.ownDir,
37631
37729
  ...toolDirectories(settings),
37632
37730
  programName: PROJECT.name,
37731
+ options: settings.options,
37633
37732
  signal: extra.signal,
37634
37733
  ...confirm && { confirm }
37635
37734
  };
@@ -37655,7 +37754,7 @@ async function main() {
37655
37754
  const settings = parseSettings(process.argv.slice(2), process.env);
37656
37755
  server = createServer(ALL_TOOLS, settings, {
37657
37756
  ownDir: packageRoot(import.meta.url),
37658
- version: true ? "0.0.0" : void 0
37757
+ version: true ? "0.1.2" : void 0
37659
37758
  });
37660
37759
  } catch (error62) {
37661
37760
  if (!isToolError(error62)) throw error62;