kojee-mcp 0.6.0 → 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 (67) 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-BYV7CWNY.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-XN3IC4B5.js → chunk-FSKGQ6GT.js} +30 -5
  14. package/dist/{chunk-GI2CKKBL.js → chunk-GKXHKR3B.js} +1 -1
  15. package/dist/{setup-handler-7HOFAD7C.js → chunk-GVWYW7MY.js} +247 -246
  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-N35X22G7.js → chunk-OB5T6P24.js} +1 -1
  21. package/dist/{chunk-65KRRDHP.js → chunk-OBIJ6WQP.js} +82 -27
  22. package/dist/{chunk-Q7T3WAST.js → chunk-QEJUNP3X.js} +2 -1
  23. package/dist/chunk-QJFMU4QC.js +33 -0
  24. package/dist/{chunk-EW72ZNQL.js → chunk-RDLF4NQC.js} +1 -1
  25. package/dist/{chunk-ALZX3SGI.js → chunk-SGRVG4HW.js} +8 -3
  26. package/dist/{chunk-DURRQDYI.js → chunk-TNZITJAB.js} +45 -15
  27. package/dist/chunk-U5HHHRXA.js +103 -0
  28. package/dist/chunk-WBXU27BF.js +35 -0
  29. package/dist/chunk-WIU5WGDF.js +10 -0
  30. package/dist/chunk-XJEBJIQE.js +52 -0
  31. package/dist/chunk-Z5LPNJQ6.js +20 -0
  32. package/dist/cli.js +62 -25
  33. package/dist/{chunk-KFDZWNQO.js → codex-stop-hook-EOMQD3J4.js} +11 -15
  34. package/dist/connect-handler-HIRM624N.js +137 -0
  35. package/dist/{control-token-4BUCTYQB.js → control-token-KXSZ3GBY.js} +2 -2
  36. package/dist/{doctor-WVX3WCYX.js → doctor-PLKLHTJM.js} +48 -22
  37. package/dist/{doctor-codex-Z5M4SFBG.js → doctor-codex-HARAAH4Y.js} +23 -6
  38. package/dist/doctor-openclaw-LL6NSPLC.js +86 -0
  39. package/dist/{event-log-HOBO3ECB.js → event-log-2NBJEIEP.js} +5 -3
  40. package/dist/{event-stream-SYBUJ5EH.js → event-stream-KRYWEYWO.js} +7 -4
  41. package/dist/index.js +12 -10
  42. package/dist/{install-LJY2CHKG.js → install-V7LSQCYZ.js} +37 -22
  43. package/dist/{keystore-XLEV3FL5.js → keystore-LQNFDHGO.js} +2 -2
  44. package/dist/lib.d.ts +4 -1
  45. package/dist/lib.js +11 -8
  46. package/dist/pair-HTCVSMR6.js +11 -0
  47. package/dist/{paired-config-JTFLHMZ2.js → paired-config-GUDDO2CH.js} +4 -2
  48. package/dist/{parent-watchdog-TLU355FB.js → parent-watchdog-LTUNF7PD.js} +24 -5
  49. package/dist/{registry-YLOFZDI2.js → registry-VRFHKOPP.js} +193 -24
  50. package/dist/resolve-slot-BFIB46Y5.js +13 -0
  51. package/dist/{runtime-record-WO4IECM6.js → runtime-record-OXRLTOLC.js} +2 -2
  52. package/dist/{send-cli-IYJF32PE.js → send-cli-45RLGYIC.js} +22 -10
  53. package/dist/{server-R24AVNTI.js → server-YTHOMA4H.js} +4 -2
  54. package/dist/{session-discovery-FNMJGFPM.js → session-discovery-NHCZ2XWA.js} +2 -2
  55. package/dist/setup-handler-UHVKSX7E.js +159 -0
  56. package/dist/{stop-hook-TCPJFGFF.js → stop-hook-YI4KRKF2.js} +17 -20
  57. package/dist/{tail-stream-4IMXI44S.js → tail-stream-NBGHHBS4.js} +40 -22
  58. package/dist/{user-prompt-submit-hook-FQ43NIHC.js → user-prompt-submit-hook-DTXXFDSD.js} +11 -14
  59. package/package.json +1 -1
  60. package/dist/ancestry-ONFBQEP5.js +0 -8
  61. package/dist/chunk-BLEGIR35.js +0 -43
  62. package/dist/chunk-CLKCNV2A.js +0 -100
  63. package/dist/chunk-OGHDTFAX.js +0 -50
  64. package/dist/chunk-VHKPWUX7.js +0 -41
  65. package/dist/codex-stop-hook-RWQSZTST.js +0 -16
  66. package/dist/doctor-openclaw-SS2TMQOX.js +0 -95
  67. package/dist/pair-P4ILCMT7.js +0 -10
@@ -1,28 +1,31 @@
1
1
  import "./chunk-XLKGPGZT.js";
2
+ import {
3
+ loadControlToken
4
+ } from "./chunk-GKXHKR3B.js";
2
5
  import {
3
6
  monitorHeartbeatPath,
4
7
  statusLogPath
5
- } from "./chunk-DURRQDYI.js";
8
+ } from "./chunk-TNZITJAB.js";
6
9
  import {
7
10
  discoveryPathForKey,
8
11
  readSessionDiscoveryByKey,
9
12
  sessionDiscoveryDir
10
- } from "./chunk-DO42NPNR.js";
11
- import {
12
- loadControlToken
13
- } from "./chunk-GI2CKKBL.js";
13
+ } from "./chunk-67F67AQ6.js";
14
14
  import {
15
15
  loadPairedConfig
16
- } from "./chunk-YH27B6SW.js";
17
- import "./chunk-BLEGIR35.js";
16
+ } from "./chunk-5SZHXYPK.js";
17
+ import "./chunk-U5HHHRXA.js";
18
18
  import {
19
19
  buildMonitorSpawn,
20
20
  buildReplyRecipe
21
- } from "./chunk-Q7T3WAST.js";
21
+ } from "./chunk-QEJUNP3X.js";
22
22
  import {
23
23
  deriveDiscoveryKey,
24
24
  findClaudeAncestorPid
25
- } from "./chunk-VHKPWUX7.js";
25
+ } from "./chunk-XJEBJIQE.js";
26
+ import {
27
+ resolveSharedSessionId
28
+ } from "./chunk-KNEJTD6G.js";
26
29
 
27
30
  // src/doctor.ts
28
31
  import fs from "fs";
@@ -95,7 +98,8 @@ function defaultIsPidAlive(pid) {
95
98
  process.kill(pid, 0);
96
99
  return true;
97
100
  } catch (err) {
98
- if (err.code === "EPERM") return true;
101
+ const code = err.code;
102
+ if (code === "EPERM" || code === "EACCES") return true;
99
103
  return false;
100
104
  }
101
105
  }
@@ -132,6 +136,19 @@ function defaultReadLastStatusLine(path2) {
132
136
  }
133
137
  }
134
138
  }
139
+ async function resolveDefaultPairedScope() {
140
+ const { resolvePairedSlot } = await import("./resolve-slot-BFIB46Y5.js");
141
+ const { readRecordedRuntime } = await import("./runtime-record-OXRLTOLC.js");
142
+ const { deriveKeystorePath } = await import("./keystore-LQNFDHGO.js");
143
+ const runtime = readRecordedRuntime() ?? process.env["KOJEE_RUNTIME"];
144
+ const resolution = resolvePairedSlot({ ...runtime ? { runtime } : {} });
145
+ const cfg = loadPairedConfig(resolution.configPath);
146
+ let present = cfg !== null && typeof cfg.token === "string" && cfg.token !== "";
147
+ if (present && resolution.scope === "paired" && cfg) {
148
+ present = fs.existsSync(deriveKeystorePath(cfg.token));
149
+ }
150
+ return { scope: resolution.scope, present, ...runtime ? { runtime } : {} };
151
+ }
135
152
  async function collectDoctorReport(deps = {}) {
136
153
  const fetchFn = deps.fetchFn ?? fetch;
137
154
  const isPidAlive = deps.isPidAlive ?? defaultIsPidAlive;
@@ -140,23 +157,32 @@ async function collectDoctorReport(deps = {}) {
140
157
  const readDiscovery = deps.readDiscovery ?? readSessionDiscoveryByKey;
141
158
  const projectDir = deps.projectDir ?? process.env["CLAUDE_PROJECT_DIR"];
142
159
  const ccPid = deps.ccPid !== void 0 ? deps.ccPid : await findClaudeAncestorPid();
143
- const discoveryKey = deriveDiscoveryKey(projectDir, ccPid);
160
+ const sessionId = deps.sessionId !== void 0 ? deps.sessionId : resolveSharedSessionId();
161
+ const discoveryKey = deriveDiscoveryKey(projectDir, ccPid, sessionId);
144
162
  const discoveryPath = discoveryPathForKey(discoveryKey);
145
163
  const checks = [];
146
164
  const discovery = readDiscovery(discoveryKey);
147
165
  const tokenMode = discovery?.authMode === "token";
148
- const paired = deps.pairedConfigPresent !== void 0 ? deps.pairedConfigPresent : loadPairedConfig() !== null;
149
- checks.push(
150
- tokenMode ? {
166
+ const pairedScope = deps.pairedScope ?? (deps.pairedConfigPresent !== void 0 ? { scope: "legacy", present: deps.pairedConfigPresent } : await resolveDefaultPairedScope());
167
+ if (tokenMode) {
168
+ checks.push({
151
169
  name: "paired config",
152
170
  ok: true,
153
171
  detail: "n/a (token mode) \u2014 proxy launched with --token; no ~/.kojee/config.json by design"
154
- } : {
172
+ });
173
+ } else if (pairedScope.scope === "paired") {
174
+ checks.push({
155
175
  name: "paired config",
156
- ok: paired,
157
- detail: paired ? "present" : "MISSING \u2014 run `kojee-mcp pair <code> --url <broker>`"
158
- }
159
- );
176
+ ok: pairedScope.present,
177
+ detail: pairedScope.present ? `present (per-runtime: ${pairedScope.runtime ?? "?"}) + token-derived keystore` : `MISSING per-runtime slot for ${pairedScope.runtime ?? "?"} \u2014 run \`kojee-mcp connect <code> --runtime ${pairedScope.runtime ?? "<id>"}\``
178
+ });
179
+ } else {
180
+ checks.push({
181
+ name: "paired config",
182
+ ok: pairedScope.present,
183
+ detail: pairedScope.present ? "present (legacy global slot)" : "MISSING \u2014 run `kojee-mcp connect <code> --runtime <id>` (or `kojee-mcp pair`)"
184
+ });
185
+ }
160
186
  let logPath = null;
161
187
  if (!discovery) {
162
188
  checks.push({
@@ -326,15 +352,15 @@ function formatDoctorReport(report) {
326
352
  return lines.join("\n");
327
353
  }
328
354
  async function runDoctor() {
329
- const { readRecordedRuntime } = await import("./runtime-record-WO4IECM6.js");
355
+ const { readRecordedRuntime } = await import("./runtime-record-OXRLTOLC.js");
330
356
  if (readRecordedRuntime() === "codex") {
331
- const { collectCodexDoctorReport, formatCodexDoctorReport } = await import("./doctor-codex-Z5M4SFBG.js");
357
+ const { collectCodexDoctorReport, formatCodexDoctorReport } = await import("./doctor-codex-HARAAH4Y.js");
332
358
  const report2 = collectCodexDoctorReport();
333
359
  console.error(formatCodexDoctorReport(report2));
334
360
  return report2.verdict === "broken" ? 1 : 0;
335
361
  }
336
362
  if (readRecordedRuntime() === "openclaw") {
337
- const { collectOpenclawDoctorReport, formatOpenclawDoctorReport } = await import("./doctor-openclaw-SS2TMQOX.js");
363
+ const { collectOpenclawDoctorReport, formatOpenclawDoctorReport } = await import("./doctor-openclaw-LL6NSPLC.js");
338
364
  const report2 = collectOpenclawDoctorReport();
339
365
  console.error(formatOpenclawDoctorReport(report2));
340
366
  return report2.verdict === "broken" ? 1 : 0;
@@ -1,15 +1,17 @@
1
1
  import {
2
2
  defaultCodexConfigPath,
3
3
  defaultCodexHooksPath
4
- } from "./chunk-65KRRDHP.js";
4
+ } from "./chunk-OBIJ6WQP.js";
5
+ import "./chunk-QJFMU4QC.js";
6
+ import "./chunk-D6JKFJ6A.js";
5
7
  import "./chunk-SQL56SEB.js";
6
8
  import {
7
9
  resolveWebhookConfig
8
10
  } from "./chunk-V5VZPYMZ.js";
9
- import "./chunk-BLEGIR35.js";
11
+ import "./chunk-U5HHHRXA.js";
10
12
  import {
11
13
  CODEX_LISTEN_CAP_MS
12
- } from "./chunk-Q7T3WAST.js";
14
+ } from "./chunk-QEJUNP3X.js";
13
15
 
14
16
  // src/doctor-codex.ts
15
17
  import fs from "fs";
@@ -39,6 +41,10 @@ function parseCodexEnvFromToml(toml) {
39
41
  return env;
40
42
  }
41
43
  var WIZARD_RERUN = "re-run `kojee-mcp init --runtime codex`";
44
+ function extractPairedConfigPath(toml) {
45
+ const m = toml.match(/args\s*=\s*\[[^\]]*"--paired-config"\s*,\s*"([^"]+)"/);
46
+ return m ? m[1].replace(/\\\\/g, "\\") : null;
47
+ }
42
48
  function defaultReadFile(path) {
43
49
  return () => {
44
50
  try {
@@ -100,8 +106,17 @@ function collectCodexDoctorReport(deps = {}) {
100
106
  } else {
101
107
  checks.push({
102
108
  name: "webhook sink",
103
- ok: false,
104
- detail: `not configured (no KOJEE_WEBHOOK_URL) \u2014 ${WIZARD_RERUN}`
109
+ ok: true,
110
+ detail: "optional \u2014 OFF (no KOJEE_WEBHOOK_URL). Codex wake is self-contained: the proxy refreshes the stop-hook pending marker on every event. Configure a receiver only for an extra low-latency push path."
111
+ });
112
+ }
113
+ const pairedPath = extractPairedConfigPath(toml);
114
+ if (pairedPath) {
115
+ const present = fs.existsSync(pairedPath);
116
+ checks.push({
117
+ name: "paired-config slot",
118
+ ok: present,
119
+ detail: present ? `present \u2014 proxy launches with --paired-config ${pairedPath}` : `MISSING referenced config ${pairedPath} \u2014 re-run \`kojee-mcp connect <code> --runtime codex\``
105
120
  });
106
121
  }
107
122
  if (deps.pingReceiver) {
@@ -120,7 +135,9 @@ function formatCodexDoctorReport(report) {
120
135
  const lines = [];
121
136
  lines.push(`kojee-mcp doctor (codex) \u2014 verdict: ${report.verdict.toUpperCase()}`);
122
137
  lines.push("");
123
- lines.push(" Wake mode: webhook-sink + stop-hook peek (Codex has no channel injection).");
138
+ lines.push(
139
+ " Wake mode: self-contained (proxy-written pending marker) + stop-hook peek (Codex has no channel injection). Webhook OPTIONAL, never required."
140
+ );
124
141
  lines.push(` Bounded-listen cap: ${CODEX_LISTEN_CAP_MS}ms (model picks listen vs drain vs ignore).`);
125
142
  lines.push("");
126
143
  for (const c of report.checks) {
@@ -0,0 +1,86 @@
1
+ import {
2
+ MCP_SERVER_NAME,
3
+ defaultOpenclawConfigPath
4
+ } from "./chunk-E6WMFMM2.js";
5
+ import "./chunk-D6JKFJ6A.js";
6
+ import {
7
+ resolveOpenclawWakeTarget
8
+ } from "./chunk-NE2F5CKS.js";
9
+ import "./chunk-SQL56SEB.js";
10
+ import {
11
+ loadPairedConfig,
12
+ pairedConfigPath,
13
+ perRuntimeConfigPath
14
+ } from "./chunk-5SZHXYPK.js";
15
+ import "./chunk-U5HHHRXA.js";
16
+
17
+ // src/doctor-openclaw.ts
18
+ import fs from "fs";
19
+ var WIZARD_RERUN = "re-run `kojee-mcp connect <code> --runtime openclaw`";
20
+ function readOpenclawConfig() {
21
+ try {
22
+ const parsed = JSON.parse(fs.readFileSync(defaultOpenclawConfigPath(), "utf8"));
23
+ return parsed && typeof parsed === "object" ? parsed : {};
24
+ } catch {
25
+ return {};
26
+ }
27
+ }
28
+ function loadOpenclawPaired() {
29
+ const perRuntime = loadPairedConfig(perRuntimeConfigPath("openclaw"));
30
+ if (perRuntime?.token) return { config: perRuntime, source: "per-runtime" };
31
+ const global = loadPairedConfig(pairedConfigPath());
32
+ if (global?.token) return { config: global, source: "global" };
33
+ return null;
34
+ }
35
+ function collectOpenclawDoctorReport(deps = {}) {
36
+ const readConfig = deps.readConfig ?? readOpenclawConfig;
37
+ const resolveWake = deps.resolveWake ?? (() => resolveOpenclawWakeTarget());
38
+ const loadPaired = deps.loadPaired ?? loadOpenclawPaired;
39
+ const checks = [];
40
+ const cfg = readConfig();
41
+ const mcp = cfg.mcp && typeof cfg.mcp === "object" ? cfg.mcp : {};
42
+ const servers = mcp.servers && typeof mcp.servers === "object" ? mcp.servers : {};
43
+ const server = servers[MCP_SERVER_NAME] && typeof servers[MCP_SERVER_NAME] === "object" ? servers[MCP_SERVER_NAME] : null;
44
+ const args = server && Array.isArray(server.args) ? server.args : [];
45
+ const pairedConfigThreaded = args.includes("--paired-config");
46
+ checks.push({
47
+ name: `~/.openclaw/openclaw.json mcp.servers.${MCP_SERVER_NAME}`,
48
+ ok: server !== null,
49
+ detail: server ? pairedConfigThreaded ? "present \u2014 OpenClaw spawns kojee-mcp with --paired-config (per-runtime slot)" : "present (WARN: no --paired-config in args \u2014 the proxy will use the global slot)" : `MISSING mcp.servers.${MCP_SERVER_NAME} block \u2014 ${WIZARD_RERUN}`
50
+ });
51
+ const wake = resolveWake();
52
+ checks.push({
53
+ name: "hooks wake receiver",
54
+ ok: wake.ok,
55
+ detail: wake.ok ? `mounted \u2014 /wake target: ${wake.target.url} (Bearer hooks.token; token value never printed)` : `${wake.reason} \u2014 ${WIZARD_RERUN}`
56
+ });
57
+ const paired = loadPaired();
58
+ checks.push({
59
+ name: "gateway credential",
60
+ ok: paired !== null,
61
+ detail: paired ? `resolves \u2014 source: ${paired.source} paired slot (token value never printed)` : `NONE resolves (no ~/.kojee/agents/openclaw/config.json or ~/.kojee/config.json token) \u2014 ${WIZARD_RERUN}`
62
+ });
63
+ const verdict = checks.some((c) => c.ok === false) ? "broken" : checks.some((c) => c.ok === "warn") ? "degraded" : "healthy";
64
+ return { checks, verdict };
65
+ }
66
+ function formatOpenclawDoctorReport(report) {
67
+ const mark = (ok) => ok === true ? "\u2713" : ok === "warn" ? "\u26A0" : ok === "unknown" ? "?" : "\u2717";
68
+ const lines = [];
69
+ lines.push(`kojee-mcp doctor (openclaw) \u2014 verdict: ${report.verdict.toUpperCase()}`);
70
+ lines.push("");
71
+ lines.push(" Wake mode: OpenClaw MCP server + /hooks/wake injector.");
72
+ lines.push(" OpenClaw spawns kojee-mcp (mcp.servers.kojee); wakes arrive via POST <gateway>/hooks/wake.");
73
+ lines.push("");
74
+ for (const c of report.checks) {
75
+ lines.push(` ${mark(c.ok)} ${c.name}: ${c.detail}`);
76
+ }
77
+ lines.push("");
78
+ lines.push(
79
+ "NOTE: live verification (gateway running, proxy spawned) is an owner step \u2014 start the OpenClaw gateway and send a Tandem message."
80
+ );
81
+ return lines.join("\n");
82
+ }
83
+ export {
84
+ collectOpenclawDoctorReport,
85
+ formatOpenclawDoctorReport
86
+ };
@@ -2,16 +2,18 @@ import {
2
2
  STATUS_LINE_PREFIX,
3
3
  monitorHeartbeatPath,
4
4
  nudgeSentinelPath,
5
+ resolveEventLogPath,
5
6
  startEventLog,
6
7
  statusLogPath,
7
8
  sweepStaleEventLogs
8
- } from "./chunk-DURRQDYI.js";
9
- import "./chunk-DO42NPNR.js";
10
- import "./chunk-BLEGIR35.js";
9
+ } from "./chunk-TNZITJAB.js";
10
+ import "./chunk-67F67AQ6.js";
11
+ import "./chunk-U5HHHRXA.js";
11
12
  export {
12
13
  STATUS_LINE_PREFIX,
13
14
  monitorHeartbeatPath,
14
15
  nudgeSentinelPath,
16
+ resolveEventLogPath,
15
17
  startEventLog,
16
18
  statusLogPath,
17
19
  sweepStaleEventLogs
@@ -5,9 +5,11 @@ import {
5
5
  normalizeBackendEvent,
6
6
  sanitizeDisplayname,
7
7
  serializeCursorMap,
8
- startEventStream
9
- } from "./chunk-XN3IC4B5.js";
10
- import "./chunk-NR4Y54OL.js";
8
+ startEventStream,
9
+ statusReason
10
+ } from "./chunk-FSKGQ6GT.js";
11
+ import "./chunk-Z5LPNJQ6.js";
12
+ import "./chunk-MIEI4PLB.js";
11
13
  export {
12
14
  UNDICI_DEFAULT_BODY_TIMEOUT_MS,
13
15
  createAdaptiveWatchdog,
@@ -15,5 +17,6 @@ export {
15
17
  normalizeBackendEvent,
16
18
  sanitizeDisplayname,
17
19
  serializeCursorMap,
18
- startEventStream
20
+ startEventStream,
21
+ statusReason
19
22
  };
package/dist/index.js CHANGED
@@ -1,17 +1,19 @@
1
1
  import {
2
2
  listTandemIds,
3
3
  startProxy
4
- } from "./chunk-BYV7CWNY.js";
5
- import "./chunk-N35X22G7.js";
6
- import "./chunk-KH5YEJIM.js";
7
- import "./chunk-JXMVZEQ7.js";
8
- import "./chunk-NR4Y54OL.js";
9
- import "./chunk-CH32ELFX.js";
10
- import "./chunk-BLEGIR35.js";
11
- import "./chunk-ALZX3SGI.js";
12
- import "./chunk-Q7T3WAST.js";
4
+ } from "./chunk-5H75AEZ2.js";
5
+ import "./chunk-OB5T6P24.js";
6
+ import "./chunk-247WFMCJ.js";
7
+ import "./chunk-I67C2HYA.js";
8
+ import "./chunk-Z5LPNJQ6.js";
9
+ import "./chunk-MIEI4PLB.js";
10
+ import "./chunk-6G6YYST6.js";
11
+ import "./chunk-U5HHHRXA.js";
12
+ import "./chunk-SGRVG4HW.js";
13
+ import "./chunk-QEJUNP3X.js";
13
14
  import "./chunk-PPTKGWFF.js";
14
- import "./chunk-VHKPWUX7.js";
15
+ import "./chunk-XJEBJIQE.js";
16
+ import "./chunk-KNEJTD6G.js";
15
17
  export {
16
18
  listTandemIds,
17
19
  startProxy
@@ -1,6 +1,13 @@
1
+ import {
2
+ buildHookCommand,
3
+ isKojeeHookCommand
4
+ } from "./chunk-QJFMU4QC.js";
5
+ import {
6
+ wrapNpxLauncher
7
+ } from "./chunk-D6JKFJ6A.js";
1
8
  import {
2
9
  secureFile
3
- } from "./chunk-BLEGIR35.js";
10
+ } from "./chunk-U5HHHRXA.js";
4
11
 
5
12
  // src/hooks/install.ts
6
13
  import fs from "fs";
@@ -27,8 +34,6 @@ function discoverInstallTargets() {
27
34
  }
28
35
  return targets;
29
36
  }
30
- var STOP_COMMAND = "npx -y kojee-mcp hook --type=stop";
31
- var UPS_COMMAND = "npx -y kojee-mcp hook --type=user-prompt-submit";
32
37
  var MCP_SERVER_CMD = "npx";
33
38
  var MCP_SERVER_ARGS = ["kojee-mcp"];
34
39
  var MCP_SERVER_ENV = { KOJEE_RUNTIME: "claude-code" };
@@ -54,14 +59,18 @@ function writeConfig(p, cfg) {
54
59
  fs.writeFileSync(p, JSON.stringify(cfg, null, 2), { mode: 384 });
55
60
  secureFile(p);
56
61
  }
57
- function hasKojeeEntry(arr, command) {
58
- if (!arr) return false;
59
- return arr.some((e) => e.hooks.some((h) => h.command === command));
60
- }
61
62
  function installHookEntry(cfg, event, command) {
62
63
  cfg.hooks ??= {};
63
64
  cfg.hooks[event] ??= [];
64
- if (hasKojeeEntry(cfg.hooks[event], command)) return "already-installed";
65
+ for (const entry of cfg.hooks[event]) {
66
+ for (const h of entry.hooks) {
67
+ if (h.command === command) return "already-installed";
68
+ if (isKojeeHookCommand(h.command)) {
69
+ h.command = command;
70
+ return "updated";
71
+ }
72
+ }
73
+ }
65
74
  cfg.hooks[event].push({ hooks: [{ type: "command", command }] });
66
75
  return "added";
67
76
  }
@@ -73,7 +82,7 @@ function uninstallHookEntries(cfg) {
73
82
  if (!arr) continue;
74
83
  const before = arr.length;
75
84
  cfg.hooks[event] = arr.filter(
76
- (entry) => !entry.hooks.some((h) => h.command.startsWith("npx -y kojee-mcp hook"))
85
+ (entry) => !entry.hooks.some((h) => isKojeeHookCommand(h.command))
77
86
  );
78
87
  if (cfg.hooks[event].length !== before) removed = true;
79
88
  }
@@ -82,8 +91,8 @@ function uninstallHookEntries(cfg) {
82
91
  function installHooks(opts = {}) {
83
92
  const p = opts.hooksPath ?? (opts.configPath ? deriveHooksPath(opts.configPath) : defaultHooksPath());
84
93
  const cfg = readConfig(p);
85
- const stop = installHookEntry(cfg, "Stop", STOP_COMMAND);
86
- const ups = installHookEntry(cfg, "UserPromptSubmit", UPS_COMMAND);
94
+ const stop = installHookEntry(cfg, "Stop", buildHookCommand("stop"));
95
+ const ups = installHookEntry(cfg, "UserPromptSubmit", buildHookCommand("user-prompt-submit"));
87
96
  writeConfig(p, cfg);
88
97
  return { stop, ups };
89
98
  }
@@ -98,26 +107,29 @@ function mcpServerArgs(opts) {
98
107
  if (opts.token && opts.url) {
99
108
  return [...MCP_SERVER_ARGS, "--token", opts.token, "--url", opts.url];
100
109
  }
110
+ if (opts.pairedConfigPath) {
111
+ return [...MCP_SERVER_ARGS, "--paired-config", opts.pairedConfigPath];
112
+ }
101
113
  return [...MCP_SERVER_ARGS];
102
114
  }
103
115
  function installMcpServer(opts = {}) {
104
116
  const p = opts.configPath ?? defaultConfigPath();
105
117
  const cfg = readConfig(p);
106
118
  cfg.mcpServers ??= {};
107
- const args = mcpServerArgs(opts);
119
+ const { command, args } = wrapNpxLauncher(MCP_SERVER_CMD, mcpServerArgs(opts));
120
+ const env = { ...MCP_SERVER_ENV };
108
121
  const existing = cfg.mcpServers["kojee"];
109
122
  if (existing) {
110
- const sameCommand = existing.command === MCP_SERVER_CMD;
123
+ const sameCommand = existing.command === command;
111
124
  const sameArgs = JSON.stringify(existing.args ?? []) === JSON.stringify(args);
112
- const sameEnv = JSON.stringify(existing.env ?? {}) === JSON.stringify(MCP_SERVER_ENV);
125
+ const sameEnv = JSON.stringify(existing.env ?? {}) === JSON.stringify(env);
113
126
  if (sameCommand && sameArgs && sameEnv) return "already-installed";
114
- return "preserved-different";
127
+ if (!opts.overwrite) return "preserved-different";
128
+ cfg.mcpServers["kojee"] = { ...existing, command, args, env };
129
+ writeConfig(p, cfg);
130
+ return "updated";
115
131
  }
116
- cfg.mcpServers["kojee"] = {
117
- command: MCP_SERVER_CMD,
118
- args,
119
- env: { ...MCP_SERVER_ENV }
120
- };
132
+ cfg.mcpServers["kojee"] = { command, args, env };
121
133
  writeConfig(p, cfg);
122
134
  return "added";
123
135
  }
@@ -130,12 +142,13 @@ function uninstallMcpServer(opts = {}) {
130
142
  return true;
131
143
  }
132
144
  function runInit(opts = {}) {
133
- const targets = opts.configPath ? [{
145
+ const discovered = opts.configPath ? [{
134
146
  kind: "cli",
135
147
  path: opts.configPath,
136
148
  exists: true,
137
149
  hooksPath: opts.hooksPath ?? deriveHooksPath(opts.configPath)
138
150
  }] : discoverInstallTargets();
151
+ const targets = opts.ensureCli ? discovered.map((t) => t.kind === "cli" ? { ...t, exists: true } : t) : discovered;
139
152
  const reports = [];
140
153
  for (const t of targets) {
141
154
  if (!t.exists) {
@@ -145,7 +158,9 @@ function runInit(opts = {}) {
145
158
  const mcpServer = installMcpServer({
146
159
  configPath: t.path,
147
160
  ...opts.token ? { token: opts.token } : {},
148
- ...opts.url ? { url: opts.url } : {}
161
+ ...opts.url ? { url: opts.url } : {},
162
+ ...opts.pairedConfigPath ? { pairedConfigPath: opts.pairedConfigPath } : {},
163
+ ...opts.overwrite ? { overwrite: true } : {}
149
164
  });
150
165
  let stopHook;
151
166
  let upsHook;
@@ -4,8 +4,8 @@ import {
4
4
  generateES256KeyPair,
5
5
  loadKeystore,
6
6
  saveKeystore
7
- } from "./chunk-CH32ELFX.js";
8
- import "./chunk-BLEGIR35.js";
7
+ } from "./chunk-6G6YYST6.js";
8
+ import "./chunk-U5HHHRXA.js";
9
9
  export {
10
10
  defaultPairedKeystorePath,
11
11
  deriveKeystorePath,
package/dist/lib.d.ts CHANGED
@@ -129,13 +129,16 @@ interface PairedConfig {
129
129
  token: string;
130
130
  broker_url: string;
131
131
  paired_at: string;
132
+ /** Stamped at connect time; used by doctor + launch cross-check. */
133
+ runtime?: string;
132
134
  principal_id?: string;
133
135
  agent_id?: string;
134
136
  }
137
+ /** Legacy global paired slot (fallback only). */
135
138
  declare function pairedConfigPath(): string;
136
139
  declare function loadPairedConfig(filePath?: string): PairedConfig | null;
137
140
 
138
- type Runtime = "claude-code" | "codex" | "unknown";
141
+ type Runtime = "claude-code" | "codex" | "openclaw" | "unknown";
139
142
 
140
143
  /**
141
144
  * Per-harness adapter. Today: minimal — only what's needed for the
package/dist/lib.js CHANGED
@@ -5,31 +5,34 @@ import {
5
5
  normalizeBackendEvent,
6
6
  sanitizeDisplayname,
7
7
  startEventStream
8
- } from "./chunk-XN3IC4B5.js";
8
+ } from "./chunk-FSKGQ6GT.js";
9
9
  import {
10
10
  loadPairedConfig,
11
11
  pairedConfigPath
12
- } from "./chunk-YH27B6SW.js";
12
+ } from "./chunk-5SZHXYPK.js";
13
13
  import {
14
14
  GatewayClient,
15
15
  applyStableSessionId
16
- } from "./chunk-KH5YEJIM.js";
16
+ } from "./chunk-247WFMCJ.js";
17
17
  import {
18
18
  AuthModule
19
- } from "./chunk-JXMVZEQ7.js";
19
+ } from "./chunk-I67C2HYA.js";
20
20
  import {
21
- createDPoPProof,
22
21
  deriveStableSessionId
23
- } from "./chunk-NR4Y54OL.js";
22
+ } from "./chunk-Z5LPNJQ6.js";
23
+ import {
24
+ createDPoPProof
25
+ } from "./chunk-MIEI4PLB.js";
24
26
  import {
25
27
  defaultPairedKeystorePath,
26
28
  deriveKeystorePath,
27
29
  generateES256KeyPair,
28
30
  loadKeystore,
29
31
  saveKeystore
30
- } from "./chunk-CH32ELFX.js";
31
- import "./chunk-BLEGIR35.js";
32
+ } from "./chunk-6G6YYST6.js";
33
+ import "./chunk-U5HHHRXA.js";
32
34
  import "./chunk-PPTKGWFF.js";
35
+ import "./chunk-KNEJTD6G.js";
33
36
  export {
34
37
  AuthModule,
35
38
  GatewayClient,
@@ -0,0 +1,11 @@
1
+ import {
2
+ runPair
3
+ } from "./chunk-EIAUW6KO.js";
4
+ import "./chunk-5SZHXYPK.js";
5
+ import "./chunk-I67C2HYA.js";
6
+ import "./chunk-MIEI4PLB.js";
7
+ import "./chunk-6G6YYST6.js";
8
+ import "./chunk-U5HHHRXA.js";
9
+ export {
10
+ runPair
11
+ };
@@ -1,11 +1,13 @@
1
1
  import {
2
2
  loadPairedConfig,
3
3
  pairedConfigPath,
4
+ perRuntimeConfigPath,
4
5
  savePairedConfig
5
- } from "./chunk-YH27B6SW.js";
6
- import "./chunk-BLEGIR35.js";
6
+ } from "./chunk-5SZHXYPK.js";
7
+ import "./chunk-U5HHHRXA.js";
7
8
  export {
8
9
  loadPairedConfig,
9
10
  pairedConfigPath,
11
+ perRuntimeConfigPath,
10
12
  savePairedConfig
11
13
  };
@@ -1,14 +1,19 @@
1
1
  import {
2
- findClaudeAncestorPid
3
- } from "./chunk-VHKPWUX7.js";
2
+ findClaudeAncestorPid,
3
+ pidLooksLikeClaude
4
+ } from "./chunk-XJEBJIQE.js";
4
5
 
5
6
  // src/runtime/parent-watchdog.ts
7
+ function shouldArmWatchdog(ccPid) {
8
+ return ccPid !== null;
9
+ }
6
10
  function defaultIsPidAlive(pid) {
7
11
  try {
8
12
  process.kill(pid, 0);
9
13
  return true;
10
14
  } catch (err) {
11
- if (err.code === "EPERM") return true;
15
+ const code = err.code;
16
+ if (code === "EPERM" || code === "EACCES") return true;
12
17
  return false;
13
18
  }
14
19
  }
@@ -16,9 +21,12 @@ function createParentWatchdog(opts) {
16
21
  const intervalMs = opts.intervalMs ?? 7e3;
17
22
  const isPidAlive = opts.isPidAlive ?? defaultIsPidAlive;
18
23
  const resolveAncestor = opts.resolveAncestor ?? (() => findClaudeAncestorPid());
24
+ const verifyPidIdentity = opts.verifyPidIdentity ?? pidLooksLikeClaude;
25
+ const identityCheckEveryNTicks = opts.identityCheckEveryNTicks ?? 4;
19
26
  let timer = null;
20
27
  let fired = false;
21
28
  let checking = false;
29
+ let tick = 0;
22
30
  function stop() {
23
31
  if (timer !== null) {
24
32
  clearInterval(timer);
@@ -30,7 +38,17 @@ function createParentWatchdog(opts) {
30
38
  checking = true;
31
39
  try {
32
40
  const ccPidAlive = isPidAlive(opts.ccPid);
33
- if (ccPidAlive) return;
41
+ if (ccPidAlive) {
42
+ tick++;
43
+ if (tick % identityCheckEveryNTicks !== 0) return;
44
+ let identity = null;
45
+ try {
46
+ identity = await verifyPidIdentity(opts.ccPid);
47
+ } catch {
48
+ identity = null;
49
+ }
50
+ if (identity !== false) return;
51
+ }
34
52
  let ancestor = null;
35
53
  try {
36
54
  ancestor = await resolveAncestor();
@@ -61,5 +79,6 @@ function createParentWatchdog(opts) {
61
79
  }
62
80
  export {
63
81
  createParentWatchdog,
64
- defaultIsPidAlive
82
+ defaultIsPidAlive,
83
+ shouldArmWatchdog
65
84
  };