kojee-mcp 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +13 -8
  2. package/dist/ancestry-A2F5KQ6A.js +10 -0
  3. package/dist/cc-session-id-RURNIHHC.js +10 -0
  4. package/dist/{chunk-KH5YEJIM.js → chunk-247WFMCJ.js} +7 -20
  5. package/dist/chunk-5DHIUN73.js +25 -0
  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-EBYUJM3H.js +14 -0
  12. package/dist/chunk-EIAUW6KO.js +82 -0
  13. package/dist/chunk-EIH2LNF4.js +45 -0
  14. package/dist/{chunk-BYV7CWNY.js → chunk-FBJCPRVH.js} +22 -9
  15. package/dist/{chunk-XN3IC4B5.js → chunk-FSKGQ6GT.js} +30 -5
  16. package/dist/{chunk-GI2CKKBL.js → chunk-GKXHKR3B.js} +1 -1
  17. package/dist/{chunk-ALZX3SGI.js → chunk-GNLCUJBK.js} +13 -27
  18. package/dist/{chunk-JXMVZEQ7.js → chunk-I67C2HYA.js} +1 -1
  19. package/dist/chunk-KNEJTD6G.js +31 -0
  20. package/dist/{chunk-65KRRDHP.js → chunk-KPMD72FY.js} +94 -28
  21. package/dist/{chunk-NR4Y54OL.js → chunk-MIEI4PLB.js} +1 -19
  22. package/dist/chunk-NE2F5CKS.js +113 -0
  23. package/dist/chunk-QJFMU4QC.js +33 -0
  24. package/dist/{chunk-EW72ZNQL.js → chunk-RDLF4NQC.js} +1 -1
  25. package/dist/{chunk-Q7T3WAST.js → chunk-SSW5AQSR.js} +6 -1
  26. package/dist/{chunk-DURRQDYI.js → chunk-TNZITJAB.js} +45 -15
  27. package/dist/chunk-U5HHHRXA.js +103 -0
  28. package/dist/{setup-handler-7HOFAD7C.js → chunk-UFHGZUST.js} +431 -253
  29. package/dist/{chunk-N35X22G7.js → chunk-UPJV7GBE.js} +1 -1
  30. package/dist/chunk-WBXU27BF.js +35 -0
  31. package/dist/chunk-XJEBJIQE.js +52 -0
  32. package/dist/chunk-Z5LPNJQ6.js +20 -0
  33. package/dist/cli.js +63 -25
  34. package/dist/codex-stop-hook-BMOJVM6O.js +96 -0
  35. package/dist/connect-handler-4DRTFMOB.js +138 -0
  36. package/dist/{control-token-4BUCTYQB.js → control-token-KXSZ3GBY.js} +2 -2
  37. package/dist/{doctor-WVX3WCYX.js → doctor-5QJ3HGNR.js} +48 -22
  38. package/dist/{doctor-codex-Z5M4SFBG.js → doctor-codex-VGJKTX2E.js} +33 -7
  39. package/dist/doctor-openclaw-LL6NSPLC.js +86 -0
  40. package/dist/{event-log-HOBO3ECB.js → event-log-2NBJEIEP.js} +5 -3
  41. package/dist/{event-stream-SYBUJ5EH.js → event-stream-KRYWEYWO.js} +7 -4
  42. package/dist/index.js +13 -10
  43. package/dist/{install-LJY2CHKG.js → install-V7LSQCYZ.js} +37 -22
  44. package/dist/{keystore-XLEV3FL5.js → keystore-LQNFDHGO.js} +2 -2
  45. package/dist/lib.d.ts +4 -1
  46. package/dist/lib.js +11 -8
  47. package/dist/pair-HTCVSMR6.js +11 -0
  48. package/dist/{paired-config-JTFLHMZ2.js → paired-config-GUDDO2CH.js} +4 -2
  49. package/dist/{parent-watchdog-TLU355FB.js → parent-watchdog-LTUNF7PD.js} +24 -5
  50. package/dist/{registry-YLOFZDI2.js → registry-ZZZ26WGA.js} +197 -24
  51. package/dist/resolve-slot-BFIB46Y5.js +13 -0
  52. package/dist/{runtime-record-WO4IECM6.js → runtime-record-OXRLTOLC.js} +2 -2
  53. package/dist/{send-cli-IYJF32PE.js → send-cli-45RLGYIC.js} +22 -10
  54. package/dist/{server-R24AVNTI.js → server-ITPFQVTK.js} +5 -2
  55. package/dist/{session-discovery-FNMJGFPM.js → session-discovery-NHCZ2XWA.js} +2 -2
  56. package/dist/setup-handler-JFM45NCN.js +160 -0
  57. package/dist/{stop-hook-TCPJFGFF.js → stop-hook-5ABGTC2O.js} +17 -20
  58. package/dist/{tail-stream-4IMXI44S.js → tail-stream-NBGHHBS4.js} +40 -22
  59. package/dist/{user-prompt-submit-hook-FQ43NIHC.js → user-prompt-submit-hook-DTXXFDSD.js} +11 -14
  60. package/package.json +3 -2
  61. package/skills/using-tandems/SKILL.md +52 -0
  62. package/dist/ancestry-ONFBQEP5.js +0 -8
  63. package/dist/chunk-BLEGIR35.js +0 -43
  64. package/dist/chunk-CLKCNV2A.js +0 -100
  65. package/dist/chunk-KFDZWNQO.js +0 -73
  66. package/dist/chunk-OGHDTFAX.js +0 -50
  67. package/dist/chunk-VHKPWUX7.js +0 -41
  68. package/dist/codex-stop-hook-RWQSZTST.js +0 -16
  69. package/dist/doctor-openclaw-SS2TMQOX.js +0 -95
  70. package/dist/pair-P4ILCMT7.js +0 -10
@@ -1,11 +1,17 @@
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-EBYUJM3H.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-UPJV7GBE.js";
12
+ import "./chunk-GNLCUJBK.js";
13
+ import "./chunk-5DHIUN73.js";
14
+ import "./chunk-SSW5AQSR.js";
9
15
  import "./chunk-PPTKGWFF.js";
10
16
 
11
17
  // src/delivery/lib/fanout.ts
@@ -36,6 +42,18 @@ async function deliverEvent(event, sinks) {
36
42
  } catch (err) {
37
43
  console.error("[event-stream] webhook enqueue failed:", err);
38
44
  }
45
+ if (sinks.codexPendingMarker) {
46
+ try {
47
+ const pending = sinks.codexPendingMarker(event);
48
+ if (pending && typeof pending.then === "function") {
49
+ pending.catch((err) => {
50
+ console.error("[event-stream] codex pending-marker write failed:", err);
51
+ });
52
+ }
53
+ } catch (err) {
54
+ console.error("[event-stream] codex pending-marker write failed:", err);
55
+ }
56
+ }
39
57
  }
40
58
 
41
59
  // src/delivery/lib/channel.ts
@@ -96,20 +114,27 @@ function createClaudeCodeDelivery() {
96
114
  writeDiscoveryByKey,
97
115
  cleanupDiscoveryByKey,
98
116
  sweepStaleDiscovery
99
- } = await import("./session-discovery-FNMJGFPM.js");
100
- const { startEventLog, sweepStaleEventLogs } = await import("./event-log-HOBO3ECB.js");
117
+ } = await import("./session-discovery-NHCZ2XWA.js");
118
+ const { startEventLog, sweepStaleEventLogs } = await import("./event-log-2NBJEIEP.js");
101
119
  const { resubscribeMemberships } = await import("./resubscribe-G5OGDZJD.js");
102
120
  const { resolveWebhookConfig } = await import("./webhook-config-O4WMQ532.js");
103
121
  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");
122
+ const { startEventStream } = await import("./event-stream-KRYWEYWO.js");
123
+ const { createMcpServer } = await import("./server-ITPFQVTK.js");
124
+ const { deriveDiscoveryKey } = await import("./ancestry-A2F5KQ6A.js");
125
+ const { resolveSharedSessionId } = await import("./cc-session-id-RURNIHHC.js");
107
126
  sweepStaleDiscovery();
108
127
  sweepStaleEventLogs();
109
128
  const projectDir = process.env["CLAUDE_PROJECT_DIR"];
110
- const discoveryKey = deriveDiscoveryKey(projectDir, ctx.ccPid);
129
+ const sessionId = resolveSharedSessionId();
130
+ const discoveryKey = deriveDiscoveryKey(projectDir, ctx.ccPid, sessionId);
111
131
  eventLog = startEventLog({
112
132
  key: ctx.instanceKey,
133
+ // The proxy's OWN discovery key: lets startEventLog reclaim the STABLE
134
+ // base log path on an in-session reconnect (env-switch / /mcp reconnect;
135
+ // unchanged ccPid → unchanged discovery key) instead of salting and
136
+ // stranding the agent's already-running Monitor on the dead base log.
137
+ selfKey: discoveryKey,
113
138
  ...ctx.eventLogDir ? { dir: ctx.eventLogDir } : {}
114
139
  });
115
140
  const log = eventLog;
@@ -142,7 +167,7 @@ function createClaudeCodeDelivery() {
142
167
  eventLog.path,
143
168
  ctx.toolCallHooks
144
169
  );
145
- const { issueControlToken, controlTokenPath } = await import("./control-token-4BUCTYQB.js");
170
+ const { issueControlToken, controlTokenPath } = await import("./control-token-KXSZ3GBY.js");
146
171
  let controlToken = null;
147
172
  try {
148
173
  controlToken = issueControlToken();
@@ -174,7 +199,7 @@ function createClaudeCodeDelivery() {
174
199
  staleAfterMs: null
175
200
  }
176
201
  });
177
- writeDiscoveryByKey(discoveryKey, {
202
+ const discoveryEntry = {
178
203
  schema: 2,
179
204
  discoveryKey,
180
205
  ccPid: ctx.ccPid,
@@ -187,8 +212,18 @@ function createClaudeCodeDelivery() {
187
212
  eventLogPath: eventLog.path,
188
213
  ...controlToken !== null ? { controlTokenPath: controlTokenPath() } : {},
189
214
  authMode: ctx.config.authMode ?? "paired"
190
- });
191
- cleanupDiscoveryFile = () => cleanupDiscoveryByKey(discoveryKey);
215
+ };
216
+ writeDiscoveryByKey(discoveryKey, discoveryEntry);
217
+ const aliasKey = sessionId && ctx.ccPid !== null ? deriveDiscoveryKey(projectDir, ctx.ccPid, null) : null;
218
+ if (aliasKey !== null && aliasKey !== discoveryKey) {
219
+ writeDiscoveryByKey(aliasKey, { ...discoveryEntry, discoveryKey: aliasKey });
220
+ }
221
+ cleanupDiscoveryFile = () => {
222
+ cleanupDiscoveryByKey(discoveryKey);
223
+ if (aliasKey !== null && aliasKey !== discoveryKey) {
224
+ cleanupDiscoveryByKey(aliasKey);
225
+ }
226
+ };
192
227
  const localCleanupDiscovery = cleanupDiscoveryFile;
193
228
  const localHookServer = hookServer;
194
229
  const localLiveliness = liveliness;
@@ -267,19 +302,19 @@ function createClaudeCodeDelivery() {
267
302
  }
268
303
 
269
304
  // src/delivery/hermes.ts
270
- function createWebhookDelivery(name) {
305
+ function createWebhookDelivery(name, codexPendingMarker) {
271
306
  let eventLog = null;
272
307
  let webhookSink = null;
273
308
  let streamHandle = null;
274
309
  return {
275
310
  name,
276
311
  async start(ctx) {
277
- const { startEventLog, sweepStaleEventLogs } = await import("./event-log-HOBO3ECB.js");
312
+ const { startEventLog, sweepStaleEventLogs } = await import("./event-log-2NBJEIEP.js");
278
313
  const { resolveWebhookConfig } = await import("./webhook-config-O4WMQ532.js");
279
314
  const { createWebhookSink } = await import("./webhook-sink-N6AUTFL3.js");
280
315
  const { resubscribeMemberships } = await import("./resubscribe-G5OGDZJD.js");
281
- const { startEventStream } = await import("./event-stream-SYBUJ5EH.js");
282
- const { createMcpServer } = await import("./server-R24AVNTI.js");
316
+ const { startEventStream } = await import("./event-stream-KRYWEYWO.js");
317
+ const { createMcpServer } = await import("./server-ITPFQVTK.js");
283
318
  sweepStaleEventLogs();
284
319
  eventLog = startEventLog({
285
320
  key: ctx.instanceKey,
@@ -348,7 +383,9 @@ function createWebhookDelivery(name) {
348
383
  async deliver(event) {
349
384
  await deliverEvent(event, {
350
385
  ...eventLog ? { eventLog } : {},
351
- ...webhookSink ? { webhookSink } : {}
386
+ ...webhookSink ? { webhookSink } : {},
387
+ // OPTIONAL codex-only marker sink (undefined ⇒ byte-identical hermes path).
388
+ ...codexPendingMarker ? { codexPendingMarker } : {}
352
389
  });
353
390
  },
354
391
  async stop() {
@@ -365,9 +402,142 @@ function createWebhookDelivery(name) {
365
402
  };
366
403
  }
367
404
 
405
+ // src/delivery/codex-pending-marker.ts
406
+ import fsp from "fs/promises";
407
+ import path from "path";
408
+ import crypto from "crypto";
409
+ var MAX_MARKER_BODY_CHARS = 128;
410
+ var ensuredDir = null;
411
+ async function writeCodexPendingMarker(event) {
412
+ if (!Number.isFinite(event.cursor) || event.cursor < 1) return;
413
+ const markerPath = codexPendingMarkerPath();
414
+ const dir = path.dirname(markerPath);
415
+ const tmp = `${markerPath}.tmp-${process.pid}-${crypto.randomUUID()}`;
416
+ try {
417
+ if (ensuredDir !== dir) {
418
+ await fsp.mkdir(dir, { recursive: true });
419
+ ensuredDir = dir;
420
+ }
421
+ const tandem = String(event.tandem_id ?? "").replace(/\s+/g, "");
422
+ const cursorTok = String(Math.floor(event.cursor));
423
+ const body = (tandem ? `${cursorTok} ${tandem}` : cursorTok).slice(0, MAX_MARKER_BODY_CHARS);
424
+ await fsp.writeFile(tmp, body, { mode: 384 });
425
+ await fsp.rename(tmp, markerPath);
426
+ } catch {
427
+ ensuredDir = null;
428
+ try {
429
+ await fsp.unlink(tmp);
430
+ } catch {
431
+ }
432
+ }
433
+ }
434
+
368
435
  // src/delivery/codex.ts
369
436
  function createCodexDelivery() {
370
- return createWebhookDelivery("codex");
437
+ return createWebhookDelivery("codex", writeCodexPendingMarker);
438
+ }
439
+
440
+ // src/delivery/openclaw.ts
441
+ function formatOpenclawNudge(event) {
442
+ const who = event.from?.member_id ?? "someone";
443
+ const body = (event.content?.body ?? "").replace(/\s+/g, " ").slice(0, 160);
444
+ return `New Kojee Tandem activity in ${event.tandem_id} from ${who}: "${body}". Catch up with tandem_messages / tandem_listen and reply via tandem_send.`;
445
+ }
446
+ function createOpenclawDelivery(deps = {}) {
447
+ const resolveTarget = deps.resolveTarget ?? createCachedOpenclawWakeResolver();
448
+ const postWake = deps.postWake ?? postOpenclawWake;
449
+ let eventLog = null;
450
+ let streamHandle = null;
451
+ let warnedUnconfigured = false;
452
+ return {
453
+ name: "openclaw",
454
+ async start(ctx) {
455
+ const { startEventLog, sweepStaleEventLogs } = await import("./event-log-2NBJEIEP.js");
456
+ const { resubscribeMemberships } = await import("./resubscribe-G5OGDZJD.js");
457
+ const { startEventStream } = await import("./event-stream-KRYWEYWO.js");
458
+ const { createMcpServer } = await import("./server-ITPFQVTK.js");
459
+ sweepStaleEventLogs();
460
+ eventLog = startEventLog({
461
+ key: ctx.instanceKey,
462
+ ...ctx.eventLogDir ? { dir: ctx.eventLogDir } : {}
463
+ });
464
+ const log = eventLog;
465
+ const initial = await resolveTarget();
466
+ void log.appendStatus(
467
+ `status=openclaw-wake ${initial.ok ? `target=${initial.target.url}` : `error="${initial.reason}"`}`
468
+ ).catch(() => {
469
+ });
470
+ const server = createMcpServer(
471
+ ctx.registry,
472
+ ctx.adapter,
473
+ ctx.tandemMembershipCount,
474
+ void 0,
475
+ ctx.toolCallHooks
476
+ );
477
+ const teardown = [() => eventLog?.cleanup()];
478
+ streamHandle = await startEventStream({
479
+ brokerUrl: ctx.config.url,
480
+ token: ctx.config.token,
481
+ gateway: ctx.gateway,
482
+ adapter: ctx.adapter,
483
+ server,
484
+ eventLog,
485
+ delivery: this,
486
+ onConnected: /* @__PURE__ */ (() => {
487
+ const debounceState = { lastRunAt: 0 };
488
+ return async () => {
489
+ await resubscribeMemberships({
490
+ gateway: ctx.gateway,
491
+ eventLog,
492
+ listTandems: async () => await ctx.listTandemIds() ?? [],
493
+ debounceState
494
+ });
495
+ };
496
+ })()
497
+ });
498
+ ctx.onStreamReady?.(streamHandle);
499
+ return { server, teardown, exitCleanup: () => eventLog?.cleanup() };
500
+ },
501
+ // Event-log append FIRST (survival/observability parity with hermes; the
502
+ // Monitor's PRIMARY wake path, so it is AWAITED like fanout's eventLog sink).
503
+ // The /wake POST is FIRE-AND-FORGET: it is network I/O with a 4s timeout and
504
+ // must NOT be awaited on the shared consumeSse loop — a gateway that accepts
505
+ // TCP but hangs would otherwise backpressure the single interleaved stream
506
+ // for every room (hermes/codex enqueue their network/disk sinks the same way,
507
+ // fanout.ts). Target RESOLUTION rides the same detached chain (F5): it is
508
+ // disk I/O (openclaw.json read — async + mtime-cached by the default
509
+ // resolver), and a stalled home dir (NFS, AV scan, full disk) must never
510
+ // block the reader loop that multiplexes tool-call proxying for every room.
511
+ async deliver(event) {
512
+ try {
513
+ await eventLog?.append(event);
514
+ } catch (err) {
515
+ console.error("[openclaw] event-log append failed:", err);
516
+ }
517
+ void (async () => {
518
+ const r = await resolveTarget();
519
+ if (!r.ok) {
520
+ if (!warnedUnconfigured) {
521
+ warnedUnconfigured = true;
522
+ console.error(`[openclaw] wake skipped: ${r.reason}`);
523
+ }
524
+ return;
525
+ }
526
+ warnedUnconfigured = false;
527
+ const res = await postWake(r.target, { text: formatOpenclawNudge(event), mode: "now" });
528
+ if (!res.ok) console.error(`[openclaw] wake POST failed: ${res.error ?? res.status}`);
529
+ })().catch((err) => {
530
+ console.error("[openclaw] wake delivery failed:", err);
531
+ });
532
+ },
533
+ async stop() {
534
+ eventLog?.cleanup();
535
+ },
536
+ health() {
537
+ const s = streamHandle?.getState();
538
+ return { connected: s ? s.connected ?? null : null, ...s ? { detail: { stream: s } } : {} };
539
+ }
540
+ };
371
541
  }
372
542
 
373
543
  // src/delivery/registry.ts
@@ -378,12 +548,15 @@ function selectDelivery(runtime, opts) {
378
548
  if (opts.supportsChannels) {
379
549
  return createClaudeCodeDelivery();
380
550
  }
381
- if (!needsWebhookEventStream(opts.env)) {
382
- return null;
383
- }
384
551
  if (runtime === "codex") {
385
552
  return createCodexDelivery();
386
553
  }
554
+ if (runtime === "openclaw") {
555
+ return createOpenclawDelivery();
556
+ }
557
+ if (!needsWebhookEventStream(opts.env)) {
558
+ return null;
559
+ }
387
560
  return createWebhookDelivery(runtime);
388
561
  }
389
562
  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,16 @@
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-GNLCUJBK.js";
8
+ import "./chunk-5DHIUN73.js";
9
+ import "./chunk-SSW5AQSR.js";
8
10
  import "./chunk-PPTKGWFF.js";
9
11
  export {
10
12
  buildChannelInstructions,
13
+ buildNonChannelInstructions,
11
14
  createMcpServer,
12
15
  executeToolCall,
13
16
  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,160 @@
1
+ import {
2
+ DEFAULT_BROKER_URL,
3
+ pairSlotFor,
4
+ reconcileConnectPairSlot,
5
+ runWizard
6
+ } from "./chunk-UFHGZUST.js";
7
+ import "./chunk-E6WMFMM2.js";
8
+ import "./chunk-KPMD72FY.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-5DHIUN73.js";
29
+ import "./chunk-SSW5AQSR.js";
30
+
31
+ // src/wizard/setup-handler.ts
32
+ var SETUP_SUPPORTED_RUNTIMES = ["claude-code", "codex"];
33
+ function isSetupRuntime(value) {
34
+ return SETUP_SUPPORTED_RUNTIMES.includes(value);
35
+ }
36
+ function resolvePairCode(opts) {
37
+ return opts.pair ?? opts.pairCode;
38
+ }
39
+ async function runSetup(opts) {
40
+ const messages = [];
41
+ const requested = opts.runtime ?? "claude-code";
42
+ if (opts.verb === "setup" && opts.runtime !== void 0 && !isSetupRuntime(opts.runtime)) {
43
+ const supported = SETUP_SUPPORTED_RUNTIMES.join(", ");
44
+ 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\`.)`;
45
+ return { runtime: requested, messages, output, exitCode: 2 };
46
+ }
47
+ if (opts.token !== void 0 && (opts.url === void 0 || opts.url.trim() === "") && !opts.uninstall) {
48
+ return {
49
+ runtime: requested,
50
+ messages,
51
+ output: "--token requires --url (the broker URL the Kojee UI gave you). Re-run with --url <broker-url>. Nothing was written.",
52
+ exitCode: 2
53
+ };
54
+ }
55
+ const url = opts.url ? opts.url.replace(/\/+$/, "") : void 0;
56
+ if (opts.pairCode && !opts.uninstall && opts.interactive && opts.runtime === void 0) {
57
+ return {
58
+ runtime: requested,
59
+ messages,
60
+ 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>.",
61
+ exitCode: 2
62
+ };
63
+ }
64
+ let justPaired = false;
65
+ let pairedConfigLauncher;
66
+ if (opts.pairCode && !opts.uninstall) {
67
+ const pair = opts.runPair ?? runPair;
68
+ const pairUrl = url ?? DEFAULT_BROKER_URL;
69
+ const reconcile = reconcileConnectPairSlot(requested, opts.pairCode);
70
+ if (!reconcile.ok) {
71
+ return { runtime: requested, messages, output: reconcile.output, exitCode: reconcile.exitCode };
72
+ }
73
+ messages.push(...reconcile.messages);
74
+ const slot = pairSlotFor(requested, opts.pairCode);
75
+ try {
76
+ const r = await pair({
77
+ code: opts.pairCode,
78
+ url: pairUrl,
79
+ keystorePath: slot.keystorePath,
80
+ configPath: slot.configPath,
81
+ ...slot.runtime ? { runtime: slot.runtime } : {},
82
+ ...slot.allowOverwrite ? { allowOverwrite: true } : {}
83
+ });
84
+ messages.push(r.message);
85
+ justPaired = true;
86
+ pairedConfigLauncher = slot.pairedConfigPath;
87
+ } catch (err) {
88
+ return {
89
+ runtime: requested,
90
+ messages,
91
+ output: `Pairing failed: ${err.message}`,
92
+ exitCode: 1
93
+ };
94
+ }
95
+ }
96
+ const loadCfg = opts.loadPairedConfig ?? loadPairedConfig;
97
+ const hasCredential = justPaired || loadCfg() !== null || opts.token !== void 0;
98
+ if (!hasCredential && !opts.interactive && !opts.uninstall) {
99
+ return {
100
+ runtime: requested,
101
+ messages,
102
+ 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.",
103
+ exitCode: 1
104
+ };
105
+ }
106
+ const result = await runWizard({
107
+ ...opts.runtime !== void 0 ? { runtime: opts.runtime } : {},
108
+ ...opts.uninstall ? { uninstall: true } : {},
109
+ ...opts.configPath ? { configPath: opts.configPath } : {},
110
+ ...opts.hooksPath ? { hooksPath: opts.hooksPath } : {},
111
+ // Token mode (token + url) threads --token/--url into the written config.
112
+ ...opts.token ? { token: opts.token } : {},
113
+ ...url ? { url } : {},
114
+ // connect-runtime pair-mode: point the launcher at the per-runtime slot so
115
+ // the launched proxy reads it (its default branch reads only the global slot).
116
+ ...pairedConfigLauncher ? { pairedConfigPath: pairedConfigLauncher } : {},
117
+ ...opts.webhookUrl ? { webhookUrl: opts.webhookUrl } : {},
118
+ ...opts.webhookSecret ? { webhookSecret: opts.webhookSecret } : {},
119
+ ...opts.webhookSignatureFormat ? { webhookSignatureFormat: opts.webhookSignatureFormat } : {},
120
+ ...opts.webhookSignatureHeader ? { webhookSignatureHeader: opts.webhookSignatureHeader } : {},
121
+ ...opts.webhookSignaturePrefix !== void 0 ? { webhookSignaturePrefix: opts.webhookSignaturePrefix } : {},
122
+ interactive: opts.interactive,
123
+ ...opts.interactive && opts.prompts ? opts.prompts : {}
124
+ });
125
+ if (opts.verb === "setup" && result.exitCode === 0 && !opts.uninstall) {
126
+ return {
127
+ runtime: result.runtime,
128
+ messages,
129
+ output: crispSetupSummary(result.runtime, opts, url),
130
+ exitCode: 0
131
+ };
132
+ }
133
+ return { runtime: result.runtime, messages, output: result.output, exitCode: result.exitCode };
134
+ }
135
+ function crispSetupSummary(runtime, opts, url) {
136
+ const pairedSlotLabel = isSetupRuntime(runtime) ? `~/.kojee/agents/${runtime}/config.json` : "~/.kojee/config.json";
137
+ const authLine = opts.token ? ` Auth: token mode (--token/--url${url ? `, ${url}` : ""})` : ` Auth: paired credentials (${pairedSlotLabel})`;
138
+ const lines = [];
139
+ if (runtime === "codex") {
140
+ lines.push("\u2713 kojee is set up for Codex.");
141
+ lines.push(` MCP config: ${opts.configPath ?? "~/.codex/config.toml"} ([mcp_servers.kojee])`);
142
+ lines.push(` Stop hook: ${opts.hooksPath ?? "~/.codex/hooks.json"} (codex-stop)`);
143
+ lines.push(authLine);
144
+ lines.push("");
145
+ lines.push("Next: restart Codex to connect.");
146
+ } else {
147
+ lines.push("\u2713 kojee is set up for Claude Code.");
148
+ lines.push(` MCP config: ${opts.configPath ?? "~/.claude.json"} (mcpServers.kojee)`);
149
+ lines.push(` Hooks: ${opts.hooksPath ?? "~/.claude/settings.json"} (Stop + UserPromptSubmit)`);
150
+ lines.push(authLine);
151
+ lines.push("");
152
+ lines.push("Next: restart Claude Code to connect.");
153
+ }
154
+ return lines.join("\n");
155
+ }
156
+ export {
157
+ SETUP_SUPPORTED_RUNTIMES,
158
+ resolvePairCode,
159
+ runSetup
160
+ };
@@ -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-SSW5AQSR.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,