@lobehub/cli 0.0.2 → 0.0.3
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/dist/index.js +154 -36
- package/man/man1/lh.1 +1 -1
- package/package.json +4 -1
package/dist/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import os from "node:os";
|
|
|
9
9
|
import crypto, { randomUUID } from "node:crypto";
|
|
10
10
|
import { createInterface } from "node:readline";
|
|
11
11
|
import { mkdir, readFile, readdir, stat, writeFile } from "node:fs/promises";
|
|
12
|
+
import ignore from "ignore";
|
|
12
13
|
//#region \0rolldown/runtime.js
|
|
13
14
|
var __create$2 = Object.create;
|
|
14
15
|
var __defProp$2 = Object.defineProperty;
|
|
@@ -5121,7 +5122,7 @@ async function getAuthAndServer() {
|
|
|
5121
5122
|
}
|
|
5122
5123
|
const result = await getValidToken();
|
|
5123
5124
|
if (!result) {
|
|
5124
|
-
log$1.error(`No authentication found. Run 'lh login' first, or set ${CLI_API_KEY_ENV}.`);
|
|
5125
|
+
log$1.error(`No authentication found. Run 'lh login' (or 'npx -y @lobehub/cli login') first, or set ${CLI_API_KEY_ENV}.`);
|
|
5125
5126
|
process.exit(1);
|
|
5126
5127
|
}
|
|
5127
5128
|
const serverUrl = resolveServerUrl();
|
|
@@ -28138,52 +28139,127 @@ function registerMessageCommand(program) {
|
|
|
28138
28139
|
}
|
|
28139
28140
|
//#endregion
|
|
28140
28141
|
//#region src/commands/migrate/openclaw.ts
|
|
28141
|
-
const
|
|
28142
|
-
|
|
28143
|
-
|
|
28144
|
-
".fleet",
|
|
28145
|
-
".cursor",
|
|
28146
|
-
".zed",
|
|
28142
|
+
const DEFAULT_AGENT_NAME = "OpenClaw";
|
|
28143
|
+
const IDENTITY_FILES = ["IDENTITY.md", "SOUL.md"];
|
|
28144
|
+
const DEFAULT_IGNORE_RULES = [
|
|
28147
28145
|
".git",
|
|
28148
28146
|
".svn",
|
|
28149
28147
|
".hg",
|
|
28148
|
+
".openclaw",
|
|
28150
28149
|
".DS_Store",
|
|
28151
28150
|
"Thumbs.db",
|
|
28152
28151
|
"desktop.ini",
|
|
28153
|
-
".
|
|
28152
|
+
".idea",
|
|
28153
|
+
".vscode",
|
|
28154
|
+
".fleet",
|
|
28155
|
+
".cursor",
|
|
28156
|
+
".zed",
|
|
28157
|
+
"*.swp",
|
|
28158
|
+
"*.swo",
|
|
28159
|
+
"*~",
|
|
28154
28160
|
"node_modules",
|
|
28155
28161
|
".pnp",
|
|
28162
|
+
".yarn",
|
|
28156
28163
|
"bower_components",
|
|
28157
28164
|
"vendor",
|
|
28165
|
+
"jspm_packages",
|
|
28158
28166
|
".venv",
|
|
28159
28167
|
"venv",
|
|
28168
|
+
"env",
|
|
28160
28169
|
"__pycache__",
|
|
28170
|
+
"*.pyc",
|
|
28171
|
+
"*.pyo",
|
|
28161
28172
|
".mypy_cache",
|
|
28162
28173
|
".ruff_cache",
|
|
28163
28174
|
".pytest_cache",
|
|
28164
28175
|
".tox",
|
|
28165
28176
|
".eggs",
|
|
28166
28177
|
"*.egg-info",
|
|
28178
|
+
".bundle",
|
|
28179
|
+
"target",
|
|
28180
|
+
"go.sum",
|
|
28181
|
+
".gradle",
|
|
28182
|
+
".m2",
|
|
28183
|
+
"bin",
|
|
28184
|
+
"obj",
|
|
28185
|
+
"packages",
|
|
28167
28186
|
".cache",
|
|
28168
28187
|
".parcel-cache",
|
|
28169
28188
|
".next",
|
|
28170
28189
|
".nuxt",
|
|
28171
28190
|
".turbo",
|
|
28191
|
+
".output",
|
|
28172
28192
|
"dist",
|
|
28173
28193
|
"build",
|
|
28174
28194
|
"out",
|
|
28175
|
-
".
|
|
28195
|
+
".sass-cache",
|
|
28176
28196
|
".env",
|
|
28177
|
-
".env
|
|
28197
|
+
".env.*",
|
|
28178
28198
|
"coverage",
|
|
28179
28199
|
".nyc_output",
|
|
28180
28200
|
".terraform",
|
|
28181
|
-
".sass-cache",
|
|
28182
28201
|
"tmp",
|
|
28183
|
-
".tmp"
|
|
28184
|
-
|
|
28185
|
-
|
|
28186
|
-
|
|
28202
|
+
".tmp",
|
|
28203
|
+
"*.log",
|
|
28204
|
+
"logs",
|
|
28205
|
+
"*.sqlite",
|
|
28206
|
+
"*.sqlite3",
|
|
28207
|
+
"*.db",
|
|
28208
|
+
"*.db-shm",
|
|
28209
|
+
"*.db-wal",
|
|
28210
|
+
"*.ldb",
|
|
28211
|
+
"*.mdb",
|
|
28212
|
+
"*.accdb",
|
|
28213
|
+
"*.zip",
|
|
28214
|
+
"*.tar",
|
|
28215
|
+
"*.tar.gz",
|
|
28216
|
+
"*.tgz",
|
|
28217
|
+
"*.gz",
|
|
28218
|
+
"*.bz2",
|
|
28219
|
+
"*.xz",
|
|
28220
|
+
"*.rar",
|
|
28221
|
+
"*.7z",
|
|
28222
|
+
"*.jar",
|
|
28223
|
+
"*.war",
|
|
28224
|
+
"*.dll",
|
|
28225
|
+
"*.so",
|
|
28226
|
+
"*.dylib",
|
|
28227
|
+
"*.exe",
|
|
28228
|
+
"*.bin",
|
|
28229
|
+
"*.o",
|
|
28230
|
+
"*.a",
|
|
28231
|
+
"*.lib",
|
|
28232
|
+
"*.class",
|
|
28233
|
+
"*.png",
|
|
28234
|
+
"*.jpg",
|
|
28235
|
+
"*.jpeg",
|
|
28236
|
+
"*.gif",
|
|
28237
|
+
"*.bmp",
|
|
28238
|
+
"*.ico",
|
|
28239
|
+
"*.webp",
|
|
28240
|
+
"*.svg",
|
|
28241
|
+
"*.mp3",
|
|
28242
|
+
"*.mp4",
|
|
28243
|
+
"*.wav",
|
|
28244
|
+
"*.avi",
|
|
28245
|
+
"*.mov",
|
|
28246
|
+
"*.mkv",
|
|
28247
|
+
"*.flac",
|
|
28248
|
+
"*.ogg",
|
|
28249
|
+
"*.pdf",
|
|
28250
|
+
"*.woff",
|
|
28251
|
+
"*.woff2",
|
|
28252
|
+
"*.ttf",
|
|
28253
|
+
"*.otf",
|
|
28254
|
+
"*.eot",
|
|
28255
|
+
"package-lock.json",
|
|
28256
|
+
"yarn.lock",
|
|
28257
|
+
"pnpm-lock.yaml",
|
|
28258
|
+
"Gemfile.lock",
|
|
28259
|
+
"Cargo.lock",
|
|
28260
|
+
"poetry.lock",
|
|
28261
|
+
"composer.lock"
|
|
28262
|
+
];
|
|
28187
28263
|
/**
|
|
28188
28264
|
* Try to extract the agent name, description, and avatar emoji from
|
|
28189
28265
|
* IDENTITY.md or SOUL.md. Falls back to "OpenClaw" if neither file
|
|
@@ -28199,8 +28275,10 @@ function readAgentProfile(workspacePath) {
|
|
|
28199
28275
|
const descMatch = content.match(/\*{0,2}(?:Creature|Vibe|Description):?\*{0,2}\s*(.+)/i);
|
|
28200
28276
|
const description = descMatch ? descMatch[1].trim() : void 0;
|
|
28201
28277
|
const emojiMatch = content.match(/\*{0,2}Emoji:?\*{0,2}\s*(.+)/i);
|
|
28278
|
+
const rawAvatar = emojiMatch ? emojiMatch[1].trim() : void 0;
|
|
28279
|
+
const isPlaceholder = rawAvatar && /^[_*((].*[))_*]$|^(?:tbd|todo|n\/?a|none|待定|未定)$/i.test(rawAvatar);
|
|
28202
28280
|
return {
|
|
28203
|
-
avatar:
|
|
28281
|
+
avatar: rawAvatar && !isPlaceholder ? rawAvatar : void 0,
|
|
28204
28282
|
description,
|
|
28205
28283
|
title
|
|
28206
28284
|
};
|
|
@@ -28208,20 +28286,51 @@ function readAgentProfile(workspacePath) {
|
|
|
28208
28286
|
return { title: DEFAULT_AGENT_NAME };
|
|
28209
28287
|
}
|
|
28210
28288
|
/**
|
|
28211
|
-
*
|
|
28289
|
+
* Build an ignore filter for the workspace. Uses .gitignore if present,
|
|
28290
|
+
* otherwise falls back to a comprehensive default rule set.
|
|
28291
|
+
*/
|
|
28292
|
+
function buildIgnoreFilter(workspacePath) {
|
|
28293
|
+
const ig = ignore();
|
|
28294
|
+
const gitignorePath = path.join(workspacePath, ".gitignore");
|
|
28295
|
+
if (fs.existsSync(gitignorePath)) ig.add(fs.readFileSync(gitignorePath, "utf8"));
|
|
28296
|
+
ig.add(DEFAULT_IGNORE_RULES);
|
|
28297
|
+
return ig;
|
|
28298
|
+
}
|
|
28299
|
+
/**
|
|
28300
|
+
* Recursively collect all files under `dir`, filtered by ignore rules.
|
|
28212
28301
|
* Returns paths relative to `baseDir`.
|
|
28213
28302
|
*/
|
|
28214
|
-
function collectFiles(dir, baseDir) {
|
|
28303
|
+
function collectFiles(dir, baseDir, ig) {
|
|
28215
28304
|
const results = [];
|
|
28216
28305
|
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
28217
|
-
|
|
28306
|
+
const relativePath = path.relative(baseDir, path.join(dir, entry.name));
|
|
28307
|
+
const testPath = entry.isDirectory() ? `${relativePath}/` : relativePath;
|
|
28308
|
+
if (ig.ignores(testPath)) continue;
|
|
28218
28309
|
const fullPath = path.join(dir, entry.name);
|
|
28219
|
-
if (entry.isDirectory()) results.push(...collectFiles(fullPath, baseDir));
|
|
28220
|
-
else if (entry.isFile()) results.push(
|
|
28310
|
+
if (entry.isDirectory()) results.push(...collectFiles(fullPath, baseDir, ig));
|
|
28311
|
+
else if (entry.isFile()) results.push(relativePath);
|
|
28221
28312
|
}
|
|
28222
28313
|
return results;
|
|
28223
28314
|
}
|
|
28224
28315
|
/**
|
|
28316
|
+
* Quick check: read the first 8KB and look for null bytes.
|
|
28317
|
+
* If found, the file is likely binary and should be skipped.
|
|
28318
|
+
*/
|
|
28319
|
+
function isBinaryFile(filePath) {
|
|
28320
|
+
const fd = fs.openSync(filePath, "r");
|
|
28321
|
+
try {
|
|
28322
|
+
const buf = Buffer.alloc(8192);
|
|
28323
|
+
const bytesRead = fs.readSync(fd, buf, 0, 8192, 0);
|
|
28324
|
+
for (let i = 0; i < bytesRead; i++) if (buf[i] === 0) return true;
|
|
28325
|
+
return false;
|
|
28326
|
+
} finally {
|
|
28327
|
+
fs.closeSync(fd);
|
|
28328
|
+
}
|
|
28329
|
+
}
|
|
28330
|
+
function formatAgentLabel(profile) {
|
|
28331
|
+
return profile.avatar ? `${profile.avatar} ${profile.title}` : profile.title;
|
|
28332
|
+
}
|
|
28333
|
+
/**
|
|
28225
28334
|
* Resolve the target agent ID.
|
|
28226
28335
|
* Priority: --agent-id > --slug > create new agent from workspace profile.
|
|
28227
28336
|
*/
|
|
@@ -28235,7 +28344,8 @@ async function resolveAgentId(client, opts, profile) {
|
|
|
28235
28344
|
}
|
|
28236
28345
|
return agent.id;
|
|
28237
28346
|
}
|
|
28238
|
-
|
|
28347
|
+
const label = formatAgentLabel(profile);
|
|
28348
|
+
log$1.info(`Creating new agent ${import_picocolors.default.bold(label)}...`);
|
|
28239
28349
|
const id = (await client.agent.createAgent.mutate({ config: {
|
|
28240
28350
|
avatar: profile.avatar,
|
|
28241
28351
|
description: profile.description,
|
|
@@ -28245,12 +28355,11 @@ async function resolveAgentId(client, opts, profile) {
|
|
|
28245
28355
|
log$1.error("Failed to create agent — no agentId returned.");
|
|
28246
28356
|
process.exit(1);
|
|
28247
28357
|
}
|
|
28248
|
-
const label = profile.avatar ? `${profile.avatar} ${profile.title}` : profile.title;
|
|
28249
28358
|
console.log(`${import_picocolors.default.green("✓")} Agent created: ${import_picocolors.default.bold(label)}`);
|
|
28250
28359
|
return id;
|
|
28251
28360
|
}
|
|
28252
28361
|
function registerOpenClawMigration(migrate) {
|
|
28253
|
-
migrate.command("openclaw").description("Import OpenClaw workspace files as agent documents
|
|
28362
|
+
migrate.command("openclaw").description("Import OpenClaw workspace files as agent documents").option("--source <path>", "Path to OpenClaw workspace", path.join(process.env.HOME || "~", ".openclaw", "workspace")).option("--agent-id <id>", "Import into an existing agent by ID").option("--slug <slug>", "Import into an existing agent by slug (e.g. \"inbox\")").option("--dry-run", "Preview files without importing").option("--yes", "Skip confirmation prompt").action(async (options) => {
|
|
28254
28363
|
if (!options.dryRun) await getTrpcClient();
|
|
28255
28364
|
const workspacePath = path.resolve(options.source);
|
|
28256
28365
|
if (!fs.existsSync(workspacePath)) {
|
|
@@ -28262,7 +28371,8 @@ function registerOpenClawMigration(migrate) {
|
|
|
28262
28371
|
process.exit(1);
|
|
28263
28372
|
}
|
|
28264
28373
|
const profile = readAgentProfile(workspacePath);
|
|
28265
|
-
const
|
|
28374
|
+
const label = formatAgentLabel(profile);
|
|
28375
|
+
const files = collectFiles(workspacePath, workspacePath, buildIgnoreFilter(workspacePath));
|
|
28266
28376
|
if (files.length === 0) {
|
|
28267
28377
|
log$1.info("No files found in workspace.");
|
|
28268
28378
|
return;
|
|
@@ -28275,8 +28385,7 @@ function registerOpenClawMigration(migrate) {
|
|
|
28275
28385
|
return;
|
|
28276
28386
|
}
|
|
28277
28387
|
if (!options.yes) {
|
|
28278
|
-
const
|
|
28279
|
-
const target = options.agentId ? `agent ${import_picocolors.default.bold(options.agentId)}` : options.slug ? `agent slug "${import_picocolors.default.bold(options.slug)}"` : `a new ${import_picocolors.default.bold(agentLabel)} agent`;
|
|
28388
|
+
const target = options.agentId ? `agent ${import_picocolors.default.bold(options.agentId)}` : options.slug ? `agent slug "${import_picocolors.default.bold(options.slug)}"` : `a new ${import_picocolors.default.bold(label)} agent`;
|
|
28280
28389
|
if (!await confirm(`Import ${files.length} file(s) as agent documents into ${target}?`)) {
|
|
28281
28390
|
console.log("Cancelled.");
|
|
28282
28391
|
return;
|
|
@@ -28284,31 +28393,40 @@ function registerOpenClawMigration(migrate) {
|
|
|
28284
28393
|
}
|
|
28285
28394
|
const client = await getTrpcClient();
|
|
28286
28395
|
const agentId = await resolveAgentId(client, options, profile);
|
|
28287
|
-
|
|
28288
|
-
console.log(`\nImporting to ${import_picocolors.default.bold(displayName)}...\n`);
|
|
28396
|
+
console.log(`\nImporting to ${import_picocolors.default.bold(label)}...\n`);
|
|
28289
28397
|
let success = 0;
|
|
28290
28398
|
let failed = 0;
|
|
28399
|
+
let skipped = 0;
|
|
28291
28400
|
for (const relativePath of files) {
|
|
28292
28401
|
const fullPath = path.join(workspacePath, relativePath);
|
|
28402
|
+
if (isBinaryFile(fullPath)) {
|
|
28403
|
+
console.log(` ${import_picocolors.default.dim("○")} ${relativePath} ${import_picocolors.default.dim("(binary, skipped)")}`);
|
|
28404
|
+
skipped++;
|
|
28405
|
+
continue;
|
|
28406
|
+
}
|
|
28293
28407
|
const content = fs.readFileSync(fullPath, "utf8");
|
|
28294
|
-
const
|
|
28408
|
+
const createdAt = fs.statSync(fullPath).mtime;
|
|
28295
28409
|
try {
|
|
28296
28410
|
await client.agentDocument.upsertDocument.mutate({
|
|
28297
28411
|
agentId,
|
|
28298
28412
|
content,
|
|
28299
|
-
|
|
28413
|
+
createdAt,
|
|
28414
|
+
filename: relativePath
|
|
28300
28415
|
});
|
|
28301
|
-
console.log(` ${import_picocolors.default.green("✓")} ${
|
|
28416
|
+
console.log(` ${import_picocolors.default.green("✓")} ${relativePath}`);
|
|
28302
28417
|
success++;
|
|
28303
28418
|
} catch (err) {
|
|
28304
|
-
console.log(` ${import_picocolors.default.red("✗")} ${
|
|
28419
|
+
console.log(` ${import_picocolors.default.red("✗")} ${relativePath} — ${err.message || err}`);
|
|
28305
28420
|
failed++;
|
|
28306
28421
|
}
|
|
28307
28422
|
}
|
|
28308
|
-
console.log();
|
|
28309
|
-
console.log(`${import_picocolors.default.green("✓")} Done: ${import_picocolors.default.bold(String(success))} imported` + (failed > 0 ? `, ${import_picocolors.default.red(String(failed))} failed` : ""));
|
|
28310
28423
|
const agentUrl = `${resolveServerUrl()}/agent/${agentId}`;
|
|
28311
|
-
|
|
28424
|
+
const skippedInfo = skipped > 0 ? `, ${skipped} skipped` : "";
|
|
28425
|
+
console.log();
|
|
28426
|
+
if (failed === 0) console.log(`${import_picocolors.default.green("✓")} Migration complete! ${import_picocolors.default.bold(String(success))} file(s) imported to ${import_picocolors.default.bold(label)}.${skippedInfo}`);
|
|
28427
|
+
else console.log(`${import_picocolors.default.yellow("⚠")} Migration finished with issues: ${import_picocolors.default.bold(String(success))} imported, ${import_picocolors.default.red(String(failed))} failed${skippedInfo}.`);
|
|
28428
|
+
console.log(`\n ${import_picocolors.default.dim("→")} ${import_picocolors.default.underline(agentUrl)}`);
|
|
28429
|
+
console.log();
|
|
28312
28430
|
});
|
|
28313
28431
|
}
|
|
28314
28432
|
//#endregion
|
package/man/man1/lh.1
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
.\" Code generated by `npm run man:generate`; DO NOT EDIT.
|
|
2
2
|
.\" Manual command details come from the Commander command tree.
|
|
3
|
-
.TH LH 1 "" "@lobehub/cli 0.0.
|
|
3
|
+
.TH LH 1 "" "@lobehub/cli 0.0.3" "User Commands"
|
|
4
4
|
.SH NAME
|
|
5
5
|
lh \- LobeHub CLI \- manage and connect to LobeHub services
|
|
6
6
|
.SH SYNOPSIS
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"lh": "./dist/index.js",
|
|
@@ -27,6 +27,9 @@
|
|
|
27
27
|
"test:coverage": "bunx vitest run --config vitest.config.mts --coverage",
|
|
28
28
|
"type-check": "tsc --noEmit"
|
|
29
29
|
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"ignore": "^7.0.5"
|
|
32
|
+
},
|
|
30
33
|
"devDependencies": {
|
|
31
34
|
"@lobechat/device-gateway-client": "workspace:*",
|
|
32
35
|
"@lobechat/local-file-shell": "workspace:*",
|