@yorha2b-lab/autodev 7.3.5 → 7.4.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/example/example.json +13 -13
- package/package.json +3 -3
- package/src/constitution/council.js +1 -1
- package/src/labs/council.js +20 -34
- package/src/units/raider.js +6 -1
- package/src/workshop/react/blueprint/molds/handleBlock.hbs +9 -8
- package/src/workshop/react/blueprint/molds/hookBlock.hbs +1 -1
- package/src/workshop/react/blueprint/molds/renderBlock.hbs +1 -1
- package/src/workshop/react/briefings/raider.js +1 -0
- package/src/workshop/react/briefings/striker.js +4 -2
- package/src/workshop/react/builder/index.js +4 -6
- package/src/workshop/react/protocols/striker.json +6 -6
package/example/example.json
CHANGED
|
@@ -77,19 +77,19 @@
|
|
|
77
77
|
],
|
|
78
78
|
"operation": [
|
|
79
79
|
{
|
|
80
|
-
"
|
|
80
|
+
"request": "BUNKER_API_ANCHOR_viewJob",
|
|
81
81
|
"label": "查看",
|
|
82
|
-
"action": "
|
|
82
|
+
"action": "viewJob"
|
|
83
83
|
},
|
|
84
84
|
{
|
|
85
|
-
"
|
|
85
|
+
"request": "BUNKER_API_ANCHOR_editJob",
|
|
86
86
|
"label": "编辑",
|
|
87
|
-
"action": "
|
|
87
|
+
"action": "editJob"
|
|
88
88
|
},
|
|
89
89
|
{
|
|
90
|
-
"
|
|
90
|
+
"request": "BUNKER_API_ANCHOR_deleteJob",
|
|
91
91
|
"label": "删除",
|
|
92
|
-
"action": "
|
|
92
|
+
"action": "deleteJob"
|
|
93
93
|
}
|
|
94
94
|
],
|
|
95
95
|
"pagination": true,
|
|
@@ -97,8 +97,8 @@
|
|
|
97
97
|
"rowSelection": true
|
|
98
98
|
},
|
|
99
99
|
"title": {
|
|
100
|
-
"chinese": "
|
|
101
|
-
"english": "
|
|
100
|
+
"chinese": "鬼剑士职业管理",
|
|
101
|
+
"english": "GhostSwordsmanManagement"
|
|
102
102
|
},
|
|
103
103
|
"formItems": [
|
|
104
104
|
{
|
|
@@ -140,7 +140,7 @@
|
|
|
140
140
|
},
|
|
141
141
|
{
|
|
142
142
|
"label": "太刀",
|
|
143
|
-
"value": "
|
|
143
|
+
"value": "katana"
|
|
144
144
|
},
|
|
145
145
|
{
|
|
146
146
|
"label": "巨剑",
|
|
@@ -170,13 +170,13 @@
|
|
|
170
170
|
"functionButton": [
|
|
171
171
|
{
|
|
172
172
|
"btn": "批量删除",
|
|
173
|
-
"
|
|
174
|
-
"action": "
|
|
173
|
+
"request": "BUNKER_API_ANCHOR_batchDeleteJobs",
|
|
174
|
+
"action": "batchDeleteJobs"
|
|
175
175
|
},
|
|
176
176
|
{
|
|
177
177
|
"btn": "批量导出",
|
|
178
|
-
"
|
|
179
|
-
"action": "
|
|
178
|
+
"request": "BUNKER_API_ANCHOR_exportJobs",
|
|
179
|
+
"action": "exportJobs"
|
|
180
180
|
}
|
|
181
181
|
]
|
|
182
182
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yorha2b-lab/autodev",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.4.0",
|
|
4
4
|
"description": "基于 AI 视觉与语义协议的前端 (React+Antd) 代码构筑与旧系统重构引擎",
|
|
5
5
|
"bin": {
|
|
6
6
|
"bunker": "bin/bunker.js"
|
|
@@ -49,8 +49,8 @@
|
|
|
49
49
|
"json-stringify-pretty-compact": "^4.0.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"
|
|
52
|
+
"http-proxy": "^1.18.1",
|
|
53
53
|
"puppeteer": "^25.4.0",
|
|
54
|
-
"
|
|
54
|
+
"segmentit": "^2.0.3"
|
|
55
55
|
}
|
|
56
56
|
}
|
|
@@ -12,7 +12,7 @@ ${realApis}
|
|
|
12
12
|
- 识别后缀(如 edit, delete, add)。
|
|
13
13
|
- 结合 UI 语义,在 API 库中寻找对应路径。
|
|
14
14
|
- **输出格式**:请只输出一个 JSON 映射表。
|
|
15
|
-
- **例如**:{"BUNKER_API_ANCHOR_editByRecord": "
|
|
15
|
+
- **例如**:{"BUNKER_API_ANCHOR_editByRecord": {"uri": "/api/records/{recordId}", "method": "POST"}}
|
|
16
16
|
|
|
17
17
|
⚠️ 严禁解释,严禁输出 JSON 之外的内容。
|
|
18
18
|
`.trim()
|
package/src/labs/council.js
CHANGED
|
@@ -14,18 +14,15 @@ module.exports = async ({ llm, yorha, dialog, logistics }) => {
|
|
|
14
14
|
pod153.report(dialog.pod153.autonomousAddressing, 'magenta')
|
|
15
15
|
|
|
16
16
|
try {
|
|
17
|
-
// 1. 抓取情报
|
|
18
17
|
const apiData = await fetch(apiDoc).then(res => res.json())
|
|
19
18
|
const refinedApis = Object.entries(apiData.paths).flatMap(([apiUrl, methods]) => {
|
|
20
|
-
// 💡 适配多方法接口:有的路径下可能既有 GET 也有 POST
|
|
21
19
|
return Object.entries(methods).map(([method, info]) => ({
|
|
22
20
|
path: apiUrl,
|
|
23
|
-
method: method
|
|
24
|
-
desc: info.summary || info.description || 'N/A'
|
|
21
|
+
method: method?.toUpperCase() || '',
|
|
22
|
+
desc: info.summary || info.description || 'N/A',
|
|
25
23
|
}))
|
|
26
24
|
})
|
|
27
25
|
|
|
28
|
-
// 2. 战场侦察
|
|
29
26
|
const pages = path.join(process.cwd(), pagesDir)
|
|
30
27
|
const files = fs.readdirSync(pages)
|
|
31
28
|
const enumParamsMap = {}
|
|
@@ -37,18 +34,15 @@ module.exports = async ({ llm, yorha, dialog, logistics }) => {
|
|
|
37
34
|
if (fs.existsSync(indexPath) && fs.existsSync(resourcePath)) {
|
|
38
35
|
let indexCode = fs.readFileSync(indexPath, 'utf-8')
|
|
39
36
|
|
|
40
|
-
// 💡 锁定待通电锚点
|
|
41
37
|
if (indexCode.includes('BUNKER_API_ANCHOR')) {
|
|
42
38
|
const resourceCode = fs.readFileSync(resourcePath, 'utf-8')
|
|
43
39
|
const bunkerAnchors = indexCode.match(/BUNKER_API_ANCHOR_\w+/g)?.join('\n') ?? ''
|
|
44
40
|
|
|
45
|
-
// 💡 执行语义提取流程
|
|
46
41
|
const returnMatch = indexCode.match(/return\s*\(([\s\S]*?)\)\s*}/)
|
|
47
42
|
const returnStatement = returnMatch ? returnMatch[0] : ''
|
|
48
43
|
|
|
49
44
|
const moduleSemantics = `${returnStatement}${resourceCode}`.match(/[\u4e00-\u9fa5][\u4e00-\u9fa5A-Za-z0-9?。,、:;!() ]*/g) || []
|
|
50
45
|
const pageKeywords = getSemanticKeywords(moduleSemantics)
|
|
51
|
-
// 💡 物理扫描:执行“语义雷达”过滤
|
|
52
46
|
const candidates = refinedApis
|
|
53
47
|
.map(api => ({
|
|
54
48
|
...api,
|
|
@@ -56,40 +50,32 @@ module.exports = async ({ llm, yorha, dialog, logistics }) => {
|
|
|
56
50
|
}))
|
|
57
51
|
.filter(item => item.score > 0)
|
|
58
52
|
.sort((a, b) => b.score - a.score)
|
|
59
|
-
.slice(0, 20)
|
|
53
|
+
.slice(0, 20)
|
|
60
54
|
|
|
61
55
|
const finalCandidates = candidates.map(item => `${item.method} ${item.path} ${item.desc}`).join('\n')
|
|
62
56
|
const spinner = pod153.start(dialog.pod153.inactiveModule(fileName), 'yellow')
|
|
63
|
-
// 3. 驱动 9S 最终裁决
|
|
64
57
|
const result = await apiParser({ bunkerAnchors, realApis: finalCandidates })
|
|
65
58
|
|
|
66
59
|
if (result) {
|
|
67
|
-
|
|
68
|
-
Object.entries(result).forEach(([anchor,
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
// 💡 4. 执行“全频道通电”
|
|
84
|
-
// $1 现在包含了 request('/api 这一串
|
|
85
|
-
indexCode = indexCode.replace(requestRegex, `$1${cleanPath}$2${realMethod.toUpperCase()}$4`)
|
|
86
|
-
// 💡 5. 兜底替换(针对没有 method 配置的简易请求)
|
|
87
|
-
// 同样保留 /api/ 前缀
|
|
88
|
-
indexCode = indexCode.replaceAll(`/api/${anchor}`, `/api${cleanPath}`)
|
|
60
|
+
let hasQsImport = indexCode.includes(`import qs from 'qs'`)
|
|
61
|
+
Object.entries(result).forEach(([anchor, { uri, method }]) => {
|
|
62
|
+
const cleanPath = uri.startsWith('/') ? uri : `/${uri}`
|
|
63
|
+
let finalUri = cleanPath.startsWith('/api') ? cleanPath : `/api${cleanPath}`
|
|
64
|
+
finalUri = finalUri.replace(/\{(\w+)\}/g, (_, key) => '${params.' + key + '}')
|
|
65
|
+
const quotationMark = finalUri.includes('${params.') ? '\`' : "'"
|
|
66
|
+
if (method?.toUpperCase() === 'GET') {
|
|
67
|
+
indexCode = indexCode.replaceAll(anchor, `request(\`${finalUri}?\${qs.stringify(params)}\`)`)
|
|
68
|
+
if (!hasQsImport) {
|
|
69
|
+
indexCode = `import qs from 'qs'\n${indexCode}`
|
|
70
|
+
hasQsImport = true
|
|
71
|
+
}
|
|
72
|
+
} else {
|
|
73
|
+
indexCode = indexCode.replaceAll(anchor, `request(${quotationMark}${finalUri}${quotationMark}, { method: '${method?.toUpperCase()}', body: params })`)
|
|
74
|
+
}
|
|
89
75
|
})
|
|
90
76
|
|
|
91
|
-
const
|
|
92
|
-
const definitions = (apiData.paths[pagesApi]?.[pagesMethod] ?? apiData.paths[pagesApi]?.[pagesMethod
|
|
77
|
+
const { uri: pagesApi, method: pagesMethod } = result?.['BUNKER_API_ANCHOR_pages']
|
|
78
|
+
const definitions = (apiData.paths[pagesApi]?.[pagesMethod] ?? apiData.paths[pagesApi]?.[pagesMethod?.toLowerCase()])?.parameters?.flatMap(item => Object.values(item.schema ?? {})?.flatMap(def => def?.split('/')?.at(-1))) || []
|
|
93
79
|
const parameters = apiData.definitions?.[definitions[0]]?.properties ?? {}
|
|
94
80
|
const enumParams = Object.entries(parameters)?.filter(([_, value]) => value.hasOwnProperty('enum')) || []
|
|
95
81
|
enumParamsMap[fileName] = contextStringify({
|
package/src/units/raider.js
CHANGED
|
@@ -37,7 +37,12 @@ module.exports = {
|
|
|
37
37
|
|
|
38
38
|
const pageConfig = await recognizePage({ prompt: raider, filePath: mission.input })
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
let { formItems, dictBlocks, processedColumns } = formatFormItemAndColumns({ pageConfig })
|
|
41
|
+
|
|
42
|
+
processedColumns = processedColumns.map(col => {
|
|
43
|
+
delete col.type
|
|
44
|
+
return col
|
|
45
|
+
})
|
|
41
46
|
|
|
42
47
|
const result = Object.fromEntries(Object.entries({ formItems, processedColumns }).filter(([key, value]) => value?.length > 0))
|
|
43
48
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
{{#each operations}}
|
|
3
|
-
const {{this.action}} = async
|
|
4
|
-
const response = await
|
|
3
|
+
const {{this.action}} = async params => {
|
|
4
|
+
const response = await {{{this.request}}}
|
|
5
5
|
if({{{../responseSuccess}}}){
|
|
6
6
|
refresh()
|
|
7
7
|
}
|
|
@@ -16,7 +16,7 @@ const {{this.action}} = () => {
|
|
|
16
16
|
centered: true,
|
|
17
17
|
content: '确认{{this.btn}}吗?',
|
|
18
18
|
onOk: async () => {
|
|
19
|
-
const response = await
|
|
19
|
+
const response = await {{{this.request}}}
|
|
20
20
|
if({{{../responseSuccess}}}){
|
|
21
21
|
refresh()
|
|
22
22
|
}
|
|
@@ -62,12 +62,13 @@ const showImg = (record, dataIndex) => {
|
|
|
62
62
|
|
|
63
63
|
{{/if}}
|
|
64
64
|
|
|
65
|
-
const modalSubmit = async
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
65
|
+
const modalSubmit = async params => {
|
|
66
|
+
const requestMap={
|
|
67
|
+
{{#each operations}}
|
|
68
|
+
{{this.action}}:()=> {{this.request}},
|
|
69
|
+
{{/each}}
|
|
70
70
|
}
|
|
71
|
+
const response = await requestMap[modal.type]
|
|
71
72
|
if({{{responseSuccess}}}){
|
|
72
73
|
setModal({ visible: false })
|
|
73
74
|
refresh()
|
|
@@ -6,7 +6,7 @@ const query = formatQuery(Object.fromEntries(new URLSearchParams(location.search
|
|
|
6
6
|
const { total, columns, loading, dataSource, search, setSearch, setDataSource, refresh } = useTableQuery({
|
|
7
7
|
cols:tableColumns,
|
|
8
8
|
initialParams: { ...initialParams, ...query },
|
|
9
|
-
api: async params => await
|
|
9
|
+
api: async params => await {{{this.uri}}},
|
|
10
10
|
formatResponse: response => {
|
|
11
11
|
return {
|
|
12
12
|
data: response?.data?.datas ?? [],
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
return (
|
|
2
2
|
<Card {{#if hasTabs}}tabList={tabs} activeTabKey={activeKey} onTabChange={onTabChange}{{/if}}>
|
|
3
|
-
{{
|
|
3
|
+
{{~#if hasImageColumn}}{img.visible && <MyImage img={img} setImg={setImg}/>}{{~/if}}
|
|
4
4
|
{modal.visible && <MyModalForm {...modal} submit={modalSubmit} setModal={setModal} />}
|
|
5
5
|
{{#each renderTree as |treeNode|}}
|
|
6
6
|
{{> (treeNode) @root }}
|
|
@@ -5,6 +5,7 @@ module.exports = `
|
|
|
5
5
|
##模块名
|
|
6
6
|
- **来源**: 页面标题/表格列信息
|
|
7
7
|
- **目标**: 提取页面主体名称[英文]作为模块名
|
|
8
|
+
- **格式**: 驼峰命名,首字母小写,单词之间无下划线空格等一系列不合符文件夹名称的符号
|
|
8
9
|
|
|
9
10
|
## 核心命名协议 (Naming Convention)
|
|
10
11
|
- **驼峰命名**: 所有变量及函数名必须遵循 camelCase。
|
|
@@ -35,7 +36,7 @@ module.exports = `
|
|
|
35
36
|
## 表格主体 (table)
|
|
36
37
|
- **基础格式(columns)**: [{ title: '文本', dataIndex: 'englishName' }]。
|
|
37
38
|
- **配置项**: [pagination, expandable, rowSelection] 均为布尔值。
|
|
38
|
-
- **行操作 (operation)**: [{ label: '操作名', action: '操作动词+[模块名单数]',
|
|
39
|
+
- **行操作 (operation)**: [{ label: '操作名', action: '操作动词+[模块名单数]', request: 'BUNKER_API_ANCHOR_动词+[模块名单数]'}]
|
|
39
40
|
- **类型定义 (type)**:
|
|
40
41
|
- enum: 枚举列
|
|
41
42
|
- money: 金额列
|
|
@@ -44,10 +45,11 @@ module.exports = `
|
|
|
44
45
|
- date: 时间/日期列
|
|
45
46
|
- text: 普通文本(默认)
|
|
46
47
|
- tag: 标签列(有背景色的文本)
|
|
48
|
+
- link: 链接列(蓝色下划线的文本)
|
|
47
49
|
- badge: 徽标列(文本前有颜色小圆点)
|
|
48
50
|
|
|
49
51
|
## 全局功能按钮 (functionButton)
|
|
50
|
-
- **基础格式**: [{ btn: '按钮', action: '操作动词+[模块名复数]',
|
|
52
|
+
- **基础格式**: [{ btn: '按钮', action: '操作动词+[模块名复数]', request: 'BUNKER_API_ANCHOR_动词+[模块名复数]'}]。
|
|
51
53
|
- **导出数据**: action 设为 'export[模块名]'。
|
|
52
54
|
- **逻辑锁定**: 只要页面中出现了非查询、非重置的独立操作按钮,必须识别并存入 [functionButton] 数组。
|
|
53
55
|
- **构筑联动**: 若 [functionButton] 数组不为空,则在下文的 [RenderTree] 中必须包含 "FunctionButtons"。
|
|
@@ -11,6 +11,7 @@ module.exports = ({ template, logistics, headquarters }) => {
|
|
|
11
11
|
date: 'text => timeRender({time: text})',
|
|
12
12
|
index: '(_, record, index) => index + 1',
|
|
13
13
|
tag: `text => <Tag color='magenta'>{text}</Tag>`,
|
|
14
|
+
link: `text => <a href='#' target='_blank'>{text}</a>`,
|
|
14
15
|
badge: `text => <Badge status='success' text={text} />`,
|
|
15
16
|
enum: dataIndex => `text => ${dataIndex}Options.find(item => item.value === text)?.label ?? text`,
|
|
16
17
|
}
|
|
@@ -32,9 +33,6 @@ module.exports = ({ template, logistics, headquarters }) => {
|
|
|
32
33
|
})
|
|
33
34
|
|
|
34
35
|
const processedColumns = columns?.map(col => {
|
|
35
|
-
if (col.type === 'text') {
|
|
36
|
-
delete col.type
|
|
37
|
-
}
|
|
38
36
|
if (['image'].includes(col.type)) {
|
|
39
37
|
return { ...col, renderAction: true }
|
|
40
38
|
}
|
|
@@ -100,7 +98,7 @@ module.exports = ({ template, logistics, headquarters }) => {
|
|
|
100
98
|
columnsData,
|
|
101
99
|
hasFormItems,
|
|
102
100
|
tabs: pageConfig.tabs,
|
|
103
|
-
dictBlocks: dictBlocks.map(item => ({ name: item, data: optionDict[item] ?? [] })),
|
|
101
|
+
dictBlocks: dictBlocks.map(item => ({ name: item, data: optionDict[item] ?? [] })).sort((a, b) => a.name.length - b.name.length),
|
|
104
102
|
tabColumns: contextStringify({ context: Object.fromEntries(tabKeys?.map(tab => [tab, wrapCode('commonColumns')])), maxLength: 100 }),
|
|
105
103
|
formItemsData: !hasTabs ?
|
|
106
104
|
`export const formItems = ${contextStringify({ context: formItems, maxLength: 120 })}` :
|
|
@@ -145,11 +143,11 @@ module.exports = ({ template, logistics, headquarters }) => {
|
|
|
145
143
|
renderTree: pageConfig.renderTree,
|
|
146
144
|
hasExpandable: pageConfig.table.expandable,
|
|
147
145
|
staticInfoText: pageConfig.staticInfo?.text,
|
|
148
|
-
operations: pageConfig.table.operation || [],
|
|
149
146
|
hasRowSelection: pageConfig.table.rowSelection,
|
|
150
|
-
uri: needMock ? fileName : 'BUNKER_API_ANCHOR_pages',
|
|
151
147
|
formItems: hasFormItems ? (hasTabs ? 'formItems[activeKey]' : 'formItems') : '[]',
|
|
148
|
+
operations: pageConfig.table.operation?.sort((a, b) => a.action.length - b.action.length) || [],
|
|
152
149
|
initParams: `{ ${hasTabs ? 'type: tabs[0].key ,' : ''}${hasPagination ? 'pageNo: 1 , pageSize: 10' : ''}}`,
|
|
150
|
+
uri: needMock ? `request('/api/${fileName}', { method: 'POST', body: params })` : 'BUNKER_API_ANCHOR_pages',
|
|
153
151
|
}
|
|
154
152
|
|
|
155
153
|
const bodyCode = indexTpl(viewData)
|
|
@@ -83,13 +83,13 @@
|
|
|
83
83
|
"items": {
|
|
84
84
|
"type": "object",
|
|
85
85
|
"required": [
|
|
86
|
-
"uri",
|
|
87
86
|
"label",
|
|
88
|
-
"action"
|
|
87
|
+
"action",
|
|
88
|
+
"request"
|
|
89
89
|
],
|
|
90
90
|
"additionalProperties": false,
|
|
91
91
|
"properties": {
|
|
92
|
-
"
|
|
92
|
+
"request": {
|
|
93
93
|
"type": "string"
|
|
94
94
|
},
|
|
95
95
|
"label": {
|
|
@@ -230,15 +230,15 @@
|
|
|
230
230
|
"type": "object",
|
|
231
231
|
"required": [
|
|
232
232
|
"btn",
|
|
233
|
-
"
|
|
234
|
-
"
|
|
233
|
+
"action",
|
|
234
|
+
"request"
|
|
235
235
|
],
|
|
236
236
|
"additionalProperties": false,
|
|
237
237
|
"properties": {
|
|
238
238
|
"btn": {
|
|
239
239
|
"type": "string"
|
|
240
240
|
},
|
|
241
|
-
"
|
|
241
|
+
"request": {
|
|
242
242
|
"type": "string"
|
|
243
243
|
},
|
|
244
244
|
"action": {
|