@yorha2b-lab/autodev 2.1.4 → 2.1.6

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.
@@ -1,49 +1,53 @@
1
- name: Bunker Native Stats
1
+ name: Bunker Native Stats & Intelligence
2
2
 
3
3
  on:
4
4
  schedule:
5
- - cron: '45 19 * * *' # 北京时间凌晨 03:45
5
+ - cron: '45 19 * * *' # 北京时间凌晨 03:45 自动巡航
6
6
  workflow_dispatch:
7
7
 
8
- # 💡 补丁 1:强制开启 Node.js 24,消灭那个烦人的黄色警告
9
8
  env:
10
9
  FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
11
10
 
12
11
  jobs:
13
- update-ledger:
12
+ recon-and-ledger:
14
13
  runs-on: ubuntu-latest
15
14
  permissions:
16
15
  contents: write
17
16
  steps:
18
- # 1. 检出数据分支
19
17
  - name: Checkout Data Branch
20
18
  uses: actions/checkout@v4
21
19
  with:
22
20
  ref: github-repo-stats
23
21
  token: ${{ secrets.STATS_TOKEN }}
24
- fetch-depth: 0 # 获取完整历史,确保物理对账无误
22
+ fetch-depth: 0
25
23
 
26
- # 2. 物理装配与合并
27
- - name: Fetch and Smart Merge
24
+ # 1. 环境准备:安装绘图依赖
25
+ - name: Setup Plotting Environment
28
26
  run: |
29
- echo "🤖 Pod 042: 启动‘全链路数据闭环协议’..."
30
-
31
- # A. 抓取数据(增加 -s 隐藏进度,-f 报错即停止)
32
- curl -sf -H "Authorization: token ${{ secrets.STATS_TOKEN }}" \
27
+ python -m pip install --upgrade pip
28
+ pip install matplotlib pandas
29
+
30
+ # 2. 情报采集与账本物理焊接
31
+ - name: Intelligence Gathering & Sovereign Merge
32
+ run: |
33
+ echo "🤖 Pod 042: 启动‘全频道情报采集协议’..."
34
+ curl -s -H "Authorization: token ${{ secrets.STATS_TOKEN }}" \
35
+ -H "Accept: application/vnd.github.v3+json" \
36
+ https://api.github.com/repos/${{ github.repository }}/traffic/clones > raw_clones.json
37
+
38
+ curl -s -H "Authorization: token ${{ secrets.STATS_TOKEN }}" \
33
39
  -H "Accept: application/vnd.github.v3+json" \
34
- https://api.github.com/repos/${{ github.repository }}/traffic/clones > raw.json
40
+ https://api.github.com/repos/${{ github.repository }}/traffic/popular/referrers > raw_referrers.json
35
41
 
36
- # B. 格式化新数据
37
42
  mkdir -p ghrs-data
38
43
  echo "date,clones,uniques" > /tmp/new_data.csv
39
- jq -r '.clones[] | "\(.timestamp[0:10]),\(.count),\(.uniques)"' raw.json >> /tmp/new_data.csv
44
+ jq -r '.clones[] | "\(.timestamp[0:10]),\(.count),\(.uniques)"' raw_clones.json >> /tmp/new_data.csv
40
45
 
41
- # C. 🧬 执行物理合并逻辑
42
46
  LEDGER="ghrs-data/clones_ledger.csv"
43
47
  if [ ! -f "$LEDGER" ]; then
44
48
  cp /tmp/new_data.csv "$LEDGER"
45
49
  else
46
- echo "📡 正在将手动补全的数据与 API 信号进行物理焊接..."
50
+ echo "📡 执行物理序列重组..."
47
51
  (head -n 1 "$LEDGER"; tail -n +2 "$LEDGER"; tail -n +2 /tmp/new_data.csv) | \
48
52
  sed 's/\//-/g' | \
49
53
  awk -F',' 'NR>1 {
@@ -52,30 +56,78 @@ jobs:
52
56
  if(length(a[3])==1) a[3]="0"a[3];
53
57
  printf "%s-%s-%s,%s,%s\n", a[1], a[2], a[3], $2, $3
54
58
  }' | awk -F',' '!a[$1]++' | sort -r > /tmp/final_ledger.csv
55
-
56
59
  echo "date,clones,uniques" > "$LEDGER"
57
60
  cat /tmp/final_ledger.csv >> "$LEDGER"
58
61
  fi
59
62
 
60
- # D. 🔥 核心:产出 [bunker-stats.json]
61
- # 确保 awk 逻辑百分之百执行
62
63
  TOTAL_CLONES=$(awk -F',' 'NR>1 {sum+=$2} END {print sum}' "$LEDGER")
63
64
  echo "{\"total_clones\": $TOTAL_CLONES}" > bunker-stats.json
64
- echo "✅ 物理总数结算达成: $TOTAL_CLONES"
65
65
 
66
- # E. 重构 README
66
+ # 3. 🧬 【核心新增】:构筑战绩可视化图像
67
+ - name: Construct Visual Radar
68
+ run: |
69
+ echo "🤖 Pod 042: 执行‘图像构筑协议’..."
70
+ python3 <<EOF
71
+ import pandas as pd
72
+ import matplotlib.pyplot as plt
73
+ import os
74
+
75
+ # 读取账本并反转顺序(变为正序绘图)
76
+ df = pd.read_csv('ghrs-data/clones_ledger.csv')
77
+ df['date'] = pd.to_datetime(df['date'])
78
+ df = df.sort_values('date')
79
+
80
+ # 样式设置:地堡深邃黑
81
+ plt.style.use('dark_background')
82
+ fig, ax = plt.subplots(figsize=(10, 5))
83
+
84
+ # 绘制曲线(地堡绿)
85
+ ax.plot(df['date'], df['clones'], color='#33cc33', marker='o', markersize=4, linewidth=2, label='Daily Clones')
86
+ ax.fill_between(df['date'], df['clones'], color='#33cc33', alpha=0.2)
87
+
88
+ ax.set_title('YoRHa Bunker - Physical Construction Trend', fontsize=14, pad=20, color='#33cc33')
89
+ ax.set_ylabel('Clone Count', color='#888')
90
+ ax.grid(color='#444', linestyle='--', linewidth=0.5)
91
+
92
+ # 旋转日期防挤占
93
+ plt.xticks(rotation=45, color='#888')
94
+ plt.yticks(color='#888')
95
+
96
+ # 自动保存
97
+ os.makedirs('plots', exist_ok=True)
98
+ plt.tight_layout()
99
+ plt.savefig('plots/clones_trend.png', dpi=100)
100
+ EOF
101
+
102
+ # 4. [报表装修]
103
+ - name: Assemble Report
104
+ run: |
67
105
  echo "# 🛰️ 地堡运行报告 (Sovereign Report)" > README.md
68
- echo "### 📊 累计物理克隆总数: **$TOTAL_CLONES**" >> README.md
69
- echo "数据已根据 AGPL-3.0 协议物理封存。愿人类荣光永存。" >> README.md
106
+ echo "### 📊 累计物理克隆总数: **$(grep -oE "[0-9]+" bunker-stats.json | head -n 1)**" >> README.md
107
+ echo "" >> README.md
108
+
109
+ # 💡 物理植入图片
110
+ echo "#### 📈 战绩增长雷达 (Growth Radar)" >> README.md
111
+ echo "![Clones Trend](./plots/clones_trend.png)" >> README.md
112
+ echo "" >> README.md
113
+
114
+ echo "#### 📡 流量来源实时追踪 (Top Referrers)" >> README.md
115
+ echo "| 来源站点 | 总访问量 | 独立指挥官 |" >> README.md
116
+ echo "| :--- | :--- | :--- |" >> README.md
117
+ if [ -s raw_referrers.json ]; then
118
+ jq -r '.[] | "| \(.referrer) | \(.count) | \(.uniques) |"' raw_referrers.json >> README.md
119
+ else
120
+ echo "| 暂无外部来源信号 | - | - |" >> README.md
121
+ fi
70
122
  echo "" >> README.md
71
- echo "> 📡 信号状态:全频道在线 | 战绩自动核算中..." >> README.md
123
+ echo "> 📡 信号状态:全频道在线 | 数据物理封存点: $(date +'%Y-%m-%d %H:%M:%S') CST" >> README.md
72
124
 
73
- # 3. 封存并强力同步
74
- - name: Commit and Push
125
+ # 5. 最终物理封存
126
+ - name: Sync Ledger to Cloud
75
127
  run: |
76
128
  git config user.name github-actions
77
129
  git config user.email github-actions@github.com
78
130
  git add -A
79
131
  TOTAL=$(grep -oE "[0-9]+" bunker-stats.json | head -n 1)
80
- git commit -m "chore: ledger & badge update - total $TOTAL" || echo "no changes"
132
+ git commit -m "chore: sovereign update v5.0 - total $TOTAL [$(date +'%Y-%m-%d')]" || echo "no changes"
81
133
  git push origin github-repo-stats --force
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yorha2b-lab/autodev",
3
- "version": "2.1.4",
3
+ "version": "2.1.6",
4
4
  "description": "基于视觉大模型的前端(react+Antd)全自动 CRUD 代码生成器",
5
5
  "bin": {
6
6
  "autodev": "bin/autodev.js"
@@ -55,7 +55,7 @@ export const exportDataToExcel = async (url, options, columns, fileName, formatt
55
55
  if (col.exportRender) {
56
56
  value = col.exportRender(value, item)
57
57
  }
58
- if (col.render) {
58
+ if (col.render&&!col.exportRender) {
59
59
  const rendered = col.render(value, item)
60
60
  value = typeof rendered === 'object' ? (rendered?.props?.children || value) : rendered
61
61
  }
@@ -70,6 +70,59 @@ export const exportDataToExcel = async (url, options, columns, fileName, formatt
70
70
  } */
71
71
  }
72
72
 
73
+ export const streamDownload = async ({ url, options, headers = {} }, fileName = '下载') => {
74
+
75
+ const response = await fetch(url, { ...options, headers })
76
+
77
+ if (!response.ok) {
78
+ console.error(response.statusText)
79
+ return
80
+ }
81
+
82
+ const blob = await response.blob()
83
+
84
+ if (!blob.size) {
85
+ console.error('文件为空')
86
+ return
87
+ }
88
+
89
+ const slice = blob.slice(0, 10)
90
+ const text = (await slice.text()).trim()
91
+
92
+ if (text.startsWith('{') || text.startsWith('[')) {
93
+ try {
94
+ const fullText = await blob.text()
95
+ const json = JSON.parse(fullText)
96
+ console.error(json?.msg ?? '系统异常')
97
+ } catch (error) {
98
+ console.error(error)
99
+ }
100
+ return
101
+ }
102
+
103
+ const disposition = response.headers.get('content-disposition')
104
+ let name = fileName
105
+
106
+ if (disposition) {
107
+ const match = disposition.match(/filename\*=UTF-8''([^;]+)|filename="?([^";]+)"?/)
108
+ if (match) {
109
+ name = decodeURIComponent(match[1] || match[2])
110
+ }
111
+ }
112
+
113
+ const link = document.createElement('a')
114
+ const urlObj = URL.createObjectURL(blob)
115
+
116
+ link.href = urlObj
117
+ link.download = name
118
+
119
+ document.body.appendChild(link)
120
+ link.click()
121
+ link.remove()
122
+
123
+ setTimeout(() => URL.revokeObjectURL(urlObj), 1000)
124
+ }
125
+
73
126
  export const moneyRender = (value, { decimals = 2, currency = 'CNY', language = 'zh-CN', showSymbol = true } = {}) => {
74
127
  if (value === null || value === undefined || value === '') return '-'
75
128
  const number = Number(value)