kojee-mcp 0.5.13 → 0.5.15
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.
- package/dist/{chunk-LVL25VLO.js → chunk-77HWBSRH.js} +0 -5
- package/dist/cli.js +2 -2
- package/dist/plugins/hermes/__init__.py +21 -0
- package/dist/plugins/hermes/adapter.py +481 -0
- package/dist/plugins/hermes/kojee_tandem_core.py +344 -0
- package/dist/plugins/hermes/plugin.yaml +58 -0
- package/dist/{runtimes-CO43XUUK.js → runtimes-GG7EOFZH.js} +1 -3
- package/dist/wizard-3FDEWEYO.js +904 -0
- package/package.json +2 -2
- package/dist/wizard-L4MYRLJI.js +0 -382
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kojee-mcp",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.15",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
},
|
|
17
17
|
"_buildNote": "src/version.ts resolves package.json via '../package.json' from import.meta.url; this assumes dist output stays flat one level under the package root (tsup default outDir=dist, no nesting). If the build adds outDir nesting or a deeper entry, update version.ts's relative path.",
|
|
18
18
|
"scripts": {
|
|
19
|
-
"build": "tsup src/cli.ts src/index.ts src/lib.ts --format esm --dts --clean",
|
|
19
|
+
"build": "tsup src/cli.ts src/index.ts src/lib.ts --format esm --dts --clean && tsx scripts/bundle-plugins.ts",
|
|
20
20
|
"prepublishOnly": "npm run build && node scripts/verify-tarball.mjs",
|
|
21
21
|
"dev": "tsup src/cli.ts --format esm --watch",
|
|
22
22
|
"typecheck": "tsc --noEmit",
|
package/dist/wizard-L4MYRLJI.js
DELETED
|
@@ -1,382 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
clearRuntimeRecord,
|
|
3
|
-
readRecordedRuntime,
|
|
4
|
-
recordRuntime
|
|
5
|
-
} from "./chunk-EW72ZNQL.js";
|
|
6
|
-
import {
|
|
7
|
-
buildCodexMcpServerTable,
|
|
8
|
-
buildCodexStopHookBlock,
|
|
9
|
-
removeCodexConfig,
|
|
10
|
-
writeCodexConfig
|
|
11
|
-
} from "./chunk-65KRRDHP.js";
|
|
12
|
-
import {
|
|
13
|
-
kojeeHomeDir
|
|
14
|
-
} from "./chunk-SQL56SEB.js";
|
|
15
|
-
import {
|
|
16
|
-
WIZARD_RUNTIMES,
|
|
17
|
-
isWizardRuntime
|
|
18
|
-
} from "./chunk-LVL25VLO.js";
|
|
19
|
-
import {
|
|
20
|
-
resolveSignatureEmission,
|
|
21
|
-
resolveWebhookConfig
|
|
22
|
-
} from "./chunk-V5VZPYMZ.js";
|
|
23
|
-
import {
|
|
24
|
-
secureFile
|
|
25
|
-
} from "./chunk-BLEGIR35.js";
|
|
26
|
-
import {
|
|
27
|
-
CODEX_LISTEN_CAP_MS,
|
|
28
|
-
buildWebhookReceiverNote
|
|
29
|
-
} from "./chunk-X672ZN7V.js";
|
|
30
|
-
|
|
31
|
-
// src/wizard/wizard.ts
|
|
32
|
-
import crypto from "crypto";
|
|
33
|
-
import fs from "fs";
|
|
34
|
-
import path from "path";
|
|
35
|
-
var DEFAULT_BROKER_URL = "https://rosie-staging.kojee.net";
|
|
36
|
-
function generateWebhookSecret() {
|
|
37
|
-
return crypto.randomBytes(32).toString("hex");
|
|
38
|
-
}
|
|
39
|
-
async function resolveRuntime(opts) {
|
|
40
|
-
if (opts.runtime !== void 0) {
|
|
41
|
-
if (!isWizardRuntime(opts.runtime)) {
|
|
42
|
-
return {
|
|
43
|
-
error: `Unknown --runtime "${opts.runtime}". Expected one of: ${WIZARD_RUNTIMES.join(", ")}.`
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
return { runtime: opts.runtime };
|
|
47
|
-
}
|
|
48
|
-
if (opts.interactive && opts.promptRuntime) {
|
|
49
|
-
const picked = await opts.promptRuntime();
|
|
50
|
-
if (!isWizardRuntime(picked)) {
|
|
51
|
-
return { error: `Unknown runtime "${picked}". Expected one of: ${WIZARD_RUNTIMES.join(", ")}.` };
|
|
52
|
-
}
|
|
53
|
-
return { runtime: picked };
|
|
54
|
-
}
|
|
55
|
-
return { runtime: "claude-code" };
|
|
56
|
-
}
|
|
57
|
-
function resolveWizardWebhook(opts) {
|
|
58
|
-
const env = opts.env ?? process.env;
|
|
59
|
-
const url = (opts.webhookUrl ?? env["KOJEE_WEBHOOK_URL"] ?? "").trim();
|
|
60
|
-
let secret = (opts.webhookSecret ?? env["KOJEE_WEBHOOK_SECRET"] ?? "").trim();
|
|
61
|
-
if (url && !secret) secret = generateWebhookSecret();
|
|
62
|
-
const sigFormat = (opts.webhookSignatureFormat ?? env["KOJEE_WEBHOOK_SIGNATURE_FORMAT"] ?? "").trim();
|
|
63
|
-
const sigHeader = (opts.webhookSignatureHeader ?? env["KOJEE_WEBHOOK_SIGNATURE_HEADER"] ?? "").trim();
|
|
64
|
-
const sigPrefix = opts.webhookSignaturePrefix ?? env["KOJEE_WEBHOOK_SIGNATURE_PREFIX"];
|
|
65
|
-
const signatureEnv = [];
|
|
66
|
-
if (sigFormat) signatureEnv.push(["KOJEE_WEBHOOK_SIGNATURE_FORMAT", sigFormat]);
|
|
67
|
-
if (sigHeader) signatureEnv.push(["KOJEE_WEBHOOK_SIGNATURE_HEADER", sigHeader]);
|
|
68
|
-
if (sigPrefix !== void 0) signatureEnv.push(["KOJEE_WEBHOOK_SIGNATURE_PREFIX", sigPrefix]);
|
|
69
|
-
const emission = resolveSignatureEmission(Object.fromEntries(signatureEnv));
|
|
70
|
-
const resolution = resolveWebhookConfig({
|
|
71
|
-
KOJEE_WEBHOOK_URL: url,
|
|
72
|
-
KOJEE_WEBHOOK_SECRET: secret,
|
|
73
|
-
...env["KOJEE_WEBHOOK_TIMEOUT_MS"] !== void 0 ? { KOJEE_WEBHOOK_TIMEOUT_MS: env["KOJEE_WEBHOOK_TIMEOUT_MS"] } : {},
|
|
74
|
-
...env["KOJEE_WEBHOOK_MAX_RETRIES"] !== void 0 ? { KOJEE_WEBHOOK_MAX_RETRIES: env["KOJEE_WEBHOOK_MAX_RETRIES"] } : {},
|
|
75
|
-
...Object.fromEntries(signatureEnv)
|
|
76
|
-
});
|
|
77
|
-
const warning = resolution.warning ?? (emission.warnings.length > 0 ? emission.warnings.join("; ") : void 0);
|
|
78
|
-
if (resolution.error) {
|
|
79
|
-
return {
|
|
80
|
-
url,
|
|
81
|
-
secret,
|
|
82
|
-
redactedSummary: "",
|
|
83
|
-
signatureEnv,
|
|
84
|
-
signatureHeader: emission.header,
|
|
85
|
-
signaturePrefix: emission.prefix,
|
|
86
|
-
error: resolution.error
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
return {
|
|
90
|
-
url,
|
|
91
|
-
secret,
|
|
92
|
-
redactedSummary: resolution.config?.redactedSummary ?? `url=${url} secret=<redacted>`,
|
|
93
|
-
signatureEnv,
|
|
94
|
-
signatureHeader: emission.header,
|
|
95
|
-
signaturePrefix: emission.prefix,
|
|
96
|
-
...warning !== void 0 ? { warning } : {}
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
function shellSingleQuote(value) {
|
|
100
|
-
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
101
|
-
}
|
|
102
|
-
function writeRuntimeEnvFile(runtime, url, secret, signatureEnv = []) {
|
|
103
|
-
const envPath = path.join(kojeeHomeDir(), ".kojee", `${runtime}.env`);
|
|
104
|
-
const body = [
|
|
105
|
-
`# kojee daemon env for runtime=${runtime} (source this before starting the daemon)`,
|
|
106
|
-
`export KOJEE_RUNTIME=${shellSingleQuote(runtime)}`,
|
|
107
|
-
`export KOJEE_WEBHOOK_URL=${shellSingleQuote(url)}`,
|
|
108
|
-
`export KOJEE_WEBHOOK_SECRET=${shellSingleQuote(secret)}`,
|
|
109
|
-
// Signature emission overrides (0.5.3) — only when explicitly configured.
|
|
110
|
-
...signatureEnv.map(([k, v]) => `export ${k}=${shellSingleQuote(v)}`),
|
|
111
|
-
""
|
|
112
|
-
].join("\n");
|
|
113
|
-
fs.mkdirSync(path.dirname(envPath), { recursive: true, mode: 448 });
|
|
114
|
-
fs.writeFileSync(envPath, body, { mode: 384 });
|
|
115
|
-
secureFile(envPath);
|
|
116
|
-
return envPath;
|
|
117
|
-
}
|
|
118
|
-
var CODEX_UNVERIFIED_NOTE = "NOTE: live Codex verification (hook fires, MCP server connects, bounded listen works) has not been run on this build \u2014 confirm in a real Codex session. This is the owner morning step.";
|
|
119
|
-
function runtimeUsesWebhook(runtime) {
|
|
120
|
-
return runtime === "codex" || runtime === "hermes" || runtime === "openclaw";
|
|
121
|
-
}
|
|
122
|
-
async function gatherGuidedInputs(runtime, opts) {
|
|
123
|
-
const preamble = [];
|
|
124
|
-
const next = { ...opts };
|
|
125
|
-
if (opts.promptUrl) {
|
|
126
|
-
const answered = (await opts.promptUrl(opts.url ?? DEFAULT_BROKER_URL)).trim();
|
|
127
|
-
next.url = (answered.length > 0 ? answered : opts.url ?? DEFAULT_BROKER_URL).replace(/\/+$/, "");
|
|
128
|
-
}
|
|
129
|
-
const brokerUrl = (next.url ?? DEFAULT_BROKER_URL).replace(/\/+$/, "");
|
|
130
|
-
if (opts.promptAuth) {
|
|
131
|
-
const mode = await opts.promptAuth();
|
|
132
|
-
if (mode === "token") {
|
|
133
|
-
const token = opts.promptToken ? (await opts.promptToken()).trim() : "";
|
|
134
|
-
if (!token) return { error: "No token entered. Re-run `kojee-mcp init` and paste a token, or choose pair mode." };
|
|
135
|
-
next.token = token;
|
|
136
|
-
next.url = brokerUrl;
|
|
137
|
-
preamble.push("Auth: token mode \u2014 the written MCP config will launch the proxy with --token/--url");
|
|
138
|
-
preamble.push(" (it enrolls its own per-token keystore on first boot).");
|
|
139
|
-
} else {
|
|
140
|
-
const code = opts.promptPairCode ? (await opts.promptPairCode()).trim() : "";
|
|
141
|
-
if (!code) return { error: "No pair code entered. Re-run `kojee-mcp init` and enter a pair code, or choose token mode." };
|
|
142
|
-
const pair = opts.runPair ?? (async (a) => {
|
|
143
|
-
const { runPair } = await import("./pair-P4ILCMT7.js");
|
|
144
|
-
const { pairedConfigPath } = await import("./paired-config-JTFLHMZ2.js");
|
|
145
|
-
const { defaultPairedKeystorePath } = await import("./keystore-XLEV3FL5.js");
|
|
146
|
-
return runPair({ code: a.code, url: a.url, keystorePath: defaultPairedKeystorePath(), configPath: pairedConfigPath() });
|
|
147
|
-
});
|
|
148
|
-
try {
|
|
149
|
-
const { message } = await pair({ code, url: brokerUrl });
|
|
150
|
-
preamble.push(`Auth: pair mode \u2014 ${message}`);
|
|
151
|
-
} catch (err) {
|
|
152
|
-
return { error: `Pairing failed: ${err.message}` };
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
if (runtimeUsesWebhook(runtime) && opts.promptWebhookUrl && opts.webhookUrl === void 0) {
|
|
157
|
-
const wh = (await opts.promptWebhookUrl()).trim();
|
|
158
|
-
if (wh.length > 0) next.webhookUrl = wh;
|
|
159
|
-
}
|
|
160
|
-
return { opts: next, preamble };
|
|
161
|
-
}
|
|
162
|
-
async function runWizard(opts) {
|
|
163
|
-
const resolved = await resolveRuntime(opts);
|
|
164
|
-
if ("error" in resolved) {
|
|
165
|
-
return { runtime: "claude-code", output: resolved.error, exitCode: 2 };
|
|
166
|
-
}
|
|
167
|
-
const runtime = resolved.runtime;
|
|
168
|
-
if (opts.uninstall) {
|
|
169
|
-
return runWizardUninstall(runtime, opts);
|
|
170
|
-
}
|
|
171
|
-
let effective = opts;
|
|
172
|
-
let preamble = [];
|
|
173
|
-
if (opts.interactive && (opts.promptUrl || opts.promptAuth || opts.promptWebhookUrl)) {
|
|
174
|
-
const gathered = await gatherGuidedInputs(runtime, opts);
|
|
175
|
-
if ("error" in gathered) {
|
|
176
|
-
return { runtime, output: gathered.error, exitCode: 2 };
|
|
177
|
-
}
|
|
178
|
-
effective = gathered.opts;
|
|
179
|
-
preamble = gathered.preamble;
|
|
180
|
-
}
|
|
181
|
-
const result = runtime === "claude-code" ? await configureClaudeCode(effective) : runtime === "codex" ? configureCodex(effective) : configureWebhookDaemon(runtime, effective);
|
|
182
|
-
if (preamble.length > 0 && result.exitCode === 0) {
|
|
183
|
-
return {
|
|
184
|
-
...result,
|
|
185
|
-
output: [...preamble, "", result.output, "", whatHappensNext(runtime, effective)].join("\n")
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
return result;
|
|
189
|
-
}
|
|
190
|
-
function whatHappensNext(runtime, opts) {
|
|
191
|
-
const lines = ["What happens next:"];
|
|
192
|
-
lines.push(" - Restart your runtime so it picks up the new kojee config.");
|
|
193
|
-
if (opts.token) {
|
|
194
|
-
lines.push(" - First boot enrolls this token's own keystore (~/.kojee/keypair-<hash>.json).");
|
|
195
|
-
} else {
|
|
196
|
-
lines.push(" - The proxy uses your paired credentials (~/.kojee/config.json + keypair.json).");
|
|
197
|
-
}
|
|
198
|
-
lines.push(" - Verify with: kojee-mcp doctor");
|
|
199
|
-
return lines.join("\n");
|
|
200
|
-
}
|
|
201
|
-
async function configureClaudeCode(opts) {
|
|
202
|
-
const { runInit } = await import("./install-LJY2CHKG.js");
|
|
203
|
-
const report = runInit({
|
|
204
|
-
...opts.configPath ? { configPath: opts.configPath } : {},
|
|
205
|
-
...opts.hooksPath ? { hooksPath: opts.hooksPath } : {},
|
|
206
|
-
// Token mode threads --token/--url into the written args (per-token
|
|
207
|
-
// keystore). Paired mode leaves both unset ⇒ args stay `["kojee-mcp"]`.
|
|
208
|
-
...opts.token && opts.url ? { token: opts.token, url: opts.url } : {}
|
|
209
|
-
});
|
|
210
|
-
recordRuntime("claude-code");
|
|
211
|
-
return { runtime: "claude-code", output: formatClaudeInit(report), exitCode: 0 };
|
|
212
|
-
}
|
|
213
|
-
function formatClaudeInit(report) {
|
|
214
|
-
const tick = (s) => {
|
|
215
|
-
if (s === "added") return "\u2713 added";
|
|
216
|
-
if (s === "already-installed") return "\u21BB already installed";
|
|
217
|
-
if (s === "preserved-different") return "\u26A0 preserved (existing entry differs \u2014 left untouched)";
|
|
218
|
-
if (s === "not-found") return "\u2014 not found";
|
|
219
|
-
return s ?? "\u2014";
|
|
220
|
-
};
|
|
221
|
-
const lines = ["Configured runtime: claude-code", "", "Installing kojee for Claude:"];
|
|
222
|
-
for (const t of report.targets) {
|
|
223
|
-
const label = t.kind === "cli" ? "CLI" : "Claude.app";
|
|
224
|
-
lines.push("");
|
|
225
|
-
lines.push(` ${t.path} (${label})`);
|
|
226
|
-
lines.push(` mcpServers.kojee ${tick(t.mcpServer)}`);
|
|
227
|
-
if (t.kind === "cli") {
|
|
228
|
-
if (t.hooksPath) lines.push(` ${t.hooksPath} (hooks)`);
|
|
229
|
-
lines.push(` hooks.Stop ${tick(t.stopHook)}`);
|
|
230
|
-
lines.push(` hooks.UserPromptSubmit ${tick(t.userPromptSubmitHook)}`);
|
|
231
|
-
} else {
|
|
232
|
-
lines.push(` (hooks not applicable for Claude.app agent mode)`);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
lines.push("");
|
|
236
|
-
if (report.targets.some((t) => t.kind === "desktop" && t.mcpServer === "added")) {
|
|
237
|
-
lines.push(
|
|
238
|
-
"Existing Claude.app agent-mode sessions snapshotted the previous config",
|
|
239
|
-
"and won't pick up this change automatically. Start a NEW agent-mode",
|
|
240
|
-
"session (not a resumed one) to use the updated kojee config.",
|
|
241
|
-
""
|
|
242
|
-
);
|
|
243
|
-
}
|
|
244
|
-
lines.push("To verify: in any new CC session, run /mcp and confirm `kojee` is listed.");
|
|
245
|
-
lines.push(" run /hooks and confirm both Stop and UserPromptSubmit show the kojee entries.");
|
|
246
|
-
lines.push("To remove: `kojee-mcp init --uninstall`");
|
|
247
|
-
return lines.join("\n");
|
|
248
|
-
}
|
|
249
|
-
function configureCodex(opts) {
|
|
250
|
-
const wh = resolveWizardWebhook(opts);
|
|
251
|
-
if (wh.error) {
|
|
252
|
-
return { runtime: "codex", output: `webhook env ERROR: ${wh.error}`, exitCode: 2 };
|
|
253
|
-
}
|
|
254
|
-
const url = wh.url || "https://YOUR-CODEX-WEBHOOK-RECEIVER.local/kojee";
|
|
255
|
-
const secret = wh.secret || generateWebhookSecret();
|
|
256
|
-
const tokenArgs = opts.token && opts.url ? { token: opts.token, url: opts.url } : {};
|
|
257
|
-
writeCodexConfig({
|
|
258
|
-
...opts.configPath ? { configPath: opts.configPath } : {},
|
|
259
|
-
...opts.hooksPath ? { hooksPath: opts.hooksPath } : {},
|
|
260
|
-
webhookUrl: url,
|
|
261
|
-
webhookSecret: secret,
|
|
262
|
-
...wh.signatureEnv.length > 0 ? { signatureEnv: wh.signatureEnv } : {},
|
|
263
|
-
...tokenArgs
|
|
264
|
-
});
|
|
265
|
-
recordRuntime("codex");
|
|
266
|
-
const lines = [];
|
|
267
|
-
lines.push("Configured runtime: codex");
|
|
268
|
-
lines.push("Wake mode: webhook-sink + stop-hook peek (Codex has no channel injection).");
|
|
269
|
-
lines.push("");
|
|
270
|
-
lines.push("Wrote [mcp_servers.kojee] to ~/.codex/config.toml:");
|
|
271
|
-
lines.push(indent(buildCodexMcpServerTable({
|
|
272
|
-
webhookUrl: url,
|
|
273
|
-
webhookSecret: "<redacted>",
|
|
274
|
-
...wh.signatureEnv.length > 0 ? { signatureEnv: wh.signatureEnv } : {},
|
|
275
|
-
// Redact the gateway token in the human-readable printed copy (it ends up
|
|
276
|
-
// in result.output → cli.ts console.error). The WRITTEN config above keeps
|
|
277
|
-
// the real token; only this printed report is redacted, like webhookSecret.
|
|
278
|
-
...tokenArgs.token ? { token: "<redacted>", url: tokenArgs.url } : {}
|
|
279
|
-
})));
|
|
280
|
-
if (wh.warning) lines.push(`webhook WARNING: ${wh.warning}`);
|
|
281
|
-
lines.push("");
|
|
282
|
-
lines.push("Wrote the Codex Stop hook (~/.codex/hooks.json; inline TOML form):");
|
|
283
|
-
lines.push(indent(buildCodexStopHookBlock()));
|
|
284
|
-
lines.push("");
|
|
285
|
-
lines.push(`webhook: ${wh.url ? wh.redactedSummary : "(receiver URL not set \u2014 fill KOJEE_WEBHOOK_URL above)"}`);
|
|
286
|
-
lines.push(`bounded-listen cap: ${CODEX_LISTEN_CAP_MS}ms (the model picks listen vs drain vs ignore).`);
|
|
287
|
-
lines.push("");
|
|
288
|
-
lines.push("Next steps (codex):");
|
|
289
|
-
lines.push(" Restart Codex (or start a new `codex` / `codex exec` session) to load the MCP server and hook.");
|
|
290
|
-
lines.push(" Stand up your webhook receiver at KOJEE_WEBHOOK_URL \u2014 contract:");
|
|
291
|
-
lines.push(indent(buildWebhookReceiverNote({ header: wh.signatureHeader, prefix: wh.signaturePrefix })));
|
|
292
|
-
lines.push(" Verify: kojee-mcp doctor");
|
|
293
|
-
lines.push("");
|
|
294
|
-
lines.push(CODEX_UNVERIFIED_NOTE);
|
|
295
|
-
return { runtime: "codex", output: lines.join("\n"), exitCode: 0 };
|
|
296
|
-
}
|
|
297
|
-
function configureWebhookDaemon(runtime, opts) {
|
|
298
|
-
const wh = resolveWizardWebhook(opts);
|
|
299
|
-
if (wh.error) {
|
|
300
|
-
return { runtime, output: `webhook env ERROR: ${wh.error}`, exitCode: 2 };
|
|
301
|
-
}
|
|
302
|
-
recordRuntime(runtime);
|
|
303
|
-
const lines = [];
|
|
304
|
-
lines.push(`Configured runtime: ${runtime}`);
|
|
305
|
-
lines.push("Wake mode: webhook sink (daemon-consumed). NO MCP-config file, NO hooks written.");
|
|
306
|
-
lines.push("");
|
|
307
|
-
if (wh.warning) lines.push(`webhook WARNING: ${wh.warning}`);
|
|
308
|
-
if (wh.url) {
|
|
309
|
-
const envFile = writeRuntimeEnvFile(runtime, wh.url, wh.secret, wh.signatureEnv);
|
|
310
|
-
lines.push("Export these before starting the daemon (also written to a source-able file):");
|
|
311
|
-
lines.push(` export KOJEE_RUNTIME=${shellSingleQuote(runtime)}`);
|
|
312
|
-
lines.push(` export KOJEE_WEBHOOK_URL=${shellSingleQuote(wh.url)}`);
|
|
313
|
-
lines.push(` export KOJEE_WEBHOOK_SECRET=<generated; in ${envFile}>`);
|
|
314
|
-
for (const [k, v] of wh.signatureEnv) lines.push(` export ${k}=${shellSingleQuote(v)}`);
|
|
315
|
-
lines.push(` (validated: ${wh.redactedSummary})`);
|
|
316
|
-
lines.push(` source ${envFile}`);
|
|
317
|
-
} else {
|
|
318
|
-
lines.push("Set the daemon env (no receiver URL supplied yet):");
|
|
319
|
-
lines.push(` export KOJEE_RUNTIME=${shellSingleQuote(runtime)}`);
|
|
320
|
-
lines.push(` export KOJEE_WEBHOOK_URL="https://YOUR-RECEIVER.local/kojee"`);
|
|
321
|
-
lines.push(` export KOJEE_WEBHOOK_SECRET=<generate a hex secret>`);
|
|
322
|
-
for (const [k, v] of wh.signatureEnv) lines.push(` export ${k}=${shellSingleQuote(v)}`);
|
|
323
|
-
}
|
|
324
|
-
lines.push("");
|
|
325
|
-
lines.push("Receiver contract:");
|
|
326
|
-
lines.push(indent(buildWebhookReceiverNote({ header: wh.signatureHeader, prefix: wh.signaturePrefix })));
|
|
327
|
-
lines.push("");
|
|
328
|
-
lines.push(`Next steps (${runtime}):`);
|
|
329
|
-
lines.push(" Start the daemon with the env above. Verify: kojee-mcp doctor (after the daemon is up).");
|
|
330
|
-
return { runtime, output: lines.join("\n"), exitCode: 0 };
|
|
331
|
-
}
|
|
332
|
-
async function runWizardUninstall(runtime, opts) {
|
|
333
|
-
const effective = opts.runtime !== void 0 ? runtime : readRecordedRuntime() ?? runtime;
|
|
334
|
-
const lines = [`Uninstalling runtime: ${effective}`];
|
|
335
|
-
if (effective === "claude-code") {
|
|
336
|
-
const { runUninstall } = await import("./install-LJY2CHKG.js");
|
|
337
|
-
const report = runUninstall({
|
|
338
|
-
...opts.configPath ? { configPath: opts.configPath } : {},
|
|
339
|
-
...opts.hooksPath ? { hooksPath: opts.hooksPath } : {}
|
|
340
|
-
});
|
|
341
|
-
lines.push("Removing kojee from Claude:");
|
|
342
|
-
for (const t of report.targets) {
|
|
343
|
-
const label = t.kind === "cli" ? "CLI" : "Claude.app";
|
|
344
|
-
lines.push("");
|
|
345
|
-
lines.push(` ${t.path} (${label})`);
|
|
346
|
-
lines.push(` mcpServers.kojee ${t.mcpServer ? "\u2713 removed" : "\u2014 not found"}`);
|
|
347
|
-
if (t.kind === "cli") {
|
|
348
|
-
if (t.hooksPath) lines.push(` ${t.hooksPath} (hooks)`);
|
|
349
|
-
lines.push(` hook entries ${t.hooks ? "\u2713 removed" : "\u2014 not found"}`);
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
} else if (effective === "codex") {
|
|
353
|
-
const removed = removeCodexConfig({
|
|
354
|
-
...opts.configPath ? { configPath: opts.configPath } : {},
|
|
355
|
-
...opts.hooksPath ? { hooksPath: opts.hooksPath } : {}
|
|
356
|
-
});
|
|
357
|
-
lines.push(` config.toml [mcp_servers.kojee]: ${removed.mcpServer ? "removed" : "not found"}`);
|
|
358
|
-
lines.push(` hooks.json Stop: ${removed.stopHook ? "removed" : "not found"}`);
|
|
359
|
-
} else {
|
|
360
|
-
lines.push(" (hermes/openclaw write no MCP-config or hooks \u2014 nothing to tear down.");
|
|
361
|
-
lines.push(" Stop the daemon and unset KOJEE_WEBHOOK_URL/SECRET to disable the sink.)");
|
|
362
|
-
const envPath = path.join(kojeeHomeDir(), ".kojee", `${effective}.env`);
|
|
363
|
-
try {
|
|
364
|
-
fs.unlinkSync(envPath);
|
|
365
|
-
lines.push(` removed ${envPath}`);
|
|
366
|
-
} catch {
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
clearRuntimeRecord();
|
|
370
|
-
return { runtime: effective, output: lines.join("\n"), exitCode: 0 };
|
|
371
|
-
}
|
|
372
|
-
function indent(s) {
|
|
373
|
-
return s.split("\n").map((l) => " " + l).join("\n");
|
|
374
|
-
}
|
|
375
|
-
export {
|
|
376
|
-
CODEX_UNVERIFIED_NOTE,
|
|
377
|
-
DEFAULT_BROKER_URL,
|
|
378
|
-
generateWebhookSecret,
|
|
379
|
-
resolveRuntime,
|
|
380
|
-
resolveWizardWebhook,
|
|
381
|
-
runWizard
|
|
382
|
-
};
|