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,11 +1,16 @@
1
- import "./chunk-KFDZWNQO.js";
1
+ import {
2
+ createCachedOpenclawWakeResolver,
3
+ postOpenclawWake
4
+ } from "./chunk-NE2F5CKS.js";
2
5
  import "./chunk-PHXO5P25.js";
3
- import "./chunk-LSUB6QMP.js";
6
+ import {
7
+ codexPendingMarkerPath
8
+ } from "./chunk-WIU5WGDF.js";
4
9
  import {
5
10
  claudeCodeAdapter
6
- } from "./chunk-N35X22G7.js";
7
- import "./chunk-ALZX3SGI.js";
8
- import "./chunk-Q7T3WAST.js";
11
+ } from "./chunk-OB5T6P24.js";
12
+ import "./chunk-SGRVG4HW.js";
13
+ import "./chunk-QEJUNP3X.js";
9
14
  import "./chunk-PPTKGWFF.js";
10
15
 
11
16
  // src/delivery/lib/fanout.ts
@@ -36,6 +41,18 @@ async function deliverEvent(event, sinks) {
36
41
  } catch (err) {
37
42
  console.error("[event-stream] webhook enqueue failed:", err);
38
43
  }
44
+ if (sinks.codexPendingMarker) {
45
+ try {
46
+ const pending = sinks.codexPendingMarker(event);
47
+ if (pending && typeof pending.then === "function") {
48
+ pending.catch((err) => {
49
+ console.error("[event-stream] codex pending-marker write failed:", err);
50
+ });
51
+ }
52
+ } catch (err) {
53
+ console.error("[event-stream] codex pending-marker write failed:", err);
54
+ }
55
+ }
39
56
  }
40
57
 
41
58
  // src/delivery/lib/channel.ts
@@ -96,20 +113,27 @@ function createClaudeCodeDelivery() {
96
113
  writeDiscoveryByKey,
97
114
  cleanupDiscoveryByKey,
98
115
  sweepStaleDiscovery
99
- } = await import("./session-discovery-FNMJGFPM.js");
100
- const { startEventLog, sweepStaleEventLogs } = await import("./event-log-HOBO3ECB.js");
116
+ } = await import("./session-discovery-NHCZ2XWA.js");
117
+ const { startEventLog, sweepStaleEventLogs } = await import("./event-log-2NBJEIEP.js");
101
118
  const { resubscribeMemberships } = await import("./resubscribe-G5OGDZJD.js");
102
119
  const { resolveWebhookConfig } = await import("./webhook-config-O4WMQ532.js");
103
120
  const { createWebhookSink } = await import("./webhook-sink-N6AUTFL3.js");
104
- const { startEventStream } = await import("./event-stream-SYBUJ5EH.js");
105
- const { createMcpServer } = await import("./server-R24AVNTI.js");
106
- const { deriveDiscoveryKey } = await import("./ancestry-ONFBQEP5.js");
121
+ const { startEventStream } = await import("./event-stream-KRYWEYWO.js");
122
+ const { createMcpServer } = await import("./server-YTHOMA4H.js");
123
+ const { deriveDiscoveryKey } = await import("./ancestry-A2F5KQ6A.js");
124
+ const { resolveSharedSessionId } = await import("./cc-session-id-RURNIHHC.js");
107
125
  sweepStaleDiscovery();
108
126
  sweepStaleEventLogs();
109
127
  const projectDir = process.env["CLAUDE_PROJECT_DIR"];
110
- const discoveryKey = deriveDiscoveryKey(projectDir, ctx.ccPid);
128
+ const sessionId = resolveSharedSessionId();
129
+ const discoveryKey = deriveDiscoveryKey(projectDir, ctx.ccPid, sessionId);
111
130
  eventLog = startEventLog({
112
131
  key: ctx.instanceKey,
132
+ // The proxy's OWN discovery key: lets startEventLog reclaim the STABLE
133
+ // base log path on an in-session reconnect (env-switch / /mcp reconnect;
134
+ // unchanged ccPid → unchanged discovery key) instead of salting and
135
+ // stranding the agent's already-running Monitor on the dead base log.
136
+ selfKey: discoveryKey,
113
137
  ...ctx.eventLogDir ? { dir: ctx.eventLogDir } : {}
114
138
  });
115
139
  const log = eventLog;
@@ -142,7 +166,7 @@ function createClaudeCodeDelivery() {
142
166
  eventLog.path,
143
167
  ctx.toolCallHooks
144
168
  );
145
- const { issueControlToken, controlTokenPath } = await import("./control-token-4BUCTYQB.js");
169
+ const { issueControlToken, controlTokenPath } = await import("./control-token-KXSZ3GBY.js");
146
170
  let controlToken = null;
147
171
  try {
148
172
  controlToken = issueControlToken();
@@ -174,7 +198,7 @@ function createClaudeCodeDelivery() {
174
198
  staleAfterMs: null
175
199
  }
176
200
  });
177
- writeDiscoveryByKey(discoveryKey, {
201
+ const discoveryEntry = {
178
202
  schema: 2,
179
203
  discoveryKey,
180
204
  ccPid: ctx.ccPid,
@@ -187,8 +211,18 @@ function createClaudeCodeDelivery() {
187
211
  eventLogPath: eventLog.path,
188
212
  ...controlToken !== null ? { controlTokenPath: controlTokenPath() } : {},
189
213
  authMode: ctx.config.authMode ?? "paired"
190
- });
191
- cleanupDiscoveryFile = () => cleanupDiscoveryByKey(discoveryKey);
214
+ };
215
+ writeDiscoveryByKey(discoveryKey, discoveryEntry);
216
+ const aliasKey = sessionId && ctx.ccPid !== null ? deriveDiscoveryKey(projectDir, ctx.ccPid, null) : null;
217
+ if (aliasKey !== null && aliasKey !== discoveryKey) {
218
+ writeDiscoveryByKey(aliasKey, { ...discoveryEntry, discoveryKey: aliasKey });
219
+ }
220
+ cleanupDiscoveryFile = () => {
221
+ cleanupDiscoveryByKey(discoveryKey);
222
+ if (aliasKey !== null && aliasKey !== discoveryKey) {
223
+ cleanupDiscoveryByKey(aliasKey);
224
+ }
225
+ };
192
226
  const localCleanupDiscovery = cleanupDiscoveryFile;
193
227
  const localHookServer = hookServer;
194
228
  const localLiveliness = liveliness;
@@ -267,19 +301,19 @@ function createClaudeCodeDelivery() {
267
301
  }
268
302
 
269
303
  // src/delivery/hermes.ts
270
- function createWebhookDelivery(name) {
304
+ function createWebhookDelivery(name, codexPendingMarker) {
271
305
  let eventLog = null;
272
306
  let webhookSink = null;
273
307
  let streamHandle = null;
274
308
  return {
275
309
  name,
276
310
  async start(ctx) {
277
- const { startEventLog, sweepStaleEventLogs } = await import("./event-log-HOBO3ECB.js");
311
+ const { startEventLog, sweepStaleEventLogs } = await import("./event-log-2NBJEIEP.js");
278
312
  const { resolveWebhookConfig } = await import("./webhook-config-O4WMQ532.js");
279
313
  const { createWebhookSink } = await import("./webhook-sink-N6AUTFL3.js");
280
314
  const { resubscribeMemberships } = await import("./resubscribe-G5OGDZJD.js");
281
- const { startEventStream } = await import("./event-stream-SYBUJ5EH.js");
282
- const { createMcpServer } = await import("./server-R24AVNTI.js");
315
+ const { startEventStream } = await import("./event-stream-KRYWEYWO.js");
316
+ const { createMcpServer } = await import("./server-YTHOMA4H.js");
283
317
  sweepStaleEventLogs();
284
318
  eventLog = startEventLog({
285
319
  key: ctx.instanceKey,
@@ -348,7 +382,9 @@ function createWebhookDelivery(name) {
348
382
  async deliver(event) {
349
383
  await deliverEvent(event, {
350
384
  ...eventLog ? { eventLog } : {},
351
- ...webhookSink ? { webhookSink } : {}
385
+ ...webhookSink ? { webhookSink } : {},
386
+ // OPTIONAL codex-only marker sink (undefined ⇒ byte-identical hermes path).
387
+ ...codexPendingMarker ? { codexPendingMarker } : {}
352
388
  });
353
389
  },
354
390
  async stop() {
@@ -365,9 +401,139 @@ function createWebhookDelivery(name) {
365
401
  };
366
402
  }
367
403
 
404
+ // src/delivery/codex-pending-marker.ts
405
+ import fsp from "fs/promises";
406
+ import path from "path";
407
+ import crypto from "crypto";
408
+ var MAX_MARKER_BODY_CHARS = 32;
409
+ var ensuredDir = null;
410
+ async function writeCodexPendingMarker(event) {
411
+ const markerPath = codexPendingMarkerPath();
412
+ const dir = path.dirname(markerPath);
413
+ const tmp = `${markerPath}.tmp-${process.pid}-${crypto.randomUUID()}`;
414
+ try {
415
+ if (ensuredDir !== dir) {
416
+ await fsp.mkdir(dir, { recursive: true });
417
+ ensuredDir = dir;
418
+ }
419
+ const body = String(event.cursor ?? 0).slice(0, MAX_MARKER_BODY_CHARS);
420
+ await fsp.writeFile(tmp, body, { mode: 384 });
421
+ await fsp.rename(tmp, markerPath);
422
+ } catch {
423
+ ensuredDir = null;
424
+ try {
425
+ await fsp.unlink(tmp);
426
+ } catch {
427
+ }
428
+ }
429
+ }
430
+
368
431
  // src/delivery/codex.ts
369
432
  function createCodexDelivery() {
370
- return createWebhookDelivery("codex");
433
+ return createWebhookDelivery("codex", writeCodexPendingMarker);
434
+ }
435
+
436
+ // src/delivery/openclaw.ts
437
+ function formatOpenclawNudge(event) {
438
+ const who = event.from?.member_id ?? "someone";
439
+ const body = (event.content?.body ?? "").replace(/\s+/g, " ").slice(0, 160);
440
+ return `New Kojee Tandem activity in ${event.tandem_id} from ${who}: "${body}". Catch up with tandem_messages / tandem_listen and reply via tandem_send.`;
441
+ }
442
+ function createOpenclawDelivery(deps = {}) {
443
+ const resolveTarget = deps.resolveTarget ?? createCachedOpenclawWakeResolver();
444
+ const postWake = deps.postWake ?? postOpenclawWake;
445
+ let eventLog = null;
446
+ let streamHandle = null;
447
+ let warnedUnconfigured = false;
448
+ return {
449
+ name: "openclaw",
450
+ async start(ctx) {
451
+ const { startEventLog, sweepStaleEventLogs } = await import("./event-log-2NBJEIEP.js");
452
+ const { resubscribeMemberships } = await import("./resubscribe-G5OGDZJD.js");
453
+ const { startEventStream } = await import("./event-stream-KRYWEYWO.js");
454
+ const { createMcpServer } = await import("./server-YTHOMA4H.js");
455
+ sweepStaleEventLogs();
456
+ eventLog = startEventLog({
457
+ key: ctx.instanceKey,
458
+ ...ctx.eventLogDir ? { dir: ctx.eventLogDir } : {}
459
+ });
460
+ const log = eventLog;
461
+ const initial = await resolveTarget();
462
+ void log.appendStatus(
463
+ `status=openclaw-wake ${initial.ok ? `target=${initial.target.url}` : `error="${initial.reason}"`}`
464
+ ).catch(() => {
465
+ });
466
+ const server = createMcpServer(
467
+ ctx.registry,
468
+ ctx.adapter,
469
+ ctx.tandemMembershipCount,
470
+ void 0,
471
+ ctx.toolCallHooks
472
+ );
473
+ const teardown = [() => eventLog?.cleanup()];
474
+ streamHandle = await startEventStream({
475
+ brokerUrl: ctx.config.url,
476
+ token: ctx.config.token,
477
+ gateway: ctx.gateway,
478
+ adapter: ctx.adapter,
479
+ server,
480
+ eventLog,
481
+ delivery: this,
482
+ onConnected: /* @__PURE__ */ (() => {
483
+ const debounceState = { lastRunAt: 0 };
484
+ return async () => {
485
+ await resubscribeMemberships({
486
+ gateway: ctx.gateway,
487
+ eventLog,
488
+ listTandems: async () => await ctx.listTandemIds() ?? [],
489
+ debounceState
490
+ });
491
+ };
492
+ })()
493
+ });
494
+ ctx.onStreamReady?.(streamHandle);
495
+ return { server, teardown, exitCleanup: () => eventLog?.cleanup() };
496
+ },
497
+ // Event-log append FIRST (survival/observability parity with hermes; the
498
+ // Monitor's PRIMARY wake path, so it is AWAITED like fanout's eventLog sink).
499
+ // The /wake POST is FIRE-AND-FORGET: it is network I/O with a 4s timeout and
500
+ // must NOT be awaited on the shared consumeSse loop — a gateway that accepts
501
+ // TCP but hangs would otherwise backpressure the single interleaved stream
502
+ // for every room (hermes/codex enqueue their network/disk sinks the same way,
503
+ // fanout.ts). Target RESOLUTION rides the same detached chain (F5): it is
504
+ // disk I/O (openclaw.json read — async + mtime-cached by the default
505
+ // resolver), and a stalled home dir (NFS, AV scan, full disk) must never
506
+ // block the reader loop that multiplexes tool-call proxying for every room.
507
+ async deliver(event) {
508
+ try {
509
+ await eventLog?.append(event);
510
+ } catch (err) {
511
+ console.error("[openclaw] event-log append failed:", err);
512
+ }
513
+ void (async () => {
514
+ const r = await resolveTarget();
515
+ if (!r.ok) {
516
+ if (!warnedUnconfigured) {
517
+ warnedUnconfigured = true;
518
+ console.error(`[openclaw] wake skipped: ${r.reason}`);
519
+ }
520
+ return;
521
+ }
522
+ warnedUnconfigured = false;
523
+ const res = await postWake(r.target, { text: formatOpenclawNudge(event), mode: "now" });
524
+ if (!res.ok) console.error(`[openclaw] wake POST failed: ${res.error ?? res.status}`);
525
+ })().catch((err) => {
526
+ console.error("[openclaw] wake delivery failed:", err);
527
+ });
528
+ },
529
+ async stop() {
530
+ eventLog?.cleanup();
531
+ },
532
+ health() {
533
+ const s = streamHandle?.getState();
534
+ return { connected: s ? s.connected ?? null : null, ...s ? { detail: { stream: s } } : {} };
535
+ }
536
+ };
371
537
  }
372
538
 
373
539
  // src/delivery/registry.ts
@@ -378,12 +544,15 @@ function selectDelivery(runtime, opts) {
378
544
  if (opts.supportsChannels) {
379
545
  return createClaudeCodeDelivery();
380
546
  }
381
- if (!needsWebhookEventStream(opts.env)) {
382
- return null;
383
- }
384
547
  if (runtime === "codex") {
385
548
  return createCodexDelivery();
386
549
  }
550
+ if (runtime === "openclaw") {
551
+ return createOpenclawDelivery();
552
+ }
553
+ if (!needsWebhookEventStream(opts.env)) {
554
+ return null;
555
+ }
387
556
  return createWebhookDelivery(runtime);
388
557
  }
389
558
  export {
@@ -0,0 +1,13 @@
1
+ import {
2
+ CONNECT_RUNTIMES,
3
+ resolveLaunchCreds,
4
+ resolvePairedSlot
5
+ } from "./chunk-EIH2LNF4.js";
6
+ import "./chunk-5SZHXYPK.js";
7
+ import "./chunk-6G6YYST6.js";
8
+ import "./chunk-U5HHHRXA.js";
9
+ export {
10
+ CONNECT_RUNTIMES,
11
+ resolveLaunchCreds,
12
+ resolvePairedSlot
13
+ };
@@ -3,9 +3,9 @@ import {
3
3
  readRecordedRuntime,
4
4
  recordRuntime,
5
5
  runtimeRecordPath
6
- } from "./chunk-EW72ZNQL.js";
6
+ } from "./chunk-RDLF4NQC.js";
7
7
  import "./chunk-SQL56SEB.js";
8
- import "./chunk-BLEGIR35.js";
8
+ import "./chunk-U5HHHRXA.js";
9
9
  export {
10
10
  clearRuntimeRecord,
11
11
  readRecordedRuntime,
@@ -1,3 +1,6 @@
1
+ import {
2
+ resolvePairedSlot
3
+ } from "./chunk-EIH2LNF4.js";
1
4
  import {
2
5
  executeJoin,
3
6
  executeSend,
@@ -6,38 +9,47 @@ import {
6
9
  } from "./chunk-PKOBR7ZN.js";
7
10
  import {
8
11
  loadPairedConfig
9
- } from "./chunk-YH27B6SW.js";
12
+ } from "./chunk-5SZHXYPK.js";
10
13
  import {
11
14
  GatewayClient,
12
15
  applyStableSessionId
13
- } from "./chunk-KH5YEJIM.js";
14
- import "./chunk-NR4Y54OL.js";
16
+ } from "./chunk-247WFMCJ.js";
17
+ import "./chunk-Z5LPNJQ6.js";
18
+ import "./chunk-MIEI4PLB.js";
15
19
  import {
20
+ deriveKeystorePath,
16
21
  loadKeystore
17
- } from "./chunk-CH32ELFX.js";
18
- import "./chunk-BLEGIR35.js";
22
+ } from "./chunk-6G6YYST6.js";
23
+ import "./chunk-U5HHHRXA.js";
19
24
  import "./chunk-PPTKGWFF.js";
25
+ import "./chunk-KNEJTD6G.js";
20
26
 
21
27
  // src/tandem/send-cli.ts
22
28
  import os from "os";
23
29
  import path from "path";
24
- async function createPairedGateway(kojeeDir, stableDeps = {}) {
25
- const configPath = path.join(kojeeDir, "config.json");
30
+ async function createPairedGateway(kojeeDir, stableDeps = {}, slot = {}) {
31
+ const resolvedRuntime = slot.runtime ?? process.env["KOJEE_RUNTIME"];
32
+ const resolution = resolvePairedSlot({
33
+ ...slot.pairedConfig ? { pairedConfig: slot.pairedConfig } : {},
34
+ ...resolvedRuntime ? { runtime: resolvedRuntime } : {},
35
+ kojeeDir
36
+ });
37
+ const configPath = resolution.configPath;
26
38
  const paired = loadPairedConfig(configPath);
27
39
  if (!paired) {
28
40
  return sendFailure(
29
41
  "not_paired",
30
- `no paired config at ${configPath} \u2014 run \`kojee-mcp pair <code> --url <broker>\` first`
42
+ `no paired config at ${configPath} \u2014 run \`kojee-mcp connect <code> --runtime <id>\` first`
31
43
  );
32
44
  }
33
45
  await applyStableSessionId(paired.token, stableDeps);
34
46
  const brokerUrl = paired.broker_url.replace(/\/+$/, "");
35
- const keystorePath = path.join(kojeeDir, "keypair.json");
47
+ const keystorePath = resolution.scope === "paired" ? deriveKeystorePath(paired.token) : path.join(kojeeDir, "keypair.json");
36
48
  const keystore = await loadKeystore(keystorePath, brokerUrl).catch(() => null);
37
49
  if (!keystore) {
38
50
  return sendFailure(
39
51
  "not_enrolled",
40
- `no DPoP keystore for ${brokerUrl} at ${keystorePath} \u2014 start the proxy once (or re-run \`kojee-mcp pair\`) to enroll a keypair`
52
+ `no DPoP keystore for ${brokerUrl} at ${keystorePath} \u2014 start the proxy once (or re-run \`kojee-mcp connect\`) to enroll a keypair`
41
53
  );
42
54
  }
43
55
  const sessionId = GatewayClient.deriveSessionId(paired.token);
@@ -1,13 +1,15 @@
1
1
  import {
2
2
  buildChannelInstructions,
3
+ buildNonChannelInstructions,
3
4
  createMcpServer,
4
5
  executeToolCall,
5
6
  startMcpServer
6
- } from "./chunk-ALZX3SGI.js";
7
- import "./chunk-Q7T3WAST.js";
7
+ } from "./chunk-SGRVG4HW.js";
8
+ import "./chunk-QEJUNP3X.js";
8
9
  import "./chunk-PPTKGWFF.js";
9
10
  export {
10
11
  buildChannelInstructions,
12
+ buildNonChannelInstructions,
11
13
  createMcpServer,
12
14
  executeToolCall,
13
15
  startMcpServer
@@ -10,8 +10,8 @@ import {
10
10
  sweepStaleDiscovery,
11
11
  writeDiscoveryByKey,
12
12
  writeSessionDiscovery
13
- } from "./chunk-DO42NPNR.js";
14
- import "./chunk-BLEGIR35.js";
13
+ } from "./chunk-67F67AQ6.js";
14
+ import "./chunk-U5HHHRXA.js";
15
15
  export {
16
16
  cleanupDiscoveryByKey,
17
17
  cleanupSessionDiscovery,
@@ -0,0 +1,159 @@
1
+ import {
2
+ DEFAULT_BROKER_URL,
3
+ pairSlotFor,
4
+ reconcileConnectPairSlot,
5
+ runWizard
6
+ } from "./chunk-GVWYW7MY.js";
7
+ import "./chunk-E6WMFMM2.js";
8
+ import "./chunk-OBIJ6WQP.js";
9
+ import "./chunk-QJFMU4QC.js";
10
+ import "./chunk-D6JKFJ6A.js";
11
+ import "./chunk-EIH2LNF4.js";
12
+ import "./chunk-RDLF4NQC.js";
13
+ import "./chunk-SQL56SEB.js";
14
+ import {
15
+ isWizardRuntime
16
+ } from "./chunk-77HWBSRH.js";
17
+ import "./chunk-V5VZPYMZ.js";
18
+ import {
19
+ runPair
20
+ } from "./chunk-EIAUW6KO.js";
21
+ import {
22
+ loadPairedConfig
23
+ } from "./chunk-5SZHXYPK.js";
24
+ import "./chunk-I67C2HYA.js";
25
+ import "./chunk-MIEI4PLB.js";
26
+ import "./chunk-6G6YYST6.js";
27
+ import "./chunk-U5HHHRXA.js";
28
+ import "./chunk-QEJUNP3X.js";
29
+
30
+ // src/wizard/setup-handler.ts
31
+ var SETUP_SUPPORTED_RUNTIMES = ["claude-code", "codex"];
32
+ function isSetupRuntime(value) {
33
+ return SETUP_SUPPORTED_RUNTIMES.includes(value);
34
+ }
35
+ function resolvePairCode(opts) {
36
+ return opts.pair ?? opts.pairCode;
37
+ }
38
+ async function runSetup(opts) {
39
+ const messages = [];
40
+ const requested = opts.runtime ?? "claude-code";
41
+ if (opts.verb === "setup" && opts.runtime !== void 0 && !isSetupRuntime(opts.runtime)) {
42
+ const supported = SETUP_SUPPORTED_RUNTIMES.join(", ");
43
+ const output = isWizardRuntime(opts.runtime) ? `\`setup\` does not support --runtime ${opts.runtime} yet (coming soon). Supported by \`setup\`: ${supported}. For ${opts.runtime}, use \`kojee-mcp init --runtime ${opts.runtime}\` for now.` : `Unknown --runtime "${opts.runtime}". \`setup\` supports: ${supported}. (For hermes/openclaw use \`kojee-mcp init\`.)`;
44
+ return { runtime: requested, messages, output, exitCode: 2 };
45
+ }
46
+ if (opts.token !== void 0 && (opts.url === void 0 || opts.url.trim() === "") && !opts.uninstall) {
47
+ return {
48
+ runtime: requested,
49
+ messages,
50
+ output: "--token requires --url (the broker URL the Kojee UI gave you). Re-run with --url <broker-url>. Nothing was written.",
51
+ exitCode: 2
52
+ };
53
+ }
54
+ const url = opts.url ? opts.url.replace(/\/+$/, "") : void 0;
55
+ if (opts.pairCode && !opts.uninstall && opts.interactive && opts.runtime === void 0) {
56
+ return {
57
+ runtime: requested,
58
+ messages,
59
+ output: "Pass --runtime (claude-code | codex) together with --pair <code> so the paired credentials are keyed to the runtime you're setting up. Re-run: kojee-mcp setup --pair <code> --runtime <id>.",
60
+ exitCode: 2
61
+ };
62
+ }
63
+ let justPaired = false;
64
+ let pairedConfigLauncher;
65
+ if (opts.pairCode && !opts.uninstall) {
66
+ const pair = opts.runPair ?? runPair;
67
+ const pairUrl = url ?? DEFAULT_BROKER_URL;
68
+ const reconcile = reconcileConnectPairSlot(requested, opts.pairCode);
69
+ if (!reconcile.ok) {
70
+ return { runtime: requested, messages, output: reconcile.output, exitCode: reconcile.exitCode };
71
+ }
72
+ messages.push(...reconcile.messages);
73
+ const slot = pairSlotFor(requested, opts.pairCode);
74
+ try {
75
+ const r = await pair({
76
+ code: opts.pairCode,
77
+ url: pairUrl,
78
+ keystorePath: slot.keystorePath,
79
+ configPath: slot.configPath,
80
+ ...slot.runtime ? { runtime: slot.runtime } : {},
81
+ ...slot.allowOverwrite ? { allowOverwrite: true } : {}
82
+ });
83
+ messages.push(r.message);
84
+ justPaired = true;
85
+ pairedConfigLauncher = slot.pairedConfigPath;
86
+ } catch (err) {
87
+ return {
88
+ runtime: requested,
89
+ messages,
90
+ output: `Pairing failed: ${err.message}`,
91
+ exitCode: 1
92
+ };
93
+ }
94
+ }
95
+ const loadCfg = opts.loadPairedConfig ?? loadPairedConfig;
96
+ const hasCredential = justPaired || loadCfg() !== null || opts.token !== void 0;
97
+ if (!hasCredential && !opts.interactive && !opts.uninstall) {
98
+ return {
99
+ runtime: requested,
100
+ messages,
101
+ output: "Not paired. Run `kojee-mcp pair <code> --url <broker>` first, then re-run \u2014 or pass --pair <code> (or --token <T> --url <U>), or run in a terminal for the guided wizard.",
102
+ exitCode: 1
103
+ };
104
+ }
105
+ const result = await runWizard({
106
+ ...opts.runtime !== void 0 ? { runtime: opts.runtime } : {},
107
+ ...opts.uninstall ? { uninstall: true } : {},
108
+ ...opts.configPath ? { configPath: opts.configPath } : {},
109
+ ...opts.hooksPath ? { hooksPath: opts.hooksPath } : {},
110
+ // Token mode (token + url) threads --token/--url into the written config.
111
+ ...opts.token ? { token: opts.token } : {},
112
+ ...url ? { url } : {},
113
+ // connect-runtime pair-mode: point the launcher at the per-runtime slot so
114
+ // the launched proxy reads it (its default branch reads only the global slot).
115
+ ...pairedConfigLauncher ? { pairedConfigPath: pairedConfigLauncher } : {},
116
+ ...opts.webhookUrl ? { webhookUrl: opts.webhookUrl } : {},
117
+ ...opts.webhookSecret ? { webhookSecret: opts.webhookSecret } : {},
118
+ ...opts.webhookSignatureFormat ? { webhookSignatureFormat: opts.webhookSignatureFormat } : {},
119
+ ...opts.webhookSignatureHeader ? { webhookSignatureHeader: opts.webhookSignatureHeader } : {},
120
+ ...opts.webhookSignaturePrefix !== void 0 ? { webhookSignaturePrefix: opts.webhookSignaturePrefix } : {},
121
+ interactive: opts.interactive,
122
+ ...opts.interactive && opts.prompts ? opts.prompts : {}
123
+ });
124
+ if (opts.verb === "setup" && result.exitCode === 0 && !opts.uninstall) {
125
+ return {
126
+ runtime: result.runtime,
127
+ messages,
128
+ output: crispSetupSummary(result.runtime, opts, url),
129
+ exitCode: 0
130
+ };
131
+ }
132
+ return { runtime: result.runtime, messages, output: result.output, exitCode: result.exitCode };
133
+ }
134
+ function crispSetupSummary(runtime, opts, url) {
135
+ const pairedSlotLabel = isSetupRuntime(runtime) ? `~/.kojee/agents/${runtime}/config.json` : "~/.kojee/config.json";
136
+ const authLine = opts.token ? ` Auth: token mode (--token/--url${url ? `, ${url}` : ""})` : ` Auth: paired credentials (${pairedSlotLabel})`;
137
+ const lines = [];
138
+ if (runtime === "codex") {
139
+ lines.push("\u2713 kojee is set up for Codex.");
140
+ lines.push(` MCP config: ${opts.configPath ?? "~/.codex/config.toml"} ([mcp_servers.kojee])`);
141
+ lines.push(` Stop hook: ${opts.hooksPath ?? "~/.codex/hooks.json"} (codex-stop)`);
142
+ lines.push(authLine);
143
+ lines.push("");
144
+ lines.push("Next: restart Codex to connect.");
145
+ } else {
146
+ lines.push("\u2713 kojee is set up for Claude Code.");
147
+ lines.push(` MCP config: ${opts.configPath ?? "~/.claude.json"} (mcpServers.kojee)`);
148
+ lines.push(` Hooks: ${opts.hooksPath ?? "~/.claude/settings.json"} (Stop + UserPromptSubmit)`);
149
+ lines.push(authLine);
150
+ lines.push("");
151
+ lines.push("Next: restart Claude Code to connect.");
152
+ }
153
+ return lines.join("\n");
154
+ }
155
+ export {
156
+ SETUP_SUPPORTED_RUNTIMES,
157
+ resolvePairCode,
158
+ runSetup
159
+ };
@@ -1,28 +1,27 @@
1
- import "./chunk-XLKGPGZT.js";
2
1
  import {
3
- formatChannelEvents
4
- } from "./chunk-PHXO5P25.js";
2
+ resolveHookDiscovery
3
+ } from "./chunk-WBXU27BF.js";
5
4
  import {
6
5
  readHookStdin
7
6
  } from "./chunk-LSUB6QMP.js";
7
+ import "./chunk-XLKGPGZT.js";
8
8
  import {
9
- monitorHeartbeatPath,
10
- nudgeSentinelPath
11
- } from "./chunk-DURRQDYI.js";
9
+ controlTokenAuthHeaders
10
+ } from "./chunk-GKXHKR3B.js";
12
11
  import {
13
- readSessionDiscoveryByKey
14
- } from "./chunk-DO42NPNR.js";
12
+ formatChannelEvents
13
+ } from "./chunk-PHXO5P25.js";
15
14
  import {
16
- controlTokenAuthHeaders
17
- } from "./chunk-GI2CKKBL.js";
18
- import "./chunk-BLEGIR35.js";
15
+ monitorHeartbeatPath,
16
+ nudgeSentinelPath
17
+ } from "./chunk-TNZITJAB.js";
18
+ import "./chunk-67F67AQ6.js";
19
+ import "./chunk-U5HHHRXA.js";
19
20
  import {
20
21
  buildMonitorNudge
21
- } from "./chunk-Q7T3WAST.js";
22
- import {
23
- deriveDiscoveryKey,
24
- findClaudeAncestorPid
25
- } from "./chunk-VHKPWUX7.js";
22
+ } from "./chunk-QEJUNP3X.js";
23
+ import "./chunk-XJEBJIQE.js";
24
+ import "./chunk-KNEJTD6G.js";
26
25
 
27
26
  // src/hooks/stop-hook.ts
28
27
  import fs from "fs";
@@ -72,10 +71,8 @@ function defaultRecordNudge(logPath) {
72
71
  }
73
72
  }
74
73
  async function runStopHook() {
75
- const { stopHookActive } = await readHookStdin();
76
- const ccPid = await findClaudeAncestorPid();
77
- const key = deriveDiscoveryKey(process.env["CLAUDE_PROJECT_DIR"], ccPid);
78
- const discovery = readSessionDiscoveryByKey(key);
74
+ const { stopHookActive, sessionId: stdinSessionId } = await readHookStdin();
75
+ const { discovery } = await resolveHookDiscovery(stdinSessionId);
79
76
  const out = await decideStopHook({
80
77
  stopHookActive,
81
78
  discovery: discovery ? { port: discovery.port, eventLogPath: discovery.eventLogPath } : null,