kojee-mcp 0.7.5-staging.6 → 0.7.5-staging.7

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.
@@ -1,7 +1,32 @@
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
+
1
23
  // src/tandem/recipe.ts
2
24
  var SEND_BODY_PARAM = "body";
25
+ function monitorPackageSpec() {
26
+ return VERSION && VERSION !== "0.0.0-unknown" ? `kojee-mcp@${VERSION}` : "kojee-mcp";
27
+ }
3
28
  function buildMonitorCommand(logPath) {
4
- return `npx kojee-mcp tail "${logPath}"`;
29
+ return `npx ${monitorPackageSpec()} tail --wake-only "${logPath}"`;
5
30
  }
6
31
  function buildMonitorSpawn(logPath) {
7
32
  return `Monitor(command=\`${buildMonitorCommand(logPath)}\`, persistent=true, description="kojee Tandem events")`;
@@ -32,6 +57,7 @@ var CODEX_LISTEN_CAP_MS = 8e3;
32
57
  var CODEX_WAKE_BELL = "[kojee] Tandem events may be pending. Call tandem_pending now and drain each room it lists (tandem_messages(id, since=cursor)), then reply in the room with a normal message (kind=message \u2014 never status). If it returns none for you, ignore this.";
33
58
 
34
59
  export {
60
+ VERSION,
35
61
  buildMonitorSpawn,
36
62
  buildReplyRecipe,
37
63
  buildCatchUpNote,
@@ -5,7 +5,7 @@ import {
5
5
  isPlaceholderWebhookUrl,
6
6
  removeCodexConfig,
7
7
  writeCodexConfig
8
- } from "./chunk-6XWTUDWW.js";
8
+ } from "./chunk-T6QANUS2.js";
9
9
  import {
10
10
  removeOpenclawMcpServer,
11
11
  writeOpenclawMcpConfig
@@ -48,14 +48,12 @@ import {
48
48
  secureFile,
49
49
  unlinkSyncRetry
50
50
  } from "./chunk-U5HHHRXA.js";
51
- import {
52
- VERSION
53
- } from "./chunk-5DHIUN73.js";
54
51
  import {
55
52
  CODEX_LISTEN_CAP_MS,
53
+ VERSION,
56
54
  buildCondensedTandemRules,
57
55
  buildWebhookReceiverNote
58
- } from "./chunk-FJUAMJHU.js";
56
+ } from "./chunk-O4JQY7IF.js";
59
57
 
60
58
  // src/wizard/pair-slot.ts
61
59
  import fs from "fs";
@@ -1,12 +1,10 @@
1
1
  import {
2
- VERSION
3
- } from "./chunk-5DHIUN73.js";
4
- import {
2
+ VERSION,
5
3
  buildCatchUpNote,
6
4
  buildCondensedTandemRules,
7
5
  buildMonitorSpawn,
8
6
  buildReplyRecipe
9
- } from "./chunk-FJUAMJHU.js";
7
+ } from "./chunk-O4JQY7IF.js";
10
8
  import {
11
9
  translateToolCallResult
12
10
  } from "./chunk-PPTKGWFF.js";
@@ -14,7 +14,7 @@ import {
14
14
  } from "./chunk-U5HHHRXA.js";
15
15
  import {
16
16
  VERSION
17
- } from "./chunk-5DHIUN73.js";
17
+ } from "./chunk-O4JQY7IF.js";
18
18
 
19
19
  // src/wizard/codex-config.ts
20
20
  import fs from "fs";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  claudeCodeAdapter
3
- } from "./chunk-TCWIXG5C.js";
3
+ } from "./chunk-XYDNRVOU.js";
4
4
  import {
5
5
  GatewayClient,
6
6
  applyStableSessionId
@@ -11,7 +11,7 @@ import {
11
11
  import {
12
12
  createMcpServer,
13
13
  startMcpServer
14
- } from "./chunk-A4IOKD4Z.js";
14
+ } from "./chunk-S35ZIVOL.js";
15
15
  import {
16
16
  findClaudeAncestorPid
17
17
  } from "./chunk-XJEBJIQE.js";
@@ -295,7 +295,7 @@ async function startProxy(config) {
295
295
  }
296
296
  console.error(`[kojee-mcp] Tandem memberships: ${tandemMembershipCount === -1 ? "unknown" : tandemMembershipCount}`);
297
297
  let server;
298
- const { selectDelivery } = await import("./registry-DKWVVXJM.js");
298
+ const { selectDelivery } = await import("./registry-ACVPVDCS.js");
299
299
  const delivery = selectDelivery(adapter.runtime, {
300
300
  supportsChannels: adapter.supportsChannels,
301
301
  // Per-window delivered mirror for the tandem_pending tool (codex only —
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  buildReplyRecipe
3
- } from "./chunk-FJUAMJHU.js";
3
+ } from "./chunk-O4JQY7IF.js";
4
4
 
5
5
  // src/adapters/claude-code.ts
6
6
  function computeSeverity(event) {
package/dist/cli.js CHANGED
@@ -4,8 +4,8 @@ import {
4
4
  } from "./chunk-EIAUW6KO.js";
5
5
  import {
6
6
  startProxy
7
- } from "./chunk-4ATSAH7H.js";
8
- import "./chunk-TCWIXG5C.js";
7
+ } from "./chunk-TUDC4GY5.js";
8
+ import "./chunk-XYDNRVOU.js";
9
9
  import {
10
10
  pairedConfigPath
11
11
  } from "./chunk-5SZHXYPK.js";
@@ -18,11 +18,10 @@ import {
18
18
  deriveKeystorePath
19
19
  } from "./chunk-6G6YYST6.js";
20
20
  import "./chunk-U5HHHRXA.js";
21
- import "./chunk-A4IOKD4Z.js";
21
+ import "./chunk-S35ZIVOL.js";
22
22
  import {
23
23
  VERSION
24
- } from "./chunk-5DHIUN73.js";
25
- import "./chunk-FJUAMJHU.js";
24
+ } from "./chunk-O4JQY7IF.js";
26
25
  import "./chunk-PPTKGWFF.js";
27
26
  import "./chunk-XJEBJIQE.js";
28
27
  import "./chunk-SRLD2UY7.js";
@@ -48,7 +47,7 @@ program.command("pair <code>").description("Pair this machine against Kojee usin
48
47
  program.command("connect <code>").description(
49
48
  "Connect this runtime to Kojee with a per-agent pair code from the dashboard (claude-code | codex | openclaw | hermes). claude-code/codex/openclaw write a per-runtime paired slot (~/.kojee/agents/<runtime>/config.json) and point the runtime launcher at it via --paired-config; hermes writes the global ~/.kojee/config.json (its daemon + `kojee-mcp send` read that). Idempotent."
50
49
  ).requiredOption("--runtime <id>", "Target runtime: claude-code | codex | openclaw | hermes").option("--url <url>", "Broker base URL (default: the canonical staging broker)").action(async (code, opts) => {
51
- const { runConnect } = await import("./connect-handler-NCHC6WPU.js");
50
+ const { runConnect } = await import("./connect-handler-W7EAIU4R.js");
52
51
  const result = await runConnect({
53
52
  code,
54
53
  runtime: opts.runtime,
@@ -63,7 +62,7 @@ program.command("hook").description("Run a kojee MCP hook script (called by Clau
63
62
  "Hook type: stop, user-prompt-submit, codex-stop, or codex-prompt-submit"
64
63
  ).action(async (opts) => {
65
64
  if (opts.type === "stop") {
66
- const { runStopHook } = await import("./stop-hook-4MNOSDCB.js");
65
+ const { runStopHook } = await import("./stop-hook-Y34L3RCR.js");
67
66
  await runStopHook();
68
67
  process.exit(0);
69
68
  } else if (opts.type === "user-prompt-submit") {
@@ -71,11 +70,11 @@ program.command("hook").description("Run a kojee MCP hook script (called by Clau
71
70
  await runUserPromptSubmitHook();
72
71
  process.exit(0);
73
72
  } else if (opts.type === "codex-stop") {
74
- const { runCodexStopHook } = await import("./codex-stop-hook-32W4BIOM.js");
73
+ const { runCodexStopHook } = await import("./codex-stop-hook-M3LEWCNP.js");
75
74
  await runCodexStopHook();
76
75
  process.exit(0);
77
76
  } else if (opts.type === "codex-prompt-submit") {
78
- const { runCodexPromptSubmitHook } = await import("./codex-prompt-submit-hook-J5PZEJSK.js");
77
+ const { runCodexPromptSubmitHook } = await import("./codex-prompt-submit-hook-ACDZSHHC.js");
79
78
  await runCodexPromptSubmitHook();
80
79
  process.exit(0);
81
80
  } else {
@@ -114,17 +113,20 @@ program.command("send <tandem_id>").description(
114
113
  process.stdout.write(JSON.stringify(envelope) + "\n");
115
114
  process.exit(exitCode);
116
115
  });
117
- program.command("tail <path>").description("Stream a file's contents and follow appends (portable replacement for `tail -F`)").action(async (filePath) => {
118
- const { runTail } = await import("./tail-stream-G4WGTXDS.js");
116
+ program.command("tail <path>").description("Stream a file's contents and follow appends (portable replacement for `tail -F`)").option(
117
+ "--wake-only",
118
+ "Suppress routine heartbeat warn/recover telemetry; surface only a sustained stream outage"
119
+ ).action(async (filePath, opts) => {
120
+ const { runTail } = await import("./tail-stream-HG4BKJOG.js");
119
121
  try {
120
- await runTail(filePath);
122
+ await runTail(filePath, { wakeOnly: opts.wakeOnly === true });
121
123
  } catch (err) {
122
124
  console.error("[kojee-mcp tail] Error:", err.message);
123
125
  process.exit(1);
124
126
  }
125
127
  });
126
128
  program.command("doctor").description("Diagnose the kojee wake path (proxy, hook-server, SSE stream, event log, Monitor) and print the exact wake recipe").action(async () => {
127
- const { runDoctor } = await import("./doctor-RKLXZR2B.js");
129
+ const { runDoctor } = await import("./doctor-O7MLJEMO.js");
128
130
  const code = await runDoctor();
129
131
  process.exit(code);
130
132
  });
@@ -143,7 +145,7 @@ function addInstallOptions(cmd, runtimeHelp) {
143
145
  function makeInstallAction(verb) {
144
146
  return async (opts) => {
145
147
  const interactive = process.stdin.isTTY === true && opts.runtime === void 0;
146
- const { runSetup, resolvePairCode } = await import("./setup-handler-DA4465VH.js");
148
+ const { runSetup, resolvePairCode } = await import("./setup-handler-6T7Q6DYQ.js");
147
149
  const pairCode = resolvePairCode(opts);
148
150
  const result = await runSetup({
149
151
  verb,
@@ -6,7 +6,7 @@ import {
6
6
  } from "./chunk-IZN7IZPW.js";
7
7
  import {
8
8
  CODEX_WAKE_BELL
9
- } from "./chunk-FJUAMJHU.js";
9
+ } from "./chunk-O4JQY7IF.js";
10
10
 
11
11
  // src/hooks/codex-prompt-submit-hook.ts
12
12
  function buildCodexPromptSubmitOutput() {
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-IZN7IZPW.js";
9
9
  import {
10
10
  CODEX_WAKE_BELL
11
- } from "./chunk-FJUAMJHU.js";
11
+ } from "./chunk-O4JQY7IF.js";
12
12
 
13
13
  // src/hooks/codex-stop-hook.ts
14
14
  import fs from "fs";
@@ -2,8 +2,8 @@ import {
2
2
  DEFAULT_BROKER_URL,
3
3
  reconcileConnectPairSlot,
4
4
  runWizard
5
- } from "./chunk-CPOK642I.js";
6
- import "./chunk-6XWTUDWW.js";
5
+ } from "./chunk-RTYRJAJO.js";
6
+ import "./chunk-T6QANUS2.js";
7
7
  import "./chunk-E6WMFMM2.js";
8
8
  import "./chunk-GEGUWQYT.js";
9
9
  import "./chunk-77HWBSRH.js";
@@ -30,8 +30,7 @@ import {
30
30
  deriveKeystorePath
31
31
  } from "./chunk-6G6YYST6.js";
32
32
  import "./chunk-U5HHHRXA.js";
33
- import "./chunk-5DHIUN73.js";
34
- import "./chunk-FJUAMJHU.js";
33
+ import "./chunk-O4JQY7IF.js";
35
34
 
36
35
  // src/wizard/connect-handler.ts
37
36
  import os from "os";
@@ -18,7 +18,7 @@ import "./chunk-U5HHHRXA.js";
18
18
  import {
19
19
  buildMonitorSpawn,
20
20
  buildReplyRecipe
21
- } from "./chunk-FJUAMJHU.js";
21
+ } from "./chunk-O4JQY7IF.js";
22
22
  import {
23
23
  deriveDiscoveryKey,
24
24
  findClaudeAncestorPid
@@ -354,7 +354,7 @@ function formatDoctorReport(report) {
354
354
  async function runDoctor() {
355
355
  const { readRecordedRuntime } = await import("./runtime-record-OXRLTOLC.js");
356
356
  if (readRecordedRuntime() === "codex") {
357
- const { collectCodexDoctorReport, formatCodexDoctorReport } = await import("./doctor-codex-PJFWIABF.js");
357
+ const { collectCodexDoctorReport, formatCodexDoctorReport } = await import("./doctor-codex-D4BOWIAA.js");
358
358
  const report2 = collectCodexDoctorReport();
359
359
  console.error(formatCodexDoctorReport(report2));
360
360
  return report2.verdict === "broken" ? 1 : 0;
@@ -2,7 +2,7 @@ import {
2
2
  defaultCodexConfigPath,
3
3
  defaultCodexHooksPath,
4
4
  isPlaceholderWebhookUrl
5
- } from "./chunk-6XWTUDWW.js";
5
+ } from "./chunk-T6QANUS2.js";
6
6
  import "./chunk-TMCNB4JH.js";
7
7
  import "./chunk-D6JKFJ6A.js";
8
8
  import {
@@ -16,11 +16,9 @@ import {
16
16
  } from "./chunk-V5VZPYMZ.js";
17
17
  import "./chunk-U5HHHRXA.js";
18
18
  import {
19
+ CODEX_LISTEN_CAP_MS,
19
20
  VERSION
20
- } from "./chunk-5DHIUN73.js";
21
- import {
22
- CODEX_LISTEN_CAP_MS
23
- } from "./chunk-FJUAMJHU.js";
21
+ } from "./chunk-O4JQY7IF.js";
24
22
 
25
23
  // src/doctor-codex.ts
26
24
  import fs from "fs";
package/dist/index.js CHANGED
@@ -1,17 +1,16 @@
1
1
  import {
2
2
  listTandemIds,
3
3
  startProxy
4
- } from "./chunk-4ATSAH7H.js";
5
- import "./chunk-TCWIXG5C.js";
4
+ } from "./chunk-TUDC4GY5.js";
5
+ import "./chunk-XYDNRVOU.js";
6
6
  import "./chunk-TBVJOXIR.js";
7
7
  import "./chunk-Z5LPNJQ6.js";
8
8
  import "./chunk-I67C2HYA.js";
9
9
  import "./chunk-MIEI4PLB.js";
10
10
  import "./chunk-6G6YYST6.js";
11
11
  import "./chunk-U5HHHRXA.js";
12
- import "./chunk-A4IOKD4Z.js";
13
- import "./chunk-5DHIUN73.js";
14
- import "./chunk-FJUAMJHU.js";
12
+ import "./chunk-S35ZIVOL.js";
13
+ import "./chunk-O4JQY7IF.js";
15
14
  import "./chunk-PPTKGWFF.js";
16
15
  import "./chunk-XJEBJIQE.js";
17
16
  import "./chunk-SRLD2UY7.js";
@@ -13,12 +13,11 @@ import {
13
13
  } from "./chunk-IZN7IZPW.js";
14
14
  import {
15
15
  claudeCodeAdapter
16
- } from "./chunk-TCWIXG5C.js";
17
- import "./chunk-A4IOKD4Z.js";
16
+ } from "./chunk-XYDNRVOU.js";
17
+ import "./chunk-S35ZIVOL.js";
18
18
  import {
19
19
  VERSION
20
- } from "./chunk-5DHIUN73.js";
21
- import "./chunk-FJUAMJHU.js";
20
+ } from "./chunk-O4JQY7IF.js";
22
21
  import "./chunk-PPTKGWFF.js";
23
22
 
24
23
  // src/delivery/lib/fanout.ts
@@ -127,7 +126,7 @@ function createClaudeCodeDelivery() {
127
126
  const { resolveWebhookConfig } = await import("./webhook-config-O4WMQ532.js");
128
127
  const { createWebhookSink } = await import("./webhook-sink-N6AUTFL3.js");
129
128
  const { startEventStream } = await import("./event-stream-ATKYXDBV.js");
130
- const { createMcpServer } = await import("./server-DU3LFS32.js");
129
+ const { createMcpServer } = await import("./server-RK4UK6SP.js");
131
130
  const { deriveDiscoveryKey } = await import("./ancestry-A2F5KQ6A.js");
132
131
  const { resolveSharedSessionId } = await import("./cc-session-id-NNCZCHZZ.js");
133
132
  sweepStaleDiscovery();
@@ -324,7 +323,7 @@ function createWebhookDelivery(name, pendingLedger) {
324
323
  const { createWebhookSink } = await import("./webhook-sink-N6AUTFL3.js");
325
324
  const { resubscribeMemberships } = await import("./resubscribe-G5OGDZJD.js");
326
325
  const { startEventStream } = await import("./event-stream-ATKYXDBV.js");
327
- const { createMcpServer } = await import("./server-DU3LFS32.js");
326
+ const { createMcpServer } = await import("./server-RK4UK6SP.js");
328
327
  sweepStaleEventLogs();
329
328
  eventLog = startEventLog({
330
329
  key: ctx.instanceKey,
@@ -518,7 +517,7 @@ function createOpenclawDelivery(deps = {}) {
518
517
  const { startEventLog, sweepStaleEventLogs } = await import("./event-log-2NBJEIEP.js");
519
518
  const { resubscribeMemberships } = await import("./resubscribe-G5OGDZJD.js");
520
519
  const { startEventStream } = await import("./event-stream-ATKYXDBV.js");
521
- const { createMcpServer } = await import("./server-DU3LFS32.js");
520
+ const { createMcpServer } = await import("./server-RK4UK6SP.js");
522
521
  sweepStaleEventLogs();
523
522
  eventLog = startEventLog({
524
523
  key: ctx.instanceKey,
@@ -5,9 +5,8 @@ import {
5
5
  executeToolCall,
6
6
  extractDrainCursor,
7
7
  startMcpServer
8
- } from "./chunk-A4IOKD4Z.js";
9
- import "./chunk-5DHIUN73.js";
10
- import "./chunk-FJUAMJHU.js";
8
+ } from "./chunk-S35ZIVOL.js";
9
+ import "./chunk-O4JQY7IF.js";
11
10
  import "./chunk-PPTKGWFF.js";
12
11
  export {
13
12
  buildChannelInstructions,
@@ -3,8 +3,8 @@ import {
3
3
  pairSlotFor,
4
4
  reconcileConnectPairSlot,
5
5
  runWizard
6
- } from "./chunk-CPOK642I.js";
7
- import "./chunk-6XWTUDWW.js";
6
+ } from "./chunk-RTYRJAJO.js";
7
+ import "./chunk-T6QANUS2.js";
8
8
  import "./chunk-E6WMFMM2.js";
9
9
  import "./chunk-GEGUWQYT.js";
10
10
  import {
@@ -26,8 +26,7 @@ import "./chunk-I67C2HYA.js";
26
26
  import "./chunk-MIEI4PLB.js";
27
27
  import "./chunk-6G6YYST6.js";
28
28
  import "./chunk-U5HHHRXA.js";
29
- import "./chunk-5DHIUN73.js";
30
- import "./chunk-FJUAMJHU.js";
29
+ import "./chunk-O4JQY7IF.js";
31
30
 
32
31
  // src/wizard/setup-handler.ts
33
32
  var SETUP_SUPPORTED_RUNTIMES = ["claude-code", "codex"];
@@ -19,7 +19,7 @@ import "./chunk-67F67AQ6.js";
19
19
  import "./chunk-U5HHHRXA.js";
20
20
  import {
21
21
  buildMonitorNudge
22
- } from "./chunk-FJUAMJHU.js";
22
+ } from "./chunk-O4JQY7IF.js";
23
23
  import "./chunk-XJEBJIQE.js";
24
24
  import "./chunk-SRLD2UY7.js";
25
25
 
@@ -16,6 +16,7 @@ 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,13 @@ 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;
103
106
  const statusPath = statusLogPath(messagesPath);
104
- const detector = createStallDetector(Date.now(), { floorMs: TAIL_STALE_FLOOR_MS });
107
+ const detector = createStallDetector(Date.now(), {
108
+ floorMs: TAIL_STALE_FLOOR_MS,
109
+ rewarnAfterMs: SUSTAINED_STALE_MS
110
+ });
105
111
  const heartbeatPath = monitorHeartbeatPath(messagesPath);
106
112
  const touchHeartbeat = () => {
107
113
  const now = /* @__PURE__ */ new Date();
@@ -116,7 +122,7 @@ async function runTail(messagesPath) {
116
122
  };
117
123
  let lastCursor = null;
118
124
  function onMessageLine(line) {
119
- if (detector.onLife(Date.now())?.kind === "recovered") {
125
+ if (detector.onLife(Date.now())?.kind === "recovered" && !wakeOnly) {
120
126
  process.stdout.write(
121
127
  "[kojee] stream recovered \u2014 events flowing again (recovery is automatic; no action needed).\n"
122
128
  );
@@ -133,7 +139,7 @@ async function runTail(messagesPath) {
133
139
  if (HEARTBEAT_FIELDS_RE.test(fields)) {
134
140
  detector.onHeartbeat(now);
135
141
  }
136
- if (detector.onLife(now)?.kind === "recovered") {
142
+ if (detector.onLife(now)?.kind === "recovered" && !wakeOnly) {
137
143
  process.stdout.write(
138
144
  "[kojee] stream recovered \u2014 heartbeats resumed (the stall was transient, likely idle-period timing or brief host load; no action needed).\n"
139
145
  );
@@ -149,7 +155,12 @@ async function runTail(messagesPath) {
149
155
  }
150
156
  }
151
157
  const followers = [
152
- makeFollower(messagesPath, onMessageLine, touchHeartbeat),
158
+ // MESSAGES (wake-critical) — prefer the OS `tail -F` follower where the
159
+ // platform has one; it delegates file-following to the battle-tested system
160
+ // binary instead of the Node fs.watch/poll tailer. STATUS (telemetry) stays
161
+ // on the Node follower: its startup-backlog seeding boundary (statusSeeded)
162
+ // is clean to detect only when we control the drain. See makeMessagesFollower.
163
+ makeMessagesFollower(messagesPath, onMessageLine, touchHeartbeat),
153
164
  makeFollower(statusPath, onStatusLine, touchHeartbeat)
154
165
  ];
155
166
  void Promise.all([
@@ -171,6 +182,7 @@ async function runTail(messagesPath) {
171
182
  );
172
183
  return;
173
184
  }
185
+ if (wakeOnly) return;
174
186
  const thresholdS = Math.round((signal.thresholdMs ?? 0) / 1e3);
175
187
  process.stdout.write(
176
188
  `[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\`.
@@ -273,11 +285,99 @@ function makeFollower(filePath, onLine, onActivity) {
273
285
  }
274
286
  };
275
287
  }
288
+ function osTailAvailable() {
289
+ const override = (process.env.KOJEE_TAIL_IMPL ?? "").trim().toLowerCase();
290
+ if (override === "os") return true;
291
+ if (override === "node") return false;
292
+ return process.platform !== "win32";
293
+ }
294
+ function makeMessagesFollower(filePath, onLine, onActivity) {
295
+ if (!osTailAvailable()) return makeFollower(filePath, onLine, onActivity);
296
+ return makeTailFollower(
297
+ filePath,
298
+ onLine,
299
+ onActivity,
300
+ () => makeFollower(filePath, onLine, onActivity)
301
+ );
302
+ }
303
+ function makeTailFollower(filePath, onLine, onActivity, fallback) {
304
+ let child = null;
305
+ let heir = null;
306
+ let hbTimer = null;
307
+ let buffer = "";
308
+ let stopped = false;
309
+ let handedOff = false;
310
+ function emit(chunk) {
311
+ onActivity();
312
+ buffer += chunk;
313
+ let nl;
314
+ while ((nl = buffer.indexOf("\n")) !== -1) {
315
+ onLine(buffer.slice(0, nl));
316
+ buffer = buffer.slice(nl + 1);
317
+ }
318
+ }
319
+ function handOff() {
320
+ if (stopped || handedOff) return;
321
+ handedOff = true;
322
+ if (hbTimer) {
323
+ clearInterval(hbTimer);
324
+ hbTimer = null;
325
+ }
326
+ if (child) {
327
+ try {
328
+ child.kill("SIGTERM");
329
+ } catch {
330
+ }
331
+ child = null;
332
+ }
333
+ heir = fallback();
334
+ void heir.start().catch(() => {
335
+ });
336
+ }
337
+ return {
338
+ async start() {
339
+ try {
340
+ child = spawn("tail", ["-n", "+1", "-F", filePath], {
341
+ stdio: ["ignore", "pipe", "ignore"]
342
+ });
343
+ } catch {
344
+ handOff();
345
+ return;
346
+ }
347
+ child.on("error", () => handOff());
348
+ child.on("exit", () => {
349
+ if (!stopped) handOff();
350
+ });
351
+ child.stdout?.setEncoding("utf8");
352
+ child.stdout?.on("data", (d) => emit(d));
353
+ onActivity();
354
+ hbTimer = setInterval(onActivity, 1e3);
355
+ },
356
+ stop() {
357
+ stopped = true;
358
+ if (hbTimer) {
359
+ clearInterval(hbTimer);
360
+ hbTimer = null;
361
+ }
362
+ if (child) {
363
+ try {
364
+ child.kill("SIGTERM");
365
+ } catch {
366
+ }
367
+ child = null;
368
+ }
369
+ if (heir) heir.stop();
370
+ }
371
+ };
372
+ }
276
373
  function sleep(ms) {
277
374
  return new Promise((r) => setTimeout(r, ms));
278
375
  }
279
376
  export {
280
377
  createStallDetector,
281
378
  makeFollower,
379
+ makeMessagesFollower,
380
+ makeTailFollower,
381
+ osTailAvailable,
282
382
  runTail
283
383
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kojee-mcp",
3
- "version": "0.7.5-staging.6",
3
+ "version": "0.7.5-staging.7",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "exports": {
@@ -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
- };