@lark-apaas/openclaw-dev-cli 0.1.3 → 0.1.5
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 +86 -0
- package/dist/index.js +56 -37
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# @lark-apaas/openclaw-dev-cli
|
|
2
|
+
|
|
3
|
+
OpenClaw 应用开发 CLI,管理应用的创建、关联和部署。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
无需安装,通过 npx 直接使用:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx --yes @lark-apaas/openclaw-dev-cli <command> [options]
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## 命令
|
|
14
|
+
|
|
15
|
+
### init — 初始化应用
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
# 从模板创建新应用
|
|
19
|
+
npx --yes @lark-apaas/openclaw-dev-cli init --template <html|nextjs-static|nextjs> --dir <path>
|
|
20
|
+
|
|
21
|
+
# clone 后初始化
|
|
22
|
+
npx --yes @lark-apaas/openclaw-dev-cli init --dir <path>
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
| 选项 | 说明 | 默认值 |
|
|
26
|
+
|------|------|--------|
|
|
27
|
+
| `--dir <path>` | 项目目录 | `.` |
|
|
28
|
+
| `--template <template>` | 模板类型(无代码时必须) | - |
|
|
29
|
+
| `--title <title>` | 应用名称 | 目录名 |
|
|
30
|
+
| `--description <desc>` | 应用描述 | `""` |
|
|
31
|
+
| `--template-version <version>` | 模板包版本 | `latest` |
|
|
32
|
+
| `--skip-install` | 跳过依赖安装 | `false` |
|
|
33
|
+
|
|
34
|
+
### link — 关联已有项目
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
npx --yes @lark-apaas/openclaw-dev-cli link --app-id <id> --template <type>
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
| 选项 | 说明 | 默认值 |
|
|
41
|
+
|------|------|--------|
|
|
42
|
+
| `--dir <path>` | 项目目录 | `.` |
|
|
43
|
+
| `--app-id <id>` | 要关联的应用 ID | 不传则自动注册 |
|
|
44
|
+
| `--template <template>` | 技术栈类型 | 从 package.json mclaw 字段读取 |
|
|
45
|
+
| `--title <title>` | 应用名称 | 目录名 |
|
|
46
|
+
| `--description <desc>` | 应用描述 | `""` |
|
|
47
|
+
|
|
48
|
+
### deploy — 部署应用
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npx --yes @lark-apaas/openclaw-dev-cli deploy
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
| 选项 | 说明 | 默认值 |
|
|
55
|
+
|------|------|--------|
|
|
56
|
+
| `--dir <path>` | 项目目录 | `.` |
|
|
57
|
+
| `--skip-build` | 跳过构建 | `false` |
|
|
58
|
+
|
|
59
|
+
## 全局选项
|
|
60
|
+
|
|
61
|
+
| 选项 | 说明 |
|
|
62
|
+
|------|------|
|
|
63
|
+
| `--canary <env>` | 设置 canary 泳道 |
|
|
64
|
+
| `-V, --version` | 输出版本号 |
|
|
65
|
+
|
|
66
|
+
## 支持的技术栈
|
|
67
|
+
|
|
68
|
+
| 模板 | 说明 |
|
|
69
|
+
|------|------|
|
|
70
|
+
| `html` | 纯 HTML + Tailwind CDN |
|
|
71
|
+
| `nextjs-static` | Next.js Pages Router,静态导出 |
|
|
72
|
+
| `nextjs` | Next.js App Router 全栈 |
|
|
73
|
+
|
|
74
|
+
## 环境配置
|
|
75
|
+
|
|
76
|
+
在项目目录下创建 `.env` 文件:
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
FORCE_AUTHN_INNERAPI_DOMAIN=<API域名>
|
|
80
|
+
FORCE_AUTHN_ACCESS_KEY=<AK>
|
|
81
|
+
FORCE_AUTHN_ACCESS_SECRET=<SK>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## License
|
|
85
|
+
|
|
86
|
+
MIT
|
package/dist/index.js
CHANGED
|
@@ -7288,7 +7288,7 @@ var initCommand = {
|
|
|
7288
7288
|
const hasPackageJson = import_node_fs9.default.existsSync(import_node_path12.default.join(projectDir, "package.json"));
|
|
7289
7289
|
const existingMeta = readSparkMeta(projectDir);
|
|
7290
7290
|
const title = options.title ?? import_node_path12.default.basename(projectDir);
|
|
7291
|
-
let
|
|
7291
|
+
let templateVersion = existingMeta.templateVersion;
|
|
7292
7292
|
if (!hasPackageJson) {
|
|
7293
7293
|
if (!options.template) {
|
|
7294
7294
|
throw new Error(
|
|
@@ -7306,26 +7306,26 @@ Available: ${TEMPLATE_TYPES.join(", ")}`
|
|
|
7306
7306
|
projectName: import_node_path12.default.basename(projectDir),
|
|
7307
7307
|
localTemplate: options.localTemplate
|
|
7308
7308
|
});
|
|
7309
|
-
|
|
7309
|
+
templateVersion = version;
|
|
7310
7310
|
}
|
|
7311
|
-
let
|
|
7312
|
-
if (!
|
|
7311
|
+
let template = options.template ?? existingMeta.template;
|
|
7312
|
+
if (!template) {
|
|
7313
7313
|
const pkgPath = import_node_path12.default.join(projectDir, "package.json");
|
|
7314
7314
|
if (import_node_fs9.default.existsSync(pkgPath)) {
|
|
7315
7315
|
try {
|
|
7316
7316
|
const pkg = JSON.parse(import_node_fs9.default.readFileSync(pkgPath, "utf-8"));
|
|
7317
|
-
|
|
7318
|
-
|
|
7317
|
+
template = pkg.mclaw?.stack;
|
|
7318
|
+
templateVersion = templateVersion ?? pkg.mclaw?.stackVersion;
|
|
7319
7319
|
} catch {
|
|
7320
7320
|
}
|
|
7321
7321
|
}
|
|
7322
7322
|
}
|
|
7323
|
-
if (!
|
|
7323
|
+
if (!template) {
|
|
7324
7324
|
throw new Error(
|
|
7325
|
-
"Cannot determine
|
|
7325
|
+
"Cannot determine template type. Please provide --template or ensure package.json has mclaw.stack field."
|
|
7326
7326
|
);
|
|
7327
7327
|
}
|
|
7328
|
-
let appId = options.appId ?? existingMeta.
|
|
7328
|
+
let appId = options.appId ?? existingMeta.appId;
|
|
7329
7329
|
if (!appId) {
|
|
7330
7330
|
const result = await createSubApp({
|
|
7331
7331
|
name: title,
|
|
@@ -7337,9 +7337,9 @@ Available: ${TEMPLATE_TYPES.join(", ")}`
|
|
|
7337
7337
|
console.log(`Using existing app_id: ${appId}`);
|
|
7338
7338
|
}
|
|
7339
7339
|
writeSparkMeta(projectDir, {
|
|
7340
|
-
|
|
7341
|
-
|
|
7342
|
-
|
|
7340
|
+
appId,
|
|
7341
|
+
template,
|
|
7342
|
+
templateVersion: templateVersion ?? "0.1.0"
|
|
7343
7343
|
});
|
|
7344
7344
|
if (!options.skipInstall) {
|
|
7345
7345
|
console.log("\nInstalling dependencies...");
|
|
@@ -7352,7 +7352,7 @@ Available: ${TEMPLATE_TYPES.join(", ")}`
|
|
|
7352
7352
|
\u2705 Initialized successfully!`);
|
|
7353
7353
|
console.log(` Directory: ${projectDir}`);
|
|
7354
7354
|
console.log(` App ID: ${appId}`);
|
|
7355
|
-
console.log(`
|
|
7355
|
+
console.log(` Template: ${template}`);
|
|
7356
7356
|
});
|
|
7357
7357
|
}
|
|
7358
7358
|
};
|
|
@@ -7399,9 +7399,9 @@ Available: ${TEMPLATE_TYPES.join(", ")}`
|
|
|
7399
7399
|
console.log(`Using app_id: ${appId}`);
|
|
7400
7400
|
}
|
|
7401
7401
|
writeSparkMeta(projectDir, {
|
|
7402
|
-
|
|
7403
|
-
stack,
|
|
7404
|
-
|
|
7402
|
+
appId,
|
|
7403
|
+
template: stack,
|
|
7404
|
+
templateVersion: stackVersion
|
|
7405
7405
|
});
|
|
7406
7406
|
if (import_node_fs10.default.existsSync(pkgPath)) {
|
|
7407
7407
|
const pkg = JSON.parse(import_node_fs10.default.readFileSync(pkgPath, "utf-8"));
|
|
@@ -7483,8 +7483,14 @@ function configureTosutil(tosutilPath, confPath, credential) {
|
|
|
7483
7483
|
], { stdio: "pipe" });
|
|
7484
7484
|
}
|
|
7485
7485
|
function uploadToTos(tosutilPath, confPath, sourceDir, destUrl) {
|
|
7486
|
-
console.
|
|
7487
|
-
|
|
7486
|
+
console.log(`${LOG_PREFIX} Uploading ${sourceDir} \u2192 ${destUrl}`);
|
|
7487
|
+
const files = import_node_fs12.default.readdirSync(sourceDir);
|
|
7488
|
+
if (files.length === 0) {
|
|
7489
|
+
console.warn(`${LOG_PREFIX} Warning: source directory is empty, skipping upload.`);
|
|
7490
|
+
return;
|
|
7491
|
+
}
|
|
7492
|
+
console.log(`${LOG_PREFIX} Source files: ${files.length}`);
|
|
7493
|
+
const output = (0, import_node_child_process3.execFileSync)(tosutilPath, [
|
|
7488
7494
|
"cp",
|
|
7489
7495
|
"-conf",
|
|
7490
7496
|
confPath,
|
|
@@ -7499,7 +7505,19 @@ function uploadToTos(tosutilPath, confPath, sourceDir, destUrl) {
|
|
|
7499
7505
|
"-ps",
|
|
7500
7506
|
"10485760",
|
|
7501
7507
|
"-f"
|
|
7502
|
-
], { stdio: "
|
|
7508
|
+
], { encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] });
|
|
7509
|
+
console.log(output);
|
|
7510
|
+
const succeedMatch = output.match(/Succeed count is:\s*(\d+)/);
|
|
7511
|
+
const failedMatch = output.match(/Failed count is:\s*(\d+)/);
|
|
7512
|
+
const succeedCount = succeedMatch ? parseInt(succeedMatch[1], 10) : 0;
|
|
7513
|
+
const failedCount = failedMatch ? parseInt(failedMatch[1], 10) : 0;
|
|
7514
|
+
if (failedCount > 0) {
|
|
7515
|
+
throw new Error(`${LOG_PREFIX} Upload failed: ${failedCount} files failed, ${succeedCount} succeeded.`);
|
|
7516
|
+
}
|
|
7517
|
+
if (succeedCount === 0) {
|
|
7518
|
+
throw new Error(`${LOG_PREFIX} Upload failed: no files were uploaded. Check tosutil credentials and bucket permissions.`);
|
|
7519
|
+
}
|
|
7520
|
+
console.log(`${LOG_PREFIX} Uploaded ${succeedCount} files successfully.`);
|
|
7503
7521
|
}
|
|
7504
7522
|
function uploadWithCredential(tosutilPath, sourceDir, destUrl, credential, label) {
|
|
7505
7523
|
const confPath = import_node_path15.default.join(import_node_os2.default.tmpdir(), `.tosutilconfig-mclaw-${label}-${process.pid}`);
|
|
@@ -7532,7 +7550,8 @@ function uploadOutput(options) {
|
|
|
7532
7550
|
}
|
|
7533
7551
|
if (validated.hasOutputStatic) {
|
|
7534
7552
|
const localPath = import_node_path15.default.join(distDir, OUTPUT_STATIC_DIR);
|
|
7535
|
-
const
|
|
7553
|
+
const prefix = preUploadResult.uploadPrefix.endsWith("/") ? preUploadResult.uploadPrefix : `${preUploadResult.uploadPrefix}/`;
|
|
7554
|
+
const destUrl = `${prefix}${OUTPUT_STATIC_DIR}/`;
|
|
7536
7555
|
console.error(`${LOG_PREFIX} Uploading output_static (static credential)...`);
|
|
7537
7556
|
uploadWithCredential(tosutilPath, localPath, destUrl, {
|
|
7538
7557
|
accessKeyID: preUploadResult.uploadCredential.AccessKeyID,
|
|
@@ -7555,30 +7574,30 @@ var deployCommand = {
|
|
|
7555
7574
|
throw new Error('.spark/meta.json not found. Run "mclaw-dev init" first.');
|
|
7556
7575
|
}
|
|
7557
7576
|
const meta = JSON.parse(import_node_fs13.default.readFileSync(metaPath, "utf-8"));
|
|
7558
|
-
if (!meta.
|
|
7577
|
+
if (!meta.appId || !meta.template) {
|
|
7559
7578
|
throw new Error('.spark/meta.json is incomplete. Run "mclaw-dev init" to fix.');
|
|
7560
7579
|
}
|
|
7561
|
-
const publishResult = await createPublish(meta.
|
|
7580
|
+
const publishResult = await createPublish(meta.appId);
|
|
7562
7581
|
console.log(`Version: ${publishResult.version}, PublishID: ${publishResult.publishID}`);
|
|
7563
7582
|
console.log("\nPreparing upload credentials...");
|
|
7564
|
-
const artifactCredential = await genArtifactUploadCredential(meta.
|
|
7565
|
-
const bucketId = await getDefaultBucketId(meta.
|
|
7566
|
-
const preUploadResult = await preUploadStatic(meta.
|
|
7583
|
+
const artifactCredential = await genArtifactUploadCredential(meta.appId, String(publishResult.version));
|
|
7584
|
+
const bucketId = await getDefaultBucketId(meta.appId);
|
|
7585
|
+
const preUploadResult = await preUploadStatic(meta.appId, bucketId);
|
|
7567
7586
|
console.log(`Static prefix: ${preUploadResult.downloadURLPrefix}`);
|
|
7568
7587
|
if (!options.skipBuild) {
|
|
7569
|
-
const cdnDomain = buildCdnDomain(meta.
|
|
7588
|
+
const cdnDomain = buildCdnDomain(meta.appId, publishResult.version);
|
|
7570
7589
|
const buildEnv = {
|
|
7571
7590
|
...process.env,
|
|
7572
|
-
MCLAW_APP_ID: meta.
|
|
7591
|
+
MCLAW_APP_ID: meta.appId,
|
|
7573
7592
|
MCLAW_VERSION: String(publishResult.version),
|
|
7574
|
-
MCLAW_STACK: meta.
|
|
7593
|
+
MCLAW_STACK: meta.template,
|
|
7575
7594
|
MCLAW_CDN_DOMAIN: cdnDomain,
|
|
7576
7595
|
MCLAW_STATIC_PREFIX: preUploadResult.downloadURLPrefix
|
|
7577
7596
|
};
|
|
7578
7597
|
console.log("\nBuilding...");
|
|
7579
|
-
console.log(` MCLAW_APP_ID=${meta.
|
|
7598
|
+
console.log(` MCLAW_APP_ID=${meta.appId}`);
|
|
7580
7599
|
console.log(` MCLAW_VERSION=${publishResult.version}`);
|
|
7581
|
-
console.log(` MCLAW_STACK=${meta.
|
|
7600
|
+
console.log(` MCLAW_STACK=${meta.template}`);
|
|
7582
7601
|
console.log(` MCLAW_CDN_DOMAIN=${cdnDomain}`);
|
|
7583
7602
|
console.log(` MCLAW_STATIC_PREFIX=${preUploadResult.downloadURLPrefix}`);
|
|
7584
7603
|
(0, import_node_child_process4.execSync)("npm run build", {
|
|
@@ -7591,7 +7610,7 @@ var deployCommand = {
|
|
|
7591
7610
|
console.log("Build output validated.");
|
|
7592
7611
|
uploadOutput({
|
|
7593
7612
|
projectDir,
|
|
7594
|
-
appId: meta.
|
|
7613
|
+
appId: meta.appId,
|
|
7595
7614
|
version: publishResult.version,
|
|
7596
7615
|
validated,
|
|
7597
7616
|
artifactCredential,
|
|
@@ -7599,7 +7618,7 @@ var deployCommand = {
|
|
|
7599
7618
|
});
|
|
7600
7619
|
if (validated.hasOutputStatic) {
|
|
7601
7620
|
console.log("\nNotifying upload complete...");
|
|
7602
|
-
const callbackResult = await callbackStatic(meta.
|
|
7621
|
+
const callbackResult = await callbackStatic(meta.appId, bucketId, preUploadResult.uploadID);
|
|
7603
7622
|
console.log(`Uploaded ${callbackResult.attachments.length} static files.`);
|
|
7604
7623
|
}
|
|
7605
7624
|
let routesConfig;
|
|
@@ -7608,18 +7627,18 @@ var deployCommand = {
|
|
|
7608
7627
|
routesConfig = import_node_fs13.default.readFileSync(routesPath, "utf-8");
|
|
7609
7628
|
console.log("Found routes.json, including in publish.");
|
|
7610
7629
|
}
|
|
7611
|
-
const publishUpdateResult = await updatePublish(meta.
|
|
7630
|
+
const publishUpdateResult = await updatePublish(meta.appId, {
|
|
7612
7631
|
publishID: publishResult.publishID,
|
|
7613
7632
|
routesConfig
|
|
7614
7633
|
});
|
|
7615
|
-
const appUrl = publishUpdateResult.onlineURL || buildAppUrl(meta.
|
|
7634
|
+
const appUrl = publishUpdateResult.onlineURL || buildAppUrl(meta.appId);
|
|
7616
7635
|
writeSparkMeta(projectDir, {
|
|
7617
7636
|
...meta,
|
|
7618
|
-
|
|
7637
|
+
appUrl
|
|
7619
7638
|
});
|
|
7620
7639
|
console.log(`
|
|
7621
7640
|
\u2705 Deployed successfully!`);
|
|
7622
|
-
console.log(` App ID: ${meta.
|
|
7641
|
+
console.log(` App ID: ${meta.appId}`);
|
|
7623
7642
|
console.log(` Version: ${publishResult.version}`);
|
|
7624
7643
|
console.log(` URL: ${appUrl}`);
|
|
7625
7644
|
});
|
|
@@ -7653,7 +7672,7 @@ function loadEnvFile(filePath) {
|
|
|
7653
7672
|
}
|
|
7654
7673
|
}
|
|
7655
7674
|
loadEnvFile(import_node_path17.default.join(process.cwd(), ".env"));
|
|
7656
|
-
var VERSION = "0.1.
|
|
7675
|
+
var VERSION = "0.1.5";
|
|
7657
7676
|
var cli = new OpenClawCLI(VERSION);
|
|
7658
7677
|
cli.useAll(commands);
|
|
7659
7678
|
cli.run();
|