kojee-mcp 0.7.5-staging.2 → 0.7.5-staging.21
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 +27 -6
- package/dist/{cc-session-id-RURNIHHC.js → cc-session-id-5HHQJ7VC.js} +3 -1
- package/dist/{chunk-ZSHCHOPL.js → chunk-676WQSWZ.js} +163 -7
- package/dist/{chunk-FJUAMJHU.js → chunk-6NPMVZD7.js} +38 -3
- package/dist/{chunk-247WFMCJ.js → chunk-AGZ7ZGLY.js} +30 -3
- package/dist/chunk-AXBJQJKA.js +65 -0
- package/dist/{chunk-TCWIXG5C.js → chunk-CCVRXJJ2.js} +1 -1
- package/dist/{chunk-WBXU27BF.js → chunk-FNMKP34Y.js} +1 -1
- package/dist/chunk-GEGUWQYT.js +90 -0
- package/dist/{chunk-NE2F5CKS.js → chunk-LKGKDZSO.js} +9 -5
- package/dist/{chunk-XPIW4N55.js → chunk-N2YAZRAD.js} +178 -43
- package/dist/{chunk-LSUB6QMP.js → chunk-NIIBVKLP.js} +3 -0
- package/dist/chunk-P64UR3SE.js +86 -0
- package/dist/{chunk-A4IOKD4Z.js → chunk-QYZP6QT2.js} +2 -4
- package/dist/{chunk-KNEJTD6G.js → chunk-SZLNNMIZ.js} +6 -2
- package/dist/{chunk-CUOJHP2S.js → chunk-UGEBGCYU.js} +48 -12
- package/dist/{chunk-6XWTUDWW.js → chunk-WDWVBPXA.js} +7 -5
- package/dist/{chunk-TNZITJAB.js → chunk-WVQU3QQ7.js} +14 -4
- package/dist/cli.js +42 -23
- package/dist/{codex-prompt-submit-hook-J5PZEJSK.js → codex-prompt-submit-hook-UQJI6A54.js} +2 -2
- package/dist/{codex-stop-hook-32W4BIOM.js → codex-stop-hook-GTGRQNVV.js} +2 -2
- package/dist/{connect-handler-NZINEMG3.js → connect-handler-GTFXNZUC.js} +68 -9
- package/dist/{doctor-WUU5BVPT.js → doctor-54S7JGOE.js} +64 -5
- package/dist/{doctor-codex-PJFWIABF.js → doctor-codex-6H4OOS6O.js} +84 -10
- package/dist/doctor-hermes-KMHM27Y3.js +597 -0
- package/dist/{doctor-openclaw-LL6NSPLC.js → doctor-openclaw-B5KADVHD.js} +5 -1
- package/dist/{event-log-2NBJEIEP.js → event-log-M22X3FAI.js} +1 -1
- package/dist/{event-stream-ATKYXDBV.js → event-stream-5ZEL7FXN.js} +5 -1
- package/dist/flap-log-D4KG7RK4.js +23 -0
- package/dist/{gateway-client-CbM2OC_w.d.ts → gateway-client-CLmQghON.d.ts} +11 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +6 -7
- package/dist/{install-JQNDGAAQ.js → install-GJVZEWLI.js} +8 -7
- package/dist/lib.d.ts +30 -1
- package/dist/lib.js +3 -3
- package/dist/plugins/hermes/adapter.py +7 -2
- package/dist/{registry-XJ67EO22.js → registry-MCJAVXJW.js} +36 -24
- package/dist/{send-cli-45RLGYIC.js → send-cli-WTY7H3BR.js} +2 -2
- package/dist/{server-DU3LFS32.js → server-VM3ZIGSZ.js} +2 -3
- package/dist/session-start-hook-VL3KYDTT.js +25 -0
- package/dist/{setup-handler-44ASXYMS.js → setup-handler-GNAIWAYU.js} +7 -7
- package/dist/{stop-hook-N6TX4YQT.js → stop-hook-BLPYRE7T.js} +5 -5
- package/dist/stream-watchdog-K2AWNCQW.js +64 -0
- package/dist/{tail-stream-G4WGTXDS.js → tail-stream-PQXEY3TI.js} +120 -9
- package/dist/{user-prompt-submit-hook-DTXXFDSD.js → user-prompt-submit-hook-YQXGE3JU.js} +3 -3
- package/package.json +3 -2
- package/dist/chunk-5DHIUN73.js +0 -25
- package/dist/chunk-TMCNB4JH.js +0 -33
|
@@ -3,19 +3,20 @@ import {
|
|
|
3
3
|
STATUS_LINE_PREFIX,
|
|
4
4
|
monitorHeartbeatPath,
|
|
5
5
|
statusLogPath
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-WVQU3QQ7.js";
|
|
7
7
|
import "./chunk-67F67AQ6.js";
|
|
8
8
|
import {
|
|
9
9
|
LOG_HEARTBEAT_INTERVAL_MS,
|
|
10
10
|
UNARMED_FALLBACK_MS,
|
|
11
11
|
createAdaptiveWatchdog
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-UGEBGCYU.js";
|
|
13
13
|
import "./chunk-Z5LPNJQ6.js";
|
|
14
14
|
import "./chunk-MIEI4PLB.js";
|
|
15
15
|
import "./chunk-U5HHHRXA.js";
|
|
16
16
|
|
|
17
17
|
// src/tail-stream.ts
|
|
18
18
|
import fs from "fs";
|
|
19
|
+
import { spawn } from "child_process";
|
|
19
20
|
var STATUS_LINE_RE = new RegExp(`^\\[[^\\]]*\\] ${STATUS_LINE_PREFIX} (.*)$`);
|
|
20
21
|
var HEARTBEAT_FIELDS_RE = /(^|\s)status=heartbeat(\s|$)/;
|
|
21
22
|
var ROTATED_FIELDS_RE = /(^|\s)status=rotated(\s|$)/;
|
|
@@ -29,6 +30,7 @@ var TAIL_STALE_FLOOR_MS = envInt(
|
|
|
29
30
|
);
|
|
30
31
|
var STALE_CHECK_INTERVAL_MS = envInt("KOJEE_TAIL_CHECK_MS", 5e3);
|
|
31
32
|
var TAIL_REWARN_AFTER_MS = 30 * 6e4;
|
|
33
|
+
var SUSTAINED_STALE_MS = envInt("KOJEE_TAIL_SUSTAINED_MS", TAIL_REWARN_AFTER_MS);
|
|
32
34
|
var TAIL_HEALTHY_RESET_MS = 30 * 6e4;
|
|
33
35
|
var TAIL_BACKOFF_CAP_CYCLES = 3;
|
|
34
36
|
function envInt(name, fallback) {
|
|
@@ -99,9 +101,14 @@ function createStallDetector(startNow, options = {}) {
|
|
|
99
101
|
}
|
|
100
102
|
};
|
|
101
103
|
}
|
|
102
|
-
async function runTail(messagesPath) {
|
|
104
|
+
async function runTail(messagesPath, opts = {}) {
|
|
105
|
+
const wakeOnly = opts.wakeOnly === true;
|
|
106
|
+
const replay = opts.replay === true;
|
|
103
107
|
const statusPath = statusLogPath(messagesPath);
|
|
104
|
-
const detector = createStallDetector(Date.now(), {
|
|
108
|
+
const detector = createStallDetector(Date.now(), {
|
|
109
|
+
floorMs: TAIL_STALE_FLOOR_MS,
|
|
110
|
+
rewarnAfterMs: SUSTAINED_STALE_MS
|
|
111
|
+
});
|
|
105
112
|
const heartbeatPath = monitorHeartbeatPath(messagesPath);
|
|
106
113
|
const touchHeartbeat = () => {
|
|
107
114
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -116,7 +123,7 @@ async function runTail(messagesPath) {
|
|
|
116
123
|
};
|
|
117
124
|
let lastCursor = null;
|
|
118
125
|
function onMessageLine(line) {
|
|
119
|
-
if (detector.onLife(Date.now())?.kind === "recovered") {
|
|
126
|
+
if (detector.onLife(Date.now())?.kind === "recovered" && !wakeOnly) {
|
|
120
127
|
process.stdout.write(
|
|
121
128
|
"[kojee] stream recovered \u2014 events flowing again (recovery is automatic; no action needed).\n"
|
|
122
129
|
);
|
|
@@ -133,7 +140,7 @@ async function runTail(messagesPath) {
|
|
|
133
140
|
if (HEARTBEAT_FIELDS_RE.test(fields)) {
|
|
134
141
|
detector.onHeartbeat(now);
|
|
135
142
|
}
|
|
136
|
-
if (detector.onLife(now)?.kind === "recovered") {
|
|
143
|
+
if (detector.onLife(now)?.kind === "recovered" && !wakeOnly) {
|
|
137
144
|
process.stdout.write(
|
|
138
145
|
"[kojee] stream recovered \u2014 heartbeats resumed (the stall was transient, likely idle-period timing or brief host load; no action needed).\n"
|
|
139
146
|
);
|
|
@@ -149,8 +156,16 @@ async function runTail(messagesPath) {
|
|
|
149
156
|
}
|
|
150
157
|
}
|
|
151
158
|
const followers = [
|
|
152
|
-
|
|
153
|
-
|
|
159
|
+
// MESSAGES (wake-critical) — prefer the OS `tail -F` follower where the
|
|
160
|
+
// platform has one; it delegates file-following to the battle-tested system
|
|
161
|
+
// binary instead of the Node fs.watch/poll tailer. STATUS (telemetry) stays
|
|
162
|
+
// on the Node follower: its startup-backlog seeding boundary (statusSeeded)
|
|
163
|
+
// is clean to detect only when we control the drain. See makeMessagesFollower.
|
|
164
|
+
makeMessagesFollower(messagesPath, onMessageLine, touchHeartbeat, replay),
|
|
165
|
+
// STATUS stays replay=true: its single current-state line is seeded on
|
|
166
|
+
// attach (statusSeeded boundary) — that's cheap, not a flood, and the
|
|
167
|
+
// connected/rotated seed is what primes the watchdog + backfill logic.
|
|
168
|
+
makeFollower(statusPath, onStatusLine, touchHeartbeat, true)
|
|
154
169
|
];
|
|
155
170
|
void Promise.all([
|
|
156
171
|
followers[0].start(),
|
|
@@ -171,6 +186,7 @@ async function runTail(messagesPath) {
|
|
|
171
186
|
);
|
|
172
187
|
return;
|
|
173
188
|
}
|
|
189
|
+
if (wakeOnly) return;
|
|
174
190
|
const thresholdS = Math.round((signal.thresholdMs ?? 0) / 1e3);
|
|
175
191
|
process.stdout.write(
|
|
176
192
|
`[kojee] WARNING: no events or heartbeat for ${silentS}s (threshold ${thresholdS}s) \u2014 stream may be dead, but this is often benign (idle stream, or brief host load delaying heartbeats) and recovery is automatic; if it persists, run \`npx kojee-mcp doctor\`.
|
|
@@ -191,7 +207,7 @@ async function runTail(messagesPath) {
|
|
|
191
207
|
process.on("SIGINT", cleanup);
|
|
192
208
|
});
|
|
193
209
|
}
|
|
194
|
-
function makeFollower(filePath, onLine, onActivity) {
|
|
210
|
+
function makeFollower(filePath, onLine, onActivity, replay = true) {
|
|
195
211
|
let buffer = "";
|
|
196
212
|
let offset = 0;
|
|
197
213
|
let watcher = null;
|
|
@@ -248,6 +264,12 @@ function makeFollower(filePath, onLine, onActivity) {
|
|
|
248
264
|
await sleep(250);
|
|
249
265
|
}
|
|
250
266
|
if (stopped) return;
|
|
267
|
+
if (!replay) {
|
|
268
|
+
try {
|
|
269
|
+
offset = (await fs.promises.stat(filePath)).size;
|
|
270
|
+
} catch {
|
|
271
|
+
}
|
|
272
|
+
}
|
|
251
273
|
onActivity();
|
|
252
274
|
await scheduleDrain();
|
|
253
275
|
pollTimer = setInterval(() => {
|
|
@@ -273,11 +295,100 @@ function makeFollower(filePath, onLine, onActivity) {
|
|
|
273
295
|
}
|
|
274
296
|
};
|
|
275
297
|
}
|
|
298
|
+
function osTailAvailable() {
|
|
299
|
+
const override = (process.env.KOJEE_TAIL_IMPL ?? "").trim().toLowerCase();
|
|
300
|
+
if (override === "os") return true;
|
|
301
|
+
if (override === "node") return false;
|
|
302
|
+
return process.platform !== "win32";
|
|
303
|
+
}
|
|
304
|
+
function makeMessagesFollower(filePath, onLine, onActivity, replay = true) {
|
|
305
|
+
if (!osTailAvailable()) return makeFollower(filePath, onLine, onActivity, replay);
|
|
306
|
+
return makeTailFollower(
|
|
307
|
+
filePath,
|
|
308
|
+
onLine,
|
|
309
|
+
onActivity,
|
|
310
|
+
() => makeFollower(filePath, onLine, onActivity, replay),
|
|
311
|
+
replay
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
function makeTailFollower(filePath, onLine, onActivity, fallback, replay = true) {
|
|
315
|
+
let child = null;
|
|
316
|
+
let heir = null;
|
|
317
|
+
let hbTimer = null;
|
|
318
|
+
let buffer = "";
|
|
319
|
+
let stopped = false;
|
|
320
|
+
let handedOff = false;
|
|
321
|
+
function emit(chunk) {
|
|
322
|
+
onActivity();
|
|
323
|
+
buffer += chunk;
|
|
324
|
+
let nl;
|
|
325
|
+
while ((nl = buffer.indexOf("\n")) !== -1) {
|
|
326
|
+
onLine(buffer.slice(0, nl));
|
|
327
|
+
buffer = buffer.slice(nl + 1);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
function handOff() {
|
|
331
|
+
if (stopped || handedOff) return;
|
|
332
|
+
handedOff = true;
|
|
333
|
+
if (hbTimer) {
|
|
334
|
+
clearInterval(hbTimer);
|
|
335
|
+
hbTimer = null;
|
|
336
|
+
}
|
|
337
|
+
if (child) {
|
|
338
|
+
try {
|
|
339
|
+
child.kill("SIGTERM");
|
|
340
|
+
} catch {
|
|
341
|
+
}
|
|
342
|
+
child = null;
|
|
343
|
+
}
|
|
344
|
+
heir = fallback();
|
|
345
|
+
void heir.start().catch(() => {
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
return {
|
|
349
|
+
async start() {
|
|
350
|
+
try {
|
|
351
|
+
child = spawn("tail", ["-n", replay ? "+1" : "0", "-F", filePath], {
|
|
352
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
353
|
+
});
|
|
354
|
+
} catch {
|
|
355
|
+
handOff();
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
child.on("error", () => handOff());
|
|
359
|
+
child.on("exit", () => {
|
|
360
|
+
if (!stopped) handOff();
|
|
361
|
+
});
|
|
362
|
+
child.stdout?.setEncoding("utf8");
|
|
363
|
+
child.stdout?.on("data", (d) => emit(d));
|
|
364
|
+
onActivity();
|
|
365
|
+
hbTimer = setInterval(onActivity, 1e3);
|
|
366
|
+
},
|
|
367
|
+
stop() {
|
|
368
|
+
stopped = true;
|
|
369
|
+
if (hbTimer) {
|
|
370
|
+
clearInterval(hbTimer);
|
|
371
|
+
hbTimer = null;
|
|
372
|
+
}
|
|
373
|
+
if (child) {
|
|
374
|
+
try {
|
|
375
|
+
child.kill("SIGTERM");
|
|
376
|
+
} catch {
|
|
377
|
+
}
|
|
378
|
+
child = null;
|
|
379
|
+
}
|
|
380
|
+
if (heir) heir.stop();
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
}
|
|
276
384
|
function sleep(ms) {
|
|
277
385
|
return new Promise((r) => setTimeout(r, ms));
|
|
278
386
|
}
|
|
279
387
|
export {
|
|
280
388
|
createStallDetector,
|
|
281
389
|
makeFollower,
|
|
390
|
+
makeMessagesFollower,
|
|
391
|
+
makeTailFollower,
|
|
392
|
+
osTailAvailable,
|
|
282
393
|
runTail
|
|
283
394
|
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
resolveHookDiscovery
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-FNMKP34Y.js";
|
|
4
4
|
import {
|
|
5
5
|
readHookStdin
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-NIIBVKLP.js";
|
|
7
7
|
import {
|
|
8
8
|
controlTokenAuthHeaders
|
|
9
9
|
} from "./chunk-GKXHKR3B.js";
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
import "./chunk-67F67AQ6.js";
|
|
14
14
|
import "./chunk-U5HHHRXA.js";
|
|
15
15
|
import "./chunk-XJEBJIQE.js";
|
|
16
|
-
import "./chunk-
|
|
16
|
+
import "./chunk-SZLNNMIZ.js";
|
|
17
17
|
|
|
18
18
|
// src/hooks/user-prompt-submit-hook.ts
|
|
19
19
|
async function runUserPromptSubmitHook() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kojee-mcp",
|
|
3
|
-
"version": "0.7.5-staging.
|
|
3
|
+
"version": "0.7.5-staging.21",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -34,7 +34,8 @@
|
|
|
34
34
|
"jose": "^5.0.0",
|
|
35
35
|
"ps-list": "^8.1.1",
|
|
36
36
|
"ulidx": "^2.3.0",
|
|
37
|
-
"undici": "
|
|
37
|
+
"undici": "8.5.0",
|
|
38
|
+
"yaml": "^2.9.0",
|
|
38
39
|
"zod": "^3.22.0"
|
|
39
40
|
},
|
|
40
41
|
"devDependencies": {
|
package/dist/chunk-5DHIUN73.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
// src/version.ts
|
|
2
|
-
import fs from "fs";
|
|
3
|
-
import path from "path";
|
|
4
|
-
import { fileURLToPath } from "url";
|
|
5
|
-
var FALLBACK_VERSION = "0.0.0-unknown";
|
|
6
|
-
function resolveVersion() {
|
|
7
|
-
try {
|
|
8
|
-
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
-
const parsed = JSON.parse(
|
|
10
|
-
fs.readFileSync(path.join(here, "..", "package.json"), "utf8")
|
|
11
|
-
);
|
|
12
|
-
return typeof parsed?.version === "string" && parsed.version ? parsed.version : FALLBACK_VERSION;
|
|
13
|
-
} catch (err) {
|
|
14
|
-
process.stderr.write(
|
|
15
|
-
`kojee-mcp: could not resolve version from package.json, falling back to ${FALLBACK_VERSION}: ${String(err)}
|
|
16
|
-
`
|
|
17
|
-
);
|
|
18
|
-
return FALLBACK_VERSION;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
var VERSION = resolveVersion();
|
|
22
|
-
|
|
23
|
-
export {
|
|
24
|
-
VERSION
|
|
25
|
-
};
|
package/dist/chunk-TMCNB4JH.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
// src/hooks/hook-command.ts
|
|
2
|
-
import fs from "fs";
|
|
3
|
-
import path from "path";
|
|
4
|
-
import { fileURLToPath } from "url";
|
|
5
|
-
function npxHookCommand(type) {
|
|
6
|
-
return `npx -y kojee-mcp hook --type=${type}`;
|
|
7
|
-
}
|
|
8
|
-
function resolveCliEntry(moduleUrl = import.meta.url) {
|
|
9
|
-
try {
|
|
10
|
-
const here = fileURLToPath(moduleUrl);
|
|
11
|
-
const candidate = path.join(path.dirname(here), "cli.js");
|
|
12
|
-
return fs.existsSync(candidate) ? candidate : null;
|
|
13
|
-
} catch {
|
|
14
|
-
return null;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
function buildHookCommand(type, opts = {}) {
|
|
18
|
-
const cliEntry = opts.cliEntry !== void 0 ? opts.cliEntry : resolveCliEntry();
|
|
19
|
-
if (!cliEntry) return npxHookCommand(type);
|
|
20
|
-
const execPath = opts.execPath ?? process.execPath;
|
|
21
|
-
return `"${execPath}" "${cliEntry}" hook --type=${type}`;
|
|
22
|
-
}
|
|
23
|
-
var PINNED_HOOK_RE = /^"[^"]+" "[^"]+" hook --type=(stop|user-prompt-submit|codex-stop|codex-prompt-submit)$/;
|
|
24
|
-
function isKojeeHookCommand(command) {
|
|
25
|
-
if (command.startsWith("npx -y kojee-mcp hook --type=")) return true;
|
|
26
|
-
return PINNED_HOOK_RE.test(command);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export {
|
|
30
|
-
npxHookCommand,
|
|
31
|
-
buildHookCommand,
|
|
32
|
-
isKojeeHookCommand
|
|
33
|
-
};
|