@yorha2b-lab/autodev 4.1.1 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/scripts/analyze/bot_detect.py +5 -5
- package/.github/scripts/analyze/cluster.py +5 -5
- package/.github/scripts/collect/traffic.py +11 -11
- package/.github/scripts/deploy/publish.py +15 -15
- package/.github/scripts/render/dashboard.py +4 -0
- package/.github/workflows/bunker-intelligence.yml +4 -4
- package/CONTRIBUTING.md +0 -18
- package/bin/autodev.js +9 -8
- package/config.js +3 -3
- package/package.json +1 -3
- package/src/bootstrap/handlebars.js +26 -0
- package/src/bootstrap/handlers.js +10 -0
- package/src/bootstrap/index.js +49 -0
- package/src/bootstrap/infrastructure.js +15 -0
- package/src/bootstrap/openai.js +13 -0
- package/src/bootstrap/prompt.js +10 -0
- package/src/commands/watch.js +21 -34
- package/{templates → src/framework}/react/components/MyModalForm.js +1 -1
- package/{templates → src/framework}/react/components/MyModalTable.js +1 -1
- package/{templates → src/framework}/react/components/index.js +2 -2
- package/src/framework/react/generator/index.js +82 -0
- package/{templates/react/handlebars → src/framework/react/handlebars/partials}/handleBlock.hbs +2 -2
- package/src/{prompts/react/watch-api.js → framework/react/prompts/api.js} +1 -1
- package/src/{prompts/react/api-linker.js → framework/react/prompts/linker.js} +1 -1
- package/src/{prompts → framework/react/prompts}/mock.js +1 -1
- package/src/{prompts/react/watch-page.js → framework/react/prompts/page.js} +1 -0
- package/src/{prompts/react/watch-part.js → framework/react/prompts/part.js} +2 -1
- package/{templates → src/framework}/react/utils/utils.js +1 -1
- package/src/{commands/handlers/api-handler.js → handlers/apiHandler.js} +15 -10
- package/src/{commands/handlers/page-handler.js → handlers/pageHandler.js} +22 -21
- package/src/{commands/handlers/part-handler.js → handlers/partHandler.js} +14 -11
- package/src/{services/api-linker.js → labs/linker.js} +20 -59
- package/src/{services/proxy-tower.js → labs/tower.js} +16 -12
- package/src/services/llm.js +64 -81
- package/src/utils/{utils.js → core.js} +38 -163
- package/src/utils/infrastructure.js +105 -0
- package/src/utils/ux.js +115 -0
- package/src/core/context.js +0 -106
- package/src/core/react-compiler.js +0 -98
- package/src/core/task-queue.js +0 -38
- /package/{templates → src/framework}/react/components/EditableCell.js +0 -0
- /package/{templates → src/framework}/react/components/MyBaseForm.js +0 -0
- /package/{templates → src/framework}/react/components/MyImage.js +0 -0
- /package/{templates → src/framework}/react/components/MySearchForm.js +0 -0
- /package/{templates → src/framework}/react/components/MyTable.js +0 -0
- /package/{templates/react → src/framework/react/handlebars}/index.hbs +0 -0
- /package/{templates/react/handlebars → src/framework/react/handlebars/partials}/AlertInfo.hbs +0 -0
- /package/{templates/react/handlebars → src/framework/react/handlebars/partials}/FunctionButtons.hbs +0 -0
- /package/{templates/react/handlebars → src/framework/react/handlebars/partials}/MySearchForm.hbs +0 -0
- /package/{templates/react/handlebars → src/framework/react/handlebars/partials}/MyTable.hbs +0 -0
- /package/{templates/react/handlebars → src/framework/react/handlebars/partials}/hookBlock.hbs +0 -0
- /package/{templates/react/handlebars → src/framework/react/handlebars/partials}/operateBlock.hbs +0 -0
- /package/{templates/react/handlebars → src/framework/react/handlebars/partials}/renderBlock.hbs +0 -0
- /package/{templates/react/handlebars → src/framework/react/handlebars/partials}/stateBlock.hbs +0 -0
- /package/{templates/react → src/framework/react/handlebars}/resource.hbs +0 -0
- /package/{templates → src/framework}/react/hooks/useTableQuery.js +0 -0
- /package/src/{prompts → framework/react/prompts}/system.js +0 -0
- /package/src/{schema/react → framework/react/schema}/page.json +0 -0
|
@@ -4,7 +4,7 @@ import matplotlib.pyplot as plt
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
def plot_bot_composition():
|
|
7
|
-
print(
|
|
7
|
+
print('🤖 Pod 042: 正在绘制‘肉机成分分析图’...')
|
|
8
8
|
df_c = pd.read_csv('ghrs-data/clones_ledger.csv')
|
|
9
9
|
df_v = pd.read_csv('ghrs-data/views_ledger.csv')
|
|
10
10
|
df = pd.merge(df_c, df_v, on='date', how='inner')
|
|
@@ -25,19 +25,19 @@ def plot_bot_composition():
|
|
|
25
25
|
|
|
26
26
|
wedges, texts, autotexts = ax.pie(data, labels=labels, autopct='%1.1f%%',
|
|
27
27
|
startangle=90, colors=colors, pctdistance=0.85,
|
|
28
|
-
explode=(0.05, 0), textprops={'color':
|
|
28
|
+
explode=(0.05, 0), textprops={'color': 'w'})
|
|
29
29
|
|
|
30
30
|
# 画个中间的黑洞,变成甜甜圈
|
|
31
31
|
centre_circle = plt.Circle((0, 0), 0.70, fc='#0d1117')
|
|
32
32
|
fig.gca().add_artist(centre_circle)
|
|
33
33
|
|
|
34
|
-
ax.set_title(
|
|
34
|
+
ax.set_title('Operational Composition: Meat vs Machine',
|
|
35
35
|
color='#33cc33', fontsize=14)
|
|
36
36
|
plt.tight_layout()
|
|
37
37
|
os.makedirs('plots', exist_ok=True)
|
|
38
38
|
plt.savefig('plots/bot_composition.png', dpi=100)
|
|
39
|
-
print(
|
|
39
|
+
print('✅ 甜甜圈图封存成功。')
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
if __name__ ==
|
|
42
|
+
if __name__ == '__main__':
|
|
43
43
|
plot_bot_composition()
|
|
@@ -4,7 +4,7 @@ import matplotlib.pyplot as plt
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
def plot_commander_profiles():
|
|
7
|
-
print(
|
|
7
|
+
print('🤖 Pod 042: 正在绘制‘指挥官军衔分布图’...')
|
|
8
8
|
df_c = pd.read_csv('ghrs-data/clones_ledger.csv')
|
|
9
9
|
df_c['intensity'] = df_c['clones'] / df_c['uniques'].replace(0, 1)
|
|
10
10
|
|
|
@@ -27,14 +27,14 @@ def plot_commander_profiles():
|
|
|
27
27
|
ax = sns.barplot(x=rank_counts.index,
|
|
28
28
|
y=rank_counts.values, palette='viridis')
|
|
29
29
|
|
|
30
|
-
plt.title(
|
|
31
|
-
plt.ylabel(
|
|
30
|
+
plt.title('Commander Hierarchy Distribution', color='#0066ff', fontsize=14)
|
|
31
|
+
plt.ylabel('Node Count', color='#888')
|
|
32
32
|
plt.grid(axis='y', color='#333', linestyle='--', alpha=0.5)
|
|
33
33
|
|
|
34
34
|
plt.tight_layout()
|
|
35
35
|
plt.savefig('plots/commander_profiles.png', dpi=100)
|
|
36
|
-
print(
|
|
36
|
+
print('✅ 军衔分布图封存成功。')
|
|
37
37
|
|
|
38
38
|
|
|
39
|
-
if __name__ ==
|
|
39
|
+
if __name__ == '__main__':
|
|
40
40
|
plot_commander_profiles()
|
|
@@ -7,7 +7,7 @@ REPO = os.getenv('REPO')
|
|
|
7
7
|
TOKEN = os.getenv('STATS_TOKEN')
|
|
8
8
|
HEADERS = {'Authorization': f'token {TOKEN}',
|
|
9
9
|
'Accept': 'application/vnd.github.v3+json'}
|
|
10
|
-
API_BASE = f
|
|
10
|
+
API_BASE = f'https://api.github.com/repos/{REPO}'
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
def fetch_api(url, fallback):
|
|
@@ -36,14 +36,14 @@ def merge_ledger(data, ledger_path, col_name):
|
|
|
36
36
|
ledger_path, index=False)
|
|
37
37
|
|
|
38
38
|
|
|
39
|
-
if __name__ ==
|
|
40
|
-
print(
|
|
39
|
+
if __name__ == '__main__':
|
|
40
|
+
print('🤖 Pod 042: Executing Data Mining Protocol...')
|
|
41
41
|
|
|
42
42
|
# 抓取原始数据
|
|
43
|
-
clones = fetch_api(f
|
|
44
|
-
views = fetch_api(f
|
|
45
|
-
repo_info = fetch_api(API_BASE, {
|
|
46
|
-
referrers = fetch_api(f
|
|
43
|
+
clones = fetch_api(f'{API_BASE}/traffic/clones', {'clones': []})
|
|
44
|
+
views = fetch_api(f'{API_BASE}/traffic/views', {'views': []})
|
|
45
|
+
repo_info = fetch_api(API_BASE, {'stargazers_count': 0, 'forks_count': 0})
|
|
46
|
+
referrers = fetch_api(f'{API_BASE}/traffic/popular/referrers', [])
|
|
47
47
|
|
|
48
48
|
# 物理焊接账本
|
|
49
49
|
merge_ledger(clones['clones'], 'ghrs-data/clones_ledger.csv', 'clones')
|
|
@@ -57,10 +57,10 @@ if __name__ == "__main__":
|
|
|
57
57
|
c_df = pd.read_csv('ghrs-data/clones_ledger.csv')
|
|
58
58
|
total_clones = int(c_df['clones'].sum())
|
|
59
59
|
stats = {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
'total_clones': total_clones,
|
|
61
|
+
'stars': repo_info['stargazers_count'],
|
|
62
|
+
'forks': repo_info['forks_count']
|
|
63
63
|
}
|
|
64
64
|
with open('bunker-stats.json', 'w') as f:
|
|
65
65
|
json.dump(stats, f)
|
|
66
|
-
print(f
|
|
66
|
+
print(f'✅ Ledger synced. Total Clones: {total_clones}')
|
|
@@ -10,14 +10,14 @@ def assemble_readme():
|
|
|
10
10
|
with open('raw_referrers.json', 'r') as f:
|
|
11
11
|
referrers = json.load(f)
|
|
12
12
|
|
|
13
|
-
ref_table =
|
|
13
|
+
ref_table = '| Referrer | Views | Uniques |\n| :--- | :--- | :--- |\n'
|
|
14
14
|
if referrers:
|
|
15
15
|
for r in referrers:
|
|
16
|
-
ref_table += f
|
|
16
|
+
ref_table += f'| {r["referrer"]} | {r["count"]} | {r["uniques"]} |\n'
|
|
17
17
|
else:
|
|
18
|
-
ref_table +=
|
|
18
|
+
ref_table += '| No Signal | - | - |\n'
|
|
19
19
|
|
|
20
|
-
report = f
|
|
20
|
+
report = f'''# 🛰️ 地堡终极运行报告 (Sovereign Dashboard v8.5)
|
|
21
21
|
## 📊 核心战力指标
|
|
22
22
|
- **累计物理克隆**: `{stats['total_clones']}` 次
|
|
23
23
|
- **社群声望**: ⭐ `{stats['stars']}` / 🍴 `{stats['forks']}`
|
|
@@ -41,7 +41,7 @@ def assemble_readme():
|
|
|
41
41
|
{ref_table}
|
|
42
42
|
|
|
43
43
|
> 📡 物理封存点: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')} CST | Glory to Mankind.
|
|
44
|
-
|
|
44
|
+
'''
|
|
45
45
|
with open('README.md', 'w') as f:
|
|
46
46
|
f.write(report)
|
|
47
47
|
|
|
@@ -51,20 +51,20 @@ def git_push():
|
|
|
51
51
|
stats = json.load(f)
|
|
52
52
|
# 执行物理封存 Git 指令
|
|
53
53
|
try:
|
|
54
|
-
subprocess.run([
|
|
55
|
-
|
|
56
|
-
subprocess.run([
|
|
57
|
-
|
|
58
|
-
subprocess.run([
|
|
54
|
+
subprocess.run(['git', 'config', 'user.name',
|
|
55
|
+
'github-actions'], check=True)
|
|
56
|
+
subprocess.run(['git', 'config', 'user.email',
|
|
57
|
+
'github-actions@github.com'], check=True)
|
|
58
|
+
subprocess.run(['git', 'add', '-A'], check=True)
|
|
59
59
|
subprocess.run(
|
|
60
|
-
[
|
|
60
|
+
['git', 'commit', '-m', f'chore: sovereign modular update [total {stats["total_clones"]}]'], check=True)
|
|
61
61
|
subprocess.run(
|
|
62
|
-
[
|
|
63
|
-
print(
|
|
62
|
+
['git', 'push', 'origin', 'github-repo-stats', '--force'], check=True)
|
|
63
|
+
print('✅ Data sealed and pushed to cloud.')
|
|
64
64
|
except Exception as e:
|
|
65
|
-
print(f
|
|
65
|
+
print(f'⚠️ Git push skipped: {e}')
|
|
66
66
|
|
|
67
67
|
|
|
68
|
-
if __name__ ==
|
|
68
|
+
if __name__ == '__main__':
|
|
69
69
|
assemble_readme()
|
|
70
70
|
git_push()
|
|
@@ -5,6 +5,7 @@ import seaborn as sns
|
|
|
5
5
|
import matplotlib.pyplot as plt
|
|
6
6
|
import matplotlib.dates as mdates
|
|
7
7
|
|
|
8
|
+
|
|
8
9
|
def peak_recon():
|
|
9
10
|
df = pd.read_csv('ghrs-data/clones_ledger.csv')
|
|
10
11
|
df['date'] = pd.to_datetime(df['date'])
|
|
@@ -56,6 +57,7 @@ def peak_recon():
|
|
|
56
57
|
plt.tight_layout()
|
|
57
58
|
plt.savefig('plots/bunker_peak_recon.png', dpi=100)
|
|
58
59
|
|
|
60
|
+
|
|
59
61
|
def intelligence_grid():
|
|
60
62
|
df = pd.read_csv('ghrs-data/clones_ledger.csv')
|
|
61
63
|
df['date'] = pd.to_datetime(df['date'])
|
|
@@ -178,6 +180,7 @@ def intelligence_grid():
|
|
|
178
180
|
plt.tight_layout(rect=[0, 0.03, 1, 0.95])
|
|
179
181
|
plt.savefig('plots/bunker_intelligence_grid.png', dpi=100)
|
|
180
182
|
|
|
183
|
+
|
|
181
184
|
def load_clean(path, col):
|
|
182
185
|
df = pd.read_csv(path)
|
|
183
186
|
df['date'] = pd.to_datetime(df['date'], errors='coerce')
|
|
@@ -218,6 +221,7 @@ def main_dashboard(df_c, df_v):
|
|
|
218
221
|
plt.tight_layout()
|
|
219
222
|
plt.savefig('plots/bunker_main_v7.png', dpi=120)
|
|
220
223
|
|
|
224
|
+
|
|
221
225
|
if __name__ == "__main__":
|
|
222
226
|
print("🤖 Pod 042: Rendering Strategic Dashboards...")
|
|
223
227
|
plt.style.use('dark_background')
|
|
@@ -39,25 +39,25 @@ jobs:
|
|
|
39
39
|
|
|
40
40
|
# 💡 步骤 3:运行脚本,注意现在的相对路径!
|
|
41
41
|
# 我们在当前根目录运行,调用 scripts_repo 里的脚本,去处理 data_repo 里的数据
|
|
42
|
-
- name:
|
|
42
|
+
- name: '🛰️ Step 1: Data Collection'
|
|
43
43
|
run: |
|
|
44
44
|
cd data_repo
|
|
45
45
|
python ../scripts_repo/.github/scripts/collect/traffic.py
|
|
46
46
|
|
|
47
|
-
- name:
|
|
47
|
+
- name: '🧠 Step 2: Intelligence Analysis'
|
|
48
48
|
run: |
|
|
49
49
|
cd data_repo
|
|
50
50
|
# 执行“肉机比”扫描与“军衔”聚类分析
|
|
51
51
|
python ../scripts_repo/.github/scripts/analyze/bot_detect.py
|
|
52
52
|
python ../scripts_repo/.github/scripts/analyze/cluster.py
|
|
53
53
|
|
|
54
|
-
- name:
|
|
54
|
+
- name: '📈 Step 3: Visualization Rendering'
|
|
55
55
|
run: |
|
|
56
56
|
cd data_repo
|
|
57
57
|
# 渲染核心看板
|
|
58
58
|
python ../scripts_repo/.github/scripts/render/dashboard.py
|
|
59
59
|
|
|
60
|
-
- name:
|
|
60
|
+
- name: '💾 Step 4: Deployment & Sealing'
|
|
61
61
|
run: |
|
|
62
62
|
cd data_repo
|
|
63
63
|
# 物理封存至 README
|
package/CONTRIBUTING.md
CHANGED
|
@@ -75,24 +75,6 @@ cp .env.example .env
|
|
|
75
75
|
# 编辑 .env 文件,填入您的API密钥
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
-
### 项目结构
|
|
79
|
-
|
|
80
|
-
```
|
|
81
|
-
auto-crud-copilot/
|
|
82
|
-
├── bin/ # 可执行文件
|
|
83
|
-
├── src/
|
|
84
|
-
│ ├── commands/ # 命令实现
|
|
85
|
-
│ ├── core/ # 核心逻辑
|
|
86
|
-
│ ├── prompts/ # AI提示词
|
|
87
|
-
│ ├── services/ # 服务层
|
|
88
|
-
│ └── utils/ # 工具函数
|
|
89
|
-
├── templates/ # 代码模板
|
|
90
|
-
│ ├── react/
|
|
91
|
-
│ ├── vue/
|
|
92
|
-
│ └── angular/
|
|
93
|
-
└── config.js # 配置文件
|
|
94
|
-
```
|
|
95
|
-
|
|
96
78
|
- 提交信息遵循[Conventional Commits](https://www.conventionalcommits.org/zh-hans/v1.0.0/)规范
|
|
97
79
|
|
|
98
80
|
### 测试
|
package/bin/autodev.js
CHANGED
|
@@ -4,8 +4,7 @@ const path = require('path')
|
|
|
4
4
|
const chalk = require('chalk')
|
|
5
5
|
const pkg = require('../package.json')
|
|
6
6
|
const { program } = require('commander')
|
|
7
|
-
const
|
|
8
|
-
const { language, matrixEffect, bootSequence } = require('../src/utils/utils.js')
|
|
7
|
+
const { language, matrixEffect, bootSequence } = require('../src/utils/ux')
|
|
9
8
|
|
|
10
9
|
program
|
|
11
10
|
.version(pkg.version)
|
|
@@ -40,7 +39,7 @@ program
|
|
|
40
39
|
console.log(chalk.green(language('🤖 Pod 042: [报告] config.js 存储完毕。', '🤖 Pod 042: [Report] config.js storage complete.')))
|
|
41
40
|
}
|
|
42
41
|
|
|
43
|
-
const bunkerCmd = chalk.yellow('
|
|
42
|
+
const bunkerCmd = chalk.yellow(`'bunker': 'autodev watch'`)
|
|
44
43
|
console.log(chalk.cyan(language(
|
|
45
44
|
`📡 Operator 6O: 呼叫 2B, 地堡部署完毕, 为了更快捷地进入战场,建议手动执行 [物理装配]: 将 ${bunkerCmd} 加入您的 package.json scripts 中`,
|
|
46
45
|
`📡 Operator 6O: Calling 2B! Bunker deployment is complete. To expedite your entry into the battlefield, I recommend a manual [Physical Assembly]: Add ${bunkerCmd} to your package.json scripts.`
|
|
@@ -52,18 +51,20 @@ program
|
|
|
52
51
|
.alias('start')
|
|
53
52
|
.description(language('开启全频道联动监控:支持 Page/Part/API 协同构筑', 'Start full-channel linked monitoring: Coordinated Page/Part/API construction'))
|
|
54
53
|
.action(() => {
|
|
54
|
+
const bunker = require('../src/bootstrap')
|
|
55
55
|
const result = bunker.init(program.opts())
|
|
56
56
|
if (!result) {
|
|
57
57
|
return
|
|
58
58
|
}
|
|
59
59
|
bootSequence(pkg.version)
|
|
60
60
|
require('../src/commands/watch')()
|
|
61
|
-
const { config } =
|
|
62
|
-
|
|
63
|
-
|
|
61
|
+
const { config } = result.infrastructure
|
|
62
|
+
const { apiDoc, needMock, proxyTarget, enableAutoAlignment } = config
|
|
63
|
+
if (apiDoc && enableAutoAlignment) {
|
|
64
|
+
require('../src/labs/linker')()
|
|
64
65
|
}
|
|
65
|
-
if (
|
|
66
|
-
require('../src/
|
|
66
|
+
if (proxyTarget && !needMock && enableAutoAlignment) {
|
|
67
|
+
require('../src/labs/tower')()
|
|
67
68
|
}
|
|
68
69
|
process.on('SIGINT', () => {
|
|
69
70
|
console.log('\n')
|
package/config.js
CHANGED
|
@@ -18,10 +18,10 @@ module.exports = {
|
|
|
18
18
|
utilsDir: 'src/utils',
|
|
19
19
|
componentsDir: 'src/components',
|
|
20
20
|
|
|
21
|
+
// 指向公司的 Swagger JSON 地址
|
|
22
|
+
apiDoc: '',
|
|
21
23
|
// 代理目标
|
|
22
|
-
proxyTarget: '
|
|
24
|
+
proxyTarget: '',
|
|
23
25
|
responseSuccess: `response?.code === 200`,
|
|
24
|
-
// 指向公司的 Swagger JSON 地址
|
|
25
|
-
apiDoc: 'http://api.company.com/v2/api-docs',
|
|
26
26
|
|
|
27
27
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yorha2b-lab/autodev",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"description": "基于视觉大模型的前端(react+Antd)全自动 CRUD 代码生成器",
|
|
5
5
|
"bin": {
|
|
6
6
|
"autodev": "bin/autodev.js"
|
|
@@ -14,8 +14,6 @@
|
|
|
14
14
|
"ai",
|
|
15
15
|
"vision",
|
|
16
16
|
"react",
|
|
17
|
-
"vue",
|
|
18
|
-
"angular",
|
|
19
17
|
"antd",
|
|
20
18
|
"umi",
|
|
21
19
|
"code-generation",
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module.exports = ({ config, template, contextStringify }) => {
|
|
2
|
+
|
|
3
|
+
const fs = require('fs')
|
|
4
|
+
const path = require('path')
|
|
5
|
+
const Handlebars = require('handlebars')
|
|
6
|
+
|
|
7
|
+
Handlebars.registerHelper('raw', opt => opt.fn())
|
|
8
|
+
Handlebars.registerHelper('stringify', (context, maxLength = 200) => context ? new Handlebars.SafeString(contextStringify({ context, maxLength })) : '[]')
|
|
9
|
+
|
|
10
|
+
const { hbsDir } = config
|
|
11
|
+
const tplDir = hbsDir !== '' ? path.join(process.cwd(), hbsDir) : path.join(__dirname, `../framework/${template}/handlebars`)
|
|
12
|
+
const partialsDir = hbsDir !== '' ? path.join(process.cwd(), hbsDir) : path.join(__dirname, `../framework/${template}/handlebars/partials`)
|
|
13
|
+
|
|
14
|
+
fs.readdirSync(partialsDir).forEach(file => {
|
|
15
|
+
if (file.endsWith('.hbs')) {
|
|
16
|
+
const name = path.basename(file, '.hbs') // 去掉后缀拿名字
|
|
17
|
+
const content = fs.readFileSync(path.join(partialsDir, file), 'utf-8')
|
|
18
|
+
Handlebars.registerPartial(name, `${content}\n`)
|
|
19
|
+
}
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
indexTpl: Handlebars.compile(fs.readFileSync(path.join(tplDir, 'index.hbs'), 'utf-8')),
|
|
24
|
+
resourceTpl: Handlebars.compile(fs.readFileSync(path.join(tplDir, 'resource.hbs'), 'utf-8')),
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
const path = require('path')
|
|
3
|
+
const chalk = require('chalk')
|
|
4
|
+
|
|
5
|
+
let instance = null
|
|
6
|
+
|
|
7
|
+
module.exports = {
|
|
8
|
+
|
|
9
|
+
init: options => {
|
|
10
|
+
|
|
11
|
+
const template = options.template
|
|
12
|
+
const ux = require('../utils/ux')
|
|
13
|
+
|
|
14
|
+
const generatorPath = path.join(__dirname, `../framework/${template}/generator`)
|
|
15
|
+
if (!fs.existsSync(generatorPath)) {
|
|
16
|
+
console.error(chalk.red(ux.language(`❌ 暂不支持 [${template}] 框架。欢迎提交 Pull Request 贡献。`, `❌ [${template}] framework not supported. Welcome to contribute a Pull Request to help.`)))
|
|
17
|
+
return
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const infrastructure = require('../utils/infrastructure')
|
|
21
|
+
|
|
22
|
+
const openAI = require('./openai')()
|
|
23
|
+
const core = require('../utils/core')
|
|
24
|
+
const handlers = require('./handlers')()
|
|
25
|
+
const config = infrastructure.getConfig()
|
|
26
|
+
const menus = infrastructure.getExistingMenus()
|
|
27
|
+
const prompts = require('./prompt')({ template })
|
|
28
|
+
require('./infrastructure')({ ux, config, options, ...infrastructure })
|
|
29
|
+
const llm = require('../services/llm')({ config, openAI, template, ...prompts })
|
|
30
|
+
const handlebars = require('./handlebars')({ config, template, ...infrastructure })
|
|
31
|
+
const generator = require(generatorPath)({ config, ...core, ...handlebars, ...infrastructure })
|
|
32
|
+
|
|
33
|
+
instance = {
|
|
34
|
+
ux,
|
|
35
|
+
llm,
|
|
36
|
+
core,
|
|
37
|
+
openAI,
|
|
38
|
+
prompts,
|
|
39
|
+
handlers,
|
|
40
|
+
generator,
|
|
41
|
+
handlebars,
|
|
42
|
+
cli: options,
|
|
43
|
+
infrastructure: { menus, config, ...infrastructure },
|
|
44
|
+
}
|
|
45
|
+
return instance
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
get: () => instance
|
|
49
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
module.exports = ({ ux, config, options, copyTemplateDir }) => {
|
|
2
|
+
|
|
3
|
+
const { language } = ux
|
|
4
|
+
const { hbsDir, hooksDir, utilsDir, componentsDir } = config
|
|
5
|
+
|
|
6
|
+
try {
|
|
7
|
+
if (hbsDir === '') {
|
|
8
|
+
copyTemplateDir(options, 'hooks', hooksDir)
|
|
9
|
+
copyTemplateDir(options, 'utils', utilsDir)
|
|
10
|
+
copyTemplateDir(options, 'components', componentsDir)
|
|
11
|
+
}
|
|
12
|
+
} catch (error) {
|
|
13
|
+
console.error(language('❌ 模板构筑失败:', '❌ Template construction failed:'), error)
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
module.exports = () => {
|
|
2
|
+
|
|
3
|
+
const fs = require('fs')
|
|
4
|
+
const path = require('path')
|
|
5
|
+
const OpenAI = require('openai')
|
|
6
|
+
|
|
7
|
+
const pkgEnv = path.resolve(__dirname, '../.env')
|
|
8
|
+
const localEnv = path.resolve(process.cwd(), '.env')
|
|
9
|
+
require('dotenv').config({ path: fs.existsSync(localEnv) ? localEnv : pkgEnv })
|
|
10
|
+
const openAI = new OpenAI({ apiKey: process.env.API_KEY, baseURL: process.env.BASE_URL })
|
|
11
|
+
|
|
12
|
+
return openAI
|
|
13
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
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
|
+
}
|
package/src/commands/watch.js
CHANGED
|
@@ -1,26 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
const path = require('path')
|
|
3
|
-
const chalk = require('chalk')
|
|
4
|
-
const chokidar = require('chokidar')
|
|
5
|
-
const stringify = require('json-stringify-pretty-compact')
|
|
1
|
+
module.exports = () => {
|
|
6
2
|
|
|
7
|
-
const
|
|
3
|
+
const fs = require('fs')
|
|
4
|
+
const path = require('path')
|
|
5
|
+
const chalk = require('chalk')
|
|
6
|
+
const chokidar = require('chokidar')
|
|
8
7
|
|
|
9
|
-
const {
|
|
10
|
-
const { copyTemplateDir } = require('../utils/utils.js')
|
|
11
|
-
const { createTaskQueue } = require('../core/task-queue.js')
|
|
8
|
+
const { ux, core, handlers, infrastructure } = require('../bootstrap').get()
|
|
12
9
|
|
|
13
|
-
const {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
copyTemplateDir(options, 'hooks', config.hooksDir)
|
|
18
|
-
copyTemplateDir(options, 'utils', config.utilsDir)
|
|
19
|
-
copyTemplateDir(options, 'components', config.componentsDir)
|
|
20
|
-
}
|
|
21
|
-
} catch (error) {
|
|
22
|
-
console.error(language('❌ 模板构筑失败:', '❌ Template construction failed:'), error)
|
|
23
|
-
}
|
|
10
|
+
const { language } = ux
|
|
11
|
+
const { createTaskQueue } = core
|
|
12
|
+
const { apiHandler, pageHandler, partHandler } = handlers
|
|
13
|
+
const { menus, config, contextStringify } = infrastructure
|
|
24
14
|
|
|
25
15
|
const queue = createTaskQueue(2)
|
|
26
16
|
|
|
@@ -31,7 +21,7 @@ const watch = () => {
|
|
|
31
21
|
)))
|
|
32
22
|
const utilsDir = path.join(process.cwd(), config.utilsDir)
|
|
33
23
|
if (!fs.existsSync(utilsDir)) fs.mkdirSync(utilsDir, { recursive: true })
|
|
34
|
-
fs.writeFileSync(path.join(utilsDir, 'menus.js'), `export const menus = ${
|
|
24
|
+
fs.writeFileSync(path.join(utilsDir, 'menus.js'), `export const menus = ${contextStringify({ context: menus, maxLength: 50 })}`)
|
|
35
25
|
console.log(chalk.gray(language(
|
|
36
26
|
'\n🤖 [System] 未检测到运行中的任务,系统待机中...\n',
|
|
37
27
|
'\n🤖 [System] System is STANDBY.\n'
|
|
@@ -50,20 +40,17 @@ const watch = () => {
|
|
|
50
40
|
'📡 Operator 6O: Calling 2B, all-channel linked monitoring is ready!'
|
|
51
41
|
)))
|
|
52
42
|
|
|
53
|
-
|
|
43
|
+
const routes = [
|
|
44
|
+
{ match: 'response', handler: apiHandler },
|
|
45
|
+
{ match: 'screenShot', handler: pageHandler },
|
|
46
|
+
{ match: 'screenPart', handler: partHandler },
|
|
47
|
+
]
|
|
54
48
|
|
|
49
|
+
watcher.on('add', filePath => {
|
|
55
50
|
const absolutePath = path.resolve(filePath)
|
|
56
|
-
|
|
57
|
-
if (
|
|
58
|
-
queue.add(() =>
|
|
59
|
-
}
|
|
60
|
-
else if (absolutePath.includes('screenPart')) {
|
|
61
|
-
queue.add(() => partHandler(filePath))
|
|
62
|
-
}
|
|
63
|
-
else if (absolutePath.includes('response')) {
|
|
64
|
-
queue.add(() => apiHandler(filePath))
|
|
51
|
+
const route = routes.find(r => absolutePath.includes(r.match))
|
|
52
|
+
if (route) {
|
|
53
|
+
queue.add(() => route.handler(filePath))
|
|
65
54
|
}
|
|
66
55
|
})
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
module.exports = watch
|
|
56
|
+
}
|
|
@@ -112,7 +112,7 @@ const FormRenderer = ({ form, formItems, tableConfig, setModalTable, setSelected
|
|
|
112
112
|
*
|
|
113
113
|
* @example
|
|
114
114
|
* <MyModalForm
|
|
115
|
-
* title=
|
|
115
|
+
* title='构筑新模块'
|
|
116
116
|
* visible={visible}
|
|
117
117
|
* submit={async (vals) => await save(vals)}
|
|
118
118
|
* formItems={[{ label: '截止日期', name: 'deadline', type: 'date' }]}
|
|
@@ -30,7 +30,7 @@ import { useTableQuery } from '../hooks/useTableQuery'
|
|
|
30
30
|
*
|
|
31
31
|
* @example
|
|
32
32
|
* <MyModalTable
|
|
33
|
-
* title=
|
|
33
|
+
* title='关联用户片段'
|
|
34
34
|
* api={async params=>await fetchUsers(params)}
|
|
35
35
|
* setModalForm={setModal} // 💡 借用主页面的表单构筑舱
|
|
36
36
|
* operate={({ refresh, setModalForm }) => ({ label: '详情', onClick: (rec) => setModalForm(...) })}
|
|
@@ -19,10 +19,10 @@ import { Button, Tree, Radio, Input, Upload, Select, Cascader, Checkbox, DatePic
|
|
|
19
19
|
*
|
|
20
20
|
* @example
|
|
21
21
|
* // 基本构筑
|
|
22
|
-
* <AliyunOSSUpload path=
|
|
22
|
+
* <AliyunOSSUpload path='project/data' url='/api/oss/token' />
|
|
23
23
|
*
|
|
24
24
|
* // 高级装配(限制文件类型并开启多选)
|
|
25
|
-
* <AliyunOSSUpload accept=
|
|
25
|
+
* <AliyunOSSUpload accept='.pdf' multiple={true} path='docs' url='/api/oss/token' />
|
|
26
26
|
*/
|
|
27
27
|
const AliyunOSSUpload = ({ value, onChange, ...restProps }) => {
|
|
28
28
|
|