@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.
@@ -0,0 +1,159 @@
1
+ import os
2
+ import numpy as np
3
+ import pandas as pd
4
+ import matplotlib.pyplot as plt
5
+ import seaborn as sns
6
+ from sklearn.cluster import DBSCAN
7
+ from sklearn.preprocessing import StandardScaler
8
+
9
+
10
+ def sigmoid(x):
11
+ """
12
+ 概率平滑函数:
13
+ 避免指标达到某个值后直接封顶,
14
+ 让异常程度呈渐进变化。
15
+ """
16
+ return 1 / (1 + np.exp(-x))
17
+
18
+
19
+ def map_rank(cluster_id):
20
+ """
21
+ DBSCAN 的 cluster 数量不是固定的,
22
+ 不能写死 0/1/2,否则新增聚类会出现 NaN。
23
+ """
24
+ if cluster_id == -1:
25
+ return 'Legendary'
26
+ if cluster_id == 0:
27
+ return 'Veteran'
28
+ return f'Tactical Unit {cluster_id}'
29
+
30
+
31
+ def execute_deep_intelligence():
32
+
33
+ print("🤖 Pod 042: 启动‘全量情报融合协议’...")
34
+
35
+ clone_path = 'ghrs-data/clones_ledger.csv'
36
+ view_path = 'ghrs-data/views_ledger.csv'
37
+
38
+ if not os.path.exists(clone_path) or not os.path.exists(view_path):
39
+ print("⚠️ 数据账本缺失,取消分析。")
40
+ return
41
+
42
+ # 1. 物理对账
43
+ df_c = pd.read_csv(clone_path)
44
+ df_v = pd.read_csv(view_path)
45
+
46
+ df = pd.merge(df_c, df_v, on='date', how='inner').fillna(0)
47
+
48
+ # ==================================================
49
+ # 2. 特征工程
50
+ # ==================================================
51
+
52
+ # 访问转化强度
53
+ df['ratio'] = (df['clones'] / df['views'].replace(0, 1))
54
+
55
+ # Github 行为天然长尾,因此进入 Log 空间
56
+ df['log_volume'] = np.log1p(df['clones'])
57
+ df['log_intensity'] = np.log1p(df['ratio'])
58
+
59
+ # ==================================================
60
+ # 3. 自动化概率审计
61
+ # ==================================================
62
+
63
+ # 原始 ratio 越高,越像自动化行为
64
+ ratio_score = sigmoid(df['ratio'] - 3)
65
+
66
+ # 单日爆发越高,异常概率越高
67
+ burst_score = sigmoid((df['clones'] - 100) / 100)
68
+
69
+ # 综合异常系数
70
+ df['bot_prob'] = (ratio_score * 0.6 + burst_score * 0.4)
71
+
72
+ # ==================================================
73
+ # 4. DBSCAN 行为聚类
74
+ # ==================================================
75
+ X = StandardScaler().fit_transform(df[['log_volume', 'log_intensity']])
76
+ db = DBSCAN(eps=0.4, min_samples=3).fit(X)
77
+ df['cluster'] = db.labels_
78
+
79
+ # ==================================================
80
+ # 5. 战力结算
81
+ # ==================================================
82
+ bot_clones = (df['clones'] * df['bot_prob']).sum()
83
+ total_clones = df['clones'].sum()
84
+ human_clones = max(0, total_clones - bot_clones)
85
+ df['rank'] = df['cluster'].apply(map_rank)
86
+ rank_counts = (df['rank'].value_counts())
87
+
88
+ # ==================================================
89
+ # 6. 全频道视觉矩阵
90
+ # ==================================================
91
+
92
+ plt.style.use('dark_background')
93
+ fig = plt.figure(figsize=(24, 8))
94
+
95
+ gs = fig.add_gridspec(1, 3, width_ratios=[1, 1.2, 1.8])
96
+
97
+ # ----------------------------
98
+ # A. 自动化组成
99
+ # ----------------------------
100
+
101
+ ax1 = fig.add_subplot(gs[0])
102
+
103
+ ax1.pie(
104
+ [human_clones, bot_clones],
105
+ labels=['Human', 'Machine'],
106
+ autopct='%1.1f%%',
107
+ startangle=90,
108
+ pctdistance=0.85,
109
+ explode=(0.05, 0)
110
+ )
111
+
112
+ ax1.add_artist(plt.Circle((0, 0), 0.70, fc='#0d1117'))
113
+ ax1.set_title("Operational Composition", color='#33cc33', pad=20)
114
+
115
+ # ----------------------------
116
+ # B. 行为层级
117
+ # ----------------------------
118
+
119
+ ax2 = fig.add_subplot(gs[1])
120
+ sns.barplot(x=rank_counts.index, y=rank_counts.values,
121
+ palette='viridis', ax=ax2)
122
+
123
+ ax2.set_title("Commander Hierarchy", color='#0066ff', pad=20)
124
+
125
+ ax2.set_ylabel("Days Count")
126
+
127
+ ax2.grid(axis='y', alpha=0.1)
128
+
129
+ # ----------------------------
130
+ # C. 行为拓扑
131
+ # ----------------------------
132
+
133
+ ax3 = fig.add_subplot(gs[2])
134
+
135
+ # sqrt 缩放避免极端 clone 撑爆气泡
136
+ bubble_size = (np.sqrt(df['clones'] + 1) * 20)
137
+ ax3.scatter(
138
+ df['log_volume'],
139
+ df['log_intensity'],
140
+ c=df['cluster'],
141
+ cmap='coolwarm',
142
+ s=bubble_size,
143
+ alpha=0.6,
144
+ edgecolors='w'
145
+ )
146
+ ax3.set_title("Sovereign Logistic Matrix (Log Space)",
147
+ color='#ff00ff', pad=20)
148
+ ax3.set_xlabel("Log(Total Clones)")
149
+ ax3.set_ylabel("Log(Intensity)")
150
+ ax3.grid(alpha=0.1)
151
+ plt.tight_layout()
152
+ os.makedirs('plots', exist_ok=True)
153
+ plt.savefig('plots/bunker_intelligence_fusion.png', dpi=120)
154
+
155
+ print("✅ 全量情报视觉矩阵封存成功!")
156
+
157
+
158
+ if __name__ == "__main__":
159
+ execute_deep_intelligence()
@@ -33,9 +33,7 @@ def assemble_readme():
33
33
  ![Peak Recon](./plots/bunker_peak_recon.png)
34
34
 
35
35
  ### 🧠 4. 深度情报审计 (Intelligence Intelligence)
36
- | 成分分析 (Meat vs Machine) | 战力梯度 (Hierarchy) |
37
- | :---: | :---: |
38
- | ![Bot](./plots/bot_composition.png) | ![Cluster](./plots/commander_profiles.png) |
36
+ ![Fusion](./plots/bunker_intelligence_fusion.png)
39
37
 
40
38
  #### 🛰️ 流量来源实时追踪
41
39
  {ref_table}
@@ -181,43 +181,87 @@ def intelligence_grid():
181
181
  plt.savefig('plots/bunker_intelligence_grid.png', dpi=100)
182
182
 
183
183
 
184
- def load_clean(path, col):
184
+ def load_clean(path, col_name):
185
185
  df = pd.read_csv(path)
186
186
  df['date'] = pd.to_datetime(df['date'], errors='coerce')
187
187
  df = df.dropna(subset=['date']).copy()
188
- df[col] = pd.to_numeric(df[col.lower()], errors='coerce').fillna(0)
189
- df['uniques'] = pd.to_numeric(df['uniques'], errors='coerce').fillna(0)
190
- return df[['date', col, 'uniques']]
188
+
189
+ # 物理强转数字
190
+ df[col_name] = pd.to_numeric(
191
+ df[col_name.lower()], errors='coerce').fillna(0)
192
+
193
+ # 💡 核心修正:直接在这里把 uniques 重命名为 [类别]_Uniques
194
+ # 这样合并后,列名就是固定的 'Clones_Uniques' 和 'Views_Uniques'
195
+ new_unique_name = f"{col_name}_Uniques"
196
+ df[new_unique_name] = pd.to_numeric(
197
+ df['uniques'], errors='coerce').fillna(0)
198
+
199
+ return df[['date', col_name, new_unique_name]]
191
200
 
192
201
 
193
202
  def main_dashboard(df_c, df_v):
203
+ # 💡 1. 数据融合与脱水
194
204
  df = pd.merge(df_c, df_v, on='date', how='outer').fillna(
195
205
  0).sort_values('date')
196
206
  df['cumulative'] = df['Clones'].cumsum()
197
- df['ratio'] = df['Clones'] / df['uniques'].replace(0, 1)
198
- df['clones_ma7'] = df['Clones'].rolling(window=7, min_periods=1).mean()
207
+ df['ratio'] = df['Clones'] / \
208
+ df['Views_Uniques'].replace(0, 1)
209
+
210
+ # 💡 2. 核心算法注入:计算“信号纯度” (Purity)
211
+ df['cumulative'] = df['Clones'].cumsum()
212
+
213
+ # 计算“信号纯度”:克隆数 / 访客数
214
+ df['ratio'] = df['Clones'] / df['Views_Uniques'].replace(0, 1)
215
+
216
+ # 算法:(比例/10 * 0.6) + (总量/500 * 0.4)
217
+ df['bot_prob'] = (df['ratio'] / 10).clip(upper=1) * 0.6 + \
218
+ (df['Clones'] / 500).clip(upper=1) * 0.4
219
+ df['purity'] = (1.0 - df['bot_prob']) * 100
199
220
 
200
- fig1 = plt.figure(figsize=(12, 10))
201
- gs1 = fig1.add_gridspec(3, 1)
221
+ # 💡 3. 画布物理扩容:由 3 行 1 列 升级为 4 行 1 列
222
+ fig1 = plt.figure(figsize=(12, 14)) # 增加高度以容纳四个雷达
223
+ gs1 = fig1.add_gridspec(4, 1)
224
+
225
+ # --- 子图 1: 实时侦察 (Views vs Clones) ---
202
226
  ax1 = fig1.add_subplot(gs1[0])
203
227
  ax1.plot(df['date'].tail(30), df['Views'].tail(
204
228
  30), alpha=0.5, ls='--', label='Views (Web)')
205
229
  ax1.plot(df['date'].tail(30), df['Clones'].tail(30),
206
230
  color='#33cc33', lw=2, label='Clones (Terminal)')
207
231
  ax1.set_title(
208
- 'Strategic Recon: Views vs Clones (Last 30D)', color='#33cc33')
232
+ 'Strategic Recon: Web Visitors vs Terminal Commandos (30D)', color='#33cc33')
209
233
  ax1.legend(loc='upper left', frameon=True, fontsize='small')
234
+
235
+ # --- 子图 2: 累计荣光 (Growth) ---
210
236
  ax2 = fig1.add_subplot(gs1[1])
211
- ax2.fill_between(df['date'], df['cumulative'],
212
- color='#0066ff', alpha=0.2)
237
+ ax2.fill_between(df['date'], df['cumulative'], color='#0066ff', alpha=0.2)
213
238
  ax2.plot(df['date'], df['cumulative'], color='#0066ff', lw=3)
214
239
  ax2.set_title('Bunker Glory: Total Cumulative Growth', color='#0066ff')
215
- ax3 = fig1.add_subplot(gs1[2])
216
- pivot = df.assign(week=df['date'].dt.isocalendar().week, day=df['date'].dt.day_name()).pivot_table(index='day', columns='week',
217
- values='Clones', aggfunc='sum').fillna(0).reindex(['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'])
240
+
241
+ # --- 💡 子图 3 [核心新增]: 信号纯度审计 (Signal Purity) ---
242
+ ax_p = fig1.add_subplot(gs1[2])
243
+ # 使用渐变紫色,代表地堡的“骇入感知”
244
+ ax_p.fill_between(df['date'].tail(45), df['purity'].tail(
245
+ 45), color='#ff00ff', alpha=0.1)
246
+ ax_p.plot(df['date'].tail(45), df['purity'].tail(45),
247
+ color='#ff00ff', lw=1.5, label='Signal Purity %')
248
+ ax_p.set_ylim(0, 105) # 留点空白放标题
249
+ ax_p.axhline(y=50, color='#444', linestyle=':', alpha=0.5) # 50% 警戒线
250
+ ax_p.set_title(
251
+ 'Neural Cloud Integrity: Human Signal Purity Audit (%)', color='#ff00ff')
252
+ ax_p.legend(loc='lower left', fontsize='x-small')
253
+
254
+ # --- 子图 4: 作战热力图 (Heatmap) ---
255
+ ax3 = fig1.add_subplot(gs1[3])
256
+ pivot = df.assign(week=df['date'].dt.isocalendar().week, day=df['date'].dt.day_name()).pivot_table(
257
+ index='day', columns='week', values='Clones', aggfunc='sum'
258
+ ).fillna(0).reindex(['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'])
259
+
218
260
  sns.heatmap(pivot, cmap='Greens', ax=ax3,
219
261
  cbar=False, lw=2, linecolor='#1a1a1a')
220
- ax3.set_title('Deployment Matrix: All-Time Activity', color='#33cc33')
262
+ ax3.set_title(
263
+ 'Global Deployment Heatmap: Strategic Activity Matrix', color='#33cc33')
264
+
221
265
  plt.tight_layout()
222
266
  plt.savefig('plots/bunker_main_v7.png', dpi=120)
223
267
 
@@ -35,7 +35,7 @@ jobs:
35
35
  python-version: '3.10'
36
36
 
37
37
  - name: Install Dependencies
38
- run: pip install matplotlib pandas seaborn scipy numpy requests
38
+ run: pip install matplotlib pandas seaborn scipy numpy requests scikit-learn
39
39
 
40
40
  # 💡 步骤 3:运行脚本,注意现在的相对路径!
41
41
  # 我们在当前根目录运行,调用 scripts_repo 里的脚本,去处理 data_repo 里的数据
@@ -48,8 +48,7 @@ jobs:
48
48
  run: |
49
49
  cd data_repo
50
50
  # 执行“肉机比”扫描与“军衔”聚类分析
51
- python ../scripts_repo/.github/scripts/analyze/bot_detect.py
52
- python ../scripts_repo/.github/scripts/analyze/cluster.py
51
+ python ../scripts_repo/.github/scripts/analyze/deep_intelligence.py
53
52
 
54
53
  - name: '📈 Step 3: Visualization Rendering'
55
54
  run: |
package/bin/autodev.js CHANGED
@@ -1,14 +1,13 @@
1
1
  #!/usr/bin/env node
2
- const fs = require('fs')
3
2
  const path = require('path')
4
3
  const chalk = require('chalk')
5
4
  const pkg = require('../package.json')
6
5
  const { program } = require('commander')
6
+ const local = Intl.DateTimeFormat().resolvedOptions().locale.toUpperCase()
7
7
 
8
- const { discover } = require('../src/utils/foundation')
9
- const { local, matrixEffect, bootSequence } = require('../src/utils/ux')
10
-
11
- const dialogs = discover(path.join(__dirname, '../src/dialogs'))
8
+ const { matrixEffect } = require('../src/utils/ux')
9
+ const recruiter = require('../src/kernel/recruiter')
10
+ const dialogs = recruiter(path.join(__dirname, '../src/dialogs'))
12
11
  const dialog = dialogs[local] ?? dialogs['EN-US']
13
12
 
14
13
  program
@@ -22,23 +21,12 @@ program
22
21
  .description(dialog.bunker.initDesc)
23
22
  .action(() => {
24
23
  const battlefield = {
25
- dirs: [],
26
24
  files: [
27
25
  { from: '.env.example', to: '.env', exist: 'envCheck', success: 'envCopy' },
28
26
  { from: 'config.js', to: 'config.js', exist: 'configCheck', success: 'configCopy' }
29
27
  ]
30
28
  }
31
- const installer = {
32
- dirs: dir => fs.mkdirSync(path.join(process.cwd(), dir), { recursive: true }),
33
- files: ({ from, to, exist, success }) => {
34
- const target = path.join(process.cwd(), to)
35
- if (fs.existsSync(target)) {
36
- return console.log(chalk.yellow(dialog.bunker[exist]))
37
- }
38
- fs.copyFileSync(path.resolve(__dirname, `../${from}`), target)
39
- console.log(chalk.green(dialog.bunker[success]))
40
- }
41
- }
29
+ const installer = require('../src/utils/installer')({ root: process.cwd(), dialog })
42
30
  Object.entries(battlefield).forEach(([type, items]) => items.forEach(installer[type]))
43
31
  const bunkerCmd = chalk.yellow(`'bunker': 'autodev watch'`)
44
32
  console.log(chalk.cyan(dialog.bunker.initComplete(bunkerCmd)))
@@ -50,11 +38,10 @@ program
50
38
  .description(dialog.bunker.watchDesc)
51
39
  .action(async () => {
52
40
  const bunker = require('../src/bootstrap')
53
- const result = bunker.init(program.opts(), dialog)
41
+ const result = await bunker.init(program.opts(), dialog, pkg.version, local)
54
42
  if (!result) {
55
43
  return
56
44
  }
57
- await bootSequence(pkg.version)
58
45
  require('../src/commands/watch')()
59
46
  process.on('SIGINT', () => {
60
47
  result.yorha.commander.report(dialog.bunker.systemOffline, 'gray')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yorha2b-lab/autodev",
3
- "version": "5.5.0",
3
+ "version": "5.6.0",
4
4
  "description": "基于视觉大模型的前端(react+Antd)全自动 CRUD 代码生成器",
5
5
  "bin": {
6
6
  "autodev": "bin/autodev.js"
@@ -32,13 +32,13 @@ const askAI = async ({ model, yorha, dialog, openAI, messages, response_format =
32
32
  }
33
33
  }
34
34
 
35
- module.exports = ({ config, yorha, openAI, dialog, prompts, template }) => {
35
+ module.exports = ({ utils, yorha, openAI, dialog, prompts }) => {
36
36
 
37
37
  const sharp = require('sharp')
38
38
 
39
- const { textModel, visionModel } = config
40
39
  const { api, mock, system, council } = prompts
41
40
  const { UI_DESIGNER, API_DESIGNER, MOCK_DESIGNER } = system
41
+ const { textModel, visionModel } = utils.foundation.getConfig()
42
42
 
43
43
  return {
44
44
  generateMock: async ({ columns, fileName }) => {
@@ -65,19 +65,7 @@ module.exports = ({ config, yorha, openAI, dialog, prompts, template }) => {
65
65
  ]
66
66
  })
67
67
  },
68
- alignResponseFields: async ({ responseStr, resourceStr }) => {
69
- return askAI({
70
- yorha,
71
- openAI,
72
- dialog,
73
- model: textModel,
74
- messages: [
75
- { role: 'system', content: API_DESIGNER },
76
- { role: 'user', content: api({ responseStr, resourceStr }) }
77
- ]
78
- })
79
- },
80
- recognizePage: async ({ prompt, filePath, taskType = 'page' }) => {
68
+ recognizePage: async ({ prompt, filePath, schema }) => {
81
69
  const compressedBuffer = await sharp(filePath)
82
70
  .resize(1280, null, { withoutEnlargement: true })
83
71
  .jpeg({ quality: 80 })
@@ -99,7 +87,19 @@ module.exports = ({ config, yorha, openAI, dialog, prompts, template }) => {
99
87
  ]
100
88
  }
101
89
  ],
102
- response_format: taskType === 'page' ? { type: 'json_schema', strict: true, json_schema: require(`../framework/${template}/schema/page.json`) } : { type: 'json_object' }
90
+ response_format: schema ? { strict: true, type: 'json_schema', json_schema: schema } : { type: 'json_object' }
91
+ })
92
+ },
93
+ alignResponseFields: async ({ responseStr, resourceStr }) => {
94
+ return askAI({
95
+ yorha,
96
+ openAI,
97
+ dialog,
98
+ model: textModel,
99
+ messages: [
100
+ { role: 'system', content: API_DESIGNER },
101
+ { role: 'user', content: api({ responseStr, resourceStr }) }
102
+ ]
103
103
  })
104
104
  },
105
105
  }
@@ -4,8 +4,8 @@ module.exports = () => {
4
4
  const path = require('path')
5
5
  const OpenAI = require('openai')
6
6
 
7
- const pkgEnv = path.resolve(__dirname, '../.env')
8
- const localEnv = path.resolve(process.cwd(), '.env')
7
+ const pkgEnv = path.resolve(__dirname, '../../.env')
8
+ const localEnv = path.resolve(process.cwd(), 'bunker', '.env')
9
9
  require('dotenv').config({ path: fs.existsSync(localEnv) ? localEnv : pkgEnv })
10
10
  const openAI = new OpenAI({ apiKey: process.env.API_KEY, baseURL: process.env.BASE_URL })
11
11
 
@@ -5,9 +5,11 @@ let instance = null
5
5
 
6
6
  module.exports = {
7
7
 
8
- init: ({ template }, dialog) => {
8
+ init: async ({ template }, dialog, version, local) => {
9
9
 
10
- const yorha = require('./yorha')()
10
+ const recruiter = require('../kernel/recruiter')
11
+ const utils = recruiter(path.join(__dirname, '../utils'))
12
+ const yorha = utils.ux.yorha()
11
13
 
12
14
  const generatorPath = path.join(__dirname, `../framework/${template}/generator`)
13
15
  if (!fs.existsSync(generatorPath)) {
@@ -15,27 +17,24 @@ module.exports = {
15
17
  return
16
18
  }
17
19
 
18
- const foundation = require('../utils/foundation')
19
- const config = foundation.getConfig()
20
-
21
20
  const accessPoint = {
21
+ utils,
22
22
  yorha,
23
- config,
24
23
  dialog,
25
24
  template,
26
- foundation,
27
- openAI: require('./openai')(),
28
- core: require('../utils/core'),
29
- menus: foundation.getExistingMenus(),
30
- handlers: foundation.discover(path.join(__dirname, '../handlers')),
31
- handlebars: require('./handlebar')({ config, template, ...foundation }),
32
- prompts: foundation.discover(path.join(__dirname, `../framework/${template}/prompts`)),
25
+ openAI: require('../ai/openai')(),
26
+ engine: require('../kernel/engine')({ utils, template }),
27
+ handlers: recruiter(path.join(__dirname, '../handlers')),
28
+ prompts: recruiter(path.join(__dirname, `../framework/${template}/prompts`)),
33
29
  }
34
30
 
35
- require('./foundation')(accessPoint)
36
- const llm = require('../services/llm')(accessPoint)
31
+ if (version) {
32
+ await utils.ux.bootSequence(version, local)
33
+ }
34
+ require('../kernel/deployment')(accessPoint)
35
+ const llm = require('../ai')(accessPoint)
37
36
  const generator = require(generatorPath)(accessPoint)
38
- const labs = require('./labs')({ llm, ...accessPoint })
37
+ const labs = require('../labs')({ llm, ...accessPoint })
39
38
 
40
39
 
41
40
  instance = { llm, labs, generator, ...accessPoint }
@@ -55,7 +54,7 @@ module.exports = {
55
54
 
56
55
  reboot() {
57
56
  const { template, dialog } = instance
58
- delete require.cache[require.resolve(path.join(process.cwd(), 'config.js'))]
57
+ delete require.cache[require.resolve(path.join(process.cwd(), 'bunker', 'config.js'))]
59
58
  instance.labs?.tower?.close()
60
59
  instance = null
61
60
  return this.init({ template }, dialog)
@@ -5,16 +5,17 @@ module.exports = () => {
5
5
  const chokidar = require('chokidar')
6
6
 
7
7
  const bootstrap = require('../bootstrap')
8
- const ctx = bootstrap.get()
8
+ const queue = require('../kernel/queue')(2)
9
9
 
10
- const queue = ctx.core.createTaskQueue(2)
10
+ const ctx = bootstrap.get()
11
11
  const routes = Object.values(ctx.handlers)
12
+ const config = ctx.utils.foundation.getConfig()
12
13
 
13
14
  queue.onIdle(() => {
14
15
  ctx.yorha.pod042.report(ctx.dialog.pod042.queueEmpty)
15
- const utilsDir = path.join(process.cwd(), ctx.config.utilsDir)
16
+ const utilsDir = path.join(process.cwd(), config.utilsDir)
16
17
  if (!fs.existsSync(utilsDir)) fs.mkdirSync(utilsDir, { recursive: true })
17
- fs.writeFileSync(path.join(utilsDir, 'menus.js'), `export const menus = ${ctx.foundation.contextStringify({ context: ctx.menus, maxLength: 50 })}`)
18
+ fs.writeFileSync(path.join(utilsDir, 'menus.js'), `export const menus = ${ctx.utils.generator.contextStringify({ context: ctx.menus, maxLength: 50 })}`)
18
19
  ctx.yorha.commander.report(ctx.dialog.bunker.systemStandby, 'gray')
19
20
  })
20
21
 
@@ -25,8 +26,8 @@ module.exports = () => {
25
26
  awaitWriteFinish: { stabilityThreshold: 500, pollInterval: 100 }
26
27
  }
27
28
 
28
- const fileWatcher = chokidar.watch(['./config.js'], options)
29
- const dirWatcher = chokidar.watch(routes.map(route => `${route.watch}`), options)
29
+ const fileWatcher = chokidar.watch(['./bunker/config.js'], options)
30
+ const dirWatcher = chokidar.watch(routes.map(route => `./bunker/${route.watch}`), options)
30
31
 
31
32
  ctx.yorha.operator6O.report(ctx.dialog.operator6O.call2B)
32
33
 
@@ -1,9 +1,8 @@
1
- module.exports = ({ core, config, handlebars, foundation }) => {
1
+ module.exports = ({ utils, engine }) => {
2
2
 
3
- const { contextStringify } = foundation
4
- const { indexTpl, resourceTpl } = handlebars
5
- const { needMock, responseSuccess } = config
6
- const { cleanCode, generateSmartImports, formatFormItemAndColumns } = core
3
+ const { indexTpl, resourceTpl } = engine
4
+ const { needMock, responseSuccess } = utils.foundation.getConfig()
5
+ const { cleanCode, contextStringify, generateSmartImports, formatFormItemAndColumns } = utils.generator
7
6
 
8
7
  return {
9
8
  index: ({ fileName, pageConfig }) => {
@@ -38,7 +38,7 @@ const onTabChange = key => {
38
38
  {{#if hasExpandable}}
39
39
  const onExpand = async (expanded, record) => {
40
40
  if (expanded) {
41
- setExpandedRowKeys(prev=>[...prev, record[rowKey])
41
+ setExpandedRowKeys(prev=>[...prev, record[rowKey]])
42
42
  } else {
43
43
  setExpandedRowKeys(prev=>prev.filter(item => item !== record[rowKey]))
44
44
  }
@@ -6,12 +6,13 @@ module.exports = {
6
6
  async handle(filePath, liveResponse = null) {
7
7
 
8
8
  const chalk = require('chalk')
9
- const { llm, core, labs, yorha, dialog, config } = require('../bootstrap').get()
9
+ const { llm, utils, labs, yorha, dialog } = require('../bootstrap').get()
10
10
 
11
- const { pagesDir } = config
12
11
  const { nineS, pod153 } = yorha
13
12
  const { alignResponseFields } = llm
14
- const { cleanCode, unwrapSignal } = core
13
+ const { cleanCode } = utils.generator
14
+ const { unwrapSignal } = utils.semantic
15
+ const { pagesDir } = utils.foundation.getConfig()
15
16
 
16
17
  const startTime = Date.now()
17
18
  const fileName = liveResponse?.fileName ?? path.basename(filePath, path.extname(filePath))
@@ -5,17 +5,18 @@ module.exports = {
5
5
  watch: 'screenShot',
6
6
  async handle(filePath) {
7
7
 
8
- const { llm, menus, yorha, dialog, config, prompts, generator, foundation } = require('../bootstrap').get()
8
+ const { llm, utils, yorha, dialog, prompts, template, generator } = require('../bootstrap').get()
9
9
 
10
10
  const { page } = prompts
11
11
  const { nineS, pod042 } = yorha
12
12
  const { index, resource } = generator
13
- const { contextStringify } = foundation
14
13
  const { generateMock, recognizePage } = llm
15
- const { useDemo, pagesDir, needMock } = config
14
+ const { contextStringify } = utils.generator
15
+ const { useDemo, pagesDir, needMock } = utils.foundation.getConfig()
16
16
 
17
17
 
18
18
  const startTime = Date.now()
19
+ const menus = utils.foundation.getExistingMenus(pagesDir)
19
20
  const fileName = path.basename(filePath, path.extname(filePath))
20
21
  const mockDir = path.join(process.cwd(), 'mock')
21
22
  const targetDir = path.join(process.cwd(), pagesDir, fileName)
@@ -37,7 +38,7 @@ module.exports = {
37
38
  pageConfig = require('../../example/example.json')
38
39
  } else {
39
40
  pod042.update(spinner, dialog.pod042.uploadVisualMetadata)
40
- pageConfig = await recognizePage({ prompt: page(fileName), filePath })
41
+ pageConfig = await recognizePage({ prompt: page(fileName), filePath, schema: require(`../framework/${template}/schema/page.json`) })
41
42
  }
42
43
 
43
44
  fs.writeFileSync(path.join(targetDir, 'resource.js'), resource({ pageConfig }))
@@ -62,6 +63,9 @@ module.exports = {
62
63
  }
63
64
 
64
65
  } catch (error) {
66
+ if (fs.existsSync(targetDir)) {
67
+ fs.rmSync(targetDir, { recursive: true, force: true })
68
+ }
65
69
  pod042.fail(spinner, dialog.pod042.constructionAborted(error))
66
70
  }
67
71
  }
@@ -5,13 +5,12 @@ module.exports = {
5
5
  async handle(filePath) {
6
6
 
7
7
  const chalk = require('chalk')
8
- const { llm, core, yorha, dialog, prompts, foundation } = require('../bootstrap').get()
8
+ const { llm, utils, yorha, dialog, prompts } = require('../bootstrap').get()
9
9
 
10
10
  const { pod042 } = yorha
11
11
  const { recognizePage } = llm
12
12
  const { part: prompt } = prompts
13
- const { contextStringify } = foundation
14
- const { cleanCode, formatFormItemAndColumns } = core
13
+ const { cleanCode, contextStringify, formatFormItemAndColumns } = utils.generator
15
14
 
16
15
  const startTime = Date.now()
17
16
 
@@ -20,7 +19,7 @@ module.exports = {
20
19
  try {
21
20
  pod042.update(spinner, dialog.pod042.extractingUiMetadata)
22
21
 
23
- const pageConfig = await recognizePage({ prompt, filePath, taskType: 'part' })
22
+ const pageConfig = await recognizePage({ prompt, filePath })
24
23
 
25
24
  const { formItems, dictBlocks, processedColumns } = formatFormItemAndColumns({ pageConfig })
26
25
 
@@ -41,7 +40,7 @@ module.exports = {
41
40
  console.log(chalk.magenta(`\n┌────────────────── [ YoRHa Construction Output ] ─────────────────┐`))
42
41
  console.log(chalk.magenta(`│ Source: ${filePath}`))
43
42
  console.log(chalk.magenta(`│ Protocol: Partial UI Fragment | Status: SUCCESS`))
44
- console.log(chalk.magenta(`├───────────────────────────────────────────────────────────────────┘`))
43
+ console.log(chalk.magenta(`├──────────────────────────────────────────────────────────────────┘`))
45
44
  console.log(chalk.white(finalResult))
46
45
  pod042.success(spinner, dialog.pod042.partialConstruction((endTime - startTime) / 1000))
47
46
  pod042.success(spinner, dialog.pod042.partialRecommendation)