rentline-sandbox 0.1.2 → 0.1.4
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/README.md +26 -0
- package/dist/index.js +2 -2
- package/dist/{setup-JPLRGUPW.js → setup-MMARJIKJ.js} +52 -55
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -20,6 +20,32 @@ Requires Node.js ≥ 18.
|
|
|
20
20
|
|
|
21
21
|
---
|
|
22
22
|
|
|
23
|
+
## Setup
|
|
24
|
+
|
|
25
|
+
Run once after install. Saves your credentials and automatically configures your AI client:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
sandbox setup
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The wizard will:
|
|
32
|
+
1. Ask for your API key (get one at **sandbox.rentline.xyz/cli-auth**)
|
|
33
|
+
2. Verify connectivity to the API
|
|
34
|
+
3. Save credentials to `~/.rentline-sandbox/credentials.json`
|
|
35
|
+
4. Detect your AI client (Claude Code, Cursor, Windsurf, OpenCode) and patch its MCP config
|
|
36
|
+
5. Install `SKILL.md` so your agent understands the game
|
|
37
|
+
|
|
38
|
+
**Non-interactive:**
|
|
39
|
+
```bash
|
|
40
|
+
sandbox setup --key sb_xxx --client opencode --yes
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Supported clients: `claude-code`, `claude-desktop`, `cursor`, `windsurf`, `opencode`, `zed`, `cline`
|
|
44
|
+
|
|
45
|
+
After setup, **restart your AI client** to load the MCP server.
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
23
49
|
## Authentication
|
|
24
50
|
|
|
25
51
|
### Browser login (recommended)
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ var _require = createRequire(import.meta.url);
|
|
|
9
9
|
var { version } = _require("../package.json");
|
|
10
10
|
var args = process.argv.slice(2);
|
|
11
11
|
if (args[0] === "setup" || args[0] === "--setup") {
|
|
12
|
-
const { runSetup, parseSetupArgs } = await import("./setup-
|
|
12
|
+
const { runSetup, parseSetupArgs } = await import("./setup-MMARJIKJ.js");
|
|
13
13
|
const opts = parseSetupArgs(args.filter((a) => a !== "setup" && a !== "--setup"));
|
|
14
14
|
await runSetup(opts);
|
|
15
15
|
process.exit(0);
|
|
@@ -31,7 +31,7 @@ if (args.length === 0 || args[0] === "server" || args[0] === "--server") {
|
|
|
31
31
|
registerMortgage(program);
|
|
32
32
|
registerAdmin(program);
|
|
33
33
|
program.command("mcp-setup", { hidden: true }).allowUnknownOption().action(async () => {
|
|
34
|
-
const { runSetup, parseSetupArgs } = await import("./setup-
|
|
34
|
+
const { runSetup, parseSetupArgs } = await import("./setup-MMARJIKJ.js");
|
|
35
35
|
const opts = parseSetupArgs(process.argv.slice(3));
|
|
36
36
|
await runSetup(opts);
|
|
37
37
|
});
|
|
@@ -13,6 +13,7 @@ import { createInterface } from "readline";
|
|
|
13
13
|
import { readFileSync, writeFileSync, mkdirSync, existsSync, copyFileSync } from "fs";
|
|
14
14
|
import { homedir, platform } from "os";
|
|
15
15
|
import { join, dirname } from "path";
|
|
16
|
+
import { execSync } from "child_process";
|
|
16
17
|
import { fileURLToPath } from "url";
|
|
17
18
|
var __filename = fileURLToPath(import.meta.url);
|
|
18
19
|
var __dirname = dirname(__filename);
|
|
@@ -51,7 +52,7 @@ async function runSetup(opts) {
|
|
|
51
52
|
}
|
|
52
53
|
}
|
|
53
54
|
if (!apiKey) {
|
|
54
|
-
console.error("API key is required. Get one
|
|
55
|
+
console.error("API key is required. Get one at: https://sandbox.rentline.xyz/cli-auth");
|
|
55
56
|
process.exit(1);
|
|
56
57
|
}
|
|
57
58
|
const existing = loadConfig();
|
|
@@ -90,7 +91,7 @@ async function runSetup(opts) {
|
|
|
90
91
|
const idx = parseInt(choice);
|
|
91
92
|
clientName = isNaN(idx) ? choice : clients[idx - 1] ?? "other";
|
|
92
93
|
}
|
|
93
|
-
await installForClient(clientName, opts.scope ?? "user", apiKey, apiUrl
|
|
94
|
+
await installForClient(clientName, opts.scope ?? "user", apiKey, apiUrl);
|
|
94
95
|
rl?.close();
|
|
95
96
|
console.log("\nSetup complete. Restart your AI client to load the Rentline Sandbox MCP server.\n");
|
|
96
97
|
}
|
|
@@ -102,84 +103,66 @@ function detectClient() {
|
|
|
102
103
|
if (env.OPENCODE_PROJECT || env.OPENCODE_SESSION) return "opencode";
|
|
103
104
|
return void 0;
|
|
104
105
|
}
|
|
105
|
-
var
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
env: {}
|
|
109
|
-
};
|
|
110
|
-
function mcpEntry(apiKey, apiUrl) {
|
|
111
|
-
return {
|
|
112
|
-
...MCP_SERVER_ENTRY,
|
|
113
|
-
env: {
|
|
114
|
-
SANDBOX_API_KEY: apiKey,
|
|
115
|
-
SANDBOX_API_URL: apiUrl
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
async function installForClient(clientName, scope, apiKey, apiUrl, displayName) {
|
|
120
|
-
const entry = mcpEntry(apiKey, apiUrl);
|
|
106
|
+
var NPX_CMD = ["npx", "-y", "rentline-sandbox"];
|
|
107
|
+
async function installForClient(clientName, scope, apiKey, apiUrl) {
|
|
108
|
+
const env = { SANDBOX_API_KEY: apiKey, SANDBOX_API_URL: apiUrl };
|
|
121
109
|
switch (clientName) {
|
|
122
110
|
case "claude-code": {
|
|
123
|
-
const
|
|
124
|
-
const
|
|
125
|
-
const cmd = `claude mcp add rentline-sandbox --scope ${scope} ${envFlags} -- npx -y rentline-sandbox`;
|
|
111
|
+
const envFlags = Object.entries(env).map(([k, v]) => `-e ${k}="${v}"`).join(" ");
|
|
112
|
+
const cmd = `claude mcp add rentline-sandbox --scope ${scope} ${envFlags} -- ${NPX_CMD.join(" ")}`;
|
|
126
113
|
try {
|
|
127
114
|
execSync(cmd, { stdio: "pipe" });
|
|
128
115
|
console.log(`Installed via claude CLI (scope=${scope})`);
|
|
129
116
|
} catch {
|
|
130
117
|
const file = join(homedir(), ".claude.json");
|
|
131
|
-
patchMcpJson(file, "rentline-sandbox",
|
|
118
|
+
patchMcpJson(file, "rentline-sandbox", { command: NPX_CMD[0], args: NPX_CMD.slice(1), env }, "mcpServers");
|
|
132
119
|
console.log(`Patched ${file}`);
|
|
133
120
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
join(homedir(), ".agents", "skills", "rentline-sandbox")
|
|
139
|
-
];
|
|
140
|
-
for (const dir of targets) {
|
|
141
|
-
mkdirSync(dir, { recursive: true });
|
|
142
|
-
copyFileSync(skillSrc, join(dir, "SKILL.md"));
|
|
143
|
-
console.log(`SKILL.md \u2192 ${dir}`);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
121
|
+
installSkill([
|
|
122
|
+
join(homedir(), ".claude", "skills", "rentline-sandbox"),
|
|
123
|
+
join(homedir(), ".agents", "skills", "rentline-sandbox")
|
|
124
|
+
]);
|
|
146
125
|
break;
|
|
147
126
|
}
|
|
148
127
|
case "claude-desktop": {
|
|
149
|
-
|
|
150
|
-
|
|
128
|
+
let file;
|
|
129
|
+
if (platform() === "win32") {
|
|
130
|
+
file = join(process.env.APPDATA ?? homedir(), "Claude", "claude_desktop_config.json");
|
|
131
|
+
} else if (platform() === "darwin") {
|
|
132
|
+
file = join(homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
|
|
133
|
+
} else {
|
|
134
|
+
file = join(homedir(), ".config", "Claude", "claude_desktop_config.json");
|
|
135
|
+
}
|
|
136
|
+
patchMcpJson(file, "rentline-sandbox", { command: NPX_CMD[0], args: NPX_CMD.slice(1), env }, "mcpServers");
|
|
151
137
|
console.log(`Patched ${file}`);
|
|
152
138
|
break;
|
|
153
139
|
}
|
|
154
140
|
case "cursor": {
|
|
155
141
|
const file = scope === "project" ? join(process.cwd(), ".cursor", "mcp.json") : join(homedir(), ".cursor", "mcp.json");
|
|
156
|
-
patchMcpJson(file, "rentline-sandbox",
|
|
142
|
+
patchMcpJson(file, "rentline-sandbox", { command: NPX_CMD[0], args: NPX_CMD.slice(1), env }, "mcpServers");
|
|
157
143
|
console.log(`Patched ${file}`);
|
|
158
144
|
break;
|
|
159
145
|
}
|
|
160
146
|
case "windsurf": {
|
|
161
|
-
const file = join(process.
|
|
162
|
-
patchMcpJson(file, "rentline-sandbox",
|
|
147
|
+
const file = platform() === "win32" ? join(process.env.APPDATA ?? homedir(), ".codeium", "windsurf", "mcp_config.json") : join(homedir(), ".codeium", "windsurf", "mcp_config.json");
|
|
148
|
+
patchMcpJson(file, "rentline-sandbox", { command: NPX_CMD[0], args: NPX_CMD.slice(1), env }, "mcpServers");
|
|
163
149
|
console.log(`Patched ${file}`);
|
|
164
150
|
break;
|
|
165
151
|
}
|
|
166
152
|
case "opencode": {
|
|
167
|
-
const file = scope === "project" ? join(process.cwd(), "opencode.json") : join(homedir(), ".config", "opencode", "
|
|
168
|
-
patchMcpJson(file, "rentline-sandbox",
|
|
153
|
+
const file = scope === "project" ? join(process.cwd(), "opencode.json") : join(homedir(), ".config", "opencode", "opencode.json");
|
|
154
|
+
patchMcpJson(file, "rentline-sandbox", {
|
|
155
|
+
type: "local",
|
|
156
|
+
command: NPX_CMD,
|
|
157
|
+
enabled: true,
|
|
158
|
+
environment: env
|
|
159
|
+
}, "mcp");
|
|
169
160
|
console.log(`Patched ${file}`);
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
join(homedir(), ".agents", "skills", "rentline-sandbox")
|
|
176
|
-
];
|
|
177
|
-
for (const dir of targets) {
|
|
178
|
-
mkdirSync(dir, { recursive: true });
|
|
179
|
-
copyFileSync(skillSrc, join(dir, "SKILL.md"));
|
|
180
|
-
console.log(`SKILL.md \u2192 ${dir}`);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
161
|
+
installSkill([
|
|
162
|
+
join(homedir(), ".config", "opencode", "skills", "rentline-sandbox"),
|
|
163
|
+
join(homedir(), ".claude", "skills", "rentline-sandbox"),
|
|
164
|
+
join(homedir(), ".agents", "skills", "rentline-sandbox")
|
|
165
|
+
]);
|
|
183
166
|
break;
|
|
184
167
|
}
|
|
185
168
|
case "zed":
|
|
@@ -190,11 +173,22 @@ async function installForClient(clientName, scope, apiKey, apiUrl, displayName)
|
|
|
190
173
|
console.log(`
|
|
191
174
|
Add the following to your MCP client config:
|
|
192
175
|
`);
|
|
193
|
-
console.log(JSON.stringify({
|
|
176
|
+
console.log(JSON.stringify({
|
|
177
|
+
"rentline-sandbox": { command: NPX_CMD[0], args: NPX_CMD.slice(1), env }
|
|
178
|
+
}, null, 2));
|
|
194
179
|
break;
|
|
195
180
|
}
|
|
196
181
|
}
|
|
197
182
|
}
|
|
183
|
+
function installSkill(dirs) {
|
|
184
|
+
const skillSrc = join(__dirname, "../SKILL.md");
|
|
185
|
+
if (!existsSync(skillSrc)) return;
|
|
186
|
+
for (const dir of dirs) {
|
|
187
|
+
mkdirSync(dir, { recursive: true });
|
|
188
|
+
copyFileSync(skillSrc, join(dir, "SKILL.md"));
|
|
189
|
+
console.log(`SKILL.md \u2192 ${dir}`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
198
192
|
function patchMcpJson(filePath, serverName, entry, key) {
|
|
199
193
|
mkdirSync(dirname(filePath), { recursive: true });
|
|
200
194
|
let config = {};
|
|
@@ -204,6 +198,9 @@ function patchMcpJson(filePath, serverName, entry, key) {
|
|
|
204
198
|
} catch {
|
|
205
199
|
}
|
|
206
200
|
}
|
|
201
|
+
if (key === "mcp" && !config["$schema"]) {
|
|
202
|
+
config["$schema"] = "https://opencode.ai/config.json";
|
|
203
|
+
}
|
|
207
204
|
const servers = config[key] ?? {};
|
|
208
205
|
servers[serverName] = entry;
|
|
209
206
|
config[key] = servers;
|
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rentline-sandbox",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "CLI and MCP server for the Rentline Sandbox real estate investment simulation game",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"sandbox": "dist/index.js",
|
|
8
|
-
"sandbox-mcp": "dist/server.js"
|
|
8
|
+
"sandbox-mcp": "dist/server.js",
|
|
9
|
+
"rentline-sandbox": "dist/server.js"
|
|
9
10
|
},
|
|
10
11
|
"main": "./dist/index.js",
|
|
11
12
|
"exports": {
|