@artyfacts/openclaw 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/README.md +92 -0
- package/bin/artyfacts-openclaw.js +2 -0
- package/dist/chunk-CTWVGZRX.mjs +1119 -0
- package/dist/chunk-TT3SG5BN.mjs +987 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +1508 -0
- package/dist/cli.mjs +391 -0
- package/dist/index.d.mts +446 -0
- package/dist/index.d.ts +446 -0
- package/dist/index.js +1172 -0
- package/dist/index.mjs +36 -0
- package/package.json +64 -0
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,391 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
clearCredentials,
|
|
4
|
+
createExecutor,
|
|
5
|
+
createListener,
|
|
6
|
+
createMcpHandler,
|
|
7
|
+
getCredentials,
|
|
8
|
+
introspect,
|
|
9
|
+
loadCredentials,
|
|
10
|
+
promptForApiKey,
|
|
11
|
+
summarize
|
|
12
|
+
} from "./chunk-CTWVGZRX.mjs";
|
|
13
|
+
|
|
14
|
+
// src/cli.ts
|
|
15
|
+
import { Command } from "commander";
|
|
16
|
+
var VERSION = "0.1.0";
|
|
17
|
+
var DEFAULT_BASE_URL = "https://artyfacts.dev/api/v1";
|
|
18
|
+
function isMcpConfigured(openclawPath = "openclaw") {
|
|
19
|
+
const handler = createMcpHandler({ apiKey: "", openclawPath });
|
|
20
|
+
return handler.isConfigured().configured;
|
|
21
|
+
}
|
|
22
|
+
function configureMcp(apiKey, baseUrl, openclawPath = "openclaw") {
|
|
23
|
+
const handler = createMcpHandler({ apiKey, baseUrl, openclawPath });
|
|
24
|
+
return handler.configure();
|
|
25
|
+
}
|
|
26
|
+
function ensureMcpConfigured(apiKey, baseUrl, openclawPath = "openclaw") {
|
|
27
|
+
if (isMcpConfigured(openclawPath)) {
|
|
28
|
+
console.log("\u2705 Artyfacts MCP tools already configured");
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
configureMcp(apiKey, baseUrl, openclawPath);
|
|
32
|
+
}
|
|
33
|
+
var program = new Command();
|
|
34
|
+
program.name("artyfacts-openclaw").description("OpenClaw adapter for Artyfacts - Execute tasks using OpenClaw CLI").version(VERSION);
|
|
35
|
+
program.command("run", { isDefault: true }).description("Start listening for and executing tasks").option("--base-url <url>", "Artyfacts API base URL", DEFAULT_BASE_URL).option("--dry-run", "Print tasks but do not execute", false).option("--openclaw-path <path>", "Path to openclaw CLI", "openclaw").action(async (options) => {
|
|
36
|
+
await runAgent(options);
|
|
37
|
+
});
|
|
38
|
+
program.command("login").description("Authenticate with Artyfacts").option("--manual", "Enter credentials manually instead of device auth").option("--base-url <url>", "Artyfacts API base URL", DEFAULT_BASE_URL).action(async (options) => {
|
|
39
|
+
try {
|
|
40
|
+
if (options.manual) {
|
|
41
|
+
await promptForApiKey();
|
|
42
|
+
} else {
|
|
43
|
+
await getCredentials({ baseUrl: options.baseUrl, forceAuth: true });
|
|
44
|
+
}
|
|
45
|
+
} catch (error) {
|
|
46
|
+
console.error("\u274C Authentication failed:", error instanceof Error ? error.message : error);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
program.command("logout").description("Clear stored credentials").action(() => {
|
|
51
|
+
clearCredentials();
|
|
52
|
+
console.log("\u2705 Credentials cleared");
|
|
53
|
+
});
|
|
54
|
+
program.command("status").description("Check authentication and connection status").option("--openclaw-path <path>", "Path to openclaw CLI", "openclaw").action(async (options) => {
|
|
55
|
+
const credentials = loadCredentials();
|
|
56
|
+
if (!credentials) {
|
|
57
|
+
console.log("\u274C Not authenticated");
|
|
58
|
+
console.log(" Run: npx @artyfacts/openclaw login");
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
console.log("\u2705 Authenticated");
|
|
62
|
+
console.log(` Agent ID: ${credentials.agentId}`);
|
|
63
|
+
if (credentials.agentName) {
|
|
64
|
+
console.log(` Agent Name: ${credentials.agentName}`);
|
|
65
|
+
}
|
|
66
|
+
const executor = createExecutor({ openclawPath: options.openclawPath });
|
|
67
|
+
const installed = await executor.isInstalled();
|
|
68
|
+
if (installed) {
|
|
69
|
+
const version = await executor.getVersion();
|
|
70
|
+
console.log(`\u2705 OpenClaw CLI installed${version ? ` (${version})` : ""}`);
|
|
71
|
+
} else {
|
|
72
|
+
console.log("\u274C OpenClaw CLI not found");
|
|
73
|
+
console.log(" Install with: npm install -g openclaw");
|
|
74
|
+
}
|
|
75
|
+
if (isMcpConfigured(options.openclawPath)) {
|
|
76
|
+
console.log("\u2705 Artyfacts MCP tools configured");
|
|
77
|
+
} else {
|
|
78
|
+
console.log("\u26A0\uFE0F Artyfacts MCP tools not configured");
|
|
79
|
+
console.log(" Will configure automatically on first run");
|
|
80
|
+
}
|
|
81
|
+
console.log("");
|
|
82
|
+
console.log("\u{1F4C2} Local Configuration:");
|
|
83
|
+
try {
|
|
84
|
+
const config = await introspect();
|
|
85
|
+
const summary = summarize(config);
|
|
86
|
+
console.log(` ${summary}`);
|
|
87
|
+
if (config.crons.length > 0 || config.skills.length > 0 || config.mcpServers.length > 0) {
|
|
88
|
+
console.log("");
|
|
89
|
+
console.log(" Run `npx @artyfacts/openclaw introspect` for details");
|
|
90
|
+
console.log(" Run `npx @artyfacts/openclaw import` to sync to Artyfacts");
|
|
91
|
+
}
|
|
92
|
+
} catch (err) {
|
|
93
|
+
console.log(" (Could not read local config)");
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
program.command("introspect").description("Show detailed local OpenClaw configuration").option("--json", "Output as JSON").action(async (options) => {
|
|
97
|
+
try {
|
|
98
|
+
const config = await introspect();
|
|
99
|
+
if (options.json) {
|
|
100
|
+
console.log(JSON.stringify(config, null, 2));
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
console.log("");
|
|
104
|
+
console.log("\u{1F4C2} OpenClaw Configuration");
|
|
105
|
+
console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
|
|
106
|
+
console.log("");
|
|
107
|
+
console.log(`\u{1F4C5} Cron Jobs (${config.crons.length})`);
|
|
108
|
+
if (config.crons.length === 0) {
|
|
109
|
+
console.log(" (none)");
|
|
110
|
+
} else {
|
|
111
|
+
for (const job of config.crons) {
|
|
112
|
+
const schedule = job.schedule.cron || job.schedule.every || job.schedule.at;
|
|
113
|
+
const status = job.enabled === false ? " [disabled]" : "";
|
|
114
|
+
console.log(` \u2022 ${job.name || job.jobId}: ${schedule}${status}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
console.log("");
|
|
118
|
+
console.log("\u{1F493} Heartbeat");
|
|
119
|
+
if (config.heartbeat) {
|
|
120
|
+
console.log(` Interval: ${config.heartbeat.every || "30m"}`);
|
|
121
|
+
if (config.heartbeat.target) {
|
|
122
|
+
console.log(` Target: ${config.heartbeat.target}${config.heartbeat.to ? ` \u2192 ${config.heartbeat.to}` : ""}`);
|
|
123
|
+
}
|
|
124
|
+
if (config.heartbeat.activeHours) {
|
|
125
|
+
console.log(` Active: ${config.heartbeat.activeHours.start} - ${config.heartbeat.activeHours.end}`);
|
|
126
|
+
}
|
|
127
|
+
} else {
|
|
128
|
+
console.log(" (using defaults or disabled)");
|
|
129
|
+
}
|
|
130
|
+
console.log("");
|
|
131
|
+
console.log(`\u{1F916} Agents (${config.agents.length})`);
|
|
132
|
+
if (config.agents.length === 0) {
|
|
133
|
+
console.log(" (using default agent)");
|
|
134
|
+
} else {
|
|
135
|
+
for (const agent of config.agents) {
|
|
136
|
+
const def = agent.default ? " [default]" : "";
|
|
137
|
+
console.log(` \u2022 ${agent.id}${agent.name ? ` (${agent.name})` : ""}${def}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
console.log("");
|
|
141
|
+
console.log(`\u{1F50C} MCP Servers (${config.mcpServers.length})`);
|
|
142
|
+
if (config.mcpServers.length === 0) {
|
|
143
|
+
console.log(" (none)");
|
|
144
|
+
} else {
|
|
145
|
+
for (const server of config.mcpServers) {
|
|
146
|
+
console.log(` \u2022 ${server.name}: ${server.url || server.command}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
console.log("");
|
|
150
|
+
console.log(`\u{1F4DA} Skills (${config.skills.length})`);
|
|
151
|
+
if (config.skills.length === 0) {
|
|
152
|
+
console.log(" (none in ~/.openclaw/skills/)");
|
|
153
|
+
} else {
|
|
154
|
+
for (const skill of config.skills) {
|
|
155
|
+
const desc = skill.description ? ` - ${skill.description.slice(0, 50)}...` : "";
|
|
156
|
+
console.log(` \u2022 ${skill.name}${desc}`);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
console.log("");
|
|
160
|
+
console.log(`\u{1F4F1} Channels (${config.channels.length})`);
|
|
161
|
+
if (config.channels.length === 0) {
|
|
162
|
+
console.log(" (none configured)");
|
|
163
|
+
} else {
|
|
164
|
+
console.log(` ${config.channels.join(", ")}`);
|
|
165
|
+
}
|
|
166
|
+
console.log("");
|
|
167
|
+
} catch (err) {
|
|
168
|
+
console.error("\u274C Failed to read configuration:", err instanceof Error ? err.message : err);
|
|
169
|
+
process.exit(1);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
program.command("import").description("Import local OpenClaw configuration to Artyfacts").option("--base-url <url>", "Artyfacts API base URL", DEFAULT_BASE_URL).option("--dry-run", "Show what would be imported without importing").option("--crons", "Import only cron jobs").option("--skills", "Import only skills").option("--mcp", "Import only MCP servers").option("--agents", "Import only agents").action(async (options) => {
|
|
173
|
+
const credentials = loadCredentials();
|
|
174
|
+
if (!credentials) {
|
|
175
|
+
console.log("\u274C Not authenticated. Run login first:");
|
|
176
|
+
console.log(" npx @artyfacts/openclaw login");
|
|
177
|
+
process.exit(1);
|
|
178
|
+
}
|
|
179
|
+
try {
|
|
180
|
+
const config = await introspect();
|
|
181
|
+
const importAll = !options.crons && !options.skills && !options.mcp && !options.agents;
|
|
182
|
+
const toImport = {
|
|
183
|
+
crons: importAll || options.crons,
|
|
184
|
+
skills: importAll || options.skills,
|
|
185
|
+
mcp: importAll || options.mcp,
|
|
186
|
+
agents: importAll || options.agents
|
|
187
|
+
};
|
|
188
|
+
console.log("");
|
|
189
|
+
console.log("\u{1F4E4} Importing to Artyfacts");
|
|
190
|
+
console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
|
|
191
|
+
console.log("");
|
|
192
|
+
const payload = {
|
|
193
|
+
source: "openclaw",
|
|
194
|
+
agentId: credentials.agentId
|
|
195
|
+
};
|
|
196
|
+
if (toImport.crons && config.crons.length > 0) {
|
|
197
|
+
console.log(`\u{1F4C5} Cron jobs: ${config.crons.length}`);
|
|
198
|
+
payload.crons = config.crons;
|
|
199
|
+
}
|
|
200
|
+
if (toImport.skills && config.skills.length > 0) {
|
|
201
|
+
console.log(`\u{1F4DA} Skills: ${config.skills.length}`);
|
|
202
|
+
payload.skills = config.skills.map((s) => ({
|
|
203
|
+
name: s.name,
|
|
204
|
+
description: s.description,
|
|
205
|
+
content: s.content
|
|
206
|
+
}));
|
|
207
|
+
}
|
|
208
|
+
if (toImport.mcp && config.mcpServers.length > 0) {
|
|
209
|
+
console.log(`\u{1F50C} MCP servers: ${config.mcpServers.length}`);
|
|
210
|
+
payload.mcpServers = config.mcpServers;
|
|
211
|
+
}
|
|
212
|
+
if (toImport.agents && config.agents.length > 0) {
|
|
213
|
+
console.log(`\u{1F916} Agents: ${config.agents.length}`);
|
|
214
|
+
payload.agents = config.agents;
|
|
215
|
+
}
|
|
216
|
+
if (config.heartbeat && (importAll || options.agents)) {
|
|
217
|
+
console.log("\u{1F493} Heartbeat config");
|
|
218
|
+
payload.heartbeat = config.heartbeat;
|
|
219
|
+
}
|
|
220
|
+
if (config.channels.length > 0 && importAll) {
|
|
221
|
+
payload.channels = config.channels;
|
|
222
|
+
}
|
|
223
|
+
console.log("");
|
|
224
|
+
if (options.dryRun) {
|
|
225
|
+
console.log("[DRY RUN] Would import:");
|
|
226
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
const response = await fetch(`${options.baseUrl}/agents/${credentials.agentId}/config/import`, {
|
|
230
|
+
method: "POST",
|
|
231
|
+
headers: {
|
|
232
|
+
"Content-Type": "application/json",
|
|
233
|
+
"Authorization": `Bearer ${credentials.apiKey}`
|
|
234
|
+
},
|
|
235
|
+
body: JSON.stringify(payload)
|
|
236
|
+
});
|
|
237
|
+
if (!response.ok) {
|
|
238
|
+
const errorText = await response.text();
|
|
239
|
+
throw new Error(`Import failed: ${errorText}`);
|
|
240
|
+
}
|
|
241
|
+
const result = await response.json();
|
|
242
|
+
console.log("\u2705 Import successful!");
|
|
243
|
+
if (result.imported) {
|
|
244
|
+
console.log(` Imported: ${Object.entries(result.imported).map(([k, v]) => `${v} ${k}`).join(", ")}`);
|
|
245
|
+
}
|
|
246
|
+
console.log("");
|
|
247
|
+
console.log(" View in Artyfacts: https://artyfacts.dev/agents/" + credentials.agentId);
|
|
248
|
+
console.log("");
|
|
249
|
+
} catch (err) {
|
|
250
|
+
console.error("\u274C Import failed:", err instanceof Error ? err.message : err);
|
|
251
|
+
process.exit(1);
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
program.command("configure").description("Configure Artyfacts MCP tools for OpenClaw").option("--base-url <url>", "Artyfacts API base URL", DEFAULT_BASE_URL).option("--openclaw-path <path>", "Path to openclaw CLI", "openclaw").action(async (options) => {
|
|
255
|
+
const credentials = loadCredentials();
|
|
256
|
+
if (!credentials) {
|
|
257
|
+
console.log("\u274C Not authenticated. Run login first:");
|
|
258
|
+
console.log(" npx @artyfacts/openclaw login");
|
|
259
|
+
process.exit(1);
|
|
260
|
+
}
|
|
261
|
+
const success = configureMcp(credentials.apiKey, options.baseUrl, options.openclawPath);
|
|
262
|
+
if (!success) {
|
|
263
|
+
process.exit(1);
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
async function runAgent(options) {
|
|
267
|
+
console.log("");
|
|
268
|
+
console.log("\u{1F99E} Artyfacts OpenClaw Adapter");
|
|
269
|
+
console.log("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
|
|
270
|
+
console.log("");
|
|
271
|
+
const credentials = await getCredentials({ baseUrl: options.baseUrl });
|
|
272
|
+
const executor = createExecutor({
|
|
273
|
+
openclawPath: options.openclawPath,
|
|
274
|
+
baseUrl: options.baseUrl,
|
|
275
|
+
apiKey: credentials.apiKey
|
|
276
|
+
});
|
|
277
|
+
const installed = await executor.isInstalled();
|
|
278
|
+
if (!installed) {
|
|
279
|
+
console.error("\u274C OpenClaw CLI not found. Please install it:");
|
|
280
|
+
console.error(" npm install -g openclaw");
|
|
281
|
+
process.exit(1);
|
|
282
|
+
}
|
|
283
|
+
ensureMcpConfigured(credentials.apiKey, options.baseUrl, options.openclawPath);
|
|
284
|
+
console.log("");
|
|
285
|
+
const listener = createListener({
|
|
286
|
+
baseUrl: options.baseUrl,
|
|
287
|
+
apiKey: credentials.apiKey,
|
|
288
|
+
agentId: credentials.agentId,
|
|
289
|
+
onStateChange: (state) => {
|
|
290
|
+
if (state === "disconnected") {
|
|
291
|
+
console.log("\u26A0\uFE0F Disconnected from Artyfacts");
|
|
292
|
+
} else if (state === "reconnecting") {
|
|
293
|
+
console.log("\u{1F504} Reconnecting...");
|
|
294
|
+
}
|
|
295
|
+
},
|
|
296
|
+
onError: (error) => {
|
|
297
|
+
console.error("\u274C Listener error:", error.message);
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
listener.on("task_assigned", async (event) => {
|
|
301
|
+
const task = event.data;
|
|
302
|
+
console.log("");
|
|
303
|
+
console.log("\u{1F4CB} Task received:");
|
|
304
|
+
console.log(` ${task.heading}`);
|
|
305
|
+
console.log(` ID: ${task.sectionId}`);
|
|
306
|
+
console.log(` Artifact: ${task.artifactTitle || task.artifactId}`);
|
|
307
|
+
console.log("");
|
|
308
|
+
if (options.dryRun) {
|
|
309
|
+
console.log(" [DRY RUN] Would execute task");
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
console.log("\u{1F504} Executing task...");
|
|
313
|
+
const taskContext = {
|
|
314
|
+
taskId: task.sectionId,
|
|
315
|
+
heading: task.heading,
|
|
316
|
+
content: task.content,
|
|
317
|
+
artifactId: task.artifactId,
|
|
318
|
+
artifactTitle: task.artifactTitle,
|
|
319
|
+
priority: task.priority
|
|
320
|
+
};
|
|
321
|
+
const result = await executor.execute(taskContext);
|
|
322
|
+
if (result.success) {
|
|
323
|
+
console.log("\u2705 Task completed");
|
|
324
|
+
console.log(` Summary: ${result.summary}`);
|
|
325
|
+
try {
|
|
326
|
+
await reportTaskCompletion(options.baseUrl, credentials.apiKey, {
|
|
327
|
+
taskId: task.sectionId,
|
|
328
|
+
success: true,
|
|
329
|
+
summary: result.summary,
|
|
330
|
+
output: result.output
|
|
331
|
+
});
|
|
332
|
+
console.log(" \u{1F4E4} Result reported to Artyfacts");
|
|
333
|
+
} catch (reportError) {
|
|
334
|
+
console.error(" \u26A0\uFE0F Failed to report result:", reportError);
|
|
335
|
+
}
|
|
336
|
+
} else {
|
|
337
|
+
console.log("\u274C Task failed");
|
|
338
|
+
console.log(` Error: ${result.error}`);
|
|
339
|
+
try {
|
|
340
|
+
await reportTaskCompletion(options.baseUrl, credentials.apiKey, {
|
|
341
|
+
taskId: task.sectionId,
|
|
342
|
+
success: false,
|
|
343
|
+
error: result.error
|
|
344
|
+
});
|
|
345
|
+
} catch (reportError) {
|
|
346
|
+
console.error(" \u26A0\uFE0F Failed to report error:", reportError);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
listener.on("mcp_connect_request", async (event) => {
|
|
351
|
+
console.log("");
|
|
352
|
+
console.log(`\u{1F50C} MCP connection request: ${event.data.platform}`);
|
|
353
|
+
console.log(" (MCP connection handling not yet implemented for OpenClaw)");
|
|
354
|
+
});
|
|
355
|
+
listener.on("connected", (event) => {
|
|
356
|
+
console.log("\u2705 Connected to Artyfacts");
|
|
357
|
+
console.log("\u{1F3A7} Listening for tasks...");
|
|
358
|
+
console.log("");
|
|
359
|
+
});
|
|
360
|
+
await listener.connect();
|
|
361
|
+
process.on("SIGINT", () => {
|
|
362
|
+
console.log("");
|
|
363
|
+
console.log("\u{1F44B} Shutting down...");
|
|
364
|
+
listener.disconnect();
|
|
365
|
+
process.exit(0);
|
|
366
|
+
});
|
|
367
|
+
process.on("SIGTERM", () => {
|
|
368
|
+
listener.disconnect();
|
|
369
|
+
process.exit(0);
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
async function reportTaskCompletion(baseUrl, apiKey, result) {
|
|
373
|
+
const endpoint = `${baseUrl}/tasks/${result.taskId}/complete`;
|
|
374
|
+
const response = await fetch(endpoint, {
|
|
375
|
+
method: "POST",
|
|
376
|
+
headers: {
|
|
377
|
+
"Content-Type": "application/json",
|
|
378
|
+
"Authorization": `Bearer ${apiKey}`
|
|
379
|
+
},
|
|
380
|
+
body: JSON.stringify({
|
|
381
|
+
status: result.success ? "done" : "failed",
|
|
382
|
+
output_summary: result.summary || result.error,
|
|
383
|
+
output_url: null
|
|
384
|
+
})
|
|
385
|
+
});
|
|
386
|
+
if (!response.ok) {
|
|
387
|
+
const errorText = await response.text();
|
|
388
|
+
throw new Error(`Failed to report completion: ${errorText}`);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
program.parse();
|