kojee-mcp 0.6.0 → 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.
- package/README.md +13 -8
- package/dist/ancestry-A2F5KQ6A.js +10 -0
- package/dist/cc-session-id-RURNIHHC.js +10 -0
- package/dist/{chunk-KH5YEJIM.js → chunk-247WFMCJ.js} +7 -20
- package/dist/chunk-5DHIUN73.js +25 -0
- package/dist/{chunk-YH27B6SW.js → chunk-5SZHXYPK.js} +16 -3
- package/dist/{chunk-DO42NPNR.js → chunk-67F67AQ6.js} +14 -3
- package/dist/{chunk-CH32ELFX.js → chunk-6G6YYST6.js} +1 -1
- package/dist/chunk-D6JKFJ6A.js +11 -0
- package/dist/chunk-E6WMFMM2.js +100 -0
- package/dist/chunk-EBYUJM3H.js +14 -0
- package/dist/chunk-EIAUW6KO.js +82 -0
- package/dist/chunk-EIH2LNF4.js +45 -0
- package/dist/{chunk-BYV7CWNY.js → chunk-FBJCPRVH.js} +22 -9
- package/dist/{chunk-XN3IC4B5.js → chunk-FSKGQ6GT.js} +30 -5
- package/dist/{chunk-GI2CKKBL.js → chunk-GKXHKR3B.js} +1 -1
- package/dist/{chunk-ALZX3SGI.js → chunk-GNLCUJBK.js} +13 -27
- package/dist/{chunk-JXMVZEQ7.js → chunk-I67C2HYA.js} +1 -1
- package/dist/chunk-KNEJTD6G.js +31 -0
- package/dist/{chunk-65KRRDHP.js → chunk-KPMD72FY.js} +94 -28
- package/dist/{chunk-NR4Y54OL.js → chunk-MIEI4PLB.js} +1 -19
- package/dist/chunk-NE2F5CKS.js +113 -0
- package/dist/chunk-QJFMU4QC.js +33 -0
- package/dist/{chunk-EW72ZNQL.js → chunk-RDLF4NQC.js} +1 -1
- package/dist/{chunk-Q7T3WAST.js → chunk-SSW5AQSR.js} +6 -1
- package/dist/{chunk-DURRQDYI.js → chunk-TNZITJAB.js} +45 -15
- package/dist/chunk-U5HHHRXA.js +103 -0
- package/dist/{setup-handler-7HOFAD7C.js → chunk-UFHGZUST.js} +431 -253
- package/dist/{chunk-N35X22G7.js → chunk-UPJV7GBE.js} +1 -1
- package/dist/chunk-WBXU27BF.js +35 -0
- package/dist/chunk-XJEBJIQE.js +52 -0
- package/dist/chunk-Z5LPNJQ6.js +20 -0
- package/dist/cli.js +63 -25
- package/dist/codex-stop-hook-BMOJVM6O.js +96 -0
- package/dist/connect-handler-4DRTFMOB.js +138 -0
- package/dist/{control-token-4BUCTYQB.js → control-token-KXSZ3GBY.js} +2 -2
- package/dist/{doctor-WVX3WCYX.js → doctor-5QJ3HGNR.js} +48 -22
- package/dist/{doctor-codex-Z5M4SFBG.js → doctor-codex-VGJKTX2E.js} +33 -7
- package/dist/doctor-openclaw-LL6NSPLC.js +86 -0
- package/dist/{event-log-HOBO3ECB.js → event-log-2NBJEIEP.js} +5 -3
- package/dist/{event-stream-SYBUJ5EH.js → event-stream-KRYWEYWO.js} +7 -4
- package/dist/index.js +13 -10
- package/dist/{install-LJY2CHKG.js → install-V7LSQCYZ.js} +37 -22
- package/dist/{keystore-XLEV3FL5.js → keystore-LQNFDHGO.js} +2 -2
- package/dist/lib.d.ts +4 -1
- package/dist/lib.js +11 -8
- package/dist/pair-HTCVSMR6.js +11 -0
- package/dist/{paired-config-JTFLHMZ2.js → paired-config-GUDDO2CH.js} +4 -2
- package/dist/{parent-watchdog-TLU355FB.js → parent-watchdog-LTUNF7PD.js} +24 -5
- package/dist/{registry-YLOFZDI2.js → registry-ZZZ26WGA.js} +197 -24
- package/dist/resolve-slot-BFIB46Y5.js +13 -0
- package/dist/{runtime-record-WO4IECM6.js → runtime-record-OXRLTOLC.js} +2 -2
- package/dist/{send-cli-IYJF32PE.js → send-cli-45RLGYIC.js} +22 -10
- package/dist/{server-R24AVNTI.js → server-ITPFQVTK.js} +5 -2
- package/dist/{session-discovery-FNMJGFPM.js → session-discovery-NHCZ2XWA.js} +2 -2
- package/dist/setup-handler-JFM45NCN.js +160 -0
- package/dist/{stop-hook-TCPJFGFF.js → stop-hook-5ABGTC2O.js} +17 -20
- package/dist/{tail-stream-4IMXI44S.js → tail-stream-NBGHHBS4.js} +40 -22
- package/dist/{user-prompt-submit-hook-FQ43NIHC.js → user-prompt-submit-hook-DTXXFDSD.js} +11 -14
- package/package.json +3 -2
- package/skills/using-tandems/SKILL.md +52 -0
- package/dist/ancestry-ONFBQEP5.js +0 -8
- package/dist/chunk-BLEGIR35.js +0 -43
- package/dist/chunk-CLKCNV2A.js +0 -100
- package/dist/chunk-KFDZWNQO.js +0 -73
- package/dist/chunk-OGHDTFAX.js +0 -50
- package/dist/chunk-VHKPWUX7.js +0 -41
- package/dist/codex-stop-hook-RWQSZTST.js +0 -16
- package/dist/doctor-openclaw-SS2TMQOX.js +0 -95
- package/dist/pair-P4ILCMT7.js +0 -10
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
|
+
readSessionDiscoveryByKey,
|
|
2
3
|
sessionDiscoveryDir
|
|
3
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-67F67AQ6.js";
|
|
4
5
|
import {
|
|
5
6
|
secureFile
|
|
6
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-U5HHHRXA.js";
|
|
7
8
|
|
|
8
9
|
// src/delivery/lib/event-log.ts
|
|
9
10
|
import fs from "fs";
|
|
@@ -21,23 +22,35 @@ function statusLogPath(eventLogPath) {
|
|
|
21
22
|
const m = base.match(/^kojee-events-(.+)\.log$/);
|
|
22
23
|
return path.join(dir, m ? `kojee-status-${m[1]}.log` : `${base}.status`);
|
|
23
24
|
}
|
|
24
|
-
function
|
|
25
|
+
function livePathOwnedByForeignProxy(candidatePath, selfKey) {
|
|
25
26
|
try {
|
|
26
|
-
const
|
|
27
|
-
|
|
27
|
+
const resolved = path.resolve(candidatePath);
|
|
28
|
+
const { liveOwners } = scanDiscovery(false);
|
|
29
|
+
for (const owner of liveOwners) {
|
|
30
|
+
if (owner.eventLogPath !== resolved) continue;
|
|
31
|
+
if (selfKey && owner.discoveryKey === selfKey) continue;
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
28
35
|
} catch {
|
|
29
36
|
return false;
|
|
30
37
|
}
|
|
31
38
|
}
|
|
39
|
+
function resolveEventLogPath(opts) {
|
|
40
|
+
const dir = opts.dir ?? DEFAULT_DIR;
|
|
41
|
+
const base = path.join(dir, `kojee-events-${opts.key}.log`);
|
|
42
|
+
if (livePathOwnedByForeignProxy(base, opts.selfKey)) {
|
|
43
|
+
const suffix = opts.selfKey ?? String(process.pid);
|
|
44
|
+
return path.join(dir, `kojee-events-${opts.key}-${suffix}.log`);
|
|
45
|
+
}
|
|
46
|
+
return base;
|
|
47
|
+
}
|
|
32
48
|
function startEventLog(opts) {
|
|
33
49
|
const dir = opts.dir ?? DEFAULT_DIR;
|
|
34
50
|
const maxBytes = opts.maxBytes ?? DEFAULT_MAX_BYTES;
|
|
35
51
|
const statusMaxBytes = opts.statusMaxBytes ?? DEFAULT_STATUS_MAX_BYTES;
|
|
36
52
|
fs.mkdirSync(dir, { recursive: true });
|
|
37
|
-
|
|
38
|
-
if (livePathOwnedBySibling(filePath)) {
|
|
39
|
-
filePath = path.join(dir, `kojee-events-${opts.key}-${process.pid}.log`);
|
|
40
|
-
}
|
|
53
|
+
const filePath = resolveEventLogPath(opts);
|
|
41
54
|
const statusPath = statusLogPath(filePath);
|
|
42
55
|
fs.writeFileSync(filePath, "", { mode: 384 });
|
|
43
56
|
secureFile(filePath);
|
|
@@ -114,6 +127,13 @@ function startEventLog(opts) {
|
|
|
114
127
|
});
|
|
115
128
|
},
|
|
116
129
|
cleanup() {
|
|
130
|
+
if (opts.selfKey) {
|
|
131
|
+
const disc = readSessionDiscoveryByKey(opts.selfKey);
|
|
132
|
+
const owner = disc?.proxyPid ?? disc?.pid;
|
|
133
|
+
if (disc && typeof owner === "number" && owner !== process.pid && isProcessAlive(owner) && disc.eventLogPath && path.resolve(disc.eventLogPath) === path.resolve(filePath)) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
117
137
|
try {
|
|
118
138
|
fs.unlinkSync(filePath);
|
|
119
139
|
} catch {
|
|
@@ -175,19 +195,21 @@ function isProcessAlive(pid) {
|
|
|
175
195
|
process.kill(pid, 0);
|
|
176
196
|
return true;
|
|
177
197
|
} catch (err) {
|
|
178
|
-
|
|
198
|
+
const code = err.code;
|
|
199
|
+
if (code === "EPERM" || code === "EACCES") return true;
|
|
179
200
|
return false;
|
|
180
201
|
}
|
|
181
202
|
}
|
|
182
|
-
function
|
|
203
|
+
function scanDiscovery(reap) {
|
|
183
204
|
const dir = sessionDiscoveryDir();
|
|
184
205
|
const active = /* @__PURE__ */ new Set();
|
|
185
206
|
const livePaths = /* @__PURE__ */ new Set();
|
|
207
|
+
const liveOwners = [];
|
|
186
208
|
let entries;
|
|
187
209
|
try {
|
|
188
210
|
entries = fs.readdirSync(dir);
|
|
189
211
|
} catch {
|
|
190
|
-
return { active, livePaths };
|
|
212
|
+
return { active, livePaths, liveOwners };
|
|
191
213
|
}
|
|
192
214
|
const dead = [];
|
|
193
215
|
for (const name of entries) {
|
|
@@ -200,13 +222,20 @@ function listActiveSessionIds() {
|
|
|
200
222
|
const livenessPid = data.proxyPid ?? data.pid;
|
|
201
223
|
if (typeof livenessPid === "number" && isProcessAlive(livenessPid)) {
|
|
202
224
|
active.add(sessionId);
|
|
203
|
-
if (data.eventLogPath)
|
|
225
|
+
if (data.eventLogPath) {
|
|
226
|
+
livePaths.add(path.resolve(data.eventLogPath));
|
|
227
|
+
liveOwners.push({
|
|
228
|
+
discoveryKey: data.discoveryKey ?? sessionId,
|
|
229
|
+
eventLogPath: path.resolve(data.eventLogPath)
|
|
230
|
+
});
|
|
231
|
+
}
|
|
204
232
|
} else {
|
|
205
233
|
dead.push({ filePath, eventLogPath: data.eventLogPath });
|
|
206
234
|
}
|
|
207
235
|
} catch {
|
|
208
236
|
}
|
|
209
237
|
}
|
|
238
|
+
if (!reap) return { active, livePaths, liveOwners };
|
|
210
239
|
for (const { filePath, eventLogPath } of dead) {
|
|
211
240
|
try {
|
|
212
241
|
fs.unlinkSync(filePath);
|
|
@@ -216,14 +245,14 @@ function listActiveSessionIds() {
|
|
|
216
245
|
reapEventLogSiblings(eventLogPath);
|
|
217
246
|
}
|
|
218
247
|
}
|
|
219
|
-
return { active, livePaths };
|
|
248
|
+
return { active, livePaths, liveOwners };
|
|
220
249
|
}
|
|
221
250
|
function sweepStaleEventLogs(dir = DEFAULT_DIR, minAgeMs = DEFAULT_MIN_AGE_MS) {
|
|
222
251
|
try {
|
|
223
252
|
fs.unlinkSync(path.join(dir, "kojee-events-no-session.log"));
|
|
224
253
|
} catch {
|
|
225
254
|
}
|
|
226
|
-
const { active, livePaths } =
|
|
255
|
+
const { active, livePaths } = scanDiscovery(true);
|
|
227
256
|
let entries;
|
|
228
257
|
try {
|
|
229
258
|
entries = fs.readdirSync(dir);
|
|
@@ -266,6 +295,7 @@ function sweepStaleEventLogs(dir = DEFAULT_DIR, minAgeMs = DEFAULT_MIN_AGE_MS) {
|
|
|
266
295
|
export {
|
|
267
296
|
STATUS_LINE_PREFIX,
|
|
268
297
|
statusLogPath,
|
|
298
|
+
resolveEventLogPath,
|
|
269
299
|
startEventLog,
|
|
270
300
|
monitorHeartbeatPath,
|
|
271
301
|
nudgeSentinelPath,
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
// src/fs-retry.ts
|
|
2
|
+
import fs from "fs";
|
|
3
|
+
var RETRYABLE = /* @__PURE__ */ new Set(["EPERM", "EBUSY", "EACCES"]);
|
|
4
|
+
function sleepSync(ms) {
|
|
5
|
+
if (ms <= 0) return;
|
|
6
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
7
|
+
}
|
|
8
|
+
function withFileOpRetry(op, opts = {}) {
|
|
9
|
+
const tries = opts.tries ?? 5;
|
|
10
|
+
const backoffMs = opts.backoffMs ?? 15;
|
|
11
|
+
let lastErr;
|
|
12
|
+
for (let i = 0; i < tries; i++) {
|
|
13
|
+
try {
|
|
14
|
+
return op();
|
|
15
|
+
} catch (err) {
|
|
16
|
+
const code = err.code;
|
|
17
|
+
if (!code || !RETRYABLE.has(code)) throw err;
|
|
18
|
+
lastErr = err;
|
|
19
|
+
if (i < tries - 1) sleepSync(backoffMs);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
throw lastErr;
|
|
23
|
+
}
|
|
24
|
+
function renameSyncRetry(from, to, opts) {
|
|
25
|
+
withFileOpRetry(() => fs.renameSync(from, to), opts);
|
|
26
|
+
}
|
|
27
|
+
function unlinkSyncRetry(p, opts) {
|
|
28
|
+
try {
|
|
29
|
+
withFileOpRetry(() => fs.unlinkSync(p), opts);
|
|
30
|
+
} catch (err) {
|
|
31
|
+
if (err.code !== "ENOENT") throw err;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// src/secure-file.ts
|
|
36
|
+
import fs2 from "fs";
|
|
37
|
+
import os from "os";
|
|
38
|
+
import { execFileSync } from "child_process";
|
|
39
|
+
function isWindows() {
|
|
40
|
+
return process.platform === "win32";
|
|
41
|
+
}
|
|
42
|
+
function secureFile(filePath) {
|
|
43
|
+
if (isWindows()) {
|
|
44
|
+
restrictAclToCurrentUser(filePath, "(F)");
|
|
45
|
+
} else {
|
|
46
|
+
try {
|
|
47
|
+
fs2.chmodSync(filePath, 384);
|
|
48
|
+
} catch {
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function secureDir(dirPath) {
|
|
53
|
+
if (isWindows()) {
|
|
54
|
+
restrictAclToCurrentUser(dirPath, "(OI)(CI)(F)");
|
|
55
|
+
} else {
|
|
56
|
+
try {
|
|
57
|
+
fs2.chmodSync(dirPath, 448);
|
|
58
|
+
} catch {
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function currentUserSid() {
|
|
63
|
+
try {
|
|
64
|
+
const out = execFileSync("whoami", ["/user", "/fo", "csv", "/nh"], { encoding: "utf8" });
|
|
65
|
+
const m = out.match(/S-1-[0-9-]+/);
|
|
66
|
+
return m ? m[0] : null;
|
|
67
|
+
} catch {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function restrictAclToCurrentUser(target, permission) {
|
|
72
|
+
try {
|
|
73
|
+
const sid = currentUserSid();
|
|
74
|
+
const grantee = sid ? `*${sid}` : os.userInfo().username;
|
|
75
|
+
execFileSync("icacls", [target, "/grant:r", `${grantee}:${permission}`], { stdio: "ignore" });
|
|
76
|
+
execFileSync("icacls", [target, "/inheritance:r"], { stdio: "ignore" });
|
|
77
|
+
if (permission.includes("(F)")) {
|
|
78
|
+
try {
|
|
79
|
+
fs2.accessSync(target, fs2.constants.R_OK);
|
|
80
|
+
} catch {
|
|
81
|
+
try {
|
|
82
|
+
execFileSync("icacls", [target, "/grant:r", `${grantee}:${permission}`], { stdio: "ignore" });
|
|
83
|
+
} catch {
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
} catch {
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function createSecureFileSync(filePath) {
|
|
91
|
+
unlinkSyncRetry(filePath);
|
|
92
|
+
const fd = fs2.openSync(filePath, "wx", 384);
|
|
93
|
+
fs2.closeSync(fd);
|
|
94
|
+
secureFile(filePath);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export {
|
|
98
|
+
renameSyncRetry,
|
|
99
|
+
unlinkSyncRetry,
|
|
100
|
+
secureFile,
|
|
101
|
+
secureDir,
|
|
102
|
+
createSecureFileSync
|
|
103
|
+
};
|