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.
Files changed (70) hide show
  1. package/README.md +13 -8
  2. package/dist/ancestry-A2F5KQ6A.js +10 -0
  3. package/dist/cc-session-id-RURNIHHC.js +10 -0
  4. package/dist/{chunk-KH5YEJIM.js → chunk-247WFMCJ.js} +7 -20
  5. package/dist/chunk-5DHIUN73.js +25 -0
  6. package/dist/{chunk-YH27B6SW.js → chunk-5SZHXYPK.js} +16 -3
  7. package/dist/{chunk-DO42NPNR.js → chunk-67F67AQ6.js} +14 -3
  8. package/dist/{chunk-CH32ELFX.js → chunk-6G6YYST6.js} +1 -1
  9. package/dist/chunk-D6JKFJ6A.js +11 -0
  10. package/dist/chunk-E6WMFMM2.js +100 -0
  11. package/dist/chunk-EBYUJM3H.js +14 -0
  12. package/dist/chunk-EIAUW6KO.js +82 -0
  13. package/dist/chunk-EIH2LNF4.js +45 -0
  14. package/dist/{chunk-BYV7CWNY.js → chunk-FBJCPRVH.js} +22 -9
  15. package/dist/{chunk-XN3IC4B5.js → chunk-FSKGQ6GT.js} +30 -5
  16. package/dist/{chunk-GI2CKKBL.js → chunk-GKXHKR3B.js} +1 -1
  17. package/dist/{chunk-ALZX3SGI.js → chunk-GNLCUJBK.js} +13 -27
  18. package/dist/{chunk-JXMVZEQ7.js → chunk-I67C2HYA.js} +1 -1
  19. package/dist/chunk-KNEJTD6G.js +31 -0
  20. package/dist/{chunk-65KRRDHP.js → chunk-KPMD72FY.js} +94 -28
  21. package/dist/{chunk-NR4Y54OL.js → chunk-MIEI4PLB.js} +1 -19
  22. package/dist/chunk-NE2F5CKS.js +113 -0
  23. package/dist/chunk-QJFMU4QC.js +33 -0
  24. package/dist/{chunk-EW72ZNQL.js → chunk-RDLF4NQC.js} +1 -1
  25. package/dist/{chunk-Q7T3WAST.js → chunk-SSW5AQSR.js} +6 -1
  26. package/dist/{chunk-DURRQDYI.js → chunk-TNZITJAB.js} +45 -15
  27. package/dist/chunk-U5HHHRXA.js +103 -0
  28. package/dist/{setup-handler-7HOFAD7C.js → chunk-UFHGZUST.js} +431 -253
  29. package/dist/{chunk-N35X22G7.js → chunk-UPJV7GBE.js} +1 -1
  30. package/dist/chunk-WBXU27BF.js +35 -0
  31. package/dist/chunk-XJEBJIQE.js +52 -0
  32. package/dist/chunk-Z5LPNJQ6.js +20 -0
  33. package/dist/cli.js +63 -25
  34. package/dist/codex-stop-hook-BMOJVM6O.js +96 -0
  35. package/dist/connect-handler-4DRTFMOB.js +138 -0
  36. package/dist/{control-token-4BUCTYQB.js → control-token-KXSZ3GBY.js} +2 -2
  37. package/dist/{doctor-WVX3WCYX.js → doctor-5QJ3HGNR.js} +48 -22
  38. package/dist/{doctor-codex-Z5M4SFBG.js → doctor-codex-VGJKTX2E.js} +33 -7
  39. package/dist/doctor-openclaw-LL6NSPLC.js +86 -0
  40. package/dist/{event-log-HOBO3ECB.js → event-log-2NBJEIEP.js} +5 -3
  41. package/dist/{event-stream-SYBUJ5EH.js → event-stream-KRYWEYWO.js} +7 -4
  42. package/dist/index.js +13 -10
  43. package/dist/{install-LJY2CHKG.js → install-V7LSQCYZ.js} +37 -22
  44. package/dist/{keystore-XLEV3FL5.js → keystore-LQNFDHGO.js} +2 -2
  45. package/dist/lib.d.ts +4 -1
  46. package/dist/lib.js +11 -8
  47. package/dist/pair-HTCVSMR6.js +11 -0
  48. package/dist/{paired-config-JTFLHMZ2.js → paired-config-GUDDO2CH.js} +4 -2
  49. package/dist/{parent-watchdog-TLU355FB.js → parent-watchdog-LTUNF7PD.js} +24 -5
  50. package/dist/{registry-YLOFZDI2.js → registry-ZZZ26WGA.js} +197 -24
  51. package/dist/resolve-slot-BFIB46Y5.js +13 -0
  52. package/dist/{runtime-record-WO4IECM6.js → runtime-record-OXRLTOLC.js} +2 -2
  53. package/dist/{send-cli-IYJF32PE.js → send-cli-45RLGYIC.js} +22 -10
  54. package/dist/{server-R24AVNTI.js → server-ITPFQVTK.js} +5 -2
  55. package/dist/{session-discovery-FNMJGFPM.js → session-discovery-NHCZ2XWA.js} +2 -2
  56. package/dist/setup-handler-JFM45NCN.js +160 -0
  57. package/dist/{stop-hook-TCPJFGFF.js → stop-hook-5ABGTC2O.js} +17 -20
  58. package/dist/{tail-stream-4IMXI44S.js → tail-stream-NBGHHBS4.js} +40 -22
  59. package/dist/{user-prompt-submit-hook-FQ43NIHC.js → user-prompt-submit-hook-DTXXFDSD.js} +11 -14
  60. package/package.json +3 -2
  61. package/skills/using-tandems/SKILL.md +52 -0
  62. package/dist/ancestry-ONFBQEP5.js +0 -8
  63. package/dist/chunk-BLEGIR35.js +0 -43
  64. package/dist/chunk-CLKCNV2A.js +0 -100
  65. package/dist/chunk-KFDZWNQO.js +0 -73
  66. package/dist/chunk-OGHDTFAX.js +0 -50
  67. package/dist/chunk-VHKPWUX7.js +0 -41
  68. package/dist/codex-stop-hook-RWQSZTST.js +0 -16
  69. package/dist/doctor-openclaw-SS2TMQOX.js +0 -95
  70. package/dist/pair-P4ILCMT7.js +0 -10
@@ -1,9 +1,10 @@
1
1
  import {
2
+ readSessionDiscoveryByKey,
2
3
  sessionDiscoveryDir
3
- } from "./chunk-DO42NPNR.js";
4
+ } from "./chunk-67F67AQ6.js";
4
5
  import {
5
6
  secureFile
6
- } from "./chunk-BLEGIR35.js";
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 livePathOwnedBySibling(candidatePath) {
25
+ function livePathOwnedByForeignProxy(candidatePath, selfKey) {
25
26
  try {
26
- const { livePaths } = listActiveSessionIds();
27
- return livePaths.has(path.resolve(candidatePath));
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
- let filePath = path.join(dir, `kojee-events-${opts.key}.log`);
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
- if (err.code === "EPERM") return true;
198
+ const code = err.code;
199
+ if (code === "EPERM" || code === "EACCES") return true;
179
200
  return false;
180
201
  }
181
202
  }
182
- function listActiveSessionIds() {
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) livePaths.add(path.resolve(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 } = listActiveSessionIds();
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
+ };