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
@@ -1,15 +1,17 @@
1
1
  import {
2
2
  defaultCodexConfigPath,
3
3
  defaultCodexHooksPath
4
- } from "./chunk-65KRRDHP.js";
4
+ } from "./chunk-OBIJ6WQP.js";
5
+ import "./chunk-QJFMU4QC.js";
6
+ import "./chunk-D6JKFJ6A.js";
5
7
  import "./chunk-SQL56SEB.js";
6
8
  import {
7
9
  resolveWebhookConfig
8
10
  } from "./chunk-V5VZPYMZ.js";
9
- import "./chunk-BLEGIR35.js";
11
+ import "./chunk-U5HHHRXA.js";
10
12
  import {
11
13
  CODEX_LISTEN_CAP_MS
12
- } from "./chunk-X672ZN7V.js";
14
+ } from "./chunk-QEJUNP3X.js";
13
15
 
14
16
  // src/doctor-codex.ts
15
17
  import fs from "fs";
@@ -39,6 +41,10 @@ function parseCodexEnvFromToml(toml) {
39
41
  return env;
40
42
  }
41
43
  var WIZARD_RERUN = "re-run `kojee-mcp init --runtime codex`";
44
+ function extractPairedConfigPath(toml) {
45
+ const m = toml.match(/args\s*=\s*\[[^\]]*"--paired-config"\s*,\s*"([^"]+)"/);
46
+ return m ? m[1].replace(/\\\\/g, "\\") : null;
47
+ }
42
48
  function defaultReadFile(path) {
43
49
  return () => {
44
50
  try {
@@ -100,8 +106,17 @@ function collectCodexDoctorReport(deps = {}) {
100
106
  } else {
101
107
  checks.push({
102
108
  name: "webhook sink",
103
- ok: false,
104
- detail: `not configured (no KOJEE_WEBHOOK_URL) \u2014 ${WIZARD_RERUN}`
109
+ ok: true,
110
+ detail: "optional \u2014 OFF (no KOJEE_WEBHOOK_URL). Codex wake is self-contained: the proxy refreshes the stop-hook pending marker on every event. Configure a receiver only for an extra low-latency push path."
111
+ });
112
+ }
113
+ const pairedPath = extractPairedConfigPath(toml);
114
+ if (pairedPath) {
115
+ const present = fs.existsSync(pairedPath);
116
+ checks.push({
117
+ name: "paired-config slot",
118
+ ok: present,
119
+ detail: present ? `present \u2014 proxy launches with --paired-config ${pairedPath}` : `MISSING referenced config ${pairedPath} \u2014 re-run \`kojee-mcp connect <code> --runtime codex\``
105
120
  });
106
121
  }
107
122
  if (deps.pingReceiver) {
@@ -120,7 +135,9 @@ function formatCodexDoctorReport(report) {
120
135
  const lines = [];
121
136
  lines.push(`kojee-mcp doctor (codex) \u2014 verdict: ${report.verdict.toUpperCase()}`);
122
137
  lines.push("");
123
- lines.push(" Wake mode: webhook-sink + stop-hook peek (Codex has no channel injection).");
138
+ lines.push(
139
+ " Wake mode: self-contained (proxy-written pending marker) + stop-hook peek (Codex has no channel injection). Webhook OPTIONAL, never required."
140
+ );
124
141
  lines.push(` Bounded-listen cap: ${CODEX_LISTEN_CAP_MS}ms (model picks listen vs drain vs ignore).`);
125
142
  lines.push("");
126
143
  for (const c of report.checks) {
@@ -0,0 +1,86 @@
1
+ import {
2
+ MCP_SERVER_NAME,
3
+ defaultOpenclawConfigPath
4
+ } from "./chunk-E6WMFMM2.js";
5
+ import "./chunk-D6JKFJ6A.js";
6
+ import {
7
+ resolveOpenclawWakeTarget
8
+ } from "./chunk-NE2F5CKS.js";
9
+ import "./chunk-SQL56SEB.js";
10
+ import {
11
+ loadPairedConfig,
12
+ pairedConfigPath,
13
+ perRuntimeConfigPath
14
+ } from "./chunk-5SZHXYPK.js";
15
+ import "./chunk-U5HHHRXA.js";
16
+
17
+ // src/doctor-openclaw.ts
18
+ import fs from "fs";
19
+ var WIZARD_RERUN = "re-run `kojee-mcp connect <code> --runtime openclaw`";
20
+ function readOpenclawConfig() {
21
+ try {
22
+ const parsed = JSON.parse(fs.readFileSync(defaultOpenclawConfigPath(), "utf8"));
23
+ return parsed && typeof parsed === "object" ? parsed : {};
24
+ } catch {
25
+ return {};
26
+ }
27
+ }
28
+ function loadOpenclawPaired() {
29
+ const perRuntime = loadPairedConfig(perRuntimeConfigPath("openclaw"));
30
+ if (perRuntime?.token) return { config: perRuntime, source: "per-runtime" };
31
+ const global = loadPairedConfig(pairedConfigPath());
32
+ if (global?.token) return { config: global, source: "global" };
33
+ return null;
34
+ }
35
+ function collectOpenclawDoctorReport(deps = {}) {
36
+ const readConfig = deps.readConfig ?? readOpenclawConfig;
37
+ const resolveWake = deps.resolveWake ?? (() => resolveOpenclawWakeTarget());
38
+ const loadPaired = deps.loadPaired ?? loadOpenclawPaired;
39
+ const checks = [];
40
+ const cfg = readConfig();
41
+ const mcp = cfg.mcp && typeof cfg.mcp === "object" ? cfg.mcp : {};
42
+ const servers = mcp.servers && typeof mcp.servers === "object" ? mcp.servers : {};
43
+ const server = servers[MCP_SERVER_NAME] && typeof servers[MCP_SERVER_NAME] === "object" ? servers[MCP_SERVER_NAME] : null;
44
+ const args = server && Array.isArray(server.args) ? server.args : [];
45
+ const pairedConfigThreaded = args.includes("--paired-config");
46
+ checks.push({
47
+ name: `~/.openclaw/openclaw.json mcp.servers.${MCP_SERVER_NAME}`,
48
+ ok: server !== null,
49
+ detail: server ? pairedConfigThreaded ? "present \u2014 OpenClaw spawns kojee-mcp with --paired-config (per-runtime slot)" : "present (WARN: no --paired-config in args \u2014 the proxy will use the global slot)" : `MISSING mcp.servers.${MCP_SERVER_NAME} block \u2014 ${WIZARD_RERUN}`
50
+ });
51
+ const wake = resolveWake();
52
+ checks.push({
53
+ name: "hooks wake receiver",
54
+ ok: wake.ok,
55
+ detail: wake.ok ? `mounted \u2014 /wake target: ${wake.target.url} (Bearer hooks.token; token value never printed)` : `${wake.reason} \u2014 ${WIZARD_RERUN}`
56
+ });
57
+ const paired = loadPaired();
58
+ checks.push({
59
+ name: "gateway credential",
60
+ ok: paired !== null,
61
+ detail: paired ? `resolves \u2014 source: ${paired.source} paired slot (token value never printed)` : `NONE resolves (no ~/.kojee/agents/openclaw/config.json or ~/.kojee/config.json token) \u2014 ${WIZARD_RERUN}`
62
+ });
63
+ const verdict = checks.some((c) => c.ok === false) ? "broken" : checks.some((c) => c.ok === "warn") ? "degraded" : "healthy";
64
+ return { checks, verdict };
65
+ }
66
+ function formatOpenclawDoctorReport(report) {
67
+ const mark = (ok) => ok === true ? "\u2713" : ok === "warn" ? "\u26A0" : ok === "unknown" ? "?" : "\u2717";
68
+ const lines = [];
69
+ lines.push(`kojee-mcp doctor (openclaw) \u2014 verdict: ${report.verdict.toUpperCase()}`);
70
+ lines.push("");
71
+ lines.push(" Wake mode: OpenClaw MCP server + /hooks/wake injector.");
72
+ lines.push(" OpenClaw spawns kojee-mcp (mcp.servers.kojee); wakes arrive via POST <gateway>/hooks/wake.");
73
+ lines.push("");
74
+ for (const c of report.checks) {
75
+ lines.push(` ${mark(c.ok)} ${c.name}: ${c.detail}`);
76
+ }
77
+ lines.push("");
78
+ lines.push(
79
+ "NOTE: live verification (gateway running, proxy spawned) is an owner step \u2014 start the OpenClaw gateway and send a Tandem message."
80
+ );
81
+ return lines.join("\n");
82
+ }
83
+ export {
84
+ collectOpenclawDoctorReport,
85
+ formatOpenclawDoctorReport
86
+ };
@@ -2,16 +2,18 @@ import {
2
2
  STATUS_LINE_PREFIX,
3
3
  monitorHeartbeatPath,
4
4
  nudgeSentinelPath,
5
+ resolveEventLogPath,
5
6
  startEventLog,
6
7
  statusLogPath,
7
8
  sweepStaleEventLogs
8
- } from "./chunk-DURRQDYI.js";
9
- import "./chunk-DO42NPNR.js";
10
- import "./chunk-BLEGIR35.js";
9
+ } from "./chunk-TNZITJAB.js";
10
+ import "./chunk-67F67AQ6.js";
11
+ import "./chunk-U5HHHRXA.js";
11
12
  export {
12
13
  STATUS_LINE_PREFIX,
13
14
  monitorHeartbeatPath,
14
15
  nudgeSentinelPath,
16
+ resolveEventLogPath,
15
17
  startEventLog,
16
18
  statusLogPath,
17
19
  sweepStaleEventLogs
@@ -5,9 +5,11 @@ import {
5
5
  normalizeBackendEvent,
6
6
  sanitizeDisplayname,
7
7
  serializeCursorMap,
8
- startEventStream
9
- } from "./chunk-74XFVX6Z.js";
10
- import "./chunk-NR4Y54OL.js";
8
+ startEventStream,
9
+ statusReason
10
+ } from "./chunk-FSKGQ6GT.js";
11
+ import "./chunk-Z5LPNJQ6.js";
12
+ import "./chunk-MIEI4PLB.js";
11
13
  export {
12
14
  UNDICI_DEFAULT_BODY_TIMEOUT_MS,
13
15
  createAdaptiveWatchdog,
@@ -15,5 +17,6 @@ export {
15
17
  normalizeBackendEvent,
16
18
  sanitizeDisplayname,
17
19
  serializeCursorMap,
18
- startEventStream
20
+ startEventStream,
21
+ statusReason
19
22
  };
@@ -3,8 +3,8 @@ import {
3
3
  httpStatusForEnvelope,
4
4
  parseSendRequest,
5
5
  sendFailure
6
- } from "./chunk-DXJ6QLSJ.js";
7
- import "./chunk-2OLXXOT3.js";
6
+ } from "./chunk-PKOBR7ZN.js";
7
+ import "./chunk-PPTKGWFF.js";
8
8
 
9
9
  // src/tandem/hook-server.ts
10
10
  import crypto from "crypto";
package/dist/index.js CHANGED
@@ -1,17 +1,19 @@
1
1
  import {
2
2
  listTandemIds,
3
3
  startProxy
4
- } from "./chunk-PSVVRGJC.js";
5
- import "./chunk-XXFVWP6H.js";
6
- import "./chunk-U4MNICQI.js";
7
- import "./chunk-JXMVZEQ7.js";
8
- import "./chunk-NR4Y54OL.js";
9
- import "./chunk-CH32ELFX.js";
10
- import "./chunk-BLEGIR35.js";
11
- import "./chunk-XIDCYUTK.js";
12
- import "./chunk-X672ZN7V.js";
13
- import "./chunk-2OLXXOT3.js";
14
- import "./chunk-VHKPWUX7.js";
4
+ } from "./chunk-5H75AEZ2.js";
5
+ import "./chunk-OB5T6P24.js";
6
+ import "./chunk-247WFMCJ.js";
7
+ import "./chunk-I67C2HYA.js";
8
+ import "./chunk-Z5LPNJQ6.js";
9
+ import "./chunk-MIEI4PLB.js";
10
+ import "./chunk-6G6YYST6.js";
11
+ import "./chunk-U5HHHRXA.js";
12
+ import "./chunk-SGRVG4HW.js";
13
+ import "./chunk-QEJUNP3X.js";
14
+ import "./chunk-PPTKGWFF.js";
15
+ import "./chunk-XJEBJIQE.js";
16
+ import "./chunk-KNEJTD6G.js";
15
17
  export {
16
18
  listTandemIds,
17
19
  startProxy
@@ -1,6 +1,13 @@
1
+ import {
2
+ buildHookCommand,
3
+ isKojeeHookCommand
4
+ } from "./chunk-QJFMU4QC.js";
5
+ import {
6
+ wrapNpxLauncher
7
+ } from "./chunk-D6JKFJ6A.js";
1
8
  import {
2
9
  secureFile
3
- } from "./chunk-BLEGIR35.js";
10
+ } from "./chunk-U5HHHRXA.js";
4
11
 
5
12
  // src/hooks/install.ts
6
13
  import fs from "fs";
@@ -27,8 +34,6 @@ function discoverInstallTargets() {
27
34
  }
28
35
  return targets;
29
36
  }
30
- var STOP_COMMAND = "npx -y kojee-mcp hook --type=stop";
31
- var UPS_COMMAND = "npx -y kojee-mcp hook --type=user-prompt-submit";
32
37
  var MCP_SERVER_CMD = "npx";
33
38
  var MCP_SERVER_ARGS = ["kojee-mcp"];
34
39
  var MCP_SERVER_ENV = { KOJEE_RUNTIME: "claude-code" };
@@ -54,14 +59,18 @@ function writeConfig(p, cfg) {
54
59
  fs.writeFileSync(p, JSON.stringify(cfg, null, 2), { mode: 384 });
55
60
  secureFile(p);
56
61
  }
57
- function hasKojeeEntry(arr, command) {
58
- if (!arr) return false;
59
- return arr.some((e) => e.hooks.some((h) => h.command === command));
60
- }
61
62
  function installHookEntry(cfg, event, command) {
62
63
  cfg.hooks ??= {};
63
64
  cfg.hooks[event] ??= [];
64
- if (hasKojeeEntry(cfg.hooks[event], command)) return "already-installed";
65
+ for (const entry of cfg.hooks[event]) {
66
+ for (const h of entry.hooks) {
67
+ if (h.command === command) return "already-installed";
68
+ if (isKojeeHookCommand(h.command)) {
69
+ h.command = command;
70
+ return "updated";
71
+ }
72
+ }
73
+ }
65
74
  cfg.hooks[event].push({ hooks: [{ type: "command", command }] });
66
75
  return "added";
67
76
  }
@@ -73,7 +82,7 @@ function uninstallHookEntries(cfg) {
73
82
  if (!arr) continue;
74
83
  const before = arr.length;
75
84
  cfg.hooks[event] = arr.filter(
76
- (entry) => !entry.hooks.some((h) => h.command.startsWith("npx -y kojee-mcp hook"))
85
+ (entry) => !entry.hooks.some((h) => isKojeeHookCommand(h.command))
77
86
  );
78
87
  if (cfg.hooks[event].length !== before) removed = true;
79
88
  }
@@ -82,8 +91,8 @@ function uninstallHookEntries(cfg) {
82
91
  function installHooks(opts = {}) {
83
92
  const p = opts.hooksPath ?? (opts.configPath ? deriveHooksPath(opts.configPath) : defaultHooksPath());
84
93
  const cfg = readConfig(p);
85
- const stop = installHookEntry(cfg, "Stop", STOP_COMMAND);
86
- const ups = installHookEntry(cfg, "UserPromptSubmit", UPS_COMMAND);
94
+ const stop = installHookEntry(cfg, "Stop", buildHookCommand("stop"));
95
+ const ups = installHookEntry(cfg, "UserPromptSubmit", buildHookCommand("user-prompt-submit"));
87
96
  writeConfig(p, cfg);
88
97
  return { stop, ups };
89
98
  }
@@ -98,26 +107,29 @@ function mcpServerArgs(opts) {
98
107
  if (opts.token && opts.url) {
99
108
  return [...MCP_SERVER_ARGS, "--token", opts.token, "--url", opts.url];
100
109
  }
110
+ if (opts.pairedConfigPath) {
111
+ return [...MCP_SERVER_ARGS, "--paired-config", opts.pairedConfigPath];
112
+ }
101
113
  return [...MCP_SERVER_ARGS];
102
114
  }
103
115
  function installMcpServer(opts = {}) {
104
116
  const p = opts.configPath ?? defaultConfigPath();
105
117
  const cfg = readConfig(p);
106
118
  cfg.mcpServers ??= {};
107
- const args = mcpServerArgs(opts);
119
+ const { command, args } = wrapNpxLauncher(MCP_SERVER_CMD, mcpServerArgs(opts));
120
+ const env = { ...MCP_SERVER_ENV };
108
121
  const existing = cfg.mcpServers["kojee"];
109
122
  if (existing) {
110
- const sameCommand = existing.command === MCP_SERVER_CMD;
123
+ const sameCommand = existing.command === command;
111
124
  const sameArgs = JSON.stringify(existing.args ?? []) === JSON.stringify(args);
112
- const sameEnv = JSON.stringify(existing.env ?? {}) === JSON.stringify(MCP_SERVER_ENV);
125
+ const sameEnv = JSON.stringify(existing.env ?? {}) === JSON.stringify(env);
113
126
  if (sameCommand && sameArgs && sameEnv) return "already-installed";
114
- return "preserved-different";
127
+ if (!opts.overwrite) return "preserved-different";
128
+ cfg.mcpServers["kojee"] = { ...existing, command, args, env };
129
+ writeConfig(p, cfg);
130
+ return "updated";
115
131
  }
116
- cfg.mcpServers["kojee"] = {
117
- command: MCP_SERVER_CMD,
118
- args,
119
- env: { ...MCP_SERVER_ENV }
120
- };
132
+ cfg.mcpServers["kojee"] = { command, args, env };
121
133
  writeConfig(p, cfg);
122
134
  return "added";
123
135
  }
@@ -130,12 +142,13 @@ function uninstallMcpServer(opts = {}) {
130
142
  return true;
131
143
  }
132
144
  function runInit(opts = {}) {
133
- const targets = opts.configPath ? [{
145
+ const discovered = opts.configPath ? [{
134
146
  kind: "cli",
135
147
  path: opts.configPath,
136
148
  exists: true,
137
149
  hooksPath: opts.hooksPath ?? deriveHooksPath(opts.configPath)
138
150
  }] : discoverInstallTargets();
151
+ const targets = opts.ensureCli ? discovered.map((t) => t.kind === "cli" ? { ...t, exists: true } : t) : discovered;
139
152
  const reports = [];
140
153
  for (const t of targets) {
141
154
  if (!t.exists) {
@@ -145,7 +158,9 @@ function runInit(opts = {}) {
145
158
  const mcpServer = installMcpServer({
146
159
  configPath: t.path,
147
160
  ...opts.token ? { token: opts.token } : {},
148
- ...opts.url ? { url: opts.url } : {}
161
+ ...opts.url ? { url: opts.url } : {},
162
+ ...opts.pairedConfigPath ? { pairedConfigPath: opts.pairedConfigPath } : {},
163
+ ...opts.overwrite ? { overwrite: true } : {}
149
164
  });
150
165
  let stopHook;
151
166
  let upsHook;
@@ -4,8 +4,8 @@ import {
4
4
  generateES256KeyPair,
5
5
  loadKeystore,
6
6
  saveKeystore
7
- } from "./chunk-CH32ELFX.js";
8
- import "./chunk-BLEGIR35.js";
7
+ } from "./chunk-6G6YYST6.js";
8
+ import "./chunk-U5HHHRXA.js";
9
9
  export {
10
10
  defaultPairedKeystorePath,
11
11
  deriveKeystorePath,
package/dist/lib.d.ts CHANGED
@@ -129,13 +129,16 @@ interface PairedConfig {
129
129
  token: string;
130
130
  broker_url: string;
131
131
  paired_at: string;
132
+ /** Stamped at connect time; used by doctor + launch cross-check. */
133
+ runtime?: string;
132
134
  principal_id?: string;
133
135
  agent_id?: string;
134
136
  }
137
+ /** Legacy global paired slot (fallback only). */
135
138
  declare function pairedConfigPath(): string;
136
139
  declare function loadPairedConfig(filePath?: string): PairedConfig | null;
137
140
 
138
- type Runtime = "claude-code" | "codex" | "unknown";
141
+ type Runtime = "claude-code" | "codex" | "openclaw" | "unknown";
139
142
 
140
143
  /**
141
144
  * Per-harness adapter. Today: minimal — only what's needed for the
package/dist/lib.js CHANGED
@@ -5,31 +5,34 @@ import {
5
5
  normalizeBackendEvent,
6
6
  sanitizeDisplayname,
7
7
  startEventStream
8
- } from "./chunk-74XFVX6Z.js";
8
+ } from "./chunk-FSKGQ6GT.js";
9
9
  import {
10
10
  loadPairedConfig,
11
11
  pairedConfigPath
12
- } from "./chunk-YH27B6SW.js";
12
+ } from "./chunk-5SZHXYPK.js";
13
13
  import {
14
14
  GatewayClient,
15
15
  applyStableSessionId
16
- } from "./chunk-U4MNICQI.js";
16
+ } from "./chunk-247WFMCJ.js";
17
17
  import {
18
18
  AuthModule
19
- } from "./chunk-JXMVZEQ7.js";
19
+ } from "./chunk-I67C2HYA.js";
20
20
  import {
21
- createDPoPProof,
22
21
  deriveStableSessionId
23
- } from "./chunk-NR4Y54OL.js";
22
+ } from "./chunk-Z5LPNJQ6.js";
23
+ import {
24
+ createDPoPProof
25
+ } from "./chunk-MIEI4PLB.js";
24
26
  import {
25
27
  defaultPairedKeystorePath,
26
28
  deriveKeystorePath,
27
29
  generateES256KeyPair,
28
30
  loadKeystore,
29
31
  saveKeystore
30
- } from "./chunk-CH32ELFX.js";
31
- import "./chunk-BLEGIR35.js";
32
- import "./chunk-2OLXXOT3.js";
32
+ } from "./chunk-6G6YYST6.js";
33
+ import "./chunk-U5HHHRXA.js";
34
+ import "./chunk-PPTKGWFF.js";
35
+ import "./chunk-KNEJTD6G.js";
33
36
  export {
34
37
  AuthModule,
35
38
  GatewayClient,
@@ -0,0 +1,11 @@
1
+ import {
2
+ runPair
3
+ } from "./chunk-EIAUW6KO.js";
4
+ import "./chunk-5SZHXYPK.js";
5
+ import "./chunk-I67C2HYA.js";
6
+ import "./chunk-MIEI4PLB.js";
7
+ import "./chunk-6G6YYST6.js";
8
+ import "./chunk-U5HHHRXA.js";
9
+ export {
10
+ runPair
11
+ };
@@ -1,11 +1,13 @@
1
1
  import {
2
2
  loadPairedConfig,
3
3
  pairedConfigPath,
4
+ perRuntimeConfigPath,
4
5
  savePairedConfig
5
- } from "./chunk-YH27B6SW.js";
6
- import "./chunk-BLEGIR35.js";
6
+ } from "./chunk-5SZHXYPK.js";
7
+ import "./chunk-U5HHHRXA.js";
7
8
  export {
8
9
  loadPairedConfig,
9
10
  pairedConfigPath,
11
+ perRuntimeConfigPath,
10
12
  savePairedConfig
11
13
  };
@@ -1,14 +1,19 @@
1
1
  import {
2
- findClaudeAncestorPid
3
- } from "./chunk-VHKPWUX7.js";
2
+ findClaudeAncestorPid,
3
+ pidLooksLikeClaude
4
+ } from "./chunk-XJEBJIQE.js";
4
5
 
5
6
  // src/runtime/parent-watchdog.ts
7
+ function shouldArmWatchdog(ccPid) {
8
+ return ccPid !== null;
9
+ }
6
10
  function defaultIsPidAlive(pid) {
7
11
  try {
8
12
  process.kill(pid, 0);
9
13
  return true;
10
14
  } catch (err) {
11
- if (err.code === "EPERM") return true;
15
+ const code = err.code;
16
+ if (code === "EPERM" || code === "EACCES") return true;
12
17
  return false;
13
18
  }
14
19
  }
@@ -16,9 +21,12 @@ function createParentWatchdog(opts) {
16
21
  const intervalMs = opts.intervalMs ?? 7e3;
17
22
  const isPidAlive = opts.isPidAlive ?? defaultIsPidAlive;
18
23
  const resolveAncestor = opts.resolveAncestor ?? (() => findClaudeAncestorPid());
24
+ const verifyPidIdentity = opts.verifyPidIdentity ?? pidLooksLikeClaude;
25
+ const identityCheckEveryNTicks = opts.identityCheckEveryNTicks ?? 4;
19
26
  let timer = null;
20
27
  let fired = false;
21
28
  let checking = false;
29
+ let tick = 0;
22
30
  function stop() {
23
31
  if (timer !== null) {
24
32
  clearInterval(timer);
@@ -30,7 +38,17 @@ function createParentWatchdog(opts) {
30
38
  checking = true;
31
39
  try {
32
40
  const ccPidAlive = isPidAlive(opts.ccPid);
33
- if (ccPidAlive) return;
41
+ if (ccPidAlive) {
42
+ tick++;
43
+ if (tick % identityCheckEveryNTicks !== 0) return;
44
+ let identity = null;
45
+ try {
46
+ identity = await verifyPidIdentity(opts.ccPid);
47
+ } catch {
48
+ identity = null;
49
+ }
50
+ if (identity !== false) return;
51
+ }
34
52
  let ancestor = null;
35
53
  try {
36
54
  ancestor = await resolveAncestor();
@@ -61,5 +79,6 @@ function createParentWatchdog(opts) {
61
79
  }
62
80
  export {
63
81
  createParentWatchdog,
64
- defaultIsPidAlive
82
+ defaultIsPidAlive,
83
+ shouldArmWatchdog
65
84
  };