settld 0.2.6 → 0.2.8
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/docs/QUICKSTART_MCP_HOSTS.md +1 -1
- package/docs/integrations/openclaw/CLAWHUB_PUBLISH_CHECKLIST.md +1 -1
- package/docs/integrations/openclaw/PUBLIC_QUICKSTART.md +10 -2
- package/docs/integrations/openclaw/settld-mcp-skill/SKILL.md +13 -11
- package/docs/integrations/openclaw/settld-mcp-skill/mcp-server.example.json +1 -1
- package/openclaw/index.js +307 -0
- package/openclaw.plugin.json +29 -0
- package/package.json +8 -1
- package/scripts/setup/host-config.mjs +1 -1
- package/scripts/setup/onboard.mjs +17 -3
- package/services/magic-link/src/server.js +2 -2
|
@@ -182,7 +182,7 @@ Then activate host-side:
|
|
|
182
182
|
- `codex`: restart Codex.
|
|
183
183
|
- `claude`: restart Claude Desktop.
|
|
184
184
|
- `cursor`: restart Cursor.
|
|
185
|
-
- `openclaw`: run `openclaw doctor`, ensure OpenClaw onboarding is complete (`openclaw onboard --install-daemon`), then run `openclaw tui`.
|
|
185
|
+
- `openclaw`: run `openclaw doctor`, ensure OpenClaw onboarding is complete (`openclaw onboard --install-daemon`), install plugin (`openclaw plugins install settld@latest`), run local verification (`openclaw agent --local --agent main --session-id settld-smoke --message "Use the tool named settld_about with empty arguments. Return only JSON." --json`), then run `openclaw tui --session main`.
|
|
186
186
|
|
|
187
187
|
## 5) Fund and verify wallet state
|
|
188
188
|
|
|
@@ -32,7 +32,7 @@ Publish the folder `docs/integrations/openclaw/settld-mcp-skill/` as your skill
|
|
|
32
32
|
If ClawHub UI requests install instructions, use:
|
|
33
33
|
|
|
34
34
|
- command: `npx`
|
|
35
|
-
- args: `-y settld-mcp`
|
|
35
|
+
- args: `-y --package settld@latest settld-mcp`
|
|
36
36
|
- env: `SETTLD_BASE_URL`, `SETTLD_TENANT_ID`, `SETTLD_API_KEY`, optional `SETTLD_PAID_TOOLS_BASE_URL`
|
|
37
37
|
|
|
38
38
|
## 4) Post-Publish Smoke Test
|
|
@@ -72,19 +72,27 @@ Run:
|
|
|
72
72
|
|
|
73
73
|
```bash
|
|
74
74
|
openclaw doctor
|
|
75
|
+
openclaw plugins install settld@latest
|
|
76
|
+
openclaw agent --local --agent main --session-id settld-smoke --message "Use the tool named settld_about with empty arguments. Return only JSON." --json
|
|
75
77
|
```
|
|
76
78
|
|
|
77
79
|
Then from OpenClaw chat/test prompt:
|
|
78
80
|
|
|
79
|
-
- `
|
|
81
|
+
- `Use tool settld_about and return JSON only.`
|
|
80
82
|
|
|
81
83
|
Expected result: success payload with Settld tool metadata.
|
|
82
84
|
|
|
85
|
+
If your TUI is in a channel-bound session (`whatsapp:*`, `telegram:*`), switch to `main` first:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
openclaw tui --session main
|
|
89
|
+
```
|
|
90
|
+
|
|
83
91
|
## 4) Run first paid tool call
|
|
84
92
|
|
|
85
93
|
From OpenClaw prompt:
|
|
86
94
|
|
|
87
|
-
- `
|
|
95
|
+
- `Use tool settld_call with tool=settld.weather_current_paid and arguments={"city":"Chicago","unit":"f"}.`
|
|
88
96
|
|
|
89
97
|
Expected result:
|
|
90
98
|
|
|
@@ -30,14 +30,16 @@ It is designed for the public `quick` onboarding flow:
|
|
|
30
30
|
- Settld runtime env from setup (`SETTLD_API_KEY`, `SETTLD_BASE_URL`, `SETTLD_TENANT_ID`)
|
|
31
31
|
- Optional paid tools base URL (`SETTLD_PAID_TOOLS_BASE_URL`)
|
|
32
32
|
|
|
33
|
-
##
|
|
33
|
+
## OpenClaw Plugin Registration
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
Install the Settld OpenClaw plugin from npm:
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
- `openclaw plugins install settld@latest`
|
|
38
38
|
|
|
39
|
-
-
|
|
40
|
-
|
|
39
|
+
This plugin wraps Settld MCP under OpenClaw-native tools:
|
|
40
|
+
|
|
41
|
+
- `settld_about`
|
|
42
|
+
- `settld_call`
|
|
41
43
|
|
|
42
44
|
Required env vars:
|
|
43
45
|
|
|
@@ -52,10 +54,10 @@ Optional env vars:
|
|
|
52
54
|
|
|
53
55
|
## Agent Usage Pattern
|
|
54
56
|
|
|
55
|
-
1. Call `
|
|
56
|
-
2. For paid search/data calls, use:
|
|
57
|
-
- `settld.exa_search_paid`
|
|
58
|
-
- `settld.weather_current_paid`
|
|
57
|
+
1. Call `settld_about` to verify connectivity.
|
|
58
|
+
2. For paid search/data calls, use `settld_call` with:
|
|
59
|
+
- `tool=settld.exa_search_paid`
|
|
60
|
+
- `tool=settld.weather_current_paid`
|
|
59
61
|
3. For agreement lifecycle demo calls, use:
|
|
60
62
|
- `settld.create_agreement`
|
|
61
63
|
- `settld.submit_evidence`
|
|
@@ -64,8 +66,8 @@ Optional env vars:
|
|
|
64
66
|
|
|
65
67
|
## Smoke Prompts
|
|
66
68
|
|
|
67
|
-
- "
|
|
68
|
-
- "
|
|
69
|
+
- "Use tool `settld_about` and return JSON."
|
|
70
|
+
- "Use tool `settld_call` with `tool=settld.weather_current_paid` and arguments for Chicago/fahrenheit."
|
|
69
71
|
|
|
70
72
|
## Identity + Traceability
|
|
71
73
|
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import process from "node:process";
|
|
5
|
+
import { spawn } from "node:child_process";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
|
|
8
|
+
const REQUIRED_ENV_KEYS = ["SETTLD_BASE_URL", "SETTLD_TENANT_ID", "SETTLD_API_KEY"];
|
|
9
|
+
const OPTIONAL_ENV_KEYS = ["SETTLD_PAID_TOOLS_BASE_URL", "SETTLD_PAID_TOOLS_AGENT_PASSPORT"];
|
|
10
|
+
const MCP_SCRIPT_PATH = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "scripts", "mcp", "settld-mcp-server.mjs");
|
|
11
|
+
|
|
12
|
+
function isObject(value) {
|
|
13
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function pickString(value) {
|
|
17
|
+
if (typeof value !== "string") return "";
|
|
18
|
+
return value.trim();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function parseSettldServerConfig(mcpConfig) {
|
|
22
|
+
if (!isObject(mcpConfig)) return null;
|
|
23
|
+
if (isObject(mcpConfig.mcpServers) && isObject(mcpConfig.mcpServers.settld)) {
|
|
24
|
+
return mcpConfig.mcpServers.settld;
|
|
25
|
+
}
|
|
26
|
+
if (pickString(mcpConfig.name) === "settld") return mcpConfig;
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function parseSettldEnvFromServer(server) {
|
|
31
|
+
if (!isObject(server) || !isObject(server.env)) return {};
|
|
32
|
+
const env = {};
|
|
33
|
+
for (const key of [...REQUIRED_ENV_KEYS, ...OPTIONAL_ENV_KEYS]) {
|
|
34
|
+
const value = pickString(server.env[key]);
|
|
35
|
+
if (value) env[key] = value;
|
|
36
|
+
}
|
|
37
|
+
return env;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function defaultMcpConfigPathCandidates() {
|
|
41
|
+
const home = os.homedir();
|
|
42
|
+
const xdgConfigHome = pickString(process.env.XDG_CONFIG_HOME) || path.join(home, ".config");
|
|
43
|
+
return [
|
|
44
|
+
pickString(process.env.OPENCLAW_MCP_CONFIG_PATH),
|
|
45
|
+
pickString(process.env.OPENCLAW_HOME) ? path.join(pickString(process.env.OPENCLAW_HOME), "mcp.json") : "",
|
|
46
|
+
path.join(home, "Library", "Application Support", "OpenClaw", "mcp.json"),
|
|
47
|
+
path.join(home, ".openclaw", "mcp.json"),
|
|
48
|
+
path.join(xdgConfigHome, "OpenClaw", "mcp.json"),
|
|
49
|
+
path.join(xdgConfigHome, "openclaw", "mcp.json")
|
|
50
|
+
].filter(Boolean);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async function readSettldEnvFromMcpConfig(mcpConfigPath) {
|
|
54
|
+
const raw = await fs.readFile(mcpConfigPath, "utf8");
|
|
55
|
+
const parsed = JSON.parse(raw);
|
|
56
|
+
const server = parseSettldServerConfig(parsed);
|
|
57
|
+
return parseSettldEnvFromServer(server);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async function resolveSettldEnv(pluginConfig = {}) {
|
|
61
|
+
const env = {};
|
|
62
|
+
|
|
63
|
+
const fromPluginConfig = {
|
|
64
|
+
SETTLD_BASE_URL: pickString(pluginConfig.baseUrl),
|
|
65
|
+
SETTLD_TENANT_ID: pickString(pluginConfig.tenantId),
|
|
66
|
+
SETTLD_API_KEY: pickString(pluginConfig.apiKey),
|
|
67
|
+
SETTLD_PAID_TOOLS_BASE_URL: pickString(pluginConfig.paidToolsBaseUrl),
|
|
68
|
+
SETTLD_PAID_TOOLS_AGENT_PASSPORT: pickString(pluginConfig.paidToolsAgentPassport)
|
|
69
|
+
};
|
|
70
|
+
for (const [key, value] of Object.entries(fromPluginConfig)) {
|
|
71
|
+
if (value) env[key] = value;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
for (const key of [...REQUIRED_ENV_KEYS, ...OPTIONAL_ENV_KEYS]) {
|
|
75
|
+
const value = pickString(process.env[key]);
|
|
76
|
+
if (value && !env[key]) env[key] = value;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const missingRequired = REQUIRED_ENV_KEYS.filter((key) => !pickString(env[key]));
|
|
80
|
+
if (missingRequired.length === 0) return env;
|
|
81
|
+
|
|
82
|
+
const candidates = [];
|
|
83
|
+
const explicitPath = pickString(pluginConfig.mcpConfigPath);
|
|
84
|
+
if (explicitPath) candidates.push(explicitPath);
|
|
85
|
+
candidates.push(...defaultMcpConfigPathCandidates());
|
|
86
|
+
|
|
87
|
+
const seen = new Set();
|
|
88
|
+
for (const candidate of candidates) {
|
|
89
|
+
const resolved = path.resolve(candidate);
|
|
90
|
+
if (seen.has(resolved)) continue;
|
|
91
|
+
seen.add(resolved);
|
|
92
|
+
try {
|
|
93
|
+
const fromFile = await readSettldEnvFromMcpConfig(resolved);
|
|
94
|
+
for (const [key, value] of Object.entries(fromFile)) {
|
|
95
|
+
if (value && !env[key]) env[key] = value;
|
|
96
|
+
}
|
|
97
|
+
const nowMissing = REQUIRED_ENV_KEYS.filter((key) => !pickString(env[key]));
|
|
98
|
+
if (nowMissing.length === 0) return env;
|
|
99
|
+
} catch {
|
|
100
|
+
// Keep searching; users may have multiple OpenClaw profiles/config paths.
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return env;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function parseLineJson(line) {
|
|
108
|
+
try {
|
|
109
|
+
return JSON.parse(line);
|
|
110
|
+
} catch {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function waitForRpcResponse(pendingMap, id, timeoutMs) {
|
|
116
|
+
return new Promise((resolve, reject) => {
|
|
117
|
+
const timer = setTimeout(() => {
|
|
118
|
+
pendingMap.delete(id);
|
|
119
|
+
reject(new Error(`MCP request timed out (id=${id})`));
|
|
120
|
+
}, timeoutMs);
|
|
121
|
+
pendingMap.set(id, { resolve, reject, timer });
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function routeRpcMessage(pendingMap, message) {
|
|
126
|
+
if (!isObject(message)) return;
|
|
127
|
+
if (!Object.prototype.hasOwnProperty.call(message, "id")) return;
|
|
128
|
+
const pending = pendingMap.get(message.id);
|
|
129
|
+
if (!pending) return;
|
|
130
|
+
clearTimeout(pending.timer);
|
|
131
|
+
pendingMap.delete(message.id);
|
|
132
|
+
pending.resolve(message);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function createStdoutRouter(stdout, pendingMap) {
|
|
136
|
+
let buffer = "";
|
|
137
|
+
stdout.setEncoding("utf8");
|
|
138
|
+
stdout.on("data", (chunk) => {
|
|
139
|
+
buffer += String(chunk ?? "");
|
|
140
|
+
while (buffer.includes("\n")) {
|
|
141
|
+
const idx = buffer.indexOf("\n");
|
|
142
|
+
const line = buffer.slice(0, idx).trim();
|
|
143
|
+
buffer = buffer.slice(idx + 1);
|
|
144
|
+
if (!line) continue;
|
|
145
|
+
const parsed = parseLineJson(line);
|
|
146
|
+
if (parsed) routeRpcMessage(pendingMap, parsed);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function rpcWrite(stdin, payload) {
|
|
152
|
+
stdin.write(`${JSON.stringify(payload)}\n`);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async function callSettldMcpTool({ toolName, toolArgs, env, timeoutMs = 30_000 }) {
|
|
156
|
+
const child = spawn(process.execPath, [MCP_SCRIPT_PATH], {
|
|
157
|
+
env: { ...process.env, ...env },
|
|
158
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
159
|
+
});
|
|
160
|
+
const pendingMap = new Map();
|
|
161
|
+
createStdoutRouter(child.stdout, pendingMap);
|
|
162
|
+
|
|
163
|
+
let stderr = "";
|
|
164
|
+
child.stderr.setEncoding("utf8");
|
|
165
|
+
child.stderr.on("data", (chunk) => {
|
|
166
|
+
stderr += String(chunk ?? "");
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
const waitInit = waitForRpcResponse(pendingMap, 1, timeoutMs);
|
|
170
|
+
rpcWrite(child.stdin, {
|
|
171
|
+
jsonrpc: "2.0",
|
|
172
|
+
id: 1,
|
|
173
|
+
method: "initialize",
|
|
174
|
+
params: {
|
|
175
|
+
protocolVersion: "2024-11-05",
|
|
176
|
+
clientInfo: { name: "openclaw-settld-plugin", version: "1" },
|
|
177
|
+
capabilities: {}
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
await waitInit;
|
|
181
|
+
rpcWrite(child.stdin, { jsonrpc: "2.0", method: "notifications/initialized", params: {} });
|
|
182
|
+
|
|
183
|
+
const waitCall = waitForRpcResponse(pendingMap, 2, timeoutMs);
|
|
184
|
+
rpcWrite(child.stdin, {
|
|
185
|
+
jsonrpc: "2.0",
|
|
186
|
+
id: 2,
|
|
187
|
+
method: "tools/call",
|
|
188
|
+
params: {
|
|
189
|
+
name: toolName,
|
|
190
|
+
arguments: isObject(toolArgs) ? toolArgs : {}
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
const callResponse = await waitCall;
|
|
194
|
+
|
|
195
|
+
child.kill("SIGTERM");
|
|
196
|
+
if (isObject(callResponse.error)) {
|
|
197
|
+
const message = pickString(callResponse.error.message) || "MCP tool call failed";
|
|
198
|
+
throw new Error(`${message}${stderr.trim() ? ` | stderr: ${stderr.trim()}` : ""}`);
|
|
199
|
+
}
|
|
200
|
+
return callResponse.result;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function buildMissingEnvMessage(env) {
|
|
204
|
+
const missing = REQUIRED_ENV_KEYS.filter((key) => !pickString(env[key]));
|
|
205
|
+
if (missing.length === 0) return "";
|
|
206
|
+
return [
|
|
207
|
+
`Missing Settld runtime env: ${missing.join(", ")}`,
|
|
208
|
+
"Run: npx -y settld@latest setup",
|
|
209
|
+
"Select host=openclaw in quick mode, then retry."
|
|
210
|
+
].join(" ");
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function normalizeToolArguments(params) {
|
|
214
|
+
if (isObject(params.arguments)) return params.arguments;
|
|
215
|
+
const raw = pickString(params.argumentsJson);
|
|
216
|
+
if (!raw) return {};
|
|
217
|
+
try {
|
|
218
|
+
const parsed = JSON.parse(raw);
|
|
219
|
+
if (!isObject(parsed)) {
|
|
220
|
+
throw new Error("argumentsJson must decode to a JSON object");
|
|
221
|
+
}
|
|
222
|
+
return parsed;
|
|
223
|
+
} catch (err) {
|
|
224
|
+
throw new Error(`Invalid argumentsJson: ${err?.message ?? "parse failed"}`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function buildToolResult(payload, details = {}) {
|
|
229
|
+
return {
|
|
230
|
+
content: [{ type: "text", text: JSON.stringify(payload ?? {}, null, 2) }],
|
|
231
|
+
details
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export default function register(api) {
|
|
236
|
+
api.registerTool({
|
|
237
|
+
name: "settld_about",
|
|
238
|
+
label: "Settld About",
|
|
239
|
+
description: "Check Settld runtime connectivity and capability info.",
|
|
240
|
+
parameters: {
|
|
241
|
+
type: "object",
|
|
242
|
+
additionalProperties: false,
|
|
243
|
+
properties: {}
|
|
244
|
+
},
|
|
245
|
+
async execute() {
|
|
246
|
+
const env = await resolveSettldEnv(api.pluginConfig ?? {});
|
|
247
|
+
const missingMessage = buildMissingEnvMessage(env);
|
|
248
|
+
if (missingMessage) throw new Error(missingMessage);
|
|
249
|
+
const result = await callSettldMcpTool({
|
|
250
|
+
toolName: "settld.about",
|
|
251
|
+
toolArgs: {},
|
|
252
|
+
env
|
|
253
|
+
});
|
|
254
|
+
return buildToolResult(result, { tool: "settld.about" });
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
api.registerTool({
|
|
259
|
+
name: "settld_call",
|
|
260
|
+
label: "Settld Tool Call",
|
|
261
|
+
description: "Call any Settld MCP tool by name with JSON arguments.",
|
|
262
|
+
parameters: {
|
|
263
|
+
type: "object",
|
|
264
|
+
additionalProperties: false,
|
|
265
|
+
required: ["tool"],
|
|
266
|
+
properties: {
|
|
267
|
+
tool: {
|
|
268
|
+
type: "string",
|
|
269
|
+
description: "Settld MCP tool name, for example settld.weather_current_paid."
|
|
270
|
+
},
|
|
271
|
+
arguments: {
|
|
272
|
+
type: "object",
|
|
273
|
+
additionalProperties: true,
|
|
274
|
+
description: "Tool arguments as an object."
|
|
275
|
+
},
|
|
276
|
+
argumentsJson: {
|
|
277
|
+
type: "string",
|
|
278
|
+
description: "JSON object string for arguments (use if your model cannot pass object args)."
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
},
|
|
282
|
+
async execute(_id, params = {}) {
|
|
283
|
+
const toolName = pickString(params.tool);
|
|
284
|
+
if (!toolName) throw new Error("tool is required");
|
|
285
|
+
if (!toolName.startsWith("settld.")) {
|
|
286
|
+
throw new Error("tool must start with settld.");
|
|
287
|
+
}
|
|
288
|
+
const toolArgs = normalizeToolArguments(params);
|
|
289
|
+
const env = await resolveSettldEnv(api.pluginConfig ?? {});
|
|
290
|
+
const missingMessage = buildMissingEnvMessage(env);
|
|
291
|
+
if (missingMessage) throw new Error(missingMessage);
|
|
292
|
+
const result = await callSettldMcpTool({
|
|
293
|
+
toolName,
|
|
294
|
+
toolArgs,
|
|
295
|
+
env
|
|
296
|
+
});
|
|
297
|
+
return buildToolResult(result, { tool: toolName });
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export {
|
|
303
|
+
parseSettldServerConfig,
|
|
304
|
+
parseSettldEnvFromServer,
|
|
305
|
+
resolveSettldEnv,
|
|
306
|
+
normalizeToolArguments
|
|
307
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "settld",
|
|
3
|
+
"name": "Settld",
|
|
4
|
+
"description": "Settld tools for OpenClaw with runtime env auto-discovery from Settld setup.",
|
|
5
|
+
"configSchema": {
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": false,
|
|
8
|
+
"properties": {
|
|
9
|
+
"baseUrl": {
|
|
10
|
+
"type": "string"
|
|
11
|
+
},
|
|
12
|
+
"tenantId": {
|
|
13
|
+
"type": "string"
|
|
14
|
+
},
|
|
15
|
+
"apiKey": {
|
|
16
|
+
"type": "string"
|
|
17
|
+
},
|
|
18
|
+
"paidToolsBaseUrl": {
|
|
19
|
+
"type": "string"
|
|
20
|
+
},
|
|
21
|
+
"paidToolsAgentPassport": {
|
|
22
|
+
"type": "string"
|
|
23
|
+
},
|
|
24
|
+
"mcpConfigPath": {
|
|
25
|
+
"type": "string"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "settld",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.8",
|
|
4
4
|
"description": "Settld kernel CLI and local control-plane tooling",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -19,6 +19,8 @@
|
|
|
19
19
|
"README.md",
|
|
20
20
|
"Dockerfile",
|
|
21
21
|
"docker-compose.yml",
|
|
22
|
+
"openclaw.plugin.json",
|
|
23
|
+
"openclaw",
|
|
22
24
|
"bin",
|
|
23
25
|
"conformance",
|
|
24
26
|
"packages/api-sdk/src",
|
|
@@ -35,6 +37,11 @@
|
|
|
35
37
|
"settld": "bin/settld.js",
|
|
36
38
|
"settld-mcp": "bin/settld-mcp"
|
|
37
39
|
},
|
|
40
|
+
"openclaw": {
|
|
41
|
+
"extensions": [
|
|
42
|
+
"./openclaw/index.js"
|
|
43
|
+
]
|
|
44
|
+
},
|
|
38
45
|
"exports": {
|
|
39
46
|
"./mcp": "./scripts/mcp/settld-mcp-server.mjs"
|
|
40
47
|
},
|
|
@@ -299,7 +299,7 @@ function parsePaidToolsAgentPassportFromEnv(env) {
|
|
|
299
299
|
|
|
300
300
|
function parseMcpArgsFromEnv(env) {
|
|
301
301
|
const argsJson = typeof env.SETTLD_MCP_ARGS_JSON === "string" ? env.SETTLD_MCP_ARGS_JSON.trim() : "";
|
|
302
|
-
if (!argsJson) return ["-y", "settld-mcp"];
|
|
302
|
+
if (!argsJson) return ["-y", "--package", "settld", "settld-mcp"];
|
|
303
303
|
let parsed;
|
|
304
304
|
try {
|
|
305
305
|
parsed = JSON.parse(argsJson);
|
|
@@ -874,8 +874,10 @@ function buildHostNextSteps({ host, installedHosts }) {
|
|
|
874
874
|
}
|
|
875
875
|
if (host === "openclaw") {
|
|
876
876
|
steps.push("Run `openclaw doctor` and ensure OpenClaw itself is onboarded (`openclaw onboard --install-daemon`).");
|
|
877
|
-
steps.push("
|
|
878
|
-
steps.push("
|
|
877
|
+
steps.push("Install the Settld OpenClaw plugin: `openclaw plugins install settld@latest`.");
|
|
878
|
+
steps.push("Verify in local mode: `openclaw agent --local --agent main --session-id settld-smoke --message \"Use the tool named settld_about with empty arguments. Return only JSON.\" --json`.");
|
|
879
|
+
steps.push("Run `openclaw tui --session main`.");
|
|
880
|
+
steps.push("If you are in a channel-bound session (e.g. whatsapp:*), switch back to `main` to access Settld tools.");
|
|
879
881
|
return steps;
|
|
880
882
|
}
|
|
881
883
|
if (host === "codex") {
|
|
@@ -1020,6 +1022,17 @@ async function runGuidedQuickFlow({
|
|
|
1020
1022
|
}
|
|
1021
1023
|
}
|
|
1022
1024
|
|
|
1025
|
+
const paidToolsBaseUrl = String(actionEnv.SETTLD_PAID_TOOLS_BASE_URL ?? "").trim();
|
|
1026
|
+
if (!paidToolsBaseUrl) {
|
|
1027
|
+
summary.firstPaidCall = {
|
|
1028
|
+
ok: false,
|
|
1029
|
+
skipped: true,
|
|
1030
|
+
reason: "SETTLD_PAID_TOOLS_BASE_URL not configured"
|
|
1031
|
+
};
|
|
1032
|
+
summary.warnings.push("first paid call probe skipped (SETTLD_PAID_TOOLS_BASE_URL not configured)");
|
|
1033
|
+
return summary;
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1023
1036
|
const paidProbe = runMcpPaidCallProbe({ env: actionEnv });
|
|
1024
1037
|
if (paidProbe.ok) {
|
|
1025
1038
|
summary.firstPaidCall = { ok: true };
|
|
@@ -1958,7 +1971,8 @@ export async function runOnboard({
|
|
|
1958
1971
|
if (guided.ran) {
|
|
1959
1972
|
lines.push(`- wallet fund: ${guided.walletFund?.ok ? "ok" : "not completed"}`);
|
|
1960
1973
|
lines.push(`- wallet balance watch: ${guided.walletBalanceWatch?.ok ? "ok" : "not completed"}`);
|
|
1961
|
-
|
|
1974
|
+
const firstPaidCallState = guided.firstPaidCall?.skipped ? "skipped" : guided.firstPaidCall?.ok ? "ok" : "failed";
|
|
1975
|
+
lines.push(`- first paid call: ${firstPaidCallState}`);
|
|
1962
1976
|
} else {
|
|
1963
1977
|
lines.push("- skipped");
|
|
1964
1978
|
}
|
|
@@ -5262,7 +5262,7 @@ async function handleTenantRuntimeBootstrap(req, res, tenantId) {
|
|
|
5262
5262
|
const mcp = {
|
|
5263
5263
|
schemaVersion: "SettldMcpServerConfig.v1",
|
|
5264
5264
|
command: "npx",
|
|
5265
|
-
args: ["-y", "settld-mcp"],
|
|
5265
|
+
args: ["-y", "--package", "settld", "settld-mcp"],
|
|
5266
5266
|
env: mcpEnv
|
|
5267
5267
|
};
|
|
5268
5268
|
const mcpConfigJson = {
|
|
@@ -6212,7 +6212,7 @@ async function handleTenantRuntimeConformanceMatrix(req, res, tenantId) {
|
|
|
6212
6212
|
const smokeOk = checkById.get("mcp_smoke")?.status === "pass";
|
|
6213
6213
|
const paidOk = checkById.get("first_paid_call")?.status === "pass";
|
|
6214
6214
|
const targetRows = targets.map((target) => {
|
|
6215
|
-
const serverConfig = mcpEnv ? { command: "npx", args: ["-y", "settld-mcp"], env: mcpEnv } : null;
|
|
6215
|
+
const serverConfig = mcpEnv ? { command: "npx", args: ["-y", "--package", "settld", "settld-mcp"], env: mcpEnv } : null;
|
|
6216
6216
|
let config;
|
|
6217
6217
|
if (target === "openhands") {
|
|
6218
6218
|
config = {
|