aiot-toolkit 2.0.6-beta.9 → 2.1.0-prender.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
@@ -74,26 +74,50 @@ aiot-toolkit2.0目前支持的打包格式如下:
74
74
 
75
75
  ## resign
76
76
 
77
- build目录重新生成rpk
78
-
79
- 步骤
80
-
81
- 1. 创建任意名称的空目录, 例如 `folder`
82
- 2. 将 `build` 复制到 `folder`
83
- 3. (可跳过)如需自定义证书,将证书复制到 `folder/sign`
84
- 4. 进入 `folder` 目录,执行 `aiot resign`,会在`foler/dist`中生成rpk
85
- 5. 目录结构如下
86
-
87
- ```sh
88
- folder
89
- build // 用户复制
90
- sign // 用户复制,可选
91
- certificate.pem
92
- private.pem
93
- dist // 生成
94
- ***.rpk
77
+ **rpk解压的代码目录**重新生成rpk
78
+
79
+ ### 示例
80
+
81
+ #### 无参数
82
+
83
+ 1. 创建目录结构如下
84
+
85
+ ```js
86
+ folder
87
+ build // 用户复制:代码目录
88
+ *.js
89
+ sign // 用户复制:证书 (可选)
90
+ certificate.pem
91
+ private.pem
92
+ ```
93
+
94
+ 1. 执行命令:`npx aiot-toolkit resign`
95
+ 1. 产物
96
+
97
+ ```js
98
+ folder
99
+ dist // 生成
100
+ ***.rpk
101
+ ```
102
+
103
+ #### 自定义参数
104
+
105
+ 1. 执行命令:`npx aiot-toolkit resign --source="com.your.app" --output="."`
106
+ 2. 产物:
107
+
108
+ ```js
109
+ com.your.app // 代码目录
110
+ com.your.app.rpk // 产物
95
111
  ```
96
112
 
113
+ ### 参数说明
114
+
115
+ | 名称 | 说明 | 默认值 |
116
+ | ------ | -------- | ------- |
117
+ | source | 代码目录 | `build` |
118
+ | output | 产物目录 | `dist` |
119
+ | sign | 证书目录 | `sign` |
120
+
97
121
  ## jsc
98
122
 
99
123
  指定目录的js文件转换为jsc文件
package/lib/bin.js CHANGED
@@ -10,7 +10,6 @@ var _VelaUxBuilder = _interopRequireDefault(require("./builder/VelaUxBuilder"));
10
10
  var _AndroidUxStart = _interopRequireDefault(require("./starter/AndroidUxStart"));
11
11
  var _VelaUxStarter = _interopRequireDefault(require("./starter/VelaUxStarter"));
12
12
  var _DeviceUtil = _interopRequireDefault(require("./utils/DeviceUtil"));
13
- var _VelaAvdUtils = _interopRequireDefault(require("./utils/VelaAvdUtils"));
14
13
  var _ZipUtil = _interopRequireDefault(require("@aiot-toolkit/aiotpack/lib/compiler/javascript/vela/utils/ZipUtil"));
15
14
  var _BuildNameFormatType = _interopRequireDefault(require("@aiot-toolkit/aiotpack/lib/compiler/javascript/vela/enum/BuildNameFormatType"));
16
15
  var _Jsc = _interopRequireDefault(require("@aiot-toolkit/aiotpack/lib/compiler/javascript/vela/utils/Jsc"));
@@ -20,6 +19,9 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
20
19
  // 支持的最低node版本
21
20
  const NODE_MINIMUM_VERSION = '18.0.0';
22
21
  checkVersion();
22
+
23
+ // VelaAvdUtil is lazy-imported in emulator commands to avoid loading emulator code for build/release
24
+
23
25
  // 校验当前环境中的node
24
26
  function checkVersion() {
25
27
  const currentVersion = process.versions.node;
@@ -142,52 +144,98 @@ async function main() {
142
144
  name: 'createVVD',
143
145
  description: 'create a vela virtual device',
144
146
  action: async () => {
145
- _VelaAvdUtils.default.createVelaVvdByInquire();
147
+ const VelaAvdUtil = (await import('./utils/VelaAvdUtils')).default;
148
+ await VelaAvdUtil.createVelaVvdByInquire();
146
149
  }
147
150
  }, {
148
151
  name: 'deleteVVD',
149
152
  description: 'delete vela virtual device(s)',
150
- paramList: [{
151
- name: 'avdNames',
152
- description: 'avd names to delete',
153
- enableInquirer: true,
154
- type: 'checkbox',
155
- choices: _VelaAvdUtils.default.vvdManager.getVvdList().map(item => {
156
- return {
157
- name: item.name,
158
- value: item.name
159
- };
160
- })
161
- }],
162
- action: async option => {
153
+ action: async () => {
163
154
  const {
164
- avdNames
165
- } = option;
155
+ checkbox
156
+ } = await import('@inquirer/prompts');
157
+ const VelaAvdUtil = (await import('./utils/VelaAvdUtils')).default;
158
+ const vvdList = VelaAvdUtil.vvdManager.getVvdList();
159
+ const avdNames = await checkbox({
160
+ message: 'avd names to delete',
161
+ choices: vvdList.map(item => {
162
+ return {
163
+ name: item.name,
164
+ value: item.name
165
+ };
166
+ })
167
+ });
166
168
  avdNames.forEach(avdName => {
167
- _VelaAvdUtils.default.vvdManager.deleteVvd(avdName);
169
+ VelaAvdUtil.vvdManager.deleteVvd(avdName);
168
170
  });
169
171
  }
172
+ }, {
173
+ name: 'status',
174
+ description: 'show active running sessions',
175
+ action: async () => {
176
+ const os = await import('os');
177
+ const sessionDir = _path.default.join(os.homedir(), '.aiot-toolkit', 'running-sessions');
178
+ if (!_fsExtra.default.existsSync(sessionDir)) {
179
+ console.log(JSON.stringify([]));
180
+ return;
181
+ }
182
+ const files = _fsExtra.default.readdirSync(sessionDir).filter(f => f.endsWith('.json'));
183
+ const active = [];
184
+ for (const file of files) {
185
+ try {
186
+ const session = _fsExtra.default.readJsonSync(_path.default.join(sessionDir, file));
187
+ process.kill(session.pid, 0);
188
+ active.push(session);
189
+ } catch {
190
+ // pid not alive, clean up stale session file
191
+ _fsExtra.default.removeSync(_path.default.join(sessionDir, file));
192
+ }
193
+ }
194
+ console.log(JSON.stringify(active, null, 2));
195
+ }
170
196
  }, {
171
197
  name: 'initEmulatorEnv',
172
198
  description: 'init/reset emulator environment',
173
199
  action: async () => {
174
- _VelaAvdUtils.default.initEmulatorEnv();
200
+ const VelaAvdUtil = (await import('./utils/VelaAvdUtils')).default;
201
+ await VelaAvdUtil.initEmulatorEnv();
175
202
  }
176
203
  }, {
177
204
  name: 'resign',
178
205
  description: 'resign build folder to dist/rpk',
179
- action: () => {
206
+ paramList: [{
207
+ name: 'source',
208
+ description: 'build folder to resign',
209
+ defaultValue: 'build',
210
+ type: 'string'
211
+ }, {
212
+ name: 'output',
213
+ description: 'output folder for the resigned build',
214
+ defaultValue: 'dist',
215
+ type: 'string'
216
+ }, {
217
+ name: 'sign',
218
+ description: 'sign folder for the resigned build',
219
+ defaultValue: 'sign',
220
+ type: 'string'
221
+ }],
222
+ action: option => {
223
+ const {
224
+ source,
225
+ output,
226
+ sign
227
+ } = option;
180
228
  const projectPath = process.cwd();
181
229
  const param = {
182
- signRoot: 'sign',
230
+ signRoot: sign,
183
231
  mode: _aiotpack.CompileMode.DEVELOPMENT,
184
- outputPath: 'build',
185
- releasePath: 'dist',
232
+ outputPath: source,
233
+ releasePath: output,
186
234
  projectPath,
187
235
  buildNameFormat: _BuildNameFormatType.default.DEFAULT,
188
- sourceRoot: 'build'
236
+ sourceRoot: source
189
237
  };
190
- return _ZipUtil.default.createRpk(projectPath + '/build', param);
238
+ return _ZipUtil.default.createRpk(_path.default.join(projectPath, source), param);
191
239
  }
192
240
  }, {
193
241
  name: 'jsc',
@@ -2,11 +2,13 @@ import { IParam } from '@aiot-toolkit/commander';
2
2
  import IBuilder from './IBuilder';
3
3
  import UxBuilderBase from './UxBuilderBase';
4
4
  import IVelaUxBuilderOption from '../interface/IVelaUxBuilderOption';
5
+ import { IJavascriptCompileOption } from '@aiot-toolkit/aiotpack';
5
6
  /**
6
7
  * VelaUxBuilder
7
8
  */
8
9
  declare class VelaUxBuilder extends UxBuilderBase<IVelaUxBuilderOption> implements IBuilder<IVelaUxBuilderOption> {
9
10
  params: IParam[];
10
11
  match(projectPath: string): boolean;
12
+ getCompilerOption(projectPath: string, options: IVelaUxBuilderOption): Partial<IJavascriptCompileOption>;
11
13
  }
12
14
  export default VelaUxBuilder;
@@ -16,5 +16,19 @@ class VelaUxBuilder extends _UxBuilderBase.default {
16
16
  match(projectPath) {
17
17
  return _sharedUtils.ProjectType.getProjectType(projectPath) === _sharedUtils.ProjectType.VELA_UX;
18
18
  }
19
+ getCompilerOption(projectPath, options) {
20
+ const compilerOption = super.getCompilerOption(projectPath, options);
21
+
22
+ // --no-prerender → enablePrerender: false
23
+ if (options.noPrerender) {
24
+ compilerOption.enablePrerender = false;
25
+ }
26
+
27
+ // --prerender-exclude "a,b" → prerenderExclude: ['a', 'b']
28
+ if (typeof options.prerenderExclude === 'string' && options.prerenderExclude) {
29
+ compilerOption.prerenderExclude = options.prerenderExclude.split(',').map(s => s.trim()).filter(Boolean);
30
+ }
31
+ return compilerOption;
32
+ }
19
33
  }
20
34
  var _default = exports.default = VelaUxBuilder;
@@ -17,6 +17,10 @@ interface IVelaUxBuilderOption extends IUxBuildOption {
17
17
  * 是否启用 jsc bundle
18
18
  */
19
19
  enableJsc?: boolean;
20
+ /**
21
+ * 是否使用 VRU 包装格式(release 模式生成 manifest+CERT+inner-vru 的双层 RPK)
22
+ */
23
+ enableVru?: boolean;
20
24
  /**
21
25
  * 是否启用 `protobuf`
22
26
  */
@@ -62,6 +66,14 @@ interface IVelaUxBuilderOption extends IUxBuildOption {
62
66
  * 删除 console. <br/>+ `true`: 全部删除 <br/>+ `false`: 不删除. <br/>+ string: 自定义. <br/>示例:`--drop-console=warn,error` ,`--drop-console=true`
63
67
  */
64
68
  dropConsole?: string;
69
+ /**
70
+ * 禁用预渲染
71
+ */
72
+ noPrerender?: boolean;
73
+ /**
74
+ * 排除不预渲染的页面路径,逗号分隔
75
+ */
76
+ prerenderExclude?: string;
65
77
  }
66
78
  declare const velaUxBuilderParams: IParam[];
67
79
  export { velaUxBuilderParams };
@@ -21,6 +21,11 @@ const velaUxBuilderParams = exports.velaUxBuilderParams = [{
21
21
  "name": "enable-jsc",
22
22
  "description": "enable jsc bundle",
23
23
  "defaultValue": false
24
+ }, {
25
+ "type": "confirm",
26
+ "name": "enable-vru",
27
+ "description": "enable VRU release format",
28
+ "defaultValue": false
24
29
  }, {
25
30
  "type": "confirm",
26
31
  "name": "enable-protobuf",
@@ -75,4 +80,13 @@ const velaUxBuilderParams = exports.velaUxBuilderParams = [{
75
80
  "name": "drop-console",
76
81
  "description": "drop console. true: drop all, false: do nothing, string: custom. example: --drop-console warn,error",
77
82
  "defaultValue": false
83
+ }, {
84
+ "type": "confirm",
85
+ "name": "no-prerender",
86
+ "description": "disable prerender",
87
+ "defaultValue": false
88
+ }, {
89
+ "type": "string",
90
+ "name": "prerender-exclude",
91
+ "description": "exclude pages from prerender, comma-separated. example: --prerender-exclude pages/Dynamic,pages/Live"
78
92
  }];
@@ -1,5 +1,5 @@
1
1
  import { IParam } from '@aiot-toolkit/commander';
2
- import { IStartOptions, CommonInstance } from '@aiot-toolkit/emulator';
2
+ import { IStartOptions, CommonInstance, BrokerInstance } from '@aiot-toolkit/emulator';
3
3
  import VelaUxBuilder from '../builder/VelaUxBuilder';
4
4
  import IStarter from './IStarter';
5
5
  import Event from 'events';
@@ -11,6 +11,7 @@ declare class VelaUxStarter extends IStarter<IStartOptions> {
11
11
  protected name: string;
12
12
  protected description: string;
13
13
  emulatorInstance?: CommonInstance;
14
+ brokerInstance?: BrokerInstance;
14
15
  builder: VelaUxBuilder;
15
16
  event: Event;
16
17
  lastRpk?: string;
@@ -14,6 +14,7 @@ var _VelaUxBuilder = _interopRequireDefault(require("../builder/VelaUxBuilder"))
14
14
  var _VelaAvdUtils = _interopRequireDefault(require("../utils/VelaAvdUtils"));
15
15
  var _IStarter = _interopRequireDefault(require("./IStarter"));
16
16
  var _fsExtra = _interopRequireDefault(require("fs-extra"));
17
+ var _os = _interopRequireDefault(require("os"));
17
18
  var _aiotpack = require("@aiot-toolkit/aiotpack");
18
19
  var _events = _interopRequireDefault(require("events"));
19
20
  var _FileLaneTriggerType = _interopRequireDefault(require("file-lane/lib/enum/FileLaneTriggerType"));
@@ -60,6 +61,14 @@ class VelaUxStarter extends _IStarter.default {
60
61
  description: 'deprecated',
61
62
  deprecated: 'please remove it now',
62
63
  deprecatedVersion: '2.1.0'
64
+ }, {
65
+ name: 'device',
66
+ description: 'device ID for MQTT topic (e.g. vela_emulator_S4)',
67
+ type: 'string'
68
+ }, {
69
+ name: 'mqttPort',
70
+ description: 'MQTT broker port',
71
+ type: 'string'
63
72
  }, ..._IVelaUxBuilderOption.velaUxBuilderParams])();
64
73
  async start(projectPath, options) {
65
74
  const check = await _VelaAvdUtils.default.checkEmulatorEnv();
@@ -96,16 +105,24 @@ class VelaUxStarter extends _IStarter.default {
96
105
  })
97
106
  });
98
107
  }
99
- // 检查选择的模拟器是否符合要求
100
- if (vvdName && !this.isAvailableEmulator(vvdName)) {
101
- _sharedUtils.ColorConsole.throw(`this emulator is unavailable, please create a new emulator.`);
102
- return;
103
- }
104
108
 
105
- // build
106
- const compilerOption = this.builder.getCompilerOption(projectPath, options);
107
- // start build
108
- await this.builder.build(projectPath, options);
109
+ // Step 1: Start MQTT broker first
110
+ this.brokerInstance = await (0, _emulator.startBroker)(options.mqttPort ? {
111
+ preferredMqttPort: Number(options.mqttPort)
112
+ } : undefined);
113
+ _sharedUtils.ColorConsole.success({
114
+ word: 'MQTT broker started: '
115
+ }, `${this.brokerInstance.mqttHost}:${this.brokerInstance.mqttPort}`);
116
+
117
+ // Step 2: Generate debug config (contains MQTT address and port)
118
+ const deviceId = options.device || `vela_emulator_${vvdName}`;
119
+ const debugCfg = {
120
+ mqttHost: this.brokerInstance.mqttHost,
121
+ mqttPort: this.brokerInstance.mqttPort,
122
+ device: deviceId
123
+ };
124
+ const cfgPath = _path.default.join(_os.default.tmpdir(), `quickapp_debug_cfg_${vvdName}.json`);
125
+ await _fsExtra.default.writeFile(cfgPath, JSON.stringify(debugCfg, undefined, 2));
109
126
 
110
127
  // 设置 debugPort
111
128
  let debugPort;
@@ -115,16 +132,95 @@ class VelaUxStarter extends _IStarter.default {
115
132
  });
116
133
  }
117
134
 
118
- // start emulator
135
+ // Step 3: Start emulator with stdoutCallback to push debug config on boot
136
+ // quickapp_debug_cfg.json is in /tmp which gets wiped on reboot,
137
+ // so we push it when emulator outputs "Start Debug Server" (same as core plugin)
138
+ const pushDebugConfig = async () => {
139
+ if (!this.emulatorInstance) return;
140
+ await this.emulatorInstance.push(cfgPath, '/tmp/quickapp_debug_cfg.json');
141
+ _sharedUtils.ColorConsole.success({
142
+ word: 'Debug config pushed to emulator'
143
+ });
144
+ };
119
145
  const startRes = await _VelaAvdUtils.default.vvdManager.startVvd({
120
146
  vvdName,
121
147
  origin: _emulator.IStartOrigin.Terminal,
122
- debugPort
148
+ debugPort,
149
+ stdoutCallback: msg => {
150
+ // 模拟器启动/重启时推送 debug config(参考 core 插件做法)
151
+ if (msg.includes('Start Debug Server')) {
152
+ pushDebugConfig();
153
+ }
154
+ }
123
155
  });
124
156
  this.emulatorInstance = startRes.emulatorInstance;
125
157
  if (!this.emulatorInstance) {
126
158
  throw new Error('emulatorInstance is undefined');
127
159
  }
160
+
161
+ // 如果是冷启动,stdoutCallback 会在启动过程中触发推送
162
+ // 如果模拟器已经在运行(非冷启动),需要手动推送一次
163
+ if (!startRes.coldBoot) {
164
+ await pushDebugConfig();
165
+ }
166
+
167
+ // Step 4: Wait for VelaJS runtime to connect to MQTT broker
168
+ await new Promise(resolve => {
169
+ if (this.brokerInstance.aedes.connectedClients > 0) {
170
+ resolve();
171
+ return;
172
+ }
173
+ const onClient = () => {
174
+ this.brokerInstance.aedes.removeListener('client', onClient);
175
+ resolve();
176
+ };
177
+ this.brokerInstance.aedes.on('client', onClient);
178
+ });
179
+ _sharedUtils.ColorConsole.success({
180
+ word: 'VelaJS runtime connected to MQTT broker'
181
+ });
182
+
183
+ // Output MCP config for AI agent
184
+ _sharedUtils.ColorConsole.success({
185
+ word: 'MCP config: '
186
+ }, `--device ${deviceId} --mqttPort ${this.brokerInstance.mqttPort}`);
187
+
188
+ // Write session file for status tracking
189
+ const sessionDir = _path.default.join(_os.default.homedir(), '.vela', 'sessions');
190
+ const sessionFile = _path.default.join(sessionDir, `${deviceId}.json`);
191
+ await _fsExtra.default.ensureDir(sessionDir);
192
+ await _fsExtra.default.writeJson(sessionFile, {
193
+ pid: process.pid,
194
+ device: deviceId,
195
+ mqttHost: this.brokerInstance.mqttHost,
196
+ mqttPort: this.brokerInstance.mqttPort,
197
+ grpcPort: Number(startRes.grpcConfig['grpc.port']),
198
+ vvdName,
199
+ source: 'cli',
200
+ startedAt: new Date().toISOString()
201
+ }, {
202
+ spaces: 2
203
+ });
204
+
205
+ // Clean up session file on exit
206
+ const cleanup = () => {
207
+ try {
208
+ _fsExtra.default.removeSync(sessionFile);
209
+ } catch {}
210
+ };
211
+ process.on('exit', cleanup);
212
+ process.on('SIGINT', () => {
213
+ cleanup();
214
+ process.exit();
215
+ });
216
+ process.on('SIGTERM', () => {
217
+ cleanup();
218
+ process.exit();
219
+ });
220
+
221
+ // Step 7: Build + push rpk + start app
222
+ const compilerOption = this.builder.getCompilerOption(projectPath, options);
223
+ await this.builder.build(projectPath, options);
128
224
  const projectInfo = _aiotpack.UxFileUtils.getManifestInfo(projectPath, compilerOption.sourceRoot);
129
225
  if (this.lastRpk && _fsExtra.default.existsSync(this.lastRpk)) {
130
226
  const targetPath = await this.emulatorInstance?.pushRpk(this.lastRpk, projectInfo.package);
@@ -157,14 +253,17 @@ class VelaUxStarter extends _IStarter.default {
157
253
  */
158
254
  isAvailableEmulator(avdName) {
159
255
  const {
160
- imageDir
256
+ imageDir,
257
+ customImagePath
161
258
  } = _VelaAvdUtils.default.vvdManager.getVvdInfo(avdName);
162
- // 没有avdImagePath,即对应的configIni里没有 image.sysdir.1 字段
163
- // 有avdImagePath,但是这个目录下没有nuttx
164
- if (!imageDir || !_fsExtra.default.existsSync(_path.default.resolve(imageDir, 'nuttx'))) {
165
- return false;
259
+ const images = [imageDir, customImagePath];
260
+ let res = false;
261
+ for (const image of images) {
262
+ if (image && _fsExtra.default.existsSync(_path.default.resolve(image, 'nuttx'))) {
263
+ res = true;
264
+ }
166
265
  }
167
- return true;
266
+ return res;
168
267
  }
169
268
  }
170
269
  var _default = exports.default = VelaUxStarter;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aiot-toolkit",
3
- "version": "2.0.6-beta.9",
3
+ "version": "2.1.0-prender.1",
4
4
  "description": "Tools for creating, developing, and packaging aiot applications.",
5
5
  "keywords": [
6
6
  "aiot"
@@ -22,14 +22,14 @@
22
22
  "test": "node ./__tests__/aiot-toolkit.test.js"
23
23
  },
24
24
  "dependencies": {
25
- "@aiot-toolkit/aiotpack": "2.0.6-beta.9",
26
- "@aiot-toolkit/commander": "2.0.6-beta.9",
27
- "@aiot-toolkit/emulator": "2.0.6-beta.9",
28
- "@aiot-toolkit/shared-utils": "2.0.6-beta.9",
25
+ "@aiot-toolkit/aiotpack": "2.1.0-prender.1",
26
+ "@aiot-toolkit/commander": "2.1.0-prender.1",
27
+ "@aiot-toolkit/emulator": "2.1.0-prender.1",
28
+ "@aiot-toolkit/shared-utils": "2.1.0-prender.1",
29
29
  "@inquirer/prompts": "^5.3.0",
30
30
  "@miwt/adb": "^0.9.0",
31
31
  "axios": "^1.7.4",
32
- "file-lane": "2.0.6-beta.9",
32
+ "file-lane": "2.1.0-prender.1",
33
33
  "fs-extra": "^11.2.0",
34
34
  "koa-router": "^13.0.1",
35
35
  "lodash": "^4.17.21",
@@ -43,5 +43,5 @@
43
43
  "@types/qr-image": "^3.2.9",
44
44
  "@types/semver": "^7.5.8"
45
45
  },
46
- "gitHead": "18718f09f1ee7f1d7361022c5fb7858c87cee2bd"
46
+ "gitHead": "8bb39a59fbe7a7c22c1167e69d44c78024330cec"
47
47
  }