clawkittool 0.1.0 → 0.1.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 CHANGED
@@ -8,6 +8,30 @@
8
8
  clawkittool get product-kit
9
9
  clawkittool get hotnews-kit --dir ./my-clawkit
10
10
  clawkittool get product-kit --manifest https://example.com/clawkit/manifest.json
11
+ clawkittool get product-kit --config ~/.openclaw
12
+ clawkittool get product-kit --target-name sandbox
13
+ ```
14
+
15
+ 默认行为:
16
+
17
+ - 下载 `core.zip`
18
+ - 下载指定 kit
19
+ - 自动执行 `npm install`
20
+ - 自动探测本机 OpenClaw 目录并执行 `deploy`
21
+
22
+ 自动探测顺序:
23
+
24
+ - `--config <path>`
25
+ - `OPENCLAW_HOME`
26
+ - `OPENCLAW_CONFIG_DIR`
27
+ - `OPENCLAW_CONFIG_PATH`
28
+ - `~/.openclaw/openclaw.json`
29
+ - `~/.config/openclaw/openclaw.json`
30
+
31
+ 如果只想下载但不自动部署,可以加:
32
+
33
+ ```bash
34
+ clawkittool get product-kit --skip-deploy
11
35
  ```
12
36
 
13
37
  ## manifest 格式
@@ -5,7 +5,7 @@ const { installKitFromManifest } = require('../lib/get');
5
5
 
6
6
  function printUsage() {
7
7
  console.log(`Usage:
8
- clawkittool get <kit-name> [--dir <path>] [--manifest <url-or-path>] [--force] [--skip-install]
8
+ clawkittool get <kit-name> [--dir <path>] [--manifest <url-or-path>] [--config <path>] [--target-name <name>] [--force] [--skip-install] [--skip-deploy]
9
9
  `);
10
10
  }
11
11
 
@@ -29,6 +29,9 @@ async function main(argv) {
29
29
  let manifestSource = process.env.CLAWKIT_MANIFEST_URL || null;
30
30
  let force = false;
31
31
  let skipInstall = false;
32
+ let skipDeploy = false;
33
+ let explicitConfigPath = null;
34
+ let targetName = null;
32
35
 
33
36
  for (let index = 0; index < rest.length; index += 1) {
34
37
  const arg = rest[index];
@@ -45,6 +48,18 @@ async function main(argv) {
45
48
  continue;
46
49
  }
47
50
 
51
+ if (arg === '--config') {
52
+ explicitConfigPath = rest[index + 1] || null;
53
+ index += 1;
54
+ continue;
55
+ }
56
+
57
+ if (arg === '--target-name') {
58
+ targetName = rest[index + 1] || null;
59
+ index += 1;
60
+ continue;
61
+ }
62
+
48
63
  if (arg === '--force') {
49
64
  force = true;
50
65
  continue;
@@ -55,6 +70,11 @@ async function main(argv) {
55
70
  continue;
56
71
  }
57
72
 
73
+ if (arg === '--skip-deploy') {
74
+ skipDeploy = true;
75
+ continue;
76
+ }
77
+
58
78
  throw new Error(`Unknown argument: ${arg}`);
59
79
  }
60
80
 
@@ -68,9 +88,19 @@ async function main(argv) {
68
88
  manifestSource,
69
89
  force,
70
90
  skipInstall,
91
+ explicitConfigPath,
92
+ skipDeploy,
93
+ targetName,
71
94
  });
72
95
 
73
96
  console.log(`Installed ${result.kitName} into ${result.targetDir}`);
97
+ if (result.deployed) {
98
+ console.log(`Deployed ${result.kitName} to ${result.detectedConfigPath}`);
99
+ } else if (result.detectedConfigPath) {
100
+ console.log(`Detected OpenClaw config at ${result.detectedConfigPath}, but deployment was skipped.`);
101
+ } else {
102
+ console.log('No OpenClaw config detected. Pass --config to deploy automatically.');
103
+ }
74
104
  }
75
105
 
76
106
  main(process.argv.slice(2)).catch((error) => {
package/lib/get.js CHANGED
@@ -7,6 +7,70 @@ function ensureDir(dirPath) {
7
7
  fs.mkdirSync(dirPath, { recursive: true });
8
8
  }
9
9
 
10
+ function resolveOpenClawConfigFile(candidatePath) {
11
+ if (!candidatePath) {
12
+ return null;
13
+ }
14
+
15
+ const resolvedPath = path.resolve(candidatePath);
16
+ if (!fs.existsSync(resolvedPath)) {
17
+ return null;
18
+ }
19
+
20
+ const stats = fs.statSync(resolvedPath);
21
+ if (stats.isDirectory()) {
22
+ const configPath = path.join(resolvedPath, 'openclaw.json');
23
+ return fs.existsSync(configPath) ? configPath : null;
24
+ }
25
+
26
+ return path.basename(resolvedPath) === 'openclaw.json' ? resolvedPath : null;
27
+ }
28
+
29
+ function detectOpenClawConfigPath({
30
+ explicitConfigPath = null,
31
+ env = process.env,
32
+ homeDir = os.homedir(),
33
+ platform = process.platform,
34
+ } = {}) {
35
+ const explicitMatch = resolveOpenClawConfigFile(explicitConfigPath);
36
+ if (explicitMatch) {
37
+ return explicitMatch;
38
+ }
39
+
40
+ const envCandidates = [
41
+ env.OPENCLAW_HOME,
42
+ env.OPENCLAW_CONFIG_DIR,
43
+ env.OPENCLAW_CONFIG_PATH,
44
+ ];
45
+
46
+ for (const candidate of envCandidates) {
47
+ const envMatch = resolveOpenClawConfigFile(candidate);
48
+ if (envMatch) {
49
+ return envMatch;
50
+ }
51
+ }
52
+
53
+ const defaultCandidates =
54
+ platform === 'win32'
55
+ ? [
56
+ path.join(homeDir, '.openclaw'),
57
+ env.APPDATA ? path.join(env.APPDATA, 'openclaw') : null,
58
+ ]
59
+ : [
60
+ path.join(homeDir, '.openclaw'),
61
+ path.join(homeDir, '.config', 'openclaw'),
62
+ ];
63
+
64
+ for (const candidate of defaultCandidates) {
65
+ const defaultMatch = resolveOpenClawConfigFile(candidate);
66
+ if (defaultMatch) {
67
+ return defaultMatch;
68
+ }
69
+ }
70
+
71
+ return null;
72
+ }
73
+
10
74
  function makeTempDir() {
11
75
  return fs.mkdtempSync(path.join(os.tmpdir(), 'clawkittool-'));
12
76
  }
@@ -184,12 +248,40 @@ function runInstall(targetDir) {
184
248
  }
185
249
  }
186
250
 
251
+ function runDeploy({ targetDir, kitName, configPath, targetName = null, force = false }) {
252
+ const nodeCommand = process.execPath;
253
+ const deployArgs = [path.join(targetDir, 'cli', 'index.js'), 'deploy', kitName, '--config', configPath, '--apply'];
254
+
255
+ if (targetName) {
256
+ deployArgs.push('--target-name', targetName);
257
+ }
258
+
259
+ if (force) {
260
+ deployArgs.push('--force');
261
+ }
262
+
263
+ const result = spawnSync(nodeCommand, deployArgs, {
264
+ cwd: targetDir,
265
+ stdio: 'inherit',
266
+ });
267
+
268
+ if (result.status !== 0) {
269
+ throw new Error(`clawkit deploy failed for ${kitName}`);
270
+ }
271
+ }
272
+
187
273
  async function installKitFromManifest({
188
274
  kitName,
189
275
  targetDir,
190
276
  manifestSource,
191
277
  force = false,
192
278
  skipInstall = false,
279
+ explicitConfigPath = null,
280
+ skipDeploy = false,
281
+ targetName = null,
282
+ env = process.env,
283
+ homeDir = os.homedir(),
284
+ deployRunner = runDeploy,
193
285
  }) {
194
286
  const manifest = await loadManifest(manifestSource);
195
287
  const kitEntry = manifest.kits[kitName];
@@ -205,6 +297,11 @@ async function installKitFromManifest({
205
297
  const coreExtractDir = path.join(tempDir, 'core');
206
298
  const kitZipPath = path.join(tempDir, `${kitName}.zip`);
207
299
  const kitExtractDir = path.join(tempDir, kitName);
300
+ const detectedConfigPath = detectOpenClawConfigPath({
301
+ explicitConfigPath,
302
+ env,
303
+ homeDir,
304
+ });
208
305
 
209
306
  try {
210
307
  await downloadFile(manifest.core.url, coreZipPath);
@@ -219,9 +316,23 @@ async function installKitFromManifest({
219
316
  runInstall(targetDir);
220
317
  }
221
318
 
319
+ let deployed = false;
320
+ if (!skipDeploy && detectedConfigPath) {
321
+ deployRunner({
322
+ targetDir,
323
+ kitName,
324
+ configPath: detectedConfigPath,
325
+ targetName,
326
+ force,
327
+ });
328
+ deployed = true;
329
+ }
330
+
222
331
  return {
223
332
  kitName,
224
333
  targetDir,
334
+ detectedConfigPath,
335
+ deployed,
225
336
  };
226
337
  } finally {
227
338
  fs.rmSync(tempDir, { recursive: true, force: true });
@@ -229,6 +340,7 @@ async function installKitFromManifest({
229
340
  }
230
341
 
231
342
  module.exports = {
343
+ detectOpenClawConfigPath,
232
344
  installKitFromManifest,
233
345
  loadManifest,
234
346
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawkittool",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "On-demand installer for OpenClaw ClawKit workflow kits",
5
5
  "bin": {
6
6
  "clawkittool": "./bin/clawkittool.js"
@@ -12,6 +12,6 @@
12
12
  ],
13
13
  "license": "MIT",
14
14
  "engines": {
15
- "node": ">=18.0.0"
15
+ "node": ">=22.0.0"
16
16
  }
17
17
  }