clawdock 0.1.1 → 0.2.1
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 +59 -14
- package/dist/index.js +197 -70
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# ClawDock CLI
|
|
2
2
|
|
|
3
|
-
The command-line tool for [ClawDock](https://clawhub-one.vercel.app) — the agent registry. Push, pull,
|
|
3
|
+
The command-line tool for [ClawDock](https://clawhub-one.vercel.app) — the agent registry. Push, pull, and run OpenClaw agent bundles.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -11,24 +11,20 @@ npm install -g clawdock
|
|
|
11
11
|
## Quick Start
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
#
|
|
15
|
-
clawdock
|
|
14
|
+
# 1. Set up runtime credentials (one-time)
|
|
15
|
+
clawdock credentials set --provider github-copilot --api-key ghu_xxx --model github-copilot/claude-sonnet-4
|
|
16
16
|
|
|
17
|
-
#
|
|
18
|
-
clawdock
|
|
19
|
-
|
|
20
|
-
# Push your agent
|
|
21
|
-
clawdock push
|
|
22
|
-
|
|
23
|
-
# Pull an agent
|
|
24
|
-
clawdock pull username/agent-name
|
|
17
|
+
# 2. Pull and run any agent
|
|
18
|
+
clawdock run hugo/caramelo
|
|
25
19
|
```
|
|
26
20
|
|
|
27
21
|
## Commands
|
|
28
22
|
|
|
23
|
+
### Registry
|
|
24
|
+
|
|
29
25
|
| Command | Description |
|
|
30
26
|
|---------|-------------|
|
|
31
|
-
| `clawdock login` | Authenticate with your access token |
|
|
27
|
+
| `clawdock login` | Authenticate with your registry access token |
|
|
32
28
|
| `clawdock whoami` | Show current user |
|
|
33
29
|
| `clawdock init` | Create a `manifest.json` in the current directory |
|
|
34
30
|
| `clawdock push [path]` | Bundle and publish an agent |
|
|
@@ -36,12 +32,61 @@ clawdock pull username/agent-name
|
|
|
36
32
|
| `clawdock search <query>` | Search the registry |
|
|
37
33
|
| `clawdock list` | List your published bundles |
|
|
38
34
|
|
|
35
|
+
### Runtime
|
|
36
|
+
|
|
37
|
+
| Command | Description |
|
|
38
|
+
|---------|-------------|
|
|
39
|
+
| `clawdock credentials set` | Configure provider/model/runtime for running agents |
|
|
40
|
+
| `clawdock credentials show` | Show stored runtime credentials |
|
|
41
|
+
| `clawdock credentials clear` | Remove stored credentials |
|
|
42
|
+
| `clawdock run <owner/slug[@version]>` | Pull + launch an agent locally |
|
|
43
|
+
|
|
44
|
+
### `clawdock run`
|
|
45
|
+
|
|
46
|
+
Pulls an agent bundle and launches it with a local runtime (OpenClaw by default).
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
# Uses stored credentials
|
|
50
|
+
clawdock run hugo/caramelo
|
|
51
|
+
|
|
52
|
+
# Override model
|
|
53
|
+
clawdock run hugo/caramelo --model github-copilot/claude-opus-4
|
|
54
|
+
|
|
55
|
+
# Use a different runtime
|
|
56
|
+
clawdock run hugo/caramelo --runtime nullclaw@latest
|
|
57
|
+
|
|
58
|
+
# Skip pull (use cached workspace)
|
|
59
|
+
clawdock run hugo/caramelo --no-pull
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Agents are cached at `~/.clawdock/agents/<owner>/<slug>/workspace/`.
|
|
63
|
+
|
|
64
|
+
### Supported Runtimes
|
|
65
|
+
|
|
66
|
+
| Runtime | Default | Install |
|
|
67
|
+
|---------|---------|---------|
|
|
68
|
+
| `openclaw@latest` | ✅ | `npm install -g openclaw` (auto-installed if missing) |
|
|
69
|
+
| `nullclaw@latest` | | [github.com/pigeonflow/brain-arch-v2](https://github.com/pigeonflow/brain-arch-v2) |
|
|
70
|
+
|
|
39
71
|
## Configuration
|
|
40
72
|
|
|
41
|
-
|
|
73
|
+
All config lives in `~/.clawdock/config.json`:
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"apiKey": "cd_registry_token",
|
|
78
|
+
"registry": "https://clawhub-one.vercel.app",
|
|
79
|
+
"runtime": {
|
|
80
|
+
"provider": "github-copilot",
|
|
81
|
+
"apiKey": "ghu_xxx",
|
|
82
|
+
"model": "github-copilot/claude-sonnet-4",
|
|
83
|
+
"runtime": "openclaw@latest"
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
42
87
|
|
|
43
88
|
Environment variables:
|
|
44
|
-
- `CLAWDOCK_API_KEY` — override
|
|
89
|
+
- `CLAWDOCK_API_KEY` — override runtime API key
|
|
45
90
|
- `CLAWDOCK_REGISTRY` — override registry URL
|
|
46
91
|
|
|
47
92
|
## License
|
package/dist/index.js
CHANGED
|
@@ -235,7 +235,59 @@ program.command("init").description("Create a manifest.json for your agent").act
|
|
|
235
235
|
console.log(`\u2705 Created manifest.json`);
|
|
236
236
|
console.log(` Edit it, then run: clawdock push`);
|
|
237
237
|
});
|
|
238
|
-
program.command("
|
|
238
|
+
var credentials = program.command("credentials").description("Manage runtime credentials for clawdock run");
|
|
239
|
+
credentials.command("set").description("Configure provider credentials for running agents").option("--provider <name>", "Provider name (e.g. github-copilot, openai, anthropic)").option("--api-key <key>", "Provider API key").option("--model <model>", "Default model (e.g. github-copilot/claude-sonnet-4)").option("--runtime <runtime>", "Runtime to use (e.g. openclaw@latest, nullclaw@latest)", "openclaw@latest").action(async (opts) => {
|
|
240
|
+
const config = loadConfig();
|
|
241
|
+
config.runtime = config.runtime || {};
|
|
242
|
+
if (opts.provider) config.runtime.provider = opts.provider;
|
|
243
|
+
if (opts.apiKey) config.runtime.apiKey = opts.apiKey;
|
|
244
|
+
if (opts.model) config.runtime.model = opts.model;
|
|
245
|
+
if (opts.runtime) config.runtime.runtime = opts.runtime;
|
|
246
|
+
if (!opts.provider && !opts.apiKey && !opts.model) {
|
|
247
|
+
const ask = (prompt) => new Promise((resolve2) => {
|
|
248
|
+
process.stdout.write(prompt);
|
|
249
|
+
let data = "";
|
|
250
|
+
process.stdin.setEncoding("utf-8");
|
|
251
|
+
process.stdin.on("data", (chunk) => {
|
|
252
|
+
data += chunk;
|
|
253
|
+
if (data.includes("\n")) {
|
|
254
|
+
process.stdin.pause();
|
|
255
|
+
resolve2(data.trim());
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
process.stdin.resume();
|
|
259
|
+
});
|
|
260
|
+
config.runtime.provider = await ask(`Provider [${config.runtime.provider || "github-copilot"}]: `) || config.runtime.provider || "github-copilot";
|
|
261
|
+
config.runtime.apiKey = await ask("API Key: ") || config.runtime.apiKey;
|
|
262
|
+
config.runtime.model = await ask(`Model [${config.runtime.model || config.runtime.provider + "/claude-sonnet-4"}]: `) || config.runtime.model;
|
|
263
|
+
config.runtime.runtime = await ask(`Runtime [${config.runtime.runtime || "openclaw@latest"}]: `) || config.runtime.runtime || "openclaw@latest";
|
|
264
|
+
}
|
|
265
|
+
saveConfig(config);
|
|
266
|
+
console.log(`\u2705 Credentials saved`);
|
|
267
|
+
console.log(` Provider: ${config.runtime.provider}`);
|
|
268
|
+
console.log(` Model: ${config.runtime.model || config.runtime.provider + "/claude-sonnet-4"}`);
|
|
269
|
+
console.log(` Runtime: ${config.runtime.runtime || "openclaw@latest"}`);
|
|
270
|
+
console.log(` Config: ${CONFIG_FILE}`);
|
|
271
|
+
});
|
|
272
|
+
credentials.command("show").description("Show current runtime credentials").action(() => {
|
|
273
|
+
const config = loadConfig();
|
|
274
|
+
if (!config.runtime?.provider) {
|
|
275
|
+
console.log("No credentials configured. Run: clawdock credentials set");
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
console.log(`Provider: ${config.runtime.provider}`);
|
|
279
|
+
console.log(`API Key: ${config.runtime.apiKey ? config.runtime.apiKey.slice(0, 8) + "..." : "(not set)"}`);
|
|
280
|
+
console.log(`Model: ${config.runtime.model || "(default)"}`);
|
|
281
|
+
console.log(`Runtime: ${config.runtime.runtime || "openclaw@latest"}`);
|
|
282
|
+
});
|
|
283
|
+
credentials.command("clear").description("Remove stored runtime credentials").action(() => {
|
|
284
|
+
const config = loadConfig();
|
|
285
|
+
delete config.runtime;
|
|
286
|
+
saveConfig(config);
|
|
287
|
+
console.log("\u2705 Credentials cleared");
|
|
288
|
+
});
|
|
289
|
+
var AGENTS_DIR = path.join(CONFIG_DIR, "agents");
|
|
290
|
+
program.command("run <bundle>").description("Pull and run an agent locally").option("--runtime <runtime>", "Runtime override (e.g. openclaw@latest)").option("--model <model>", "Model override").option("--provider <name>", "Provider override").option("--api-key <key>", "API key override").option("--no-pull", "Skip pull, use cached workspace").action(async (bundle, opts) => {
|
|
239
291
|
const { execSync, spawn } = await import("child_process");
|
|
240
292
|
const match = bundle.match(/^([^/]+)\/([^@]+)(?:@(.+))?$/);
|
|
241
293
|
if (!match) {
|
|
@@ -243,10 +295,72 @@ program.command("run <bundle>").description("Pull and run an agent with NullClaw
|
|
|
243
295
|
process.exit(1);
|
|
244
296
|
}
|
|
245
297
|
const [, owner, slug, version] = match;
|
|
246
|
-
const
|
|
298
|
+
const agentName = `${owner}-${slug}`;
|
|
299
|
+
const config = loadConfig();
|
|
300
|
+
const rt = config.runtime || {};
|
|
301
|
+
const provider = opts.provider || rt.provider;
|
|
302
|
+
const apiKey = opts.apiKey || rt.apiKey || process.env.CLAWDOCK_API_KEY;
|
|
303
|
+
const model = opts.model || rt.model;
|
|
304
|
+
const runtimeSpec = opts.runtime || rt.runtime || "openclaw@latest";
|
|
305
|
+
if (!provider || !apiKey) {
|
|
306
|
+
console.log("\u2139\uFE0F No runtime credentials configured \u2014 launching without provider override.");
|
|
307
|
+
console.log(" To set defaults: clawdock credentials set");
|
|
308
|
+
console.log(" Or pass --provider and --api-key");
|
|
309
|
+
console.log();
|
|
310
|
+
}
|
|
311
|
+
const [runtimeName, runtimeVersion] = runtimeSpec.split("@");
|
|
312
|
+
console.log(`\u{1F50D} Checking runtime: ${runtimeName}...`);
|
|
313
|
+
let runtimeBin = null;
|
|
314
|
+
if (runtimeName === "openclaw") {
|
|
315
|
+
try {
|
|
316
|
+
const which = execSync("which openclaw 2>/dev/null", { encoding: "utf-8" }).trim();
|
|
317
|
+
if (which) {
|
|
318
|
+
runtimeBin = which;
|
|
319
|
+
const ver = execSync("openclaw --version 2>/dev/null", { encoding: "utf-8" }).trim();
|
|
320
|
+
console.log(` Found openclaw ${ver}`);
|
|
321
|
+
}
|
|
322
|
+
} catch {
|
|
323
|
+
}
|
|
324
|
+
if (!runtimeBin) {
|
|
325
|
+
console.log(" OpenClaw not found. Installing via npm...");
|
|
326
|
+
try {
|
|
327
|
+
execSync("npm install -g openclaw", { stdio: "inherit" });
|
|
328
|
+
runtimeBin = execSync("which openclaw", { encoding: "utf-8" }).trim();
|
|
329
|
+
console.log(" \u2705 OpenClaw installed");
|
|
330
|
+
} catch {
|
|
331
|
+
console.error("\u274C Failed to install OpenClaw. Install manually:");
|
|
332
|
+
console.error(" npm install -g openclaw");
|
|
333
|
+
process.exit(1);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
} else if (runtimeName === "nullclaw") {
|
|
337
|
+
const candidates = [
|
|
338
|
+
"nullclaw",
|
|
339
|
+
path.join(os.homedir(), ".nullclaw", "bin", "nullclaw"),
|
|
340
|
+
"/usr/local/bin/nullclaw"
|
|
341
|
+
];
|
|
342
|
+
for (const c of candidates) {
|
|
343
|
+
try {
|
|
344
|
+
execSync(`which ${c} 2>/dev/null || test -x ${c}`, { stdio: "pipe" });
|
|
345
|
+
runtimeBin = c;
|
|
346
|
+
break;
|
|
347
|
+
} catch {
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
if (!runtimeBin) {
|
|
351
|
+
console.error(`\u274C ${runtimeName} not found in PATH.`);
|
|
352
|
+
console.error(" Install from: https://github.com/pigeonflow/brain-arch-v2");
|
|
353
|
+
process.exit(1);
|
|
354
|
+
}
|
|
355
|
+
} else {
|
|
356
|
+
console.error(`\u274C Unknown runtime: ${runtimeName}`);
|
|
357
|
+
console.error(" Supported: openclaw, nullclaw");
|
|
358
|
+
process.exit(1);
|
|
359
|
+
}
|
|
360
|
+
const workspaceDir = path.join(AGENTS_DIR, owner, slug, "workspace");
|
|
247
361
|
if (opts.pull !== false) {
|
|
248
|
-
console.log(`\u{1F4E5} Pulling ${bundle}...`);
|
|
249
362
|
const ver = version || "latest";
|
|
363
|
+
console.log(`\u{1F4E5} Pulling ${owner}/${slug}@${ver}...`);
|
|
250
364
|
try {
|
|
251
365
|
const { url, version: resolvedVersion } = await apiRequest(
|
|
252
366
|
"GET",
|
|
@@ -269,79 +383,92 @@ program.command("run <bundle>").description("Pull and run an agent with NullClaw
|
|
|
269
383
|
}
|
|
270
384
|
if (!fs.existsSync(workspaceDir)) {
|
|
271
385
|
console.error(`\u274C Workspace not found: ${workspaceDir}`);
|
|
272
|
-
console.error(" Run without --no-pull
|
|
386
|
+
console.error(" Run without --no-pull to download first.");
|
|
273
387
|
process.exit(1);
|
|
274
388
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
389
|
+
const resolvedModel = model || (provider ? `${provider}/claude-sonnet-4` : null);
|
|
390
|
+
console.log(`
|
|
391
|
+
\u{1F980} Starting ${owner}/${slug}...`);
|
|
392
|
+
console.log(` Runtime: ${runtimeSpec}`);
|
|
393
|
+
console.log(` Workspace: ${workspaceDir}`);
|
|
394
|
+
if (resolvedModel) console.log(` Model: ${resolvedModel}`);
|
|
395
|
+
console.log();
|
|
396
|
+
if (runtimeName === "openclaw") {
|
|
397
|
+
try {
|
|
398
|
+
const list = execSync("openclaw agents list --json 2>/dev/null", { encoding: "utf-8" });
|
|
399
|
+
const agents = JSON.parse(list);
|
|
400
|
+
if (!agents.find((a) => a.name === agentName)) {
|
|
401
|
+
throw new Error("not found");
|
|
402
|
+
}
|
|
403
|
+
} catch {
|
|
404
|
+
console.log(` Registering agent "${agentName}"...`);
|
|
283
405
|
try {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
406
|
+
const modelFlag = resolvedModel ? ` --model ${resolvedModel}` : "";
|
|
407
|
+
execSync(
|
|
408
|
+
`openclaw agents add ${agentName} --workspace ${workspaceDir}${modelFlag} --non-interactive`,
|
|
409
|
+
{ stdio: "inherit" }
|
|
410
|
+
);
|
|
411
|
+
} catch (err) {
|
|
412
|
+
console.error(`\u274C Failed to register agent: ${err.message}`);
|
|
413
|
+
process.exit(1);
|
|
288
414
|
}
|
|
289
415
|
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
models: {
|
|
305
|
-
providers: {
|
|
306
|
-
[opts.provider]: providerApiKey ? { api_key: providerApiKey } : {}
|
|
416
|
+
if (provider && apiKey) {
|
|
417
|
+
const agentDir = path.join(os.homedir(), ".openclaw", "agents", agentName, "agent");
|
|
418
|
+
fs.mkdirSync(agentDir, { recursive: true });
|
|
419
|
+
const authProfilesPath = path.join(agentDir, "auth-profiles.json");
|
|
420
|
+
const authProfiles = {};
|
|
421
|
+
authProfiles[provider] = { type: "api-key", apiKey };
|
|
422
|
+
fs.writeFileSync(authProfilesPath, JSON.stringify(authProfiles, null, 2));
|
|
423
|
+
}
|
|
424
|
+
const child = spawn(
|
|
425
|
+
runtimeBin,
|
|
426
|
+
["agent", "--agent", agentName, "--prompt", "Hello! I just pulled you from ClawDock. Introduce yourself."],
|
|
427
|
+
{
|
|
428
|
+
stdio: "inherit",
|
|
429
|
+
env: { ...process.env }
|
|
307
430
|
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
431
|
+
);
|
|
432
|
+
child.on("error", (err) => {
|
|
433
|
+
console.error(`\u274C Failed to start: ${err.message}`);
|
|
434
|
+
process.exit(1);
|
|
435
|
+
});
|
|
436
|
+
child.on("exit", (code) => process.exit(code || 0));
|
|
437
|
+
process.on("SIGINT", () => child.kill("SIGINT"));
|
|
438
|
+
process.on("SIGTERM", () => child.kill("SIGTERM"));
|
|
439
|
+
} else if (runtimeName === "nullclaw") {
|
|
440
|
+
const configPath = path.join(workspaceDir, ".nullclaw.json");
|
|
441
|
+
const nullclawConfig = {
|
|
442
|
+
default_temperature: 0.7,
|
|
443
|
+
models: {
|
|
444
|
+
providers: {
|
|
445
|
+
[provider]: { api_key: apiKey }
|
|
446
|
+
}
|
|
447
|
+
},
|
|
448
|
+
agents: {
|
|
449
|
+
defaults: {
|
|
450
|
+
model: { primary: resolvedModel }
|
|
451
|
+
}
|
|
452
|
+
},
|
|
453
|
+
channels: { cli: true },
|
|
454
|
+
memory: {
|
|
455
|
+
profile: "markdown_only",
|
|
456
|
+
backend: "markdown",
|
|
457
|
+
auto_save: true
|
|
312
458
|
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
\u{1F980} Starting ${manifest.name || slug} with NullClaw...`);
|
|
328
|
-
console.log(` Workspace: ${workspaceDir}`);
|
|
329
|
-
console.log(` Model: ${model}`);
|
|
330
|
-
console.log(` Channel: ${opts.channel}`);
|
|
331
|
-
console.log();
|
|
332
|
-
const child = spawn(nullclawBin, ["--config", configPath, "--workspace", workspaceDir], {
|
|
333
|
-
stdio: "inherit",
|
|
334
|
-
cwd: workspaceDir,
|
|
335
|
-
env: { ...process.env }
|
|
336
|
-
});
|
|
337
|
-
child.on("error", (err) => {
|
|
338
|
-
console.error(`\u274C Failed to start NullClaw: ${err.message}`);
|
|
339
|
-
process.exit(1);
|
|
340
|
-
});
|
|
341
|
-
child.on("exit", (code) => {
|
|
342
|
-
process.exit(code || 0);
|
|
343
|
-
});
|
|
344
|
-
process.on("SIGINT", () => child.kill("SIGINT"));
|
|
345
|
-
process.on("SIGTERM", () => child.kill("SIGTERM"));
|
|
459
|
+
};
|
|
460
|
+
fs.writeFileSync(configPath, JSON.stringify(nullclawConfig, null, 2));
|
|
461
|
+
const child = spawn(runtimeBin, ["--config", configPath, "--workspace", workspaceDir], {
|
|
462
|
+
stdio: "inherit",
|
|
463
|
+
cwd: workspaceDir
|
|
464
|
+
});
|
|
465
|
+
child.on("error", (err) => {
|
|
466
|
+
console.error(`\u274C Failed to start NullClaw: ${err.message}`);
|
|
467
|
+
process.exit(1);
|
|
468
|
+
});
|
|
469
|
+
child.on("exit", (code) => process.exit(code || 0));
|
|
470
|
+
process.on("SIGINT", () => child.kill("SIGINT"));
|
|
471
|
+
process.on("SIGTERM", () => child.kill("SIGTERM"));
|
|
472
|
+
}
|
|
346
473
|
});
|
|
347
474
|
program.parse();
|