kojee-mcp 0.5.19 → 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 (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-U4MNICQI.js → chunk-247WFMCJ.js} +12 -22
  5. package/dist/{chunk-PSVVRGJC.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-74XFVX6Z.js → chunk-FSKGQ6GT.js} +47 -10
  14. package/dist/{chunk-GI2CKKBL.js → chunk-GKXHKR3B.js} +1 -1
  15. package/dist/{wizard-Y3ULSO2C.js → chunk-GVWYW7MY.js} +247 -138
  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-XXFVWP6H.js → chunk-OB5T6P24.js} +1 -1
  21. package/dist/{chunk-65KRRDHP.js → chunk-OBIJ6WQP.js} +82 -27
  22. package/dist/{chunk-DXJ6QLSJ.js → chunk-PKOBR7ZN.js} +1 -1
  23. package/dist/{chunk-2OLXXOT3.js → chunk-PPTKGWFF.js} +69 -3
  24. package/dist/{chunk-X672ZN7V.js → chunk-QEJUNP3X.js} +3 -2
  25. package/dist/chunk-QJFMU4QC.js +33 -0
  26. package/dist/{chunk-EW72ZNQL.js → chunk-RDLF4NQC.js} +1 -1
  27. package/dist/{chunk-XIDCYUTK.js → chunk-SGRVG4HW.js} +9 -4
  28. package/dist/{chunk-DURRQDYI.js → chunk-TNZITJAB.js} +45 -15
  29. package/dist/chunk-U5HHHRXA.js +103 -0
  30. package/dist/chunk-WBXU27BF.js +35 -0
  31. package/dist/chunk-WIU5WGDF.js +10 -0
  32. package/dist/chunk-XJEBJIQE.js +52 -0
  33. package/dist/chunk-Z5LPNJQ6.js +20 -0
  34. package/dist/cli.js +121 -89
  35. package/dist/{chunk-35XBRG3V.js → codex-stop-hook-EOMQD3J4.js} +11 -15
  36. package/dist/connect-handler-HIRM624N.js +137 -0
  37. package/dist/{control-token-4BUCTYQB.js → control-token-KXSZ3GBY.js} +2 -2
  38. package/dist/{doctor-U3MTB4GY.js → doctor-PLKLHTJM.js} +48 -22
  39. package/dist/{doctor-codex-PA3WO6LR.js → doctor-codex-HARAAH4Y.js} +23 -6
  40. package/dist/doctor-openclaw-LL6NSPLC.js +86 -0
  41. package/dist/{event-log-HOBO3ECB.js → event-log-2NBJEIEP.js} +5 -3
  42. package/dist/{event-stream-XX5EZ6HN.js → event-stream-KRYWEYWO.js} +7 -4
  43. package/dist/{hook-server-XK2NHLJV.js → hook-server-CWBH6PFL.js} +2 -2
  44. package/dist/index.js +13 -11
  45. package/dist/{install-LJY2CHKG.js → install-V7LSQCYZ.js} +37 -22
  46. package/dist/{keystore-XLEV3FL5.js → keystore-LQNFDHGO.js} +2 -2
  47. package/dist/lib.d.ts +4 -1
  48. package/dist/lib.js +12 -9
  49. package/dist/pair-HTCVSMR6.js +11 -0
  50. package/dist/{paired-config-JTFLHMZ2.js → paired-config-GUDDO2CH.js} +4 -2
  51. package/dist/{parent-watchdog-TLU355FB.js → parent-watchdog-LTUNF7PD.js} +24 -5
  52. package/dist/{registry-CGLE5X54.js → registry-VRFHKOPP.js} +195 -26
  53. package/dist/resolve-slot-BFIB46Y5.js +13 -0
  54. package/dist/{runtime-record-WO4IECM6.js → runtime-record-OXRLTOLC.js} +2 -2
  55. package/dist/{send-cli-IPADRDD2.js → send-cli-45RLGYIC.js} +24 -12
  56. package/dist/{server-LTFG4GMV.js → server-YTHOMA4H.js} +5 -3
  57. package/dist/{session-discovery-FNMJGFPM.js → session-discovery-NHCZ2XWA.js} +2 -2
  58. package/dist/setup-handler-UHVKSX7E.js +159 -0
  59. package/dist/{stop-hook-QZTFH5WV.js → stop-hook-YI4KRKF2.js} +17 -20
  60. package/dist/{tail-stream-CEJZGSIR.js → tail-stream-NBGHHBS4.js} +61 -22
  61. package/dist/{user-prompt-submit-hook-FQ43NIHC.js → user-prompt-submit-hook-DTXXFDSD.js} +11 -14
  62. package/package.json +2 -1
  63. package/dist/ancestry-ONFBQEP5.js +0 -8
  64. package/dist/chunk-BLEGIR35.js +0 -43
  65. package/dist/chunk-CLKCNV2A.js +0 -100
  66. package/dist/chunk-OGHDTFAX.js +0 -50
  67. package/dist/chunk-VHKPWUX7.js +0 -41
  68. package/dist/codex-stop-hook-VY7DOMAG.js +0 -16
  69. package/dist/doctor-openclaw-SS2TMQOX.js +0 -95
  70. package/dist/pair-P4ILCMT7.js +0 -10
package/dist/cli.js CHANGED
@@ -1,28 +1,30 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runPair
4
- } from "./chunk-OGHDTFAX.js";
4
+ } from "./chunk-EIAUW6KO.js";
5
5
  import {
6
6
  startProxy
7
- } from "./chunk-PSVVRGJC.js";
8
- import "./chunk-XXFVWP6H.js";
7
+ } from "./chunk-5H75AEZ2.js";
8
+ import "./chunk-OB5T6P24.js";
9
9
  import {
10
10
  pairedConfigPath
11
- } from "./chunk-YH27B6SW.js";
12
- import "./chunk-U4MNICQI.js";
13
- import "./chunk-JXMVZEQ7.js";
14
- import "./chunk-NR4Y54OL.js";
11
+ } from "./chunk-5SZHXYPK.js";
12
+ import "./chunk-247WFMCJ.js";
13
+ import "./chunk-I67C2HYA.js";
14
+ import "./chunk-Z5LPNJQ6.js";
15
+ import "./chunk-MIEI4PLB.js";
15
16
  import {
16
17
  defaultPairedKeystorePath,
17
18
  deriveKeystorePath
18
- } from "./chunk-CH32ELFX.js";
19
- import "./chunk-BLEGIR35.js";
19
+ } from "./chunk-6G6YYST6.js";
20
+ import "./chunk-U5HHHRXA.js";
20
21
  import {
21
22
  VERSION
22
- } from "./chunk-XIDCYUTK.js";
23
- import "./chunk-X672ZN7V.js";
24
- import "./chunk-2OLXXOT3.js";
25
- import "./chunk-VHKPWUX7.js";
23
+ } from "./chunk-SGRVG4HW.js";
24
+ import "./chunk-QEJUNP3X.js";
25
+ import "./chunk-PPTKGWFF.js";
26
+ import "./chunk-XJEBJIQE.js";
27
+ import "./chunk-KNEJTD6G.js";
26
28
 
27
29
  // src/cli.ts
28
30
  import { Command } from "commander";
@@ -42,17 +44,30 @@ program.command("pair <code>").description("Pair this machine against Kojee usin
42
44
  process.exit(1);
43
45
  }
44
46
  });
47
+ program.command("connect <code>").description(
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."
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) => {
50
+ const { runConnect } = await import("./connect-handler-HIRM624N.js");
51
+ const result = await runConnect({
52
+ code,
53
+ runtime: opts.runtime,
54
+ ...opts.url ? { url: opts.url } : {}
55
+ });
56
+ for (const m of result.messages) console.error(m);
57
+ console.error(result.output);
58
+ process.exit(result.exitCode);
59
+ });
45
60
  program.command("hook").description("Run a kojee MCP hook script (called by Claude Code via ~/.claude/settings.json)").requiredOption("--type <type>", "Hook type: stop, user-prompt-submit, or codex-stop").action(async (opts) => {
46
61
  if (opts.type === "stop") {
47
- const { runStopHook } = await import("./stop-hook-QZTFH5WV.js");
62
+ const { runStopHook } = await import("./stop-hook-YI4KRKF2.js");
48
63
  await runStopHook();
49
64
  process.exit(0);
50
65
  } else if (opts.type === "user-prompt-submit") {
51
- const { runUserPromptSubmitHook } = await import("./user-prompt-submit-hook-FQ43NIHC.js");
66
+ const { runUserPromptSubmitHook } = await import("./user-prompt-submit-hook-DTXXFDSD.js");
52
67
  await runUserPromptSubmitHook();
53
68
  process.exit(0);
54
69
  } else if (opts.type === "codex-stop") {
55
- const { runCodexStopHook } = await import("./codex-stop-hook-VY7DOMAG.js");
70
+ const { runCodexStopHook } = await import("./codex-stop-hook-EOMQD3J4.js");
56
71
  await runCodexStopHook();
57
72
  process.exit(0);
58
73
  } else {
@@ -61,16 +76,17 @@ program.command("hook").description("Run a kojee MCP hook script (called by Clau
61
76
  }
62
77
  });
63
78
  program.command("install-hooks").description("Install kojee Stop + UserPromptSubmit hooks in ~/.claude/settings.json (idempotent)").option("--hooks-path <path>", "Override default ~/.claude/settings.json").option("--uninstall", "Remove kojee hook entries instead of installing them").action(async (opts) => {
64
- const { installHooks, uninstallHooks } = await import("./install-LJY2CHKG.js");
79
+ const { installHooks, uninstallHooks } = await import("./install-V7LSQCYZ.js");
65
80
  if (opts.uninstall) {
66
81
  const removed = uninstallHooks({ hooksPath: opts.hooksPath });
67
82
  console.error(removed ? "Removed kojee hook entries." : "No kojee hook entries found.");
68
83
  } else {
69
84
  const { stop, ups } = installHooks({ hooksPath: opts.hooksPath });
85
+ const label = (s) => s === "added" ? "\u2713 added" : s === "updated" ? "\u21BB updated" : "\u21BB already installed";
70
86
  console.error(
71
87
  "Installed kojee hooks in " + (opts.hooksPath ?? "~/.claude/settings.json") + `:
72
- - Stop: ${stop === "added" ? "\u2713 added" : "\u21BB already installed"}
73
- - UserPromptSubmit: ${ups === "added" ? "\u2713 added" : "\u21BB already installed"}
88
+ - Stop: ${label(stop)}
89
+ - UserPromptSubmit: ${label(ups)}
74
90
  Restart Claude Code for hooks to take effect.`
75
91
  );
76
92
  }
@@ -78,7 +94,7 @@ Restart Claude Code for hooks to take effect.`
78
94
  program.command("send <tandem_id>").description(
79
95
  "Send a Tandem message using this machine's paired credentials (~/.kojee). Prints one JSON envelope to stdout: {ok, message_id, cursor, text} on success, {ok:false, error:<typed code>, message} on failure (exit 1)."
80
96
  ).requiredOption("--body <text>", "Message body (required)").option("--reply-to <message_id>", "Message id this send replies to").option("--kind <kind>", "Message kind: message | status (default: backend default)").action(async (tandemId, opts) => {
81
- const { runSendCli } = await import("./send-cli-IPADRDD2.js");
97
+ const { runSendCli } = await import("./send-cli-45RLGYIC.js");
82
98
  const { exitCode, envelope } = await runSendCli({
83
99
  tandemId,
84
100
  body: opts.body,
@@ -89,7 +105,7 @@ program.command("send <tandem_id>").description(
89
105
  process.exit(exitCode);
90
106
  });
91
107
  program.command("tail <path>").description("Stream a file's contents and follow appends (portable replacement for `tail -F`)").action(async (filePath) => {
92
- const { runTail } = await import("./tail-stream-CEJZGSIR.js");
108
+ const { runTail } = await import("./tail-stream-NBGHHBS4.js");
93
109
  try {
94
110
  await runTail(filePath);
95
111
  } catch (err) {
@@ -98,75 +114,70 @@ program.command("tail <path>").description("Stream a file's contents and follow
98
114
  }
99
115
  });
100
116
  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 () => {
101
- const { runDoctor } = await import("./doctor-U3MTB4GY.js");
117
+ const { runDoctor } = await import("./doctor-PLKLHTJM.js");
102
118
  const code = await runDoctor();
103
119
  process.exit(code);
104
120
  });
105
- program.command("init").description(
106
- "Set up kojee for a runtime (claude-code | hermes | openclaw | codex). Interactive when stdin is a TTY; `--runtime <id>` for non-interactive/CI. Run after `kojee-mcp pair`."
107
- ).option("--runtime <id>", "Target runtime: claude-code | hermes | openclaw | codex").option("--config-path <path>", "Override the runtime's MCP-config path").option("--hooks-path <path>", "Override the runtime's hooks-file path").option("--token <token>", "Gateway token \u2014 token mode (writes --token/--url into the MCP config)").option("--url <url>", "Broker base URL (token mode / pair URL; default https://rosie-staging.kojee.net)").option("--pair-code <code>", "Pair code \u2014 runs the pair flow (writes ~/.kojee/config.json) before configuring").option("--webhook-url <url>", "Webhook receiver URL (codex/hermes/openclaw)").option("--webhook-secret <secret>", "Webhook HMAC secret (generated if omitted)").option(
108
- "--webhook-signature-format <preset>",
109
- 'Signature preset: "github" = header X-Hub-Signature-256, value sha256=<hex> (default: bare hex in X-Kojee-Signature)'
110
- ).option(
111
- "--webhook-signature-header <name>",
112
- "Signature header name (default X-Kojee-Signature; overrides the preset's header)"
113
- ).option(
114
- "--webhook-signature-prefix <prefix>",
115
- "Literal string prepended to the hex digest (default empty; overrides the preset's prefix)"
116
- ).option("--uninstall", "Remove the kojee config for the chosen (or recorded) runtime").action(async (opts) => {
117
- const interactive = process.stdin.isTTY === true && opts.runtime === void 0;
118
- if (opts.pairCode && !opts.uninstall) {
119
- const { runPair: runPair2 } = await import("./pair-P4ILCMT7.js");
120
- const { pairedConfigPath: pairedConfigPath2 } = await import("./paired-config-JTFLHMZ2.js");
121
- const { defaultPairedKeystorePath: defaultPairedKeystorePath2 } = await import("./keystore-XLEV3FL5.js");
122
- const url = (opts.url ?? "https://rosie-staging.kojee.net").replace(/\/+$/, "");
123
- try {
124
- const r = await runPair2({
125
- code: opts.pairCode,
126
- url,
127
- keystorePath: defaultPairedKeystorePath2(),
128
- configPath: pairedConfigPath2()
129
- });
130
- console.error(r.message);
131
- } catch (err) {
132
- console.error("[kojee-mcp init] Pairing failed:", err.message);
133
- process.exit(1);
134
- }
135
- }
136
- const { loadPairedConfig } = await import("./paired-config-JTFLHMZ2.js");
137
- const hasCredential = loadPairedConfig() !== null || opts.token !== void 0;
138
- if (!hasCredential && !interactive && !opts.uninstall) {
139
- console.error("Not paired. Run `kojee-mcp pair <code> --url <broker>` first, then re-run `init` \u2014 or pass --token/--pair-code, or run `init` in a terminal for the guided wizard.");
140
- process.exit(1);
141
- }
142
- const { runWizard } = await import("./wizard-Y3ULSO2C.js");
143
- const result = await runWizard({
144
- ...opts.runtime !== void 0 ? { runtime: opts.runtime } : {},
145
- ...opts.uninstall ? { uninstall: true } : {},
146
- ...opts.configPath ? { configPath: opts.configPath } : {},
147
- ...opts.hooksPath ? { hooksPath: opts.hooksPath } : {},
148
- // Token-mode threading (token + url ⇒ --token/--url in the written config).
149
- // Normalize the URL exactly like the proxy action does (strip trailing /).
150
- ...opts.token ? { token: opts.token } : {},
151
- ...opts.url ? { url: opts.url.replace(/\/+$/, "") } : {},
152
- ...opts.webhookUrl ? { webhookUrl: opts.webhookUrl } : {},
153
- ...opts.webhookSecret ? { webhookSecret: opts.webhookSecret } : {},
154
- ...opts.webhookSignatureFormat ? { webhookSignatureFormat: opts.webhookSignatureFormat } : {},
155
- ...opts.webhookSignatureHeader ? { webhookSignatureHeader: opts.webhookSignatureHeader } : {},
156
- ...opts.webhookSignaturePrefix !== void 0 ? { webhookSignaturePrefix: opts.webhookSignaturePrefix } : {},
157
- interactive,
158
- ...interactive ? {
159
- promptRuntime: promptRuntimeFromTty,
160
- promptUrl: promptUrlFromTty,
161
- promptAuth: promptAuthFromTty,
162
- promptToken: promptTokenFromTty,
163
- promptPairCode: promptPairCodeFromTty,
164
- promptWebhookUrl: promptWebhookUrlFromTty
165
- } : {}
166
- });
167
- console.error(result.output);
168
- process.exit(result.exitCode);
169
- });
121
+ function addInstallOptions(cmd, runtimeHelp) {
122
+ return cmd.option("--runtime <id>", runtimeHelp).option("--config-path <path>", "Override the runtime's MCP-config path").option("--hooks-path <path>", "Override the runtime's hooks-file path").option("--token <token>", "Gateway token \u2014 token mode (writes --token/--url into the MCP config; requires --url)").option("--url <url>", "Broker base URL (token mode / pair URL; default https://rosie-staging.kojee.net)").option("--pair <code>", "Pair code \u2014 runs the pair flow before configuring (alias of --pair-code)").option("--pair-code <code>", "Pair code \u2014 runs the pair flow before configuring (connect runtimes write ~/.kojee/agents/<runtime>/config.json; hermes/openclaw write ~/.kojee/config.json)").option("--webhook-url <url>", "Webhook receiver URL (codex/hermes/openclaw)").option("--webhook-secret <secret>", "Webhook HMAC secret (generated if omitted)").option(
123
+ "--webhook-signature-format <preset>",
124
+ 'Signature preset: "github" = header X-Hub-Signature-256, value sha256=<hex> (default: bare hex in X-Kojee-Signature)'
125
+ ).option(
126
+ "--webhook-signature-header <name>",
127
+ "Signature header name (default X-Kojee-Signature; overrides the preset's header)"
128
+ ).option(
129
+ "--webhook-signature-prefix <prefix>",
130
+ "Literal string prepended to the hex digest (default empty; overrides the preset's prefix)"
131
+ ).option("--uninstall", "Remove the kojee config for the chosen (or recorded) runtime");
132
+ }
133
+ function makeInstallAction(verb) {
134
+ return async (opts) => {
135
+ const interactive = process.stdin.isTTY === true && opts.runtime === void 0;
136
+ const { runSetup, resolvePairCode } = await import("./setup-handler-UHVKSX7E.js");
137
+ const pairCode = resolvePairCode(opts);
138
+ const result = await runSetup({
139
+ verb,
140
+ ...opts.runtime !== void 0 ? { runtime: opts.runtime } : {},
141
+ ...opts.configPath ? { configPath: opts.configPath } : {},
142
+ ...opts.hooksPath ? { hooksPath: opts.hooksPath } : {},
143
+ ...opts.token ? { token: opts.token } : {},
144
+ ...opts.url ? { url: opts.url } : {},
145
+ ...pairCode ? { pairCode } : {},
146
+ ...opts.webhookUrl ? { webhookUrl: opts.webhookUrl } : {},
147
+ ...opts.webhookSecret ? { webhookSecret: opts.webhookSecret } : {},
148
+ ...opts.webhookSignatureFormat ? { webhookSignatureFormat: opts.webhookSignatureFormat } : {},
149
+ ...opts.webhookSignatureHeader ? { webhookSignatureHeader: opts.webhookSignatureHeader } : {},
150
+ ...opts.webhookSignaturePrefix !== void 0 ? { webhookSignaturePrefix: opts.webhookSignaturePrefix } : {},
151
+ ...opts.uninstall ? { uninstall: true } : {},
152
+ interactive,
153
+ ...interactive ? {
154
+ prompts: {
155
+ promptRuntime: promptRuntimeFromTty,
156
+ promptUrl: promptUrlFromTty,
157
+ promptAuth: promptAuthFromTty,
158
+ promptToken: promptTokenFromTty,
159
+ promptPairCode: promptPairCodeFromTty,
160
+ promptWebhookUrl: promptWebhookUrlFromTty
161
+ }
162
+ } : {}
163
+ });
164
+ for (const m of result.messages) console.error(m);
165
+ console.error(result.output);
166
+ process.exit(result.exitCode);
167
+ };
168
+ }
169
+ addInstallOptions(
170
+ program.command("init").description(
171
+ "Set up kojee for a runtime (claude-code | hermes | openclaw | codex). Interactive when stdin is a TTY; `--runtime <id>` for non-interactive/CI. Run after `kojee-mcp pair`."
172
+ ),
173
+ "Target runtime: claude-code | hermes | openclaw | codex"
174
+ ).action(makeInstallAction("init"));
175
+ addInstallOptions(
176
+ program.command("setup").description(
177
+ "One-line install: pair + write the runtime's MCP config + hooks in one shot (claude-code | codex). `--pair <code> --url <broker> --runtime <id>`, or the token form `--token <T> --url <U> --runtime <id>` for CI."
178
+ ),
179
+ "Target runtime: claude-code | codex"
180
+ ).action(makeInstallAction("setup"));
170
181
  async function withReadline(fn) {
171
182
  const readline = await import("readline/promises");
172
183
  const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
@@ -208,6 +219,9 @@ async function promptWebhookUrlFromTty() {
208
219
  return withReadline((ask) => ask("Webhook receiver URL (press Enter to skip and set it up later):\n> "));
209
220
  }
210
221
  program.option("--token <token>", "Gateway token (for token-mode)").option("--url <url>", "Broker base URL (for token-mode; required if --token is passed)").option(
222
+ "--paired-config <path>",
223
+ "Explicit per-runtime paired config path (written by `connect`)"
224
+ ).option(
211
225
  "--keystore-path <path>",
212
226
  "Path to keypair file (defaults to per-token path under ~/.kojee/)"
213
227
  ).action(async (opts) => {
@@ -216,18 +230,36 @@ program.option("--token <token>", "Gateway token (for token-mode)").option("--ur
216
230
  let keystorePath = opts.keystorePath;
217
231
  const authMode = token ? "token" : "paired";
218
232
  if (token) {
233
+ if (opts.pairedConfig) {
234
+ console.error(
235
+ "[kojee-mcp] both --token and --paired-config given; using --token (the per-runtime paired config is ignored)."
236
+ );
237
+ }
219
238
  if (!url) {
220
239
  console.error("--url is required when --token is provided");
221
240
  process.exit(1);
222
241
  }
223
242
  url = url.replace(/\/+$/, "");
224
243
  keystorePath ??= deriveKeystorePath(token);
244
+ } else if (opts.pairedConfig) {
245
+ const { resolveLaunchCreds } = await import("./resolve-slot-BFIB46Y5.js");
246
+ const resolved = resolveLaunchCreds({
247
+ pairedConfig: opts.pairedConfig,
248
+ ...url ? { url } : {}
249
+ });
250
+ if (!resolved.ok) {
251
+ console.error(resolved.error);
252
+ process.exit(1);
253
+ }
254
+ token = resolved.token;
255
+ url = resolved.url;
256
+ keystorePath = resolved.keystorePath;
225
257
  } else {
226
- const { loadPairedConfig } = await import("./paired-config-JTFLHMZ2.js");
258
+ const { loadPairedConfig } = await import("./paired-config-GUDDO2CH.js");
227
259
  const cfg = loadPairedConfig();
228
260
  if (!cfg) {
229
261
  console.error(
230
- "No --token provided and no ~/.kojee/config.json found. Run `kojee-mcp pair <code> --url <broker>` first."
262
+ "No --token provided and no ~/.kojee/config.json found. Run `kojee-mcp connect <code> --runtime <id>` (or `kojee-mcp pair`) first."
231
263
  );
232
264
  process.exit(1);
233
265
  }
@@ -1,14 +1,15 @@
1
1
  import {
2
2
  readHookStdin
3
3
  } from "./chunk-LSUB6QMP.js";
4
+ import {
5
+ codexPendingMarkerPath
6
+ } from "./chunk-WIU5WGDF.js";
4
7
  import {
5
8
  buildCodexWakeReason
6
- } from "./chunk-X672ZN7V.js";
9
+ } from "./chunk-QEJUNP3X.js";
7
10
 
8
11
  // src/hooks/codex-stop-hook.ts
9
12
  import fs from "fs";
10
- import os from "os";
11
- import path from "path";
12
13
  var CODEX_PEEK_MS = clampPeekMs(
13
14
  Number.parseInt(process.env["KOJEE_CODEX_PEEK_MS"] ?? "150", 10)
14
15
  );
@@ -26,12 +27,8 @@ function decideCodexStopHook(deps) {
26
27
  reason: buildCodexWakeReason(peek.cursor)
27
28
  });
28
29
  }
29
- function codexPendingMarkerPath(sessionId) {
30
- const safe = (sessionId ?? "no-session").replace(/[^A-Za-z0-9._-]/g, "_");
31
- return path.join(os.homedir(), ".kojee", `codex-pending-${safe}`);
32
- }
33
- function defaultPeekPending(sessionId) {
34
- const markerPath = codexPendingMarkerPath(sessionId);
30
+ function defaultPeekPending() {
31
+ const markerPath = codexPendingMarkerPath();
35
32
  try {
36
33
  const st = fs.statSync(markerPath);
37
34
  const ageMs = Date.now() - st.mtimeMs;
@@ -49,12 +46,12 @@ function defaultPeekPending(sessionId) {
49
46
  }
50
47
  }
51
48
  async function runCodexStopHook() {
52
- const { sessionId, stopHookActive } = await readHookStdin();
49
+ const { stopHookActive } = await readHookStdin();
53
50
  const out = decideCodexStopHook({
54
51
  stopHookActive,
55
52
  peekPending: () => {
56
53
  try {
57
- return defaultPeekPending(sessionId);
54
+ return defaultPeekPending();
58
55
  } catch {
59
56
  return { pending: false, cursor: null };
60
57
  }
@@ -63,11 +60,10 @@ async function runCodexStopHook() {
63
60
  process.stdout.write(out);
64
61
  }
65
62
  var CODEX_PEEK_BUDGET_MS = CODEX_PEEK_MS;
66
-
67
63
  export {
68
- decideCodexStopHook,
64
+ CODEX_PEEK_BUDGET_MS,
69
65
  codexPendingMarkerPath,
66
+ decideCodexStopHook,
70
67
  defaultPeekPending,
71
- runCodexStopHook,
72
- CODEX_PEEK_BUDGET_MS
68
+ runCodexStopHook
73
69
  };
@@ -0,0 +1,137 @@
1
+ import {
2
+ DEFAULT_BROKER_URL,
3
+ reconcileConnectPairSlot,
4
+ runWizard
5
+ } from "./chunk-GVWYW7MY.js";
6
+ import "./chunk-E6WMFMM2.js";
7
+ import "./chunk-OBIJ6WQP.js";
8
+ import "./chunk-QJFMU4QC.js";
9
+ import "./chunk-D6JKFJ6A.js";
10
+ import {
11
+ CONNECT_RUNTIMES
12
+ } from "./chunk-EIH2LNF4.js";
13
+ import "./chunk-RDLF4NQC.js";
14
+ import "./chunk-SQL56SEB.js";
15
+ import "./chunk-77HWBSRH.js";
16
+ import "./chunk-V5VZPYMZ.js";
17
+ import {
18
+ runPair
19
+ } from "./chunk-EIAUW6KO.js";
20
+ import {
21
+ loadPairedConfig,
22
+ pairedConfigPath,
23
+ perRuntimeConfigPath
24
+ } from "./chunk-5SZHXYPK.js";
25
+ import "./chunk-I67C2HYA.js";
26
+ import "./chunk-MIEI4PLB.js";
27
+ import {
28
+ defaultPairedKeystorePath,
29
+ deriveKeystorePath
30
+ } from "./chunk-6G6YYST6.js";
31
+ import "./chunk-U5HHHRXA.js";
32
+ import "./chunk-QEJUNP3X.js";
33
+
34
+ // src/wizard/connect-handler.ts
35
+ import os from "os";
36
+ import path from "path";
37
+ function absConfigPath(runtime) {
38
+ const p = path.resolve(perRuntimeConfigPath(runtime));
39
+ if (process.platform === "win32" && !/^[a-zA-Z]:/.test(p)) {
40
+ return path.resolve(path.join(os.homedir(), ".kojee", "agents", runtime, "config.json"));
41
+ }
42
+ return p;
43
+ }
44
+ function identityLabel(cfg) {
45
+ if (cfg?.agent_id && cfg?.principal_id) return `${cfg.agent_id} (${cfg.principal_id})`;
46
+ if (cfg?.agent_id) return cfg.agent_id;
47
+ if (cfg?.principal_id) return cfg.principal_id;
48
+ return "this runtime";
49
+ }
50
+ async function runConnect(opts) {
51
+ if (opts.runtime === "hermes") return runConnectHermes(opts);
52
+ const messages = [];
53
+ const runtime = opts.runtime;
54
+ if (!CONNECT_RUNTIMES.includes(runtime)) {
55
+ return {
56
+ messages,
57
+ output: `\`connect\` supports: ${CONNECT_RUNTIMES.join(", ")}, hermes. Unknown --runtime "${runtime}". (claude-code/codex/openclaw write a per-runtime paired slot; hermes writes the global ~/.kojee/config.json.)`,
58
+ exitCode: 2
59
+ };
60
+ }
61
+ const url = (opts.url ?? DEFAULT_BROKER_URL).replace(/\/+$/, "");
62
+ const configPath = absConfigPath(runtime);
63
+ const oldConfig = loadPairedConfig(configPath);
64
+ const reconcile = reconcileConnectPairSlot(runtime, opts.code);
65
+ if (!reconcile.ok) {
66
+ return { messages, output: reconcile.output, exitCode: reconcile.exitCode };
67
+ }
68
+ messages.push(...reconcile.messages);
69
+ const pair = opts.runPair ?? runPair;
70
+ try {
71
+ const r = await pair({
72
+ code: opts.code,
73
+ url,
74
+ keystorePath: deriveKeystorePath(opts.code),
75
+ configPath,
76
+ runtime,
77
+ allowOverwrite: true
78
+ });
79
+ messages.push(r.message);
80
+ } catch (err) {
81
+ return { messages, output: `Connect failed while pairing: ${err.message}`, exitCode: 1 };
82
+ }
83
+ const wizard = opts.runWizard ?? runWizard;
84
+ const wiz = await wizard({ runtime, pairedConfigPath: configPath, interactive: false });
85
+ if (wiz.exitCode !== 0) {
86
+ return { messages, output: wiz.output, exitCode: wiz.exitCode };
87
+ }
88
+ const newConfig = loadPairedConfig(configPath);
89
+ const newLabel = identityLabel(newConfig);
90
+ const summary = oldConfig ? `\u21BB re-connected ${runtime} as ${newLabel} (was ${identityLabel(oldConfig)})` : `\u2713 connected ${runtime} as ${newLabel} \u2192 ${url}`;
91
+ const output = `${summary}
92
+ Restart ${runtime} to pick up the connection.`;
93
+ return { messages, output, exitCode: 0 };
94
+ }
95
+ async function runConnectHermes(opts) {
96
+ const messages = [];
97
+ const url = (opts.url ?? DEFAULT_BROKER_URL).replace(/\/+$/, "");
98
+ const configPath = pairedConfigPath();
99
+ const oldConfig = loadPairedConfig(configPath);
100
+ const guard = reconcileConnectPairSlot("hermes", opts.code);
101
+ if (!guard.ok) {
102
+ return { messages, output: guard.output, exitCode: guard.exitCode };
103
+ }
104
+ messages.push(...guard.messages);
105
+ const pair = opts.runPair ?? runPair;
106
+ try {
107
+ const r = await pair({
108
+ code: opts.code,
109
+ url,
110
+ keystorePath: defaultPairedKeystorePath(),
111
+ configPath,
112
+ runtime: "hermes",
113
+ allowOverwrite: true
114
+ // connect is idempotent
115
+ });
116
+ messages.push(r.message);
117
+ } catch (err) {
118
+ return { messages, output: `Connect failed while pairing: ${err.message}`, exitCode: 1 };
119
+ }
120
+ const wizard = opts.runWizard ?? runWizard;
121
+ const wiz = await wizard({ runtime: "hermes", interactive: false });
122
+ if (wiz.exitCode !== 0) {
123
+ return { messages, output: wiz.output, exitCode: wiz.exitCode };
124
+ }
125
+ const label = identityLabel(loadPairedConfig(configPath));
126
+ const summary = oldConfig ? `\u21BB re-connected hermes as ${label}` : `\u2713 connected hermes as ${label} \u2192 ${url}`;
127
+ return {
128
+ messages,
129
+ output: `${summary}
130
+ Start (or restart) the hermes daemon to pick up the connection.`,
131
+ exitCode: 0
132
+ };
133
+ }
134
+ export {
135
+ runConnect,
136
+ runConnectHermes
137
+ };
@@ -3,8 +3,8 @@ import {
3
3
  controlTokenPath,
4
4
  issueControlToken,
5
5
  loadControlToken
6
- } from "./chunk-GI2CKKBL.js";
7
- import "./chunk-BLEGIR35.js";
6
+ } from "./chunk-GKXHKR3B.js";
7
+ import "./chunk-U5HHHRXA.js";
8
8
  export {
9
9
  controlTokenAuthHeaders,
10
10
  controlTokenPath,
@@ -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-X672ZN7V.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-PA3WO6LR.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;