aiot-toolkit 1.2.0-alpha.8 → 1.2.1-alpha.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/bin/index.js +10 -0
- package/lib/commands/aa.js +1 -1
- package/lib/commands/ai.js +1 -1
- package/lib/commands/chrome.js +2 -0
- package/lib/commands/koa.js +2 -0
- package/lib/commands/koa.test.js +2 -0
- package/package.json +13 -9
- package/CHANGELOG.md +0 -393
package/bin/index.js
CHANGED
|
@@ -39,6 +39,16 @@ program
|
|
|
39
39
|
ai(prompt, options)
|
|
40
40
|
})
|
|
41
41
|
|
|
42
|
+
program
|
|
43
|
+
.command('chrome [query]')
|
|
44
|
+
.description('Call AIOT Chrome Extension from command line.')
|
|
45
|
+
.option('-i, --interactive', 'interactive mode')
|
|
46
|
+
.option('--keep-alive', 'keep browser open after query')
|
|
47
|
+
.action((query, options) => {
|
|
48
|
+
const chrome = require('../lib/commands/chrome')
|
|
49
|
+
chrome(query, options)
|
|
50
|
+
})
|
|
51
|
+
|
|
42
52
|
program
|
|
43
53
|
.command('mcp')
|
|
44
54
|
.description('A MCP Service to generate QuickApp.')
|
package/lib/commands/aa.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";const puppeteer=require("puppeteer"),chalk=require("chalk"),fs=require("fs"),path=require("path"),sleep=e=>new Promise((t=>setTimeout(t,e)));async function test(){const e=await puppeteer.launch(),t=await e.newPage();var
|
|
1
|
+
"use strict";const puppeteer=require("puppeteer"),chalk=require("chalk"),fs=require("fs"),path=require("path"),sleep=e=>new Promise((t=>setTimeout(t,e)));async function test(){const e=await puppeteer.launch(),t=await e.newPage();var n;await t.emulate({name:"iPhone X",userAgent:"Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0.3 Mobile/15E148 Safari/604.1",viewport:{width:375,height:812,deviceScaleFactor:3,isMobile:!0,hasTouch:!0,isLandscape:!1}}),await(n=1e3,new Promise((e=>setTimeout(e,n))));await t.goto("http://localhost:8000/preview/Home",{waitUntil:"load",timeout:6e4});await t.evaluate((()=>{const e=document.querySelector("body");return e&&""===e.innerHTML.trim()}))?console.error(chalk.red("页面白屏")):console.log(chalk.green("页面正常加载"));const a=path.join(__dirname,"screenshots");fs.existsSync(a)||fs.mkdirSync(a,{recursive:!0});const o=path.join(a,"run_1.png");await t.screenshot({path:o})}function extractJSON(e){try{var t;const n=null===(t=(e=e.replace(/```/g,"").trim()).match(/{[\s\S]*}/))||void 0===t?void 0:t[0];if(!n)throw new Error("No JSON content found");const a=n.replace(/,\s*}/g,"}").replace(/,\s*]/g,"]").replace(/\\n/g,"\\\\n").replace(/\\t/g,"\\\\t"),o=JSON.parse(a);return console.log("Extracted JSON:",o),o}catch(e){return console.error("Error extracting JSON:",e.message),null}}function testPath(){const e=path.basename("/home/lvxin/work/gitlab/ai-quickapp/test/screenshots/run_29.png"),t=path.join("screenshots",e);console.log(t)}const mockFiles=[{id:"cbb08670-6e8d-4230-9d04-9d1206b928ba",name:"Cyber_User.png",size:562298,extension:"png",mime_type:"image/png",created_by:"be6afaf3-63ef-42b3-9137-84b326c29e73",created_at:1746777496},{id:"e8d2827e-318b-4885-9def-3abf39af3cb2",name:"拍照解题-手机解题快应用.pdf",size:502150,extension:"pdf",mime_type:"application/pdf",created_by:"be6afaf3-63ef-42b3-9137-84b326c29e73",created_at:1746777522}],filesStr=mockFiles.map((e=>`${e.mime_type}:${e.id}`)).join(","),{repairJson:repairJson,loads:loads}=require("json-repair-js"),testJSONString='\n我将根据您提供的需求文档,为您设计一个图像生成器快应用。\n\n首先,我需要分析一下文档内容,提取核心功能点:\n\n1. 这是一个图像生成器应用,有两个主要页面\n2. 第一个页面是图像生成页面,包含示例卡片列表和底部输入区\n3. 第二个页面是图像编辑页面,可以修改生成的图像或提高清晰度\n4. 应用需要调用API接口来生成、修改和提高图像清晰度\n\n让我为您生成一个完整的快应用项目:\n{\n "HomePage": "<template>\n",\n} \n';console.log(typeof loads(testJSONString),loads(testJSONString));
|
|
2
2
|
//# sourceMappingURL=aa.js.map
|
package/lib/commands/ai.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";const ora=require("ora"),chalk=require("chalk"),inquirer=require("inquirer"),axios=require("axios"),fs=require("fs"),fsExtra=require("fs-extra"),path=require("path"),DIFY_API_BASE_URL="https://mify-be.pt.xiaomi.com",API_PATH="/api/v1/chat-messages",API_KEY="app-f4yeq6almP6pVZd0YVFZ2ZcG",COZE_API_BASE_URL="https://api.coze.cn",COZE_API_PATH="/v1/workflow/run",COZE_API_KEY="sat_4qRrZHlme4mgZkYO7q1Wx8pf51laLJLoyH8JvYOh2dQf1ybydd6Pa37c1c7nnjSw",headers={Authorization:`Bearer ${COZE_API_KEY}`,"Content-Type":"application/json"},mockData={project_name:"WeatherApp",package_name:"com.example.weatherapp",page_content:{home:'<template>\n <div class="page">\n <div class="header">\n <text class="title">天气预报</text>\n </div>\n <div class="location-bar">\n <text class="location-text">{{locationName}}</text>\n <input type="button" class="location-btn" value="切换城市" onclick="switchCity" />\n </div>\n <div class="current-weather">\n <text class="temp">{{currentTemp}}°</text>\n <text class="weather-desc">{{weatherDesc}}</text>\n <text class="high-low">{{lowTemp}}° / {{highTemp}}°</text>\n </div>\n <div class="weather-detail">\n <div class="detail-item">\n <text class="detail-label">湿度</text>\n <text class="detail-value">{{humidity}}%</text>\n </div>\n <div class="detail-item">\n <text class="detail-label">风力</text>\n <text class="detail-value">{{windLevel}}</text>\n </div>\n <div class="detail-item">\n <text class="detail-label">气压</text>\n <text class="detail-value">{{pressure}}hPa</text>\n </div>\n </div>\n <text class="forecast-title">未来天气预报</text>\n <list class="forecast-list">\n <list-item type="forecast" for="{{forecastData}}" class="forecast-item">\n <text class="day">{{$item.day}}</text>\n <text class="forecast-temp">{{$item.lowTemp}}° / {{$item.highTemp}}°</text>\n <text class="forecast-desc">{{$item.desc}}</text>\n </list-item>\n </list>\n <div class="footer">\n <input type="button" class="refresh-btn" value="刷新" onclick="refreshWeather" />\n <input type="button" class="settings-btn" value="设置" onclick="goToSettings" />\n </div>\n </div>\n</template>\n\n<style>\n .page {\n flex-direction: column;\n background-color: #f5f5f5;\n width: 100%;\n }\n .header {\n height: 120px;\n width: 100%;\n background-color: #2196f3;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n }\n .title {\n font-size: 40px;\n color: #ffffff;\n font-weight: bold;\n }\n .location-bar {\n padding: 20px;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n background-color: #ffffff;\n margin: 10px 0;\n }\n .location-text {\n font-size: 34px;\n color: #333333;\n font-weight: bold;\n }\n .location-btn {\n background-color: #2196f3;\n color: #ffffff;\n font-size: 28px;\n padding: 10px 20px;\n border-radius: 4px;\n }\n .current-weather {\n padding: 40px;\n background-color: #ffffff;\n flex-direction: column;\n align-items: center;\n margin-bottom: 10px;\n }\n .temp {\n font-size: 90px;\n color: #333333;\n font-weight: bold;\n }\n .weather-desc {\n font-size: 34px;\n color: #666666;\n margin: 10px 0;\n }\n .high-low {\n font-size: 30px;\n color: #888888;\n }\n .weather-detail {\n flex-direction: row;\n justify-content: space-around;\n background-color: #ffffff;\n padding: 20px;\n margin-bottom: 10px;\n }\n .detail-item {\n flex-direction: column;\n align-items: center;\n }\n .detail-label {\n font-size: 28px;\n color: #888888;\n margin-bottom: 10px;\n }\n .detail-value {\n font-size: 32px;\n color: #333333;\n font-weight: bold;\n }\n .forecast-title {\n font-size: 34px;\n color: #333333;\n font-weight: bold;\n margin: 20px;\n }\n .forecast-list {\n background-color: #ffffff;\n padding: 10px 0;\n }\n .forecast-item {\n height: 100px;\n flex-direction: row;\n align-items: center;\n justify-content: space-between;\n padding: 0 20px;\n border-bottom-width: 1px;\n border-bottom-color: #eeeeee;\n }\n .day {\n font-size: 30px;\n color: #333333;\n width: 100px;\n }\n .forecast-temp {\n font-size: 28px;\n color: #666666;\n }\n .forecast-desc {\n font-size: 28px;\n color: #888888;\n width: 120px;\n text-align: right;\n }\n .footer {\n flex-direction: row;\n justify-content: center;\n margin-top: 20px;\n margin-bottom: 20px;\n }\n .refresh-btn, .settings-btn {\n background-color: #2196f3;\n color: #ffffff;\n font-size: 28px;\n padding: 10px 30px;\n border-radius: 4px;\n margin: 0 10px;\n }\n</style>\n\n<script>\n export default {\n data: {\n locationName: \'北京\',\n currentTemp: 25,\n weatherDesc: \'晴\',\n lowTemp: 20,\n highTemp: 30,\n humidity: 45,\n windLevel: \'3级\',\n pressure: 1013,\n forecastData: [\n { day: \'明天\', lowTemp: 19, highTemp: 28, desc: \'多云\' },\n { day: \'后天\', lowTemp: 18, highTemp: 27, desc: \'小雨\' },\n { day: \'周三\', lowTemp: 16, highTemp: 24, desc: \'阵雨\' },\n { day: \'周四\', lowTemp: 15, highTemp: 26, desc: \'晴\' },\n { day: \'周五\', lowTemp: 17, highTemp: 28, desc: \'晴\' }\n ]\n },\n onInit() {\n this.getWeatherData()\n },\n getWeatherData() {\n // 在实际项目中,这里应该调用天气API获取真实的数据\n console.log(\'Getting weather data...\')\n // 模拟网络请求延迟\n setTimeout(() => {\n console.log(\'Weather data updated\')\n }, 1000)\n },\n switchCity() {\n // 跳转到城市选择页面\n this.$router.push({\n uri: \'city\'\n })\n },\n refreshWeather() {\n this.getWeatherData()\n },\n goToSettings() {\n // 跳转到设置页面\n this.$router.push({\n uri: \'settings\'\n })\n }\n }\n<\/script>',city:'<template>\n <div class="page">\n <div class="header">\n <text class="title">选择城市</text>\n </div>\n <div class="search-bar">\n <input type="text" class="search-input" placeholder="搜索城市" onchange="onSearch" />\n </div>\n <div class="hot-cities">\n <text class="section-title">热门城市</text>\n <div class="city-grid">\n <div class="city-item" for="{{hotCities}}" onclick="selectCity($item)">\n <text class="city-name">{{$item.name}}</text>\n </div>\n </div>\n </div>\n <list class="city-list">\n <list-item type="city" for="{{cityGroups}}" class="city-group">\n <text class="group-title">{{$item.initial}}</text>\n <div class="cities">\n <div class="city-row" for="{{$item.cities}}" onclick="selectCity($item)">\n <text class="city-name">{{$item.name}}</text>\n </div>\n </div>\n </list-item>\n </list>\n <div class="footer">\n <input type="button" class="back-btn" value="返回" onclick="goBack" />\n </div>\n </div>\n</template>\n\n<style>\n .page {\n flex-direction: column;\n background-color: #f5f5f5;\n width: 100%;\n }\n .header {\n height: 100px;\n width: 100%;\n background-color: #2196f3;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n }\n .title {\n font-size: 36px;\n color: #ffffff;\n font-weight: bold;\n }\n .search-bar {\n padding: 20px;\n background-color: #ffffff;\n margin-bottom: 10px;\n }\n .search-input {\n width: 100%;\n height: 80px;\n border: 1px solid #dddddd;\n border-radius: 4px;\n font-size: 30px;\n padding: 0 20px;\n }\n .hot-cities {\n background-color: #ffffff;\n padding: 20px;\n margin-bottom: 10px;\n }\n .section-title {\n font-size: 32px;\n color: #333333;\n font-weight: bold;\n margin-bottom: 20px;\n }\n .city-grid {\n flex-direction: row;\n flex-wrap: wrap;\n }\n .city-item {\n width: 23%;\n height: 80px;\n background-color: #f5f5f5;\n margin: 1%;\n justify-content: center;\n align-items: center;\n border-radius: 4px;\n }\n .city-name {\n font-size: 28px;\n color: #333333;\n }\n .city-list {\n background-color: #ffffff;\n flex: 1;\n }\n .city-group {\n flex-direction: column;\n }\n .group-title {\n font-size: 30px;\n color: #2196f3;\n background-color: #f5f5f5;\n padding: 10px 20px;\n }\n .cities {\n flex-direction: column;\n }\n .city-row {\n height: 90px;\n padding: 0 20px;\n justify-content: flex-start;\n align-items: center;\n border-bottom-width: 1px;\n border-bottom-color: #eeeeee;\n }\n .footer {\n padding: 20px;\n justify-content: center;\n }\n .back-btn {\n background-color: #2196f3;\n color: #ffffff;\n font-size: 30px;\n padding: 10px 40px;\n border-radius: 4px;\n }\n</style>\n\n<script>\n export default {\n data: {\n searchText: \'\',\n hotCities: [\n { id: 1, name: \'北京\' },\n { id: 2, name: \'上海\' },\n { id: 3, name: \'广州\' },\n { id: 4, name: \'深圳\' },\n { id: 5, name: \'杭州\' },\n { id: 6, name: \'南京\' },\n { id: 7, name: \'武汉\' },\n { id: 8, name: \'成都\' }\n ],\n cityGroups: [\n {\n initial: \'A\',\n cities: [\n { id: 101, name: \'安庆\' },\n { id: 102, name: \'鞍山\' }\n ]\n },\n {\n initial: \'B\',\n cities: [\n { id: 1, name: \'北京\' },\n { id: 201, name: \'保定\' },\n { id: 202, name: \'宝鸡\' }\n ]\n },\n {\n initial: \'C\',\n cities: [\n { id: 301, name: \'长沙\' },\n { id: 302, name: \'长春\' },\n { id: 8, name: \'成都\' }\n ]\n },\n {\n initial: \'G\',\n cities: [\n { id: 3, name: \'广州\' },\n { id: 401, name: \'贵阳\' }\n ]\n }\n ]\n },\n onSearch(e) {\n this.searchText = e.value\n // 在实际项目中,这里应该根据搜索文本过滤城市列表\n console.log(\'Search text:\', this.searchText)\n },\n selectCity(city) {\n // 选择城市后返回主页并更新城市\n this.$router.back({\n params: {\n city: city\n }\n })\n },\n goBack() {\n this.$router.back()\n }\n }\n<\/script>',settings:'<template>\n <div class="page">\n <div class="header">\n <text class="title">设置</text>\n </div>\n <list class="settings-list">\n <list-item type="setting" class="setting-item">\n <text class="setting-label">温度单位</text>\n <div class="unit-toggle">\n <div class="unit-option {{tempUnit === \'c\' ? \'active\' : \'\'}}" onclick="setTempUnit(\'c\')">\n <text class="unit-text {{tempUnit === \'c\' ? \'active-text\' : \'\'}}">°C</text>\n </div>\n <div class="unit-option {{tempUnit === \'f\' ? \'active\' : \'\'}}" onclick="setTempUnit(\'f\')">\n <text class="unit-text {{tempUnit === \'f\' ? \'active-text\' : \'\'}}">°F</text>\n </div>\n </div>\n </list-item>\n <list-item type="setting" class="setting-item">\n <text class="setting-label">自动更新</text>\n <switch class="setting-switch" checked="{{autoUpdate}}" onchange="toggleAutoUpdate"></switch>\n </list-item>\n <list-item type="setting" class="setting-item">\n <text class="setting-label">更新频率</text>\n <div class="frequency-select">\n <text class="frequency-value">{{updateFrequency}}分钟</text>\n <div class="frequency-buttons">\n <input type="button" class="frequency-btn" value="-" onclick="decreaseFrequency" />\n <input type="button" class="frequency-btn" value="+" onclick="increaseFrequency" />\n </div>\n </div>\n </list-item>\n <list-item type="setting" class="setting-item">\n <text class="setting-label">天气预警通知</text>\n <switch class="setting-switch" checked="{{weatherAlert}}" onchange="toggleWeatherAlert"></switch>\n </list-item>\n <list-item type="setting" class="setting-item">\n <text class="setting-label">背景颜色</text>\n <div class="color-options">\n <div class="color-option {{themeColor === \'blue\' ? \'color-selected\' : \'\'}}" style="background-color: #2196f3;" onclick="setThemeColor(\'blue\')"></div>\n <div class="color-option {{themeColor === \'green\' ? \'color-selected\' : \'\'}}" style="background-color: #4caf50;" onclick="setThemeColor(\'green\')"></div>\n <div class="color-option {{themeColor === \'orange\' ? \'color-selected\' : \'\'}}" style="background-color: #ff9800;" onclick="setThemeColor(\'orange\')"></div>\n <div class="color-option {{themeColor === \'purple\' ? \'color-selected\' : \'\'}}" style="background-color: #9c27b0;" onclick="setThemeColor(\'purple\')"></div>\n </div>\n </list-item>\n </list>\n <div class="footer">\n <input type="button" class="save-btn" value="保存设置" onclick="saveSettings" />\n <input type="button" class="back-btn" value="返回" onclick="goBack" />\n </div>\n </div>\n</template>\n\n<style>\n .page {\n flex-direction: column;\n background-color: #f5f5f5;\n width: 100%;\n }\n .header {\n height: 100px;\n width: 100%;\n background-color: #2196f3;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n }\n .title {\n font-size: 36px;\n color: #ffffff;\n font-weight: bold;\n }\n .settings-list {\n margin-top: 10px;\n background-color: #ffffff;\n }\n .setting-item {\n height: 100px;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n padding: 0 20px;\n border-bottom-width: 1px;\n border-bottom-color: #eeeeee;\n }\n .setting-label {\n font-size: 32px;\n color: #333333;\n }\n .unit-toggle {\n flex-direction: row;\n width: 180px;\n height: 60px;\n border-radius: 30px;\n background-color: #eeeeee;\n overflow: hidden;\n }\n .unit-option {\n flex: 1;\n justify-content: center;\n align-items: center;\n }\n .unit-text {\n font-size: 28px;\n color: #666666;\n }\n .active {\n background-color: #2196f3;\n }\n .active-text {\n color: #ffffff;\n }\n .setting-switch {\n width: 100px;\n }\n .frequency-select {\n flex-direction: row;\n align-items: center;\n }\n .frequency-value {\n font-size: 30px;\n color: #666666;\n margin-right: 20px;\n }\n .frequency-buttons {\n flex-direction: row;\n }\n .frequency-btn {\n width: 60px;\n height: 60px;\n background-color: #2196f3;\n color: #ffffff;\n font-size: 36px;\n border-radius: 30px;\n margin: 0 5px;\n text-align: center;\n }\n .color-options {\n flex-direction: row;\n }\n .color-option {\n width: 50px;\n height: 50px;\n border-radius: 25px;\n margin: 0 5px;\n border: 2px solid transparent;\n }\n .color-selected {\n border-color: #333333;\n }\n .footer {\n flex-direction: row;\n justify-content: center;\n margin-top: 40px;\n margin-bottom: 20px;\n }\n .save-btn, .back-btn {\n background-color: #2196f3;\n color: #ffffff;\n font-size: 30px;\n padding: 10px 30px;\n border-radius: 4px;\n margin: 0 10px;\n }\n</style>\n\n<script>\n export default {\n data: {\n tempUnit: \'c\',\n autoUpdate: true,\n updateFrequency: 30,\n weatherAlert: true,\n themeColor: \'blue\'\n },\n onInit() {\n // 从存储加载设置\n this.loadSettings()\n },\n loadSettings() {\n // 在实际项目中,这里应该从本地存储加载用户设置\n console.log(\'Loading settings...\')\n },\n setTempUnit(unit) {\n this.tempUnit = unit\n },\n toggleAutoUpdate(e) {\n this.autoUpdate = e.checked\n },\n increaseFrequency() {\n if (this.updateFrequency < 120) {\n this.updateFrequency += 15\n }\n },\n decreaseFrequency() {\n if (this.updateFrequency > 15) {\n this.updateFrequency -= 15\n }\n },\n toggleWeatherAlert(e) {\n this.weatherAlert = e.checked\n },\n setThemeColor(color) {\n this.themeColor = color\n },\n saveSettings() {\n // 在实际项目中,这里应该将设置保存到本地存储\n console.log(\'Saving settings:\', {\n tempUnit: this.tempUnit,\n autoUpdate: this.autoUpdate,\n updateFrequency: this.updateFrequency,\n weatherAlert: this.weatherAlert,\n themeColor: this.themeColor\n })\n \n // 显示保存成功提示\n this.$app.$def.showToast(\'设置已保存\')\n \n // 返回主页\n setTimeout(() => {\n this.$router.back()\n }, 1500)\n },\n goBack() {\n this.$router.back()\n }\n }\n<\/script>'},manifest:{package:"com.example.weatherapp",name:"WeatherApp",versionName:"1.0.0",versionCode:1,minPlatformVersion:1070,icon:"/common/images/logo.png",features:[],permissions:[{origin:"*"}],config:{logLevel:"debug",designWidth:750},router:{entry:"home",pages:{home:{component:"index"},city:{component:"index"},settings:{component:"index"}}},display:{titleBarBackgroundColor:"#2196f3",titleBarTextColor:"#ffffff",menu:!0,pages:{home:{titleBarText:"天气预报",menu:!1},city:{titleBarText:"选择城市"},settings:{titleBarText:"设置"}}}}},mockFiles=[{id:"cbb08670-6e8d-4230-9d04-9d1206b928ba",name:"Cyber_User.png",size:562298,extension:"png",mime_type:"image/png",created_by:"be6afaf3-63ef-42b3-9137-84b326c29e73",created_at:1746777496},{id:"e8d2827e-318b-4885-9def-3abf39af3cb2",name:"拍照解题-手机解题快应用.pdf",size:502150,extension:"pdf",mime_type:"application/pdf",created_by:"be6afaf3-63ef-42b3-9137-84b326c29e73",created_at:1746777522}],postDataParams={inputs:{image:[{type:"image",transfer_method:"local_file",upload_file_id:"b3c5bee5-3a1a-4ec3-83c6-5d50f8ea8430"},{type:"image",transfer_method:"local_file",upload_file_id:"983603f3-341b-436a-8457-f2c81b708b1e"}]},response_mode:"blocking",conversation_id:"",user:"test",query:"query",files:[{type:"document",transfer_method:"local_file",upload_file_id:"ce9680ab-bf48-453e-87d2-05c0a57441e6"}]},postDataParamsCoze={workflow_id:"7529788219019116583",user:"aiot-toolkit-coze",parameters:{file:JSON.stringify({file_id:"7530178871225090082"}),image:[JSON.stringify({file_id:"7529830150276431922"})],query:"做一个天气快应用"}};function convertToJsonArray(n){return n.split(",").map((n=>{const[e,t]=n.split(":");return{[e.toLocaleLowerCase()]:t}}))}async function postData(n,e){const t={workflow_id:"7529788219019116583",user:"aiot-toolkit-coze",parameters:{query:n}};if(e&&e.length>1){const n=convertToJsonArray(e),i=["png","jpg","jpeg","gif","webp","bmp"],o=["pdf","doc","docx","txt","xls","xlsx"];n.forEach((n=>{const e=Object.keys(n)[0],a=n[e];o.includes(e)&&(t.parameters.file=JSON.stringify({file_id:a})),i.includes(e)&&(t.parameters.image||(t.parameters.image=[]),t.parameters.image.push(JSON.stringify({file_id:a})))})),t.user="IDE_COZE"}try{const n=await axios.post(`${COZE_API_BASE_URL+COZE_API_PATH}`,t,{headers:headers});return writeAnswerToFile(JSON.parse(n.data.data).answer,"/home/lvxin/work/gerrit/aiot-toolkit/answer.log"),cleanJSON(JSON.parse(n.data.data).answer)}catch(n){console.error("POST Error:",n.response?n.response.data:n.message)}}const sleep=n=>new Promise((e=>setTimeout(e,n)));function writeAnswerToFile(n,e){fs.writeFile(e,n,{flag:"a"},(n=>{}))}function extractJSON(n){try{var e;const t=null===(e=(n=n.replace(/```/g,"").trim()).match(/{[\s\S]*}/))||void 0===e?void 0:e[0];if(!t)throw new Error("No JSON content found");const i=t.replace(/,\s*}/g,"}").replace(/,\s*]/g,"]");return JSON.parse(i)}catch(n){throw console.error("Error extracting JSON:",n),new Error("Failed to extract valid JSON")}}function cleanJSON(n){try{let e=extractJSON(n);const t=e.page_content;for(const[n,e]of Object.entries(t))t[n]=e.replace(/\\n/g,"\n").replace(/\\"/g,'"').replace(/\\t/g,"\t");let i;return i="string"==typeof e.manifest?JSON.parse(e.manifest.replace(/\\"/g,'"')):e.manifest,{project_name:e.project_name,package_name:e.package_name,page_content:t,manifest:i}}catch(n){return console.error("\nError parsing JSON:",n),null}}function replacePage(n,e,t,i){for(const[n,i]of Object.entries(t)){const t=path.join(e,"src",n,"index.ux");fs.mkdirSync(path.dirname(t),{recursive:!0}),fs.writeFileSync(t,i)}n.icon="/Common/logo.png";const o=path.join(e,"src","manifest.json");fs.mkdirSync(path.dirname(o),{recursive:!0});const a=JSON.stringify(n,null,2);fs.writeFileSync(o,a)}async function ai(n){let e=n.prompt;if(!e){const n=`\n ${chalk.bold.green("快应用智能编程助手\n")}\n ${chalk.cyan("您好!我是快应用智能编程助手,专注于为您创建高质量的快应用项目文件。\n")}\n ${chalk.yellow("您可以试试这样说:")}\n ${chalk.magenta(" 做一个天气快应用")}\n ${chalk.magenta(" 做一个计算器手表快应用")}\n ${chalk.magenta(" 做一个滴答清单手环快应用")}\n `;console.log(n);e=(await inquirer.prompt({type:"input",name:"prompt",message:"请输入您的需求:",prefix:"",validate:n=>n.length>0||"请输入您的需求!"})).prompt}const t=ora({spinner:"dots"});t.start(),setInterval((()=>{}),1e3);const i=await postData(e,n.files);if(!i)return t.fail(chalk.red("生成失败,请重新生成!")),ai(n);let{project_name:o,package_name:a,page_content:r,manifest:c}=i;if(fs.existsSync(path.join(n.cwd||process.cwd(),o))){let e=1,t=o;for(;fs.existsSync(path.join(n.cwd||process.cwd(),t));)t=`${o}_${e++}`;o=t}console.log(`${chalk.yellow("\n包名:")+a}`),console.log(`${chalk.yellow("\n项目名称:")+o}`);const s=Array.isArray(c.deviceTypeList)&&c.deviceTypeList.length>0?c.deviceTypeList[0]:"phone",l=require("../../lib/commands/init");await l(o,{cwd:n.cwd||process.cwd()});const d=path.join(n.cwd||process.cwd(),o);if(replacePage(c,d,r,o),console.log(`${chalk.yellow("\n项目路径:")+d}`),t.succeed(chalk.green("\n恭喜!您的快应用项目已经创建成功!\n")),!n.test){const n=[{type:"confirm",name:"preview",message:"请问是否进行预览?",prefix:"",default:!0}];inquirer.prompt(n).then((n=>{if(n.preview){if("watch"===s){const n="/home/lvxin/work/gitlab/ai-quickapp/velasim";fsExtra.copySync(n,path.join(d,"node_modules/@aiot-toolkit/velasim"));const{compile:e}=require("../../lib/commands/compile");return void e("native","dev",!0,{cwd:d,openNuttx:!0})}const{launchServer:n}=require("@aiot-toolkit/server"),{compile:e}=require("../../lib/commands/compile");n({watch:!0,cwd:d,openBrowser:!0}),e("native","dev",!0,{cwd:d})}else console.log(`${chalk.green("\n您可以使用以下命令进行开发预览调试:")}`),console.log(`${chalk.cyan(" npm run start")}`),console.log(`${chalk.cyan(" npm run build")}`),console.log(`${chalk.cyan(" npm run watch")}`)}))}return{projectPath:path.join(n.cwd||process.cwd(),o),projectName:o,packageName:a,router:c.router.entry,deviceType:s}}module.exports=ai;
|
|
1
|
+
"use strict";const ora=require("ora"),chalk=require("chalk"),inquirer=require("inquirer"),axios=require("axios"),fs=require("fs"),fsExtra=require("fs-extra"),path=require("path"),{repairJson:repairJson,loads:loads}=require("json-repair-js"),DIFY_API_BASE_URL="https://service.mify.mioffice.cn",API_PATH="/api/v1/chat-messages",API_KEY="app-NKy1uQeBGzXViy9BYUJ9LPzU",headers={Authorization:`Bearer ${API_KEY}`,"Content-Type":"application/json"},mockData={project_name:"WeatherApp",package_name:"com.example.weatherapp",page_content:{home:'<template>\n <div class="page">\n <div class="header">\n <text class="title">天气预报</text>\n </div>\n <div class="location-bar">\n <text class="location-text">{{locationName}}</text>\n <input type="button" class="location-btn" value="切换城市" onclick="switchCity" />\n </div>\n <div class="current-weather">\n <text class="temp">{{currentTemp}}°</text>\n <text class="weather-desc">{{weatherDesc}}</text>\n <text class="high-low">{{lowTemp}}° / {{highTemp}}°</text>\n </div>\n <div class="weather-detail">\n <div class="detail-item">\n <text class="detail-label">湿度</text>\n <text class="detail-value">{{humidity}}%</text>\n </div>\n <div class="detail-item">\n <text class="detail-label">风力</text>\n <text class="detail-value">{{windLevel}}</text>\n </div>\n <div class="detail-item">\n <text class="detail-label">气压</text>\n <text class="detail-value">{{pressure}}hPa</text>\n </div>\n </div>\n <text class="forecast-title">未来天气预报</text>\n <list class="forecast-list">\n <list-item type="forecast" for="{{forecastData}}" class="forecast-item">\n <text class="day">{{$item.day}}</text>\n <text class="forecast-temp">{{$item.lowTemp}}° / {{$item.highTemp}}°</text>\n <text class="forecast-desc">{{$item.desc}}</text>\n </list-item>\n </list>\n <div class="footer">\n <input type="button" class="refresh-btn" value="刷新" onclick="refreshWeather" />\n <input type="button" class="settings-btn" value="设置" onclick="goToSettings" />\n </div>\n </div>\n</template>\n\n<style>\n .page {\n flex-direction: column;\n background-color: #f5f5f5;\n width: 100%;\n }\n .header {\n height: 120px;\n width: 100%;\n background-color: #2196f3;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n }\n .title {\n font-size: 40px;\n color: #ffffff;\n font-weight: bold;\n }\n .location-bar {\n padding: 20px;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n background-color: #ffffff;\n margin: 10px 0;\n }\n .location-text {\n font-size: 34px;\n color: #333333;\n font-weight: bold;\n }\n .location-btn {\n background-color: #2196f3;\n color: #ffffff;\n font-size: 28px;\n padding: 10px 20px;\n border-radius: 4px;\n }\n .current-weather {\n padding: 40px;\n background-color: #ffffff;\n flex-direction: column;\n align-items: center;\n margin-bottom: 10px;\n }\n .temp {\n font-size: 90px;\n color: #333333;\n font-weight: bold;\n }\n .weather-desc {\n font-size: 34px;\n color: #666666;\n margin: 10px 0;\n }\n .high-low {\n font-size: 30px;\n color: #888888;\n }\n .weather-detail {\n flex-direction: row;\n justify-content: space-around;\n background-color: #ffffff;\n padding: 20px;\n margin-bottom: 10px;\n }\n .detail-item {\n flex-direction: column;\n align-items: center;\n }\n .detail-label {\n font-size: 28px;\n color: #888888;\n margin-bottom: 10px;\n }\n .detail-value {\n font-size: 32px;\n color: #333333;\n font-weight: bold;\n }\n .forecast-title {\n font-size: 34px;\n color: #333333;\n font-weight: bold;\n margin: 20px;\n }\n .forecast-list {\n background-color: #ffffff;\n padding: 10px 0;\n }\n .forecast-item {\n height: 100px;\n flex-direction: row;\n align-items: center;\n justify-content: space-between;\n padding: 0 20px;\n border-bottom-width: 1px;\n border-bottom-color: #eeeeee;\n }\n .day {\n font-size: 30px;\n color: #333333;\n width: 100px;\n }\n .forecast-temp {\n font-size: 28px;\n color: #666666;\n }\n .forecast-desc {\n font-size: 28px;\n color: #888888;\n width: 120px;\n text-align: right;\n }\n .footer {\n flex-direction: row;\n justify-content: center;\n margin-top: 20px;\n margin-bottom: 20px;\n }\n .refresh-btn, .settings-btn {\n background-color: #2196f3;\n color: #ffffff;\n font-size: 28px;\n padding: 10px 30px;\n border-radius: 4px;\n margin: 0 10px;\n }\n</style>\n\n<script>\n export default {\n data: {\n locationName: \'北京\',\n currentTemp: 25,\n weatherDesc: \'晴\',\n lowTemp: 20,\n highTemp: 30,\n humidity: 45,\n windLevel: \'3级\',\n pressure: 1013,\n forecastData: [\n { day: \'明天\', lowTemp: 19, highTemp: 28, desc: \'多云\' },\n { day: \'后天\', lowTemp: 18, highTemp: 27, desc: \'小雨\' },\n { day: \'周三\', lowTemp: 16, highTemp: 24, desc: \'阵雨\' },\n { day: \'周四\', lowTemp: 15, highTemp: 26, desc: \'晴\' },\n { day: \'周五\', lowTemp: 17, highTemp: 28, desc: \'晴\' }\n ]\n },\n onInit() {\n this.getWeatherData()\n },\n getWeatherData() {\n // 在实际项目中,这里应该调用天气API获取真实的数据\n console.log(\'Getting weather data...\')\n // 模拟网络请求延迟\n setTimeout(() => {\n console.log(\'Weather data updated\')\n }, 1000)\n },\n switchCity() {\n // 跳转到城市选择页面\n this.$router.push({\n uri: \'city\'\n })\n },\n refreshWeather() {\n this.getWeatherData()\n },\n goToSettings() {\n // 跳转到设置页面\n this.$router.push({\n uri: \'settings\'\n })\n }\n }\n<\/script>',city:'<template>\n <div class="page">\n <div class="header">\n <text class="title">选择城市</text>\n </div>\n <div class="search-bar">\n <input type="text" class="search-input" placeholder="搜索城市" onchange="onSearch" />\n </div>\n <div class="hot-cities">\n <text class="section-title">热门城市</text>\n <div class="city-grid">\n <div class="city-item" for="{{hotCities}}" onclick="selectCity($item)">\n <text class="city-name">{{$item.name}}</text>\n </div>\n </div>\n </div>\n <list class="city-list">\n <list-item type="city" for="{{cityGroups}}" class="city-group">\n <text class="group-title">{{$item.initial}}</text>\n <div class="cities">\n <div class="city-row" for="{{$item.cities}}" onclick="selectCity($item)">\n <text class="city-name">{{$item.name}}</text>\n </div>\n </div>\n </list-item>\n </list>\n <div class="footer">\n <input type="button" class="back-btn" value="返回" onclick="goBack" />\n </div>\n </div>\n</template>\n\n<style>\n .page {\n flex-direction: column;\n background-color: #f5f5f5;\n width: 100%;\n }\n .header {\n height: 100px;\n width: 100%;\n background-color: #2196f3;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n }\n .title {\n font-size: 36px;\n color: #ffffff;\n font-weight: bold;\n }\n .search-bar {\n padding: 20px;\n background-color: #ffffff;\n margin-bottom: 10px;\n }\n .search-input {\n width: 100%;\n height: 80px;\n border: 1px solid #dddddd;\n border-radius: 4px;\n font-size: 30px;\n padding: 0 20px;\n }\n .hot-cities {\n background-color: #ffffff;\n padding: 20px;\n margin-bottom: 10px;\n }\n .section-title {\n font-size: 32px;\n color: #333333;\n font-weight: bold;\n margin-bottom: 20px;\n }\n .city-grid {\n flex-direction: row;\n flex-wrap: wrap;\n }\n .city-item {\n width: 23%;\n height: 80px;\n background-color: #f5f5f5;\n margin: 1%;\n justify-content: center;\n align-items: center;\n border-radius: 4px;\n }\n .city-name {\n font-size: 28px;\n color: #333333;\n }\n .city-list {\n background-color: #ffffff;\n flex: 1;\n }\n .city-group {\n flex-direction: column;\n }\n .group-title {\n font-size: 30px;\n color: #2196f3;\n background-color: #f5f5f5;\n padding: 10px 20px;\n }\n .cities {\n flex-direction: column;\n }\n .city-row {\n height: 90px;\n padding: 0 20px;\n justify-content: flex-start;\n align-items: center;\n border-bottom-width: 1px;\n border-bottom-color: #eeeeee;\n }\n .footer {\n padding: 20px;\n justify-content: center;\n }\n .back-btn {\n background-color: #2196f3;\n color: #ffffff;\n font-size: 30px;\n padding: 10px 40px;\n border-radius: 4px;\n }\n</style>\n\n<script>\n export default {\n data: {\n searchText: \'\',\n hotCities: [\n { id: 1, name: \'北京\' },\n { id: 2, name: \'上海\' },\n { id: 3, name: \'广州\' },\n { id: 4, name: \'深圳\' },\n { id: 5, name: \'杭州\' },\n { id: 6, name: \'南京\' },\n { id: 7, name: \'武汉\' },\n { id: 8, name: \'成都\' }\n ],\n cityGroups: [\n {\n initial: \'A\',\n cities: [\n { id: 101, name: \'安庆\' },\n { id: 102, name: \'鞍山\' }\n ]\n },\n {\n initial: \'B\',\n cities: [\n { id: 1, name: \'北京\' },\n { id: 201, name: \'保定\' },\n { id: 202, name: \'宝鸡\' }\n ]\n },\n {\n initial: \'C\',\n cities: [\n { id: 301, name: \'长沙\' },\n { id: 302, name: \'长春\' },\n { id: 8, name: \'成都\' }\n ]\n },\n {\n initial: \'G\',\n cities: [\n { id: 3, name: \'广州\' },\n { id: 401, name: \'贵阳\' }\n ]\n }\n ]\n },\n onSearch(e) {\n this.searchText = e.value\n // 在实际项目中,这里应该根据搜索文本过滤城市列表\n console.log(\'Search text:\', this.searchText)\n },\n selectCity(city) {\n // 选择城市后返回主页并更新城市\n this.$router.back({\n params: {\n city: city\n }\n })\n },\n goBack() {\n this.$router.back()\n }\n }\n<\/script>',settings:'<template>\n <div class="page">\n <div class="header">\n <text class="title">设置</text>\n </div>\n <list class="settings-list">\n <list-item type="setting" class="setting-item">\n <text class="setting-label">温度单位</text>\n <div class="unit-toggle">\n <div class="unit-option {{tempUnit === \'c\' ? \'active\' : \'\'}}" onclick="setTempUnit(\'c\')">\n <text class="unit-text {{tempUnit === \'c\' ? \'active-text\' : \'\'}}">°C</text>\n </div>\n <div class="unit-option {{tempUnit === \'f\' ? \'active\' : \'\'}}" onclick="setTempUnit(\'f\')">\n <text class="unit-text {{tempUnit === \'f\' ? \'active-text\' : \'\'}}">°F</text>\n </div>\n </div>\n </list-item>\n <list-item type="setting" class="setting-item">\n <text class="setting-label">自动更新</text>\n <switch class="setting-switch" checked="{{autoUpdate}}" onchange="toggleAutoUpdate"></switch>\n </list-item>\n <list-item type="setting" class="setting-item">\n <text class="setting-label">更新频率</text>\n <div class="frequency-select">\n <text class="frequency-value">{{updateFrequency}}分钟</text>\n <div class="frequency-buttons">\n <input type="button" class="frequency-btn" value="-" onclick="decreaseFrequency" />\n <input type="button" class="frequency-btn" value="+" onclick="increaseFrequency" />\n </div>\n </div>\n </list-item>\n <list-item type="setting" class="setting-item">\n <text class="setting-label">天气预警通知</text>\n <switch class="setting-switch" checked="{{weatherAlert}}" onchange="toggleWeatherAlert"></switch>\n </list-item>\n <list-item type="setting" class="setting-item">\n <text class="setting-label">背景颜色</text>\n <div class="color-options">\n <div class="color-option {{themeColor === \'blue\' ? \'color-selected\' : \'\'}}" style="background-color: #2196f3;" onclick="setThemeColor(\'blue\')"></div>\n <div class="color-option {{themeColor === \'green\' ? \'color-selected\' : \'\'}}" style="background-color: #4caf50;" onclick="setThemeColor(\'green\')"></div>\n <div class="color-option {{themeColor === \'orange\' ? \'color-selected\' : \'\'}}" style="background-color: #ff9800;" onclick="setThemeColor(\'orange\')"></div>\n <div class="color-option {{themeColor === \'purple\' ? \'color-selected\' : \'\'}}" style="background-color: #9c27b0;" onclick="setThemeColor(\'purple\')"></div>\n </div>\n </list-item>\n </list>\n <div class="footer">\n <input type="button" class="save-btn" value="保存设置" onclick="saveSettings" />\n <input type="button" class="back-btn" value="返回" onclick="goBack" />\n </div>\n </div>\n</template>\n\n<style>\n .page {\n flex-direction: column;\n background-color: #f5f5f5;\n width: 100%;\n }\n .header {\n height: 100px;\n width: 100%;\n background-color: #2196f3;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n }\n .title {\n font-size: 36px;\n color: #ffffff;\n font-weight: bold;\n }\n .settings-list {\n margin-top: 10px;\n background-color: #ffffff;\n }\n .setting-item {\n height: 100px;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n padding: 0 20px;\n border-bottom-width: 1px;\n border-bottom-color: #eeeeee;\n }\n .setting-label {\n font-size: 32px;\n color: #333333;\n }\n .unit-toggle {\n flex-direction: row;\n width: 180px;\n height: 60px;\n border-radius: 30px;\n background-color: #eeeeee;\n overflow: hidden;\n }\n .unit-option {\n flex: 1;\n justify-content: center;\n align-items: center;\n }\n .unit-text {\n font-size: 28px;\n color: #666666;\n }\n .active {\n background-color: #2196f3;\n }\n .active-text {\n color: #ffffff;\n }\n .setting-switch {\n width: 100px;\n }\n .frequency-select {\n flex-direction: row;\n align-items: center;\n }\n .frequency-value {\n font-size: 30px;\n color: #666666;\n margin-right: 20px;\n }\n .frequency-buttons {\n flex-direction: row;\n }\n .frequency-btn {\n width: 60px;\n height: 60px;\n background-color: #2196f3;\n color: #ffffff;\n font-size: 36px;\n border-radius: 30px;\n margin: 0 5px;\n text-align: center;\n }\n .color-options {\n flex-direction: row;\n }\n .color-option {\n width: 50px;\n height: 50px;\n border-radius: 25px;\n margin: 0 5px;\n border: 2px solid transparent;\n }\n .color-selected {\n border-color: #333333;\n }\n .footer {\n flex-direction: row;\n justify-content: center;\n margin-top: 40px;\n margin-bottom: 20px;\n }\n .save-btn, .back-btn {\n background-color: #2196f3;\n color: #ffffff;\n font-size: 30px;\n padding: 10px 30px;\n border-radius: 4px;\n margin: 0 10px;\n }\n</style>\n\n<script>\n export default {\n data: {\n tempUnit: \'c\',\n autoUpdate: true,\n updateFrequency: 30,\n weatherAlert: true,\n themeColor: \'blue\'\n },\n onInit() {\n // 从存储加载设置\n this.loadSettings()\n },\n loadSettings() {\n // 在实际项目中,这里应该从本地存储加载用户设置\n console.log(\'Loading settings...\')\n },\n setTempUnit(unit) {\n this.tempUnit = unit\n },\n toggleAutoUpdate(e) {\n this.autoUpdate = e.checked\n },\n increaseFrequency() {\n if (this.updateFrequency < 120) {\n this.updateFrequency += 15\n }\n },\n decreaseFrequency() {\n if (this.updateFrequency > 15) {\n this.updateFrequency -= 15\n }\n },\n toggleWeatherAlert(e) {\n this.weatherAlert = e.checked\n },\n setThemeColor(color) {\n this.themeColor = color\n },\n saveSettings() {\n // 在实际项目中,这里应该将设置保存到本地存储\n console.log(\'Saving settings:\', {\n tempUnit: this.tempUnit,\n autoUpdate: this.autoUpdate,\n updateFrequency: this.updateFrequency,\n weatherAlert: this.weatherAlert,\n themeColor: this.themeColor\n })\n \n // 显示保存成功提示\n this.$app.$def.showToast(\'设置已保存\')\n \n // 返回主页\n setTimeout(() => {\n this.$router.back()\n }, 1500)\n },\n goBack() {\n this.$router.back()\n }\n }\n<\/script>'},manifest:{package:"com.example.weatherapp",name:"WeatherApp",versionName:"1.0.0",versionCode:1,minPlatformVersion:1070,icon:"/common/images/logo.png",features:[],permissions:[{origin:"*"}],config:{logLevel:"debug",designWidth:750},router:{entry:"home",pages:{home:{component:"index"},city:{component:"index"},settings:{component:"index"}}},display:{titleBarBackgroundColor:"#2196f3",titleBarTextColor:"#ffffff",menu:!0,pages:{home:{titleBarText:"天气预报",menu:!1},city:{titleBarText:"选择城市"},settings:{titleBarText:"设置"}}}}},mockFiles=[{id:"cbb08670-6e8d-4230-9d04-9d1206b928ba",name:"Cyber_User.png",size:562298,extension:"png",mime_type:"image/png",created_by:"be6afaf3-63ef-42b3-9137-84b326c29e73",created_at:1746777496},{id:"e8d2827e-318b-4885-9def-3abf39af3cb2",name:"拍照解题-手机解题快应用.pdf",size:502150,extension:"pdf",mime_type:"application/pdf",created_by:"be6afaf3-63ef-42b3-9137-84b326c29e73",created_at:1746777522}],postDataParams={inputs:{image:[{type:"image",transfer_method:"local_file",upload_file_id:"b3c5bee5-3a1a-4ec3-83c6-5d50f8ea8430"},{type:"image",transfer_method:"local_file",upload_file_id:"983603f3-341b-436a-8457-f2c81b708b1e"}]},response_mode:"blocking",conversation_id:"",user:"test",query:"query",files:[{type:"document",transfer_method:"local_file",upload_file_id:"ce9680ab-bf48-453e-87d2-05c0a57441e6"}]};function convertToJsonArray(n){return n.split(",").map((n=>{const[e,t]=n.split(":");return{[e]:t}}))}async function postData(n,e){const t={inputs:{image:[]},response_mode:"blocking",conversation_id:"",user:"aiot-toolkit",query:n,files:[]};if(e&&e.length>1){convertToJsonArray(e).forEach((n=>{const e=Object.keys(n)[0],i=n[e];e.startsWith("image/")&&t.inputs.image.push({type:"image",transfer_method:"local_file",upload_file_id:i}),e.startsWith("application/")&&t.files.push({type:"document",transfer_method:"local_file",upload_file_id:i})})),t.user="IDE"}try{const n=await axios.post(`${DIFY_API_BASE_URL+API_PATH}`,t,{headers:headers});return writeAnswerToFile(n.data.answer,"/home/lvxin/work/gerrit/aiot-toolkit/answer.log"),cleanJSON(n.data.answer)}catch(n){console.error("POST Error:",n.response?n.response.data:n.message)}}const sleep=n=>new Promise((e=>setTimeout(e,n)));function writeAnswerToFile(n,e){fs.writeFile(e,n,{flag:"a"},(n=>{}))}function extractJSON(n){try{var e;const t=null===(e=(n=n.replace(/```/g,"").trim()).match(/{[\s\S]*}/))||void 0===e?void 0:e[0];if(!t)throw new Error("No JSON content found");const i=t.replace(/,\s*}/g,"}").replace(/,\s*]/g,"]");return JSON.parse(i)}catch(n){throw console.error("Error extracting JSON:",n),new Error("Failed to extract valid JSON")}}function cleanJSON(n){try{let e=extractJSON(n);const t=e.page_content;for(const[n,e]of Object.entries(t))t[n]=e.replace(/\\n/g,"\n").replace(/\\"/g,'"').replace(/\\t/g,"\t");let i;return i="string"==typeof e.manifest?JSON.parse(e.manifest.replace(/\\"/g,'"')):e.manifest,{project_name:e.project_name,package_name:e.package_name,page_content:t,manifest:i}}catch(n){return console.error("\nError parsing JSON:",n),null}}function replacePage(n,e,t,i){for(const[n,i]of Object.entries(t)){const t=path.join(e,"src",n,"index.ux");fs.mkdirSync(path.dirname(t),{recursive:!0}),fs.writeFileSync(t,i)}n.icon="/Common/logo.png";const o=path.join(e,"src","manifest.json");fs.mkdirSync(path.dirname(o),{recursive:!0});const a=JSON.stringify(n,null,2);fs.writeFileSync(o,a)}async function ai(n){let e=n.prompt;if(!e){const n=`\n ${chalk.bold.green("快应用智能编程助手\n")}\n ${chalk.cyan("您好!我是快应用智能编程助手,专注于为您创建高质量的快应用项目文件。\n")}\n ${chalk.yellow("您可以试试这样说:")}\n ${chalk.magenta(" 做一个小米股票4*4卡片")}\n ${chalk.magenta(" 做一个北京天气2*2卡片")}\n ${chalk.magenta(" 做一个新闻资讯4*4卡片")}\n `;console.log(n);e=(await inquirer.prompt({type:"input",name:"prompt",message:"请输入您的需求:",prefix:"",validate:n=>n.length>0||"请输入您的需求!"})).prompt}let t=1;const i=ora({text:chalk.cyan(`\n生成中... ${chalk.green(t)}s \n`),spinner:"dots"});i.start(),setInterval((()=>{i.text=chalk.cyan(`\n生成中... ${chalk.green(t++)}s`)}),1e3);const o=await postData(e,n.files);if(!o){if(n.retryCount){if(n.retryCount>=3)return i.fail(chalk.red("生成失败次数过多,请检查您的需求描述后重试!")),null;n.retryCount++}else n.retryCount=1;return i.fail(chalk.red(`生成失败,正在进行第 ${n.retryCount} 次重试...`)),ai(n)}let{project_name:a,package_name:r,page_content:c,manifest:s}=o;if(fs.existsSync(path.join(n.cwd||process.cwd(),a))){let e=1,t=a;for(;fs.existsSync(path.join(n.cwd||process.cwd(),t));)t=`${a}_${e++}`;a=t}console.log(`${chalk.yellow("\n包名:")+r}`),console.log(`${chalk.yellow("\n项目名称:")+a}`);const l=Array.isArray(s.deviceTypeList)&&s.deviceTypeList.length>0?s.deviceTypeList[0]:"phone",d=require("../../lib/commands/init");await d(a,{cwd:n.cwd||process.cwd()});const p=path.join(n.cwd||process.cwd(),a);if(replacePage(s,p,c,a),console.log(`${chalk.yellow("\n项目路径:")+p}`),i.succeed(chalk.green("\n恭喜!您的快应用卡片项目已经创建成功!\n")),!n.test){const n=[{type:"confirm",name:"preview",message:"请问是否进行预览?",prefix:"",default:!0}];inquirer.prompt(n).then((n=>{if(n.preview){if("watch"===l){const n="/home/lvxin/work/gitlab/ai-quickapp/velasim";fsExtra.copySync(n,path.join(p,"node_modules/@aiot-toolkit/velasim"));const{compile:e}=require("../../lib/commands/compile");return void e("native","dev",!0,{cwd:p,openNuttx:!0})}const{launchServer:n}=require("@aiot-toolkit/server"),{compile:e}=require("../../lib/commands/compile");n({watch:!0,cwd:p,openBrowser:!0}),e("native","dev",!0,{cwd:p})}else console.log(`${chalk.green("\n您可以使用以下命令进行开发预览调试:")}`),console.log(`${chalk.cyan(" npm run start")}`),console.log(`${chalk.cyan(" npm run build")}`),console.log(`${chalk.cyan(" npm run watch")}`)}))}return{projectPath:path.join(n.cwd||process.cwd(),a),projectName:a,packageName:r,router:s.router.entry,deviceType:l}}module.exports=ai;
|
|
2
2
|
//# sourceMappingURL=ai.js.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";const ora=require("ora"),chalk=require("chalk"),puppeteer=require("puppeteer"),path=require("path"),crypto=require("crypto");function generateId(){return crypto.randomBytes(16).toString("hex")}function wait(e){return new Promise((o=>setTimeout(o,e)))}async function chrome(e,o={}){return o.interactive||!e?interactiveMode(o):singleQuery(e,o)}async function interactiveMode(e){const o=require("readline");console.log(chalk.cyan("\n🤖 Chrome AI 助手 - 交互模式")),console.log(chalk.yellow("输入查询内容,输入 exit 或 quit 退出\n"));const t=ora({text:chalk.cyan("正在启动 Chrome...\n"),spinner:"dots"}).start();let l;try{const a=e.extensionPath||path.join(__dirname,"../../../../aiot-chrome-extension");t.text=chalk.cyan("加载 Chrome 扩展..."),l=await puppeteer.launch({headless:!1,args:[`--disable-extensions-except=${a}`,`--load-extension=${a}`,"--no-sandbox","--disable-setuid-sandbox"]});const c=(await l.pages())[0];await wait(2e3);const n=(await l.targets()).find((e=>"service_worker"===e.type()&&e.url().includes("chrome-extension://")));if(!n)throw new Error("未找到扩展,请确保扩展已正确安装");const r=n.url().split("/")[2];await c.goto(`chrome-extension://${r}/popup.html`),await wait(1e3),t.succeed(chalk.green("✅ Chrome 已启动\n"));const s=o.createInterface({input:process.stdin,output:process.stdout,prompt:chalk.cyan("💬 请输入查询: ")});s.prompt(),s.on("line",(async e=>{const o=e.trim();if(o){"exit"!==o&&"quit"!==o||(console.log(chalk.yellow("\n👋 再见!\n")),s.close(),await l.close(),process.exit(0)),s.pause(),console.log(chalk.cyan("AI 正在思考..."));try{const e=generateId();await c.evaluate(((e,o)=>new Promise((t=>{chrome.storage.local.get(["cliQueries"],(l=>{const a=l.cliQueries||[];a.push({id:e,query:o,timestamp:Date.now()}),chrome.storage.local.set({cliQueries:a},t)}))}))),e,o);let t=null;const l=60;for(let o=0;o<l;o++){await wait(1e3);const o=await c.evaluate((e=>new Promise((o=>{chrome.storage.local.get(["cliResults"],(t=>{const l=t.cliResults||{};o(l[e])}))}))),e);if(o){if(o.error)throw new Error(o.error);t=o.result;break}}if(!t)throw new Error("查询超时");console.log(chalk.green("✅ 完成\n")),console.log(chalk.bold.cyan("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")),console.log(chalk.white(t)),console.log(chalk.bold.cyan("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n")),await c.evaluate((e=>new Promise((o=>{chrome.storage.local.get(["cliResults"],(t=>{const l=t.cliResults||{};delete l[e],chrome.storage.local.set({cliResults:l},o)}))}))),e)}catch(e){console.log(chalk.red("❌ 失败")),console.error(chalk.red(`错误: ${e.message}\n`))}s.resume(),s.prompt()}else s.prompt()}))}catch(e){return t.fail(chalk.red("❌ 启动失败")),console.error(chalk.red(`\n错误: ${e.message}\n`)),l&&await l.close(),null}}async function singleQuery(e,o){if(!e)return console.log(chalk.red("❌ 请提供查询内容")),console.log(chalk.yellow("\n示例:")),console.log(chalk.cyan(' aiot chrome "查询小米股票"')),console.log(chalk.cyan(' aiot chrome "搜索 AI 新闻"')),console.log(chalk.cyan(' aiot chrome "现在几点了"')),console.log(chalk.yellow("\n交互模式:")),console.log(chalk.cyan(" aiot chrome -i")),console.log(chalk.cyan(" aiot chrome --interactive")),void console.log(chalk.yellow("\n提示: 扩展会自动打开并处理查询\n"));const t=ora({text:chalk.cyan("正在启动 Chrome...\n"),spinner:"dots"}).start();let l,a=null;try{const c=generateId(),n=o.extensionPath||path.join(__dirname,"../../../../aiot-chrome-extension");t.text=chalk.cyan("加载 Chrome 扩展..."),l=await puppeteer.launch({headless:!1,args:[`--disable-extensions-except=${n}`,`--load-extension=${n}`,"--no-sandbox","--disable-setuid-sandbox"]});const r=(await l.pages())[0];t.text=chalk.cyan("连接扩展..."),await wait(2e3);const s=(await l.targets()).find((e=>"service_worker"===e.type()&&e.url().includes("chrome-extension://")));if(!s)throw new Error("未找到扩展,请确保扩展已正确安装");const i=s.url().split("/")[2];await r.goto(`chrome-extension://${i}/popup.html`),await wait(1e3),t.text=chalk.cyan("提交查询..."),await r.evaluate(((e,o)=>new Promise((t=>{chrome.storage.local.get(["cliQueries"],(l=>{const a=l.cliQueries||[];a.push({id:e,query:o,timestamp:Date.now()}),chrome.storage.local.set({cliQueries:a},t)}))}))),c,e),t.text=chalk.cyan("等待 AI 响应...");const h=60;for(let e=0;e<h;e++){await wait(1e3);const o=await r.evaluate((e=>new Promise((o=>{chrome.storage.local.get(["cliResults"],(t=>{const l=t.cliResults||{};o(l[e])}))}))),c);if(o){if(o.error)throw new Error(o.error);a=o.result;break}t.text=chalk.cyan(`等待响应... (${e+1}s)`)}if(!a)throw new Error("查询超时,请检查网络连接");return t.succeed(chalk.green("✅ 查询完成!\n")),console.log(chalk.bold.cyan("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━")),console.log(chalk.bold.white("📋 查询结果:")),console.log(chalk.bold.cyan("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n")),console.log(chalk.white(a)),console.log(chalk.bold.cyan("\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n")),await r.evaluate((e=>new Promise((o=>{chrome.storage.local.get(["cliResults"],(t=>{const l=t.cliResults||{};delete l[e],chrome.storage.local.set({cliResults:l},o)}))}))),c),o.keepAlive?console.log(chalk.yellow("浏览器保持打开(--keep-alive 模式)\n")):await l.close(),a}catch(e){return t.fail(chalk.red("❌ 查询失败")),console.error(chalk.red(`\n错误: ${e.message}\n`)),e.message.includes("未找到扩展")&&(console.log(chalk.yellow("请确保:")),console.log(chalk.cyan("1. 扩展已安装到 Chrome")),console.log(chalk.cyan("2. 扩展路径正确")),console.log(chalk.cyan("3. 尝试手动打开扩展一次\n"))),l&&!o.keepAlive&&await l.close(),null}}module.exports=chrome;
|
|
2
|
+
//# sourceMappingURL=chrome.js.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";const path=require("path"),fs=require("fs"),chalk=require("chalk"),{spawn:spawn}=require("child_process"),{randomUUID:randomUUID}=require("crypto"),Koa=require("koa"),Router=require("koa-router"),bodyParser=require("koa-bodyparser"),ai=require("../../lib/commands/ai"),BUILD_DIR_NAME="build";function runCommand(e,r=[],s={}){return new Promise(((t,o)=>{const n=spawn(e,r,{cwd:s.cwd||process.cwd(),env:s.env||process.env,stdio:["ignore","pipe","pipe"]});let a="",i="";n.stdout.on("data",(e=>{a+=e})),n.stderr.on("data",(e=>{i+=e})),n.on("close",(e=>{if(0!==e){const r=new Error(`Command failed with exit code ${e}`);return r.stdout=a,r.stderr=i,void o(r)}t({stdout:a,stderr:i})})),n.on("error",o)}))}function readStockNewsCard(e,r){const s=path.join(e,"build",r),t=path.join(s,"index.template.json"),o=path.join(s,"index.css.json"),n=path.join(s,"index.js");if(!fs.existsSync(t)||!fs.existsSync(o)||!fs.existsSync(n))throw new Error(`${r} 生成失败,缺少必要文件`);const a=JSON.parse(fs.readFileSync(t,"utf-8")),i=JSON.parse(fs.readFileSync(o,"utf-8")),c=fs.readFileSync(n);return{template:a,style:i,script:Buffer.from(c).toString("base64"),data:{},actions:{},cardId:randomUUID(),widgetName:r}}async function handleGenerate(e){const r=process.hrtime.bigint(),{prompt:s}=e.request.body||{};if(!s||"string"!=typeof s)return e.status=400,void(e.body={success:!1,message:"prompt 参数必填"});try{const t=await ai({prompt:s,test:!0}),o=t.projectName||`App_${Date.now()}`,n=t.projectPath||path.join(process.cwd(),o);if(!fs.existsSync(n))throw new Error("项目生成失败");const a=path.join(n,"src","manifest.json");if(!fs.existsSync(a))throw new Error("manifest.json 不存在,无法定位卡片目录");const i=JSON.parse(fs.readFileSync(a,"utf-8")),c=i.router&&i.router.widgets||{},d=Object.keys(c)[0];if(!d)throw new Error("manifest.json 中没有 widgets 配置");await runCommand("npx",["hap","build"],{cwd:n});const u=readStockNewsCard(n,d);e.body={success:!0,message:"卡片生成成功",data:u};const p=Number(process.hrtime.bigint()-r)/1e9;console.log(chalk.green(`卡片 ${d} 生成成功, 用时 ${p.toFixed(2)} 秒!`))}catch(r){console.error("处理失败:",r),e.status=500,e.body={success:!1,message:r.message||"服务器内部错误"}}}function startServer(e=process.env.KOA_SERVICE_PORT||4e3){const r=new Koa,s=new Router;r.use(bodyParser()),s.post("/generate-card",handleGenerate),r.use(s.routes()).use(s.allowedMethods()),r.listen(e,(()=>{console.log(chalk.green(`AIOT Toolkit Koa 服务已启动,端口:${e}`))}))}startServer();
|
|
2
|
+
//# sourceMappingURL=koa.js.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";const http=require("http"),DEFAULT_HOST=process.env.KOA_TEST_HOST||"10.220.190.47",DEFAULT_PORT=Number(process.env.KOA_SERVICE_PORT||4e3),PROMPT=process.argv.slice(2).join(" ")||"hello aiot",payload=JSON.stringify({prompt:PROMPT}),options={hostname:DEFAULT_HOST,port:DEFAULT_PORT,path:"/generate-card",method:"POST",headers:{"Content-Type":"application/json","Content-Length":Buffer.byteLength(payload)}};console.log(`向 http://${DEFAULT_HOST}:${DEFAULT_PORT}/generate-card 发送测试请求...`);const req=http.request(options,(e=>{let o="";e.setEncoding("utf8"),e.on("data",(e=>{o+=e})),e.on("end",(()=>{console.log(`响应状态:${e.statusCode}`);try{const e=JSON.parse(o);console.log("响应内容:",JSON.stringify(e,null,2))}catch(e){console.log("原始响应:",o),console.error("解析响应为 JSON 失败:",e.message)}}))}));req.on("error",(e=>{console.error("请求失败:",e.message)})),req.write(payload),req.end();
|
|
2
|
+
//# sourceMappingURL=koa.test.js.map
|
package/package.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aiot-toolkit",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.1-alpha.0",
|
|
4
4
|
"description": "A command line toolkit for developing Aiot Quick Apps.",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=8.0.0"
|
|
7
7
|
},
|
|
8
8
|
"dependencies": {
|
|
9
|
-
"@aiot-toolkit/compiler": "1.2.
|
|
10
|
-
"@aiot-toolkit/debugger": "1.2.
|
|
11
|
-
"@aiot-toolkit/dsl-vue": "1.2.
|
|
12
|
-
"@aiot-toolkit/dsl-xvm": "1.2.
|
|
9
|
+
"@aiot-toolkit/compiler": "1.2.1-alpha.0",
|
|
10
|
+
"@aiot-toolkit/debugger": "1.2.1-alpha.0",
|
|
11
|
+
"@aiot-toolkit/dsl-vue": "1.2.1-alpha.0",
|
|
12
|
+
"@aiot-toolkit/dsl-xvm": "1.2.1-alpha.0",
|
|
13
13
|
"@aiot-toolkit/emulator": "^2.0.5-beta.13",
|
|
14
|
-
"@aiot-toolkit/packager": "1.2.
|
|
15
|
-
"@aiot-toolkit/server": "1.2.
|
|
16
|
-
"@aiot-toolkit/shared-utils": "1.2.
|
|
14
|
+
"@aiot-toolkit/packager": "1.2.1-alpha.0",
|
|
15
|
+
"@aiot-toolkit/server": "1.2.1-alpha.0",
|
|
16
|
+
"@aiot-toolkit/shared-utils": "1.2.1-alpha.0",
|
|
17
17
|
"@babel/core": "^7.9.6",
|
|
18
18
|
"@babel/plugin-syntax-jsx": "^7.8.3",
|
|
19
19
|
"@babel/preset-env": "^7.9.6",
|
|
@@ -29,7 +29,11 @@
|
|
|
29
29
|
"commander": "~2.14.1",
|
|
30
30
|
"fs-extra": "^7.0.1",
|
|
31
31
|
"inquirer": "^6.5.2",
|
|
32
|
+
"json-repair-js": "^1.0.0",
|
|
32
33
|
"jszip": "^3.4.0",
|
|
34
|
+
"koa": "^3.1.1",
|
|
35
|
+
"koa-bodyparser": "^4.4.1",
|
|
36
|
+
"koa-router": "^14.0.0",
|
|
33
37
|
"lodash": "^4.17.21",
|
|
34
38
|
"ora": "^5.4.1",
|
|
35
39
|
"puppeteer": "^24.6.1",
|
|
@@ -58,5 +62,5 @@
|
|
|
58
62
|
"supertest": "^3.3.0",
|
|
59
63
|
"webpack-cli": "^4.3.0"
|
|
60
64
|
},
|
|
61
|
-
"gitHead": "
|
|
65
|
+
"gitHead": "e0504d9af7f914f3640b36a247d923c94b4725ef"
|
|
62
66
|
}
|
package/CHANGELOG.md
DELETED
|
@@ -1,393 +0,0 @@
|
|
|
1
|
-
# Change Log
|
|
2
|
-
|
|
3
|
-
#### [1.1.4] - 2024-08-30
|
|
4
|
-
|
|
5
|
-
- 增加 `scroll-snap-*` 的值在 css 中支持
|
|
6
|
-
- 增加 `png8` 的图片格式支持
|
|
7
|
-
- 支持 `image` 转换为 `bin` 的功能
|
|
8
|
-
|
|
9
|
-
#### [1.1.3] - 2024-07-24
|
|
10
|
-
|
|
11
|
-
- 优化媒体查询表达式的值
|
|
12
|
-
|
|
13
|
-
#### [1.1.2] - 2024-06-19
|
|
14
|
-
|
|
15
|
-
- 优化 `screen and` 媒体查询的条件
|
|
16
|
-
- 增加 `internal://` 协议的资源在 css 中支持
|
|
17
|
-
- 修改 `global.Env.designWidth` 的值在 velaApp 中
|
|
18
|
-
|
|
19
|
-
#### [1.1.1] - 2024-05-09
|
|
20
|
-
|
|
21
|
-
- 支持 `internal` 绝对文件路径
|
|
22
|
-
- 增加 `process` 的属性 type 值
|
|
23
|
-
- 优化 `style` 的 class 动态值
|
|
24
|
-
- 修复 `optimizeUnusedResource` 配置无效的问题
|
|
25
|
-
|
|
26
|
-
#### [1.1.0] - 2024-01-10
|
|
27
|
-
|
|
28
|
-
- 支持 `enable-e2e` 在 server 模式下
|
|
29
|
-
- 修复 `sourcemap` 丢失的问题
|
|
30
|
-
- 优化 `vela` 自动化测试代码
|
|
31
|
-
|
|
32
|
-
#### [1.0.20] - 2024-01-02
|
|
33
|
-
|
|
34
|
-
- 支持 `services` 配置数组格式
|
|
35
|
-
- 支持媒体查询 `designWidth` 字符串值
|
|
36
|
-
- 支持媒体查询 `device-type` 属性
|
|
37
|
-
- 修复合并用户的 `webpack` 配置使用深层合并的问题
|
|
38
|
-
- 修复 `feature` 未定义时报错的问题
|
|
39
|
-
- 修复分包时 `$app_evaluate$` 未执行的问题
|
|
40
|
-
- 优化 `MEDIA` 放到样式的最后以便生效
|
|
41
|
-
- 优化 `app_require` 使用包裹函数的方式
|
|
42
|
-
|
|
43
|
-
#### [1.0.19] - 2023-10-24
|
|
44
|
-
|
|
45
|
-
- 支持 `protobuf` 二进制版本 css 添加 `object` 值
|
|
46
|
-
- 支持二进制添加 `cdc` 函数
|
|
47
|
-
- 支持远程组件 `remotewidget`
|
|
48
|
-
- 支持 `vela` 项目中 css 的 `@media`
|
|
49
|
-
- 修改 `url` 匹配的写法
|
|
50
|
-
- 修复 `ux` 瘦身,image、css 被意外删除的问题
|
|
51
|
-
- 优化 `image` 的 `src` 属性值
|
|
52
|
-
- 优化动态组件的函数
|
|
53
|
-
- 增加 manifest.json 中的 `minAPILevel`
|
|
54
|
-
|
|
55
|
-
#### [1.0.18] - 2023-08-02
|
|
56
|
-
|
|
57
|
-
- 支持打包 Android 浮窗
|
|
58
|
-
- 支持编译 `jsc` 字节码
|
|
59
|
-
- 支持`Block-static dynamic`
|
|
60
|
-
- 修复中文名称路径的签名问题
|
|
61
|
-
- 修复 `vela` 项目唤起 Android 快应用调试器的问题
|
|
62
|
-
- 优化 `protobuf` 二进制
|
|
63
|
-
- 更新工具版本: `"node": ">=14.0.0"`
|
|
64
|
-
|
|
65
|
-
#### [1.0.17] - 2023-04-26
|
|
66
|
-
|
|
67
|
-
- 支持 `scroll` 组件
|
|
68
|
-
- 支持 `maml` 组件(和`image`组件一致)
|
|
69
|
-
- 修复路径为变量时,未转换成绝对路径的问题
|
|
70
|
-
- `server` 命令新增 `--devtool` 配置参数
|
|
71
|
-
- 增加 `maskRepeat` 属性
|
|
72
|
-
- 增加 CSS 属性 `box-shadow`、`text-shadow` 和 `background-blend-mode`
|
|
73
|
-
|
|
74
|
-
#### [1.0.16] - 2022-12-02
|
|
75
|
-
|
|
76
|
-
- 支持打包应用服务 service 文件
|
|
77
|
-
- 支持元素 `static` 属性的编译优化
|
|
78
|
-
- 支持打包编译`.so`或`.jidl`文件
|
|
79
|
-
- 修复 `src` 属性、行内样式等问题
|
|
80
|
-
- 增加 `maml` 快应用组件配置文件
|
|
81
|
-
- 增加 `enableOpsWrap`与`disableBuildRpk`参数
|
|
82
|
-
|
|
83
|
-
#### [1.0.15] - 2022-08-16
|
|
84
|
-
|
|
85
|
-
- 支持 `vela` 项目 --enable-custom-component 参数
|
|
86
|
-
- 修复 `installdbg` 命令无法使用的问题
|
|
87
|
-
- 增加供 ide 使用的安装调试工具 APK 函数
|
|
88
|
-
- 增加 build 文件夹中的 `META-INF` 文件
|
|
89
|
-
|
|
90
|
-
#### [1.0.14] - 2022-06-22
|
|
91
|
-
|
|
92
|
-
- 修复 `vela` 项目 for 列表 tid 属性错误的问题
|
|
93
|
-
|
|
94
|
-
#### [1.0.13] - 2022-06-15
|
|
95
|
-
|
|
96
|
-
- 支持 `vela` 项目的全局样式
|
|
97
|
-
- 支持 `vela` 项目 --enable-ops-wrap、--enable-export-function 参数
|
|
98
|
-
- 重构 `vela` 项目的编译时函数
|
|
99
|
-
- 修复 `vela` 项目 for、if 属性丢失等问题
|
|
100
|
-
- 增加 `vela` 项目 jsc 转译功能
|
|
101
|
-
|
|
102
|
-
#### [1.0.12] - 2022-03-23
|
|
103
|
-
|
|
104
|
-
- 支持 `vela` 项目中事件参数可以加上{{}}
|
|
105
|
-
- 修复 `vela` 项目 this 文本转换问题
|
|
106
|
-
- 增加 `vela` 项目 qrcode 标签
|
|
107
|
-
|
|
108
|
-
#### [1.0.11] - 2022-02-09
|
|
109
|
-
|
|
110
|
-
- 支持 `vela` 项目分离文件中可以 import 文件
|
|
111
|
-
- 修复 `vela` 项目热更新的问题
|
|
112
|
-
- 增加 `vela` 项目基础模板
|
|
113
|
-
|
|
114
|
-
#### [1.0.10] - 2021-11-30
|
|
115
|
-
|
|
116
|
-
- 支持 `vela` 项目 template、js、css 分开编译
|
|
117
|
-
- 修复 `H5` 项目监听 manifest 文件位置错误的问题
|
|
118
|
-
- 增加 `aiot-toolkit` 项目的测试用例
|
|
119
|
-
|
|
120
|
-
#### [1.0.9] - 2021-10-29
|
|
121
|
-
|
|
122
|
-
- 支持 `vela` 项目编译时可带参数自启动 `nuttx` 模拟器
|
|
123
|
-
- 修复 `vela` 模板中 for 编译错误的问题
|
|
124
|
-
|
|
125
|
-
#### [1.0.8] - 2021-09-27
|
|
126
|
-
|
|
127
|
-
- 支持 `vela` 项目 color 值带 alpha 通道的十六进制,如: `#fffa`、`#ff0011aa`
|
|
128
|
-
- 增加 `vela` 项目的自动化测试
|
|
129
|
-
- 增加 `vela` 项目的热更新
|
|
130
|
-
- 修复 `H5` 项目中多级目录复制文件错误的问题
|
|
131
|
-
|
|
132
|
-
#### [1.0.7] - 2021-08-24
|
|
133
|
-
|
|
134
|
-
- `progress` 组件支持 `radius` 等样式
|
|
135
|
-
|
|
136
|
-
#### [1.0.6] - 2021-07-05
|
|
137
|
-
|
|
138
|
-
- 修复 `vela` 项目中属性 `@KEYFRAMES` 丢失的问题
|
|
139
|
-
- 支持 `vela` 项目的原生组件 `chart`
|
|
140
|
-
- 更新 H5 项目模板默认全屏处理
|
|
141
|
-
|
|
142
|
-
#### [1.0.5] - 2021-06-23
|
|
143
|
-
|
|
144
|
-
- 更新 H5 项目模板
|
|
145
|
-
|
|
146
|
-
#### [1.0.4] - 2021-06-17
|
|
147
|
-
|
|
148
|
-
- `vela` 应用中支持 `@keyframes` 样式
|
|
149
|
-
|
|
150
|
-
#### [1.0.3] - 2021-06-16
|
|
151
|
-
|
|
152
|
-
- 新增 `vela` 应用中 `progress` 组件的 `type` 属性支持 `arc` 值
|
|
153
|
-
|
|
154
|
-
#### [1.0.2] - 2021-06-08
|
|
155
|
-
|
|
156
|
-
- 新增 `aiot packages` 子命令,可独立打包快应用项目 build 结果为一个 rpk
|
|
157
|
-
- 更新 H5 项目模板
|
|
158
|
-
|
|
159
|
-
## [1.0.1] - 2021-05-20
|
|
160
|
-
|
|
161
|
-
- 增加 vela 项目的模拟器 velasim,可直接在模拟器里预览
|
|
162
|
-
|
|
163
|
-
## [1.0.0] - 2021-05-14
|
|
164
|
-
|
|
165
|
-
- 增加 vela 项目模板及编译打包能力
|
|
166
|
-
- 增加 H5 项目模板及编译打包能力
|
|
167
|
-
- 替换工具编译日志输出为英语
|
|
168
|
-
- 替换 4096 新证书
|
|
169
|
-
- 新增 shortcut-button、share-button 组件
|
|
170
|
-
- 自定义标签覆盖系统标签时不需要按系统标签的规则检查
|
|
171
|
-
- 解决 emitWarning 抛出的警告没有打印出来的问题
|
|
172
|
-
- webpack5 动态 import 兼容
|
|
173
|
-
- webpack5 固定版本号为 5.24.0
|
|
174
|
-
- 解决 require.context 引入,分包打包报错问题
|
|
175
|
-
- 增加 video 组件播放倍速设置功能
|
|
176
|
-
- 支持双向绑定
|
|
177
|
-
- input 新增 eventbutton 类型
|
|
178
|
-
- 优化 lottie 配置文件读取
|
|
179
|
-
- 不对 minPlatformVersion 配置进行强制修改
|
|
180
|
-
- 修改初始模板配置
|
|
181
|
-
- 1090 新增组件
|
|
182
|
-
- 适配 webpack5 打包
|
|
183
|
-
- 修复 alt 属性打包错误
|
|
184
|
-
- 增删页面修改 webpack 入口
|
|
185
|
-
- 新增 slideview 组件
|
|
186
|
-
- 新增 section-list 组件
|
|
187
|
-
- 新增 trimDotnine 参数,可在 quickapp.config.js 中增加是否对.9 图进行 aapt 处理的参数
|
|
188
|
-
- 新增 transition 动画
|
|
189
|
-
- 动画组件增加 animation-direction 属性
|
|
190
|
-
- 跟踪上报调试流程
|
|
191
|
-
- list 组件增加 focusbehavior 属性及 selected 事件
|
|
192
|
-
- 增加 manifest.json 内容校验
|
|
193
|
-
- css 新增 filter 属性, 支持 blur 模糊滤镜
|
|
194
|
-
- 添加 alt-object-fit 样式
|
|
195
|
-
- 添加打包来源及其他数据埋点文件
|
|
196
|
-
- 修复默认新建工程 menu:true,导致 menubar 面板无法显示
|
|
197
|
-
- 动态导入 js,提示用户需增加打包参数
|
|
198
|
-
- 修复了 1080 部分编译报错的提示
|
|
199
|
-
- 预览页面优化
|
|
200
|
-
- 兼容`<style lang="scss">`情况
|
|
201
|
-
- 修复运行时报错 $app_define_wrap$不存在的问题
|
|
202
|
-
- 修复在分包时动态引入 js 的报错
|
|
203
|
-
- 移除模板中的 babel.config.js 文件,兼容自定义 babel.config.js 文件
|
|
204
|
-
- 加入多平台适配文件的默认模板
|
|
205
|
-
- 增加编译动态引入 js 文件的能力,即开发者可以使用 import().then()的方式引入 js 文件
|
|
206
|
-
- 将 app.ux 引入的公共组件单独抽离到 app-chunks.json 中,不影响 app.js 体积
|
|
207
|
-
- 优化部分报错信息
|
|
208
|
-
- 非文本组件包含文本给出 warning 提示
|
|
209
|
-
- toolkit 改造适配多终端。aiot init 命令加入 -d --device [device-type-list]选项,指定项目运行的设备类型,device-type-list 为字符串,以逗号连接,如 "tv,phone,car"
|
|
210
|
-
- 支持编译全局公共组件 -修复 adb 调试下模拟器无法连接到正确的调试器地址的问题
|
|
211
|
-
- 新增动态存在大写的组件名编译警告提示
|
|
212
|
-
- 去除不必要的编译提示
|
|
213
|
-
- 编译工具支持 dp 单位的编译
|
|
214
|
-
- 优化编译工具代码,提高编译工具的性能
|
|
215
|
-
- 新增 toolkit 增加在快应用注入输出 log 的能力
|
|
216
|
-
- 修复 watch 模式下修改 manifest.json 退出中断的问题
|
|
217
|
-
- 重构 debugger 模块的目录结构
|
|
218
|
-
- 重构 devtools 模块
|
|
219
|
-
- 修复部分标签样式的校验规则
|
|
220
|
-
- 增加了项目编译时禁止对 rpk/rpks 文件进行签名的能力
|
|
221
|
-
- 增加项目重新签名的能力,新增命令行 resign
|
|
222
|
-
- 打包文件添加 sitemap.json 文件,提供快应用被搜索引擎检索的能力
|
|
223
|
-
- 完成了调试器界面的优化与更新
|
|
224
|
-
- 增加 lint 能力,开发者可以使用 eslint 模块对项目进行校验和格式化
|
|
225
|
-
- richtext 组件增加 start 和 complete 事件的校验
|
|
226
|
-
- progress 增加 layer-color 样式校验
|
|
227
|
-
- list 增加 layout-type 样式校验
|
|
228
|
-
- 增加元素夜间模式 forcedark 参数校验
|
|
229
|
-
- 修复公共 js 抽取的 bug
|
|
230
|
-
- 修复调试器在 chrome v61 版本下报错的问题
|
|
231
|
-
- 修复 background 渐变样式格式化无法正确展示的问题
|
|
232
|
-
- 修复 packager 包启动 server 时,代码覆盖率接口出现报错的问题
|
|
233
|
-
- 修复快应用 vue 项目的部分 bug
|
|
234
|
-
- 修复编译工具启用 enable-e2e 时输出变量或者函数返回,无法进行测试的 bug
|
|
235
|
-
- 支持抽取公共 js 文件的能力,使用方法为编译选项设置--split-chunks-mode <value>;默认不启动,value 为 smart 时启动该能力
|
|
236
|
-
- 重构初始化项目模板
|
|
237
|
-
- 修复调试器在 chrome66 版本以下无法调试问题
|
|
238
|
-
- 增加 mediaquery 支持 prefers-color-scheme 编译功能
|
|
239
|
-
- toolkit 配置统一使用 quickapp.config.js,兼容 hap.config.js
|
|
240
|
-
- 增加预览版的编译模式
|
|
241
|
-
- hap.config.js 支持 webpack、cli 字段。webpack 字段对应的对象与目前 hap.config.js 文件输出对象相同;cli 可以设置命令行参数,该对象会与全局的命令行对象合并。
|
|
242
|
-
- 样式元信息从@meta 改为@info
|
|
243
|
-
- 修复流式加载顺序的问题
|
|
244
|
-
- 修复 chrome66 以上版本的调试器不兼容问题
|
|
245
|
-
- 修复打包出的 css.json 在非样式抽取模式下添加 meta 信息的问题
|
|
246
|
-
- 移除环境变量中 NODE_TEST 标识,使用命令行参数传递
|
|
247
|
-
- 增加 ux 项目提取公共 css 样式的能力
|
|
248
|
-
- 更新对 animation 样式校验
|
|
249
|
-
- 增加快应用项目的 e2e 测试能力
|
|
250
|
-
- 修复了 1060 部分编译报错的提示
|
|
251
|
-
- 增加测试 ux 项目的代码覆盖率的能力
|
|
252
|
-
- toolkit 支持字体颜色 auto|transparent|currentColor 的编译
|
|
253
|
-
- 兼容 android 10 以上版本的 USB 调试功能
|
|
254
|
-
- 修复获取不到设备信息时的 localWsPort 报错问题
|
|
255
|
-
- 增加非独立包非 base 包不打入 i18n 文件的能力
|
|
256
|
-
- 增加分包可以配置独立的 icon 的能力
|
|
257
|
-
- 增加支持 component 节点的编译能力
|
|
258
|
-
- 修复 0.6.4 预览页面问题
|
|
259
|
-
- 增加说明:针对 sourcemap 定位不准确的问题,请在命令行中添加`--match-sourcemap`选项
|
|
260
|
-
- 完善了快应用自定义配置的能力。开发者可以通过在项目根目录下配置 hap.config.js 文件定制 toolkit。目前开放了 resolve/module/plugins 三个字段
|
|
261
|
-
- 修复了 release 包下 sourcemap 定位不准确的问题
|
|
262
|
-
- 更新了 dsl 包的依赖
|
|
263
|
-
- 添加 vue-dsl 移除空白文本节点的能力
|
|
264
|
-
- 完善 ux-loader,可以添加 enforce 字段增强 loader
|
|
265
|
-
- 增加了流式加载适配多语言配置的能力
|
|
266
|
-
- 支持地图组件展示自定义 View 的能力
|
|
267
|
-
- 更新预览的 web.js 文件
|
|
268
|
-
- 增加了对多语言包打包的能力
|
|
269
|
-
- 补充了 1050 部分功能校验: 1.通用 resize 事件 2.slider 的 block-color 样式 3.map 的 polygons 属性和 poitap 事件 4.system 的 resident 接口和 service 的 ad、health、exchange 接口
|
|
270
|
-
- 修复`{{}}`内文本带有/img/修饰符的正则表达式不生效的问题
|
|
271
|
-
- 修复 vue-dsl 使用 less 语法 validate 校验错误的问题
|
|
272
|
-
- 调试器 支持`chrome[google-chrome]`浏览器和`chromium[chromium-browser]`浏览器
|
|
273
|
-
- 修复预览命令时报的路径错误
|
|
274
|
-
- 修改 build 模式默认 sourcemap 选项 devtool 为 cheap-module-eval-source-map,如果开发者想还原默认的 sourcemap 行为,可以通过 `-- --devtool source-map`设置
|
|
275
|
-
- 修复 macos 特定版本启动问题
|
|
276
|
-
- 修复 font-family 样式字符串带引号的问题
|
|
277
|
-
- 将 vue-dsl 的$app_define$和$app_bootstrap$移至 toolkit
|
|
278
|
-
- 修复 font-face 编译问题
|
|
279
|
-
- 修复构建失败退出进程的问题
|
|
280
|
-
- 修复编译时拷贝文件的匹配问题
|
|
281
|
-
- 解决 template 里字符串模板错乱问题
|
|
282
|
-
- 修复 vue-dsl release 问题
|
|
283
|
-
- 证书私钥缺失时候,错误输出到 webpack
|
|
284
|
-
- 修复 IDE 拷贝图片失败问题
|
|
285
|
-
- 修复 vue-dsl css2json 插件缓存问题
|
|
286
|
-
- 支持 app 全局样式的编译
|
|
287
|
-
- 支持 span 嵌套 span 标签
|
|
288
|
-
- 修复获取 dsl 名称异常的问题
|
|
289
|
-
- 修复内部 spec fragment-loader 路径问题
|
|
290
|
-
- 修复自定义 build 路径时预览报错问题
|
|
291
|
-
- 修复停止 webpack watch 模式,没有同时停止监听 manifest 问题
|
|
292
|
-
- 修复了 manifest 中 minPlatformVersion 为 1040 时 不会转换 ES6 为 ES5 的编译时 JS 报错
|
|
293
|
-
- 支持在项目目录中添加 hap.config.js 自定义配置 webpack module 和 plugins 的能力
|
|
294
|
-
- 修复了 aiot update --force 时 JS 报错的问题
|
|
295
|
-
- 修复了 dsl-vue 编译 css 文件名不正确的问题
|
|
296
|
-
- 添加`--disable-stream-pack`参数用于禁用流式包(`build`,`release`,`watch`命令有效)
|
|
297
|
-
- 支持自定义配置
|
|
298
|
-
- 支持`font-weight`
|
|
299
|
-
- 优化命令交互
|
|
300
|
-
- 监听模式现在会监听`manifest.json`文件
|
|
301
|
-
- 修复若干问题
|
|
302
|
-
- 1040 平台支持
|
|
303
|
-
- 不再支持`node 6`,要求`node 8`以上版本
|
|
304
|
-
- 不再创建备份文件
|
|
305
|
-
- 新增`web`预览功能,打开服务`/preview`页面可使用浏览器预览快应用
|
|
306
|
-
- 新增`aiot preview`子命令,可直接预览`rpk`文件或解压的`rpk`文件目录(包括`build`目录)
|
|
307
|
-
- 新增`aiot view`子命令,可用于直接查看`rpk` 文件。详情可执行`aiot view --help`查看
|
|
308
|
-
- 修复了`hap-toolkit`导致系统`adb` 不可使用的问题
|
|
309
|
-
- 修复其他若干缺陷
|
|
310
|
-
- 优化了`aiot init` 子命令,当文件夹存在时会询问输入新的应用名
|
|
311
|
-
- 优化了错误信息提示
|
|
312
|
-
- 修复`toolkit`误报使用`node`原生模块问题
|
|
313
|
-
- 支持分包
|
|
314
|
-
- `chrome devtools` 升级到 66
|
|
315
|
-
- 移除的`mix`命令(`hap`和`mix`完全一致)
|
|
316
|
-
- 优化错误栈信息
|
|
317
|
-
- 稳定性优化
|
|
318
|
-
- 修复初始化模块的 elisnt 配置无效的问题
|
|
319
|
-
- 修复若干 bug
|
|
320
|
-
- 初始化项目时,更新项目的 toolkit 的版本号
|
|
321
|
-
- 支持 node 6+(未来将不再支持 node 6,建议使用 node 8 以上版本)
|
|
322
|
-
- IDE 无法自动升级项目
|
|
323
|
-
- 项目 package.json 的依赖只有 hap-toolkit,移除了其他依赖
|
|
324
|
-
- 支持可以自定义属性 data-xxx
|
|
325
|
-
- slot 可以作为 text 的子组件
|
|
326
|
-
- 支持 postcss 解析 css
|
|
327
|
-
- 修复了图片资源检查的 bug
|
|
328
|
-
- 支持 touchstart,touchmove,touchcancel,touchend 事件
|
|
329
|
-
- 支持 font-family 样式
|
|
330
|
-
- image 组件增加 complete、error 事件
|
|
331
|
-
- video 组件支持 muted 属性
|
|
332
|
-
- audio 组件支持 stop 方法
|
|
333
|
-
- 支持 CSS @font-face
|
|
334
|
-
- justify-content 支持 space-around
|
|
335
|
-
- background-image 支持网络图片地址
|
|
336
|
-
- input/textarea 组件增加 selectionchange 事件
|
|
337
|
-
- tab-content 组件增加 scrollable 属性
|
|
338
|
-
- input 组件支持动态切换 type 类型
|
|
339
|
-
- WebSocket 支持 ArrayBuffer
|
|
340
|
-
- 升级到 babel7
|
|
341
|
-
- 升级到 webpack4
|
|
342
|
-
- 优化了 webpack 的参数读取方式
|
|
343
|
-
- transform 支持多个值,动画命名以下划线开发
|
|
344
|
-
- 支持 map 组件定位点样式修改
|
|
345
|
-
- 修复调试的时候,屏幕息屏的确认
|
|
346
|
-
- 编译工具支持卡片开发
|
|
347
|
-
- 命令行增加清除设备记录,如:aiot server --clear-records
|
|
348
|
-
- 使用 node 原生模块增加报错提示
|
|
349
|
-
- 增加了对 IDE 默认打开浏览器的支持
|
|
350
|
-
- 增加了捕获 webpack 的错误提示
|
|
351
|
-
- 升级 mocha 到 5.2.0 版本
|
|
352
|
-
- 优化了 webpack.config.js
|
|
353
|
-
- 修复 windows 下资源引用路径时转换的 BUG
|
|
354
|
-
- 修复了 adb 执行时候的错误提示
|
|
355
|
-
- 修复打包时 manifest.json 中 config.debug 标识的 BUG
|
|
356
|
-
- 支持 node_modules 模块中引入快应用接口
|
|
357
|
-
- 重构了编译模块,调整了打包的生命周期,从 done 到 after-emit
|
|
358
|
-
- 引入 json 文件
|
|
359
|
-
- 引入 node_modules 中@组织的库
|
|
360
|
-
- usb 调试功能(1020+)
|
|
361
|
-
- build 时增加参数 env.disable-source-map 以禁用 sourcemap
|
|
362
|
-
- chrome 调试页面:隐藏导航条,console 面板增加 warn 提示
|
|
363
|
-
- 修复调试时,断点调试的问题(1020+)
|
|
364
|
-
- 修复微信,微博,qq 账号在控制台下的提示警告问题
|
|
365
|
-
- 修复调试时,element 面板的展开问题
|
|
366
|
-
- 修复 sourceMap 行数不正确
|
|
367
|
-
- 修复打开 chrome 出现的一些问题
|
|
368
|
-
- 修复 css 属性 border-color 的解析
|
|
369
|
-
- 支持 npm run release 打包的 rpk 包增加版本号和时间戳功能
|
|
370
|
-
- 调试器支持编辑 html 和属性(1020+)
|
|
371
|
-
- 构建 rpk 时向 hap-toolkit 中历史记录的最近 5 条手机设备发送/update HTTP 信息
|
|
372
|
-
- 升级到 webpack3
|
|
373
|
-
- 修复 translate(tx)转换不正确问题
|
|
374
|
-
- 修复 chrome 调试器通过键盘左右键展开 element 节点
|
|
375
|
-
- 新增 chrome 调试器动态编辑样式功能
|
|
376
|
-
- 新增预处理.9 图
|
|
377
|
-
- 支持 background-position/ translate % unit
|
|
378
|
-
- 多列 picker 属性 type 增加 multi-text 值,增加 onclumnchange 和 cancel 方法
|
|
379
|
-
- flexbox 添加 align-self 属性支持
|
|
380
|
-
- 新增 textarea 组件属性 maxlength
|
|
381
|
-
- 新增 input 组件属性 maxlength,方法 enterkeytype 和 enterkeyclick
|
|
382
|
-
- 新增 video 组件属性 controls
|
|
383
|
-
- 新增 swiper 组件属性 loop
|
|
384
|
-
- 优化 jszip 打包的参数配置
|
|
385
|
-
- 重构了编译模块,移除 hap-tools,使用 hap-toolkit 替代
|
|
386
|
-
- 优化 package.json 的文件的内容,精简 script 命令
|
|
387
|
-
- 更改 aiot update --force 方式,覆盖 script, dependencies, devDependencies
|
|
388
|
-
- 打包使用 jszip 替换 node-archiver;进而支持 NodeJS 8.0.\*等版本;
|
|
389
|
-
- 新增 popup 的事件 visibilitychange;
|
|
390
|
-
- 在 manifest.json 里面支持了 debug 调试项;
|
|
391
|
-
- 更新 init 时的示例代码,调整代码风格;
|
|
392
|
-
- 重构 toolkit 项目以及内置模块;
|
|
393
|
-
- 如果在 manifest.json 里没有申明 minPlatformVersion,默认为 1070
|