nextclaw 0.33.2 → 0.35.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/dist/cli/app/index.js +184 -33
- package/dist/cli/app/index.js.map +1 -1
- package/package.json +13 -12
- package/resources/USAGE.md +29 -0
- package/ui-dist/assets/{api-a_GaOFc7.js → api-Dket1cmq.js} +1 -1
- package/ui-dist/assets/{appearance-settings-page-KEYKkxHu.js → appearance-settings-page-CfwDf9ag.js} +1 -1
- package/ui-dist/assets/{channels-list-page-eXLXPgKT.js → channels-list-page-Dyn83ZlS.js} +2 -2
- package/ui-dist/assets/chat-page-CL0IMvgF.js +1 -0
- package/ui-dist/assets/{config-split-page-ps1Aod3g.js → config-split-page-D4D4HFhq.js} +1 -1
- package/ui-dist/assets/{confirm-dialog-DJSUNG33.js → confirm-dialog-Cv6-9Nnj.js} +1 -1
- package/ui-dist/assets/{desktop-update-config-C20U71k1.js → desktop-update-config-Bckgulvm.js} +1 -1
- package/ui-dist/assets/{dist-BkTYNzm_.js → dist-Bh_tj3FN.js} +1 -1
- package/ui-dist/assets/{dist-DkR7_Dpl.js → dist-BrRgjiq1.js} +1 -1
- package/ui-dist/assets/{doc-browser-Q67TOGVS.js → doc-browser-BlWjhmnM.js} +1 -1
- package/ui-dist/assets/doc-browser-Da9hDsoQ.js +1 -0
- package/ui-dist/assets/{doc-browser-context-BQim8SqD.js → doc-browser-context-NGYa66Xg.js} +1 -1
- package/ui-dist/assets/{form-actions-B2-bpFie.js → form-actions-CeKgh4SQ.js} +1 -1
- package/ui-dist/assets/{index-BP0Hd2jI.js → index-Bz5yNMXA.js} +44 -44
- package/ui-dist/assets/loader-circle-DLp2jNIf.js +1 -0
- package/ui-dist/assets/mcp-marketplace-page-CIWbjXM8.js +1 -0
- package/ui-dist/assets/{mcp-marketplace-page-w8panjZG.js → mcp-marketplace-page-DfNmMqKs.js} +1 -1
- package/ui-dist/assets/{model-config-page-CJCnaKOh.js → model-config-page-DHzyDV5v.js} +1 -1
- package/ui-dist/assets/{navigation-link-mpHFXwRr.js → navigation-link-CzGgQGi_.js} +1 -1
- package/ui-dist/assets/plus-Dfj3tJ_m.js +1 -0
- package/ui-dist/assets/{provider-scoped-model-input-Dqu-ZoWG.js → provider-scoped-model-input-CjrHwzFb.js} +1 -1
- package/ui-dist/assets/providers-config-page-ZPvJWHFN.js +1 -0
- package/ui-dist/assets/{react-BlXwvOLo.js → react-BXRf96P-.js} +1 -1
- package/ui-dist/assets/{refresh-cw-JFuyDj_P.js → refresh-cw-ChKuqgPR.js} +1 -1
- package/ui-dist/assets/remote-C2enAZbs.js +1 -0
- package/ui-dist/assets/rotate-cw-BGkZpcc7.js +1 -0
- package/ui-dist/assets/runtime-config-page-CGpPQD8K.js +1 -0
- package/ui-dist/assets/{save-BL8P8CLX.js → save-BWGNAKV5.js} +1 -1
- package/ui-dist/assets/{search-bZL75Pgc.js → search-DFcT_9wJ.js} +1 -1
- package/ui-dist/assets/{search-config-page-DhSFjYj4.js → search-config-page-DBBzVAQZ.js} +1 -1
- package/ui-dist/assets/{secrets-config-page-BLGcyb1D.js → secrets-config-page-bnJ8sIB7.js} +2 -2
- package/ui-dist/assets/security-config-CfbXSpgX.js +1 -0
- package/ui-dist/assets/{select-rUZ8nIZu.js → select-BnNrv8si.js} +1 -1
- package/ui-dist/assets/{settings-2-BI4SCkxQ.js → settings-2-CFHrgKTX.js} +1 -1
- package/ui-dist/assets/skeleton-tfWhGuJT.js +1 -0
- package/ui-dist/assets/{tag-chip-BdI_yIOA.js → tag-chip-L5w4xfS7.js} +1 -1
- package/ui-dist/assets/x-BCSE3LCQ.js +1 -0
- package/ui-dist/index.html +18 -18
- package/ui-dist/assets/chat-page-jfImLdsq.js +0 -1
- package/ui-dist/assets/doc-browser-DahzJEWj.js +0 -1
- package/ui-dist/assets/loader-circle-DyXZU92l.js +0 -1
- package/ui-dist/assets/mcp-marketplace-page-B0dBE5CV.js +0 -1
- package/ui-dist/assets/plus-Dhb4KuMH.js +0 -1
- package/ui-dist/assets/providers-config-page-C6fRN2rJ.js +0 -1
- package/ui-dist/assets/remote-Xyv2c_W9.js +0 -1
- package/ui-dist/assets/rotate-cw-DjbbiIW_.js +0 -1
- package/ui-dist/assets/runtime-config-page-CtypMgLd.js +0 -1
- package/ui-dist/assets/security-config-DmJw9QZA.js +0 -1
- package/ui-dist/assets/skeleton-CVmEPG43.js +0 -1
- package/ui-dist/assets/x-BcEayhV6.js +0 -1
package/dist/cli/app/index.js
CHANGED
|
@@ -4,14 +4,15 @@ import { createRequire } from "node:module";
|
|
|
4
4
|
import { APP_NAME, APP_TAGLINE, getConfigPath, getDataDir, getRunPath, loadConfig, resolveConfigSecrets } from "@nextclaw/core";
|
|
5
5
|
import { Command, InvalidArgumentError } from "commander";
|
|
6
6
|
import { constants, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
7
|
-
import { randomBytes } from "node:crypto";
|
|
7
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
8
8
|
import { execFile } from "node:child_process";
|
|
9
9
|
import path, { join, resolve } from "node:path";
|
|
10
10
|
import { tmpdir } from "node:os";
|
|
11
11
|
import "@nextclaw/server";
|
|
12
12
|
import { NextclawDistributionService, NextclawServiceRuntime, readLearningLoopRuntimeConfig } from "@nextclaw/service";
|
|
13
|
-
import {
|
|
13
|
+
import { AppHomeService, AppInstanceStorageService, AppPublishService, AppPublishValidationService } from "@nextclaw/app-runtime";
|
|
14
14
|
import { McpServiceAppRuntimeService, buildServiceActionId, getServiceAppManifestPath, mergeServiceAppRuntimeActions, readServiceAppManifest } from "@nextclaw/kernel";
|
|
15
|
+
import { access, mkdtemp, readFile, rm, stat } from "node:fs/promises";
|
|
15
16
|
import { promisify } from "node:util";
|
|
16
17
|
var __commonJSMin = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
17
18
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
@@ -2019,7 +2020,7 @@ var require_websocket = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
2019
2020
|
const http$1 = __require("http");
|
|
2020
2021
|
const net = __require("net");
|
|
2021
2022
|
const tls = __require("tls");
|
|
2022
|
-
const { randomBytes: randomBytes$1, createHash: createHash$
|
|
2023
|
+
const { randomBytes: randomBytes$1, createHash: createHash$2 } = __require("crypto");
|
|
2023
2024
|
const { Duplex: Duplex$2, Readable } = __require("stream");
|
|
2024
2025
|
const { URL: URL$1 } = __require("url");
|
|
2025
2026
|
const PerMessageDeflate = require_permessage_deflate();
|
|
@@ -2671,7 +2672,7 @@ var require_websocket = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
2671
2672
|
abortHandshake(websocket, socket, "Invalid Upgrade header");
|
|
2672
2673
|
return;
|
|
2673
2674
|
}
|
|
2674
|
-
const digest = createHash$
|
|
2675
|
+
const digest = createHash$2("sha1").update(key + GUID).digest("base64");
|
|
2675
2676
|
if (res.headers["sec-websocket-accept"] !== digest) {
|
|
2676
2677
|
abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
|
|
2677
2678
|
return;
|
|
@@ -3143,7 +3144,7 @@ var require_websocket_server = /* @__PURE__ */ __commonJSMin(((exports, module)
|
|
|
3143
3144
|
const EventEmitter = __require("events");
|
|
3144
3145
|
const http = __require("http");
|
|
3145
3146
|
const { Duplex } = __require("stream");
|
|
3146
|
-
const { createHash } = __require("crypto");
|
|
3147
|
+
const { createHash: createHash$1 } = __require("crypto");
|
|
3147
3148
|
const extension = require_extension();
|
|
3148
3149
|
const PerMessageDeflate = require_permessage_deflate();
|
|
3149
3150
|
const subprotocol = require_subprotocol();
|
|
@@ -3402,7 +3403,7 @@ var require_websocket_server = /* @__PURE__ */ __commonJSMin(((exports, module)
|
|
|
3402
3403
|
"HTTP/1.1 101 Switching Protocols",
|
|
3403
3404
|
"Upgrade: websocket",
|
|
3404
3405
|
"Connection: Upgrade",
|
|
3405
|
-
`Sec-WebSocket-Accept: ${createHash("sha1").update(key + GUID).digest("base64")}`
|
|
3406
|
+
`Sec-WebSocket-Accept: ${createHash$1("sha1").update(key + GUID).digest("base64")}`
|
|
3406
3407
|
];
|
|
3407
3408
|
const ws = new this.options.WebSocket(null, void 0, this.options);
|
|
3408
3409
|
if (protocols.size) {
|
|
@@ -3632,6 +3633,7 @@ const registerHostServiceControls = ({ program, nextclaw }) => {
|
|
|
3632
3633
|
//#endregion
|
|
3633
3634
|
//#region src/cli/app/services/service-app-dev.service.ts
|
|
3634
3635
|
var ServiceAppDevService = class {
|
|
3636
|
+
instanceStorageService = new AppInstanceStorageService();
|
|
3635
3637
|
constructor(params = {}) {
|
|
3636
3638
|
this.params = params;
|
|
3637
3639
|
}
|
|
@@ -3642,14 +3644,14 @@ var ServiceAppDevService = class {
|
|
|
3642
3644
|
if (!loaded) return this.buildDevReport(appPath, void 0, [], issues);
|
|
3643
3645
|
if (this.hasErrors(issues)) return this.buildDevReport(appPath, this.toServiceAppRecord(appPath, loaded.manifest, this.idleRuntimeStatus), [], issues);
|
|
3644
3646
|
const runtime = this.createRuntimeService();
|
|
3645
|
-
const
|
|
3647
|
+
const storage = await this.createDevStorage(appPath, loaded.manifest.id);
|
|
3646
3648
|
try {
|
|
3647
|
-
const startRecord = this.toServiceAppRecord(appPath, loaded.manifest, runtime,
|
|
3649
|
+
const startRecord = this.toServiceAppRecord(appPath, loaded.manifest, runtime, storage);
|
|
3648
3650
|
const runtimeActions = await runtime.listActions({
|
|
3649
3651
|
app: startRecord,
|
|
3650
3652
|
manifest: loaded.manifest
|
|
3651
3653
|
});
|
|
3652
|
-
const record = this.toServiceAppRecord(appPath, loaded.manifest, runtime,
|
|
3654
|
+
const record = this.toServiceAppRecord(appPath, loaded.manifest, runtime, storage);
|
|
3653
3655
|
const actions = mergeServiceAppRuntimeActions({
|
|
3654
3656
|
record,
|
|
3655
3657
|
manifest: loaded.manifest,
|
|
@@ -3658,14 +3660,7 @@ var ServiceAppDevService = class {
|
|
|
3658
3660
|
this.collectRuntimeIssues(record, actions, issues);
|
|
3659
3661
|
return this.buildDevReport(appPath, record, actions, issues);
|
|
3660
3662
|
} finally {
|
|
3661
|
-
|
|
3662
|
-
await runtime.dispose();
|
|
3663
|
-
} finally {
|
|
3664
|
-
await rm(dataDirectory, {
|
|
3665
|
-
recursive: true,
|
|
3666
|
-
force: true
|
|
3667
|
-
});
|
|
3668
|
-
}
|
|
3663
|
+
await runtime.dispose();
|
|
3669
3664
|
}
|
|
3670
3665
|
};
|
|
3671
3666
|
call = async (target, actionName, input) => {
|
|
@@ -3685,19 +3680,19 @@ var ServiceAppDevService = class {
|
|
|
3685
3680
|
return this.buildCallReport(appPath, record, void 0, void 0, issues);
|
|
3686
3681
|
}
|
|
3687
3682
|
const runtime = this.createRuntimeService();
|
|
3688
|
-
const
|
|
3683
|
+
const storage = await this.createDevStorage(appPath, loaded.manifest.id);
|
|
3689
3684
|
try {
|
|
3690
|
-
const record = this.toServiceAppRecord(appPath, loaded.manifest, runtime,
|
|
3685
|
+
const record = this.toServiceAppRecord(appPath, loaded.manifest, runtime, storage);
|
|
3691
3686
|
const result = await runtime.invokeAction({
|
|
3692
3687
|
app: record,
|
|
3693
3688
|
manifest: loaded.manifest,
|
|
3694
3689
|
actionName: action,
|
|
3695
3690
|
input
|
|
3696
3691
|
});
|
|
3697
|
-
const nextRecord = this.toServiceAppRecord(appPath, loaded.manifest, runtime,
|
|
3692
|
+
const nextRecord = this.toServiceAppRecord(appPath, loaded.manifest, runtime, storage);
|
|
3698
3693
|
return this.buildCallReport(appPath, nextRecord, buildServiceActionId(loaded.manifest.id, action), result, issues);
|
|
3699
3694
|
} catch (error) {
|
|
3700
|
-
const record = this.toServiceAppRecord(appPath, loaded.manifest, runtime,
|
|
3695
|
+
const record = this.toServiceAppRecord(appPath, loaded.manifest, runtime, storage);
|
|
3701
3696
|
issues.push({
|
|
3702
3697
|
severity: "error",
|
|
3703
3698
|
code: "service.runtime.callFailed",
|
|
@@ -3705,14 +3700,7 @@ var ServiceAppDevService = class {
|
|
|
3705
3700
|
});
|
|
3706
3701
|
return this.buildCallReport(appPath, record, buildServiceActionId(loaded.manifest.id, action), void 0, issues);
|
|
3707
3702
|
} finally {
|
|
3708
|
-
|
|
3709
|
-
await runtime.dispose();
|
|
3710
|
-
} finally {
|
|
3711
|
-
await rm(dataDirectory, {
|
|
3712
|
-
recursive: true,
|
|
3713
|
-
force: true
|
|
3714
|
-
});
|
|
3715
|
-
}
|
|
3703
|
+
await runtime.dispose();
|
|
3716
3704
|
}
|
|
3717
3705
|
};
|
|
3718
3706
|
loadServiceApp = async (appPath, issues) => {
|
|
@@ -3744,8 +3732,16 @@ var ServiceAppDevService = class {
|
|
|
3744
3732
|
return resolveConfigSecrets(loadConfig(configPath), { configPath });
|
|
3745
3733
|
};
|
|
3746
3734
|
idleRuntimeStatus = { getStatus: () => ({ status: "idle" }) };
|
|
3747
|
-
|
|
3748
|
-
|
|
3735
|
+
createDevStorage = async (appPath, appId) => {
|
|
3736
|
+
const sourceId = createHash("sha256").update(appPath).digest("hex").slice(0, 16);
|
|
3737
|
+
const instanceDirectory = path.join(new AppHomeService().getAppHomeDirectory(), "dev-instances", appId, sourceId, "default");
|
|
3738
|
+
return (await this.instanceStorageService.materialize({
|
|
3739
|
+
appId,
|
|
3740
|
+
instanceId: "default",
|
|
3741
|
+
instanceDirectory
|
|
3742
|
+
})).storage;
|
|
3743
|
+
};
|
|
3744
|
+
toServiceAppRecord = (dirPath, manifest, runtime, storage) => {
|
|
3749
3745
|
const runtimeStatus = runtime.getStatus(manifest.id);
|
|
3750
3746
|
const record = {
|
|
3751
3747
|
id: manifest.id,
|
|
@@ -3758,7 +3754,10 @@ var ServiceAppDevService = class {
|
|
|
3758
3754
|
enabled: manifest.enabled,
|
|
3759
3755
|
protocol: manifest.protocol,
|
|
3760
3756
|
status: manifest.enabled ? runtimeStatus.status : "stopped",
|
|
3761
|
-
dataDirectory
|
|
3757
|
+
dataDirectory: storage?.dataDirectory,
|
|
3758
|
+
instanceId: storage?.instanceId,
|
|
3759
|
+
storage,
|
|
3760
|
+
isolation: "full-user"
|
|
3762
3761
|
};
|
|
3763
3762
|
if (manifest.description) record.description = manifest.description;
|
|
3764
3763
|
if (runtimeStatus.lastError) record.lastError = runtimeStatus.lastError;
|
|
@@ -4607,13 +4606,165 @@ var AppRestartCommandController = class {
|
|
|
4607
4606
|
};
|
|
4608
4607
|
};
|
|
4609
4608
|
//#endregion
|
|
4609
|
+
//#region src/cli/app/services/app-publishing.service.ts
|
|
4610
|
+
var AppPublishingService = class {
|
|
4611
|
+
constructor(validationService = new AppPublishValidationService(), publishService = new AppPublishService()) {
|
|
4612
|
+
this.validationService = validationService;
|
|
4613
|
+
this.publishService = publishService;
|
|
4614
|
+
}
|
|
4615
|
+
validate = async (params) => {
|
|
4616
|
+
const result = await this.validationService.validate({
|
|
4617
|
+
appDirectory: params.appDirectory,
|
|
4618
|
+
metadataPath: params.metadataPath,
|
|
4619
|
+
mode: "bundle"
|
|
4620
|
+
});
|
|
4621
|
+
if (result.profile !== "components") throw new Error("nextclaw app publish 只支持由 Panel App 或 Service App 组成的 schema v2 Mini App。");
|
|
4622
|
+
if (result.distributionMode !== "bundle") throw new Error("NextClaw Mini App 只支持 bundle 分发。");
|
|
4623
|
+
return result;
|
|
4624
|
+
};
|
|
4625
|
+
publish = async (params) => {
|
|
4626
|
+
const validation = await this.validate(params);
|
|
4627
|
+
if (validation.warnings.length > 0 && !params.allowWarnings) {
|
|
4628
|
+
const warningList = validation.warnings.map((warning) => `[${warning.code}] ${warning.message}`).join("; ");
|
|
4629
|
+
throw new Error(`发布校验包含警告:${warningList}。确认后可使用 --allow-warnings 继续。`);
|
|
4630
|
+
}
|
|
4631
|
+
const tempDirectory = await mkdtemp(path.join(tmpdir(), "nextclaw-app-publish-"));
|
|
4632
|
+
try {
|
|
4633
|
+
const result = await this.publishService.publish({
|
|
4634
|
+
appDirectory: params.appDirectory,
|
|
4635
|
+
metadataPath: params.metadataPath,
|
|
4636
|
+
bundleOutputPath: path.join(tempDirectory, "artifact.napp"),
|
|
4637
|
+
mode: "bundle"
|
|
4638
|
+
});
|
|
4639
|
+
const { item } = result;
|
|
4640
|
+
return {
|
|
4641
|
+
validation,
|
|
4642
|
+
publish: {
|
|
4643
|
+
created: result.created,
|
|
4644
|
+
item: {
|
|
4645
|
+
slug: item.slug,
|
|
4646
|
+
appId: item.appId,
|
|
4647
|
+
ownerScope: item.ownerScope,
|
|
4648
|
+
appName: item.appName,
|
|
4649
|
+
publishStatus: item.publishStatus,
|
|
4650
|
+
name: item.name,
|
|
4651
|
+
latestVersion: item.latestVersion,
|
|
4652
|
+
webUrl: item.publishStatus === "published" ? item.webUrl : void 0
|
|
4653
|
+
},
|
|
4654
|
+
fileCount: result.fileCount
|
|
4655
|
+
}
|
|
4656
|
+
};
|
|
4657
|
+
} catch (error) {
|
|
4658
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4659
|
+
throw new Error(message.replace(/缺少 marketplace publish token。请先登录 NextClaw,或传入 --token。?/g, "发布需要 NextClaw 平台登录态。请先运行 nextclaw login。").replace(/,或传入 --token。?/g, "。"));
|
|
4660
|
+
} finally {
|
|
4661
|
+
await rm(tempDirectory, {
|
|
4662
|
+
recursive: true,
|
|
4663
|
+
force: true
|
|
4664
|
+
});
|
|
4665
|
+
}
|
|
4666
|
+
};
|
|
4667
|
+
};
|
|
4668
|
+
//#endregion
|
|
4669
|
+
//#region src/cli/app/controllers/app-publish-command.controller.ts
|
|
4670
|
+
const PLATFORM_APPS_URL = "https://platform.nextclaw.io/apps";
|
|
4671
|
+
var AppPublishCommandController = class {
|
|
4672
|
+
constructor(appPublishingService = new AppPublishingService()) {
|
|
4673
|
+
this.appPublishingService = appPublishingService;
|
|
4674
|
+
}
|
|
4675
|
+
publish = async (target, options) => {
|
|
4676
|
+
const { allowWarnings, json, meta } = options;
|
|
4677
|
+
try {
|
|
4678
|
+
const result = await this.appPublishingService.publish({
|
|
4679
|
+
appDirectory: target,
|
|
4680
|
+
metadataPath: meta,
|
|
4681
|
+
allowWarnings
|
|
4682
|
+
});
|
|
4683
|
+
process.stdout.write(json ? `${JSON.stringify({
|
|
4684
|
+
ok: true,
|
|
4685
|
+
...result
|
|
4686
|
+
}, null, 2)}\n` : this.format(result));
|
|
4687
|
+
} catch (error) {
|
|
4688
|
+
this.writeError(error, Boolean(json));
|
|
4689
|
+
process.exitCode = 1;
|
|
4690
|
+
}
|
|
4691
|
+
};
|
|
4692
|
+
format = (result) => {
|
|
4693
|
+
const { item } = result.publish;
|
|
4694
|
+
if (item.publishStatus === "pending") return [
|
|
4695
|
+
`Submitted ${item.name} (${item.appId}) ${item.latestVersion} for review.`,
|
|
4696
|
+
"Status: pending",
|
|
4697
|
+
"The app will appear in the App Marketplace after approval.",
|
|
4698
|
+
`Manage submissions: ${PLATFORM_APPS_URL}`,
|
|
4699
|
+
""
|
|
4700
|
+
].join("\n");
|
|
4701
|
+
return [
|
|
4702
|
+
`${result.publish.created ? "Published" : "Updated"} ${item.name} (${item.appId}) ${item.latestVersion}.`,
|
|
4703
|
+
"Status: published",
|
|
4704
|
+
item.webUrl ? `Details: ${item.webUrl}` : "",
|
|
4705
|
+
`Manage apps: ${PLATFORM_APPS_URL}`,
|
|
4706
|
+
""
|
|
4707
|
+
].filter((line, index, lines) => line || index === lines.length - 1).join("\n");
|
|
4708
|
+
};
|
|
4709
|
+
writeError = (error, json) => {
|
|
4710
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4711
|
+
process.stdout.write(json ? `${JSON.stringify({
|
|
4712
|
+
ok: false,
|
|
4713
|
+
error: { message }
|
|
4714
|
+
}, null, 2)}\n` : `Mini App publish failed: ${message}\n`);
|
|
4715
|
+
};
|
|
4716
|
+
};
|
|
4717
|
+
//#endregion
|
|
4718
|
+
//#region src/cli/app/controllers/app-validate-publish-command.controller.ts
|
|
4719
|
+
var AppValidatePublishCommandController = class {
|
|
4720
|
+
constructor(appPublishingService = new AppPublishingService()) {
|
|
4721
|
+
this.appPublishingService = appPublishingService;
|
|
4722
|
+
}
|
|
4723
|
+
validate = async (target, options) => {
|
|
4724
|
+
try {
|
|
4725
|
+
const validation = await this.appPublishingService.validate({
|
|
4726
|
+
appDirectory: target,
|
|
4727
|
+
metadataPath: options.meta
|
|
4728
|
+
});
|
|
4729
|
+
process.stdout.write(options.json ? `${JSON.stringify({
|
|
4730
|
+
ok: true,
|
|
4731
|
+
validation
|
|
4732
|
+
}, null, 2)}\n` : this.format(validation));
|
|
4733
|
+
} catch (error) {
|
|
4734
|
+
this.writeError(error, Boolean(options.json));
|
|
4735
|
+
process.exitCode = 1;
|
|
4736
|
+
}
|
|
4737
|
+
};
|
|
4738
|
+
format = (validation) => {
|
|
4739
|
+
const lines = [
|
|
4740
|
+
`Mini App publish validation passed: ${validation.appId}@${validation.version}`,
|
|
4741
|
+
`Components: ${validation.componentCount ?? 0}`,
|
|
4742
|
+
`Bundle size: ${validation.bundleSizeBytes} bytes`,
|
|
4743
|
+
`Metadata: ${validation.metadataPath}`
|
|
4744
|
+
];
|
|
4745
|
+
for (const warning of validation.warnings) lines.push(`Warning [${warning.code}]: ${warning.message}`);
|
|
4746
|
+
return `${lines.join("\n")}\n`;
|
|
4747
|
+
};
|
|
4748
|
+
writeError = (error, json) => {
|
|
4749
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4750
|
+
process.stdout.write(json ? `${JSON.stringify({
|
|
4751
|
+
ok: false,
|
|
4752
|
+
error: { message }
|
|
4753
|
+
}, null, 2)}\n` : `Mini App publish validation failed: ${message}\n`);
|
|
4754
|
+
};
|
|
4755
|
+
};
|
|
4756
|
+
//#endregion
|
|
4610
4757
|
//#region src/cli/app/register-app-commands.ts
|
|
4611
4758
|
function registerAppCommands(program) {
|
|
4612
|
-
const app = program.command("app").description("
|
|
4759
|
+
const app = program.command("app").description("Develop, validate, and publish NextClaw apps");
|
|
4613
4760
|
const appCheck = new AppCheckCommandController();
|
|
4614
4761
|
const appDev = new AppDevCommandController();
|
|
4615
4762
|
const appCall = new AppCallCommandController();
|
|
4616
4763
|
const appRestart = new AppRestartCommandController();
|
|
4764
|
+
const appValidatePublish = new AppValidatePublishCommandController();
|
|
4765
|
+
const appPublish = new AppPublishCommandController();
|
|
4766
|
+
app.command("validate-publish <app-dir>").description("Validate a NextClaw Mini App before Marketplace submission").option("--meta <path>", "Use a custom marketplace metadata file").option("--json", "Output JSON", false).action(async (target, opts) => appValidatePublish.validate(target, opts));
|
|
4767
|
+
app.command("publish <app-dir>").description("Submit a NextClaw Mini App to the App Marketplace").option("--meta <path>", "Use a custom marketplace metadata file").option("--allow-warnings", "Submit after reviewing validation warnings", false).option("--json", "Output JSON", false).action(async (target, opts) => appPublish.publish(target, opts));
|
|
4617
4768
|
app.command("check <app-dir>").description("Check a Panel App or Service App directory").option("--json", "Output JSON", false).action(async (target, opts) => appCheck.check(target, opts));
|
|
4618
4769
|
app.command("dev <service-app-dir>").description("Start a Service App through the real runtime and inspect its actions").option("--json", "Output JSON", false).action(async (target, opts) => appDev.dev(target, opts));
|
|
4619
4770
|
app.command("call <service-app-dir> <action-name>").description("Call a Service App action through the real runtime").option("--input <json>", "JSON object input for the action").option("--json", "Output JSON", false).action(async (target, actionName, opts) => appCall.call(target, actionName, opts));
|