@yorha2b-lab/autodev 5.0.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 +31 -45
- package/package.json +1 -1
- package/src/bootstrap/foundation.js +15 -0
- package/src/bootstrap/index.js +35 -30
- package/src/bootstrap/labs.js +21 -0
- package/src/bootstrap/registry.js +14 -0
- package/src/bootstrap/yorha.js +36 -0
- package/src/commands/watch.js +23 -27
- package/src/dialogs/EN-US.js +62 -0
- package/src/dialogs/ZH-CN.js +62 -0
- package/src/framework/react/generator/index.js +4 -1
- package/src/framework/react/prompts/page.js +29 -38
- package/src/handlers/api.js +89 -0
- package/src/handlers/page.js +68 -0
- package/src/handlers/part.js +57 -0
- package/src/labs/linker.js +11 -31
- package/src/labs/tower.js +9 -21
- package/src/services/llm.js +21 -23
- package/src/utils/core.js +43 -3
- package/src/utils/{infrastructure.js → foundation.js} +5 -44
- package/src/utils/ux.js +17 -20
- package/src/bootstrap/handlers.js +0 -10
- package/src/bootstrap/infrastructure.js +0 -15
- package/src/bootstrap/prompt.js +0 -10
- package/src/handlers/apiHandler.js +0 -111
- package/src/handlers/pageHandler.js +0 -95
- package/src/handlers/partHandler.js +0 -77
- /package/src/bootstrap/{handlebars.js → handlebar.js} +0 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
const path = require('path')
|
|
3
|
+
|
|
4
|
+
module.exports = {
|
|
5
|
+
watch: 'response',
|
|
6
|
+
async handle(filePath, liveResponse = null) {
|
|
7
|
+
|
|
8
|
+
const chalk = require('chalk')
|
|
9
|
+
const { llm, core, yorha, dialog, config } = require('../bootstrap').get()
|
|
10
|
+
|
|
11
|
+
const { pagesDir } = config
|
|
12
|
+
const { unwrapSignal } = core
|
|
13
|
+
const { nineS, pod153 } = yorha
|
|
14
|
+
const { alignResponseFields } = llm
|
|
15
|
+
|
|
16
|
+
const startTime = Date.now()
|
|
17
|
+
const fileName = liveResponse?.fileName ?? path.basename(filePath, path.extname(filePath))
|
|
18
|
+
const resourcePath = path.join(process.cwd(), pagesDir, fileName, 'resource.js')
|
|
19
|
+
|
|
20
|
+
const spinner = pod153.start(dialog.pod153.reconEncryptedData(fileName))
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
if (!fs.existsSync(resourcePath)) {
|
|
24
|
+
pod153.fail(spinner, dialog.pod153.unknownModule(fileName))
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let rawJson = liveResponse ? liveResponse.data : JSON.parse(fs.readFileSync(filePath, 'utf8'))
|
|
29
|
+
let resourceStr = fs.readFileSync(resourcePath, 'utf8')
|
|
30
|
+
|
|
31
|
+
const coreArray = unwrapSignal(rawJson)
|
|
32
|
+
if (!coreArray || coreArray.length === 0) {
|
|
33
|
+
pod153.warning(spinner, dialog.pod153.formatError)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
nineS.update(spinner, dialog.nineS.scanningField)
|
|
37
|
+
|
|
38
|
+
const extractKeys = str => {
|
|
39
|
+
const keys = []
|
|
40
|
+
const regex = /(dataIndex|name)\s*:\s*['"]([^'"]+)['"]/g
|
|
41
|
+
let match
|
|
42
|
+
while ((match = regex.exec(str)) !== null) {
|
|
43
|
+
keys.push(match[2])
|
|
44
|
+
}
|
|
45
|
+
return Array.from(new Set(keys))
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const sampleData = coreArray && coreArray.length > 0 ? [coreArray[0]] : rawJson
|
|
49
|
+
const result = await alignResponseFields({ responseStr: JSON.stringify(sampleData), resourceStr: extractKeys(resourceStr).join(',') })
|
|
50
|
+
let changeCount = 0
|
|
51
|
+
const resultMapping = {}
|
|
52
|
+
Object.entries(result).forEach(([oldField, newField]) => {
|
|
53
|
+
if (oldField === newField) return
|
|
54
|
+
const regex = new RegExp(`(dataIndex|name)\\s*:\\s*['"]${oldField}['"]`, 'g')
|
|
55
|
+
resourceStr = resourceStr.replace(regex, `$1: '${newField}'`)
|
|
56
|
+
changeCount++
|
|
57
|
+
resultMapping[oldField] = newField
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
fs.writeFileSync(resourcePath, resourceStr)
|
|
61
|
+
const endTime = Date.now()
|
|
62
|
+
|
|
63
|
+
pod153.success(spinner, dialog.pod153.bridgeProtocolComplete(changeCount, (endTime - startTime) / 1000))
|
|
64
|
+
|
|
65
|
+
if (changeCount > 0) {
|
|
66
|
+
console.log(chalk.magenta(`\n┌────── [ YoRHa Autonomous Backend Alignment ] ──────┐`))
|
|
67
|
+
const maxOldFieldLength = Math.max(...Object.keys(resultMapping).map(key => key.length))
|
|
68
|
+
Object.entries(resultMapping).forEach(([oldField, newField]) => {
|
|
69
|
+
const padding = ' '.repeat(Math.max(1, maxOldFieldLength + 1 - oldField.length))
|
|
70
|
+
console.log(
|
|
71
|
+
chalk.yellow(` │ `) +
|
|
72
|
+
chalk.yellow(oldField) +
|
|
73
|
+
padding +
|
|
74
|
+
chalk.cyan(` -> `) +
|
|
75
|
+
chalk.white(newField)
|
|
76
|
+
)
|
|
77
|
+
})
|
|
78
|
+
console.log(chalk.magenta(`└────────────────────────────────────────────────────┘`))
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (fs.existsSync(filePath)) {
|
|
82
|
+
fs.unlinkSync(filePath)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
} catch (error) {
|
|
86
|
+
pod153.fail(spinner, dialog.pod153.alignmentFailed(error))
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
const path = require('path')
|
|
3
|
+
|
|
4
|
+
module.exports = {
|
|
5
|
+
watch: 'screenShot',
|
|
6
|
+
async handle(filePath) {
|
|
7
|
+
|
|
8
|
+
const { llm, menus, yorha, dialog, config, prompts, generator, foundation } = require('../bootstrap').get()
|
|
9
|
+
|
|
10
|
+
const { page } = prompts
|
|
11
|
+
const { nineS, pod042 } = yorha
|
|
12
|
+
const { index, resource } = generator
|
|
13
|
+
const { contextStringify } = foundation
|
|
14
|
+
const { generateMock, recognizePage } = llm
|
|
15
|
+
const { useDemo, pagesDir, needMock } = config
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
const startTime = Date.now()
|
|
19
|
+
const fileName = path.basename(filePath, path.extname(filePath))
|
|
20
|
+
const mockDir = path.join(process.cwd(), 'mock')
|
|
21
|
+
const targetDir = path.join(process.cwd(), pagesDir, fileName)
|
|
22
|
+
|
|
23
|
+
const spinner = pod042.start(dialog.pod042.visualCaptured(fileName))
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
if (fs.existsSync(targetDir)) {
|
|
27
|
+
pod042.warning(spinner, dialog.pod042.intercept(fileName))
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (!fs.existsSync(mockDir)) fs.mkdirSync(mockDir, { recursive: true })
|
|
32
|
+
if (!fs.existsSync(targetDir)) fs.mkdirSync(targetDir, { recursive: true })
|
|
33
|
+
|
|
34
|
+
let pageConfig
|
|
35
|
+
if (useDemo) {
|
|
36
|
+
pod042.report(dialog.pod042.simulate)
|
|
37
|
+
pageConfig = require('../../example/example.json')
|
|
38
|
+
} else {
|
|
39
|
+
pod042.update(spinner, dialog.pod042.uploadVisualMetadata)
|
|
40
|
+
pageConfig = await recognizePage({ prompt: page(fileName), filePath })
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
fs.writeFileSync(path.join(targetDir, 'resource.js'), resource({ pageConfig }))
|
|
44
|
+
fs.writeFileSync(path.join(targetDir, 'index.js'), index({ fileName, pageConfig }))
|
|
45
|
+
|
|
46
|
+
if (!menus.find(m => m.key === fileName)) {
|
|
47
|
+
menus.push({ label: fileName, key: fileName })
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (needMock) {
|
|
51
|
+
nineS.update(spinner, dialog.nineS.dataCamouflage(fileName))
|
|
52
|
+
const rawContent = await generateMock({ columns: pageConfig.table.columns, fileName })
|
|
53
|
+
fs.writeFileSync(path.join(mockDir, `${fileName}.js`), `export default ${contextStringify({ context: rawContent })}`)
|
|
54
|
+
nineS.success(spinner, dialog.nineS.dataCamouflageComplete)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const endTime = Date.now()
|
|
58
|
+
pod042.success(spinner, dialog.pod042.assemblyComplete(fileName, (endTime - startTime) / 1000))
|
|
59
|
+
|
|
60
|
+
if (fs.existsSync(filePath)) {
|
|
61
|
+
fs.unlinkSync(filePath)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
} catch (error) {
|
|
65
|
+
pod042.fail(spinner, dialog.pod042.constructionAborted(error))
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
watch: 'screenPart',
|
|
5
|
+
async handle(filePath) {
|
|
6
|
+
|
|
7
|
+
const chalk = require('chalk')
|
|
8
|
+
const { llm, core, yorha, dialog, prompts, foundation } = require('../bootstrap').get()
|
|
9
|
+
|
|
10
|
+
const { pod042 } = yorha
|
|
11
|
+
const { recognizePage } = llm
|
|
12
|
+
const { part: prompt } = prompts
|
|
13
|
+
const { contextStringify } = foundation
|
|
14
|
+
const { cleanCode, formatFormItemAndColumns } = core
|
|
15
|
+
|
|
16
|
+
const startTime = Date.now()
|
|
17
|
+
|
|
18
|
+
const spinner = pod042.start(dialog.pod042.visualPartCaptured)
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
pod042.update(spinner, dialog.pod042.extractingUiMetadata)
|
|
22
|
+
|
|
23
|
+
const pageConfig = await recognizePage({ prompt, filePath, taskType: 'part' })
|
|
24
|
+
|
|
25
|
+
const { formItems, dictBlocks, processedColumns } = formatFormItemAndColumns({ pageConfig })
|
|
26
|
+
|
|
27
|
+
const result = Object.fromEntries(Object.entries({ formItems, processedColumns }).filter(([key, value]) => value?.length > 0))
|
|
28
|
+
|
|
29
|
+
let mainConfigStr = cleanCode(contextStringify({ context: result }))
|
|
30
|
+
|
|
31
|
+
let optionsCodeStr = ''
|
|
32
|
+
dictBlocks.forEach(key => {
|
|
33
|
+
const optionsArray = pageConfig.optionDict?.[key] ?? []
|
|
34
|
+
const arrayItemsStr = optionsArray.map(opt => ` { label: '${opt.label}', value: '${opt.value}' }`).join(',\n')
|
|
35
|
+
optionsCodeStr += `\nexport const ${key} = [\n${arrayItemsStr}\n]\n`
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
const finalResult = `${mainConfigStr}\n${optionsCodeStr}`
|
|
39
|
+
const endTime = Date.now()
|
|
40
|
+
spinner.stop()
|
|
41
|
+
console.log(chalk.magenta(`\n┌────────────────── [ YoRHa Construction Output ] ─────────────────┐`))
|
|
42
|
+
console.log(chalk.magenta(`│ Source: ${filePath}`))
|
|
43
|
+
console.log(chalk.magenta(`│ Protocol: Partial UI Fragment | Status: SUCCESS`))
|
|
44
|
+
console.log(chalk.magenta(`├───────────────────────────────────────────────────────────────────┘`))
|
|
45
|
+
console.log(chalk.white(finalResult))
|
|
46
|
+
pod042.success(spinner, dialog.pod042.partialConstruction((endTime - startTime) / 1000))
|
|
47
|
+
pod042.success(spinner, dialog.pod042.partialRecommendation)
|
|
48
|
+
|
|
49
|
+
if (fs.existsSync(filePath)) {
|
|
50
|
+
fs.unlinkSync(filePath)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
} catch (error) {
|
|
54
|
+
pod042.fail(spinner, dialog.pod042.partialConstructionAborted(error))
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
package/src/labs/linker.js
CHANGED
|
@@ -1,22 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
const path = require('path')
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
const path = require('path')
|
|
5
|
-
const chalk = require('chalk')
|
|
4
|
+
module.exports = async ({ llm, core, yorha, dialog, config }) => {
|
|
6
5
|
|
|
7
|
-
const { ux, llm, infrastructure } = require('../bootstrap').get()
|
|
8
|
-
|
|
9
|
-
const { language } = ux
|
|
10
6
|
const { apiLinker } = llm
|
|
11
|
-
const {
|
|
12
|
-
|
|
7
|
+
const { pod153, commander } = yorha
|
|
13
8
|
const { apiDoc, pagesDir } = config
|
|
9
|
+
const { getLocalScore, getSemanticKeywords } = core
|
|
10
|
+
|
|
14
11
|
if (!apiDoc) return
|
|
15
12
|
|
|
16
|
-
|
|
17
|
-
`\n🤖 Pod 153: 启动‘全频道自动寻址协议 [语义扫描版]’...`,
|
|
18
|
-
`\n🤖 Pod 153: Initiating 'Full-Channel Autonomous Addressing Protocol [Semantic Scan]'...`
|
|
19
|
-
)))
|
|
13
|
+
pod153.report(dialog.pod153.autonomousAddressing, 'magenta')
|
|
20
14
|
|
|
21
15
|
try {
|
|
22
16
|
// 1. 抓取情报
|
|
@@ -63,12 +57,7 @@ module.exports = async () => {
|
|
|
63
57
|
.slice(0, 20) // 💡 拓宽至前 20 名,给 AI 更多的判别空间
|
|
64
58
|
|
|
65
59
|
const finalCandidates = candidates.map(item => `${item.method} ${item.path} ${item.desc}`).join('\n')
|
|
66
|
-
|
|
67
|
-
console.log(chalk.yellow(language(
|
|
68
|
-
` 🛰️ Inactive module: [${fileName}]. Requesting 9S for precise alignment...`,
|
|
69
|
-
` 🛰️ 发现未通电模块 [${fileName}],请求 9S 执行高精度对账...`
|
|
70
|
-
)))
|
|
71
|
-
|
|
60
|
+
pod153.report(dialog.pod153.inactiveModule(fileName), 'yellow')
|
|
72
61
|
// 3. 驱动 9S 最终裁决
|
|
73
62
|
const result = await apiLinker({ bunkerAnchors, realApis: finalCandidates })
|
|
74
63
|
|
|
@@ -99,23 +88,14 @@ module.exports = async () => {
|
|
|
99
88
|
indexCode = indexCode.replaceAll(`/api/${anchor}`, `/api${cleanPath}`)
|
|
100
89
|
})
|
|
101
90
|
fs.writeFileSync(indexPath, indexCode)
|
|
102
|
-
|
|
103
|
-
`✅ 信号同步完成,${Object.keys(result).length} 个节点已通电。`,
|
|
104
|
-
`✅ Signal Synchronized: ${Object.keys(result).length} nodes energized.`
|
|
105
|
-
)))
|
|
91
|
+
pod153.report(dialog.pod153.signalSynchronized(Object.keys(result).length))
|
|
106
92
|
// 💡 战术免责补丁:采用橙黄色高亮,提醒指挥官保持警惕
|
|
107
|
-
|
|
108
|
-
`⚠️ 匹配结果仅供参考,不构成最终决策,各机体需根据实际情况进行调整。`,
|
|
109
|
-
`⚠️ Match Result Reference Only. Not Final Decision. Each Unit should adjust based on battlefield conditions.`
|
|
110
|
-
)))
|
|
93
|
+
commander.report(dialog.bunker.disclaimer, 'yellow')
|
|
111
94
|
}
|
|
112
95
|
}
|
|
113
96
|
}
|
|
114
97
|
}
|
|
115
98
|
} catch (e) {
|
|
116
|
-
|
|
117
|
-
`\n❌ Pod 153: 信号链路故障: ${e.message}\n`,
|
|
118
|
-
`\n❌ Pod 153: Signal Link Fault: ${e.message}\n`
|
|
119
|
-
)))
|
|
99
|
+
pod153.report(dialog.pod153.signalLinkFault(e.message), 'red')
|
|
120
100
|
}
|
|
121
101
|
}
|
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
|
-
const chalk = require('chalk')
|
|
11
10
|
const httpProxy = require('http-proxy')
|
|
12
11
|
|
|
13
|
-
const {
|
|
14
|
-
|
|
15
|
-
const { language } = ux
|
|
16
|
-
const { apiHandler } = handlers
|
|
17
|
-
const { config } = infrastructure
|
|
12
|
+
const { pod153, commander } = yorha
|
|
18
13
|
const { unwrapSignal, isQuerySignal } = core
|
|
19
14
|
const { routeMap = {}, proxyTarget } = config
|
|
20
15
|
|
|
@@ -58,16 +53,13 @@ module.exports = () => {
|
|
|
58
53
|
return
|
|
59
54
|
}
|
|
60
55
|
|
|
61
|
-
|
|
62
|
-
`\n📡 Pod 153: 截获运行时信号 [${fileName}]。执行自动对齐协议...`,
|
|
63
|
-
`\n📡 Pod 153: Captured runtime signal [${fileName}]. Executing semantic alignment protocol...`
|
|
64
|
-
)))
|
|
56
|
+
pod153.report(dialog.pod153.capturedRuntimeSignal(fileName))
|
|
65
57
|
// 💡 直接调用 api-handler 物理更新 resource.js
|
|
66
|
-
await
|
|
58
|
+
await handlers.api.handle(null, { fileName, data: json })
|
|
67
59
|
hackedRegistry.set(fileName, fingerprint)
|
|
68
60
|
} catch (e) {
|
|
69
|
-
console.log(e)
|
|
70
61
|
// 非 JSON 信号,保持静默
|
|
62
|
+
console.log(e)
|
|
71
63
|
}
|
|
72
64
|
})
|
|
73
65
|
})
|
|
@@ -82,13 +74,9 @@ module.exports = () => {
|
|
|
82
74
|
})
|
|
83
75
|
|
|
84
76
|
server.listen(TOWER_PORT, () => {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
`✨ YoRHa Joint Station: Signal Intercept Tower Online [Band: ${TOWER_PORT}]`
|
|
88
|
-
)))
|
|
89
|
-
console.log(chalk.gray(language(
|
|
90
|
-
`💡 指令:请将您的代理目标指向 http://localhost:${TOWER_PORT}`,
|
|
91
|
-
`💡 Command: Please point your local proxy target to http://localhost:${TOWER_PORT}`
|
|
92
|
-
)))
|
|
77
|
+
commander.report(dialog.bunker.towerOnline('42153'), 'magenta')
|
|
78
|
+
commander.report(dialog.bunker.towerConnected('42153'), 'magenta')
|
|
93
79
|
})
|
|
80
|
+
|
|
81
|
+
return server
|
|
94
82
|
}
|
package/src/services/llm.js
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
const chalk = require('chalk')
|
|
3
|
-
const { language } = require('../utils/ux')
|
|
4
|
-
|
|
5
|
-
const askAI = async ({ model, openAI, messages, response_format = { type: 'json_object' }, retryCount = 0 }) => {
|
|
1
|
+
const askAI = async ({ model, yorha, dialog, openAI, messages, response_format = { type: 'json_object' }, retryCount = 0 }) => {
|
|
6
2
|
|
|
7
3
|
if (retryCount > 3) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
'YoRHa Command Link Severed: Check network status or Black Box resonance.'
|
|
11
|
-
))
|
|
4
|
+
yorha.commander.report(dialog.bunker.linkSevered, 'red')
|
|
5
|
+
throw new Error()
|
|
12
6
|
}
|
|
13
7
|
|
|
14
8
|
try {
|
|
@@ -28,56 +22,58 @@ const askAI = async ({ model, openAI, messages, response_format = { type: 'json_
|
|
|
28
22
|
const statusCode = err.status || err.response?.status
|
|
29
23
|
const isAuthError = err.message.includes('401') || err.message.includes('402') || [401, 402].includes(statusCode)
|
|
30
24
|
if (isAuthError) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
'[SYSTEM ALERT] YoRHa Command Center Access Denied: Invalid API Key or quota exhausted!'
|
|
34
|
-
))
|
|
25
|
+
yorha.commander.report(dialog.bunker.accessDenied, 'red')
|
|
26
|
+
throw new Error()
|
|
35
27
|
}
|
|
36
28
|
|
|
37
|
-
|
|
38
|
-
`[系统警告] 神经云网络连接不稳,正在尝试重新链接... (第 ${retryCount + 1} 次重试)`,
|
|
39
|
-
`[SYSTEM ALERT] Neural Network instability detected. Attempting to re-establish link... (Retry #${retryCount + 1})`
|
|
40
|
-
)), err.message)
|
|
29
|
+
yorha.commander.report(dialog.bunker.networkInstability(retryCount + 1))
|
|
41
30
|
|
|
42
|
-
return askAI({ model, messages, response_format, retryCount: retryCount + 1 })
|
|
31
|
+
return askAI({ model, yorha, dialog, openAI, messages, response_format, retryCount: retryCount + 1 })
|
|
43
32
|
}
|
|
44
33
|
}
|
|
45
34
|
|
|
46
|
-
module.exports = ({ config,
|
|
35
|
+
module.exports = ({ config, yorha, openAI, dialog, prompts, template }) => {
|
|
47
36
|
|
|
48
37
|
const sharp = require('sharp')
|
|
49
38
|
|
|
50
39
|
const { textModel, visionModel } = config
|
|
51
|
-
const {
|
|
40
|
+
const { api, mock, system, linker } = prompts
|
|
41
|
+
const { UI_DESIGNER, API_DESIGNER, MOCK_DESIGNER } = system
|
|
52
42
|
|
|
53
43
|
return {
|
|
54
44
|
generateMock: async ({ columns, fileName }) => {
|
|
55
45
|
return askAI({
|
|
46
|
+
yorha,
|
|
56
47
|
openAI,
|
|
48
|
+
dialog,
|
|
57
49
|
model: textModel,
|
|
58
50
|
messages: [
|
|
59
51
|
{ role: 'system', content: MOCK_DESIGNER },
|
|
60
|
-
{ role: 'user', content:
|
|
52
|
+
{ role: 'user', content: mock({ columns, fileName }) }
|
|
61
53
|
]
|
|
62
54
|
})
|
|
63
55
|
},
|
|
64
56
|
apiLinker: async ({ bunkerAnchors, realApis }) => {
|
|
65
57
|
return askAI({
|
|
58
|
+
yorha,
|
|
66
59
|
openAI,
|
|
60
|
+
dialog,
|
|
67
61
|
model: textModel,
|
|
68
62
|
messages: [
|
|
69
63
|
{ role: 'system', content: API_DESIGNER },
|
|
70
|
-
{ role: 'user', content:
|
|
64
|
+
{ role: 'user', content: linker({ bunkerAnchors, realApis }) }
|
|
71
65
|
]
|
|
72
66
|
})
|
|
73
67
|
},
|
|
74
68
|
alignResponseFields: async ({ responseStr, resourceStr }) => {
|
|
75
69
|
return askAI({
|
|
70
|
+
yorha,
|
|
76
71
|
openAI,
|
|
72
|
+
dialog,
|
|
77
73
|
model: textModel,
|
|
78
74
|
messages: [
|
|
79
75
|
{ role: 'system', content: API_DESIGNER },
|
|
80
|
-
{ role: 'user', content:
|
|
76
|
+
{ role: 'user', content: api({ responseStr, resourceStr }) }
|
|
81
77
|
]
|
|
82
78
|
})
|
|
83
79
|
},
|
|
@@ -89,7 +85,9 @@ module.exports = ({ config, openAI, template, systemPrompt, apiPrompt, mockPromp
|
|
|
89
85
|
const base64Image = compressedBuffer.toString('base64')
|
|
90
86
|
|
|
91
87
|
return askAI({
|
|
88
|
+
yorha,
|
|
92
89
|
openAI,
|
|
90
|
+
dialog,
|
|
93
91
|
model: visionModel,
|
|
94
92
|
messages: [
|
|
95
93
|
{ role: 'system', content: UI_DESIGNER },
|
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 }
|