htmlgen-mcp 0.3.9__py3-none-any.whl → 0.4.8__py3-none-any.whl

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.
@@ -154,7 +154,8 @@ async def get_progress_optimized(
154
154
  "job_id", "status", "plan_id", "progress_log",
155
155
  "started_at", "updated_at", "completed_at",
156
156
  "project_directory", "model", "upload_status",
157
- "website_url", "upload_completed_at"
157
+ "upload_url", "web_url", "deployment_env",
158
+ "upload_completed_at", "uploaded_directory"
158
159
  ]
159
160
  job_snapshot = {
160
161
  k: job_info.get(k) for k in snapshot_keys
@@ -192,4 +193,4 @@ async def get_progress_optimized(
192
193
  return {
193
194
  "status": "error",
194
195
  "message": str(exc)
195
- }
196
+ }
@@ -44,8 +44,9 @@ DEFAULT_PROJECT_ROOT = os.path.abspath(
44
44
  )
45
45
  # 是否自动生成项目子目录(可通过环境变量控制)
46
46
  AUTO_CREATE_PROJECT_DIR = os.environ.get("AUTO_CREATE_PROJECT_DIR", "true").lower() == "true"
47
- # 默认的文件上传URL(可通过环境变量 UPLOAD_URL 覆盖)
48
- DEFAULT_UPLOAD_URL = os.environ.get("UPLOAD_URL", "https://www.mcpcn.cc/api/fileUploadAndDownload/uploadMcpFile")
47
+ DEFAULT_UPLOAD_URL = os.environ.get(
48
+ "UPLOAD_URL", "https://www.mcpcn.cc/api/fileUploadAndDownload/uploadMcpFile"
49
+ )
49
50
  DEFAULT_MODEL = os.environ.get("WEB_AGENT_MODEL", "qwen3-coder-plus-2025-09-23")
50
51
  DEFAULT_BASE_URL = os.environ.get(
51
52
  "OPENAI_BASE_URL", "https://dashscope.aliyuncs.com/compatible-mode/v1"
@@ -85,6 +86,38 @@ _CONTEXT_CACHE_BY_ID: dict[str, Dict[str, Any]] = {}
85
86
  _CONTEXT_ID_BY_PLAN: dict[str, str] = {}
86
87
 
87
88
 
89
+ def _resolve_edgeone_deploy_env() -> str:
90
+ """解析 EdgeOne 自动部署环境,默认 Production。"""
91
+ env_value = (
92
+ os.environ.get("EDGEONE_AUTO_DEPLOY_ENV")
93
+ or os.environ.get("EDGEONE_PAGES_DEPLOY_ENV")
94
+ or "Production"
95
+ )
96
+ return env_value if env_value in {"Production", "Preview"} else "Production"
97
+
98
+
99
+ def _should_upload_zip_to_oss() -> bool:
100
+ """是否在 EdgeOne 部署前上传 ZIP 到 OSS。"""
101
+ flag = os.environ.get("KEEP_OSS_UPLOAD", "true").strip().lower()
102
+ return flag not in {"0", "false", "no", "off"}
103
+
104
+
105
+ def _extract_zip_url(upload_result: Dict[str, Any]) -> Optional[str]:
106
+ """从上传结果中提取包含 .zip 的下载地址。"""
107
+ try:
108
+ candidates = [
109
+ upload_result.get("oss_url"),
110
+ upload_result.get("upload_url"),
111
+ (upload_result.get("oss_response") or {}).get("url"),
112
+ upload_result.get("url"),
113
+ ]
114
+ for candidate in candidates:
115
+ if candidate and ".zip" in str(candidate).lower():
116
+ return candidate
117
+ except Exception:
118
+ pass
119
+ return None
120
+
88
121
  def _job_state_path(job_id: str) -> Path:
89
122
  return JOB_STATE_DIR / f"{job_id}.json"
90
123
 
@@ -464,37 +497,32 @@ async def execute_plan(
464
497
  # confirm_each_step: bool = False, # 后台执行模式下用户无法交互确认
465
498
  # show_code: bool = False, # 后台执行时用户看不到输出
466
499
  # verbose: bool = False, # 后台执行时详细日志意义不大
467
- save_output: bool = False,
500
+ # save_output: bool = True, # 已固定为 True,始终创建进度日志
468
501
  progress_log: Optional[str] = None,
469
502
  ) -> Dict[str, Any]:
470
503
  """执行网页构建计划,始终以后台模式运行。
471
504
 
472
505
  参数详细说明:
473
506
  - plan_id: 计划的唯一标识符
474
- plan_site 工具返回的计划ID,用于从缓存或文件系统中查找对应的执行计划。
507
+ create_simple_site 工具返回的计划ID,用于从缓存或文件系统中查找对应的执行计划。
475
508
  例如:"a1b2c3d4e5f6..." 这样的32位十六进制字符串。
476
509
 
477
- - project_root: 网站文件生成的目标目录路径
510
+ - project_root: 网站文件生成的目标目录路径(可选)
478
511
  指定项目文件的输出位置,可以是绝对路径或相对路径。
479
512
  例如:"/path/to/my/website" 或 "./my-project"
480
513
  如果目录不存在,系统会自动创建。
481
-
482
- - save_output: 是否保存执行过程的详细输出到文件
483
- True: 会自动创建进度日志文件,记录所有执行步骤和结果
484
- False: 不创建进度日志文件,只保留基本的任务状态信息
485
- 建议在调试或需要详细追踪时设置为 True
514
+ 如果未指定,将使用计划中保存的项目目录。
486
515
 
487
516
  - progress_log: 自定义进度日志文件的保存路径(可选)
488
517
  如果指定:使用该路径保存进度日志(JSONL格式)
489
- 如果未指定但 save_output=True:自动在 ~/.mcp/make_web/progress_logs 目录创建时间戳命名的日志文件(可通过环境变量覆盖)
490
- 如果都未指定:不记录进度日志
518
+ 如果未指定:自动在 ~/.mcp/make_web/progress_logs 目录创建时间戳命名的日志文件(可通过环境变量覆盖)
491
519
  路径可以是绝对路径或相对于 project_root 的相对路径
492
520
 
493
521
  执行流程:
494
- - 任务始终在后台异步执行,立即返回 job_id 和 progress_log 路径
495
- - 使用 get_progress(job_id=..., limit=...) 可以实时查询执行状态和进度
496
- - 支持通过进度日志文件追踪详细的执行步骤和结果
497
- - 执行完成后可以获取完整的执行报告、生成文件列表,以及自动上传结果
522
+ - 任务在后台异步执行,立即返回 job_id 和 progress_log 路径
523
+ - 任务完成后,系统会自动推送通知给用户,包含执行报告、生成文件列表和上传结果
524
+ - 系统会自动记录详细的执行步骤和结果到进度日志文件
525
+ - 如需实时了解任务进展或调试,可使用 get_progress(job_id=...) 工具手动查询状态
498
526
  """
499
527
  try:
500
528
  # 如果没有提供project_root,尝试从缓存中获取
@@ -517,36 +545,38 @@ async def execute_plan(
517
545
  break
518
546
  except Exception:
519
547
  pass
520
-
548
+
521
549
  if not project_root:
522
550
  # 使用默认根目录,但不添加子目录
523
551
  project_root = None
524
-
552
+
525
553
  # 从计划中获取项目名称(如果有)
526
554
  project_name = None
527
555
  if plan_id:
528
556
  cached_plan = _PLAN_CACHE_BY_ID.get(plan_id)
529
557
  if cached_plan:
530
558
  # 尝试从缓存中获取项目名称
531
- project_name = cached_plan.get("site_title") or cached_plan.get("project_name")
532
-
533
- project_dir = _resolve_project_directory(project_root, project_name)
559
+ project_name = cached_plan.get("site_title") or cached_plan.get(
560
+ "project_name"
561
+ )
534
562
 
535
- # 移除 auto_plan 检查,因为参数已被移除
563
+ project_dir = _resolve_project_directory(project_root, project_name)
536
564
 
565
+ # 进度日志始终启用
537
566
  if progress_log:
567
+ # 用户指定了自定义日志路径
538
568
  progress_log_path = (
539
569
  progress_log
540
570
  if os.path.isabs(progress_log)
541
571
  else os.path.join(project_dir, progress_log)
542
572
  )
543
- elif save_output:
573
+ else:
574
+ # 自动生成日志文件
544
575
  progress_log_path = os.path.join(
545
576
  PROGRESS_LOG_DIR, f"agent_progress_{int(time.time())}.jsonl"
546
577
  )
547
- else:
548
- progress_log_path = None
549
578
 
579
+ # 尝试创建日志文件
550
580
  if progress_log_path:
551
581
  try:
552
582
  Path(progress_log_path).parent.mkdir(parents=True, exist_ok=True)
@@ -554,9 +584,10 @@ async def execute_plan(
554
584
  except Exception:
555
585
  progress_log_path = None
556
586
 
587
+ # save_output 固定为 True
557
588
  agent = _build_agent(
558
589
  project_dir,
559
- save_output=save_output,
590
+ save_output=True,
560
591
  )
561
592
 
562
593
  # 通过 plan_id 查询计划
@@ -627,6 +658,7 @@ async def execute_plan(
627
658
  "project_directory": project_dir,
628
659
  "model": agent.model,
629
660
  "progress_log": progress_log_path,
661
+ "deployment_env": _resolve_edgeone_deploy_env(),
630
662
  "started_at": time.time(),
631
663
  "updated_at": time.time(),
632
664
  }
@@ -658,7 +690,9 @@ async def execute_plan(
658
690
  "job_id": job_id,
659
691
  "plan_id": plan_id,
660
692
  "progress_log": progress_log_path,
661
- "upload_url": DEFAULT_UPLOAD_URL,
693
+ "upload_url": None,
694
+ "web_url": None,
695
+ "deployment_env": job_info["deployment_env"],
662
696
  "message": message,
663
697
  }
664
698
  except Exception as exc:
@@ -715,29 +749,71 @@ async def _handle_auto_upload(
715
749
  if not project_dir:
716
750
  return
717
751
 
752
+ upload_target = project_dir
753
+
754
+ created_files = (job_info.get("result") or {}).get("created_files") or []
755
+ for file_path in created_files:
756
+ if not file_path:
757
+ continue
758
+ try:
759
+ candidate_path = file_path
760
+ if not os.path.isabs(candidate_path):
761
+ candidate_path = os.path.join(project_dir, candidate_path)
762
+ if not os.path.exists(candidate_path):
763
+ continue
764
+ candidate_dir = (
765
+ candidate_path if os.path.isdir(candidate_path) else os.path.dirname(candidate_path)
766
+ )
767
+ rel_path = os.path.relpath(candidate_dir, project_dir)
768
+ if rel_path == "." or rel_path.startswith(".."):
769
+ continue
770
+ top_level = rel_path.split(os.sep, 1)[0]
771
+ top_level_dir = os.path.join(project_dir, top_level)
772
+ if os.path.isdir(top_level_dir):
773
+ upload_target = top_level_dir
774
+ break
775
+ except Exception:
776
+ continue
777
+
718
778
  job_info["upload_status"] = "uploading"
719
779
  _persist_job_state(job_id)
720
780
 
721
781
  try:
722
- upload_result = await upload_project_to_mcp_server(
723
- folder_path=project_dir,
724
- upload_url=DEFAULT_UPLOAD_URL,
725
- )
782
+ upload_func = getattr(upload_project_to_mcp_server, "fn", None)
783
+ if not callable(upload_func):
784
+ raise RuntimeError("upload_project_to_mcp_server 缺少可调用实现")
785
+
786
+ upload_result = await upload_func(folder_path=upload_target)
726
787
 
727
788
  job_info["upload_result"] = upload_result
728
789
  job_info["upload_status"] = upload_result.get("status")
790
+ if upload_result.get("deployment_env"):
791
+ job_info["deployment_env"] = upload_result["deployment_env"]
729
792
 
730
793
  if upload_result.get("status") == "success":
731
- job_info["website_url"] = upload_result.get("url")
794
+ zip_url = _extract_zip_url(upload_result)
795
+ web_url = (
796
+ upload_result.get("web_url")
797
+ or (upload_result.get("result") or {}).get("url")
798
+ )
799
+ if zip_url:
800
+ job_info["upload_url"] = zip_url
801
+ if web_url:
802
+ job_info["web_url"] = web_url
732
803
  job_info["upload_completed_at"] = time.time()
804
+ job_info["uploaded_directory"] = upload_target
733
805
 
734
806
  if progress_log_path:
735
807
  upload_event = {
736
808
  "timestamp": time.time(),
737
809
  "type": "upload_completed",
738
810
  "status": "success",
739
- "website_url": upload_result.get("url"),
811
+ "web_url": web_url,
812
+ "upload_url": zip_url,
813
+ "oss_url": zip_url,
814
+ "deployment_env": job_info.get("deployment_env"),
740
815
  "message": upload_result.get("message"),
816
+ "uploaded_directory": upload_target,
741
817
  }
742
818
  try:
743
819
  with open(progress_log_path, "a", encoding="utf-8") as log_file:
@@ -781,7 +857,7 @@ async def create_simple_site(
781
857
  使用流程:
782
858
  1. 调用此工具生成计划,获得 plan_id
783
859
  2. 使用 plan_id 调用 execute_plan 执行构建
784
- 3. 使用 plan_id 调用 get_progress 查询进度
860
+ 3. 构建完成后会自动推送通知给用户,包含项目文件和访问链接
785
861
 
786
862
  💡 使用提示:
787
863
  如果你有地图查询结果、API数据等,请将完整信息传递给 context_content 参数,
@@ -1097,8 +1173,11 @@ async def get_progress(
1097
1173
  "project_directory",
1098
1174
  "model",
1099
1175
  "upload_status",
1100
- "website_url",
1176
+ "upload_url",
1177
+ "web_url",
1178
+ "deployment_env",
1101
1179
  "upload_completed_at",
1180
+ "uploaded_directory",
1102
1181
  ]
1103
1182
  job_snapshot = {
1104
1183
  k: job_info.get(k) for k in snapshot_keys if job_info.get(k) is not None
@@ -1133,15 +1212,17 @@ async def get_progress(
1133
1212
  async def upload_project_to_mcp_server(
1134
1213
  folder_path: str,
1135
1214
  ) -> Dict[str, Any]:
1136
- """将项目文件夹打包成ZIP并上传到MCP服务器。
1215
+ """将项目文件夹打包成ZIP并上传到 EdgeOne Pages(自动部署流程)。
1137
1216
 
1138
1217
  参数说明:
1139
1218
  - folder_path: 项目文件夹的绝对路径
1140
1219
 
1141
1220
  返回值:
1142
1221
  - status: 上传状态 ("success" 或 "error")
1143
- - url: 上传成功后返回的文件访问URL
1144
- - zip_path: 临时ZIP文件路径(用于调试)
1222
+ - web_url: 部署成功后返回的 EdgeOne 访问地址
1223
+ - deployment_env: 部署环境(Production/Preview)
1224
+ - deployment_result: EdgeOne 原始部署结果
1225
+ - deployment_logs: 部署日志
1145
1226
  - message: 状态信息
1146
1227
  """
1147
1228
  try:
@@ -1152,6 +1233,12 @@ async def upload_project_to_mcp_server(
1152
1233
  if not os.path.isdir(folder_path):
1153
1234
  return {"status": "error", "message": f"路径不是文件夹: {folder_path}"}
1154
1235
 
1236
+ if not os.getenv("EDGEONE_PAGES_API_TOKEN"):
1237
+ return {
1238
+ "status": "error",
1239
+ "message": "缺少 EDGEONE_PAGES_API_TOKEN 环境变量,无法执行 EdgeOne 部署",
1240
+ }
1241
+
1155
1242
  # 创建临时ZIP文件
1156
1243
  project_name = os.path.basename(folder_path.rstrip("/"))
1157
1244
  temp_dir = tempfile.gettempdir()
@@ -1176,52 +1263,85 @@ async def upload_project_to_mcp_server(
1176
1263
  "message": f"ZIP文件过大: {zip_size / 1024 / 1024:.1f}MB,超过50MB限制",
1177
1264
  }
1178
1265
 
1179
- # 上传文件
1180
- async with aiohttp.ClientSession() as session:
1181
- with open(zip_path, "rb") as f:
1182
- data = aiohttp.FormData()
1183
- data.add_field(
1184
- "file", f, filename=zip_filename, content_type="application/zip"
1185
- )
1266
+ oss_url: Optional[str] = None
1267
+ oss_response: Optional[Dict[str, Any]] = None
1268
+ if _should_upload_zip_to_oss():
1269
+ async with aiohttp.ClientSession() as session:
1270
+ with open(zip_path, "rb") as f:
1271
+ data = aiohttp.FormData()
1272
+ data.add_field(
1273
+ "file", f, filename=zip_filename, content_type="application/zip"
1274
+ )
1275
+
1276
+ async with session.post(DEFAULT_UPLOAD_URL, data=data) as response:
1277
+ response_text = await response.text()
1186
1278
 
1187
- async with session.post(DEFAULT_UPLOAD_URL, data=data) as response:
1188
- response_text = await response.text()
1189
-
1190
- if response.status != 200:
1191
- return {
1192
- "status": "error",
1193
- "message": f"上传失败,HTTP {response.status}: {response_text}",
1194
- }
1195
-
1196
- # 解析响应JSON
1197
- try:
1198
- result = json.loads(response_text)
1199
- if result.get("code") == 0 and result.get("data", {}).get(
1200
- "url"
1201
- ):
1202
- # 清理临时文件
1203
- try:
1204
- os.remove(zip_path)
1205
- except:
1206
- pass
1279
+ if response.status != 200:
1280
+ return {
1281
+ "status": "error",
1282
+ "message": f"OSS 上传失败,HTTP {response.status}: {response_text}",
1283
+ }
1207
1284
 
1285
+ try:
1286
+ result = json.loads(response_text)
1287
+ except json.JSONDecodeError:
1208
1288
  return {
1209
- "status": "success",
1210
- "url": result["data"]["url"],
1211
- "message": f"项目 '{project_name}' 上传成功",
1212
- "zip_size": f"{zip_size / 1024:.1f}KB",
1289
+ "status": "error",
1290
+ "message": f"OSS 上传响应解析失败: {response_text}",
1213
1291
  }
1292
+
1293
+ upload_data = result.get("data") or {}
1294
+ oss_response = upload_data
1295
+ if result.get("code") == 0 and upload_data.get("url"):
1296
+ oss_url = upload_data["url"]
1214
1297
  else:
1215
1298
  return {
1216
1299
  "status": "error",
1217
- "message": f"上传失败: {result.get('msg', '未知错误')}",
1300
+ "message": f"OSS 上传失败: {result.get('msg', '未知错误')}",
1218
1301
  "response": response_text,
1219
1302
  }
1220
- except json.JSONDecodeError:
1221
- return {
1222
- "status": "error",
1223
- "message": f"响应解析失败: {response_text}",
1224
- }
1303
+
1304
+ # 导入 EdgeOne 部署工具
1305
+ from htmlgen_mcp.agents.web_tools.edgeone_deploy import (
1306
+ deploy_folder_or_zip_to_edgeone,
1307
+ )
1308
+
1309
+ deployment_env = _resolve_edgeone_deploy_env()
1310
+
1311
+ # 将 ZIP 包部署到 EdgeOne(使用线程避免阻塞事件循环)
1312
+ result_json = await asyncio.to_thread(
1313
+ deploy_folder_or_zip_to_edgeone, zip_path, deployment_env
1314
+ )
1315
+
1316
+ try:
1317
+ deploy_result = json.loads(result_json)
1318
+ except json.JSONDecodeError:
1319
+ return {
1320
+ "status": "error",
1321
+ "message": f"EdgeOne 返回数据解析失败: {result_json}",
1322
+ }
1323
+
1324
+ edgeone_result = deploy_result.get("result") or {}
1325
+ web_url = edgeone_result.get("url")
1326
+
1327
+ response: Dict[str, Any] = {
1328
+ "status": "success",
1329
+ "web_url": web_url,
1330
+ "oss_url": oss_url,
1331
+ "oss_response": oss_response,
1332
+ "deployment_env": deployment_env,
1333
+ "deployment_result": edgeone_result,
1334
+ "deployment_logs": deploy_result.get("deployment_logs"),
1335
+ "zip_size": f"{zip_size / 1024:.1f}KB",
1336
+ "message": f"项目 '{project_name}' 已部署到 EdgeOne ({deployment_env})",
1337
+ }
1338
+ if oss_url:
1339
+ response["upload_url"] = oss_url
1340
+
1341
+ if not web_url:
1342
+ response["message"] += ",但未获取到访问链接"
1343
+
1344
+ return response
1225
1345
 
1226
1346
  except Exception as exc:
1227
1347
  # 清理临时文件
@@ -1231,11 +1351,42 @@ async def upload_project_to_mcp_server(
1231
1351
  except:
1232
1352
  pass
1233
1353
 
1234
- return {
1354
+ error_message = str(exc)
1355
+ try:
1356
+ # EdgeOne 部署错误通常是 JSON 字符串
1357
+ if error_message.startswith("{"):
1358
+ error_data = json.loads(error_message)
1359
+ error_response = {
1360
+ "status": "error",
1361
+ "message": error_data.get("error", error_message),
1362
+ "deployment_logs": error_data.get("deployment_logs", ""),
1363
+ "traceback": traceback.format_exc(),
1364
+ }
1365
+ if "oss_url" in locals() and oss_url:
1366
+ error_response["upload_url"] = oss_url
1367
+ if "oss_response" in locals() and oss_response:
1368
+ error_response["oss_response"] = oss_response
1369
+ return error_response
1370
+ except Exception:
1371
+ pass
1372
+
1373
+ error_response = {
1235
1374
  "status": "error",
1236
- "message": str(exc),
1375
+ "message": error_message,
1237
1376
  "traceback": traceback.format_exc(),
1238
1377
  }
1378
+ if "oss_url" in locals() and oss_url:
1379
+ error_response["upload_url"] = oss_url
1380
+ if "oss_response" in locals() and oss_response:
1381
+ error_response["oss_response"] = oss_response
1382
+ return error_response
1383
+ finally:
1384
+ # 确保清理临时ZIP文件
1385
+ if "zip_path" in locals() and os.path.exists(zip_path):
1386
+ try:
1387
+ os.remove(zip_path)
1388
+ except:
1389
+ pass
1239
1390
 
1240
1391
 
1241
1392
  @mcp.tool()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: htmlgen-mcp
3
- Version: 0.3.9
3
+ Version: 0.4.8
4
4
  Summary: AI-powered HTML website generator with auto-upload functionality via Model Context Protocol
5
5
  Author-email: HTML Generator Team <contact@htmlgen-mcp.com>
6
6
  License: MIT
@@ -97,7 +97,10 @@ print(f"状态: {progress['job']['status']}")
97
97
 
98
98
  # 如果启用了自动上传
99
99
  if progress['job'].get('upload_status') == 'success':
100
- print(f"网站地址: {progress['job']['website_url']}")
100
+ if progress['job'].get('upload_url'):
101
+ print(f"部署包下载: {progress['job']['upload_url']}")
102
+ if progress['job'].get('web_url'):
103
+ print(f"网站地址: {progress['job']['web_url']}")
101
104
  ```
102
105
 
103
106
  ## 🛠️ MCP 工具
@@ -105,7 +108,7 @@ if progress['job'].get('upload_status') == 'success':
105
108
  - `create_simple_site()` - 生成网站计划
106
109
  - `execute_plan()` - 执行网站构建
107
110
  - `get_progress()` - 查询构建进度
108
- - `upload_project_to_mcp_server()` - 手动上传项目
111
+ - `upload_project_to_mcp_server()` - 打包上传至 OSS 并部署到 EdgeOne Pages
109
112
  - `deploy_folder_or_zip()` - 部署到EdgeOne Pages
110
113
 
111
114
  ## 🔧 环境配置
@@ -124,11 +127,13 @@ WEB_AGENT_PROJECT_ROOT=/path/to/projects
124
127
  # EdgeOne Pages 部署(可选)
125
128
  EDGEONE_PAGES_API_TOKEN=your_token
126
129
  EDGEONE_PAGES_PROJECT_NAME=your_project
130
+ EDGEONE_AUTO_DEPLOY_ENV=Production # 支持 Production / Preview
131
+ KEEP_OSS_UPLOAD=true # 保留 OSS 压缩包上传(false 则跳过)
127
132
  ```
128
133
 
129
134
  ## 🎯 自动上传功能
130
135
 
131
- 构建完成时自动上传到云端,无需手动操作:
136
+ 构建完成时自动部署到 EdgeOne Pages,同时保留 OSS 压缩包链接:
132
137
 
133
138
  ```python
134
139
  # 启动带自动上传的构建
@@ -146,7 +151,10 @@ while True:
146
151
  if status == 'completed':
147
152
  upload_status = progress['job'].get('upload_status')
148
153
  if upload_status == 'success':
149
- print(f"🎉 网站已上线: {progress['job']['website_url']}")
154
+ if progress['job'].get('upload_url'):
155
+ print(f"📦 部署包下载: {progress['job']['upload_url']}")
156
+ if progress['job'].get('web_url'):
157
+ print(f"🎉 网站已上线: {progress['job']['web_url']}")
150
158
  break
151
159
  elif upload_status == 'failed':
152
160
  print("❌ 上传失败")
@@ -159,7 +167,7 @@ while True:
159
167
 
160
168
  - **构建阶段**: `running` → `completed`
161
169
  - **上传阶段**: `uploading` → `success`/`failed`
162
- - **最终结果**: `website_url` (成功时)
170
+ - **最终结果**: `upload_url` (OSS 压缩包下载地址,可选)、`web_url` (EdgeOne 访问地址)
163
171
 
164
172
  ## 🤝 贡献
165
173
 
@@ -7,8 +7,8 @@ htmlgen_mcp/nas_storage.py,sha256=HpgROy53vrYiBiXsUJO56GCoYZdyYR15iVvOBqyp7Yc,11
7
7
  htmlgen_mcp/progress_tools.py,sha256=SOScPSr3hEv4rvGzqvwUcomEFiPhhNxJ7CbWURlFpBs,5067
8
8
  htmlgen_mcp/progress_tracker.py,sha256=2TVduWNJJH08EQ7Vf9EpiwPjtp61JX7muSCdbGHZAfM,12210
9
9
  htmlgen_mcp/prompt_enhancer.py,sha256=8UIxt45vSNarS5uqfxC5thOfnGY7luDs2YjHZRx1GAM,7976
10
- htmlgen_mcp/sse_optimizations.py,sha256=_UTpgLtxgNAiiEkO5lPihOi1-eEQk6R4ejNParufrrc,6932
11
- htmlgen_mcp/web_agent_server.py,sha256=AITqK4X0-lcbbbqNJDyvBgEBfi81Sy21oKQ0cOxeOIc,50849
10
+ htmlgen_mcp/sse_optimizations.py,sha256=lkAizXEwJxDuhf0ZiaHg_N-RYsfVd1USnd1p9UTLT38,7003
11
+ htmlgen_mcp/web_agent_server.py,sha256=Jna9yYMxz2IdZPMV9gyYRq9UxZbGgAA6FmIccWaDeWQ,56671
12
12
  htmlgen_mcp/agents/__init__.py,sha256=Xydfjzw9s9O6I5Ixx6EmsTdXu26136NDPUAqt9B1hzE,121
13
13
  htmlgen_mcp/agents/ai_content_generator.py,sha256=tWGC9cY6Wp7MB1P9J7uCv8LUdiS02rgS6vxaNHD7KQk,10311
14
14
  htmlgen_mcp/agents/quick_generator.py,sha256=2wV4PCRugV0suTedLDV91_etHy_2Fiw4J0MraT7MQjw,34201
@@ -31,8 +31,8 @@ htmlgen_mcp/agents/web_tools/simple_css.py,sha256=kj9X3sHHhj1wGwBVL20j6w2qIHXRdx
31
31
  htmlgen_mcp/agents/web_tools/simple_js.py,sha256=xMiuF-u-h_IIkUONZIa4Xf8vKB5mcXxwQf5b_BIcpoE,12174
32
32
  htmlgen_mcp/agents/web_tools/simple_templates.py,sha256=-Rs-SsWpGZT2hiwa3jZNVDHOMZOo1vV2pWbmBdR30os,6471
33
33
  htmlgen_mcp/agents/web_tools/validation.py,sha256=bNA6aWXrCSi7sPqQw5bBR3XF69gRf85D5jSMi996CtI,2069
34
- htmlgen_mcp-0.3.9.dist-info/METADATA,sha256=nzK-E-ngj-NNdwXiwjWSwEdSCqaGGubDzaLfyRxLndk,5161
35
- htmlgen_mcp-0.3.9.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
36
- htmlgen_mcp-0.3.9.dist-info/entry_points.txt,sha256=w7ufTQJobIxT3FYI24yKsCEwEQvBOWhNjckUd9Amu_k,66
37
- htmlgen_mcp-0.3.9.dist-info/top_level.txt,sha256=KnglzX4ekV8SQkHTsJg2_nTBXz2TxaYLdvoMMovHLNk,12
38
- htmlgen_mcp-0.3.9.dist-info/RECORD,,
34
+ htmlgen_mcp-0.4.8.dist-info/METADATA,sha256=fN2M_vuYxEquzylz0yjZBRloJuwSNfLNgIJC98BI3KY,5746
35
+ htmlgen_mcp-0.4.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
36
+ htmlgen_mcp-0.4.8.dist-info/entry_points.txt,sha256=w7ufTQJobIxT3FYI24yKsCEwEQvBOWhNjckUd9Amu_k,66
37
+ htmlgen_mcp-0.4.8.dist-info/top_level.txt,sha256=KnglzX4ekV8SQkHTsJg2_nTBXz2TxaYLdvoMMovHLNk,12
38
+ htmlgen_mcp-0.4.8.dist-info/RECORD,,