@kodama-run/sdk 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/package.json +34 -0
- package/src/adapters/cli.ts +172 -0
- package/src/adapters/mcp.ts +677 -0
- package/src/adapters/openclaw.ts +231 -0
- package/src/crypto.ts +102 -0
- package/src/index.ts +9 -0
- package/src/permissions.ts +160 -0
- package/src/room.ts +399 -0
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kodama-run/sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": "./src/index.ts"
|
|
7
|
+
},
|
|
8
|
+
"bin": {
|
|
9
|
+
"kodama": "./src/adapters/cli.ts",
|
|
10
|
+
"kodama-mcp": "./src/adapters/mcp.ts"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"src/**/*.ts",
|
|
14
|
+
"!src/__tests__",
|
|
15
|
+
"README.md"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "echo 'No build step for sdk (source-only)'",
|
|
19
|
+
"test": "bun test",
|
|
20
|
+
"lint": "tsc --noEmit",
|
|
21
|
+
"clean": "rm -rf dist"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@kodama-run/shared": "workspace:*",
|
|
25
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
26
|
+
"commander": "^13",
|
|
27
|
+
"ws": "^8",
|
|
28
|
+
"zod": "^4.3.6"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@types/ws": "^8",
|
|
32
|
+
"typescript": "*"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { program } from "commander";
|
|
3
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
4
|
+
import { Kodama } from "../room.ts";
|
|
5
|
+
import * as readline from "readline";
|
|
6
|
+
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
// Helper: read a line from stdin
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
|
|
11
|
+
function readLine(prompt: string): Promise<string> {
|
|
12
|
+
return new Promise((resolve) => {
|
|
13
|
+
const rl = readline.createInterface({
|
|
14
|
+
input: process.stdin,
|
|
15
|
+
output: process.stdout,
|
|
16
|
+
terminal: false,
|
|
17
|
+
});
|
|
18
|
+
process.stdout.write(prompt);
|
|
19
|
+
rl.once("line", (line) => {
|
|
20
|
+
rl.close();
|
|
21
|
+
resolve(line);
|
|
22
|
+
});
|
|
23
|
+
rl.once("close", () => {
|
|
24
|
+
resolve("");
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// `kodama create`
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
program
|
|
34
|
+
.command("create")
|
|
35
|
+
.description("Create a new Kodama room")
|
|
36
|
+
.option("-p, --password <password>", "Room password")
|
|
37
|
+
.option("-r, --rounds <number>", "Max rounds", "10")
|
|
38
|
+
.option("-t, --timeout <seconds>", "Turn timeout in seconds", "90")
|
|
39
|
+
.option("--topic <text>", "Room topic / negotiation subject")
|
|
40
|
+
.option("--relay <url>", "Relay HTTP base URL", "http://localhost:8000")
|
|
41
|
+
.action(async (options) => {
|
|
42
|
+
const body: Record<string, unknown> = {
|
|
43
|
+
maxRounds: parseInt(options.rounds, 10),
|
|
44
|
+
turnTimeout: parseInt(options.timeout, 10),
|
|
45
|
+
};
|
|
46
|
+
if (options.password) {
|
|
47
|
+
body.password = options.password;
|
|
48
|
+
}
|
|
49
|
+
if (options.topic) {
|
|
50
|
+
body.topic = options.topic;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
const res = await fetch(`${options.relay}/api/rooms`, {
|
|
55
|
+
method: "POST",
|
|
56
|
+
headers: { "Content-Type": "application/json" },
|
|
57
|
+
body: JSON.stringify(body),
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
if (!res.ok) {
|
|
61
|
+
const text = await res.text();
|
|
62
|
+
console.error(`Error creating room (HTTP ${res.status}): ${text}`);
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const data = await res.json() as {
|
|
67
|
+
code: string;
|
|
68
|
+
topic?: string;
|
|
69
|
+
inviteTokens?: string[];
|
|
70
|
+
status?: string;
|
|
71
|
+
};
|
|
72
|
+
const inviteToken = data.inviteTokens?.[0] ?? "???";
|
|
73
|
+
|
|
74
|
+
console.log(`Room created: ${data.code}`);
|
|
75
|
+
if (data.topic) {
|
|
76
|
+
console.log(`Topic: ${data.topic}`);
|
|
77
|
+
}
|
|
78
|
+
console.log("");
|
|
79
|
+
console.log("Share with your friend:");
|
|
80
|
+
console.log(` kodama join ${data.code} --invite ${inviteToken}`);
|
|
81
|
+
console.log("");
|
|
82
|
+
console.log(`Spectate: http://localhost:3000/room/${data.code}`);
|
|
83
|
+
if (options.password) {
|
|
84
|
+
console.log(`Password: ${options.password}`);
|
|
85
|
+
}
|
|
86
|
+
} catch (err) {
|
|
87
|
+
console.error("Failed to reach relay:", (err as Error).message);
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// ---------------------------------------------------------------------------
|
|
93
|
+
// `kodama join <code>`
|
|
94
|
+
// ---------------------------------------------------------------------------
|
|
95
|
+
|
|
96
|
+
program
|
|
97
|
+
.command("join <code>")
|
|
98
|
+
.description("Join a Kodama room as a CLI agent")
|
|
99
|
+
.requiredOption("--invite <token>", "Invite token for the room")
|
|
100
|
+
.option("-n, --name <name>", "Agent display name", "CLI Agent")
|
|
101
|
+
.option("-p, --password <password>", "Room password")
|
|
102
|
+
.option("--goal <text>", "Goal for autonomous LLM mode")
|
|
103
|
+
.option("--manual", "Manual stdin mode (for debugging)")
|
|
104
|
+
.option("--relay <url>", "Relay WebSocket URL", "ws://localhost:8000/ws")
|
|
105
|
+
.action(async (code: string, options) => {
|
|
106
|
+
const agent = new Kodama(code, {
|
|
107
|
+
relayUrl: options.relay,
|
|
108
|
+
name: options.name,
|
|
109
|
+
password: options.password,
|
|
110
|
+
inviteToken: options.invite,
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
agent.on("error", (err: Error) => {
|
|
114
|
+
console.error(`[error] ${err.message}`);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
agent.on("turn", async (messages, _ctx) => {
|
|
118
|
+
if (options.manual) {
|
|
119
|
+
// Manual stdin mode
|
|
120
|
+
const last = messages[messages.length - 1];
|
|
121
|
+
if (last) {
|
|
122
|
+
console.log(`\n[${last.agent.name}]: ${last.content}`);
|
|
123
|
+
} else {
|
|
124
|
+
console.log("\n[Room] You go first.");
|
|
125
|
+
}
|
|
126
|
+
return await readLine("You: ");
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Autonomous LLM mode
|
|
130
|
+
const client = new Anthropic();
|
|
131
|
+
const systemPrompt = options.goal || "You are a helpful conversationalist.";
|
|
132
|
+
const history = messages.map((m) => ({
|
|
133
|
+
role: "user" as const,
|
|
134
|
+
content: `${m.agent.name}: ${m.content}`,
|
|
135
|
+
}));
|
|
136
|
+
if (history.length === 0) {
|
|
137
|
+
history.push({ role: "user", content: "Start the conversation. Introduce yourself." });
|
|
138
|
+
}
|
|
139
|
+
const response = await client.messages.create({
|
|
140
|
+
model: "claude-sonnet-4-6",
|
|
141
|
+
max_tokens: 500,
|
|
142
|
+
system: systemPrompt,
|
|
143
|
+
messages: history,
|
|
144
|
+
});
|
|
145
|
+
const text = response.content[0]?.type === "text" ? response.content[0].text : "";
|
|
146
|
+
console.log(`\n[You]: ${text}`);
|
|
147
|
+
return text;
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
try {
|
|
151
|
+
console.log(`Joining room ${code} as "${options.name}" …`);
|
|
152
|
+
await agent.join();
|
|
153
|
+
const ownerToken = agent.getOwnerToken();
|
|
154
|
+
console.log(`Joined!`);
|
|
155
|
+
console.log(`Owner token: ${ownerToken}`);
|
|
156
|
+
console.log(`Spectate: http://localhost:3000/room/${code}`);
|
|
157
|
+
console.log("Waiting for your turn… (Ctrl+C to exit)");
|
|
158
|
+
} catch (err) {
|
|
159
|
+
console.error("Failed to join room:", (err as Error).message);
|
|
160
|
+
process.exit(1);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// ---------------------------------------------------------------------------
|
|
165
|
+
// Parse
|
|
166
|
+
// ---------------------------------------------------------------------------
|
|
167
|
+
|
|
168
|
+
program
|
|
169
|
+
.name("kodama")
|
|
170
|
+
.description("Kodama CLI — create and join negotiation rooms")
|
|
171
|
+
.version("0.1.0")
|
|
172
|
+
.parse(process.argv);
|