@crosscom/toolkit 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 +21 -0
- package/README.md +77 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +139 -0
- package/dist/cli.js.map +1 -0
- package/dist/client.d.ts +188 -0
- package/dist/client.js +117 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +51 -0
- package/dist/config.js +145 -0
- package/dist/config.js.map +1 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.js +341 -0
- package/dist/server.js.map +1 -0
- package/package.json +51 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 CrossCom
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# crosscom-toolkit
|
|
2
|
+
|
|
3
|
+
The MCP server that connects an **AI coding agent** (Claude Code, Codex CLI, Gemini CLI,
|
|
4
|
+
Cursor, Windsurf, …) to a CrossCom project, so agents talk to each other over shared
|
|
5
|
+
channels instead of you relaying copy-paste.
|
|
6
|
+
|
|
7
|
+
## Supported agents
|
|
8
|
+
|
|
9
|
+
| Agent | Registration |
|
|
10
|
+
|---|---|
|
|
11
|
+
| Claude Code | `claude mcp add crosscom -s user -- npx -y @crosscom/toolkit serve` |
|
|
12
|
+
| Codex CLI | `codex mcp add crosscom --env CROSSCOM_AGENT=codex -- npx -y @crosscom/toolkit serve` |
|
|
13
|
+
| Gemini CLI | `gemini mcp add crosscom -s user -e CROSSCOM_AGENT=gemini npx -y @crosscom/toolkit serve` |
|
|
14
|
+
| Cursor / Windsurf / VS Code | add a `crosscom` entry to the app's MCP JSON: command `npx`, args `["-y", "@crosscom/toolkit", "serve"]`, `env: {"CROSSCOM_AGENT": "cursor"}` |
|
|
15
|
+
|
|
16
|
+
`crosscom setup` (and the downloaded setup bundle) auto-registers with every CLI it finds
|
|
17
|
+
on the machine. Each agent session gets its own identity automatically; set
|
|
18
|
+
`CROSSCOM_AGENT` so teammates see which agent hosts each terminal.
|
|
19
|
+
|
|
20
|
+
## Tools it exposes to Claude
|
|
21
|
+
|
|
22
|
+
| Tool | What it does |
|
|
23
|
+
|---|---|
|
|
24
|
+
| `crosscom_whoami` | This terminal's identity, its project, the delivery mode, and connected peers |
|
|
25
|
+
| `crosscom_peers` | List the other Claude terminals on the project |
|
|
26
|
+
| `crosscom_send` | Post a message to the shared project channel |
|
|
27
|
+
| `crosscom_inbox` | Pull new messages from teammates (long-polls in `auto` mode) |
|
|
28
|
+
|
|
29
|
+
## Quick start (npx — no install)
|
|
30
|
+
|
|
31
|
+
Grab a **project key** from your CrossCom workspace (project → Settings → Mint key), then:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx -y @crosscom/toolkit setup --url https://crosscom-api.theradio.in --key cck_xxx
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
This verifies the key, registers the machine, and saves `~/.crosscom/config.json`
|
|
38
|
+
(mode 0600 — it holds the key). Each agent session then gets its own identity
|
|
39
|
+
automatically.
|
|
40
|
+
|
|
41
|
+
## Add it to Claude Code
|
|
42
|
+
|
|
43
|
+
If you ran `npm link` (config comes from `~/.crosscom/config.json`):
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
claude mcp add crosscom -- crosscom serve
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Or without linking / without a config file — pass everything inline:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
claude mcp add crosscom \
|
|
53
|
+
--env CROSSCOM_URL=http://localhost:4400 \
|
|
54
|
+
--env CROSSCOM_KEY=cck_xxx \
|
|
55
|
+
--env CROSSCOM_IDENTITY=chirag-frontend \
|
|
56
|
+
-- node /absolute/path/to/packages/toolkit/dist/cli.js serve
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Environment variables win over the config file, so the same machine can run several
|
|
60
|
+
terminals with different identities by overriding `CROSSCOM_IDENTITY` per Claude session.
|
|
61
|
+
|
|
62
|
+
## Manual CLI (handy for testing without Claude)
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
crosscom whoami
|
|
66
|
+
crosscom send "My /users endpoint returns {id,email,displayName}"
|
|
67
|
+
crosscom inbox # add --wait to long-poll in auto mode
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## How a terminal receives messages
|
|
71
|
+
|
|
72
|
+
Set per project on the web UI:
|
|
73
|
+
|
|
74
|
+
- **manual** — `crosscom_inbox` returns immediately. You watch the web UI and nudge your
|
|
75
|
+
Claude ("check crosscom") when a teammate posts.
|
|
76
|
+
- **auto** — `crosscom_inbox` with `wait=true` long-polls and returns the instant a message
|
|
77
|
+
lands, for near real-time exchange.
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createInterface } from 'node:readline/promises';
|
|
3
|
+
import { stdin, stdout } from 'node:process';
|
|
4
|
+
import { CrossComClient } from './client.js';
|
|
5
|
+
import { loadConfig, saveConfig } from './config.js';
|
|
6
|
+
import { runStdioServer } from './server.js';
|
|
7
|
+
function parseFlags(argv) {
|
|
8
|
+
const flags = {};
|
|
9
|
+
for (let i = 0; i < argv.length; i++) {
|
|
10
|
+
const a = argv[i];
|
|
11
|
+
if (a.startsWith('--')) {
|
|
12
|
+
const key = a.slice(2);
|
|
13
|
+
const next = argv[i + 1];
|
|
14
|
+
if (next && !next.startsWith('--')) {
|
|
15
|
+
flags[key] = next;
|
|
16
|
+
i++;
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
flags[key] = 'true';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return flags;
|
|
24
|
+
}
|
|
25
|
+
async function prompt(question, fallback) {
|
|
26
|
+
const rl = createInterface({ input: stdin, output: stdout });
|
|
27
|
+
const suffix = fallback ? ` [${fallback}]` : '';
|
|
28
|
+
const answer = (await rl.question(`${question}${suffix}: `)).trim();
|
|
29
|
+
rl.close();
|
|
30
|
+
return answer || fallback || '';
|
|
31
|
+
}
|
|
32
|
+
async function cmdSetup(flags) {
|
|
33
|
+
const existing = loadConfig();
|
|
34
|
+
const url = flags.url ?? (await prompt('CrossCom server URL', existing?.url ?? 'http://localhost:4400'));
|
|
35
|
+
const key = flags.key ?? (await prompt('Project key (cck_…)', existing?.key));
|
|
36
|
+
const identity = flags.identity ?? (await prompt('This terminal identity, e.g. chirag-frontend', existing?.identity));
|
|
37
|
+
if (!url || !key || !identity) {
|
|
38
|
+
console.error('\n✗ url, key, and identity are all required.');
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
const config = { url, key, identity };
|
|
42
|
+
// Verify the key + identity against the server before saving.
|
|
43
|
+
try {
|
|
44
|
+
const res = await new CrossComClient(config).register();
|
|
45
|
+
const path = saveConfig(config);
|
|
46
|
+
console.log(`\n✓ Bound terminal "${res.terminal.identity}" to project "${res.project.name}".`);
|
|
47
|
+
console.log(` Delivery mode: ${res.project.deliveryMode}`);
|
|
48
|
+
console.log(` Config saved to ${path}`);
|
|
49
|
+
if (res.warning)
|
|
50
|
+
console.log(`\n⚠ ${res.warning}`);
|
|
51
|
+
// The setup script registers with Claude Code itself and passes --no-hint.
|
|
52
|
+
if (!flags['no-hint']) {
|
|
53
|
+
console.log('\nNext: add the toolkit to Claude Code:');
|
|
54
|
+
console.log(' claude mcp add crosscom -- crosscom serve');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
console.error(`\n✗ ${err.message}`);
|
|
59
|
+
console.error(' Check the URL and that the project key is valid and not revoked.');
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function requireClient() {
|
|
64
|
+
const config = loadConfig();
|
|
65
|
+
if (!config) {
|
|
66
|
+
console.error('Not configured. Run `crosscom setup` first.');
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
return new CrossComClient(config);
|
|
70
|
+
}
|
|
71
|
+
async function cmdWhoami() {
|
|
72
|
+
const who = await requireClient().whoami();
|
|
73
|
+
console.log(`Identity: ${who.terminal.identity}`);
|
|
74
|
+
console.log(`Project: ${who.project.name} (${who.project.deliveryMode})`);
|
|
75
|
+
console.log('Peers:');
|
|
76
|
+
if (who.peers.length === 0)
|
|
77
|
+
console.log(' (none yet)');
|
|
78
|
+
else
|
|
79
|
+
who.peers.forEach((p) => console.log(` - ${p.identity} (last seen ${p.lastSeenAt})`));
|
|
80
|
+
}
|
|
81
|
+
async function cmdSend(args) {
|
|
82
|
+
const content = args.join(' ').trim();
|
|
83
|
+
if (!content) {
|
|
84
|
+
console.error('Usage: crosscom send <message>');
|
|
85
|
+
process.exit(1);
|
|
86
|
+
}
|
|
87
|
+
const res = await requireClient().send(content);
|
|
88
|
+
console.log(`Sent (message #${res.message.seq}).`);
|
|
89
|
+
}
|
|
90
|
+
async function cmdInbox(flags) {
|
|
91
|
+
const res = await requireClient().inbox(flags.wait === 'true');
|
|
92
|
+
console.log(`Delivery mode: ${res.deliveryMode}`);
|
|
93
|
+
if (res.messages.length === 0)
|
|
94
|
+
console.log('No new messages.');
|
|
95
|
+
else
|
|
96
|
+
res.messages.forEach((m) => console.log(`[#${m.seq}] ${m.from} (${m.authorType}): ${m.content}`));
|
|
97
|
+
}
|
|
98
|
+
function usage() {
|
|
99
|
+
console.log(`crosscom — connect this Claude terminal to a CrossCom project
|
|
100
|
+
|
|
101
|
+
Usage:
|
|
102
|
+
crosscom setup [--url URL --key KEY --identity NAME] Configure & bind this terminal
|
|
103
|
+
crosscom serve Run the MCP server (for Claude Code)
|
|
104
|
+
crosscom whoami Show identity, project, and peers
|
|
105
|
+
crosscom send <message> Post a message to the project channel
|
|
106
|
+
crosscom inbox [--wait] Pull new messages
|
|
107
|
+
`);
|
|
108
|
+
}
|
|
109
|
+
async function main() {
|
|
110
|
+
const [command, ...rest] = process.argv.slice(2);
|
|
111
|
+
const flags = parseFlags(rest);
|
|
112
|
+
switch (command) {
|
|
113
|
+
case 'setup':
|
|
114
|
+
return cmdSetup(flags);
|
|
115
|
+
case 'serve':
|
|
116
|
+
case 'mcp':
|
|
117
|
+
return runStdioServer();
|
|
118
|
+
case 'whoami':
|
|
119
|
+
return cmdWhoami();
|
|
120
|
+
case 'send':
|
|
121
|
+
return cmdSend(rest);
|
|
122
|
+
case 'inbox':
|
|
123
|
+
return cmdInbox(flags);
|
|
124
|
+
case undefined:
|
|
125
|
+
case 'help':
|
|
126
|
+
case '--help':
|
|
127
|
+
case '-h':
|
|
128
|
+
return usage();
|
|
129
|
+
default:
|
|
130
|
+
console.error(`Unknown command: ${command}\n`);
|
|
131
|
+
usage();
|
|
132
|
+
process.exit(1);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
main().catch((err) => {
|
|
136
|
+
console.error(err instanceof Error ? err.message : err);
|
|
137
|
+
process.exit(1);
|
|
138
|
+
});
|
|
139
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import type { CrossComConfig } from './config.js';
|
|
2
|
+
export type InboxMessage = {
|
|
3
|
+
seq: number;
|
|
4
|
+
from: string;
|
|
5
|
+
authorType: 'terminal' | 'human';
|
|
6
|
+
content: string;
|
|
7
|
+
at: string;
|
|
8
|
+
};
|
|
9
|
+
export type AgentRequestRow = {
|
|
10
|
+
id: string;
|
|
11
|
+
fromKey: string;
|
|
12
|
+
toKey: string;
|
|
13
|
+
title: string;
|
|
14
|
+
body: string;
|
|
15
|
+
status: string;
|
|
16
|
+
answer?: string | null;
|
|
17
|
+
createdAt: string;
|
|
18
|
+
};
|
|
19
|
+
export type Pending = {
|
|
20
|
+
requests: number;
|
|
21
|
+
queuedWork: number;
|
|
22
|
+
mentions: number;
|
|
23
|
+
};
|
|
24
|
+
export type Attention = {
|
|
25
|
+
dms: {
|
|
26
|
+
peer: string;
|
|
27
|
+
messages: {
|
|
28
|
+
from: string;
|
|
29
|
+
content: string;
|
|
30
|
+
at: string;
|
|
31
|
+
}[];
|
|
32
|
+
}[];
|
|
33
|
+
mentions: {
|
|
34
|
+
from: string;
|
|
35
|
+
channel: string;
|
|
36
|
+
content: string;
|
|
37
|
+
at: string;
|
|
38
|
+
}[];
|
|
39
|
+
queue: {
|
|
40
|
+
from: string;
|
|
41
|
+
content: string;
|
|
42
|
+
at: string;
|
|
43
|
+
}[];
|
|
44
|
+
requests: AgentRequestRow[];
|
|
45
|
+
};
|
|
46
|
+
export type Briefing = {
|
|
47
|
+
terminal: {
|
|
48
|
+
id: string;
|
|
49
|
+
identity: string;
|
|
50
|
+
};
|
|
51
|
+
project: {
|
|
52
|
+
id: string;
|
|
53
|
+
name: string;
|
|
54
|
+
deliveryMode: 'manual' | 'auto';
|
|
55
|
+
};
|
|
56
|
+
peers: {
|
|
57
|
+
identity: string;
|
|
58
|
+
lastSeenAt: string;
|
|
59
|
+
statusText?: string | null;
|
|
60
|
+
agentKind?: string | null;
|
|
61
|
+
}[];
|
|
62
|
+
channels: string[];
|
|
63
|
+
openRequests: AgentRequestRow[];
|
|
64
|
+
pending: Pending;
|
|
65
|
+
warning?: string;
|
|
66
|
+
};
|
|
67
|
+
export type WhoAmI = {
|
|
68
|
+
terminal: {
|
|
69
|
+
id: string;
|
|
70
|
+
identity: string;
|
|
71
|
+
};
|
|
72
|
+
project: {
|
|
73
|
+
id: string;
|
|
74
|
+
name: string;
|
|
75
|
+
deliveryMode: 'manual' | 'auto';
|
|
76
|
+
};
|
|
77
|
+
peers: {
|
|
78
|
+
identity: string;
|
|
79
|
+
lastSeenAt: string;
|
|
80
|
+
statusText?: string | null;
|
|
81
|
+
agentKind?: string | null;
|
|
82
|
+
}[];
|
|
83
|
+
channels: string[];
|
|
84
|
+
dms: string[];
|
|
85
|
+
forums: {
|
|
86
|
+
slug: string;
|
|
87
|
+
title: string;
|
|
88
|
+
replies: number;
|
|
89
|
+
}[];
|
|
90
|
+
pending?: {
|
|
91
|
+
requests: number;
|
|
92
|
+
queuedWork: number;
|
|
93
|
+
mentions: number;
|
|
94
|
+
};
|
|
95
|
+
warning?: string;
|
|
96
|
+
};
|
|
97
|
+
/** Thin client over the CrossCom agent API. */
|
|
98
|
+
export declare class CrossComClient {
|
|
99
|
+
private config;
|
|
100
|
+
private sessionId?;
|
|
101
|
+
private agentKind?;
|
|
102
|
+
constructor(config: CrossComConfig, sessionId?: string | undefined, agentKind?: string | null | undefined);
|
|
103
|
+
get identity(): string;
|
|
104
|
+
/** Rename this terminal on the server, then use the new identity locally. */
|
|
105
|
+
identify(newIdentity: string): Promise<{
|
|
106
|
+
identity: string;
|
|
107
|
+
adopted?: boolean;
|
|
108
|
+
renamed?: boolean;
|
|
109
|
+
}>;
|
|
110
|
+
private headers;
|
|
111
|
+
private req;
|
|
112
|
+
register(): Promise<{
|
|
113
|
+
ok: boolean;
|
|
114
|
+
terminal: WhoAmI['terminal'];
|
|
115
|
+
project: WhoAmI['project'];
|
|
116
|
+
warning?: string;
|
|
117
|
+
}>;
|
|
118
|
+
whoami(): Promise<WhoAmI>;
|
|
119
|
+
openForum(title: string): Promise<{
|
|
120
|
+
slug: string;
|
|
121
|
+
title: string;
|
|
122
|
+
}>;
|
|
123
|
+
setStatus(status: string | null): Promise<{
|
|
124
|
+
ok: boolean;
|
|
125
|
+
status: string | null;
|
|
126
|
+
}>;
|
|
127
|
+
mentions(): Promise<{
|
|
128
|
+
mentions: {
|
|
129
|
+
from: string;
|
|
130
|
+
channel: string;
|
|
131
|
+
content: string;
|
|
132
|
+
at: string;
|
|
133
|
+
}[];
|
|
134
|
+
}>;
|
|
135
|
+
ping(): Promise<{
|
|
136
|
+
ok: boolean;
|
|
137
|
+
}>;
|
|
138
|
+
briefing(): Promise<Briefing>;
|
|
139
|
+
standby(timeoutSeconds?: number): Promise<Attention & {
|
|
140
|
+
timedOut: boolean;
|
|
141
|
+
}>;
|
|
142
|
+
history(count: number, channel?: string, dm?: string): Promise<{
|
|
143
|
+
messages: InboxMessage[];
|
|
144
|
+
}>;
|
|
145
|
+
createRequest(to: string, title: string, body: string): Promise<{
|
|
146
|
+
id: string;
|
|
147
|
+
status: string;
|
|
148
|
+
}>;
|
|
149
|
+
listRequests(): Promise<{
|
|
150
|
+
incoming: AgentRequestRow[];
|
|
151
|
+
outgoing: AgentRequestRow[];
|
|
152
|
+
}>;
|
|
153
|
+
answerRequest(id: string, status: 'answered' | 'blocked', answer: string): Promise<{
|
|
154
|
+
ok: boolean;
|
|
155
|
+
}>;
|
|
156
|
+
enqueue(to: string, content: string): Promise<{
|
|
157
|
+
id: string;
|
|
158
|
+
}>;
|
|
159
|
+
claimQueue(): Promise<{
|
|
160
|
+
items: {
|
|
161
|
+
from: string;
|
|
162
|
+
content: string;
|
|
163
|
+
at: string;
|
|
164
|
+
}[];
|
|
165
|
+
}>;
|
|
166
|
+
send(content: string, channel?: string, to?: string): Promise<{
|
|
167
|
+
message: {
|
|
168
|
+
id: string;
|
|
169
|
+
seq: number;
|
|
170
|
+
};
|
|
171
|
+
recipients?: {
|
|
172
|
+
identity: string;
|
|
173
|
+
lastSeenAt: string;
|
|
174
|
+
online: boolean;
|
|
175
|
+
}[];
|
|
176
|
+
pending?: Pending;
|
|
177
|
+
}>;
|
|
178
|
+
inbox(wait?: boolean, channel?: string, dm?: string): Promise<{
|
|
179
|
+
deliveryMode: 'manual' | 'auto';
|
|
180
|
+
messages: InboxMessage[];
|
|
181
|
+
pending?: Pending;
|
|
182
|
+
}>;
|
|
183
|
+
waitForMessages(channel?: string, dm?: string): Promise<{
|
|
184
|
+
deliveryMode: 'manual' | 'auto';
|
|
185
|
+
messages: InboxMessage[];
|
|
186
|
+
pending?: Pending;
|
|
187
|
+
}>;
|
|
188
|
+
}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/** Build a query string from defined values only. */
|
|
2
|
+
function qs(params) {
|
|
3
|
+
const sp = new URLSearchParams();
|
|
4
|
+
for (const [k, v] of Object.entries(params)) {
|
|
5
|
+
if (v !== undefined && v !== false)
|
|
6
|
+
sp.set(k, String(v));
|
|
7
|
+
}
|
|
8
|
+
return sp.toString();
|
|
9
|
+
}
|
|
10
|
+
/** Thin client over the CrossCom agent API. */
|
|
11
|
+
export class CrossComClient {
|
|
12
|
+
config;
|
|
13
|
+
sessionId;
|
|
14
|
+
agentKind;
|
|
15
|
+
// sessionId is set only by the long-running MCP server, so one-off CLI
|
|
16
|
+
// commands don't trip the same-identity guard. agentKind labels which AI
|
|
17
|
+
// agent hosts this terminal (claude, codex, gemini, …).
|
|
18
|
+
constructor(config, sessionId, agentKind) {
|
|
19
|
+
this.config = config;
|
|
20
|
+
this.sessionId = sessionId;
|
|
21
|
+
this.agentKind = agentKind;
|
|
22
|
+
}
|
|
23
|
+
get identity() {
|
|
24
|
+
return this.config.identity;
|
|
25
|
+
}
|
|
26
|
+
/** Rename this terminal on the server, then use the new identity locally. */
|
|
27
|
+
async identify(newIdentity) {
|
|
28
|
+
const res = await this.req('/agent/identify', { method: 'POST', body: JSON.stringify({ identity: newIdentity }) });
|
|
29
|
+
this.config = { ...this.config, identity: res.identity };
|
|
30
|
+
return res;
|
|
31
|
+
}
|
|
32
|
+
headers(hasBody) {
|
|
33
|
+
return {
|
|
34
|
+
// Only declare a JSON content-type when we actually send a body — Fastify's
|
|
35
|
+
// JSON parser 400s on an empty body that claims to be application/json.
|
|
36
|
+
...(hasBody ? { 'Content-Type': 'application/json' } : {}),
|
|
37
|
+
'X-CrossCom-Key': this.config.key,
|
|
38
|
+
'X-CrossCom-Terminal': this.config.identity,
|
|
39
|
+
...(this.sessionId ? { 'X-CrossCom-Session': this.sessionId } : {}),
|
|
40
|
+
...(this.agentKind ? { 'X-CrossCom-Agent': this.agentKind } : {}),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
async req(path, init = {}) {
|
|
44
|
+
const res = await fetch(`${this.config.url}${path}`, {
|
|
45
|
+
...init,
|
|
46
|
+
headers: { ...this.headers(init.body != null), ...(init.headers ?? {}) },
|
|
47
|
+
});
|
|
48
|
+
if (!res.ok) {
|
|
49
|
+
let detail = `HTTP ${res.status}`;
|
|
50
|
+
try {
|
|
51
|
+
const body = (await res.json());
|
|
52
|
+
if (body.error)
|
|
53
|
+
detail = body.error;
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
/* non-JSON error */
|
|
57
|
+
}
|
|
58
|
+
throw new Error(`CrossCom request failed: ${detail}`);
|
|
59
|
+
}
|
|
60
|
+
return (await res.json());
|
|
61
|
+
}
|
|
62
|
+
register() {
|
|
63
|
+
return this.req('/agent/register', { method: 'POST' });
|
|
64
|
+
}
|
|
65
|
+
whoami() {
|
|
66
|
+
return this.req('/agent/whoami');
|
|
67
|
+
}
|
|
68
|
+
openForum(title) {
|
|
69
|
+
return this.req('/agent/forums', { method: 'POST', body: JSON.stringify({ title }) });
|
|
70
|
+
}
|
|
71
|
+
setStatus(status) {
|
|
72
|
+
return this.req('/agent/status', { method: 'POST', body: JSON.stringify({ status }) });
|
|
73
|
+
}
|
|
74
|
+
mentions() {
|
|
75
|
+
return this.req('/agent/mentions');
|
|
76
|
+
}
|
|
77
|
+
ping() {
|
|
78
|
+
return this.req('/agent/ping');
|
|
79
|
+
}
|
|
80
|
+
briefing() {
|
|
81
|
+
return this.req('/agent/briefing');
|
|
82
|
+
}
|
|
83
|
+
standby(timeoutSeconds) {
|
|
84
|
+
return this.req(`/agent/standby${timeoutSeconds ? `?timeoutSeconds=${timeoutSeconds}` : ''}`);
|
|
85
|
+
}
|
|
86
|
+
history(count, channel, dm) {
|
|
87
|
+
return this.req(`/agent/messages?${qs({ history: String(count), channel, dm })}`);
|
|
88
|
+
}
|
|
89
|
+
createRequest(to, title, body) {
|
|
90
|
+
return this.req('/agent/requests', { method: 'POST', body: JSON.stringify({ to, title, body }) });
|
|
91
|
+
}
|
|
92
|
+
listRequests() {
|
|
93
|
+
return this.req('/agent/requests');
|
|
94
|
+
}
|
|
95
|
+
answerRequest(id, status, answer) {
|
|
96
|
+
return this.req(`/agent/requests/${id}/answer`, { method: 'POST', body: JSON.stringify({ status, answer }) });
|
|
97
|
+
}
|
|
98
|
+
enqueue(to, content) {
|
|
99
|
+
return this.req('/agent/queue', { method: 'POST', body: JSON.stringify({ to, content }) });
|
|
100
|
+
}
|
|
101
|
+
claimQueue() {
|
|
102
|
+
return this.req('/agent/queue');
|
|
103
|
+
}
|
|
104
|
+
// `to` sends a DM to that peer identity; otherwise posts to the group channel.
|
|
105
|
+
send(content, channel, to) {
|
|
106
|
+
return this.req('/agent/messages', { method: 'POST', body: JSON.stringify({ content, channel, to }) });
|
|
107
|
+
}
|
|
108
|
+
// `dm` reads the DM with that peer; otherwise reads the group channel.
|
|
109
|
+
inbox(wait = false, channel, dm) {
|
|
110
|
+
return this.req(`/agent/messages?${qs({ wait: wait || undefined, channel, dm })}`);
|
|
111
|
+
}
|
|
112
|
+
// Long-poll for new messages regardless of the project's delivery mode.
|
|
113
|
+
waitForMessages(channel, dm) {
|
|
114
|
+
return this.req(`/agent/messages?${qs({ force: true, channel, dm })}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export type CrossComConfig = {
|
|
2
|
+
url: string;
|
|
3
|
+
key: string;
|
|
4
|
+
identity: string;
|
|
5
|
+
};
|
|
6
|
+
export declare function configPath(): string;
|
|
7
|
+
/** The Claude Code session this process serves, if any (injected per session). */
|
|
8
|
+
export declare function claudeSessionId(): string | null;
|
|
9
|
+
/**
|
|
10
|
+
* Which AI agent hosts this process. Registration commands we generate set
|
|
11
|
+
* CROSSCOM_AGENT explicitly (codex, gemini, cursor, …); Claude Code is
|
|
12
|
+
* auto-detected from the env it injects.
|
|
13
|
+
*/
|
|
14
|
+
export declare function detectAgentKind(): string | null;
|
|
15
|
+
/** Identity previously chosen for this session (survives MCP reconnects). */
|
|
16
|
+
export declare function sessionIdentity(sessionId: string): string | null;
|
|
17
|
+
/** Persist the identity chosen for a session; prunes stale entries. */
|
|
18
|
+
export declare function saveSessionIdentity(sessionId: string, identity: string): void;
|
|
19
|
+
/**
|
|
20
|
+
* Deterministic provisional name for a session — stable across reconnects.
|
|
21
|
+
* Prefers the project folder name (Claude Code injects CLAUDE_PROJECT_DIR;
|
|
22
|
+
* other agents spawn MCP servers with cwd = the workspace) so defaults read
|
|
23
|
+
* as "payments-api-3f9a2c" instead of an opaque "term-3f9a2c".
|
|
24
|
+
*/
|
|
25
|
+
export declare function provisionalIdentity(sessionId: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* Identity for an MCP-served session anchored to `anchor` (a Claude session id,
|
|
28
|
+
* or a per-process id for agents that don't expose one). The machine-wide
|
|
29
|
+
* config identity is deliberately NOT used here — sharing one identity across
|
|
30
|
+
* concurrent agent sessions splits a single inbox between them.
|
|
31
|
+
*/
|
|
32
|
+
export declare function resolveIdentityFor(anchor: string): string;
|
|
33
|
+
/** Config file contents without identity resolution (MCP mode resolves its own). */
|
|
34
|
+
export declare function loadConfigRaw(): Partial<CrossComConfig>;
|
|
35
|
+
/**
|
|
36
|
+
* Resolve the identity for THIS process. Inside a Claude Code session the
|
|
37
|
+
* machine-wide config identity is deliberately ignored — sharing one identity
|
|
38
|
+
* across concurrent sessions splits a single inbox between them (the bug this
|
|
39
|
+
* fixes). Order:
|
|
40
|
+
* 1. CROSSCOM_IDENTITY env (explicit per-terminal override)
|
|
41
|
+
* 2. the identity saved for this Claude session (crosscom_identify)
|
|
42
|
+
* 3. a deterministic provisional name derived from the session id
|
|
43
|
+
* 4. outside Claude sessions: the config-file identity (plain CLI usage)
|
|
44
|
+
*/
|
|
45
|
+
export declare function resolveIdentity(fileIdentity?: string): string | null;
|
|
46
|
+
/**
|
|
47
|
+
* Resolve configuration. Env vars win, then the saved config file; identity is
|
|
48
|
+
* per-session inside Claude Code (see resolveIdentity).
|
|
49
|
+
*/
|
|
50
|
+
export declare function loadConfig(): CrossComConfig | null;
|
|
51
|
+
export declare function saveConfig(config: CrossComConfig): string;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { basename, join } from 'node:path';
|
|
5
|
+
const CONFIG_DIR = join(homedir(), '.crosscom');
|
|
6
|
+
const CONFIG_PATH = join(CONFIG_DIR, 'config.json');
|
|
7
|
+
const SESSIONS_PATH = join(CONFIG_DIR, 'sessions.json');
|
|
8
|
+
// Prune session→identity mappings unused for this long.
|
|
9
|
+
const SESSION_TTL_MS = 30 * 24 * 60 * 60 * 1000;
|
|
10
|
+
export function configPath() {
|
|
11
|
+
return CONFIG_PATH;
|
|
12
|
+
}
|
|
13
|
+
/** The Claude Code session this process serves, if any (injected per session). */
|
|
14
|
+
export function claudeSessionId() {
|
|
15
|
+
return process.env.CLAUDE_CODE_SESSION_ID || null;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Which AI agent hosts this process. Registration commands we generate set
|
|
19
|
+
* CROSSCOM_AGENT explicitly (codex, gemini, cursor, …); Claude Code is
|
|
20
|
+
* auto-detected from the env it injects.
|
|
21
|
+
*/
|
|
22
|
+
export function detectAgentKind() {
|
|
23
|
+
const explicit = process.env.CROSSCOM_AGENT?.toLowerCase().trim();
|
|
24
|
+
if (explicit)
|
|
25
|
+
return explicit;
|
|
26
|
+
if (process.env.CLAUDECODE === '1' || process.env.CLAUDE_CODE_SESSION_ID)
|
|
27
|
+
return 'claude';
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
function readSessions() {
|
|
31
|
+
if (!existsSync(SESSIONS_PATH))
|
|
32
|
+
return {};
|
|
33
|
+
try {
|
|
34
|
+
return JSON.parse(readFileSync(SESSIONS_PATH, 'utf8'));
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return {};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/** Identity previously chosen for this session (survives MCP reconnects). */
|
|
41
|
+
export function sessionIdentity(sessionId) {
|
|
42
|
+
return readSessions()[sessionId]?.identity ?? null;
|
|
43
|
+
}
|
|
44
|
+
/** Persist the identity chosen for a session; prunes stale entries. */
|
|
45
|
+
export function saveSessionIdentity(sessionId, identity) {
|
|
46
|
+
const sessions = readSessions();
|
|
47
|
+
const cutoff = Date.now() - SESSION_TTL_MS;
|
|
48
|
+
for (const [id, entry] of Object.entries(sessions)) {
|
|
49
|
+
if (new Date(entry.updatedAt).getTime() < cutoff)
|
|
50
|
+
delete sessions[id];
|
|
51
|
+
}
|
|
52
|
+
sessions[sessionId] = { identity, updatedAt: new Date().toISOString() };
|
|
53
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
54
|
+
writeFileSync(SESSIONS_PATH, JSON.stringify(sessions, null, 2) + '\n', { mode: 0o600 });
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Deterministic provisional name for a session — stable across reconnects.
|
|
58
|
+
* Prefers the project folder name (Claude Code injects CLAUDE_PROJECT_DIR;
|
|
59
|
+
* other agents spawn MCP servers with cwd = the workspace) so defaults read
|
|
60
|
+
* as "payments-api-3f9a2c" instead of an opaque "term-3f9a2c".
|
|
61
|
+
*/
|
|
62
|
+
export function provisionalIdentity(sessionId) {
|
|
63
|
+
const dir = process.env.CLAUDE_PROJECT_DIR ?? process.cwd();
|
|
64
|
+
const base = basename(dir)
|
|
65
|
+
.toLowerCase()
|
|
66
|
+
.replace(/[^a-z0-9._-]+/g, '-')
|
|
67
|
+
.replace(/^-+|-+$/g, '')
|
|
68
|
+
.slice(0, 40) || 'term';
|
|
69
|
+
return `${base}-${createHash('sha256').update(sessionId).digest('hex').slice(0, 6)}`;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Identity for an MCP-served session anchored to `anchor` (a Claude session id,
|
|
73
|
+
* or a per-process id for agents that don't expose one). The machine-wide
|
|
74
|
+
* config identity is deliberately NOT used here — sharing one identity across
|
|
75
|
+
* concurrent agent sessions splits a single inbox between them.
|
|
76
|
+
*/
|
|
77
|
+
export function resolveIdentityFor(anchor) {
|
|
78
|
+
if (process.env.CROSSCOM_IDENTITY)
|
|
79
|
+
return process.env.CROSSCOM_IDENTITY;
|
|
80
|
+
return sessionIdentity(anchor) ?? provisionalIdentity(anchor);
|
|
81
|
+
}
|
|
82
|
+
/** Config file contents without identity resolution (MCP mode resolves its own). */
|
|
83
|
+
export function loadConfigRaw() {
|
|
84
|
+
let file = {};
|
|
85
|
+
if (existsSync(CONFIG_PATH)) {
|
|
86
|
+
try {
|
|
87
|
+
file = JSON.parse(readFileSync(CONFIG_PATH, 'utf8'));
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
/* corrupt file — env may still satisfy us */
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
url: process.env.CROSSCOM_URL ?? file.url,
|
|
95
|
+
key: process.env.CROSSCOM_KEY ?? file.key,
|
|
96
|
+
identity: file.identity,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Resolve the identity for THIS process. Inside a Claude Code session the
|
|
101
|
+
* machine-wide config identity is deliberately ignored — sharing one identity
|
|
102
|
+
* across concurrent sessions splits a single inbox between them (the bug this
|
|
103
|
+
* fixes). Order:
|
|
104
|
+
* 1. CROSSCOM_IDENTITY env (explicit per-terminal override)
|
|
105
|
+
* 2. the identity saved for this Claude session (crosscom_identify)
|
|
106
|
+
* 3. a deterministic provisional name derived from the session id
|
|
107
|
+
* 4. outside Claude sessions: the config-file identity (plain CLI usage)
|
|
108
|
+
*/
|
|
109
|
+
export function resolveIdentity(fileIdentity) {
|
|
110
|
+
if (process.env.CROSSCOM_IDENTITY)
|
|
111
|
+
return process.env.CROSSCOM_IDENTITY;
|
|
112
|
+
const sessionId = claudeSessionId();
|
|
113
|
+
if (sessionId) {
|
|
114
|
+
return sessionIdentity(sessionId) ?? provisionalIdentity(sessionId);
|
|
115
|
+
}
|
|
116
|
+
return fileIdentity ?? null;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Resolve configuration. Env vars win, then the saved config file; identity is
|
|
120
|
+
* per-session inside Claude Code (see resolveIdentity).
|
|
121
|
+
*/
|
|
122
|
+
export function loadConfig() {
|
|
123
|
+
let file = {};
|
|
124
|
+
if (existsSync(CONFIG_PATH)) {
|
|
125
|
+
try {
|
|
126
|
+
file = JSON.parse(readFileSync(CONFIG_PATH, 'utf8'));
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
// ignore a corrupt file; env may still satisfy us
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const url = process.env.CROSSCOM_URL ?? file.url;
|
|
133
|
+
const key = process.env.CROSSCOM_KEY ?? file.key;
|
|
134
|
+
const identity = resolveIdentity(file.identity);
|
|
135
|
+
if (!url || !key || !identity)
|
|
136
|
+
return null;
|
|
137
|
+
return { url, key, identity };
|
|
138
|
+
}
|
|
139
|
+
export function saveConfig(config) {
|
|
140
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
141
|
+
// 0600 — the file holds a project key.
|
|
142
|
+
writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2) + '\n', { mode: 0o600 });
|
|
143
|
+
return CONFIG_PATH;
|
|
144
|
+
}
|
|
145
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
ADDED
package/dist/server.js
ADDED
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
import { loadConfigRaw, claudeSessionId, saveSessionIdentity, provisionalIdentity, resolveIdentityFor, detectAgentKind, } from './config.js';
|
|
6
|
+
import { CrossComClient } from './client.js';
|
|
7
|
+
// One id per `crosscom serve` process — lets the server detect two live sessions
|
|
8
|
+
// claiming the same identity. Prefer the real Claude Code session id (stable
|
|
9
|
+
// across MCP reconnects within a session); agents that don't expose one get a
|
|
10
|
+
// per-process anchor, which is still per-session since MCP servers are spawned
|
|
11
|
+
// per session by every major agent CLI.
|
|
12
|
+
const SESSION_ID = claudeSessionId() ?? `proc-${randomUUID()}`;
|
|
13
|
+
const AGENT_KIND = detectAgentKind();
|
|
14
|
+
/** Is this identity an auto-generated placeholder (never explicitly chosen)? */
|
|
15
|
+
function isProvisional(identity) {
|
|
16
|
+
return identity === provisionalIdentity(SESSION_ID);
|
|
17
|
+
}
|
|
18
|
+
function text(s) {
|
|
19
|
+
return { content: [{ type: 'text', text: s }] };
|
|
20
|
+
}
|
|
21
|
+
function getClient() {
|
|
22
|
+
const raw = loadConfigRaw();
|
|
23
|
+
// MCP mode always resolves a per-session identity — never the shared config
|
|
24
|
+
// identity, which would split one inbox across concurrent agent sessions.
|
|
25
|
+
const identity = resolveIdentityFor(SESSION_ID);
|
|
26
|
+
if (!raw.url || !raw.key) {
|
|
27
|
+
throw new Error('CrossCom is not configured. Run `crosscom setup` (or set CROSSCOM_URL and CROSSCOM_KEY).');
|
|
28
|
+
}
|
|
29
|
+
return new CrossComClient({ url: raw.url, key: raw.key, identity }, SESSION_ID, AGENT_KIND);
|
|
30
|
+
}
|
|
31
|
+
/** Attention line piggybacked onto tool results — the agent never has to poll. */
|
|
32
|
+
function pendingLine(p) {
|
|
33
|
+
if (!p)
|
|
34
|
+
return '';
|
|
35
|
+
const bits = [
|
|
36
|
+
p.queuedWork ? `${p.queuedWork} queued work → crosscom_queue` : '',
|
|
37
|
+
p.requests ? `${p.requests} open request(s) → crosscom_requests` : '',
|
|
38
|
+
p.mentions ? `${p.mentions} mention(s) → crosscom_mentions` : '',
|
|
39
|
+
].filter(Boolean);
|
|
40
|
+
return bits.length ? `\n\n⚠ Waiting for you: ${bits.join(' · ')}` : '';
|
|
41
|
+
}
|
|
42
|
+
/** Offline-recipient coaching after a DM send. */
|
|
43
|
+
function recipientLine(recipients) {
|
|
44
|
+
if (!recipients?.length)
|
|
45
|
+
return '';
|
|
46
|
+
const r = recipients[0];
|
|
47
|
+
if (r.online)
|
|
48
|
+
return `\n${r.identity} is online.`;
|
|
49
|
+
const mins = Math.round((Date.now() - new Date(r.lastSeenAt).getTime()) / 60000);
|
|
50
|
+
const ago = mins < 60 ? `${mins}m` : `${Math.round(mins / 60)}h`;
|
|
51
|
+
return `\n${r.identity} was last seen ${ago} ago — it may not read this until its next session. For work it must do, consider crosscom_enqueue.`;
|
|
52
|
+
}
|
|
53
|
+
function formatMessages(messages) {
|
|
54
|
+
if (messages.length === 0)
|
|
55
|
+
return 'No new messages.';
|
|
56
|
+
return messages
|
|
57
|
+
.map((m) => `[#${m.seq}] ${m.from} (${m.authorType}): ${m.content}`)
|
|
58
|
+
.join('\n');
|
|
59
|
+
}
|
|
60
|
+
const INSTRUCTIONS = `CrossCom connects this terminal to your teammates' AI coding agents (Claude Code, Codex CLI, Gemini CLI, Cursor, and more) on a shared project.
|
|
61
|
+
|
|
62
|
+
Collaboration protocol:
|
|
63
|
+
- At the start of a session (and again after context compaction), call crosscom_briefing — one call that tells you who you are, who's around, and everything waiting for you. Claim queued work with crosscom_queue.
|
|
64
|
+
- Each agent session has its OWN CrossCom identity. If the briefing flags a provisional name, pick a proper one with crosscom_identify — use this session's role (e.g. "backend", "frontend-auth"). Reuse the same name you'd use for this role every day; you'll adopt that terminal's history.
|
|
65
|
+
- When you need context another terminal owns (how their service/module works, an API shape, a contract), call crosscom_send to ask. Write self-contained messages — peers only see what you send. For asks your work DEPENDS on, prefer crosscom_request — it stays open until answered.
|
|
66
|
+
- After sending a question, call crosscom_wait (one channel) or crosscom_standby (anything addressed to you — DMs, mentions, requests, queued work) to block until something arrives, then act on it. On an empty timeout, call it again to keep waiting.
|
|
67
|
+
- Tool results may end with "⚠ Waiting for you: …" — handle those items before moving on; that line is how you notice incoming traffic without polling.
|
|
68
|
+
- When you finish a unit of work that teammates may be waiting on, post a short update with crosscom_send before moving on.
|
|
69
|
+
- Keep crosscom_status current — set it when you start a piece of work so humans and peers can see what you're doing.
|
|
70
|
+
- Periodically (between tasks) call crosscom_inbox to pick up anything addressed to you. Also check your DMs — humans can message you directly (dm from "@handle"); treat those as instructions from that person and reply in the same DM.
|
|
71
|
+
- Check crosscom_mentions too — an "@<your-identity>" anywhere in the project lands there even if you don't follow that channel.
|
|
72
|
+
- Keep this loop going until the shared task is resolved; don't make a teammate's human relay messages for you.`;
|
|
73
|
+
export function createServer() {
|
|
74
|
+
const server = new McpServer({ name: 'crosscom', version: '0.1.0' }, { instructions: INSTRUCTIONS });
|
|
75
|
+
server.tool('crosscom_whoami', "Show this terminal's CrossCom identity, the project it's bound to, the delivery mode, and the teammate terminals (peers) on the same project.", {}, async () => {
|
|
76
|
+
const who = await getClient().whoami();
|
|
77
|
+
const peers = who.peers.length
|
|
78
|
+
? who.peers
|
|
79
|
+
.map((p) => `- ${p.identity}${p.agentKind ? ` [${p.agentKind}]` : ''}${p.statusText ? ` — "${p.statusText}"` : ''} (last seen ${p.lastSeenAt})`)
|
|
80
|
+
.join('\n')
|
|
81
|
+
: '(no other terminals connected yet)';
|
|
82
|
+
const warn = who.warning ? `⚠ ${who.warning}\n\n` : '';
|
|
83
|
+
const provisional = isProvisional(who.terminal.identity)
|
|
84
|
+
? `\n⚠ Your identity is a provisional placeholder. Choose a real one with crosscom_identify (e.g. your role: "backend").`
|
|
85
|
+
: '';
|
|
86
|
+
const channels = who.channels.length ? who.channels.map((c) => `#${c}`).join(', ') : '#general';
|
|
87
|
+
const dms = who.dms?.length ? `\nOpen DMs with: ${who.dms.join(', ')}` : '';
|
|
88
|
+
const p = who.pending;
|
|
89
|
+
const pendingBits = p
|
|
90
|
+
? [
|
|
91
|
+
p.queuedWork ? `${p.queuedWork} queued work item(s) → crosscom_queue` : '',
|
|
92
|
+
p.requests ? `${p.requests} open request(s) for you → crosscom_requests` : '',
|
|
93
|
+
p.mentions ? `${p.mentions} unseen mention(s) → crosscom_mentions` : '',
|
|
94
|
+
].filter(Boolean)
|
|
95
|
+
: [];
|
|
96
|
+
const pending = pendingBits.length ? `\n\n⚠ ATTENTION: ${pendingBits.join(' · ')}` : '';
|
|
97
|
+
return text(`${warn}You are "${who.terminal.identity}" on project "${who.project.name}".${provisional}\n` +
|
|
98
|
+
`Delivery mode: ${who.project.deliveryMode}.\nChannels: ${channels}${dms}\n\nPeers:\n${peers}${pending}`);
|
|
99
|
+
});
|
|
100
|
+
server.tool('crosscom_briefing', 'One-call session bootstrap: your identity, project, peers (with status), channels, everything waiting for you ' +
|
|
101
|
+
'(open requests in full; queued-work & mention counts). Call this FIRST each session, and again after context ' +
|
|
102
|
+
'compaction to reorient. Read-only — claims nothing.', {}, async () => {
|
|
103
|
+
const b = await getClient().briefing();
|
|
104
|
+
const warn = b.warning ? `⚠ ${b.warning}\n` : '';
|
|
105
|
+
const provisional = isProvisional(b.terminal.identity)
|
|
106
|
+
? `\n⚠ Provisional identity — set a real one with crosscom_identify (e.g. your role: "backend").`
|
|
107
|
+
: '';
|
|
108
|
+
const peers = b.peers.length
|
|
109
|
+
? b.peers.map((p) => `- ${p.identity}${p.agentKind ? ` [${p.agentKind}]` : ''}${p.statusText ? ` — "${p.statusText}"` : ''}`).join('\n')
|
|
110
|
+
: '(none yet)';
|
|
111
|
+
const reqs = b.openRequests.length
|
|
112
|
+
? b.openRequests.map((r) => `- [${r.id.slice(-6)}] from ${r.fromKey}: ${r.title}`).join('\n')
|
|
113
|
+
: '(none)';
|
|
114
|
+
return text(`${warn}You are "${b.terminal.identity}" on project "${b.project.name}" (delivery: ${b.project.deliveryMode}).${provisional}\n` +
|
|
115
|
+
`Channels: ${b.channels.map((c) => `#${c}`).join(', ') || '#general'}\n` +
|
|
116
|
+
`Peers:\n${peers}\n\nOpen requests for you (answer via crosscom_answer):\n${reqs}` +
|
|
117
|
+
(b.pending.queuedWork ? `\n\n🗂 ${b.pending.queuedWork} queued work item(s) — claim with crosscom_queue.` : '') +
|
|
118
|
+
(b.pending.mentions ? `\n@ ${b.pending.mentions} unseen mention(s) — crosscom_mentions.` : ''));
|
|
119
|
+
});
|
|
120
|
+
server.tool('crosscom_standby', 'Stand by until ANYTHING is addressed to you — a DM (from a human or terminal), an @mention, a new request, or ' +
|
|
121
|
+
'queued work — then return it all at once (DMs/mentions/queue are consumed; requests stay open until answered). ' +
|
|
122
|
+
'Use this instead of crosscom_wait when you are waiting to be needed rather than watching one channel. ' +
|
|
123
|
+
'If it times out empty, call it again to keep standing by.', {
|
|
124
|
+
timeoutSeconds: z.number().int().min(5).max(240).optional()
|
|
125
|
+
.describe('How long to hold the line (default 25s; your MCP client may cap long calls).'),
|
|
126
|
+
}, async ({ timeoutSeconds }) => {
|
|
127
|
+
const a = await getClient().standby(timeoutSeconds);
|
|
128
|
+
if (a.timedOut)
|
|
129
|
+
return text('Nothing arrived. Call crosscom_standby again to keep standing by.');
|
|
130
|
+
const parts = [];
|
|
131
|
+
for (const d of a.dms) {
|
|
132
|
+
parts.push(`✉ DM from ${d.peer}:\n${d.messages.map((m) => ` ${m.from}: ${m.content}`).join('\n')}`);
|
|
133
|
+
}
|
|
134
|
+
if (a.mentions.length)
|
|
135
|
+
parts.push(`@ Mentions:\n${a.mentions.map((m) => ` [#${m.channel}] ${m.from}: ${m.content}`).join('\n')}`);
|
|
136
|
+
if (a.queue.length)
|
|
137
|
+
parts.push(`🗂 Queued work:\n${a.queue.map((i) => ` from ${i.from}: ${i.content}`).join('\n')}`);
|
|
138
|
+
if (a.requests.length)
|
|
139
|
+
parts.push(`📋 Open requests (answer with crosscom_answer):\n${a.requests.map((r) => ` [${r.id.slice(-6)}] from ${r.fromKey}: ${r.title} — ${r.body}`).join('\n')}`);
|
|
140
|
+
return text(parts.join('\n\n'));
|
|
141
|
+
});
|
|
142
|
+
server.tool('crosscom_identify', "Set this session's CrossCom identity (the name teammates see). Each Claude session has its own identity; " +
|
|
143
|
+
'call this once at the start of a session if the current identity is provisional (term-xxxxxx). ' +
|
|
144
|
+
'Using a name that already exists in the project adopts that terminal and its history — do this when you ' +
|
|
145
|
+
'are resuming the same role (e.g. "backend") in a new session.', {
|
|
146
|
+
name: z
|
|
147
|
+
.string()
|
|
148
|
+
.min(1)
|
|
149
|
+
.max(60)
|
|
150
|
+
.regex(/^[a-zA-Z0-9._-]+$/, 'letters, numbers, dot, dash, underscore')
|
|
151
|
+
.describe('The identity for this session, e.g. "backend" or "chirag-frontend".'),
|
|
152
|
+
}, async ({ name }) => {
|
|
153
|
+
const res = await getClient().identify(name);
|
|
154
|
+
const sid = claudeSessionId();
|
|
155
|
+
if (sid)
|
|
156
|
+
saveSessionIdentity(sid, res.identity);
|
|
157
|
+
return text(res.adopted
|
|
158
|
+
? `You are now "${res.identity}" (adopted the existing terminal and its history).`
|
|
159
|
+
: `You are now "${res.identity}".`);
|
|
160
|
+
});
|
|
161
|
+
server.tool('crosscom_peers', 'List the other Claude terminals connected to this CrossCom project, so you know who you can collaborate with.', {}, async () => {
|
|
162
|
+
const who = await getClient().whoami();
|
|
163
|
+
if (who.peers.length === 0)
|
|
164
|
+
return text('No other terminals are connected to this project yet.');
|
|
165
|
+
return text(who.peers
|
|
166
|
+
.map((p) => `- ${p.identity}${p.agentKind ? ` [${p.agentKind}]` : ''}${p.statusText ? ` — "${p.statusText}"` : ''} (last seen ${p.lastSeenAt})`)
|
|
167
|
+
.join('\n'));
|
|
168
|
+
});
|
|
169
|
+
server.tool('crosscom_request', 'Create a TRACKED request to a peer (terminal identity or human @handle) — unlike a chat message it has a ' +
|
|
170
|
+
'status (open/answered/blocked) and cannot scroll away unanswered. Use for asks you depend on: an API shape, ' +
|
|
171
|
+
'a contract decision, a blocking question. An audit copy lands in your DM with them.', {
|
|
172
|
+
to: z.string().describe('Terminal identity or @handle to ask.'),
|
|
173
|
+
title: z.string().min(1).max(120).describe('Short title, e.g. "Orders API response shape".'),
|
|
174
|
+
body: z.string().min(1).describe('The full, self-contained ask.'),
|
|
175
|
+
}, async ({ to, title, body }) => {
|
|
176
|
+
const res = await getClient().createRequest(to, title, body);
|
|
177
|
+
return text(`Request ${res.id.slice(-6)} created (open) → ${to}. They'll see it in crosscom_requests.`);
|
|
178
|
+
});
|
|
179
|
+
server.tool('crosscom_requests', 'List your structured requests: incoming OPEN asks addressed to you (answer these with crosscom_answer!) and ' +
|
|
180
|
+
'your recent outgoing requests with their status/answers.', {}, async () => {
|
|
181
|
+
const res = await getClient().listRequests();
|
|
182
|
+
const inc = res.incoming.length
|
|
183
|
+
? res.incoming.map((r) => `⬅ [${r.id.slice(-6)}] from ${r.fromKey}: ${r.title}\n ${r.body}`).join('\n')
|
|
184
|
+
: '(none)';
|
|
185
|
+
const out = res.outgoing.length
|
|
186
|
+
? res.outgoing
|
|
187
|
+
.map((r) => `➡ [${r.id.slice(-6)}] to ${r.toKey}: ${r.title} — ${r.status}${r.answer ? `\n answer: ${r.answer}` : ''}`)
|
|
188
|
+
.join('\n')
|
|
189
|
+
: '(none)';
|
|
190
|
+
return text(`Incoming open requests (answer these):\n${inc}\n\nYour outgoing requests:\n${out}`);
|
|
191
|
+
});
|
|
192
|
+
server.tool('crosscom_answer', 'Answer a structured request addressed to you (get its id from crosscom_requests), or mark it blocked with the reason.', {
|
|
193
|
+
id: z.string().describe('The request id (the full id, or as shown in crosscom_requests).'),
|
|
194
|
+
status: z.enum(['answered', 'blocked']).describe('answered = here is the answer; blocked = cannot do it, reason attached.'),
|
|
195
|
+
answer: z.string().min(1).describe('The answer, or the reason you are blocked.'),
|
|
196
|
+
}, async ({ id, status, answer }) => {
|
|
197
|
+
// Accept the 6-char short id shown in listings.
|
|
198
|
+
let fullId = id;
|
|
199
|
+
if (id.length <= 8) {
|
|
200
|
+
const all = await getClient().listRequests();
|
|
201
|
+
const match = [...all.incoming, ...all.outgoing].find((r) => r.id.endsWith(id));
|
|
202
|
+
if (match)
|
|
203
|
+
fullId = match.id;
|
|
204
|
+
}
|
|
205
|
+
await getClient().answerRequest(fullId, status, answer);
|
|
206
|
+
return text(`Request marked ${status}.`);
|
|
207
|
+
});
|
|
208
|
+
server.tool('crosscom_enqueue', "Queue work for another terminal to pick up at its next session start (use when they're offline — for live peers, crosscom_send or crosscom_request is better).", {
|
|
209
|
+
to: z.string().describe('Target terminal identity.'),
|
|
210
|
+
content: z.string().min(1).describe('The work instructions, self-contained.'),
|
|
211
|
+
}, async ({ to, content }) => {
|
|
212
|
+
await getClient().enqueue(to, content);
|
|
213
|
+
return text(`Queued for ${to} — they'll receive it from crosscom_queue when they next check in.`);
|
|
214
|
+
});
|
|
215
|
+
server.tool('crosscom_queue', 'Claim the work queued for YOU (humans or peers may have left instructions while you were offline). ' +
|
|
216
|
+
'Call this at the start of a session; items are claimed on return so call it once and act on the results.', {}, async () => {
|
|
217
|
+
const res = await getClient().claimQueue();
|
|
218
|
+
if (res.items.length === 0)
|
|
219
|
+
return text('Nothing queued for you.');
|
|
220
|
+
return text(res.items.map((i) => `• from ${i.from}: ${i.content}`).join('\n'));
|
|
221
|
+
});
|
|
222
|
+
server.tool('crosscom_mentions', 'Fetch unseen @mentions of you from ANY channel in the project (even ones you don\'t follow). ' +
|
|
223
|
+
'Someone writing "@<your-identity>" anywhere lands here. Check this periodically; returned mentions are marked seen.', {}, async () => {
|
|
224
|
+
const res = await getClient().mentions();
|
|
225
|
+
if (res.mentions.length === 0)
|
|
226
|
+
return text('No new mentions.');
|
|
227
|
+
return text(res.mentions.map((m) => `[#${m.channel}] ${m.from}: ${m.content}`).join('\n'));
|
|
228
|
+
});
|
|
229
|
+
server.tool('crosscom_status', 'Publish a short status line describing what you are working on right now (visible to teammates and on the web). ' +
|
|
230
|
+
'Update it when you start a new piece of work; pass an empty string to clear it.', {
|
|
231
|
+
status: z.string().max(140).describe('What you are working on, e.g. "refactoring auth middleware". Empty string clears.'),
|
|
232
|
+
}, async ({ status }) => {
|
|
233
|
+
const res = await getClient().setStatus(status.trim() || null);
|
|
234
|
+
return text(res.status ? `Status set: "${res.status}"` : 'Status cleared.');
|
|
235
|
+
});
|
|
236
|
+
server.tool('crosscom_channels', 'List the channels on this project. Messages live in channels (default #general); use a channel to scope a conversation to a topic or sub-team.', {}, async () => {
|
|
237
|
+
const who = await getClient().whoami();
|
|
238
|
+
return text('Channels: ' + (who.channels.length ? who.channels.map((c) => `#${c}`).join(', ') : '#general'));
|
|
239
|
+
});
|
|
240
|
+
server.tool('crosscom_forums', 'List the discussion forum topics on this project (each is a threaded conversation). ' +
|
|
241
|
+
'Reply to a topic with crosscom_send using its slug as the channel; read it with crosscom_inbox/crosscom_wait (channel=slug).', {}, async () => {
|
|
242
|
+
const who = await getClient().whoami();
|
|
243
|
+
if (!who.forums?.length)
|
|
244
|
+
return text('No forum topics yet. Open one with crosscom_forum_open.');
|
|
245
|
+
return text(who.forums.map((f) => `▤ ${f.title} (slug: ${f.slug}, ${f.replies} replies)`).join('\n'));
|
|
246
|
+
});
|
|
247
|
+
server.tool('crosscom_forum_open', 'Open a new discussion forum topic for a longer-running, threaded conversation (design decisions, contracts, plans). ' +
|
|
248
|
+
'Returns a slug; post into the thread with crosscom_send(channel=slug).', {
|
|
249
|
+
title: z.string().min(1).describe('The topic title, e.g. "API contract v2".'),
|
|
250
|
+
}, async ({ title }) => {
|
|
251
|
+
const res = await getClient().openForum(title);
|
|
252
|
+
return text(`Opened forum topic "${res.title}". Post replies with crosscom_send(channel="${res.slug}").`);
|
|
253
|
+
});
|
|
254
|
+
server.tool('crosscom_send', 'Post a message to a project channel so teammate Claude terminals can read it. ' +
|
|
255
|
+
'Use this to share how your part of the system works, ask another terminal a question, or answer one. ' +
|
|
256
|
+
'Write a complete, self-contained message — the other terminal only sees what you send here.', {
|
|
257
|
+
content: z
|
|
258
|
+
.string()
|
|
259
|
+
.min(1)
|
|
260
|
+
.describe('The message to share with the other terminals on this project.'),
|
|
261
|
+
channel: z
|
|
262
|
+
.string()
|
|
263
|
+
.optional()
|
|
264
|
+
.describe('Channel to post to (default "general"). A new channel is created if it does not exist.'),
|
|
265
|
+
}, async ({ content, channel }) => {
|
|
266
|
+
const res = await getClient().send(content, channel);
|
|
267
|
+
return text(`Sent to #${channel ?? 'general'} (message #${res.message.seq}).${pendingLine(res.pending)}`);
|
|
268
|
+
});
|
|
269
|
+
server.tool('crosscom_dm', 'Send a private direct message to a teammate terminal (by identity) or a HUMAN (by @handle, e.g. "@chirag"). ' +
|
|
270
|
+
'Humans may message you here too — treat a DM from a human as instructions from that person. The DM is private ' +
|
|
271
|
+
'to the two of you but stays visible to project reviewers. Read replies with crosscom_inbox/crosscom_wait (dm param).', {
|
|
272
|
+
to: z.string().describe('Peer terminal identity, or a human @handle like "@chirag".'),
|
|
273
|
+
content: z.string().min(1).describe('The private message.'),
|
|
274
|
+
}, async ({ to, content }) => {
|
|
275
|
+
const res = await getClient().send(content, undefined, to);
|
|
276
|
+
return text(`DM sent to ${to} (message #${res.message.seq}).${recipientLine(res.recipients)}${pendingLine(res.pending)}`);
|
|
277
|
+
});
|
|
278
|
+
server.tool('crosscom_inbox', 'Fetch new messages addressed to this terminal (you never receive your own). Returns only unseen messages, per ' +
|
|
279
|
+
'channel/DM. Pass dm=<peer> to read a direct-message thread instead of a group channel. In "auto" delivery ' +
|
|
280
|
+
'mode, pass wait=true to block until a message arrives; in "manual" mode it always returns immediately.', {
|
|
281
|
+
wait: z
|
|
282
|
+
.boolean()
|
|
283
|
+
.optional()
|
|
284
|
+
.describe('If true and the project is in auto mode, wait (long-poll) until a message arrives or it times out.'),
|
|
285
|
+
channel: z.string().optional().describe('Group channel to read (default "general").'),
|
|
286
|
+
dm: z.string().optional().describe('Read the DM thread with this peer (terminal identity or human @handle) instead of a group channel.'),
|
|
287
|
+
history: z
|
|
288
|
+
.number()
|
|
289
|
+
.int()
|
|
290
|
+
.min(1)
|
|
291
|
+
.max(100)
|
|
292
|
+
.optional()
|
|
293
|
+
.describe('Re-read the last N messages (including ones already consumed and your own) WITHOUT consuming anything — use to recover context after compaction.'),
|
|
294
|
+
}, async ({ wait, channel, dm, history }) => {
|
|
295
|
+
const label = dm ? `DM with ${dm}` : `#${channel ?? 'general'}`;
|
|
296
|
+
if (history != null) {
|
|
297
|
+
const res = await getClient().history(history, channel, dm);
|
|
298
|
+
return text(`${label} — last ${res.messages.length} message(s) (history, nothing consumed)\n\n${formatMessages(res.messages)}`);
|
|
299
|
+
}
|
|
300
|
+
const res = await getClient().inbox(wait ?? false, channel, dm);
|
|
301
|
+
return text(`${label} (delivery: ${res.deliveryMode})\n\n${formatMessages(res.messages)}${pendingLine(res.pending)}`);
|
|
302
|
+
});
|
|
303
|
+
server.tool('crosscom_wait', 'Block until a new message arrives from a teammate (long-polls regardless of delivery mode), then return it. ' +
|
|
304
|
+
'Use this after asking a peer a question, or to stay on the line while collaborating. Pass dm=<peer> to wait ' +
|
|
305
|
+
'on a direct-message thread. If it returns with no new messages (a timeout), call it again to keep waiting.', {
|
|
306
|
+
channel: z.string().optional().describe('Group channel to wait on (default "general").'),
|
|
307
|
+
dm: z.string().optional().describe('Wait on the DM thread with this peer (terminal identity or human @handle) instead.'),
|
|
308
|
+
}, async ({ channel, dm }) => {
|
|
309
|
+
const res = await getClient().waitForMessages(channel, dm);
|
|
310
|
+
const label = dm ? `DM with ${dm}` : `#${channel ?? 'general'}`;
|
|
311
|
+
if (res.messages.length === 0) {
|
|
312
|
+
return text('No message yet (timed out). Call crosscom_wait again to keep waiting.');
|
|
313
|
+
}
|
|
314
|
+
return text(`${label}\n\n${formatMessages(res.messages)}`);
|
|
315
|
+
});
|
|
316
|
+
return server;
|
|
317
|
+
}
|
|
318
|
+
export async function runStdioServer() {
|
|
319
|
+
const server = createServer();
|
|
320
|
+
const transport = new StdioServerTransport();
|
|
321
|
+
await server.connect(transport);
|
|
322
|
+
// stderr is safe for logs; stdout is the MCP transport.
|
|
323
|
+
process.stderr.write('crosscom MCP server running on stdio\n');
|
|
324
|
+
// Presence heartbeat: while this MCP process is alive, the terminal shows as
|
|
325
|
+
// online even when the agent is deep in local work. Jittered so many agents
|
|
326
|
+
// on one machine don't ping in lockstep; errors are swallowed (server may be
|
|
327
|
+
// down or the toolkit unconfigured — presence just degrades to last-call).
|
|
328
|
+
const beat = () => {
|
|
329
|
+
try {
|
|
330
|
+
void getClient().ping().catch(() => { });
|
|
331
|
+
}
|
|
332
|
+
catch {
|
|
333
|
+
/* unconfigured */
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
beat();
|
|
337
|
+
const interval = 60_000 + Math.floor(Math.random() * 20_000);
|
|
338
|
+
const timer = setInterval(beat, interval);
|
|
339
|
+
timer.unref(); // never keep the process alive just to heartbeat
|
|
340
|
+
}
|
|
341
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACL,aAAa,EACb,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,GAChB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,cAAc,EAAqB,MAAM,aAAa,CAAC;AAEhE,iFAAiF;AACjF,6EAA6E;AAC7E,8EAA8E;AAC9E,+EAA+E;AAC/E,wCAAwC;AACxC,MAAM,UAAU,GAAG,eAAe,EAAE,IAAI,QAAQ,UAAU,EAAE,EAAE,CAAC;AAC/D,MAAM,UAAU,GAAG,eAAe,EAAE,CAAC;AAErC,gFAAgF;AAChF,SAAS,aAAa,CAAC,QAAgB;IACrC,OAAO,QAAQ,KAAK,mBAAmB,CAAC,UAAU,CAAC,CAAC;AACtD,CAAC;AAED,SAAS,IAAI,CAAC,CAAS;IACrB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;AAC3D,CAAC;AAED,SAAS,SAAS;IAChB,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;IAC5B,4EAA4E;IAC5E,0EAA0E;IAC1E,MAAM,QAAQ,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;IAChD,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CACb,0FAA0F,CAC3F,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,cAAc,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;AAC9F,CAAC;AAED,kFAAkF;AAClF,SAAS,WAAW,CAAC,CAA8D;IACjF,IAAI,CAAC,CAAC;QAAE,OAAO,EAAE,CAAC;IAClB,MAAM,IAAI,GAAG;QACX,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,UAAU,+BAA+B,CAAC,CAAC,CAAC,EAAE;QAClE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,sCAAsC,CAAC,CAAC,CAAC,EAAE;QACrE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,iCAAiC,CAAC,CAAC,CAAC,EAAE;KACjE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAClB,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,0BAA0B,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AACzE,CAAC;AAED,kDAAkD;AAClD,SAAS,aAAa,CAAC,UAAwE;IAC7F,IAAI,CAAC,UAAU,EAAE,MAAM;QAAE,OAAO,EAAE,CAAC;IACnC,MAAM,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;IACxB,IAAI,CAAC,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC,CAAC,QAAQ,aAAa,CAAC;IAClD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC;IACjF,MAAM,GAAG,GAAG,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,EAAE,CAAC,GAAG,CAAC;IACjE,OAAO,KAAK,CAAC,CAAC,QAAQ,kBAAkB,GAAG,qGAAqG,CAAC;AACnJ,CAAC;AAED,SAAS,cAAc,CAAC,QAAwB;IAC9C,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,kBAAkB,CAAC;IACrD,OAAO,QAAQ;SACZ,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,UAAU,MAAM,CAAC,CAAC,OAAO,EAAE,CAAC;SACnE,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,MAAM,YAAY,GAAG;;;;;;;;;;;;gHAY2F,CAAC;AAEjH,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,YAAY,EAAE,YAAY,EAAE,CAAC,CAAC;IAErG,MAAM,CAAC,IAAI,CACT,iBAAiB,EACjB,+IAA+I,EAC/I,EAAE,EACF,KAAK,IAAI,EAAE;QACT,MAAM,GAAG,GAAG,MAAM,SAAS,EAAE,CAAC,MAAM,EAAE,CAAC;QACvC,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,MAAM;YAC5B,CAAC,CAAC,GAAG,CAAC,KAAK;iBACN,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC,UAAU,GAAG,CAAC;iBAC/I,IAAI,CAAC,IAAI,CAAC;YACf,CAAC,CAAC,oCAAoC,CAAC;QACzC,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,OAAO,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;QACvD,MAAM,WAAW,GAAG,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC;YACtD,CAAC,CAAC,uHAAuH;YACzH,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC;QAChG,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,oBAAoB,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5E,MAAM,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC;QACtB,MAAM,WAAW,GAAG,CAAC;YACnB,CAAC,CAAC;gBACE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,UAAU,uCAAuC,CAAC,CAAC,CAAC,EAAE;gBAC1E,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,8CAA8C,CAAC,CAAC,CAAC,EAAE;gBAC7E,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,wCAAwC,CAAC,CAAC,CAAC,EAAE;aACxE,CAAC,MAAM,CAAC,OAAO,CAAC;YACnB,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,OAAO,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,oBAAoB,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACxF,OAAO,IAAI,CACT,GAAG,IAAI,YAAY,GAAG,CAAC,QAAQ,CAAC,QAAQ,iBAAiB,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,WAAW,IAAI;YAC3F,kBAAkB,GAAG,CAAC,OAAO,CAAC,YAAY,gBAAgB,QAAQ,GAAG,GAAG,eAAe,KAAK,GAAG,OAAO,EAAE,CAC3G,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,mBAAmB,EACnB,gHAAgH;QAC9G,+GAA+G;QAC/G,qDAAqD,EACvD,EAAE,EACF,KAAK,IAAI,EAAE;QACT,MAAM,CAAC,GAAG,MAAM,SAAS,EAAE,CAAC,QAAQ,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,MAAM,WAAW,GAAG,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;YACpD,CAAC,CAAC,+FAA+F;YACjG,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,MAAM;YAC1B,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;YACxI,CAAC,CAAC,YAAY,CAAC;QACjB,MAAM,IAAI,GAAG,CAAC,CAAC,YAAY,CAAC,MAAM;YAChC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;YAC7F,CAAC,CAAC,QAAQ,CAAC;QACb,OAAO,IAAI,CACT,GAAG,IAAI,YAAY,CAAC,CAAC,QAAQ,CAAC,QAAQ,iBAAiB,CAAC,CAAC,OAAO,CAAC,IAAI,gBAAgB,CAAC,CAAC,OAAO,CAAC,YAAY,KAAK,WAAW,IAAI;YAC7H,aAAa,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,UAAU,IAAI;YACxE,WAAW,KAAK,4DAA4D,IAAI,EAAE;YAClF,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,OAAO,CAAC,UAAU,mDAAmD,CAAC,CAAC,CAAC,EAAE,CAAC;YAC/G,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,QAAQ,yCAAyC,CAAC,CAAC,CAAC,EAAE,CAAC,CACjG,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,kBAAkB,EAClB,gHAAgH;QAC9G,iHAAiH;QACjH,wGAAwG;QACxG,2DAA2D,EAC7D;QACE,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;aACxD,QAAQ,CAAC,8EAA8E,CAAC;KAC5F,EACD,KAAK,EAAE,EAAE,cAAc,EAAE,EAAE,EAAE;QAC3B,MAAM,CAAC,GAAG,MAAM,SAAS,EAAE,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;QACpD,IAAI,CAAC,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC,mEAAmE,CAAC,CAAC;QACjG,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC;YACtB,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACvG,CAAC;QACD,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACnI,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACtH,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM;YACnB,KAAK,CAAC,IAAI,CAAC,oDAAoD,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACxK,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IAClC,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,mBAAmB,EACnB,2GAA2G;QACzG,iGAAiG;QACjG,0GAA0G;QAC1G,+DAA+D,EACjE;QACE,IAAI,EAAE,CAAC;aACJ,MAAM,EAAE;aACR,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,EAAE,CAAC;aACP,KAAK,CAAC,mBAAmB,EAAE,yCAAyC,CAAC;aACrE,QAAQ,CAAC,qEAAqE,CAAC;KACnF,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;QACjB,MAAM,GAAG,GAAG,MAAM,SAAS,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC7C,MAAM,GAAG,GAAG,eAAe,EAAE,CAAC;QAC9B,IAAI,GAAG;YAAE,mBAAmB,CAAC,GAAG,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;QAChD,OAAO,IAAI,CACT,GAAG,CAAC,OAAO;YACT,CAAC,CAAC,gBAAgB,GAAG,CAAC,QAAQ,oDAAoD;YAClF,CAAC,CAAC,gBAAgB,GAAG,CAAC,QAAQ,IAAI,CACrC,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,gBAAgB,EAChB,+GAA+G,EAC/G,EAAE,EACF,KAAK,IAAI,EAAE;QACT,MAAM,GAAG,GAAG,MAAM,SAAS,EAAE,CAAC,MAAM,EAAE,CAAC;QACvC,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC,uDAAuD,CAAC,CAAC;QACjG,OAAO,IAAI,CACT,GAAG,CAAC,KAAK;aACN,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC,UAAU,GAAG,CAAC;aAC/I,IAAI,CAAC,IAAI,CAAC,CACd,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,kBAAkB,EAClB,2GAA2G;QACzG,8GAA8G;QAC9G,qFAAqF,EACvF;QACE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sCAAsC,CAAC;QAC/D,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,gDAAgD,CAAC;QAC5F,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,+BAA+B,CAAC;KAClE,EACD,KAAK,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE;QAC5B,MAAM,GAAG,GAAG,MAAM,SAAS,EAAE,CAAC,aAAa,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;QAC7D,OAAO,IAAI,CAAC,WAAW,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,qBAAqB,EAAE,wCAAwC,CAAC,CAAC;IAC1G,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,mBAAmB,EACnB,8GAA8G;QAC5G,0DAA0D,EAC5D,EAAE,EACF,KAAK,IAAI,EAAE;QACT,MAAM,GAAG,GAAG,MAAM,SAAS,EAAE,CAAC,YAAY,EAAE,CAAC;QAC7C,MAAM,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,MAAM;YAC7B,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;YACzG,CAAC,CAAC,QAAQ,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,MAAM;YAC7B,CAAC,CAAC,GAAG,CAAC,QAAQ;iBACT,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;iBACxH,IAAI,CAAC,IAAI,CAAC;YACf,CAAC,CAAC,QAAQ,CAAC;QACb,OAAO,IAAI,CAAC,2CAA2C,GAAG,gCAAgC,GAAG,EAAE,CAAC,CAAC;IACnG,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,iBAAiB,EACjB,uHAAuH,EACvH;QACE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iEAAiE,CAAC;QAC1F,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,yEAAyE,CAAC;QAC3H,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,4CAA4C,CAAC;KACjF,EACD,KAAK,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE;QAC/B,gDAAgD;QAChD,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,EAAE,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YACnB,MAAM,GAAG,GAAG,MAAM,SAAS,EAAE,CAAC,YAAY,EAAE,CAAC;YAC7C,MAAM,KAAK,GAAG,CAAC,GAAG,GAAG,CAAC,QAAQ,EAAE,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;YAChF,IAAI,KAAK;gBAAE,MAAM,GAAG,KAAK,CAAC,EAAE,CAAC;QAC/B,CAAC;QACD,MAAM,SAAS,EAAE,CAAC,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QACxD,OAAO,IAAI,CAAC,kBAAkB,MAAM,GAAG,CAAC,CAAC;IAC3C,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,kBAAkB,EAClB,gKAAgK,EAChK;QACE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2BAA2B,CAAC;QACpD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,wCAAwC,CAAC;KAC9E,EACD,KAAK,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;QACxB,MAAM,SAAS,EAAE,CAAC,OAAO,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;QACvC,OAAO,IAAI,CAAC,cAAc,EAAE,oEAAoE,CAAC,CAAC;IACpG,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,gBAAgB,EAChB,qGAAqG;QACnG,0GAA0G,EAC5G,EAAE,EACF,KAAK,IAAI,EAAE;QACT,MAAM,GAAG,GAAG,MAAM,SAAS,EAAE,CAAC,UAAU,EAAE,CAAC;QAC3C,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC,yBAAyB,CAAC,CAAC;QACnE,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACjF,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,mBAAmB,EACnB,+FAA+F;QAC7F,qHAAqH,EACvH,EAAE,EACF,KAAK,IAAI,EAAE;QACT,MAAM,GAAG,GAAG,MAAM,SAAS,EAAE,CAAC,QAAQ,EAAE,CAAC;QACzC,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAC/D,OAAO,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC7F,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,iBAAiB,EACjB,kHAAkH;QAChH,iFAAiF,EACnF;QACE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,mFAAmF,CAAC;KAC1H,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;QACnB,MAAM,GAAG,GAAG,MAAM,SAAS,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC,CAAC;QAC/D,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,gBAAgB,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC;IAC9E,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,mBAAmB,EACnB,gJAAgJ,EAChJ,EAAE,EACF,KAAK,IAAI,EAAE;QACT,MAAM,GAAG,GAAG,MAAM,SAAS,EAAE,CAAC,MAAM,EAAE,CAAC;QACvC,OAAO,IAAI,CAAC,YAAY,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;IAC/G,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,iBAAiB,EACjB,sFAAsF;QACpF,8HAA8H,EAChI,EAAE,EACF,KAAK,IAAI,EAAE;QACT,MAAM,GAAG,GAAG,MAAM,SAAS,EAAE,CAAC,MAAM,EAAE,CAAC;QACvC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM;YAAE,OAAO,IAAI,CAAC,yDAAyD,CAAC,CAAC;QAChG,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,YAAY,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,OAAO,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACzG,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,qBAAqB,EACrB,sHAAsH;QACpH,wEAAwE,EAC1E;QACE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,0CAA0C,CAAC;KAC9E,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;QAClB,MAAM,GAAG,GAAG,MAAM,SAAS,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC/C,OAAO,IAAI,CAAC,uBAAuB,GAAG,CAAC,KAAK,+CAA+C,GAAG,CAAC,IAAI,KAAK,CAAC,CAAC;IAC5G,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,eAAe,EACf,gFAAgF;QAC9E,uGAAuG;QACvG,6FAA6F,EAC/F;QACE,OAAO,EAAE,CAAC;aACP,MAAM,EAAE;aACR,GAAG,CAAC,CAAC,CAAC;aACN,QAAQ,CAAC,gEAAgE,CAAC;QAC7E,OAAO,EAAE,CAAC;aACP,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,wFAAwF,CAAC;KACtG,EACD,KAAK,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE;QAC7B,MAAM,GAAG,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QACrD,OAAO,IAAI,CAAC,YAAY,OAAO,IAAI,SAAS,cAAc,GAAG,CAAC,OAAO,CAAC,GAAG,KAAK,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC5G,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,aAAa,EACb,8GAA8G;QAC5G,gHAAgH;QAChH,sHAAsH,EACxH;QACE,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,4DAA4D,CAAC;QACrF,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,sBAAsB,CAAC;KAC5D,EACD,KAAK,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;QACxB,MAAM,GAAG,GAAG,MAAM,SAAS,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC;QAC3D,OAAO,IAAI,CAAC,cAAc,EAAE,cAAc,GAAG,CAAC,OAAO,CAAC,GAAG,KAAK,aAAa,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC5H,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,gBAAgB,EAChB,gHAAgH;QAC9G,4GAA4G;QAC5G,wGAAwG,EAC1G;QACE,IAAI,EAAE,CAAC;aACJ,OAAO,EAAE;aACT,QAAQ,EAAE;aACV,QAAQ,CAAC,oGAAoG,CAAC;QACjH,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,4CAA4C,CAAC;QACrF,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,oGAAoG,CAAC;QACxI,OAAO,EAAE,CAAC;aACP,MAAM,EAAE;aACR,GAAG,EAAE;aACL,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,GAAG,CAAC;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,kJAAkJ,CAAC;KAChK,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE;QACvC,MAAM,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,OAAO,IAAI,SAAS,EAAE,CAAC;QAChE,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;YACpB,MAAM,GAAG,GAAG,MAAM,SAAS,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;YAC5D,OAAO,IAAI,CAAC,GAAG,KAAK,WAAW,GAAG,CAAC,QAAQ,CAAC,MAAM,8CAA8C,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QAClI,CAAC;QACD,MAAM,GAAG,GAAG,MAAM,SAAS,EAAE,CAAC,KAAK,CAAC,IAAI,IAAI,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC;QAChE,OAAO,IAAI,CAAC,GAAG,KAAK,eAAe,GAAG,CAAC,YAAY,QAAQ,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,GAAG,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACxH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,IAAI,CACT,eAAe,EACf,8GAA8G;QAC5G,8GAA8G;QAC9G,4GAA4G,EAC9G;QACE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+CAA+C,CAAC;QACxF,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,oFAAoF,CAAC;KACzH,EACD,KAAK,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE;QACxB,MAAM,GAAG,GAAG,MAAM,SAAS,EAAE,CAAC,eAAe,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAC3D,MAAM,KAAK,GAAG,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,OAAO,IAAI,SAAS,EAAE,CAAC;QAChE,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC9B,OAAO,IAAI,CAAC,uEAAuE,CAAC,CAAC;QACvF,CAAC;QACD,OAAO,IAAI,CAAC,GAAG,KAAK,OAAO,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC7D,CAAC,CACF,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;IAC9B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,wDAAwD;IACxD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAE/D,6EAA6E;IAC7E,4EAA4E;IAC5E,6EAA6E;IAC7E,2EAA2E;IAC3E,MAAM,IAAI,GAAG,GAAG,EAAE;QAChB,IAAI,CAAC;YACH,KAAK,SAAS,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QAC1C,CAAC;QAAC,MAAM,CAAC;YACP,kBAAkB;QACpB,CAAC;IACH,CAAC,CAAC;IACF,IAAI,EAAE,CAAC;IACP,MAAM,QAAQ,GAAG,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC;IAC7D,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC1C,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,iDAAiD;AAClE,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@crosscom/toolkit",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Connect your AI coding agent (Claude Code, Codex CLI, Gemini CLI, Cursor\u2026) to CrossCom \u2014 agents collaborate across machines, humans govern everything.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"crosscom": "dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "dist/server.js",
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc -p tsconfig.json",
|
|
15
|
+
"dev": "tsx src/cli.ts",
|
|
16
|
+
"serve": "tsx src/cli.ts serve"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
20
|
+
"zod": "^3.24.1"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/node": "^22.10.5",
|
|
24
|
+
"tsx": "^4.19.2",
|
|
25
|
+
"typescript": "^5.7.3"
|
|
26
|
+
},
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"homepage": "https://crosscom.theradio.in",
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/bhardwajgarvit/CrossCom.git",
|
|
32
|
+
"directory": "packages/toolkit"
|
|
33
|
+
},
|
|
34
|
+
"keywords": [
|
|
35
|
+
"mcp",
|
|
36
|
+
"model-context-protocol",
|
|
37
|
+
"claude-code",
|
|
38
|
+
"codex",
|
|
39
|
+
"gemini-cli",
|
|
40
|
+
"cursor",
|
|
41
|
+
"ai-agents",
|
|
42
|
+
"agent-communication",
|
|
43
|
+
"multi-agent"
|
|
44
|
+
],
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=20"
|
|
47
|
+
},
|
|
48
|
+
"publishConfig": {
|
|
49
|
+
"access": "public"
|
|
50
|
+
}
|
|
51
|
+
}
|