@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
|
|
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
|
|
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
|
|
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
|
-
|
|
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)
|
|
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)
|
|
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
|
|
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
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
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.");
|