@yorha2b-lab/autodev 5.5.0 → 5.6.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/.github/scripts/analyze/deep_intelligence.py +159 -0
- package/.github/scripts/deploy/publish.py +1 -3
- package/.github/scripts/render/dashboard.py +59 -15
- package/.github/workflows/bunker-intelligence.yml +2 -3
- package/bin/autodev.js +6 -19
- package/package.json +1 -1
- package/src/{services/llm.js → ai/index.js} +16 -16
- package/src/{bootstrap → ai}/openai.js +2 -2
- package/src/bootstrap/index.js +16 -17
- package/src/commands/watch.js +7 -6
- package/src/framework/react/generator/index.js +4 -5
- package/src/framework/react/handlebars/partials/handleBlock.hbs +1 -1
- package/src/handlers/api.js +4 -3
- package/src/handlers/page.js +8 -4
- package/src/handlers/part.js +4 -5
- package/src/{bootstrap/foundation.js → kernel/deployment.js} +5 -5
- package/src/{bootstrap/handlebar.js → kernel/engine.js} +5 -5
- package/src/kernel/queue.js +36 -0
- package/src/kernel/recruiter.js +14 -0
- package/src/labs/council.js +4 -5
- package/src/{bootstrap/labs.js → labs/index.js} +1 -1
- package/src/labs/tower.js +4 -4
- package/src/utils/foundation.js +7 -33
- package/src/utils/generator.js +98 -0
- package/src/utils/installer.js +15 -0
- package/src/utils/semantic.js +58 -0
- package/src/utils/ux.js +43 -20
- package/.github/scripts/analyze/bot_detect.py +0 -43
- package/.github/scripts/analyze/cluster.py +0 -40
- package/src/bootstrap/yorha.js +0 -36
- package/src/utils/core.js +0 -262
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
const fs = require('fs')
|
|
2
2
|
const path = require('path')
|
|
3
3
|
|
|
4
|
-
module.exports = ({
|
|
4
|
+
module.exports = ({ utils, yorha, dialog, handlers, template }) => {
|
|
5
5
|
|
|
6
|
-
const { copyTemplateDir } = foundation
|
|
7
|
-
const { hbsDir, hooksDir, utilsDir, componentsDir } =
|
|
6
|
+
const { copyTemplateDir } = utils.foundation
|
|
7
|
+
const { hbsDir, hooksDir, utilsDir, componentsDir } = utils.foundation.getConfig()
|
|
8
8
|
|
|
9
9
|
try {
|
|
10
|
-
Object.values(handlers).forEach(handler => fs.mkdirSync(path.join(process.cwd(), handler.watch), { recursive: true }))
|
|
11
|
-
if (hbsDir
|
|
10
|
+
Object.values(handlers).forEach(handler => fs.mkdirSync(path.join(process.cwd(), 'bunker', handler.watch), { recursive: true }))
|
|
11
|
+
if (!hbsDir) {
|
|
12
12
|
copyTemplateDir(template, 'hooks', hooksDir)
|
|
13
13
|
copyTemplateDir(template, 'utils', utilsDir)
|
|
14
14
|
copyTemplateDir(template, 'components', componentsDir)
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
module.exports = ({
|
|
1
|
+
module.exports = ({ utils, template }) => {
|
|
2
2
|
|
|
3
3
|
const fs = require('fs')
|
|
4
4
|
const path = require('path')
|
|
5
5
|
const Handlebars = require('handlebars')
|
|
6
6
|
|
|
7
7
|
Handlebars.registerHelper('raw', opt => opt.fn())
|
|
8
|
-
Handlebars.registerHelper('stringify', (context, maxLength = 200) => context ? new Handlebars.SafeString(contextStringify({ context, maxLength })) : '[]')
|
|
8
|
+
Handlebars.registerHelper('stringify', (context, maxLength = 200) => context ? new Handlebars.SafeString(utils.generator.contextStringify({ context, maxLength })) : '[]')
|
|
9
9
|
|
|
10
|
-
const { hbsDir } =
|
|
11
|
-
const tplDir = hbsDir
|
|
12
|
-
const partialsDir = hbsDir
|
|
10
|
+
const { hbsDir } = utils.foundation.getConfig()
|
|
11
|
+
const tplDir = !!hbsDir ? path.join(process.cwd(), hbsDir) : path.join(__dirname, `../framework/${template}/handlebars`)
|
|
12
|
+
const partialsDir = !!hbsDir ? path.join(process.cwd(), hbsDir, 'partials') : path.join(__dirname, `../framework/${template}/handlebars/partials`)
|
|
13
13
|
|
|
14
14
|
fs.readdirSync(partialsDir).forEach(file => {
|
|
15
15
|
if (file.endsWith('.hbs')) {
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module.exports = (concurrency = 1) => {
|
|
2
|
+
|
|
3
|
+
let running = 0
|
|
4
|
+
let queue = []
|
|
5
|
+
let onIdleCallback = null
|
|
6
|
+
|
|
7
|
+
const next = async () => {
|
|
8
|
+
|
|
9
|
+
if (running >= concurrency || queue.length === 0) return
|
|
10
|
+
|
|
11
|
+
const task = queue.shift()
|
|
12
|
+
running++
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
await task()
|
|
16
|
+
} catch (err) {
|
|
17
|
+
console.error('任务执行异常:', err)
|
|
18
|
+
} finally {
|
|
19
|
+
running--
|
|
20
|
+
next()
|
|
21
|
+
if (running === 0 && queue.length === 0 && onIdleCallback) {
|
|
22
|
+
onIdleCallback()
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
add: (task) => {
|
|
29
|
+
queue.push(task)
|
|
30
|
+
next()
|
|
31
|
+
},
|
|
32
|
+
onIdle: (callback) => {
|
|
33
|
+
onIdleCallback = callback
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto CRUD Copilot - YoRHa Bunker Construction System
|
|
3
|
+
* This file is part of AutoDev.
|
|
4
|
+
* AutoDev is free software: you can redistribute it and/or modify
|
|
5
|
+
* it under the terms of the GNU Affero General Public License as
|
|
6
|
+
* published by the Free Software Foundation, either version 3 of the
|
|
7
|
+
* License, or (at your option) any later version.
|
|
8
|
+
* (c) 2026 [yorha2b-lab]. Glory to Mankind.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const fs = require('fs')
|
|
12
|
+
const path = require('path')
|
|
13
|
+
|
|
14
|
+
module.exports = dir => Object.fromEntries(fs.readdirSync(dir).filter(file => file.endsWith('.js')).map(file => [path.basename(file, '.js'), require(path.join(dir, file))]))
|
package/src/labs/council.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
const fs = require('fs')
|
|
2
2
|
const path = require('path')
|
|
3
3
|
|
|
4
|
-
module.exports = async ({ llm,
|
|
4
|
+
module.exports = async ({ llm, utils, yorha, dialog }) => {
|
|
5
5
|
|
|
6
6
|
const { apiParser } = llm
|
|
7
7
|
const { pod153, commander } = yorha
|
|
8
|
-
const {
|
|
9
|
-
const {
|
|
10
|
-
const { getLocalScore, getSemanticKeywords } =
|
|
8
|
+
const { contextStringify } = utils.generator
|
|
9
|
+
const { apiDoc, pagesDir } = utils.foundation.getConfig()
|
|
10
|
+
const { getLocalScore, getSemanticKeywords } = utils.semantic
|
|
11
11
|
|
|
12
12
|
if (!apiDoc) return
|
|
13
13
|
|
|
@@ -36,7 +36,6 @@ module.exports = async ({ llm, core, yorha, dialog, config, foundation }) => {
|
|
|
36
36
|
|
|
37
37
|
if (fs.existsSync(indexPath) && fs.existsSync(resourcePath)) {
|
|
38
38
|
let indexCode = fs.readFileSync(indexPath, 'utf-8')
|
|
39
|
-
let resourceCode = fs.readFileSync(resourcePath, 'utf-8')
|
|
40
39
|
|
|
41
40
|
// 💡 锁定待通电锚点
|
|
42
41
|
if (indexCode.includes('BUNKER_API_ANCHOR')) {
|
|
@@ -2,7 +2,7 @@ module.exports = accessPoint => {
|
|
|
2
2
|
|
|
3
3
|
const labs = {}
|
|
4
4
|
|
|
5
|
-
const { apiDoc, needMock, proxyTarget, enableAutoAlignment } = accessPoint.
|
|
5
|
+
const { apiDoc, needMock, proxyTarget, enableAutoAlignment } = accessPoint.utils.foundation.getConfig()
|
|
6
6
|
|
|
7
7
|
if (!needMock && proxyTarget && enableAutoAlignment) {
|
|
8
8
|
labs.tower = require('../labs/tower')(accessPoint)
|
package/src/labs/tower.js
CHANGED
|
@@ -3,15 +3,15 @@
|
|
|
3
3
|
* @description [地堡 42153 联合波段] 启动流量拦截塔。
|
|
4
4
|
* 独立运行于后台,监听 42153 端口,物理截获联调过程中的 JSON 信号并触发语义对齐。
|
|
5
5
|
*/
|
|
6
|
-
module.exports = ({
|
|
6
|
+
module.exports = ({ utils, yorha, dialog, 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
12
|
const { pod153, commander } = yorha
|
|
13
|
-
const { unwrapSignal, isQuerySignal } =
|
|
14
|
-
const { routeMap = {}, proxyTarget } =
|
|
13
|
+
const { unwrapSignal, isQuerySignal } = utils.semantic
|
|
14
|
+
const { routeMap = {}, proxyTarget } = utils.foundation.getConfig()
|
|
15
15
|
|
|
16
16
|
const TOWER_PORT = 42153
|
|
17
17
|
const hackedRegistry = new Map()
|
|
@@ -45,7 +45,7 @@ module.exports = ({ core, yorha, dialog, config, handlers }) => {
|
|
|
45
45
|
const urlPath = new URL(referer).pathname
|
|
46
46
|
const fileName = routeMap?.[urlPath] ?? urlPath.split('/').filter(Boolean).at(-1)
|
|
47
47
|
|
|
48
|
-
const fingerprint = getJsonFingerprint(
|
|
48
|
+
const fingerprint = getJsonFingerprint(coreData) // 获取数据指纹
|
|
49
49
|
const lastFingerprint = hackedRegistry.get(fileName)
|
|
50
50
|
|
|
51
51
|
// 如果指纹没变,说明字段结构是一样的,无需再次骇入
|
package/src/utils/foundation.js
CHANGED
|
@@ -1,37 +1,17 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This file is part of AutoDev.
|
|
3
|
-
* AutoDev is free software: you can redistribute it and/or modify
|
|
4
|
-
* it under the terms of the GNU Affero General Public License as
|
|
5
|
-
* published by the Free Software Foundation, either version 3 of the
|
|
6
|
-
* License, or (at your option) any later version.
|
|
7
|
-
*
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
1
|
const fs = require('fs')
|
|
11
2
|
const path = require('path')
|
|
12
|
-
const stringify = require('json-stringify-pretty-compact')
|
|
13
3
|
|
|
14
|
-
/**
|
|
15
|
-
* 获取项目配置信息
|
|
16
|
-
* 优先读取项目根目录的 config.js,如果不存在则使用默认配置
|
|
17
|
-
* @returns {Object} 合并后的配置对象
|
|
18
|
-
*/
|
|
19
4
|
const getConfig = () => {
|
|
20
|
-
const localConfigPath = path.join(process.cwd(), 'config.js') //
|
|
5
|
+
const localConfigPath = path.join(process.cwd(), 'bunker', 'config.js') // 项目配置
|
|
21
6
|
const defaultConfigPath = path.resolve(__dirname, '../../config.js') // 默认配置
|
|
22
7
|
let config = require(defaultConfigPath)
|
|
23
8
|
if (fs.existsSync(localConfigPath)) {
|
|
24
9
|
const userConfig = require(localConfigPath)
|
|
25
|
-
config = { ...config, ...userConfig }
|
|
10
|
+
config = { ...config, ...userConfig }
|
|
26
11
|
}
|
|
27
12
|
return config
|
|
28
13
|
}
|
|
29
14
|
|
|
30
|
-
/**
|
|
31
|
-
* 获取已有的页面菜单配置
|
|
32
|
-
* @param {string} dir - 页面目录路径(默认 'src/pages')
|
|
33
|
-
* @returns {Array} 菜单数组 [{ label: '页面名', key: '页面名' }]
|
|
34
|
-
*/
|
|
35
15
|
const getExistingMenus = (dir = 'src/pages') => {
|
|
36
16
|
const pagesDir = path.join(process.cwd(), dir)
|
|
37
17
|
if (!fs.existsSync(pagesDir)) return []
|
|
@@ -40,12 +20,6 @@ const getExistingMenus = (dir = 'src/pages') => {
|
|
|
40
20
|
.map(file => ({ label: file, key: file }))
|
|
41
21
|
}
|
|
42
22
|
|
|
43
|
-
/**
|
|
44
|
-
* 复制模板目录到目标项目
|
|
45
|
-
* @param {string} template - 框架名称
|
|
46
|
-
* @param {string} templateSubDir - 模板子目录(如 'hooks'、'components')
|
|
47
|
-
* @param {string} targetSubDir - 目标子目录(如 'src/hooks'、'src/components')
|
|
48
|
-
*/
|
|
49
23
|
const copyTemplateDir = (template, templateSubDir, targetSubDir) => {
|
|
50
24
|
const targetDir = path.join(process.cwd(), targetSubDir)
|
|
51
25
|
const sourceDir = path.join(__dirname, `../framework/${template}/${templateSubDir}`)
|
|
@@ -60,8 +34,8 @@ const copyTemplateDir = (template, templateSubDir, targetSubDir) => {
|
|
|
60
34
|
})
|
|
61
35
|
}
|
|
62
36
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
37
|
+
module.exports = {
|
|
38
|
+
getConfig,
|
|
39
|
+
copyTemplateDir,
|
|
40
|
+
getExistingMenus,
|
|
41
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
const stringify = require('json-stringify-pretty-compact')
|
|
2
|
+
|
|
3
|
+
const cleanCode = str => str
|
|
4
|
+
.replace(/```[a-z]*\n?/gi, '')// 物理超度 Markdown 糖衣(解决```json 报错)
|
|
5
|
+
.replace(/```/g, '')
|
|
6
|
+
.replace(/\\"/g, '"') // 逻辑自愈 处理 AI 错误转义的引号(把 \" 还原回 ")
|
|
7
|
+
.replace(/['"]?_CODE_([\s\S]*?)_CODE_['"]?/g, '$1') // 去掉 _CODE_ 包裹的代码
|
|
8
|
+
.replace(/_CODE_/g, '') // 兜底清理
|
|
9
|
+
.replace(/"(\w+)":/g, '$1:') // 去掉 key 的双引号
|
|
10
|
+
.replace(/"/g, "'") // 双引号全部转单引号
|
|
11
|
+
.replace(/[ \t]+$/gm, '') // 去除每一行行尾的多余空格
|
|
12
|
+
.replace(/\n{3,}/g, '\n\n') // 将3个或以上的换行符压缩成2个换行符
|
|
13
|
+
.replace(/^\s+/, '') // 去掉文件头部的空行
|
|
14
|
+
.trim() + '\n'
|
|
15
|
+
|
|
16
|
+
const formatFormItemAndColumns = ({ pageConfig }) => {
|
|
17
|
+
|
|
18
|
+
const codePresets = {
|
|
19
|
+
money: 'text => moneyRender(text)',
|
|
20
|
+
date: 'text => timeRender({time: text})',
|
|
21
|
+
index: '(_, record, index) => index + 1',
|
|
22
|
+
tag: `text => <Tag color='magenta'>{text}</Tag>`,
|
|
23
|
+
badge: `text => <Badge status='success' text={text} />`,
|
|
24
|
+
enum: dataIndex => `text => ${dataIndex}Options.find(item => item.value === text)?.label ?? text`,
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const columns = pageConfig.table?.columns ?? pageConfig?.columns ?? []
|
|
28
|
+
|
|
29
|
+
const tableDicts = columns?.filter(item => item.type === 'enum')?.map(item => `${item.dataIndex}Options`) ?? []
|
|
30
|
+
const formDicts = pageConfig.formItems?.filter(item => item.type === 'select')?.map(item => `${item.name}Options`) ?? []
|
|
31
|
+
const dictBlocks = Array.from(new Set([...formDicts, ...tableDicts]))
|
|
32
|
+
|
|
33
|
+
const formItems = pageConfig.formItems?.map(item => {
|
|
34
|
+
if (item.type === 'text') {
|
|
35
|
+
delete item.type
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
...item,
|
|
39
|
+
...(item.type === 'select' ? { options: `_CODE_${item.name}Options_CODE_` } : {})
|
|
40
|
+
}
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
const processedColumns = columns?.map(col => {
|
|
44
|
+
if (col.type === 'text') {
|
|
45
|
+
delete col.type
|
|
46
|
+
}
|
|
47
|
+
if (['image'].includes(col.type)) {
|
|
48
|
+
return { ...col, renderAction: true }
|
|
49
|
+
}
|
|
50
|
+
if (col.type && codePresets[col.type]) {
|
|
51
|
+
const renderCode = typeof codePresets[col.type] === 'function' ? codePresets[col.type](col.dataIndex) : codePresets[col.type]
|
|
52
|
+
return { ...col, render: `_CODE_${renderCode}_CODE_` }
|
|
53
|
+
}
|
|
54
|
+
return col
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
return { formItems, dictBlocks, processedColumns }
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const generateSmartImports = ({ module, hasTabs, bodyCode, hasFormItems }) => {
|
|
61
|
+
|
|
62
|
+
const hooksLib = ['useTableQuery']
|
|
63
|
+
const utilsLib = ['timeRender', 'moneyRender']
|
|
64
|
+
const reactLib = ['useState', 'useEffect', 'useRef', 'useMemo']
|
|
65
|
+
const componentsLib = ['MyTable', 'MyImage', 'MyModalForm', 'MySearchForm']
|
|
66
|
+
const antdLib = ['Tag', 'Card', 'Badge', 'Space', 'Modal', 'Alert', 'Image', 'Table', 'Input', 'Select', 'Button']
|
|
67
|
+
|
|
68
|
+
const usedAntd = antdLib.filter(name => new RegExp(`\\b${name}\\b`).test(bodyCode))
|
|
69
|
+
const usedUtils = utilsLib.filter(name => new RegExp(`\\b${name}\\b`).test(bodyCode))
|
|
70
|
+
const usedHooks = hooksLib.filter(name => new RegExp(`\\b${name}\\b`).test(bodyCode))
|
|
71
|
+
const usedReact = reactLib.filter(name => new RegExp(`\\b${name}\\b`).test(bodyCode))
|
|
72
|
+
const usedComps = componentsLib.filter(name => new RegExp(`\\b${name}\\b`).test(bodyCode))
|
|
73
|
+
|
|
74
|
+
const imports = [
|
|
75
|
+
usedReact.length && `import { ${usedReact.join(', ')} } from 'react'`,
|
|
76
|
+
usedAntd.length && `import { ${hasFormItems && module === 'index' ? 'Form, ' : ''}${usedAntd.join(', ')} } from 'antd'`,
|
|
77
|
+
...usedHooks.map(hook => `import { ${hook} } from '../../hooks/${hook}'`),
|
|
78
|
+
...usedComps.map(comp => `import { ${comp} } from '../../components/${comp}'`),
|
|
79
|
+
...(module === 'index' ? [
|
|
80
|
+
`import { request } from '../../utils/request'`,
|
|
81
|
+
`import { formatQuery } from '../../utils/utils'`,
|
|
82
|
+
`import { ${hasTabs ? 'tabs, ' : ''}${hasFormItems ? 'formItems, ' : ''}modalItems, tableColumns} from './resource'`
|
|
83
|
+
] : [
|
|
84
|
+
usedUtils.length && `import { ${usedUtils.join(', ')} } from '../../utils/utils'`
|
|
85
|
+
]),
|
|
86
|
+
].sort((a, b) => a.length - b.length)
|
|
87
|
+
|
|
88
|
+
return imports.filter(Boolean).join('\n')
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const contextStringify = ({ context, indent = 4, maxLength = 200 }) => stringify.default(context, { indent, maxLength })
|
|
92
|
+
|
|
93
|
+
module.exports = {
|
|
94
|
+
cleanCode,
|
|
95
|
+
contextStringify,
|
|
96
|
+
generateSmartImports,
|
|
97
|
+
formatFormItemAndColumns,
|
|
98
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
const path = require('path')
|
|
3
|
+
const chalk = require('chalk')
|
|
4
|
+
|
|
5
|
+
module.exports = ({ root, dialog }) => ({
|
|
6
|
+
dirs: dir => fs.mkdirSync(path.join(root, dir), { recursive: true }),
|
|
7
|
+
files: ({ from, to, exist, success }) => {
|
|
8
|
+
const target = path.join(root, 'bunker', to)
|
|
9
|
+
if (fs.existsSync(target)) {
|
|
10
|
+
return console.log(chalk.yellow(dialog.bunker[exist]))
|
|
11
|
+
}
|
|
12
|
+
fs.cpSync(path.resolve(__dirname, `../../${from}`), target, { recursive: true })
|
|
13
|
+
console.log(chalk.green(dialog.bunker[success]))
|
|
14
|
+
}
|
|
15
|
+
})
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
const { Segment, useDefault } = require('segmentit')
|
|
2
|
+
const segmentit = useDefault(new Segment())
|
|
3
|
+
|
|
4
|
+
const unwrapSignal = json => {
|
|
5
|
+
if (Array.isArray(json)) return json
|
|
6
|
+
const dataKeys = ['data', 'list', 'items', 'datas', 'rows', 'result', 'payload', 'results', 'dataList']
|
|
7
|
+
for (const key of dataKeys) {
|
|
8
|
+
if (json[key] && Array.isArray(json[key])) return json[key]
|
|
9
|
+
}
|
|
10
|
+
for (const key in json) {
|
|
11
|
+
if (json[key] && typeof json[key] === 'object') {
|
|
12
|
+
const nested = unwrapSignal(json[key])
|
|
13
|
+
if (Array.isArray(nested)) return nested
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return null
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const getSemanticKeywords = text => {
|
|
20
|
+
const content = Array.isArray(text) ? text.join(' ') : (text || '')
|
|
21
|
+
const result = segmentit.doSegment(content, {
|
|
22
|
+
simple: true, // 开启简易模式,提升吞吐效率
|
|
23
|
+
stripPunctuation: true // 过滤掉所有的标点符号
|
|
24
|
+
})
|
|
25
|
+
return Array.from(new Set(result.filter(word => word.length >= 2 && !/^[0-9]+$/.test(word))))
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const isQuerySignal = (req, json, coreData) => {
|
|
29
|
+
const url = req.url.toLowerCase()
|
|
30
|
+
const actionKeywords = ['add', 'delete', 'update', 'save', 'remove', 'edit', 'insert', 'create', 'export', 'upload']
|
|
31
|
+
if (actionKeywords.some(key => url.includes(key))) return false
|
|
32
|
+
const hasListData = Array.isArray(coreData) && coreData.length > 0
|
|
33
|
+
const hasPaginationFingerprint = ['total', 'records', 'page', 'size', 'count'].some(key => {
|
|
34
|
+
const k = key.toLowerCase()
|
|
35
|
+
return Object.keys(json).some(rawKey => rawKey.toLowerCase().includes(k))
|
|
36
|
+
})
|
|
37
|
+
return hasListData || hasPaginationFingerprint
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const getLocalScore = (api, pageKeywords, moduleName) => {
|
|
41
|
+
let score = 0
|
|
42
|
+
const path = api.path.toLowerCase()
|
|
43
|
+
const desc = api.desc.toLowerCase()
|
|
44
|
+
const mod = moduleName.toLowerCase()
|
|
45
|
+
if (path.includes(mod)) score += 50
|
|
46
|
+
pageKeywords.forEach(word => {
|
|
47
|
+
if (desc.includes(word.toLowerCase())) score += 10
|
|
48
|
+
if (path.includes(word.toLowerCase())) score += 5
|
|
49
|
+
})
|
|
50
|
+
return score
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
module.exports = {
|
|
54
|
+
unwrapSignal,
|
|
55
|
+
isQuerySignal,
|
|
56
|
+
getLocalScore,
|
|
57
|
+
getSemanticKeywords,
|
|
58
|
+
}
|
package/src/utils/ux.js
CHANGED
|
@@ -1,21 +1,45 @@
|
|
|
1
|
-
|
|
2
|
-
* (c) 2026 [yorha2b-lab]. Glory to Mankind.
|
|
3
|
-
*
|
|
4
|
-
*/
|
|
5
|
-
|
|
1
|
+
const ora = require('ora')
|
|
6
2
|
const chalk = require('chalk')
|
|
7
3
|
const figlet = require('figlet')
|
|
8
4
|
|
|
9
|
-
const local = Intl.DateTimeFormat().resolvedOptions().locale.toUpperCase()
|
|
10
|
-
|
|
11
5
|
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
|
|
12
6
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
7
|
+
const yorha = () => {
|
|
8
|
+
|
|
9
|
+
const createMember = ({ name }) => ({
|
|
10
|
+
start(text) {
|
|
11
|
+
const spinner = ora({ text: chalk.cyan(`${name} ${text}\n`) }).start()
|
|
12
|
+
return spinner
|
|
13
|
+
},
|
|
14
|
+
fail(spinner, text) {
|
|
15
|
+
spinner.fail(chalk.red(`${name} ${text}\n`))
|
|
16
|
+
},
|
|
17
|
+
report(text, color = 'yellow') {
|
|
18
|
+
console.log(chalk[color](`${name} ${text}\n`))
|
|
19
|
+
},
|
|
20
|
+
update(spinner, text) {
|
|
21
|
+
spinner.text = chalk.cyan(`${name} ${text}\n`)
|
|
22
|
+
},
|
|
23
|
+
warning(spinner, text) {
|
|
24
|
+
spinner.warn(chalk.yellow(`${name} ${text}\n`))
|
|
25
|
+
},
|
|
26
|
+
success(spinner, text) {
|
|
27
|
+
spinner.succeed(chalk.green(`${name} ${text}\n`))
|
|
28
|
+
},
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
nineS: createMember({ name: '[YoRHa::9S]' }),
|
|
33
|
+
commander: createMember({ name: '[BUNKER]' }),
|
|
34
|
+
pod042: createMember({ name: '[YoRHa::Pod042]' }),
|
|
35
|
+
pod153: createMember({ name: '[YoRHa::Pod153]' }),
|
|
36
|
+
operator6O: createMember({ name: '[YoRHa::6O]' }),
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const bootSequence = async (version, local) => {
|
|
42
|
+
|
|
19
43
|
const lines = [
|
|
20
44
|
chalk.cyan(figlet.textSync('AutoDev', { horizontalLayout: 'full' })),
|
|
21
45
|
chalk.gray('[BUNKER] Booting System...'),
|
|
@@ -27,18 +51,13 @@ const bootSequence = async (version) => {
|
|
|
27
51
|
chalk.white('[BUNKER] ') + chalk.magenta('Glory to mankind. (人类荣光永存)'),
|
|
28
52
|
chalk.gray('--------------------------------------------------')
|
|
29
53
|
]
|
|
54
|
+
|
|
30
55
|
for (const line of lines) {
|
|
31
56
|
console.log(line)
|
|
32
57
|
await sleep(line.includes('AutoDev') ? 300 : 80)
|
|
33
58
|
}
|
|
34
59
|
}
|
|
35
60
|
|
|
36
|
-
/**
|
|
37
|
-
* 矩阵效果
|
|
38
|
-
* 模拟数据物理封存过程中的矩阵效果
|
|
39
|
-
* @param {number} duration - 持续时间(毫秒)
|
|
40
|
-
* @returns {void}
|
|
41
|
-
*/
|
|
42
61
|
const matrixEffect = async (duration = 1500, dialog) => {
|
|
43
62
|
|
|
44
63
|
let currentTotal = 0
|
|
@@ -109,4 +128,8 @@ const matrixEffect = async (duration = 1500, dialog) => {
|
|
|
109
128
|
}, 40)
|
|
110
129
|
}
|
|
111
130
|
|
|
112
|
-
module.exports = {
|
|
131
|
+
module.exports = {
|
|
132
|
+
yorha,
|
|
133
|
+
bootSequence,
|
|
134
|
+
matrixEffect
|
|
135
|
+
}
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import pandas as pd
|
|
3
|
-
import matplotlib.pyplot as plt
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def plot_bot_composition():
|
|
7
|
-
print('🤖 Pod 042: 正在绘制‘肉机成分分析图’...')
|
|
8
|
-
df_c = pd.read_csv('ghrs-data/clones_ledger.csv')
|
|
9
|
-
df_v = pd.read_csv('ghrs-data/views_ledger.csv')
|
|
10
|
-
df = pd.merge(df_c, df_v, on='date', how='inner')
|
|
11
|
-
|
|
12
|
-
# 算法:Shadow Ratio > 5 判定为机器
|
|
13
|
-
df['is_bot'] = (df['clones'] / df['views'].replace(0, 1)) > 5
|
|
14
|
-
bot_clones = df[df['is_bot']]['clones'].sum()
|
|
15
|
-
total_clones = df['clones'].sum()
|
|
16
|
-
human_clones = total_clones - bot_clones
|
|
17
|
-
|
|
18
|
-
# 💡 绘图:地堡级甜甜圈图
|
|
19
|
-
plt.style.use('dark_background')
|
|
20
|
-
fig, ax = plt.subplots(figsize=(8, 8))
|
|
21
|
-
|
|
22
|
-
data = [human_clones, bot_clones]
|
|
23
|
-
labels = ['Human Commanders', 'Machine Lifeforms']
|
|
24
|
-
colors = ['#33cc33', '#444444'] # 地堡绿 vs 灰
|
|
25
|
-
|
|
26
|
-
wedges, texts, autotexts = ax.pie(data, labels=labels, autopct='%1.1f%%',
|
|
27
|
-
startangle=90, colors=colors, pctdistance=0.85,
|
|
28
|
-
explode=(0.05, 0), textprops={'color': 'w'})
|
|
29
|
-
|
|
30
|
-
# 画个中间的黑洞,变成甜甜圈
|
|
31
|
-
centre_circle = plt.Circle((0, 0), 0.70, fc='#0d1117')
|
|
32
|
-
fig.gca().add_artist(centre_circle)
|
|
33
|
-
|
|
34
|
-
ax.set_title('Operational Composition: Meat vs Machine',
|
|
35
|
-
color='#33cc33', fontsize=14)
|
|
36
|
-
plt.tight_layout()
|
|
37
|
-
os.makedirs('plots', exist_ok=True)
|
|
38
|
-
plt.savefig('plots/bot_composition.png', dpi=100)
|
|
39
|
-
print('✅ 甜甜圈图封存成功。')
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
if __name__ == '__main__':
|
|
43
|
-
plot_bot_composition()
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import pandas as pd
|
|
2
|
-
import seaborn as sns
|
|
3
|
-
import matplotlib.pyplot as plt
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def plot_commander_profiles():
|
|
7
|
-
print('🤖 Pod 042: 正在绘制‘指挥官军衔分布图’...')
|
|
8
|
-
df_c = pd.read_csv('ghrs-data/clones_ledger.csv')
|
|
9
|
-
df_c['intensity'] = df_c['clones'] / df_c['uniques'].replace(0, 1)
|
|
10
|
-
|
|
11
|
-
# 定义军衔逻辑
|
|
12
|
-
def get_rank(row):
|
|
13
|
-
if row['intensity'] > 5:
|
|
14
|
-
return 'Industrial (CI/CD)'
|
|
15
|
-
if row['intensity'] > 1.5:
|
|
16
|
-
return 'Veteran (Hardcore)'
|
|
17
|
-
return 'Recruit (Fresh)'
|
|
18
|
-
|
|
19
|
-
df_c['rank'] = df_c.apply(get_rank, axis=1)
|
|
20
|
-
rank_counts = df_c['rank'].value_counts()
|
|
21
|
-
|
|
22
|
-
# 💡 绘图:战力梯度图
|
|
23
|
-
plt.style.use('dark_background')
|
|
24
|
-
plt.figure(figsize=(10, 6))
|
|
25
|
-
|
|
26
|
-
# 用 seaborn 画出更有质感的柱状图
|
|
27
|
-
ax = sns.barplot(x=rank_counts.index,
|
|
28
|
-
y=rank_counts.values, palette='viridis')
|
|
29
|
-
|
|
30
|
-
plt.title('Commander Hierarchy Distribution', color='#0066ff', fontsize=14)
|
|
31
|
-
plt.ylabel('Node Count', color='#888')
|
|
32
|
-
plt.grid(axis='y', color='#333', linestyle='--', alpha=0.5)
|
|
33
|
-
|
|
34
|
-
plt.tight_layout()
|
|
35
|
-
plt.savefig('plots/commander_profiles.png', dpi=100)
|
|
36
|
-
print('✅ 军衔分布图封存成功。')
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
if __name__ == '__main__':
|
|
40
|
-
plot_commander_profiles()
|
package/src/bootstrap/yorha.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
module.exports = () => {
|
|
2
|
-
|
|
3
|
-
const ora = require('ora')
|
|
4
|
-
const chalk = require('chalk')
|
|
5
|
-
|
|
6
|
-
const createMember = ({ name }) => ({
|
|
7
|
-
start(text) {
|
|
8
|
-
const spinner = ora({ text: chalk.cyan(`\n${name} ${text}`) }).start()
|
|
9
|
-
return spinner
|
|
10
|
-
},
|
|
11
|
-
fail(spinner, text) {
|
|
12
|
-
spinner.fail(chalk.red(`\n${name} ${text}`))
|
|
13
|
-
},
|
|
14
|
-
report(text, color = 'yellow') {
|
|
15
|
-
console.log(chalk[color](`\n${name} ${text}`))
|
|
16
|
-
},
|
|
17
|
-
update(spinner, text) {
|
|
18
|
-
spinner.text = chalk.cyan(`\n${name} ${text}`)
|
|
19
|
-
},
|
|
20
|
-
warning(spinner, text) {
|
|
21
|
-
spinner.warn(chalk.yellow(`\n${name} ${text}`))
|
|
22
|
-
},
|
|
23
|
-
success(spinner, text) {
|
|
24
|
-
spinner.succeed(chalk.green(`\n${name} ${text}`))
|
|
25
|
-
},
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
return {
|
|
29
|
-
nineS: createMember({ name: '[YoRHa::9S]' }),
|
|
30
|
-
commander: createMember({ name: '[BUNKER]' }),
|
|
31
|
-
pod042: createMember({ name: '[YoRHa::Pod042]' }),
|
|
32
|
-
pod153: createMember({ name: '[YoRHa::Pod153]' }),
|
|
33
|
-
operator6O: createMember({ name: '[YoRHa::6O]' }),
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
}
|