@yawlabs/mcp 0.63.2 → 0.64.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.
@@ -2,17 +2,17 @@
2
2
 
3
3
  // src/team-sync.ts
4
4
  import { existsSync } from "fs";
5
- import { chmod, readFile, unlink as unlink2 } from "fs/promises";
5
+ import { chmod as chmod2, readFile, unlink as unlink2 } from "fs/promises";
6
6
  import { homedir as homedir2 } from "os";
7
7
  import { join } from "path";
8
8
 
9
9
  // src/atomic-write.ts
10
- import { mkdir, rename, unlink, writeFile } from "fs/promises";
10
+ import { chmod, mkdir, rename, stat, unlink, writeFile } from "fs/promises";
11
11
  import path from "path";
12
- async function atomicWriteFile(filePath, contents, encoding = "utf8", mode) {
12
+ async function atomicWriteFile(filePath, contents, encoding = "utf8", mode, dirMode) {
13
13
  const dir = path.dirname(filePath);
14
14
  const tmp = `${filePath}.tmp-${process.pid}-${Date.now()}`;
15
- await mkdir(dir, { recursive: true });
15
+ await mkdirpWithMode(dir, dirMode);
16
16
  try {
17
17
  await writeFile(tmp, contents, mode === void 0 ? { encoding } : { encoding, mode });
18
18
  await rename(tmp, filePath);
@@ -21,6 +21,36 @@ async function atomicWriteFile(filePath, contents, encoding = "utf8", mode) {
21
21
  throw err;
22
22
  }
23
23
  }
24
+ async function mkdirpWithMode(dir, dirMode) {
25
+ if (dirMode === void 0 || process.platform === "win32") {
26
+ await mkdir(dir, { recursive: true });
27
+ return;
28
+ }
29
+ const resolved = path.resolve(dir);
30
+ const toCreate = [];
31
+ let cursor = resolved;
32
+ while (true) {
33
+ let exists = true;
34
+ try {
35
+ await stat(cursor);
36
+ } catch {
37
+ exists = false;
38
+ }
39
+ if (exists) break;
40
+ toCreate.unshift(cursor);
41
+ const parent = path.dirname(cursor);
42
+ if (parent === cursor) break;
43
+ cursor = parent;
44
+ }
45
+ if (toCreate.length === 0) return;
46
+ await mkdir(resolved, { recursive: true });
47
+ for (const created of toCreate) {
48
+ try {
49
+ await chmod(created, dirMode);
50
+ } catch {
51
+ }
52
+ }
53
+ }
24
54
 
25
55
  // src/logger.ts
26
56
  var LOG_LEVELS = { debug: 0, info: 1, warn: 2, error: 3 };
@@ -52,12 +82,24 @@ var CONFIG_DIRNAME = ".yaw-mcp";
52
82
  function userConfigDir(home = homedir()) {
53
83
  return path2.join(home, CONFIG_DIRNAME);
54
84
  }
85
+ function normalizeForCompare(p) {
86
+ return process.platform === "win32" ? p.toLowerCase() : p;
87
+ }
88
+ function isUnderHome(dir, homeResolved) {
89
+ const dirKey = normalizeForCompare(dir);
90
+ const homeKey = normalizeForCompare(homeResolved);
91
+ if (dirKey === homeKey) return false;
92
+ const rel = path2.relative(homeResolved, dir);
93
+ const relNorm = normalizeForCompare(rel);
94
+ return relNorm !== "" && !relNorm.startsWith("..") && !path2.isAbsolute(rel);
95
+ }
55
96
  async function findProjectConfigDir(start, home = homedir()) {
56
- const homeResolved = path2.resolve(home);
97
+ const homeFallback = home && home.length > 0 ? home : process.env.USERPROFILE || homedir();
98
+ const homeResolved = path2.resolve(homeFallback);
57
99
  let dir = path2.resolve(start);
58
100
  let prev = "";
59
101
  while (dir !== prev) {
60
- if (dir === homeResolved) return null;
102
+ if (!isUnderHome(dir, homeResolved)) return null;
61
103
  const candidate = path2.join(dir, CONFIG_DIRNAME);
62
104
  try {
63
105
  await access(candidate);
@@ -108,7 +150,8 @@ function resolveBaseUrl(env = process.env) {
108
150
  }
109
151
  function expMs(session) {
110
152
  const e = session.exp;
111
- return e > 0 && e < 1e12 ? e * 1e3 : e;
153
+ if (typeof e !== "number" || !Number.isFinite(e) || e <= 0) return 0;
154
+ return e < 1e12 ? e * 1e3 : e;
112
155
  }
113
156
  var cachedState = null;
114
157
  function invalidateState() {
@@ -117,7 +160,7 @@ function invalidateState() {
117
160
  async function loadStoredState(filePath) {
118
161
  if (cachedState && cachedState.filePath === filePath) {
119
162
  const s = cachedState.state;
120
- if (s && expMs(s.session) < Date.now()) {
163
+ if (s && expMs(s.session) <= Date.now()) {
121
164
  cachedState = { filePath, state: null };
122
165
  return null;
123
166
  }
@@ -130,11 +173,12 @@ async function loadStoredState(filePath) {
130
173
  if (!obj || typeof obj !== "object") parsed = null;
131
174
  else if (typeof obj.cookie !== "string" || !obj.cookie) parsed = null;
132
175
  else if (!obj.session || typeof obj.session !== "object") parsed = null;
176
+ else if (typeof obj.session.exp !== "number" || !Number.isFinite(obj.session.exp)) parsed = null;
133
177
  else parsed = obj;
134
178
  } catch {
135
179
  parsed = null;
136
180
  }
137
- if (parsed && expMs(parsed.session) < Date.now()) {
181
+ if (parsed && expMs(parsed.session) <= Date.now()) {
138
182
  cachedState = { filePath, state: null };
139
183
  return null;
140
184
  }
@@ -144,10 +188,10 @@ async function loadStoredState(filePath) {
144
188
  async function saveStoredState(filePath, state) {
145
189
  cachedState = { filePath, state };
146
190
  try {
147
- await atomicWriteFile(filePath, JSON.stringify(state, null, 2), "utf8", 384);
191
+ await atomicWriteFile(filePath, JSON.stringify(state, null, 2), "utf8", 384, 448);
148
192
  if (process.platform !== "win32") {
149
193
  try {
150
- await chmod(filePath, 384);
194
+ await chmod2(filePath, 384);
151
195
  } catch {
152
196
  }
153
197
  }
@@ -208,12 +252,18 @@ async function signIn(key, opts = {}) {
208
252
  const trimmed = key.trim();
209
253
  if (!trimmed) throw new Error("License key is required.");
210
254
  const baseUrl = opts.baseUrl;
211
- const post = await httpJson({
212
- method: "POST",
213
- path: "/api/team/session",
214
- body: { key: trimmed },
215
- baseUrl
216
- });
255
+ let post;
256
+ try {
257
+ post = await httpJson({
258
+ method: "POST",
259
+ path: "/api/team/session",
260
+ body: { key: trimmed },
261
+ baseUrl
262
+ });
263
+ } catch (err) {
264
+ const msg = err instanceof Error ? err.message : String(err);
265
+ throw new TeamSyncAuthError(`Sign in request failed: ${msg.replace(trimmed, "[redacted]")}`);
266
+ }
217
267
  if (post.status !== 200 || !post.cookie || !post.body.email || !post.body.role || !post.body.order_id) {
218
268
  if (post.body.error) log("warn", "team sign-in failed", { status: post.status, error: post.body.error });
219
269
  throw new TeamSyncAuthError("Sign in failed. Check your license key and try again.");