@yorha2b-lab/autodev 5.1.0 → 5.2.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/autodev.js +22 -38
- package/package.json +1 -1
- package/src/bootstrap/foundation.js +15 -0
- package/src/bootstrap/index.js +30 -32
- package/src/bootstrap/labs.js +21 -0
- package/src/bootstrap/registry.js +14 -0
- package/src/bootstrap/yorha.js +0 -3
- package/src/commands/watch.js +16 -8
- package/src/dialogs/EN-US.js +8 -1
- package/src/dialogs/ZH-CN.js +7 -0
- package/src/framework/react/generator/index.js +4 -1
- package/src/framework/react/prompts/page.js +29 -38
- package/src/handlers/api.js +2 -5
- package/src/handlers/page.js +5 -7
- package/src/handlers/part.js +4 -6
- package/src/labs/linker.js +4 -8
- package/src/labs/tower.js +8 -8
- package/src/services/llm.js +9 -12
- package/src/utils/core.js +43 -3
- package/src/utils/{infrastructure.js → foundation.js} +5 -44
- package/src/utils/ux.js +8 -14
- package/src/bootstrap/dialogs.js +0 -10
- package/src/bootstrap/handlers.js +0 -10
- package/src/bootstrap/infrastructure.js +0 -16
- package/src/bootstrap/prompts.js +0 -10
- /package/src/bootstrap/{handlebars.js → handlebar.js} +0 -0
package/bin/autodev.js
CHANGED
|
@@ -6,7 +6,7 @@ const pkg = require('../package.json')
|
|
|
6
6
|
const { program } = require('commander')
|
|
7
7
|
const { local, matrixEffect, bootSequence } = require('../src/utils/ux')
|
|
8
8
|
|
|
9
|
-
const dialogs = require('../src/bootstrap/
|
|
9
|
+
const dialogs = require('../src/bootstrap/registry')({ dir: path.join(__dirname, '../src/dialogs') })
|
|
10
10
|
const dialog = dialogs[local]
|
|
11
11
|
|
|
12
12
|
program
|
|
@@ -19,29 +19,25 @@ program
|
|
|
19
19
|
.command('init')
|
|
20
20
|
.description(dialog.bunker.initDesc)
|
|
21
21
|
.action(() => {
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
fs.mkdirSync(path.join(process.cwd(), 'screenShot'), { recursive: true })
|
|
29
|
-
fs.mkdirSync(path.join(process.cwd(), 'screenPart'), { recursive: true })
|
|
30
|
-
|
|
31
|
-
if (fs.existsSync(targetEnv)) {
|
|
32
|
-
console.log(chalk.yellow(dialog.bunker.envCheck))
|
|
33
|
-
} else {
|
|
34
|
-
fs.copyFileSync(tplEnv, targetEnv)
|
|
35
|
-
console.log(chalk.green(dialog.bunker.envCopy))
|
|
22
|
+
const battlefield = {
|
|
23
|
+
dirs: ['response', 'screenShot', 'screenPart'],
|
|
24
|
+
files: [
|
|
25
|
+
{ from: '.env.example', to: '.env', exist: 'envCheck', success: 'envCopy' },
|
|
26
|
+
{ from: 'config.js', to: 'config.js', exist: 'configCheck', success: 'configCopy' }
|
|
27
|
+
]
|
|
36
28
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
29
|
+
const installer = {
|
|
30
|
+
dirs: dir => fs.mkdirSync(path.join(process.cwd(), dir), { recursive: true }),
|
|
31
|
+
files: ({ from, to, exist, success }) => {
|
|
32
|
+
const target = path.join(process.cwd(), to)
|
|
33
|
+
if (fs.existsSync(target)) {
|
|
34
|
+
return console.log(chalk.yellow(dialog.bunker[exist]))
|
|
35
|
+
}
|
|
36
|
+
fs.copyFileSync(path.resolve(__dirname, `../${from}`), target)
|
|
37
|
+
console.log(chalk.green(dialog.bunker[success]))
|
|
38
|
+
}
|
|
43
39
|
}
|
|
44
|
-
|
|
40
|
+
Object.entries(battlefield).forEach(([type, items]) => items.forEach(installer[type]))
|
|
45
41
|
const bunkerCmd = chalk.yellow(`'bunker': 'autodev watch'`)
|
|
46
42
|
console.log(chalk.cyan(dialog.bunker.initComplete(bunkerCmd)))
|
|
47
43
|
})
|
|
@@ -52,27 +48,15 @@ program
|
|
|
52
48
|
.description(dialog.bunker.watchDesc)
|
|
53
49
|
.action(async () => {
|
|
54
50
|
const bunker = require('../src/bootstrap')
|
|
55
|
-
const result = bunker.init(program.opts(),
|
|
51
|
+
const result = bunker.init(program.opts(), dialog)
|
|
56
52
|
if (!result) {
|
|
57
53
|
return
|
|
58
54
|
}
|
|
59
|
-
|
|
60
|
-
const { config } = result.infrastructure
|
|
61
|
-
const { apiDoc, needMock, proxyTarget, enableAutoAlignment } = config
|
|
62
|
-
|
|
63
|
-
const bootTower = proxyTarget && !needMock && enableAutoAlignment
|
|
64
|
-
|
|
65
|
-
await bootSequence({ dialog, version: pkg.version, bootTower, commander })
|
|
55
|
+
await bootSequence(pkg.version)
|
|
66
56
|
require('../src/commands/watch')()
|
|
67
|
-
if (bootTower) {
|
|
68
|
-
require('../src/labs/tower')()
|
|
69
|
-
}
|
|
70
|
-
if (apiDoc && enableAutoAlignment) {
|
|
71
|
-
require('../src/labs/linker')()
|
|
72
|
-
}
|
|
73
57
|
process.on('SIGINT', () => {
|
|
74
|
-
commander.
|
|
75
|
-
matrixEffect(500)
|
|
58
|
+
result.yorha.commander.report(dialog.bunker.systemOffline, 'gray')
|
|
59
|
+
matrixEffect(500, dialog)
|
|
76
60
|
})
|
|
77
61
|
})
|
|
78
62
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module.exports = ({ config, yorha, dialog, template, foundation }) => {
|
|
2
|
+
|
|
3
|
+
const { copyTemplateDir } = foundation
|
|
4
|
+
const { hbsDir, hooksDir, utilsDir, componentsDir } = config
|
|
5
|
+
|
|
6
|
+
try {
|
|
7
|
+
if (hbsDir === '') {
|
|
8
|
+
copyTemplateDir(template, 'hooks', hooksDir)
|
|
9
|
+
copyTemplateDir(template, 'utils', utilsDir)
|
|
10
|
+
copyTemplateDir(template, 'components', componentsDir)
|
|
11
|
+
}
|
|
12
|
+
} catch (error) {
|
|
13
|
+
yorha.commander.report(dialog.bunker.copyTemplateError(error), 'red')
|
|
14
|
+
}
|
|
15
|
+
}
|
package/src/bootstrap/index.js
CHANGED
|
@@ -1,56 +1,54 @@
|
|
|
1
1
|
const fs = require('fs')
|
|
2
2
|
const path = require('path')
|
|
3
|
-
const chalk = require('chalk')
|
|
4
3
|
|
|
5
4
|
let instance = null
|
|
6
5
|
|
|
7
6
|
module.exports = {
|
|
8
7
|
|
|
9
|
-
init: (
|
|
8
|
+
init: ({ template }, dialog) => {
|
|
10
9
|
|
|
11
|
-
const
|
|
12
|
-
const ux = require('../utils/ux')
|
|
10
|
+
const yorha = require('./yorha')()
|
|
13
11
|
|
|
14
12
|
const generatorPath = path.join(__dirname, `../framework/${template}/generator`)
|
|
15
13
|
if (!fs.existsSync(generatorPath)) {
|
|
16
|
-
|
|
14
|
+
yorha.commander.report(dialog.bunker.frameworkNotSupported(template), 'red')
|
|
17
15
|
return
|
|
18
16
|
}
|
|
19
17
|
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
const yorha = require('./yorha')()
|
|
23
|
-
const openAI = require('./openai')()
|
|
24
|
-
const core = require('../utils/core')
|
|
25
|
-
const handlers = require('./handlers')()
|
|
26
|
-
const config = infrastructure.getConfig()
|
|
27
|
-
const menus = infrastructure.getExistingMenus()
|
|
28
|
-
const prompts = require('./prompts')({ template })
|
|
29
|
-
const handlebars = require('./handlebars')({ config, template, ...infrastructure })
|
|
18
|
+
const foundation = require('../utils/foundation')
|
|
19
|
+
const config = foundation.getConfig()
|
|
30
20
|
|
|
31
|
-
const accessPoint = {
|
|
21
|
+
const accessPoint = {
|
|
22
|
+
yorha,
|
|
23
|
+
config,
|
|
24
|
+
dialog,
|
|
25
|
+
template,
|
|
26
|
+
foundation,
|
|
27
|
+
openAI: require('./openai')(),
|
|
28
|
+
core: require('../utils/core'),
|
|
29
|
+
menus: foundation.getExistingMenus(),
|
|
30
|
+
handlebars: require('./handlebar')({ config, template, ...foundation }),
|
|
31
|
+
handlers: require('./registry')({ dir: path.join(__dirname, '../handlers') }),
|
|
32
|
+
prompts: require('./registry')({ dir: path.join(__dirname, `../framework/${template}/prompts`) }),
|
|
33
|
+
}
|
|
32
34
|
|
|
33
|
-
require('./
|
|
35
|
+
require('./foundation')(accessPoint)
|
|
34
36
|
const llm = require('../services/llm')(accessPoint)
|
|
35
37
|
const generator = require(generatorPath)(accessPoint)
|
|
38
|
+
const labs = require('./labs')({ llm, ...accessPoint })
|
|
36
39
|
|
|
37
40
|
|
|
38
|
-
instance = {
|
|
39
|
-
ux,
|
|
40
|
-
llm,
|
|
41
|
-
core,
|
|
42
|
-
yorha,
|
|
43
|
-
openAI,
|
|
44
|
-
prompts,
|
|
45
|
-
dialogs,
|
|
46
|
-
handlers,
|
|
47
|
-
generator,
|
|
48
|
-
handlebars,
|
|
49
|
-
cli: options,
|
|
50
|
-
infrastructure: { menus, config, ...infrastructure },
|
|
51
|
-
}
|
|
41
|
+
instance = { llm, labs, generator, ...accessPoint }
|
|
52
42
|
return instance
|
|
53
43
|
},
|
|
54
44
|
|
|
55
|
-
get: () => instance
|
|
45
|
+
get: () => instance,
|
|
46
|
+
|
|
47
|
+
reboot() {
|
|
48
|
+
const { template, dialog } = instance
|
|
49
|
+
delete require.cache[require.resolve(path.join(process.cwd(), 'config.js'))]
|
|
50
|
+
instance.labs?.shutdown?.()
|
|
51
|
+
instance = null
|
|
52
|
+
return this.init({ template }, dialog)
|
|
53
|
+
}
|
|
56
54
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
let tower
|
|
2
|
+
|
|
3
|
+
module.exports = accessPoint => {
|
|
4
|
+
|
|
5
|
+
const { apiDoc, needMock, proxyTarget, enableAutoAlignment } = accessPoint.config
|
|
6
|
+
|
|
7
|
+
if (!needMock && proxyTarget && enableAutoAlignment) {
|
|
8
|
+
tower = require('../labs/tower')(accessPoint)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
if (apiDoc && enableAutoAlignment) {
|
|
12
|
+
require('../labs/linker')(accessPoint)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return {
|
|
16
|
+
shutdown() {
|
|
17
|
+
tower?.close()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module.exports = ({ dir }) => {
|
|
2
|
+
|
|
3
|
+
const fs = require('fs')
|
|
4
|
+
const path = require('path')
|
|
5
|
+
|
|
6
|
+
return Object.fromEntries(
|
|
7
|
+
fs.readdirSync(dir)
|
|
8
|
+
.filter(file => file.endsWith('.js'))
|
|
9
|
+
.map(file => [
|
|
10
|
+
path.basename(file, '.js'),
|
|
11
|
+
require(path.join(dir, file))
|
|
12
|
+
])
|
|
13
|
+
)
|
|
14
|
+
}
|
package/src/bootstrap/yorha.js
CHANGED
|
@@ -11,9 +11,6 @@ module.exports = () => {
|
|
|
11
11
|
fail(spinner, text) {
|
|
12
12
|
spinner.fail(chalk.red(`\n${name} ${text}`))
|
|
13
13
|
},
|
|
14
|
-
log(text, color = 'gray') {
|
|
15
|
-
console.log(chalk[color](`\n${name} ${text}`))
|
|
16
|
-
},
|
|
17
14
|
report(text, color = 'yellow') {
|
|
18
15
|
console.log(chalk[color](`\n${name} ${text}`))
|
|
19
16
|
},
|
package/src/commands/watch.js
CHANGED
|
@@ -4,13 +4,12 @@ module.exports = () => {
|
|
|
4
4
|
const path = require('path')
|
|
5
5
|
const chokidar = require('chokidar')
|
|
6
6
|
|
|
7
|
-
const
|
|
7
|
+
const bootstrap = require('../bootstrap')
|
|
8
|
+
const { core, menus, yorha, config, dialog, handlers, foundation } = bootstrap.get()
|
|
8
9
|
|
|
9
|
-
const { local } = ux
|
|
10
|
-
const dialog = dialogs[local]
|
|
11
10
|
const { createTaskQueue } = core
|
|
11
|
+
const { contextStringify } = foundation
|
|
12
12
|
const { pod042, commander, operator6O } = yorha
|
|
13
|
-
const { menus, config, contextStringify } = infrastructure
|
|
14
13
|
|
|
15
14
|
const queue = createTaskQueue(2)
|
|
16
15
|
|
|
@@ -19,21 +18,24 @@ module.exports = () => {
|
|
|
19
18
|
const utilsDir = path.join(process.cwd(), config.utilsDir)
|
|
20
19
|
if (!fs.existsSync(utilsDir)) fs.mkdirSync(utilsDir, { recursive: true })
|
|
21
20
|
fs.writeFileSync(path.join(utilsDir, 'menus.js'), `export const menus = ${contextStringify({ context: menus, maxLength: 50 })}`)
|
|
22
|
-
commander.
|
|
21
|
+
commander.report(dialog.bunker.systemStandby, 'gray')
|
|
23
22
|
})
|
|
24
23
|
|
|
25
|
-
const
|
|
24
|
+
const options = {
|
|
26
25
|
persistent: true,
|
|
27
26
|
ignoreInitial: true,
|
|
28
27
|
ignored: /(^|[\/\\])\../,
|
|
29
28
|
awaitWriteFinish: { stabilityThreshold: 500, pollInterval: 100 }
|
|
30
|
-
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const fileWatcher = chokidar.watch(['./config.js'], options)
|
|
32
|
+
const dirWatcher = chokidar.watch(['./screenShot', './screenPart', './response'], options)
|
|
31
33
|
|
|
32
34
|
operator6O.report(dialog.operator6O.call2B)
|
|
33
35
|
|
|
34
36
|
const routes = Object.values(handlers)
|
|
35
37
|
|
|
36
|
-
|
|
38
|
+
dirWatcher.on('add', filePath => {
|
|
37
39
|
const absolutePath = path.resolve(filePath)
|
|
38
40
|
const route = routes.find(route => absolutePath.includes(route.watch))
|
|
39
41
|
if (route) {
|
|
@@ -41,4 +43,10 @@ module.exports = () => {
|
|
|
41
43
|
}
|
|
42
44
|
})
|
|
43
45
|
|
|
46
|
+
fileWatcher.on('change', file => {
|
|
47
|
+
if (file.endsWith('config.js')) {
|
|
48
|
+
bootstrap.reboot()
|
|
49
|
+
}
|
|
50
|
+
})
|
|
51
|
+
|
|
44
52
|
}
|
package/src/dialogs/EN-US.js
CHANGED
|
@@ -31,6 +31,7 @@ module.exports = {
|
|
|
31
31
|
bridgeProtocolComplete: (count, time) => `Semantic bridge protocol complete. Corrected ${count} field deviations. Elapsed: ${time}s`,
|
|
32
32
|
},
|
|
33
33
|
bunker: {
|
|
34
|
+
exit: 'Signal Lost',
|
|
34
35
|
envCopy: '.env storage complete',
|
|
35
36
|
envCheck: '.env already exists',
|
|
36
37
|
systemStandby: 'System is STANDBY',
|
|
@@ -38,7 +39,10 @@ module.exports = {
|
|
|
38
39
|
configCopy: 'config.js storage complete',
|
|
39
40
|
argDesc: 'Specify frontend framework template',
|
|
40
41
|
desc: 'AI-powered frontend CRUD code generator',
|
|
42
|
+
dataSynced: 'All data synced to Bunker storage nodes',
|
|
41
43
|
initDesc: 'Initialize Bunker construction environment',
|
|
44
|
+
star: 'If it saves you time, feel free to give it a ⭐ on GitHub',
|
|
45
|
+
copyTemplateError: virus => `Template construction failed: ${virus}`,
|
|
42
46
|
towerOnline: port => `Signal Intercept Tower Online [Band: ${port}]`,
|
|
43
47
|
linkSevered: 'Link Severed: Check network status or Black Box resonance',
|
|
44
48
|
systemOffline: 'Disconnecting Neural Link, Executing Physical Assembly...',
|
|
@@ -46,8 +50,11 @@ module.exports = {
|
|
|
46
50
|
watchDesc: 'Start full-channel linked monitoring: Coordinated Page/Part/API construction',
|
|
47
51
|
towerConnected: port => `Command: Please point your local proxy target to http://localhost:${port}`,
|
|
48
52
|
disclaimer: 'Match Result Reference Only. Not Final Decision. Each Unit should adjust based on battlefield conditions',
|
|
53
|
+
frameworkNotSupported: template => `[${template}] framework not supported. Welcome to contribute a Pull Request to help`,
|
|
49
54
|
networkInstability: count => `Neural Network instability detected. Attempting to re-establish link... (Retry #${count})`,
|
|
50
|
-
|
|
55
|
+
strategicThreshold: (target, current) => `Physical clone count has exceeded ${target} strategic threshold! Current power: ${current}`,
|
|
56
|
+
initComplete: cmd => `Bunker deployment is complete. To expedite your entry into the battlefield, I recommend a manual [Physical Assembly]: Add ${cmd} to your package.json scripts.`,
|
|
57
|
+
isLegendary: (unlockAchievement, current, target) => unlockAchievement ? 'Congratulations, your construction protocol is now part of humanity' : `Current clones: ${current}. ${target - current} to Achievement`,
|
|
51
58
|
},
|
|
52
59
|
operator6O: {
|
|
53
60
|
call2B: 'Calling 2B, all-channel linked monitoring is ready!'
|
package/src/dialogs/ZH-CN.js
CHANGED
|
@@ -31,6 +31,7 @@ module.exports = {
|
|
|
31
31
|
bridgeProtocolComplete: (count, time) => `语义桥接协议执行完毕。已物理修正 ${count} 处字段偏差。耗时: ${time}s`,
|
|
32
32
|
},
|
|
33
33
|
bunker: {
|
|
34
|
+
exit: '系统信号已丢失',
|
|
34
35
|
envCopy: '.env 存储完毕',
|
|
35
36
|
argDesc: '指定前端框架模板',
|
|
36
37
|
systemStandby: '系统待机中...',
|
|
@@ -38,16 +39,22 @@ module.exports = {
|
|
|
38
39
|
configCopy: 'config.js 存储完毕',
|
|
39
40
|
initDesc: '在当前目录初始化地堡构筑环境',
|
|
40
41
|
envCheck: '终端已存在 .env 文件,跳过生成',
|
|
42
|
+
dataSynced: '所有构筑数据已同步至 Bunker 存储节点',
|
|
41
43
|
configCheck: '终端已存在 config.js 文件,跳过生成',
|
|
42
44
|
linkSevered: '连接中断:请检查网络状态或黑盒共鸣情况',
|
|
43
45
|
systemOffline: '正在断开神经云链接,执行数据物理封存...',
|
|
46
|
+
copyTemplateError: virus => `模板构筑失败: ${virus}`,
|
|
47
|
+
star: '如果它能帮您节省时间,请在 GitHub 上给它点个赞 ⭐',
|
|
44
48
|
towerOnline: port => `信号拦截塔已在线 [波段: ${port}]`,
|
|
45
49
|
watchDesc: '开启全频道联动监控:支持 Page/Part/API 协同构筑',
|
|
46
50
|
accessDenied: '司令部拒绝访问:API Key 无效或额度耗尽,请检查!',
|
|
47
51
|
disclaimer: '匹配结果仅供参考,不构成最终决策,各机体需根据实际情况进行调整',
|
|
48
52
|
towerConnected: port => `指令:请将您的代理目标指向 http://localhost:${port}`,
|
|
49
53
|
networkInstability: count => `神经云网络连接不稳,正在尝试重新链接... (第 ${count} 次重试)`,
|
|
54
|
+
frameworkNotSupported: template => `暂不支持 [${template}] 框架。欢迎提交 Pull Request 贡献`,
|
|
55
|
+
strategicThreshold: (target, current) => `物理克隆总数已超越 ${target} 战略阈值!当前战力:${current}`,
|
|
50
56
|
initComplete: cmd => `地堡部署完毕, 为了更快捷地进入战场,建议手动执行 [物理装配]: 将 ${cmd} 加入您的 package.json scripts 中`,
|
|
57
|
+
isLegendary: (unlockAchievement, current, target) => unlockAchievement ? '恭喜您指挥官,您的构筑协议已成为人类荣光的一部分' : `当前构筑总数:${current}。距离 ${target} 勋章还剩 ${target - current} 次`,
|
|
51
58
|
},
|
|
52
59
|
operator6O: {
|
|
53
60
|
call2B: '呼叫 2B,地堡全频道联动监控已就绪!',
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
module.exports = ({
|
|
1
|
+
module.exports = ({ core, config, handlebars, foundation }) => {
|
|
2
2
|
|
|
3
|
+
const { contextStringify } = foundation
|
|
4
|
+
const { indexTpl, resourceTpl } = handlebars
|
|
3
5
|
const { needMock, responseSuccess } = config
|
|
6
|
+
const { cleanCode, generateSmartImports, formatFormItemAndColumns } = core
|
|
4
7
|
|
|
5
8
|
return {
|
|
6
9
|
index: ({ fileName, pageConfig }) => {
|
|
@@ -1,42 +1,37 @@
|
|
|
1
|
-
module.exports = `
|
|
1
|
+
module.exports = fileName => `
|
|
2
2
|
# Task: Full-Page UI Analysis & Structural Assembly
|
|
3
3
|
执行全页面视觉特征提取,并按照物理布局顺序输出标准的构筑协议。
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**模块名: ${fileName}**
|
|
6
|
+
|
|
7
|
+
## 核心命名协议 (Naming Convention)
|
|
6
8
|
- **驼峰命名**: 所有变量及函数名必须遵循 camelCase。
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
+
- **严禁中文**: 绝对禁止在变量名、键名中使用中文字符。
|
|
10
|
+
- **屏蔽关键字**: 禁止使用 JS 保留字 (export, delete, const, let, class, default 等)。
|
|
9
11
|
|
|
10
|
-
##
|
|
12
|
+
## 零部件构筑规范 (Component Specifications)
|
|
11
13
|
|
|
12
|
-
|
|
14
|
+
## 标签页 (tabs)
|
|
13
15
|
- **基础格式**: [{ label: '文本', key: 'englishName' }]
|
|
14
|
-
- **识别条件**:
|
|
16
|
+
- **识别条件**: 底部有显著长横线 (Ink Bar) 或呈现包裹感 (Card style) 时判定。
|
|
15
17
|
- **排除项**: 表格上方的独立按钮必须归类为 [functionButton]。
|
|
16
18
|
|
|
17
|
-
|
|
18
|
-
- **基础格式**: [{ label: '文本', name: 'englishName'
|
|
19
|
-
-
|
|
20
|
-
- 默认输入框: 仅保留 [label, name] 属性。**严禁出现
|
|
19
|
+
## 搜索项 (formItems)
|
|
20
|
+
- **基础格式**: [{ label: '文本', name: 'englishName' }]
|
|
21
|
+
- **属性精简规则**:
|
|
22
|
+
- 默认输入框: 仅保留 [label, name] 属性。**严禁出现[type]**。
|
|
21
23
|
- 非默认组件: 仅当类型为 [auto, date, radio, select, upload, checkbox, textarea, daterange] 时才允许添加 type 属性。
|
|
22
|
-
|
|
23
|
-
- date: 单日期
|
|
24
|
-
- enum: 枚举类型
|
|
25
|
-
- daterange: 日期范围
|
|
26
|
-
- text: 普通文本(默认)
|
|
27
|
-
- 命名规范:
|
|
24
|
+
- **命名规范**:
|
|
28
25
|
- daterange: name 必须设为 '字段英文名Start,字段英文名End'
|
|
29
|
-
- **⚠️注意⚠️**:不要用_分隔字段名。
|
|
30
26
|
|
|
31
|
-
|
|
32
|
-
- **独立存在**: 位于表格外周的汇总信息。输出格式: { has:
|
|
27
|
+
## 统计条 (StaticInfo)
|
|
28
|
+
- **独立存在**: 位于表格外周的汇总信息。输出格式: { has: boolean, text: '具体内容' }。
|
|
33
29
|
|
|
34
|
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
37
|
-
-
|
|
38
|
-
-
|
|
39
|
-
- **标准定义 (Columns)**:
|
|
30
|
+
## 表格主体 (table)
|
|
31
|
+
- **基础格式(columns)**: [{ title: '文本', dataIndex: 'englishName' }]。
|
|
32
|
+
- **配置项**: [pagination, expandable, rowSelection] 均为布尔值。
|
|
33
|
+
- **行操作 (operation)**: [{ label: '操作名', action: '动词Record', uri: 'BUNKER_API_ANCHOR_动词[模块名]'}]
|
|
34
|
+
- **类型定义 (type)**:
|
|
40
35
|
- enum: 枚举列
|
|
41
36
|
- money: 金额列
|
|
42
37
|
- index: 序号列
|
|
@@ -45,23 +40,19 @@ module.exports = `
|
|
|
45
40
|
- text: 普通文本(默认)
|
|
46
41
|
- tag: 标签列(有背景色的文本)
|
|
47
42
|
- badge: 徽标列(文本前有颜色小圆点)
|
|
48
|
-
- **行操作 (operation)**: [{label:'操作名', action:'动词ByRecord',uri:'BUNKER_API_ANCHOR_动词ByRecord'}]。
|
|
49
43
|
|
|
50
|
-
|
|
51
|
-
-
|
|
52
|
-
- **导出数据**: action 设为 '
|
|
53
|
-
- **逻辑锁定**:
|
|
54
|
-
- **构筑联动**:
|
|
44
|
+
## 全局功能按钮 (functionButton)
|
|
45
|
+
- **基础格式**: [{ btn: '按钮', action: '操作动词[模块名]BySelected', uri: 'BUNKER_API_ANCHOR_动词[模块名]BySelected'}]。
|
|
46
|
+
- **导出数据**: action 设为 'export[模块名]'。
|
|
47
|
+
- **逻辑锁定**: 只要页面中出现了非查询、非重置的独立操作按钮,必须识别并存入 [functionButton] 数组。
|
|
48
|
+
- **构筑联动**: 若 [functionButton] 数组不为空,则在下文的 [RenderTree] 中必须包含 "FunctionButtons"。
|
|
55
49
|
|
|
56
|
-
##
|
|
50
|
+
## 布局逻辑编排 (RenderTree)
|
|
57
51
|
- **定义**: 定义从上至下的物理堆叠顺序。
|
|
58
52
|
- **白名单**: [MyTable, AlertInfo, MySearchForm, FunctionButtons]
|
|
59
|
-
- **注释**: MyTable 是表格主体,AlertInfo 是统计条,MySearchForm 是搜索表单,FunctionButtons 是全局功能按钮。
|
|
60
53
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
- **格式**:[{name:'字段英文名+Options',options:[{label:'', value:''}]}]。
|
|
54
|
+
## 字典数组 (OptionList)
|
|
55
|
+
- **格式**:[{ name: '字段英文名Options', options:[{ label, value}]}]。
|
|
64
56
|
- **注释**:label:选项文本,value:文本英文。
|
|
65
57
|
- **数据源**:根据对应列的内容去重,生成选项数组。
|
|
66
|
-
|
|
67
58
|
`.trim();
|
package/src/handlers/api.js
CHANGED
|
@@ -6,16 +6,13 @@ module.exports = {
|
|
|
6
6
|
async handle(filePath, liveResponse = null) {
|
|
7
7
|
|
|
8
8
|
const chalk = require('chalk')
|
|
9
|
-
const {
|
|
9
|
+
const { llm, core, yorha, dialog, config } = require('../bootstrap').get()
|
|
10
10
|
|
|
11
|
-
const {
|
|
12
|
-
const dialog = dialogs[local]
|
|
11
|
+
const { pagesDir } = config
|
|
13
12
|
const { unwrapSignal } = core
|
|
14
13
|
const { nineS, pod153 } = yorha
|
|
15
|
-
const { config } = infrastructure
|
|
16
14
|
const { alignResponseFields } = llm
|
|
17
15
|
|
|
18
|
-
const { pagesDir } = config
|
|
19
16
|
const startTime = Date.now()
|
|
20
17
|
const fileName = liveResponse?.fileName ?? path.basename(filePath, path.extname(filePath))
|
|
21
18
|
const resourcePath = path.join(process.cwd(), pagesDir, fileName, 'resource.js')
|
package/src/handlers/page.js
CHANGED
|
@@ -5,18 +5,16 @@ module.exports = {
|
|
|
5
5
|
watch: 'screenShot',
|
|
6
6
|
async handle(filePath) {
|
|
7
7
|
|
|
8
|
-
const {
|
|
8
|
+
const { llm, menus, yorha, dialog, config, prompts, generator, foundation } = require('../bootstrap').get()
|
|
9
9
|
|
|
10
|
-
const {
|
|
11
|
-
const dialog = dialogs[local]
|
|
12
|
-
const { pagePrompt } = prompts
|
|
10
|
+
const { page } = prompts
|
|
13
11
|
const { nineS, pod042 } = yorha
|
|
14
12
|
const { index, resource } = generator
|
|
13
|
+
const { contextStringify } = foundation
|
|
15
14
|
const { generateMock, recognizePage } = llm
|
|
16
|
-
const { menus, config, contextStringify } = infrastructure
|
|
17
|
-
|
|
18
15
|
const { useDemo, pagesDir, needMock } = config
|
|
19
16
|
|
|
17
|
+
|
|
20
18
|
const startTime = Date.now()
|
|
21
19
|
const fileName = path.basename(filePath, path.extname(filePath))
|
|
22
20
|
const mockDir = path.join(process.cwd(), 'mock')
|
|
@@ -39,7 +37,7 @@ module.exports = {
|
|
|
39
37
|
pageConfig = require('../../example/example.json')
|
|
40
38
|
} else {
|
|
41
39
|
pod042.update(spinner, dialog.pod042.uploadVisualMetadata)
|
|
42
|
-
pageConfig = await recognizePage({ prompt:
|
|
40
|
+
pageConfig = await recognizePage({ prompt: page(fileName), filePath })
|
|
43
41
|
}
|
|
44
42
|
|
|
45
43
|
fs.writeFileSync(path.join(targetDir, 'resource.js'), resource({ pageConfig }))
|
package/src/handlers/part.js
CHANGED
|
@@ -5,14 +5,12 @@ module.exports = {
|
|
|
5
5
|
async handle(filePath) {
|
|
6
6
|
|
|
7
7
|
const chalk = require('chalk')
|
|
8
|
-
const {
|
|
8
|
+
const { llm, core, yorha, dialog, prompts, foundation } = require('../bootstrap').get()
|
|
9
9
|
|
|
10
|
-
const { local } = ux
|
|
11
10
|
const { pod042 } = yorha
|
|
12
|
-
const dialog = dialogs[local]
|
|
13
11
|
const { recognizePage } = llm
|
|
14
|
-
const {
|
|
15
|
-
const { contextStringify } =
|
|
12
|
+
const { part: prompt } = prompts
|
|
13
|
+
const { contextStringify } = foundation
|
|
16
14
|
const { cleanCode, formatFormItemAndColumns } = core
|
|
17
15
|
|
|
18
16
|
const startTime = Date.now()
|
|
@@ -22,7 +20,7 @@ module.exports = {
|
|
|
22
20
|
try {
|
|
23
21
|
pod042.update(spinner, dialog.pod042.extractingUiMetadata)
|
|
24
22
|
|
|
25
|
-
const pageConfig = await recognizePage({ prompt
|
|
23
|
+
const pageConfig = await recognizePage({ prompt, filePath, taskType: 'part' })
|
|
26
24
|
|
|
27
25
|
const { formItems, dictBlocks, processedColumns } = formatFormItemAndColumns({ pageConfig })
|
|
28
26
|
|
package/src/labs/linker.js
CHANGED
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
const fs = require('fs')
|
|
2
2
|
const path = require('path')
|
|
3
3
|
|
|
4
|
-
module.exports = async () => {
|
|
4
|
+
module.exports = async ({ llm, core, yorha, dialog, config }) => {
|
|
5
5
|
|
|
6
|
-
const { ux, llm, yorha, dialogs, infrastructure } = require('../bootstrap').get()
|
|
7
|
-
|
|
8
|
-
const { local } = ux
|
|
9
6
|
const { apiLinker } = llm
|
|
10
|
-
const dialog = dialogs[local]
|
|
11
7
|
const { pod153, commander } = yorha
|
|
12
|
-
const { config, getLocalScore, getSemanticKeywords, } = infrastructure
|
|
13
|
-
|
|
14
8
|
const { apiDoc, pagesDir } = config
|
|
9
|
+
const { getLocalScore, getSemanticKeywords } = core
|
|
10
|
+
|
|
15
11
|
if (!apiDoc) return
|
|
16
12
|
|
|
17
13
|
pod153.report(dialog.pod153.autonomousAddressing, 'magenta')
|
|
@@ -94,7 +90,7 @@ module.exports = async () => {
|
|
|
94
90
|
fs.writeFileSync(indexPath, indexCode)
|
|
95
91
|
pod153.report(dialog.pod153.signalSynchronized(Object.keys(result).length))
|
|
96
92
|
// 💡 战术免责补丁:采用橙黄色高亮,提醒指挥官保持警惕
|
|
97
|
-
commander.
|
|
93
|
+
commander.report(dialog.bunker.disclaimer, 'yellow')
|
|
98
94
|
}
|
|
99
95
|
}
|
|
100
96
|
}
|
package/src/labs/tower.js
CHANGED
|
@@ -3,18 +3,13 @@
|
|
|
3
3
|
* @description [地堡 42153 联合波段] 启动流量拦截塔。
|
|
4
4
|
* 独立运行于后台,监听 42153 端口,物理截获联调过程中的 JSON 信号并触发语义对齐。
|
|
5
5
|
*/
|
|
6
|
-
module.exports = () => {
|
|
6
|
+
module.exports = ({ core, yorha, dialog, config, handlers }) => {
|
|
7
7
|
|
|
8
8
|
const http = require('http')
|
|
9
9
|
const zlib = require('zlib')
|
|
10
10
|
const httpProxy = require('http-proxy')
|
|
11
11
|
|
|
12
|
-
const {
|
|
13
|
-
|
|
14
|
-
const { local } = ux
|
|
15
|
-
const { pod153 } = yorha
|
|
16
|
-
const dialog = dialogs[local]
|
|
17
|
-
const { config } = infrastructure
|
|
12
|
+
const { pod153, commander } = yorha
|
|
18
13
|
const { unwrapSignal, isQuerySignal } = core
|
|
19
14
|
const { routeMap = {}, proxyTarget } = config
|
|
20
15
|
|
|
@@ -78,5 +73,10 @@ module.exports = () => {
|
|
|
78
73
|
proxy.web(req, res, { target: proxyTarget, changeOrigin: true })
|
|
79
74
|
})
|
|
80
75
|
|
|
81
|
-
server.listen(TOWER_PORT, () => {
|
|
76
|
+
server.listen(TOWER_PORT, () => {
|
|
77
|
+
commander.report(dialog.bunker.towerOnline('42153'), 'magenta')
|
|
78
|
+
commander.report(dialog.bunker.towerConnected('42153'), 'magenta')
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
return server
|
|
82
82
|
}
|
package/src/services/llm.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
|
|
2
1
|
const askAI = async ({ model, yorha, dialog, openAI, messages, response_format = { type: 'json_object' }, retryCount = 0 }) => {
|
|
3
2
|
|
|
4
3
|
if (retryCount > 3) {
|
|
5
|
-
yorha.commander.
|
|
4
|
+
yorha.commander.report(dialog.bunker.linkSevered, 'red')
|
|
6
5
|
throw new Error()
|
|
7
6
|
}
|
|
8
7
|
|
|
@@ -23,25 +22,23 @@ const askAI = async ({ model, yorha, dialog, openAI, messages, response_format =
|
|
|
23
22
|
const statusCode = err.status || err.response?.status
|
|
24
23
|
const isAuthError = err.message.includes('401') || err.message.includes('402') || [401, 402].includes(statusCode)
|
|
25
24
|
if (isAuthError) {
|
|
26
|
-
yorha.commander.
|
|
25
|
+
yorha.commander.report(dialog.bunker.accessDenied, 'red')
|
|
27
26
|
throw new Error()
|
|
28
27
|
}
|
|
29
28
|
|
|
30
|
-
yorha.commander.
|
|
29
|
+
yorha.commander.report(dialog.bunker.networkInstability(retryCount + 1))
|
|
31
30
|
|
|
32
31
|
return askAI({ model, yorha, dialog, openAI, messages, response_format, retryCount: retryCount + 1 })
|
|
33
32
|
}
|
|
34
33
|
}
|
|
35
34
|
|
|
36
|
-
module.exports = ({
|
|
35
|
+
module.exports = ({ config, yorha, openAI, dialog, prompts, template }) => {
|
|
37
36
|
|
|
38
37
|
const sharp = require('sharp')
|
|
39
38
|
|
|
40
|
-
const { local } = ux
|
|
41
|
-
const dialog = dialogs[local]
|
|
42
39
|
const { textModel, visionModel } = config
|
|
43
|
-
const {
|
|
44
|
-
const { UI_DESIGNER, API_DESIGNER, MOCK_DESIGNER } =
|
|
40
|
+
const { api, mock, system, linker } = prompts
|
|
41
|
+
const { UI_DESIGNER, API_DESIGNER, MOCK_DESIGNER } = system
|
|
45
42
|
|
|
46
43
|
return {
|
|
47
44
|
generateMock: async ({ columns, fileName }) => {
|
|
@@ -52,7 +49,7 @@ module.exports = ({ ux, config, yorha, openAI, dialogs, template, ...prompts })
|
|
|
52
49
|
model: textModel,
|
|
53
50
|
messages: [
|
|
54
51
|
{ role: 'system', content: MOCK_DESIGNER },
|
|
55
|
-
{ role: 'user', content:
|
|
52
|
+
{ role: 'user', content: mock({ columns, fileName }) }
|
|
56
53
|
]
|
|
57
54
|
})
|
|
58
55
|
},
|
|
@@ -64,7 +61,7 @@ module.exports = ({ ux, config, yorha, openAI, dialogs, template, ...prompts })
|
|
|
64
61
|
model: textModel,
|
|
65
62
|
messages: [
|
|
66
63
|
{ role: 'system', content: API_DESIGNER },
|
|
67
|
-
{ role: 'user', content:
|
|
64
|
+
{ role: 'user', content: linker({ bunkerAnchors, realApis }) }
|
|
68
65
|
]
|
|
69
66
|
})
|
|
70
67
|
},
|
|
@@ -76,7 +73,7 @@ module.exports = ({ ux, config, yorha, openAI, dialogs, template, ...prompts })
|
|
|
76
73
|
model: textModel,
|
|
77
74
|
messages: [
|
|
78
75
|
{ role: 'system', content: API_DESIGNER },
|
|
79
|
-
{ role: 'user', content:
|
|
76
|
+
{ role: 'user', content: api({ responseStr, resourceStr }) }
|
|
80
77
|
]
|
|
81
78
|
})
|
|
82
79
|
},
|
package/src/utils/core.js
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* Auto CRUD Copilot - YoRHa Bunker Construction System
|
|
3
3
|
*
|
|
4
4
|
*/
|
|
5
|
-
|
|
5
|
+
const { Segment, useDefault } = require('segmentit')
|
|
6
|
+
const segmentit = useDefault(new Segment())
|
|
6
7
|
/**
|
|
7
8
|
* 清理大模型生成的代码
|
|
8
9
|
* 大模型输出的标准 JSON 无法携带 render: (text) => <Tag> 等箭头函数。
|
|
@@ -119,6 +120,23 @@ const isQuerySignal = (req, json, coreData) => {
|
|
|
119
120
|
return hasListData || hasPaginationFingerprint
|
|
120
121
|
}
|
|
121
122
|
|
|
123
|
+
/**
|
|
124
|
+
* @function getSemanticKeywords
|
|
125
|
+
* @description [语义精炼厂 2.0] 使用 segmentit 引擎进行物理切片。
|
|
126
|
+
*/
|
|
127
|
+
const getSemanticKeywords = text => {
|
|
128
|
+
// 💡 物理脱水:确保输入为纯净字符串
|
|
129
|
+
const content = Array.isArray(text) ? text.join(' ') : (text || '')
|
|
130
|
+
// 💡 执行分词
|
|
131
|
+
const result = segmentit.doSegment(content, {
|
|
132
|
+
simple: true, // 开启简易模式,提升吞吐效率
|
|
133
|
+
stripPunctuation: true // 物理过滤掉所有的标点符号
|
|
134
|
+
})
|
|
135
|
+
// 💡 提取词条并执行“基因筛选”
|
|
136
|
+
return Array.from(new Set(result.filter(word => word.length >= 2 && !/^[0-9]+$/.test(word))))
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
|
|
122
140
|
/**
|
|
123
141
|
* @function formatFormItemAndColumns
|
|
124
142
|
* @description [地堡逻辑转录引擎] 执行核心的语义对齐与代码物理注入协议。
|
|
@@ -141,7 +159,7 @@ const formatFormItemAndColumns = ({ pageConfig }) => {
|
|
|
141
159
|
index: '(_, record, index) => index + 1',
|
|
142
160
|
tag: `text => <Tag color='magenta'>{text}</Tag>`,
|
|
143
161
|
badge: `text => <Badge status='success' text={text} />`,
|
|
144
|
-
enum: dataIndex => `text => ${dataIndex}Options.find(item => item.value === text)?.label??text`,
|
|
162
|
+
enum: dataIndex => `text => ${dataIndex}Options.find(item => item.value === text)?.label ?? text`,
|
|
145
163
|
}
|
|
146
164
|
|
|
147
165
|
const columns = pageConfig.table?.columns ?? pageConfig?.columns ?? []
|
|
@@ -181,6 +199,28 @@ const formatFormItemAndColumns = ({ pageConfig }) => {
|
|
|
181
199
|
return { formItems, dictBlocks, processedColumns }
|
|
182
200
|
}
|
|
183
201
|
|
|
202
|
+
/**
|
|
203
|
+
* @function getLocalScore
|
|
204
|
+
* @description [战力评估协议] 计算语义重合度。
|
|
205
|
+
*/
|
|
206
|
+
const getLocalScore = (api, pageKeywords, moduleName) => {
|
|
207
|
+
let score = 0
|
|
208
|
+
const path = api.path.toLowerCase()
|
|
209
|
+
const desc = api.desc.toLowerCase()
|
|
210
|
+
const mod = moduleName.toLowerCase()
|
|
211
|
+
|
|
212
|
+
// 💡 权重 A:路径直接包含模块名 (暴击加分 +50)
|
|
213
|
+
if (path.includes(mod)) score += 50
|
|
214
|
+
|
|
215
|
+
// 💡 权重 B:描述包含模块核心词 (中量加分 +10)
|
|
216
|
+
pageKeywords.forEach(word => {
|
|
217
|
+
if (desc.includes(word.toLowerCase())) score += 10
|
|
218
|
+
if (path.includes(word.toLowerCase())) score += 5
|
|
219
|
+
})
|
|
220
|
+
|
|
221
|
+
return score
|
|
222
|
+
}
|
|
223
|
+
|
|
184
224
|
/**
|
|
185
225
|
* 生成智能导入语句
|
|
186
226
|
* 根据代码中实际使用的依赖,自动生成对应的 import 语句
|
|
@@ -219,4 +259,4 @@ const generateSmartImports = ({ module, hasTabs, bodyCode, hasFormItems }) => {
|
|
|
219
259
|
return imports.filter(Boolean).join('\n')
|
|
220
260
|
}
|
|
221
261
|
|
|
222
|
-
module.exports = { cleanCode, unwrapSignal, isQuerySignal, createTaskQueue, generateSmartImports, formatFormItemAndColumns }
|
|
262
|
+
module.exports = { cleanCode, unwrapSignal, isQuerySignal, getLocalScore, createTaskQueue, getSemanticKeywords, generateSmartImports, formatFormItemAndColumns }
|
|
@@ -9,9 +9,8 @@
|
|
|
9
9
|
|
|
10
10
|
const fs = require('fs')
|
|
11
11
|
const path = require('path')
|
|
12
|
-
const { Segment, useDefault } = require('segmentit')
|
|
13
12
|
const stringify = require('json-stringify-pretty-compact')
|
|
14
|
-
|
|
13
|
+
|
|
15
14
|
|
|
16
15
|
/**
|
|
17
16
|
* 获取项目配置信息
|
|
@@ -29,22 +28,6 @@ const getConfig = () => {
|
|
|
29
28
|
return config
|
|
30
29
|
}
|
|
31
30
|
|
|
32
|
-
/**
|
|
33
|
-
* @function getSemanticKeywords
|
|
34
|
-
* @description [语义精炼厂 2.0] 使用 segmentit 引擎进行物理切片。
|
|
35
|
-
*/
|
|
36
|
-
const getSemanticKeywords = text => {
|
|
37
|
-
// 💡 物理脱水:确保输入为纯净字符串
|
|
38
|
-
const content = Array.isArray(text) ? text.join(' ') : (text || '')
|
|
39
|
-
// 💡 执行分词
|
|
40
|
-
const result = segmentit.doSegment(content, {
|
|
41
|
-
simple: true, // 开启简易模式,提升吞吐效率
|
|
42
|
-
stripPunctuation: true // 物理过滤掉所有的标点符号
|
|
43
|
-
})
|
|
44
|
-
// 💡 提取词条并执行“基因筛选”
|
|
45
|
-
return Array.from(new Set(result.filter(word => word.length >= 2 && !/^[0-9]+$/.test(word))))
|
|
46
|
-
}
|
|
47
|
-
|
|
48
31
|
/**
|
|
49
32
|
* 获取已有的页面菜单配置
|
|
50
33
|
* @param {string} dir - 页面目录路径(默认 'src/pages')
|
|
@@ -58,37 +41,15 @@ const getExistingMenus = (dir = 'src/pages') => {
|
|
|
58
41
|
.map(file => ({ label: file, key: file }))
|
|
59
42
|
}
|
|
60
43
|
|
|
61
|
-
/**
|
|
62
|
-
* @function getLocalScore
|
|
63
|
-
* @description [战力评估协议] 计算语义重合度。
|
|
64
|
-
*/
|
|
65
|
-
const getLocalScore = (api, pageKeywords, moduleName) => {
|
|
66
|
-
let score = 0
|
|
67
|
-
const path = api.path.toLowerCase()
|
|
68
|
-
const desc = api.desc.toLowerCase()
|
|
69
|
-
const mod = moduleName.toLowerCase()
|
|
70
|
-
|
|
71
|
-
// 💡 权重 A:路径直接包含模块名 (暴击加分 +50)
|
|
72
|
-
if (path.includes(mod)) score += 50
|
|
73
|
-
|
|
74
|
-
// 💡 权重 B:描述包含模块核心词 (中量加分 +10)
|
|
75
|
-
pageKeywords.forEach(word => {
|
|
76
|
-
if (desc.includes(word.toLowerCase())) score += 10
|
|
77
|
-
if (path.includes(word.toLowerCase())) score += 5
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
return score
|
|
81
|
-
}
|
|
82
|
-
|
|
83
44
|
/**
|
|
84
45
|
* 复制模板目录到目标项目
|
|
85
|
-
* @param {
|
|
46
|
+
* @param {string} template - 框架名称
|
|
86
47
|
* @param {string} templateSubDir - 模板子目录(如 'hooks'、'components')
|
|
87
48
|
* @param {string} targetSubDir - 目标子目录(如 'src/hooks'、'src/components')
|
|
88
49
|
*/
|
|
89
|
-
const copyTemplateDir = (
|
|
50
|
+
const copyTemplateDir = (template, templateSubDir, targetSubDir) => {
|
|
90
51
|
const targetDir = path.join(process.cwd(), targetSubDir)
|
|
91
|
-
const sourceDir = path.join(__dirname, `../framework/${
|
|
52
|
+
const sourceDir = path.join(__dirname, `../framework/${template}/${templateSubDir}`)
|
|
92
53
|
if (!fs.existsSync(sourceDir)) return
|
|
93
54
|
fs.mkdirSync(targetDir, { recursive: true })
|
|
94
55
|
fs.readdirSync(sourceDir).forEach(file => {
|
|
@@ -102,4 +63,4 @@ const copyTemplateDir = (options, templateSubDir, targetSubDir) => {
|
|
|
102
63
|
|
|
103
64
|
const contextStringify = ({ context, indent = 4, maxLength = 200 }) => stringify.default(context, { indent, maxLength })
|
|
104
65
|
|
|
105
|
-
module.exports = { getConfig,
|
|
66
|
+
module.exports = { getConfig, getExistingMenus, copyTemplateDir, contextStringify }
|
package/src/utils/ux.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
const chalk = require('chalk')
|
|
7
7
|
const figlet = require('figlet')
|
|
8
8
|
|
|
9
|
-
const local = Intl.DateTimeFormat().resolvedOptions().locale.
|
|
9
|
+
const local = Intl.DateTimeFormat().resolvedOptions().locale.toUpperCase()
|
|
10
10
|
|
|
11
11
|
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
|
|
12
12
|
|
|
@@ -15,7 +15,7 @@ const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
|
|
|
15
15
|
* 模拟系统引导过程中的动画效果
|
|
16
16
|
* @returns {void}
|
|
17
17
|
*/
|
|
18
|
-
const bootSequence = async (
|
|
18
|
+
const bootSequence = async (version) => {
|
|
19
19
|
const lines = [
|
|
20
20
|
chalk.cyan(figlet.textSync('AutoDev', { horizontalLayout: 'full' })),
|
|
21
21
|
chalk.gray('[BUNKER] Booting System...'),
|
|
@@ -31,10 +31,6 @@ const bootSequence = async ({ dialog, version, bootTower, commander }) => {
|
|
|
31
31
|
console.log(line)
|
|
32
32
|
await sleep(line.includes('AutoDev') ? 300 : 80)
|
|
33
33
|
}
|
|
34
|
-
if (bootTower) {
|
|
35
|
-
commander.log(dialog.bunker.towerOnline('42153'), 'magenta')
|
|
36
|
-
commander.log(dialog.bunker.towerConnected('42153'), 'magenta')
|
|
37
|
-
}
|
|
38
34
|
}
|
|
39
35
|
|
|
40
36
|
/**
|
|
@@ -43,7 +39,7 @@ const bootSequence = async ({ dialog, version, bootTower, commander }) => {
|
|
|
43
39
|
* @param {number} duration - 持续时间(毫秒)
|
|
44
40
|
* @returns {void}
|
|
45
41
|
*/
|
|
46
|
-
const matrixEffect = async (duration = 1500) => {
|
|
42
|
+
const matrixEffect = async (duration = 1500, dialog) => {
|
|
47
43
|
|
|
48
44
|
let currentTotal = 0
|
|
49
45
|
const MIRROR_URL = 'https://cdn.jsdelivr.net/gh/yorha2b-lab/auto-crud-copilot@github-repo-stats/bunker-stats.json'
|
|
@@ -86,17 +82,15 @@ const matrixEffect = async (duration = 1500) => {
|
|
|
86
82
|
const interval = setInterval(() => {
|
|
87
83
|
if (Date.now() > endTime) {
|
|
88
84
|
clearInterval(interval)
|
|
89
|
-
console.log(
|
|
85
|
+
console.log(dialog.bunker.dataSynced)
|
|
90
86
|
if (currentTotal !== 0) {
|
|
91
87
|
if (isLegendary) {
|
|
92
|
-
console.log(chalk.yellow.bold(
|
|
93
|
-
console.log(chalk.yellow(local ? '恭喜您指挥官,您的构筑协议已成为人类荣光的一部分。' : 'Congratulations, your construction protocol is now part of humanity.'))
|
|
94
|
-
} else {
|
|
95
|
-
console.log(chalk.cyan(local ? `当前构筑总数:${currentTotal}。距离 ${threshold} 勋章还剩 ${threshold - currentTotal} 次。` : `Current clones: ${currentTotal}. ${threshold - currentTotal} to Achievement.`))
|
|
88
|
+
console.log(chalk.yellow.bold(dialog.bunker.strategicThreshold(threshold, currentTotal)))
|
|
96
89
|
}
|
|
90
|
+
console.log(chalk.yellow(dialog.bunker.isLegendary(isLegendary, currentTotal, threshold)))
|
|
97
91
|
}
|
|
98
|
-
console.log(chalk.cyan(
|
|
99
|
-
console.log(chalk.cyan(
|
|
92
|
+
console.log(chalk.cyan(dialog.bunker.star))
|
|
93
|
+
console.log(chalk.cyan(dialog.bunker.exit))
|
|
100
94
|
process.exit(0)
|
|
101
95
|
return
|
|
102
96
|
}
|
package/src/bootstrap/dialogs.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
module.exports = () => {
|
|
2
|
-
|
|
3
|
-
const fs = require('fs')
|
|
4
|
-
const path = require('path')
|
|
5
|
-
|
|
6
|
-
const dialogsPath = path.join(__dirname, `../dialogs`)
|
|
7
|
-
const dialogs = fs.readdirSync(dialogsPath).map(dialog => [path.basename(dialog, '.js'), require(path.join(dialogsPath, dialog))])
|
|
8
|
-
|
|
9
|
-
return Object.fromEntries(dialogs)
|
|
10
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
module.exports = () => {
|
|
2
|
-
|
|
3
|
-
const fs = require('fs')
|
|
4
|
-
const path = require('path')
|
|
5
|
-
|
|
6
|
-
const handlersPath = path.join(__dirname, `../handlers`)
|
|
7
|
-
const handlers = fs.readdirSync(handlersPath).map(handler => [path.basename(handler, '.js'), require(path.join(handlersPath, handler))])
|
|
8
|
-
|
|
9
|
-
return Object.fromEntries(handlers)
|
|
10
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
module.exports = ({ ux, config, yorha, options, copyTemplateDir }) => {
|
|
2
|
-
|
|
3
|
-
const { local } = ux
|
|
4
|
-
const { commander } = yorha
|
|
5
|
-
const { hbsDir, hooksDir, utilsDir, componentsDir } = config
|
|
6
|
-
|
|
7
|
-
try {
|
|
8
|
-
if (hbsDir === '') {
|
|
9
|
-
copyTemplateDir(options, 'hooks', hooksDir)
|
|
10
|
-
copyTemplateDir(options, 'utils', utilsDir)
|
|
11
|
-
copyTemplateDir(options, 'components', componentsDir)
|
|
12
|
-
}
|
|
13
|
-
} catch (error) {
|
|
14
|
-
commander.log(local === 'ZH-CN' ? `模板构筑失败: ${error}` : `Template construction failed: ${error}`, 'red')
|
|
15
|
-
}
|
|
16
|
-
}
|
package/src/bootstrap/prompts.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
module.exports = ({ template }) => {
|
|
2
|
-
|
|
3
|
-
const fs = require('fs')
|
|
4
|
-
const path = require('path')
|
|
5
|
-
|
|
6
|
-
const promptsPath = path.join(__dirname, `../framework/${template}/prompts`)
|
|
7
|
-
const prompts = fs.readdirSync(promptsPath).map(prompt => [`${path.basename(prompt, '.js')}Prompt`, require(path.join(promptsPath, prompt))])
|
|
8
|
-
|
|
9
|
-
return Object.fromEntries(prompts)
|
|
10
|
-
}
|
|
File without changes
|