@yorha2b-lab/autodev 1.1.0 → 2.0.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/README.md +28 -85
- package/README_EN.md +46 -100
- package/bin/autodev.js +29 -44
- package/config.js +7 -25
- package/package.json +1 -1
- package/src/commands/handlers/api-handler.js +80 -0
- package/src/commands/handlers/page-handler.js +92 -0
- package/src/commands/handlers/part-handler.js +76 -0
- package/src/commands/watch.js +96 -0
- package/src/core/react-compiler.js +6 -20
- package/src/prompts/mock.js +2 -2
- package/src/prompts/react/watch-part.js +30 -25
- package/src/services/llm.js +2 -24
- package/src/utils/utils.js +7 -28
- package/src/commands/watch-api.js +0 -68
- package/src/commands/watch-page.js +0 -155
- package/src/commands/watch-part.js +0 -77
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
const fs = require('fs')
|
|
2
|
-
const ora = require('ora')
|
|
3
|
-
const path = require('path')
|
|
4
|
-
const chalk = require('chalk')
|
|
5
|
-
const chokidar = require('chokidar')
|
|
6
|
-
|
|
7
|
-
const watchApi = options => {
|
|
8
|
-
// 导入配置文件和多语言函数
|
|
9
|
-
const { getConfig, language } = require('../utils/utils.js')
|
|
10
|
-
const { alignResponseFields } = require('../services/llm.js')
|
|
11
|
-
|
|
12
|
-
const config = getConfig()
|
|
13
|
-
|
|
14
|
-
const watcher = chokidar.watch('./response', {
|
|
15
|
-
persistent: true,
|
|
16
|
-
ignored: /(^|[\/\\])\../,
|
|
17
|
-
awaitWriteFinish: {
|
|
18
|
-
stabilityThreshold: 500,
|
|
19
|
-
pollInterval: 100
|
|
20
|
-
}
|
|
21
|
-
})
|
|
22
|
-
|
|
23
|
-
watcher.on('add', async filePath => {
|
|
24
|
-
const startTime = Date.now()
|
|
25
|
-
const fileName = path.basename(filePath, path.extname(filePath))
|
|
26
|
-
|
|
27
|
-
// 使用 language 函数包装 Pod 153 的启动报告
|
|
28
|
-
const spinner = ora(chalk.cyan(language(
|
|
29
|
-
`🤖 Pod 153: [报告] 侦测到未知的 Response 数据源 [${fileName}],开始进行语义对齐...`,
|
|
30
|
-
`🤖 Pod 153: [Report] Detected unknown Response data source [${fileName}]. Commencing semantic alignment...`
|
|
31
|
-
)))
|
|
32
|
-
spinner.start()
|
|
33
|
-
|
|
34
|
-
try {
|
|
35
|
-
const responseStr = fs.readFileSync(filePath, 'utf8')
|
|
36
|
-
let resourceStr = fs.readFileSync(`./${config.pagesDir}/${fileName}/resource.js`, 'utf8')
|
|
37
|
-
|
|
38
|
-
// 调用 AI 服务进行字段对齐
|
|
39
|
-
const result = await alignResponseFields(options, responseStr, resourceStr)
|
|
40
|
-
|
|
41
|
-
Object.entries(result).forEach(([oldField, newField]) => {
|
|
42
|
-
if (oldField === newField) return
|
|
43
|
-
const regex = new RegExp(`(dataIndex|name)\\s*:\\s*['"]${oldField}['"]`, 'g')
|
|
44
|
-
resourceStr = resourceStr.replace(regex, `$1: '${newField}'`)
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
fs.writeFileSync(path.join(`./${config.pagesDir}/${fileName}/resource.js`), resourceStr)
|
|
48
|
-
const endTime = Date.now()
|
|
49
|
-
|
|
50
|
-
// 成功报告:带上 9S 的骇客梗
|
|
51
|
-
spinner.succeed(chalk.green(language(
|
|
52
|
-
`🤖 Pod 153: [肯定] 字段对齐协议执行完毕:耗时 ${(endTime - startTime) / 1000} 秒。9S 的骇客任务很顺利。`,
|
|
53
|
-
`🤖 Pod 153: [Affirmative] Field alignment protocol executed. Time: ${(endTime - startTime) / 1000}s. 9S's hacking mission was successful.`
|
|
54
|
-
)))
|
|
55
|
-
if (fs.existsSync(filePath)) {
|
|
56
|
-
fs.unlinkSync(filePath)
|
|
57
|
-
}
|
|
58
|
-
} catch (error) {
|
|
59
|
-
// 失败报告:提到“防火墙”
|
|
60
|
-
spinner.fail(chalk.red(language(
|
|
61
|
-
`🤖 Pod 153: [警告] 骇入 [${fileName}] 失败。接口数据遭遇强力防火墙:${error}`,
|
|
62
|
-
`🤖 Pod 153: [Warning] Hacking into [${fileName}] failed. Encountered a powerful firewall in API data: ${error}`
|
|
63
|
-
)))
|
|
64
|
-
}
|
|
65
|
-
})
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
module.exports = watchApi
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
const fs = require('fs')
|
|
2
|
-
const ora = require('ora')
|
|
3
|
-
const path = require('path')
|
|
4
|
-
const chalk = require('chalk')
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* 监听截图目录,自动生成 CRUD 页面
|
|
8
|
-
* @param {Object} options - 命令行选项
|
|
9
|
-
* @param {string} options.template - 前端框架模板
|
|
10
|
-
*/
|
|
11
|
-
const watchPage = options => {
|
|
12
|
-
|
|
13
|
-
const { language, getConfig, copyTemplateDir, checkPromptPath, getExistingMenus } = require('../utils/utils.js')
|
|
14
|
-
|
|
15
|
-
const promptPath = `../prompts/${options.template}/watch-page.js`
|
|
16
|
-
|
|
17
|
-
checkPromptPath(promptPath)
|
|
18
|
-
|
|
19
|
-
const chokidar = require('chokidar')
|
|
20
|
-
const pagePrompt = require(promptPath)
|
|
21
|
-
const Handlebars = require('handlebars')
|
|
22
|
-
const { createTaskQueue } = require('../core/task-queue')
|
|
23
|
-
const stringify = require('json-stringify-pretty-compact')
|
|
24
|
-
const { recognizePage, generateMock } = require('../services/llm.js')
|
|
25
|
-
|
|
26
|
-
const config = getConfig()
|
|
27
|
-
|
|
28
|
-
const compilerPath = path.join(__dirname, `../core/${options.template}-compiler.js`)
|
|
29
|
-
|
|
30
|
-
// 1. 检查框架支持
|
|
31
|
-
if (!fs.existsSync(compilerPath)) {
|
|
32
|
-
console.error(chalk.red(language(
|
|
33
|
-
`\n❌ 糟糕!暂不支持 [${options.template}] 框架的自动生成。`,
|
|
34
|
-
`\n❌ Errors! Automatic generation for [${options.template}] is not supported.`
|
|
35
|
-
)))
|
|
36
|
-
console.log(language(
|
|
37
|
-
`💡 提示:目前仅内置了 react 编译器。`,
|
|
38
|
-
`💡 Note: Only the react compiler is currently built-in.`
|
|
39
|
-
))
|
|
40
|
-
console.log(language(
|
|
41
|
-
`🚀 强烈欢迎社区大佬提 PR 补充 ${options.template}-compiler.js !\n`,
|
|
42
|
-
`🚀 PRs for ${options.template}-compiler.js are highly welcomed!\n`
|
|
43
|
-
))
|
|
44
|
-
return
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const { index, resource } = require(compilerPath)
|
|
48
|
-
|
|
49
|
-
try {
|
|
50
|
-
//默认使用内置模板
|
|
51
|
-
if (config.hbsDir === '') {
|
|
52
|
-
copyTemplateDir(options, 'hooks', config.hooksDir)
|
|
53
|
-
copyTemplateDir(options, 'utils', config.utilsDir)
|
|
54
|
-
copyTemplateDir(options, 'components', config.componentsDir)
|
|
55
|
-
}
|
|
56
|
-
} catch (error) {
|
|
57
|
-
console.error(language('❌ 程序运行出错:', '❌ Runtime error:'), error)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const queue = createTaskQueue(2)
|
|
61
|
-
const menus = getExistingMenus()
|
|
62
|
-
|
|
63
|
-
const tplDir = config.hbsDir !== '' ? path.join(process.cwd(), config.hbsDir) : path.join(__dirname, `../../templates/${options.template}`)
|
|
64
|
-
const indexTpl = Handlebars.compile(fs.readFileSync(path.join(tplDir, 'index.hbs'), 'utf-8'))
|
|
65
|
-
const resourceTpl = Handlebars.compile(fs.readFileSync(path.join(tplDir, 'resource.hbs'), 'utf-8'))
|
|
66
|
-
|
|
67
|
-
// 2. 队列空闲时的菜单同步
|
|
68
|
-
queue.onIdle(() => {
|
|
69
|
-
console.log(chalk.green(language(
|
|
70
|
-
'🤖 Pod 042: [报告] 所有排队的视觉数据已解析完毕,正在向 Bunker 同步 Menu 路由配置...',
|
|
71
|
-
'🤖 Pod 042: [Report] Queued visual data processed. Syncing Menu configuration to the Bunker...'
|
|
72
|
-
)))
|
|
73
|
-
const constantDir = path.join(process.cwd(), config.utilsDir)
|
|
74
|
-
if (!fs.existsSync(constantDir)) fs.mkdirSync(constantDir, { recursive: true })
|
|
75
|
-
fs.writeFileSync(path.join(constantDir, 'menus.js'), `export const menus = ${stringify.default(menus, { indent: 4, maxLength: 50 })}`)
|
|
76
|
-
console.log(chalk.green(language(
|
|
77
|
-
'🤖 Pod 042: [肯定] Menu 配置同步成功。',
|
|
78
|
-
'🤖 Pod 042: [Affirmative] Menu configuration synced successfully.'
|
|
79
|
-
)))
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
const watcher = chokidar.watch('./screenShot', {
|
|
83
|
-
persistent: true,
|
|
84
|
-
ignored: /(^|[\/\\])\../,
|
|
85
|
-
awaitWriteFinish: { stabilityThreshold: 500, pollInterval: 100 }
|
|
86
|
-
})
|
|
87
|
-
|
|
88
|
-
// 3. 文件添加事件
|
|
89
|
-
watcher.on('add', filePath => {
|
|
90
|
-
queue.add(async () => {
|
|
91
|
-
const startTime = Date.now()
|
|
92
|
-
const mockDir = path.join(process.cwd(), 'mock')
|
|
93
|
-
const fileName = path.basename(filePath, path.extname(filePath))
|
|
94
|
-
const targetDir = path.join(process.cwd(), config.pagesDir, fileName)
|
|
95
|
-
|
|
96
|
-
const spinner = ora(chalk.cyan(language(
|
|
97
|
-
`🤖 Pod 042: [报告] 捕获到新的视觉图像 [${fileName}],开始执行构筑程序...`,
|
|
98
|
-
`🤖 Pod 042: [Report] Captured new visual image [${fileName}]. Initializing construction...`
|
|
99
|
-
)))
|
|
100
|
-
spinner.start()
|
|
101
|
-
|
|
102
|
-
try {
|
|
103
|
-
if (!fs.existsSync(mockDir)) fs.mkdirSync(mockDir, { recursive: true })
|
|
104
|
-
if (!fs.existsSync(targetDir)) fs.mkdirSync(targetDir, { recursive: true })
|
|
105
|
-
|
|
106
|
-
let pageConfig
|
|
107
|
-
if (config.useDemo) {
|
|
108
|
-
console.log(chalk.yellow(language(
|
|
109
|
-
`\nPod 042: [警告] 当前处于模拟模式。检测到视觉样本,但 Bunker 已拦截实弹请求,正在空投标准构筑包`,
|
|
110
|
-
`\nPod 042: [Warning] Current mode is demo. Visual sample detected, but Bunker has intercepted real requests. Sending standard package.`
|
|
111
|
-
)))
|
|
112
|
-
pageConfig = require(path.join(__dirname, '../../example/example.json'))
|
|
113
|
-
} else {
|
|
114
|
-
pageConfig = await recognizePage(pagePrompt, filePath)
|
|
115
|
-
}
|
|
116
|
-
fs.writeFileSync(path.join(targetDir, 'resource.js'), resource({ pageConfig, resourceTpl }))
|
|
117
|
-
fs.writeFileSync(path.join(targetDir, 'index.js'), index({ config, fileName, indexTpl, pageConfig }))
|
|
118
|
-
|
|
119
|
-
if (!menus.find(m => m.key === fileName)) {
|
|
120
|
-
menus.push({ label: fileName, key: fileName })
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// 4. 生成 Mock 数据
|
|
124
|
-
if (config.needMock) {
|
|
125
|
-
console.log(chalk.yellow(language(
|
|
126
|
-
`\n🧑💻 9S: 交给我吧 2B!正在骇入并伪造 [${fileName}] 的 Mock 数据...`,
|
|
127
|
-
`\n🧑💻 9S: Leave it to me, 2B! Hacking and forging Mock data for [${fileName}]...`
|
|
128
|
-
)))
|
|
129
|
-
const rawContent = await generateMock(pageConfig.table.columns, fileName)
|
|
130
|
-
fs.writeFileSync(path.join(mockDir, `${fileName}.js`), `export default ${stringify.default(rawContent, { indent: 4, maxLength: 200 })}`)
|
|
131
|
-
console.log(chalk.green(language(
|
|
132
|
-
`\n🤖 Pod 042: [报告] Mock 数据注入完成,耗时: ${(Date.now() - startTime) / 1000} 秒`,
|
|
133
|
-
`\n🤖 Pod 042: [Report] Mock data injection complete. Elapsed time: ${(Date.now() - startTime) / 1000}s`
|
|
134
|
-
)))
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const endTime = Date.now()
|
|
138
|
-
spinner.succeed(chalk.green(language(
|
|
139
|
-
`🤖 Pod 042: [报告] 模块 [${fileName}] 物理装配完成!耗时 ${(endTime - startTime) / 1000} 秒`,
|
|
140
|
-
`🤖 Pod 042: [Report] Module [${fileName}] assembly complete! Elapsed time: ${(endTime - startTime) / 1000}s`
|
|
141
|
-
)))
|
|
142
|
-
if (fs.existsSync(filePath)) {
|
|
143
|
-
//fs.unlinkSync(filePath)
|
|
144
|
-
}
|
|
145
|
-
} catch (error) {
|
|
146
|
-
spinner.fail(chalk.red(language(
|
|
147
|
-
`🤖 Pod 042: [警告] 模块 [${fileName}] 构筑失败。原因:${error}`,
|
|
148
|
-
`🤖 Pod 042: [Warning] Module [${fileName}] construction failed. Reason: ${error}`
|
|
149
|
-
)))
|
|
150
|
-
}
|
|
151
|
-
})
|
|
152
|
-
})
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
module.exports = watchPage
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
const fs = require('fs')
|
|
2
|
-
const ora = require('ora')
|
|
3
|
-
const chalk = require('chalk')
|
|
4
|
-
const chokidar = require('chokidar')
|
|
5
|
-
const stringify = require('json-stringify-pretty-compact')
|
|
6
|
-
|
|
7
|
-
const watchPart = options => {
|
|
8
|
-
|
|
9
|
-
const { language, checkPromptPath } = require('../utils/utils.js')
|
|
10
|
-
|
|
11
|
-
const promptPath = `../prompts/${options.template}/watch-part.js`
|
|
12
|
-
|
|
13
|
-
checkPromptPath(promptPath)
|
|
14
|
-
const partPrompt = require(promptPath)
|
|
15
|
-
const { recognizePage } = require('../services/llm.js')
|
|
16
|
-
|
|
17
|
-
const watcher = chokidar.watch('./screenPart', {
|
|
18
|
-
persistent: true,
|
|
19
|
-
ignored: /(^|[\/\\])\../,
|
|
20
|
-
awaitWriteFinish: {
|
|
21
|
-
stabilityThreshold: 500,
|
|
22
|
-
pollInterval: 100
|
|
23
|
-
}
|
|
24
|
-
})
|
|
25
|
-
|
|
26
|
-
watcher.on('add', async filePath => {
|
|
27
|
-
// 使用 language 函数包装 Pod 报告
|
|
28
|
-
const spinner = ora(chalk.cyan(language(
|
|
29
|
-
`🤖 Pod 042: [报告] 捕获到新的视觉图像,开始执行构筑程序...`,
|
|
30
|
-
`🤖 Pod 042: [Report] Captured new visual image. Initializing construction...`
|
|
31
|
-
)))
|
|
32
|
-
spinner.start()
|
|
33
|
-
|
|
34
|
-
try {
|
|
35
|
-
const startTime = Date.now()
|
|
36
|
-
const pageConfig = await recognizePage(partPrompt, filePath)
|
|
37
|
-
|
|
38
|
-
const optionDict = pageConfig.optionDict || {}
|
|
39
|
-
delete pageConfig.optionDict
|
|
40
|
-
|
|
41
|
-
// 处理配置字符串映射
|
|
42
|
-
let mainConfigStr = stringify.default(pageConfig, { indent: 4, maxLength: 200 })
|
|
43
|
-
.replace(/"(\w+)":/g, '$1:')
|
|
44
|
-
.replace(/"/g, "'")
|
|
45
|
-
.replace(/['"]_CODE_([\s\S]*?)_CODE_['"]/g, '$1')
|
|
46
|
-
.replace(/_CODE_/g, '')
|
|
47
|
-
|
|
48
|
-
let optionsCodeStr = ''
|
|
49
|
-
Object.keys(optionDict).forEach(key => {
|
|
50
|
-
const varName = key.replaceAll('_CODE_', '')
|
|
51
|
-
const optionsArray = optionDict[key]
|
|
52
|
-
const arrayItemsStr = optionsArray.map(opt => ` { label: '${opt.label}', value: '${opt.value}' }`).join(',\n')
|
|
53
|
-
optionsCodeStr += `\nexport const ${varName} = [\n${arrayItemsStr}\n]\n`
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
const finalResult = `${mainConfigStr}\n${optionsCodeStr}`
|
|
57
|
-
const endTime = Date.now()
|
|
58
|
-
|
|
59
|
-
// 成功报告
|
|
60
|
-
spinner.succeed(language(
|
|
61
|
-
`🤖 Pod 042: [报告] 识别程序结束!耗时 ${(endTime - startTime) / 1000} 秒\n================\n\n${finalResult}\n\n================`,
|
|
62
|
-
`🤖 Pod 042: [Report] Recognition complete! Elapsed time: ${(endTime - startTime) / 1000}s\n================\n\n${finalResult}\n\n================`
|
|
63
|
-
))
|
|
64
|
-
if (fs.existsSync(filePath)) {
|
|
65
|
-
fs.unlinkSync(filePath)
|
|
66
|
-
}
|
|
67
|
-
} catch (error) {
|
|
68
|
-
// 失败报告
|
|
69
|
-
spinner.fail(chalk.red(language(
|
|
70
|
-
`🤖 Pod 042: [警告] 识别程序失败。原因:${error}`,
|
|
71
|
-
`🤖 Pod 042: [Warning] Recognition failed. Reason: ${error}`
|
|
72
|
-
)))
|
|
73
|
-
}
|
|
74
|
-
})
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
module.exports = watchPart
|