@essentialai/cc-bridge-mcp-server 0.1.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.
- package/LICENSE +15 -0
- package/README.md +289 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +18 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +28 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +35 -0
- package/dist/config.js.map +1 -0
- package/dist/constants.d.ts +3 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +6 -0
- package/dist/constants.js.map +1 -0
- package/dist/errors.d.ts +40 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +53 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +66 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +22 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +74 -0
- package/dist/logger.js.map +1 -0
- package/dist/services/cc-cli.d.ts +3 -0
- package/dist/services/cc-cli.d.ts.map +1 -0
- package/dist/services/cc-cli.js +57 -0
- package/dist/services/cc-cli.js.map +1 -0
- package/dist/services/health-check.d.ts +23 -0
- package/dist/services/health-check.d.ts.map +1 -0
- package/dist/services/health-check.js +96 -0
- package/dist/services/health-check.js.map +1 -0
- package/dist/services/peer-registry.d.ts +9 -0
- package/dist/services/peer-registry.d.ts.map +1 -0
- package/dist/services/peer-registry.js +207 -0
- package/dist/services/peer-registry.js.map +1 -0
- package/dist/startup.d.ts +2 -0
- package/dist/startup.d.ts.map +1 -0
- package/dist/startup.js +119 -0
- package/dist/startup.js.map +1 -0
- package/dist/tools/deregister-peer.d.ts +3 -0
- package/dist/tools/deregister-peer.d.ts.map +1 -0
- package/dist/tools/deregister-peer.js +37 -0
- package/dist/tools/deregister-peer.js.map +1 -0
- package/dist/tools/get-history.d.ts +3 -0
- package/dist/tools/get-history.d.ts.map +1 -0
- package/dist/tools/get-history.js +39 -0
- package/dist/tools/get-history.js.map +1 -0
- package/dist/tools/health-check.d.ts +3 -0
- package/dist/tools/health-check.d.ts.map +1 -0
- package/dist/tools/health-check.js +27 -0
- package/dist/tools/health-check.js.map +1 -0
- package/dist/tools/list-peers.d.ts +3 -0
- package/dist/tools/list-peers.d.ts.map +1 -0
- package/dist/tools/list-peers.js +35 -0
- package/dist/tools/list-peers.js.map +1 -0
- package/dist/tools/register-peer.d.ts +3 -0
- package/dist/tools/register-peer.d.ts.map +1 -0
- package/dist/tools/register-peer.js +47 -0
- package/dist/tools/register-peer.js.map +1 -0
- package/dist/tools/send-message.d.ts +3 -0
- package/dist/tools/send-message.d.ts.map +1 -0
- package/dist/tools/send-message.js +103 -0
- package/dist/tools/send-message.js.map +1 -0
- package/dist/types.d.ts +31 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/wizard/detect.d.ts +4 -0
- package/dist/wizard/detect.d.ts.map +1 -0
- package/dist/wizard/detect.js +21 -0
- package/dist/wizard/detect.js.map +1 -0
- package/dist/wizard/index.d.ts +5 -0
- package/dist/wizard/index.d.ts.map +1 -0
- package/dist/wizard/index.js +140 -0
- package/dist/wizard/index.js.map +1 -0
- package/dist/wizard/prompts.d.ts +18 -0
- package/dist/wizard/prompts.d.ts.map +1 -0
- package/dist/wizard/prompts.js +66 -0
- package/dist/wizard/prompts.js.map +1 -0
- package/dist/wizard/scaffold-demo.d.ts +6 -0
- package/dist/wizard/scaffold-demo.d.ts.map +1 -0
- package/dist/wizard/scaffold-demo.js +37 -0
- package/dist/wizard/scaffold-demo.js.map +1 -0
- package/dist/wizard/scaffold-real.d.ts +16 -0
- package/dist/wizard/scaffold-real.d.ts.map +1 -0
- package/dist/wizard/scaffold-real.js +64 -0
- package/dist/wizard/scaffold-real.js.map +1 -0
- package/dist/wizard/templates.d.ts +9 -0
- package/dist/wizard/templates.d.ts.map +1 -0
- package/dist/wizard/templates.js +175 -0
- package/dist/wizard/templates.js.map +1 -0
- package/package.json +66 -0
- package/server.json +60 -0
package/dist/logger.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
const LEVELS = {
|
|
4
|
+
debug: 0,
|
|
5
|
+
info: 1,
|
|
6
|
+
warn: 2,
|
|
7
|
+
error: 3,
|
|
8
|
+
};
|
|
9
|
+
export class Logger {
|
|
10
|
+
threshold;
|
|
11
|
+
textStream = null;
|
|
12
|
+
jsonStream = null;
|
|
13
|
+
constructor(level, logDir) {
|
|
14
|
+
this.threshold = LEVELS[level];
|
|
15
|
+
if (logDir) {
|
|
16
|
+
fs.mkdirSync(logDir, { recursive: true });
|
|
17
|
+
const now = new Date()
|
|
18
|
+
.toISOString()
|
|
19
|
+
.replace(/:/g, "-")
|
|
20
|
+
.replace(/\.\d{3}Z$/, "");
|
|
21
|
+
const textFile = `bridge-${now}.log`;
|
|
22
|
+
const jsonFile = `bridge-${now}.json.log`;
|
|
23
|
+
this.textStream = fs.createWriteStream(path.join(logDir, textFile), {
|
|
24
|
+
flags: "a",
|
|
25
|
+
});
|
|
26
|
+
this.jsonStream = fs.createWriteStream(path.join(logDir, jsonFile), {
|
|
27
|
+
flags: "a",
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
log(level, message, data) {
|
|
32
|
+
if (LEVELS[level] < this.threshold)
|
|
33
|
+
return;
|
|
34
|
+
const timestamp = new Date().toISOString();
|
|
35
|
+
const humanLine = `${timestamp} [${level.toUpperCase()}] ${message}\n`;
|
|
36
|
+
process.stderr.write(humanLine);
|
|
37
|
+
this.textStream?.write(humanLine);
|
|
38
|
+
const entry = { timestamp, level, message };
|
|
39
|
+
if (data !== undefined) {
|
|
40
|
+
entry.data = data;
|
|
41
|
+
}
|
|
42
|
+
this.jsonStream?.write(JSON.stringify(entry) + "\n");
|
|
43
|
+
}
|
|
44
|
+
debug(message, data) {
|
|
45
|
+
this.log("debug", message, data);
|
|
46
|
+
}
|
|
47
|
+
info(message, data) {
|
|
48
|
+
this.log("info", message, data);
|
|
49
|
+
}
|
|
50
|
+
warn(message, data) {
|
|
51
|
+
this.log("warn", message, data);
|
|
52
|
+
}
|
|
53
|
+
error(message, data) {
|
|
54
|
+
this.log("error", message, data);
|
|
55
|
+
}
|
|
56
|
+
close() {
|
|
57
|
+
this.textStream?.end();
|
|
58
|
+
this.jsonStream?.end();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
export function createLogger(level, logDir) {
|
|
62
|
+
return new Logger(level, logDir);
|
|
63
|
+
}
|
|
64
|
+
/** Pre-config logger: stderr-only at info level. Replaced after startup. */
|
|
65
|
+
export let logger = new Logger("info");
|
|
66
|
+
/**
|
|
67
|
+
* Initialize the fully-configured logger with file outputs.
|
|
68
|
+
* Replaces the module-level `logger` export.
|
|
69
|
+
*/
|
|
70
|
+
export function initLogger(level, logDir) {
|
|
71
|
+
logger.close();
|
|
72
|
+
logger = new Logger(level, logDir);
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cc-cli.d.ts","sourceRoot":"","sources":["../../src/services/cc-cli.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAG5C,wBAAgB,UAAU,CACxB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,aAAa,CAAC,CAqExB"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { getConfig } from "../config.js";
|
|
3
|
+
export function execClaude(sessionId, message, cwd) {
|
|
4
|
+
return new Promise((resolve) => {
|
|
5
|
+
const config = getConfig();
|
|
6
|
+
// Apply character limit: 0 means no truncation
|
|
7
|
+
const truncated = config.CC_BRIDGE_CHAR_LIMIT > 0 &&
|
|
8
|
+
message.length > config.CC_BRIDGE_CHAR_LIMIT
|
|
9
|
+
? message.slice(0, config.CC_BRIDGE_CHAR_LIMIT) + "\n...[truncated]"
|
|
10
|
+
: message;
|
|
11
|
+
const args = ["--resume", sessionId, "-p", truncated];
|
|
12
|
+
execFile(config.CC_BRIDGE_CLAUDE_PATH, args, {
|
|
13
|
+
cwd,
|
|
14
|
+
timeout: config.CC_BRIDGE_TIMEOUT_MS,
|
|
15
|
+
maxBuffer: 10 * 1024 * 1024,
|
|
16
|
+
env: { ...process.env },
|
|
17
|
+
}, (error, stdout, stderr) => {
|
|
18
|
+
if (error) {
|
|
19
|
+
const execError = error;
|
|
20
|
+
// Detect timeout: process was killed by SIGTERM from timeout
|
|
21
|
+
if (execError.killed && execError.signal === "SIGTERM") {
|
|
22
|
+
resolve({
|
|
23
|
+
stdout: stdout || "",
|
|
24
|
+
stderr: `CLI_TIMEOUT: CLI subprocess timed out after ${config.CC_BRIDGE_TIMEOUT_MS}ms. Increase CC_BRIDGE_TIMEOUT_MS if needed.`,
|
|
25
|
+
exitCode: null,
|
|
26
|
+
});
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
// Detect missing binary
|
|
30
|
+
if (execError.code === "ENOENT") {
|
|
31
|
+
resolve({
|
|
32
|
+
stdout: "",
|
|
33
|
+
stderr: `CLI_NOT_FOUND: '${config.CC_BRIDGE_CLAUDE_PATH}' not found. Install Claude Code or set CC_BRIDGE_CLAUDE_PATH.`,
|
|
34
|
+
exitCode: 127,
|
|
35
|
+
});
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
// Other errors: include exit code and stderr
|
|
39
|
+
const exitCode = typeof execError.code === "number"
|
|
40
|
+
? Number(execError.code)
|
|
41
|
+
: error.code ?? 1;
|
|
42
|
+
resolve({
|
|
43
|
+
stdout: stdout || "",
|
|
44
|
+
stderr: `CLI_EXEC_FAILED: claude exited with code ${exitCode}. stderr: ${stderr || error.message}`,
|
|
45
|
+
exitCode,
|
|
46
|
+
});
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
resolve({
|
|
50
|
+
stdout: stdout || "",
|
|
51
|
+
stderr: stderr || "",
|
|
52
|
+
exitCode: 0,
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=cc-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cc-cli.js","sourceRoot":"","sources":["../../src/services/cc-cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAEzC,MAAM,UAAU,UAAU,CACxB,SAAiB,EACjB,OAAe,EACf,GAAW;IAEX,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAE3B,+CAA+C;QAC/C,MAAM,SAAS,GACb,MAAM,CAAC,oBAAoB,GAAG,CAAC;YAC/B,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,oBAAoB;YAC1C,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,oBAAoB,CAAC,GAAG,kBAAkB;YACpE,CAAC,CAAC,OAAO,CAAC;QAEd,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;QAEtD,QAAQ,CACN,MAAM,CAAC,qBAAqB,EAC5B,IAAI,EACJ;YACE,GAAG;YACH,OAAO,EAAE,MAAM,CAAC,oBAAoB;YACpC,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI;YAC3B,GAAG,EAAE,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE;SACxB,EACD,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;YACxB,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,SAAS,GAAG,KAGjB,CAAC;gBAEF,6DAA6D;gBAC7D,IAAI,SAAS,CAAC,MAAM,IAAI,SAAS,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;oBACvD,OAAO,CAAC;wBACN,MAAM,EAAE,MAAM,IAAI,EAAE;wBACpB,MAAM,EAAE,+CAA+C,MAAM,CAAC,oBAAoB,8CAA8C;wBAChI,QAAQ,EAAE,IAAI;qBACf,CAAC,CAAC;oBACH,OAAO;gBACT,CAAC;gBAED,wBAAwB;gBACxB,IAAI,SAAS,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBAChC,OAAO,CAAC;wBACN,MAAM,EAAE,EAAE;wBACV,MAAM,EAAE,mBAAmB,MAAM,CAAC,qBAAqB,gEAAgE;wBACvH,QAAQ,EAAE,GAAG;qBACd,CAAC,CAAC;oBACH,OAAO;gBACT,CAAC;gBAED,6CAA6C;gBAC7C,MAAM,QAAQ,GACZ,OAAO,SAAS,CAAC,IAAI,KAAK,QAAQ;oBAChC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC;oBACxB,CAAC,CAAE,KAAsC,CAAC,IAAI,IAAI,CAAC,CAAC;gBACxD,OAAO,CAAC;oBACN,MAAM,EAAE,MAAM,IAAI,EAAE;oBACpB,MAAM,EAAE,4CAA4C,QAAQ,aAAa,MAAM,IAAI,KAAK,CAAC,OAAO,EAAE;oBAClG,QAAQ;iBACT,CAAC,CAAC;gBACH,OAAO;YACT,CAAC;YACD,OAAO,CAAC;gBACN,MAAM,EAAE,MAAM,IAAI,EAAE;gBACpB,MAAM,EAAE,MAAM,IAAI,EAAE;gBACpB,QAAQ,EAAE,CAAC;aACZ,CAAC,CAAC;QACL,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
interface CheckResult {
|
|
2
|
+
ok: boolean;
|
|
3
|
+
message: string;
|
|
4
|
+
}
|
|
5
|
+
interface ClaudeCliCheckResult extends CheckResult {
|
|
6
|
+
version?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface HealthCheckResult {
|
|
9
|
+
healthy: boolean;
|
|
10
|
+
serverVersion: string;
|
|
11
|
+
statePath: string;
|
|
12
|
+
claudePath: string;
|
|
13
|
+
checks: {
|
|
14
|
+
stateFile: CheckResult;
|
|
15
|
+
lockMechanism: CheckResult;
|
|
16
|
+
claudeCli: ClaudeCliCheckResult;
|
|
17
|
+
};
|
|
18
|
+
timestamp: string;
|
|
19
|
+
}
|
|
20
|
+
/** Run all health checks and return a comprehensive result. */
|
|
21
|
+
export declare function checkHealth(): Promise<HealthCheckResult>;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=health-check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health-check.d.ts","sourceRoot":"","sources":["../../src/services/health-check.ts"],"names":[],"mappings":"AAUA,UAAU,WAAW;IACnB,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,UAAU,oBAAqB,SAAQ,WAAW;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE;QACN,SAAS,EAAE,WAAW,CAAC;QACvB,aAAa,EAAE,WAAW,CAAC;QAC3B,SAAS,EAAE,oBAAoB,CAAC;KACjC,CAAC;IACF,SAAS,EAAE,MAAM,CAAC;CACnB;AA+ED,+DAA+D;AAC/D,wBAAsB,WAAW,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAqB9D"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { execFile } from "node:child_process";
|
|
4
|
+
import { getConfig } from "../config.js";
|
|
5
|
+
import { SERVER_VERSION } from "../constants.js";
|
|
6
|
+
/* ------------------------------------------------------------------ */
|
|
7
|
+
/* Derive paths from config at call time (not module load time) */
|
|
8
|
+
/* ------------------------------------------------------------------ */
|
|
9
|
+
function getStatePath() {
|
|
10
|
+
return path.join(getConfig().CC_BRIDGE_STATE_PATH, "cc-bridge-state.json");
|
|
11
|
+
}
|
|
12
|
+
/* ------------------------------------------------------------------ */
|
|
13
|
+
/* Sub-checks */
|
|
14
|
+
/* ------------------------------------------------------------------ */
|
|
15
|
+
/** HLTH-01: Check state file accessibility. */
|
|
16
|
+
async function checkStateFile() {
|
|
17
|
+
const statePath = getStatePath();
|
|
18
|
+
const dir = path.dirname(statePath);
|
|
19
|
+
try {
|
|
20
|
+
await fs.access(dir, fs.constants.R_OK | fs.constants.W_OK);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return { ok: false, message: `State directory not accessible: ${dir}` };
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
const raw = await fs.readFile(statePath, "utf-8");
|
|
27
|
+
JSON.parse(raw);
|
|
28
|
+
return { ok: true, message: "State file readable and valid JSON" };
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
if (err.code === "ENOENT") {
|
|
32
|
+
return { ok: true, message: "State directory writable (no state file yet)" };
|
|
33
|
+
}
|
|
34
|
+
if (err instanceof SyntaxError) {
|
|
35
|
+
return { ok: false, message: "State file exists but contains invalid JSON" };
|
|
36
|
+
}
|
|
37
|
+
return { ok: false, message: `State file error: ${err.message}` };
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/** HLTH-02: Check lock mechanism with a separate health-check lock path. */
|
|
41
|
+
async function checkLockMechanism() {
|
|
42
|
+
const healthLockPath = getStatePath() + ".health-lock";
|
|
43
|
+
try {
|
|
44
|
+
await fs.writeFile(healthLockPath, String(process.pid), { flag: "wx" });
|
|
45
|
+
try {
|
|
46
|
+
await fs.unlink(healthLockPath);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// Cleanup failure is non-fatal
|
|
50
|
+
}
|
|
51
|
+
return { ok: true, message: "Lock acquire/release cycle succeeded" };
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
if (err.code === "EEXIST") {
|
|
55
|
+
return { ok: false, message: "Health check lock file exists unexpectedly" };
|
|
56
|
+
}
|
|
57
|
+
return { ok: false, message: `Lock mechanism error: ${err.message}` };
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/** HLTH-03: Check Claude CLI availability. */
|
|
61
|
+
function checkClaudeCli() {
|
|
62
|
+
const claudePath = getConfig().CC_BRIDGE_CLAUDE_PATH;
|
|
63
|
+
return new Promise((resolve) => {
|
|
64
|
+
execFile(claudePath, ["--version"], { timeout: 5000 }, (error, stdout) => {
|
|
65
|
+
if (error) {
|
|
66
|
+
resolve({ ok: false, message: `Claude CLI not found at '${claudePath}'` });
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
resolve({ ok: true, message: "Claude CLI found", version: (stdout || "").trim() });
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
/* ------------------------------------------------------------------ */
|
|
74
|
+
/* Public API */
|
|
75
|
+
/* ------------------------------------------------------------------ */
|
|
76
|
+
/** Run all health checks and return a comprehensive result. */
|
|
77
|
+
export async function checkHealth() {
|
|
78
|
+
const config = getConfig();
|
|
79
|
+
// Run all three checks (not short-circuiting)
|
|
80
|
+
const [stateFile, lockMechanism, claudeCli] = await Promise.all([
|
|
81
|
+
checkStateFile(),
|
|
82
|
+
checkLockMechanism(),
|
|
83
|
+
checkClaudeCli(),
|
|
84
|
+
]);
|
|
85
|
+
const checks = { stateFile, lockMechanism, claudeCli };
|
|
86
|
+
const healthy = Object.values(checks).every((c) => c.ok);
|
|
87
|
+
return {
|
|
88
|
+
healthy,
|
|
89
|
+
serverVersion: SERVER_VERSION,
|
|
90
|
+
statePath: path.join(config.CC_BRIDGE_STATE_PATH, "cc-bridge-state.json"),
|
|
91
|
+
claudePath: config.CC_BRIDGE_CLAUDE_PATH,
|
|
92
|
+
checks,
|
|
93
|
+
timestamp: new Date().toISOString(),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=health-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health-check.js","sourceRoot":"","sources":["../../src/services/health-check.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { PeerInfo, MessageRecord } from "../types.js";
|
|
2
|
+
export declare function registerPeer(peerId: string, sessionId: string, cwd: string, label: string): Promise<PeerInfo>;
|
|
3
|
+
export declare function updateLastSeen(peerId: string): Promise<void>;
|
|
4
|
+
export declare function deregisterPeer(peerId: string): Promise<boolean>;
|
|
5
|
+
export declare function getPeer(peerId: string): Promise<PeerInfo | undefined>;
|
|
6
|
+
export declare function listPeers(): Promise<PeerInfo[]>;
|
|
7
|
+
export declare function recordMessage(record: Omit<MessageRecord, "id" | "timestamp">): Promise<MessageRecord>;
|
|
8
|
+
export declare function getHistory(peerId?: string, limit?: number): Promise<MessageRecord[]>;
|
|
9
|
+
//# sourceMappingURL=peer-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"peer-registry.d.ts","sourceRoot":"","sources":["../../src/services/peer-registry.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAgKtD,wBAAsB,YAAY,CAChC,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,QAAQ,CAAC,CAgBnB;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CASlE;AAED,wBAAsB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQrE;AAED,wBAAsB,OAAO,CAC3B,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAG/B;AAED,wBAAsB,SAAS,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,CAGrD;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,IAAI,GAAG,WAAW,CAAC,GAC9C,OAAO,CAAC,aAAa,CAAC,CAgBxB;AAED,wBAAsB,UAAU,CAC9B,MAAM,CAAC,EAAE,MAAM,EACf,KAAK,SAAK,GACT,OAAO,CAAC,aAAa,EAAE,CAAC,CAS1B"}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { getConfig } from "../config.js";
|
|
5
|
+
import { logger } from "../logger.js";
|
|
6
|
+
import { BridgeError, BridgeErrorCode } from "../errors.js";
|
|
7
|
+
/* ------------------------------------------------------------------ */
|
|
8
|
+
/* File-based shared state */
|
|
9
|
+
/* Two or more MCP server processes share a state JSON file */
|
|
10
|
+
/* State path is config-driven via CC_BRIDGE_STATE_PATH */
|
|
11
|
+
/* ------------------------------------------------------------------ */
|
|
12
|
+
const MAX_MESSAGES = 500;
|
|
13
|
+
const LOCK_RETRY_MS = 50;
|
|
14
|
+
const LOCK_MAX_WAIT_MS = 5_000;
|
|
15
|
+
/** Derive state file path from config at call time (not module load time). */
|
|
16
|
+
function getStatePath() {
|
|
17
|
+
return path.join(getConfig().CC_BRIDGE_STATE_PATH, "cc-bridge-state.json");
|
|
18
|
+
}
|
|
19
|
+
/** Derive lock file path from state path at call time. */
|
|
20
|
+
function getLockPath() {
|
|
21
|
+
return getStatePath() + ".lock";
|
|
22
|
+
}
|
|
23
|
+
/* ---- low-level helpers ------------------------------------------- */
|
|
24
|
+
function emptyState() {
|
|
25
|
+
return { peers: {}, messages: [] };
|
|
26
|
+
}
|
|
27
|
+
/** Migrate legacy state: ensure all peers have lastSeenAt field. */
|
|
28
|
+
function migrateState(state) {
|
|
29
|
+
for (const peer of Object.values(state.peers)) {
|
|
30
|
+
if (!peer.lastSeenAt) {
|
|
31
|
+
peer.lastSeenAt = peer.registeredAt;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return state;
|
|
35
|
+
}
|
|
36
|
+
async function readState() {
|
|
37
|
+
const statePath = getStatePath();
|
|
38
|
+
try {
|
|
39
|
+
const raw = await fs.readFile(statePath, "utf-8");
|
|
40
|
+
return migrateState(JSON.parse(raw));
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
if (err.code === "ENOENT") {
|
|
44
|
+
return migrateState(emptyState());
|
|
45
|
+
}
|
|
46
|
+
if (err instanceof SyntaxError) {
|
|
47
|
+
// Corrupt JSON -- auto-recover with backup
|
|
48
|
+
const backupPath = statePath + ".corrupt." + Date.now();
|
|
49
|
+
try {
|
|
50
|
+
await fs.copyFile(statePath, backupPath);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// Backup failure is non-fatal
|
|
54
|
+
}
|
|
55
|
+
logger.warn(`STATE_CORRUPT: State file corrupt (invalid JSON), backed up to ${backupPath}. Starting with empty state.`);
|
|
56
|
+
return migrateState(emptyState());
|
|
57
|
+
}
|
|
58
|
+
throw new BridgeError(BridgeErrorCode.STATE_WRITE_FAILED, `Failed to read state file: ${err.message}`, `Check permissions on ${statePath}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async function writeState(state) {
|
|
62
|
+
const statePath = getStatePath();
|
|
63
|
+
const tmp = statePath + "." + process.pid + ".tmp";
|
|
64
|
+
try {
|
|
65
|
+
await fs.writeFile(tmp, JSON.stringify(state, null, 2), "utf-8");
|
|
66
|
+
await fs.rename(tmp, statePath); // atomic on same filesystem
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
throw new BridgeError(BridgeErrorCode.STATE_WRITE_FAILED, `Failed to write state file: ${err.message}`, `Check permissions on ${statePath}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/* ---- file-lock (O_CREAT | O_EXCL) ------------------------------- */
|
|
73
|
+
async function acquireLock() {
|
|
74
|
+
const lockPath = getLockPath();
|
|
75
|
+
const deadline = Date.now() + LOCK_MAX_WAIT_MS;
|
|
76
|
+
while (Date.now() < deadline) {
|
|
77
|
+
try {
|
|
78
|
+
// Atomic create-if-not-exists
|
|
79
|
+
await fs.writeFile(lockPath, String(process.pid), {
|
|
80
|
+
flag: "wx", // O_WRONLY | O_CREAT | O_EXCL
|
|
81
|
+
});
|
|
82
|
+
return; // lock acquired
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
if (err.code === "EEXIST") {
|
|
86
|
+
// Check for stale lock (process died)
|
|
87
|
+
try {
|
|
88
|
+
const content = await fs.readFile(lockPath, "utf-8");
|
|
89
|
+
const lockPid = parseInt(content, 10);
|
|
90
|
+
if (!isNaN(lockPid)) {
|
|
91
|
+
try {
|
|
92
|
+
process.kill(lockPid, 0); // just checks existence
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
// Process doesn't exist -- stale lock
|
|
96
|
+
logger.info(`Cleaned up stale lock from PID ${lockPid}`);
|
|
97
|
+
await fs.unlink(lockPath).catch(() => { });
|
|
98
|
+
continue; // retry immediately
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch { /* lock file disappeared, retry */
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
await sleep(LOCK_RETRY_MS);
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
throw err;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// Timeout -- read lock to report holder PID
|
|
112
|
+
let lockPid = "unknown";
|
|
113
|
+
try {
|
|
114
|
+
const content = await fs.readFile(lockPath, "utf-8");
|
|
115
|
+
lockPid = content.trim();
|
|
116
|
+
}
|
|
117
|
+
catch { /* ignore read failure */ }
|
|
118
|
+
throw new BridgeError(BridgeErrorCode.LOCK_TIMEOUT, `Failed to acquire lock within ${LOCK_MAX_WAIT_MS}ms (held by PID ${lockPid})`, `Another cc-bridge process may be stuck. Delete ${lockPath} if no other instance is running.`);
|
|
119
|
+
}
|
|
120
|
+
async function releaseLock() {
|
|
121
|
+
await fs.unlink(getLockPath()).catch(() => { });
|
|
122
|
+
}
|
|
123
|
+
function sleep(ms) {
|
|
124
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
125
|
+
}
|
|
126
|
+
/** Run a mutating operation under an exclusive file lock. */
|
|
127
|
+
async function withLock(fn) {
|
|
128
|
+
await acquireLock();
|
|
129
|
+
try {
|
|
130
|
+
return await fn();
|
|
131
|
+
}
|
|
132
|
+
finally {
|
|
133
|
+
await releaseLock();
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/* ---- public API (all async) -------------------------------------- */
|
|
137
|
+
export async function registerPeer(peerId, sessionId, cwd, label) {
|
|
138
|
+
return withLock(async () => {
|
|
139
|
+
const state = await readState();
|
|
140
|
+
const now = new Date().toISOString();
|
|
141
|
+
const peer = {
|
|
142
|
+
peerId,
|
|
143
|
+
sessionId,
|
|
144
|
+
cwd,
|
|
145
|
+
label,
|
|
146
|
+
registeredAt: now,
|
|
147
|
+
lastSeenAt: now,
|
|
148
|
+
};
|
|
149
|
+
state.peers[peerId] = peer;
|
|
150
|
+
await writeState(state);
|
|
151
|
+
return peer;
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
export async function updateLastSeen(peerId) {
|
|
155
|
+
return withLock(async () => {
|
|
156
|
+
const state = await readState();
|
|
157
|
+
const peer = state.peers[peerId];
|
|
158
|
+
if (peer) {
|
|
159
|
+
peer.lastSeenAt = new Date().toISOString();
|
|
160
|
+
await writeState(state);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
export async function deregisterPeer(peerId) {
|
|
165
|
+
return withLock(async () => {
|
|
166
|
+
const state = await readState();
|
|
167
|
+
if (!(peerId in state.peers))
|
|
168
|
+
return false;
|
|
169
|
+
delete state.peers[peerId];
|
|
170
|
+
await writeState(state);
|
|
171
|
+
return true;
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
export async function getPeer(peerId) {
|
|
175
|
+
const state = await readState();
|
|
176
|
+
return state.peers[peerId];
|
|
177
|
+
}
|
|
178
|
+
export async function listPeers() {
|
|
179
|
+
const state = await readState();
|
|
180
|
+
return Object.values(state.peers);
|
|
181
|
+
}
|
|
182
|
+
export async function recordMessage(record) {
|
|
183
|
+
return withLock(async () => {
|
|
184
|
+
const state = await readState();
|
|
185
|
+
const full = {
|
|
186
|
+
...record,
|
|
187
|
+
id: crypto.randomUUID(),
|
|
188
|
+
timestamp: new Date().toISOString(),
|
|
189
|
+
};
|
|
190
|
+
state.messages.push(full);
|
|
191
|
+
// Cap history to prevent unbounded growth
|
|
192
|
+
if (state.messages.length > MAX_MESSAGES) {
|
|
193
|
+
state.messages = state.messages.slice(-MAX_MESSAGES);
|
|
194
|
+
}
|
|
195
|
+
await writeState(state);
|
|
196
|
+
return full;
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
export async function getHistory(peerId, limit = 50) {
|
|
200
|
+
const state = await readState();
|
|
201
|
+
let filtered = state.messages;
|
|
202
|
+
if (peerId) {
|
|
203
|
+
filtered = state.messages.filter((m) => m.fromPeerId === peerId || m.toPeerId === peerId);
|
|
204
|
+
}
|
|
205
|
+
return filtered.slice(-limit);
|
|
206
|
+
}
|
|
207
|
+
//# sourceMappingURL=peer-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"peer-registry.js","sourceRoot":"","sources":["../../src/services/peer-registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"startup.d.ts","sourceRoot":"","sources":["../src/startup.ts"],"names":[],"mappings":"AAqHA,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAuChD"}
|
package/dist/startup.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import os from "node:os";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import fs from "node:fs/promises";
|
|
4
|
+
import readline from "node:readline";
|
|
5
|
+
import { execFile } from "node:child_process";
|
|
6
|
+
import { promisify } from "node:util";
|
|
7
|
+
import { loadConfig, getConfig } from "./config.js";
|
|
8
|
+
import { initLogger, logger } from "./logger.js";
|
|
9
|
+
import { BridgeError, BridgeErrorCode } from "./errors.js";
|
|
10
|
+
const execFileAsync = promisify(execFile);
|
|
11
|
+
const PERSIST_PATH = path.join(os.homedir(), ".cc-bridge-config.json");
|
|
12
|
+
async function loadPersistedConfig() {
|
|
13
|
+
try {
|
|
14
|
+
const raw = await fs.readFile(PERSIST_PATH, "utf-8");
|
|
15
|
+
return JSON.parse(raw);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return {};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
async function savePersistedConfig(config) {
|
|
22
|
+
try {
|
|
23
|
+
await fs.writeFile(PERSIST_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
27
|
+
logger.warn(`Could not save config to ${PERSIST_PATH}: ${msg}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
// First-run interactive prompt
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
async function firstRunPrompt(defaultPath) {
|
|
34
|
+
// Non-TTY (MCP host context): use defaults silently
|
|
35
|
+
if (!process.stdin.isTTY) {
|
|
36
|
+
return defaultPath;
|
|
37
|
+
}
|
|
38
|
+
// Check if persisted config already exists (not first run)
|
|
39
|
+
const persisted = await loadPersistedConfig();
|
|
40
|
+
if (persisted.statePath) {
|
|
41
|
+
return persisted.statePath;
|
|
42
|
+
}
|
|
43
|
+
// First run with TTY -- prompt the user
|
|
44
|
+
const rl = readline.createInterface({
|
|
45
|
+
input: process.stdin,
|
|
46
|
+
output: process.stderr, // CRITICAL: output to stderr, not stdout
|
|
47
|
+
});
|
|
48
|
+
return new Promise((resolve) => {
|
|
49
|
+
rl.question(`\nFirst run detected. Where should cc-bridge store its data?\n` +
|
|
50
|
+
` Default: ${defaultPath}\n` +
|
|
51
|
+
` Press Enter to accept, or type a custom path: `, async (answer) => {
|
|
52
|
+
rl.close();
|
|
53
|
+
const chosen = answer.trim() || defaultPath;
|
|
54
|
+
await savePersistedConfig({ statePath: chosen });
|
|
55
|
+
resolve(chosen);
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
// ---------------------------------------------------------------------------
|
|
60
|
+
// Validation helpers
|
|
61
|
+
// ---------------------------------------------------------------------------
|
|
62
|
+
async function validateStateDir(statePath) {
|
|
63
|
+
await fs.mkdir(statePath, { recursive: true });
|
|
64
|
+
const testFile = path.join(statePath, ".write-test");
|
|
65
|
+
try {
|
|
66
|
+
await fs.writeFile(testFile, "test", "utf-8");
|
|
67
|
+
await fs.unlink(testFile);
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
throw new BridgeError(BridgeErrorCode.STARTUP_FAILED, `Cannot write to state directory: ${statePath}`, "Check permissions or set CC_BRIDGE_STATE_PATH to a writable directory");
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
async function checkClaudeCli(claudePath) {
|
|
74
|
+
try {
|
|
75
|
+
const { stdout } = await execFileAsync(claudePath, ["--version"], {
|
|
76
|
+
timeout: 5000,
|
|
77
|
+
});
|
|
78
|
+
logger.info(`Claude CLI detected: ${stdout.trim()}`);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
logger.warn(`CLI_NOT_FOUND: '${claudePath}' not found on PATH. ` +
|
|
82
|
+
`cc_send_message will fail until Claude Code is installed. ` +
|
|
83
|
+
`Set CC_BRIDGE_CLAUDE_PATH if installed in a non-standard location.`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// ---------------------------------------------------------------------------
|
|
87
|
+
// Main startup flow
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
export async function runStartup() {
|
|
90
|
+
// Determine state path: env var takes precedence, then first-run prompt
|
|
91
|
+
const envStatePath = process.env.CC_BRIDGE_STATE_PATH;
|
|
92
|
+
let statePath;
|
|
93
|
+
if (envStatePath) {
|
|
94
|
+
statePath = envStatePath;
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
const defaultPath = path.join(os.homedir(), "cloud_code_bridge");
|
|
98
|
+
statePath = await firstRunPrompt(defaultPath);
|
|
99
|
+
}
|
|
100
|
+
// If the prompt chose a different path, set it in env for loadConfig
|
|
101
|
+
if (!envStatePath && statePath !== path.join(os.homedir(), "cloud_code_bridge")) {
|
|
102
|
+
process.env.CC_BRIDGE_STATE_PATH = statePath;
|
|
103
|
+
}
|
|
104
|
+
else if (!envStatePath) {
|
|
105
|
+
// Ensure the default or persisted path is available to loadConfig
|
|
106
|
+
process.env.CC_BRIDGE_STATE_PATH = statePath;
|
|
107
|
+
}
|
|
108
|
+
// Load and freeze config
|
|
109
|
+
loadConfig();
|
|
110
|
+
const config = getConfig();
|
|
111
|
+
// Initialize full logger with file outputs
|
|
112
|
+
initLogger(config.CC_BRIDGE_LOG_LEVEL, path.join(config.CC_BRIDGE_STATE_PATH, "logs"));
|
|
113
|
+
// Validate state directory writability
|
|
114
|
+
await validateStateDir(config.CC_BRIDGE_STATE_PATH);
|
|
115
|
+
// Check for claude CLI (warn-only)
|
|
116
|
+
await checkClaudeCli(config.CC_BRIDGE_CLAUDE_PATH);
|
|
117
|
+
logger.info(`Startup complete. State: ${config.CC_BRIDGE_STATE_PATH}, Log level: ${config.CC_BRIDGE_LOG_LEVEL}`);
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=startup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"startup.js","sourceRoot":"","sources":["../src/startup.ts"],"names":[],"mappings":"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"}
|