kojee-mcp 0.5.19 → 0.7.0

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-U4MNICQI.js → chunk-247WFMCJ.js} +12 -22
  5. package/dist/{chunk-PSVVRGJC.js → chunk-5H75AEZ2.js} +22 -9
  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-EIAUW6KO.js +82 -0
  12. package/dist/chunk-EIH2LNF4.js +45 -0
  13. package/dist/{chunk-74XFVX6Z.js → chunk-FSKGQ6GT.js} +47 -10
  14. package/dist/{chunk-GI2CKKBL.js → chunk-GKXHKR3B.js} +1 -1
  15. package/dist/{wizard-Y3ULSO2C.js → chunk-GVWYW7MY.js} +247 -138
  16. package/dist/{chunk-JXMVZEQ7.js → chunk-I67C2HYA.js} +1 -1
  17. package/dist/chunk-KNEJTD6G.js +31 -0
  18. package/dist/{chunk-NR4Y54OL.js → chunk-MIEI4PLB.js} +1 -19
  19. package/dist/chunk-NE2F5CKS.js +113 -0
  20. package/dist/{chunk-XXFVWP6H.js → chunk-OB5T6P24.js} +1 -1
  21. package/dist/{chunk-65KRRDHP.js → chunk-OBIJ6WQP.js} +82 -27
  22. package/dist/{chunk-DXJ6QLSJ.js → chunk-PKOBR7ZN.js} +1 -1
  23. package/dist/{chunk-2OLXXOT3.js → chunk-PPTKGWFF.js} +69 -3
  24. package/dist/{chunk-X672ZN7V.js → chunk-QEJUNP3X.js} +3 -2
  25. package/dist/chunk-QJFMU4QC.js +33 -0
  26. package/dist/{chunk-EW72ZNQL.js → chunk-RDLF4NQC.js} +1 -1
  27. package/dist/{chunk-XIDCYUTK.js → chunk-SGRVG4HW.js} +9 -4
  28. package/dist/{chunk-DURRQDYI.js → chunk-TNZITJAB.js} +45 -15
  29. package/dist/chunk-U5HHHRXA.js +103 -0
  30. package/dist/chunk-WBXU27BF.js +35 -0
  31. package/dist/chunk-WIU5WGDF.js +10 -0
  32. package/dist/chunk-XJEBJIQE.js +52 -0
  33. package/dist/chunk-Z5LPNJQ6.js +20 -0
  34. package/dist/cli.js +121 -89
  35. package/dist/{chunk-35XBRG3V.js → codex-stop-hook-EOMQD3J4.js} +11 -15
  36. package/dist/connect-handler-HIRM624N.js +137 -0
  37. package/dist/{control-token-4BUCTYQB.js → control-token-KXSZ3GBY.js} +2 -2
  38. package/dist/{doctor-U3MTB4GY.js → doctor-PLKLHTJM.js} +48 -22
  39. package/dist/{doctor-codex-PA3WO6LR.js → doctor-codex-HARAAH4Y.js} +23 -6
  40. package/dist/doctor-openclaw-LL6NSPLC.js +86 -0
  41. package/dist/{event-log-HOBO3ECB.js → event-log-2NBJEIEP.js} +5 -3
  42. package/dist/{event-stream-XX5EZ6HN.js → event-stream-KRYWEYWO.js} +7 -4
  43. package/dist/{hook-server-XK2NHLJV.js → hook-server-CWBH6PFL.js} +2 -2
  44. package/dist/index.js +13 -11
  45. package/dist/{install-LJY2CHKG.js → install-V7LSQCYZ.js} +37 -22
  46. package/dist/{keystore-XLEV3FL5.js → keystore-LQNFDHGO.js} +2 -2
  47. package/dist/lib.d.ts +4 -1
  48. package/dist/lib.js +12 -9
  49. package/dist/pair-HTCVSMR6.js +11 -0
  50. package/dist/{paired-config-JTFLHMZ2.js → paired-config-GUDDO2CH.js} +4 -2
  51. package/dist/{parent-watchdog-TLU355FB.js → parent-watchdog-LTUNF7PD.js} +24 -5
  52. package/dist/{registry-CGLE5X54.js → registry-VRFHKOPP.js} +195 -26
  53. package/dist/resolve-slot-BFIB46Y5.js +13 -0
  54. package/dist/{runtime-record-WO4IECM6.js → runtime-record-OXRLTOLC.js} +2 -2
  55. package/dist/{send-cli-IPADRDD2.js → send-cli-45RLGYIC.js} +24 -12
  56. package/dist/{server-LTFG4GMV.js → server-YTHOMA4H.js} +5 -3
  57. package/dist/{session-discovery-FNMJGFPM.js → session-discovery-NHCZ2XWA.js} +2 -2
  58. package/dist/setup-handler-UHVKSX7E.js +159 -0
  59. package/dist/{stop-hook-QZTFH5WV.js → stop-hook-YI4KRKF2.js} +17 -20
  60. package/dist/{tail-stream-CEJZGSIR.js → tail-stream-NBGHHBS4.js} +61 -22
  61. package/dist/{user-prompt-submit-hook-FQ43NIHC.js → user-prompt-submit-hook-DTXXFDSD.js} +11 -14
  62. package/package.json +2 -1
  63. package/dist/ancestry-ONFBQEP5.js +0 -8
  64. package/dist/chunk-BLEGIR35.js +0 -43
  65. package/dist/chunk-CLKCNV2A.js +0 -100
  66. package/dist/chunk-OGHDTFAX.js +0 -50
  67. package/dist/chunk-VHKPWUX7.js +0 -41
  68. package/dist/codex-stop-hook-VY7DOMAG.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
+ };
@@ -0,0 +1,35 @@
1
+ import {
2
+ readSessionDiscoveryByKey
3
+ } from "./chunk-67F67AQ6.js";
4
+ import {
5
+ deriveDiscoveryKey,
6
+ findClaudeAncestorPid
7
+ } from "./chunk-XJEBJIQE.js";
8
+ import {
9
+ resolveSharedSessionId
10
+ } from "./chunk-KNEJTD6G.js";
11
+
12
+ // src/hooks/discovery.ts
13
+ async function resolveHookDiscovery(stdinSessionId, deps = {}) {
14
+ const read = deps.readDiscovery ?? readSessionDiscoveryByKey;
15
+ const findPid = deps.findAncestorPid ?? findClaudeAncestorPid;
16
+ const projectDir = deps.projectDir !== void 0 ? deps.projectDir : process.env["CLAUDE_PROJECT_DIR"];
17
+ const sessionId = resolveSharedSessionId({ env: {}, stdinSessionId });
18
+ if (sessionId) {
19
+ const sidKey = deriveDiscoveryKey(projectDir, null, sessionId);
20
+ const sidHit = read(sidKey);
21
+ if (sidHit) return { discovery: sidHit, key: sidKey };
22
+ const ccPid2 = await findPid();
23
+ const legacyKey2 = deriveDiscoveryKey(projectDir, ccPid2, null);
24
+ const legacyHit = read(legacyKey2);
25
+ if (legacyHit) return { discovery: legacyHit, key: legacyKey2 };
26
+ return { discovery: null, key: sidKey };
27
+ }
28
+ const ccPid = await findPid();
29
+ const legacyKey = deriveDiscoveryKey(projectDir, ccPid, null);
30
+ return { discovery: read(legacyKey), key: legacyKey };
31
+ }
32
+
33
+ export {
34
+ resolveHookDiscovery
35
+ };
@@ -0,0 +1,10 @@
1
+ // src/hooks/codex-pending-path.ts
2
+ import os from "os";
3
+ import path from "path";
4
+ function codexPendingMarkerPath() {
5
+ return path.join(os.homedir(), ".kojee", "codex-pending");
6
+ }
7
+
8
+ export {
9
+ codexPendingMarkerPath
10
+ };
@@ -0,0 +1,52 @@
1
+ // src/runtime/ancestry.ts
2
+ import psList from "ps-list";
3
+ import { createHash } from "crypto";
4
+ var CLAUDE_PROCESS_RE = /\bclaude\b/i;
5
+ function rowLooksLikeClaude(row) {
6
+ return CLAUDE_PROCESS_RE.test(`${row.name} ${row.cmd ?? ""}`);
7
+ }
8
+ async function findClaudeAncestorPid(startPid = process.ppid) {
9
+ let processes;
10
+ try {
11
+ processes = await psList();
12
+ } catch {
13
+ return null;
14
+ }
15
+ const byPid = /* @__PURE__ */ new Map();
16
+ for (const p of processes) byPid.set(p.pid, p);
17
+ let pid = startPid;
18
+ for (let depth = 0; depth < 20 && pid !== void 0 && pid > 1; depth++) {
19
+ const row = byPid.get(pid);
20
+ if (!row) return null;
21
+ if (rowLooksLikeClaude(row)) return pid;
22
+ if (row.ppid === void 0 || row.ppid === pid) return null;
23
+ pid = row.ppid;
24
+ }
25
+ return null;
26
+ }
27
+ async function pidLooksLikeClaude(pid) {
28
+ let processes;
29
+ try {
30
+ processes = await psList();
31
+ } catch {
32
+ return null;
33
+ }
34
+ const row = processes.find((p) => p.pid === pid);
35
+ if (!row) return null;
36
+ return rowLooksLikeClaude(row);
37
+ }
38
+ function deriveDiscoveryKey(projectDir, ccPid, sessionId) {
39
+ const hasProjectDir = typeof projectDir === "string" && projectDir.length > 0;
40
+ const prefix = createHash("sha256").update(hasProjectDir ? projectDir : "<no-project>").digest("hex").slice(0, 12);
41
+ const sid = typeof sessionId === "string" ? sessionId.trim() : "";
42
+ if (sid) return `${prefix}-s-${sid}`;
43
+ if (!hasProjectDir && ccPid === null) return `orphan-${process.pid}`;
44
+ if (ccPid === null) return `${prefix}-orphan`;
45
+ return `${prefix}-${ccPid}`;
46
+ }
47
+
48
+ export {
49
+ findClaudeAncestorPid,
50
+ pidLooksLikeClaude,
51
+ deriveDiscoveryKey
52
+ };
@@ -0,0 +1,20 @@
1
+ // src/tandem/session-id.ts
2
+ import crypto from "crypto";
3
+ import { ulid } from "ulidx";
4
+ var MCP_SESSION_ID = ulid();
5
+ function deriveStableSessionId(token, instanceKey) {
6
+ return crypto.createHash("sha256").update(`${token}:${instanceKey}`).digest("hex").slice(0, 32);
7
+ }
8
+ var _stableSessionId = null;
9
+ function setStableSessionId(id) {
10
+ _stableSessionId = id;
11
+ }
12
+ function getSessionId() {
13
+ return _stableSessionId ?? MCP_SESSION_ID;
14
+ }
15
+
16
+ export {
17
+ deriveStableSessionId,
18
+ setStableSessionId,
19
+ getSessionId
20
+ };