@whyshu/argent-engine 0.0.0-stage → 0.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.
Files changed (305) hide show
  1. package/MANIFEST.json +307 -0
  2. package/engine/VERSION +1 -0
  3. package/engine/agents/catalog.json +454 -0
  4. package/engine/configs/_aliases.proposed.json +651 -0
  5. package/engine/configs/_migration-plan.proposed.json +899 -0
  6. package/engine/configs/account.json +272 -0
  7. package/engine/configs/advanced.json +205 -0
  8. package/engine/configs/host.json +149 -0
  9. package/engine/configs/hr.json +27 -0
  10. package/engine/configs/notify.json +264 -0
  11. package/engine/core/cli/argent.mjs +277 -0
  12. package/engine/core/contracts/argent.contracts.json +1065 -0
  13. package/engine/core/contracts/verbs.schema.json +2539 -0
  14. package/engine/core/lib/argent-datadir.mjs +223 -0
  15. package/engine/core/lib/audit.mjs +187 -0
  16. package/engine/core/lib/claim.mjs +258 -0
  17. package/engine/core/lib/config-catalog.mjs +1172 -0
  18. package/engine/core/lib/doctor-customer.mjs +577 -0
  19. package/engine/core/lib/flow-list.mjs +138 -0
  20. package/engine/core/lib/flow-registry.mjs +48 -0
  21. package/engine/core/lib/init.mjs +247 -0
  22. package/engine/core/lib/ledger.mjs +124 -0
  23. package/engine/core/lib/license-activate.mjs +813 -0
  24. package/engine/core/lib/license-device.mjs +314 -0
  25. package/engine/core/lib/license-file.mjs +349 -0
  26. package/engine/core/lib/license-guard.mjs +123 -0
  27. package/engine/core/lib/license-ops.mjs +1645 -0
  28. package/engine/core/lib/license-verdict.mjs +133 -0
  29. package/engine/core/lib/license.mjs +577 -0
  30. package/engine/core/lib/notify/dedup.mjs +101 -0
  31. package/engine/core/lib/notify/feishu.mjs +38 -0
  32. package/engine/core/lib/notify/index.mjs +95 -0
  33. package/engine/core/lib/notify/verb.mjs +327 -0
  34. package/engine/core/lib/notify/webhook.mjs +135 -0
  35. package/engine/core/lib/notify/wecom.mjs +36 -0
  36. package/engine/core/lib/python.mjs +145 -0
  37. package/engine/core/lib/sop.mjs +116 -0
  38. package/engine/core/lib/versions.mjs +205 -0
  39. package/engine/core/mcp/client.mjs +67 -0
  40. package/engine/core/mcp/http.mjs +138 -0
  41. package/engine/core/mcp/server.mjs +702 -0
  42. package/engine/scripts/_engine_rules_probe.py +15 -0
  43. package/engine/scripts/analyze-full-day.py +568 -0
  44. package/engine/scripts/archive/feishu-bridge.js +246 -0
  45. package/engine/scripts/argent-agents.mjs +527 -0
  46. package/engine/scripts/argent-capabilities.mjs +776 -0
  47. package/engine/scripts/argent-catalog.mjs +186 -0
  48. package/engine/scripts/argent-datadir.py +62 -0
  49. package/engine/scripts/argent-doctor.mjs +624 -0
  50. package/engine/scripts/argent-env-write.mjs +302 -0
  51. package/engine/scripts/argent-schedule.mjs +620 -0
  52. package/engine/scripts/argent-setup-check.mjs +369 -0
  53. package/engine/scripts/argent-upgrade.mjs +1046 -0
  54. package/engine/scripts/base-bootstrap.sh +575 -0
  55. package/engine/scripts/billing-mode-daily.sh +12 -0
  56. package/engine/scripts/build-engine-package.mjs +123 -0
  57. package/engine/scripts/capability-packs.lock.json +484 -0
  58. package/engine/scripts/capability_pack.py +1242 -0
  59. package/engine/scripts/check-1.0-criteria.mjs +355 -0
  60. package/engine/scripts/check-agent-catalog.mjs +141 -0
  61. package/engine/scripts/check-billing-mode.sh +377 -0
  62. package/engine/scripts/check-child-sessions.mjs +83 -0
  63. package/engine/scripts/check-config-catalog.mjs +677 -0
  64. package/engine/scripts/check-docs-drift.mjs +522 -0
  65. package/engine/scripts/check-dsh-web-expose.sh +98 -0
  66. package/engine/scripts/check-judgment-drift.mjs +403 -0
  67. package/engine/scripts/check-license.mjs +199 -0
  68. package/engine/scripts/check-model-auth.py +443 -0
  69. package/engine/scripts/check-pack-closure.mjs +661 -0
  70. package/engine/scripts/check-portable-symbols.mjs +116 -0
  71. package/engine/scripts/check-preset-landing.mjs +124 -0
  72. package/engine/scripts/check-production-home.mjs +602 -0
  73. package/engine/scripts/check-role-mapping.mjs +461 -0
  74. package/engine/scripts/check-sample-redaction.mjs +320 -0
  75. package/engine/scripts/check-skill-classification.mjs +188 -0
  76. package/engine/scripts/check-sop-consistency.mjs +431 -0
  77. package/engine/scripts/check-test-env-safety.mjs +627 -0
  78. package/engine/scripts/check-version-consistency.mjs +452 -0
  79. package/engine/scripts/ci-run.sh +558 -0
  80. package/engine/scripts/config-explain.mjs +278 -0
  81. package/engine/scripts/configure-provider.rb +29 -0
  82. package/engine/scripts/customer-config-migrate.mjs +179 -0
  83. package/engine/scripts/customer-preflight.py +892 -0
  84. package/engine/scripts/customer-readiness.sh +134 -0
  85. package/engine/scripts/daily-report-inbox.py +242 -0
  86. package/engine/scripts/daily-report-reconcile.mjs +312 -0
  87. package/engine/scripts/daily-report.mjs +1310 -0
  88. package/engine/scripts/daily-report.sh +46 -0
  89. package/engine/scripts/data/lip-product-dict.json +306 -0
  90. package/engine/scripts/deliver-customer.mjs +932 -0
  91. package/engine/scripts/delivery-faces.txt +31 -0
  92. package/engine/scripts/desktop-trial.sh +146 -0
  93. package/engine/scripts/dev-window.sh +260 -0
  94. package/engine/scripts/drill-clean-machine.sh +315 -0
  95. package/engine/scripts/dsh-api-client.mjs +215 -0
  96. package/engine/scripts/dsh-backup-scope.sh +83 -0
  97. package/engine/scripts/dsh-offline-pack.mjs +77 -0
  98. package/engine/scripts/dsh-overlay-pin.sh +87 -0
  99. package/engine/scripts/dsh-plane.mjs +153 -0
  100. package/engine/scripts/dsh-portforward.py +223 -0
  101. package/engine/scripts/dsh-preflight.mjs +179 -0
  102. package/engine/scripts/dsh-release-watch-daily.sh +19 -0
  103. package/engine/scripts/dsh-release-watch.mjs +458 -0
  104. package/engine/scripts/dsh-remote-check.sh +99 -0
  105. package/engine/scripts/dsh-restart.sh +179 -0
  106. package/engine/scripts/dsh-restore.sh +111 -0
  107. package/engine/scripts/dsh-scope-rewire.mjs +803 -0
  108. package/engine/scripts/dsh-snapshot.mjs +116 -0
  109. package/engine/scripts/dsh-upgrade-readiness.mjs +165 -0
  110. package/engine/scripts/dsh-upgrade.mjs +612 -0
  111. package/engine/scripts/dsh-url.sh +86 -0
  112. package/engine/scripts/dsh-web-launch.mjs +155 -0
  113. package/engine/scripts/ensure-store-windows.py +509 -0
  114. package/engine/scripts/entitlements.py +458 -0
  115. package/engine/scripts/env_probe.py +411 -0
  116. package/engine/scripts/feishu-card.mjs +252 -0
  117. package/engine/scripts/fix-skill-frontmatter.py +209 -0
  118. package/engine/scripts/flow-auto-retry.py +454 -0
  119. package/engine/scripts/flow-requirements.json +720 -0
  120. package/engine/scripts/flow-scaffold.py +275 -0
  121. package/engine/scripts/flow-timers-plist.sh +86 -0
  122. package/engine/scripts/flow-timers.sh +182 -0
  123. package/engine/scripts/flow-trigger-wake.mjs +284 -0
  124. package/engine/scripts/flow-trigger.sh +571 -0
  125. package/engine/scripts/flow_billing.py +354 -0
  126. package/engine/scripts/flow_capability_stats.py +314 -0
  127. package/engine/scripts/flow_case.py +194 -0
  128. package/engine/scripts/flow_claim.py +497 -0
  129. package/engine/scripts/flow_config.py +1024 -0
  130. package/engine/scripts/flow_failure.py +588 -0
  131. package/engine/scripts/flow_learn.py +105 -0
  132. package/engine/scripts/flow_ledger.py +235 -0
  133. package/engine/scripts/flow_policy.py +238 -0
  134. package/engine/scripts/flow_preflight.py +339 -0
  135. package/engine/scripts/flow_registry.py +341 -0
  136. package/engine/scripts/flow_retry.py +304 -0
  137. package/engine/scripts/flow_return_to_ops.py +191 -0
  138. package/engine/scripts/flow_source.py +315 -0
  139. package/engine/scripts/flow_sources/__init__.py +53 -0
  140. package/engine/scripts/flow_sources/cases_json.py +106 -0
  141. package/engine/scripts/flow_sources/common.py +428 -0
  142. package/engine/scripts/flow_sources/feishu_base.py +273 -0
  143. package/engine/scripts/flow_stale.py +185 -0
  144. package/engine/scripts/flow_status_reconcile.py +344 -0
  145. package/engine/scripts/flow_triage.py +849 -0
  146. package/engine/scripts/flow_write_verify.py +496 -0
  147. package/engine/scripts/fulfillment.js +586 -0
  148. package/engine/scripts/gen-agent-bundles.mjs +276 -0
  149. package/engine/scripts/gen-preset-rows.mjs +259 -0
  150. package/engine/scripts/init-ml.sh +2275 -0
  151. package/engine/scripts/install-internal-role.sh +190 -0
  152. package/engine/scripts/install-license.mjs +641 -0
  153. package/engine/scripts/install-one-shot.mjs +665 -0
  154. package/engine/scripts/integration_contract.py +220 -0
  155. package/engine/scripts/integrations/wenyao/adapter.py +98 -0
  156. package/engine/scripts/integrations/xzh/adapter.py +75 -0
  157. package/engine/scripts/invoice-mapping.example.json +40 -0
  158. package/engine/scripts/invoice-table.sh +194 -0
  159. package/engine/scripts/invoice_carrier_notice.py +279 -0
  160. package/engine/scripts/invoice_fail_closeout.py +297 -0
  161. package/engine/scripts/invoice_lip_runner.py +1508 -0
  162. package/engine/scripts/invoice_lip_runner.py.bak-20260922-1710-freready +1090 -0
  163. package/engine/scripts/invoice_ready_audit.py +191 -0
  164. package/engine/scripts/invoice_runner.py +675 -0
  165. package/engine/scripts/invoice_stageb.py +516 -0
  166. package/engine/scripts/launchd/com.whyshu.argent-bridge.plist.example +42 -0
  167. package/engine/scripts/launchd/com.whyshu.fulfillment-poll.plist.example +29 -0
  168. package/engine/scripts/lease.py +377 -0
  169. package/engine/scripts/lib/agent-install.mjs +649 -0
  170. package/engine/scripts/lib/argent-datadir.mjs +16 -0
  171. package/engine/scripts/lib/argent_datadir.py +262 -0
  172. package/engine/scripts/lib/argent_filelock.py +507 -0
  173. package/engine/scripts/lib/bootcheck-wiring.mjs +510 -0
  174. package/engine/scripts/lib/cdp_ports.py +197 -0
  175. package/engine/scripts/lib/customer-env.mjs +102 -0
  176. package/engine/scripts/lib/daily-report-core.mjs +517 -0
  177. package/engine/scripts/lib/dep-declaration.mjs +81 -0
  178. package/engine/scripts/lib/deps-migrate.mjs +310 -0
  179. package/engine/scripts/lib/dsh-host-resolve.mjs +109 -0
  180. package/engine/scripts/lib/dsh-scope.mjs +500 -0
  181. package/engine/scripts/lib/dsh-snapshot-path.mjs +35 -0
  182. package/engine/scripts/lib/dsh-versions.mjs +96 -0
  183. package/engine/scripts/lib/dsh-web-probe.mjs +214 -0
  184. package/engine/scripts/lib/is-direct-run.mjs +61 -0
  185. package/engine/scripts/lib/patch-compose.mjs +241 -0
  186. package/engine/scripts/lib/patch-target.mjs +35 -0
  187. package/engine/scripts/lib/plugin-lifecycle.mjs +128 -0
  188. package/engine/scripts/lib/plugin-packages.mjs +332 -0
  189. package/engine/scripts/lib/preset-compat.mjs +127 -0
  190. package/engine/scripts/lib/preset-install.mjs +575 -0
  191. package/engine/scripts/lib/preset-mechanism.mjs +56 -0
  192. package/engine/scripts/lib/preset-sync.mjs +59 -0
  193. package/engine/scripts/lib/profile-retire.mjs +97 -0
  194. package/engine/scripts/lib/python-runtime.mjs +190 -0
  195. package/engine/scripts/lib/registry.mjs +72 -0
  196. package/engine/scripts/lib/repo-root.sh +56 -0
  197. package/engine/scripts/lib/schedule-mechanism.mjs +659 -0
  198. package/engine/scripts/lib/schedule-probe.mjs +835 -0
  199. package/engine/scripts/lib/scope-pointer.mjs +164 -0
  200. package/engine/scripts/lib/settings-panels.mjs +816 -0
  201. package/engine/scripts/lib/stdio_utf8.py +86 -0
  202. package/engine/scripts/lib/wake-auth.mjs +392 -0
  203. package/engine/scripts/lib/webdriver_ipc.py +264 -0
  204. package/engine/scripts/lib/zstd-frames.mjs +104 -0
  205. package/engine/scripts/license-e2e-drill.mjs +426 -0
  206. package/engine/scripts/license-gate.mjs +245 -0
  207. package/engine/scripts/lip_backlog.py +171 -0
  208. package/engine/scripts/lip_table.py +185 -0
  209. package/engine/scripts/local-usage.mjs +214 -0
  210. package/engine/scripts/migrate-providers.mjs +127 -0
  211. package/engine/scripts/migrate-skills.sh +65 -0
  212. package/engine/scripts/ml-oauth-setup.mjs +550 -0
  213. package/engine/scripts/ml-store-ids.json +26 -0
  214. package/engine/scripts/ml_artifact_attribution.py +333 -0
  215. package/engine/scripts/ml_capacity_probe.py +1158 -0
  216. package/engine/scripts/ml_hub_status.py +1556 -0
  217. package/engine/scripts/ml_schema_check.py +115 -0
  218. package/engine/scripts/ml_store_ids.py +139 -0
  219. package/engine/scripts/npm-publish-argent.mjs +499 -0
  220. package/engine/scripts/npm-publish-argent.sh +20 -0
  221. package/engine/scripts/orchestrator.py +13811 -0
  222. package/engine/scripts/pack-plugins.mjs +140 -0
  223. package/engine/scripts/patches/dsh-llm-deepseek--transport-diagnostics.patch +297 -0
  224. package/engine/scripts/patches/dsh-session--append-message-shape.patch +15 -0
  225. package/engine/scripts/patches/dsh-session--tool-result-block-017.patch +28 -0
  226. package/engine/scripts/patches/dsh-session-format-v0-to-v1--permission-preset-origin.patch +11 -0
  227. package/engine/scripts/patches/dsh-session-format-v3-to-v4--turn-outside-replace.patch +20 -0
  228. package/engine/scripts/patches/dsh-session-persistence-jsonl--worker-bundled-migrators.patch +39 -0
  229. package/engine/scripts/patches/dsh-tools--render-return-shape.patch +50 -0
  230. package/engine/scripts/patches/verify-bundled-migrators.mjs +79 -0
  231. package/engine/scripts/patches/verify-hardening.mjs +167 -0
  232. package/engine/scripts/patches/verify-session-migration.mjs +149 -0
  233. package/engine/scripts/patches/verify-transport-diagnostics.mjs +227 -0
  234. package/engine/scripts/plan-role-rename.mjs +125 -0
  235. package/engine/scripts/plugin-bootcheck.mjs +451 -0
  236. package/engine/scripts/plugin-composition.json +15 -0
  237. package/engine/scripts/poc-mcp-host.mjs +455 -0
  238. package/engine/scripts/poll-fulfillment.sh +293 -0
  239. package/engine/scripts/poll-invoice.sh +74 -0
  240. package/engine/scripts/profile-doctor.mjs +686 -0
  241. package/engine/scripts/provider-select.sh +70 -0
  242. package/engine/scripts/provider-switch.sh +146 -0
  243. package/engine/scripts/provider-sync-target.check.mjs +64 -0
  244. package/engine/scripts/python-runtime.sh +78 -0
  245. package/engine/scripts/query_runner.py +310 -0
  246. package/engine/scripts/release-argent.sh +574 -0
  247. package/engine/scripts/repair-unresolved-tools.mjs +178 -0
  248. package/engine/scripts/run-tests.sh +256 -0
  249. package/engine/scripts/self-sign-license.mjs +179 -0
  250. package/engine/scripts/session-health-scan.mjs +63 -0
  251. package/engine/scripts/session-repair-tool-result-content.mjs +181 -0
  252. package/engine/scripts/setup.sh +22 -0
  253. package/engine/scripts/skill-install.mjs +629 -0
  254. package/engine/scripts/sku_translate.py +148 -0
  255. package/engine/scripts/sync-plugins.sh +90 -0
  256. package/engine/scripts/sync-presets.sh +27 -0
  257. package/engine/scripts/sync-scripts.sh +445 -0
  258. package/engine/scripts/telemetry.py +873 -0
  259. package/engine/scripts/ui-copy-count.mjs +220 -0
  260. package/engine/scripts/usage-anchor.sh +136 -0
  261. package/engine/scripts/usage_report.py +531 -0
  262. package/engine/scripts/validate-preset-schema.mjs +208 -0
  263. package/engine/scripts/vertical-init.mjs +323 -0
  264. package/engine/scripts/vertical-lint.mjs +482 -0
  265. package/engine/scripts/wenyao-browser.sh +73 -0
  266. package/engine/scripts/wenyao-fixture-export.py +116 -0
  267. package/engine/scripts/wenyao-invoice-writeback.mjs +540 -0
  268. package/engine/scripts/wenyao-login.sh +34 -0
  269. package/engine/scripts/wenyao-template-map.json +292 -0
  270. package/engine/scripts/wenyao_attach.py +131 -0
  271. package/engine/scripts/wenyao_download_template.py +144 -0
  272. package/engine/scripts/wenyao_fill_template.py +568 -0
  273. package/engine/scripts/wenyao_login.py +145 -0
  274. package/engine/scripts/wenyao_portal.py +633 -0
  275. package/engine/scripts/wenyao_recon.py +230 -0
  276. package/engine/scripts/wenyao_run.py +503 -0
  277. package/engine/scripts/wenyao_shadow_diff.py +160 -0
  278. package/engine/scripts/wenyao_skill_contract.py +156 -0
  279. package/engine/scripts/wenyao_template_fetch.py +175 -0
  280. package/engine/scripts/win/dsh-web-autostart.ps1 +372 -0
  281. package/engine/scripts/ziniao-auth-probe.sh +268 -0
  282. package/engine/scripts/ziniao-keepalive.sh +216 -0
  283. package/engine/scripts/ziniao-post-upgrade-check.sh +120 -0
  284. package/engine/scripts/ziniao-windows.sh +153 -0
  285. package/engine/version.mjs +1 -0
  286. package/engine/verticals/README.md +103 -0
  287. package/engine/verticals/_engine-words.baseline.txt +237 -0
  288. package/engine/verticals/_engine-words.json +19 -0
  289. package/engine/verticals/mercadolibre/README.md +43 -0
  290. package/engine/verticals/mercadolibre/config.json +709 -0
  291. package/engine/verticals/mercadolibre/flows.json +706 -0
  292. package/engine/verticals/mercadolibre/manifest.json +538 -0
  293. package/engine/verticals/mercadolibre/migrate-machine-state.mjs +138 -0
  294. package/engine/verticals/mercadolibre/preflight.py +143 -0
  295. package/engine/verticals/mercadolibre/prompts/daily-report.failure.md +69 -0
  296. package/engine/verticals/mercadolibre/prompts/daily-report.md +47 -0
  297. package/engine/verticals/mercadolibre/prompts/daily-report.scheduled.md +79 -0
  298. package/engine/verticals/mercadolibre/prompts/full.failure.md +125 -0
  299. package/engine/verticals/mercadolibre/prompts/full.md +91 -0
  300. package/engine/verticals/mercadolibre/prompts/wenyao-invoice.failure.md +88 -0
  301. package/engine/verticals/mercadolibre/prompts/wenyao-invoice.md +64 -0
  302. package/engine/verticals/mercadolibre/prompts/xzh-invoice.failure.md +91 -0
  303. package/engine/verticals/mercadolibre/prompts/xzh-invoice.md +46 -0
  304. package/package.json +21 -4
  305. package/README.md +0 -3
@@ -0,0 +1,339 @@
1
+ #!/usr/bin/env python3
2
+ """每流程**前置检查 + 操作指南**(用户要求 2026-09-17:缺配置必须暴露并给出人工操作步骤)。
3
+
4
+ 与 `customer-preflight.py` 的分工:
5
+ · customer-preflight = 整机/环境级(node/dsh/版本/挂载/凭据文件/触发器并存…),人工按需跑;
6
+ · **本脚本 = 单流程级,跑流程前必跑**:缺 lark-cli 身份 / 缺表权限 / 缺推送身份 / 缺角色 BOT,
7
+ 都要**响亮报出 + 给出"谁去做、做什么、在哪做"的指南**,绝不静默降级。
8
+
9
+ 用法:
10
+ python3 scripts/flow_preflight.py --flow full [--online] [--json]
11
+ (--online 会真读一次表做权限探测;缺省只查配置与身份,秒级)
12
+ 退出码:0 全绿;1 有 FAIL(**调用方必须据此停下并暴露指南**)。
13
+ """
14
+ from __future__ import annotations
15
+
16
+ import argparse
17
+ import json
18
+ import os
19
+ import pathlib
20
+ import subprocess
21
+ import sys
22
+
23
+ HERE = pathlib.Path(__file__).resolve().parent
24
+ sys.path.insert(0, str(HERE / 'lib'))
25
+ from argent_datadir import resolve_data_dir # noqa: E402 数据目录唯一判据(勿在此复制链)
26
+ DATA = pathlib.Path(resolve_data_dir()['dir'])
27
+
28
+ GUIDE = {
29
+ "lark-cli": {"who": "用户(终端)", "steps": [
30
+ "安装 lark-cli(见 skills/lark-shared)",
31
+ "登录:`lark-cli auth login`(浏览器确认)",
32
+ ]},
33
+ "profile": {"who": "用户(终端,Secret 不进对话)", "steps": [
34
+ "新建/补配置:`lark-cli config init --new`(会打印授权链接,浏览器里完成应用创建/授权)",
35
+ "或已有应用:`lark-cli config init --api-key-stdin`(App Secret 从标准输入喂入,不要贴在聊天里)",
36
+ "完成后复核:`lark-cli profile list` 应能看到该 profile",
37
+ ]},
38
+ "table": {"who": "用户(飞书开放平台)", "steps": [
39
+ "确认该应用已开权限点:多维表格 `base:table:read`(写表再加 `base:table:record:update` 等)",
40
+ "把该 bot 加为目标 Base 的协作者(可编辑/可阅读)",
41
+ "重新发布应用版本,等待生效后重试",
42
+ ]},
43
+ "push": {"who": "用户(飞书建群/加机器人)", "steps": [
44
+ "把推送用的 bot 拉进目标群(否则报 230002 Bot/User can NOT be out of the chat)",
45
+ "在部署配置里填对群 ID(`FULL_INTERNAL_CHAT_ID` / `mlDailyChatId` / `*_CHAT_ID`)",
46
+ "验证:`node scripts/feishu-card.mjs --template flow-result --flow <id> --result 'TEST=done|自检' --to internal --send`",
47
+ ]},
48
+ "role-bot": {"who": "用户(飞书开放平台)+ 开发接线", "steps": [
49
+ "若需要该角色有独立飞书入口:开放平台新建自建应用 → 开 `im:message`、`base:*` 等权限 → 发布",
50
+ "把 App Secret 在终端喂进 lark-cli(`config init`),**不要贴进聊天**",
51
+ "把 appId 告知开发 → 改 `~/.dsh/argent/gateway.json` 的该角色 botAppId + 复核 `roles.json` 映射 → 重启 dsh web",
52
+ "不需要独立入口时:**可共用主 bot**(通知走 `NOTIFY_PROFILE`),流程照跑",
53
+ ]},
54
+ "model-auth": {"who": "用户(问述账号登录 / DeepSeek Key)", "steps": [
55
+ "**问述积分模式**:客户机浏览器打开 http://127.0.0.1:<port> → 设置 → Argent → 「✦ 一键登录问述科技账号」(设备流授权一次,token 90 天)",
56
+ "**DeepSeek 官方直连模式**:确认本机 dsh credentials 里有 `DEEPSEEK_API_KEY`,且 `bash scripts/provider-switch.sh status` 显示「DeepSeek 官方直连」",
57
+ "⚠️ 2026-09-14 whyshu.com **硬切换过 JWT 密钥**(无灰度)⇒ 那之前签发的问述 token **全部作废**;"
58
+ "现象是 HTTP 401「未登录或 Token 已过期」,**不是** exp 过期,重登才会好",
59
+ "复核:`python3 scripts/check-model-auth.py --online`(红灯必须清零);"
60
+ "排障现场确需临时放行时设 `ARGENT_SKIP_MODEL_AUTH=1`(会照旧 401 空转,不推荐)",
61
+ ]},
62
+ }
63
+
64
+
65
+ class R:
66
+ def __init__(self): self.items = []
67
+ def add(self, cid, level, title, detail="", guide=None):
68
+ self.items.append({"id": cid, "level": level, "title": title, "detail": detail,
69
+ "guide": GUIDE.get(guide) if guide else None})
70
+
71
+
72
+ def run(cmd, timeout=60):
73
+ try:
74
+ p = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout)
75
+ return p.returncode, (p.stdout or ""), (p.stderr or "")
76
+ except FileNotFoundError:
77
+ return 127, "", f"命令不存在: {cmd[0]}"
78
+ except Exception as e: # noqa: BLE001
79
+ return 125, "", str(e)
80
+
81
+
82
+ def read_env_file(name):
83
+ out = {}
84
+ try:
85
+ for line in (DATA / name).read_text(encoding="utf-8").splitlines():
86
+ t = line.strip()
87
+ if t and not t.startswith("#") and "=" in t:
88
+ k, v = t.split("=", 1)
89
+ out[k.strip()] = v.strip()
90
+ except FileNotFoundError:
91
+ pass
92
+ return out
93
+
94
+
95
+ def check_lease(cfg: dict, r: "R") -> None:
96
+ """能力租约状态(批 C4,2026-09-21)——把"这个能力现在还有效吗"放进前置检查。
97
+
98
+ 未启用强制(注册表 lease.enforce=false)时报 ok 并附当前状态 ⇒ **不制造噪音**;
99
+ 启用后:无租约/超出宽限 ⇒ fail(附换租约命令),宽限期内 ⇒ warn(仍可跑)。
100
+ """
101
+ cap = str(cfg.get("capability") or "")
102
+ try:
103
+ _code, out, err = run([sys.executable, str(HERE / "lease.py"), "--check", cap, "--json"])
104
+ data = json.loads(out) if out.strip().startswith("{") else {}
105
+ except Exception as exc: # noqa: BLE001
106
+ r.add("lease", "warn", f"租约检查执行失败:{exc}", "", "lease")
107
+ return
108
+ verdict = str(data.get("verdict") or "")
109
+ reason = str(data.get("reason") or (err or "").strip()[:160])
110
+ if verdict == "ok":
111
+ r.add("lease", "ok", f"能力租约:{reason}", "", "lease")
112
+ elif verdict == "grace":
113
+ r.add("lease", "warn", "能力租约已过期(宽限期内,本轮仍可跑)", reason,
114
+ "python3 scripts/lease.py --refresh")
115
+ else:
116
+ r.add("lease", "fail", "能力租约不可用 ⇒ 该能力应停跑", reason,
117
+ "python3 scripts/lease.py --refresh(需 WHYSHU_API_KEY);或联系问述科技续订")
118
+
119
+
120
+ def check_model_auth(r: "R") -> None:
121
+ """模型凭证必须在位且(离线可判的)没死 —— 跑流程前的**红灯闸门**(2026-09-29 事故固化)。
122
+
123
+ 事故:2026-09-14 whyshu.com 硬切换 JWT 密钥 ⇒ 客户机上那把 08-22 签发的 token 当场失效,
124
+ 但「还在、exp 没到」⇒ 上线核对全绿;09-29 日报唤醒后**第一步 401**,
125
+ 票据「停滞→回收→重派」循环 60 分钟 ×N,**零告警**,唯一信号是"日报没来"。
126
+ 这里把它提前成开跑前的 FAIL(调用方据此停下)——比空转 60 分钟强,但代价是"凭证坏 = 全停",
127
+ 故留 `ARGENT_SKIP_MODEL_AUTH=1` 应急旁路(需人明确设置)。
128
+
129
+ 只做**离线**判定(文件/环境 + exp/旧密钥验签),不联网、不花时间;在线探针在装机与
130
+ `customer-preflight.py`(非 --offline)里做。
131
+ """
132
+ if os.environ.get("ARGENT_SKIP_MODEL_AUTH") == "1":
133
+ r.add("model-auth", "warn", "模型凭证体检被 ARGENT_SKIP_MODEL_AUTH=1 跳过",
134
+ "仅在已确认凭证可用的排障现场使用", "model-auth")
135
+ return
136
+ script = HERE / "check-model-auth.py"
137
+ if not script.exists():
138
+ r.add("model-auth", "warn", "缺 scripts/check-model-auth.py(老克隆,跳过)",
139
+ "git pull 后即生效", None)
140
+ return
141
+ dsh_home = os.environ.get("DSH_HOME") or str(DATA.parent)
142
+ code, out, err = run([sys.executable, str(script), "--dsh-home", dsh_home, "--json"], timeout=60)
143
+ doc = None
144
+ try:
145
+ doc = json.loads(out) if (out or "").strip().startswith("{") else None
146
+ except Exception: # noqa: BLE001
147
+ doc = None
148
+ if not isinstance(doc, dict):
149
+ r.add("model-auth", "warn", "模型凭证体检没跑成(不阻断本轮)",
150
+ (err or out or "").strip().splitlines()[-1:][0] if (err or out or "").strip() else "", None)
151
+ return
152
+ bad = [i for i in (doc.get("checks") or []) if i.get("level") == "fail"]
153
+ if bad:
154
+ for i in bad:
155
+ r.add(f"model-auth.{i.get('id', '')}", "fail", str(i.get("title") or "模型凭证红灯"),
156
+ str(i.get("detail") or ""), "model-auth")
157
+ return
158
+ fps = [str(i.get("detail") or "") for i in (doc.get("checks") or [])
159
+ if str(i.get("id", "")).startswith("auth.cred.") and i.get("level") == "ok"]
160
+ r.add("model-auth", "ok", f"模型凭证在位(计费模式 {doc.get('mode')})", "|".join(fps)[:220])
161
+
162
+
163
+ def check_write_guards(cfg: dict, r: "R") -> None:
164
+ """注册表声明的写守卫 vs **实际写手**的姿态 —— 必须一致(2026-09-20 迭代1-步骤4)。
165
+
166
+ 此前 `guards.backup/audit/writeFields` 只被 flow_config 归一化、**没有执行者**:
167
+ 两条发票 flow 声明相反(true/true vs false/false),而 false 那条的注释又写着
168
+ "写前整行备份 + 读回验收 + 审计" ⇒ 声明与实际不符,读文档的人会被误导。
169
+ 这里把它接上:读写手导出的姿态,逐项比对;不一致 = FAIL(调用方据此停下)。
170
+ """
171
+ g = cfg.get("guards") or {}
172
+ want_fields = sorted(g.get("writeFields") or [])
173
+ if not want_fields:
174
+ return # 该流程没有声明写字段(只读流程)⇒ 无需比对
175
+ wb = HERE / "wenyao-invoice-writeback.mjs"
176
+ if not wb.exists():
177
+ r.add("guards.writer", "fail", "写回器缺失,无法校验写守卫",
178
+ f"{wb} 不存在", guide=None)
179
+ return
180
+ code, out, err = run(["node", str(wb), "--print-posture"], timeout=60)
181
+ if code != 0 or not out.strip().startswith("{"):
182
+ r.add("guards.writer", "fail", "写回器姿态导出失败", (err or out).strip()[:200])
183
+ return
184
+ try:
185
+ posture = json.loads(out)
186
+ except Exception as exc: # noqa: BLE001
187
+ r.add("guards.writer", "fail", "写回器姿态无法解析", str(exc)[:200])
188
+ return
189
+ got_fields = sorted(posture.get("allowedFields") or [])
190
+ if got_fields != want_fields:
191
+ r.add("guards.writeFields", "fail",
192
+ "注册表 guards.writeFields 与实际写手白名单不一致",
193
+ f"注册表={want_fields}|写手={got_fields}"
194
+ " ⇒ 改注册表或改写手(守卫必须只有一处真源)")
195
+ else:
196
+ r.add("guards.writeFields", "ok", "写字段白名单与写手一致", f"{len(got_fields)} 个字段")
197
+ # 备份/审计/读回:注册表若声明了就必须真做(写手侧导出的是实际姿态)
198
+ for key, label in (("backup", "写前整行备份"), ("audit", "审计 JSONL"), ("readback", "写后读回验收")):
199
+ if key in g and bool(g.get(key)) != bool(posture.get(key)):
200
+ r.add(f"guards.{key}", "fail",
201
+ f"注册表声明 guards.{key}={bool(g.get(key))},而写手实际={bool(posture.get(key))}",
202
+ f"({label})⇒ 声明与实际必须一致")
203
+ elif key in g:
204
+ r.add(f"guards.{key}", "ok", f"{label}:注册表与写手一致({bool(posture.get(key))})")
205
+
206
+
207
+ def main(argv=None) -> int:
208
+ ap = argparse.ArgumentParser(description="单流程前置检查 + 操作指南")
209
+ ap.add_argument("--flow", required=True)
210
+ ap.add_argument("--online", action="store_true", help="真读一次表(权限探测)")
211
+ ap.add_argument("--json", action="store_true")
212
+ a = ap.parse_args(argv)
213
+ r = R()
214
+
215
+ code, out, err = run([sys.executable, str(HERE / "flow_config.py"), "--flow", a.flow, "--json"])
216
+ if code != 0:
217
+ r.add("config", "fail", f"流程配置不可解析:{(err or out).strip().splitlines()[-1:]}",
218
+ "缺部署 env(表 id / base token)", "table")
219
+ return _emit(r, a.json)
220
+ cfg = json.loads(out)
221
+ src = cfg.get("source") or {}
222
+ fid_env = src.get("envFile")
223
+
224
+ # ① lark-cli
225
+ if not any((pathlib.Path(p) / "lark-cli").exists() for p in os.environ.get("PATH", "").split(":") if p):
226
+ code, _, _ = run(["lark-cli", "--version"])
227
+ if code == 127:
228
+ r.add("lark-cli", "fail", "PATH 里没有 lark-cli(读/写飞书表与推送都要它)", "", "lark-cli")
229
+ if not any(i["id"] == "lark-cli" for i in r.items):
230
+ r.add("lark-cli", "ok", "lark-cli 可用")
231
+
232
+ # ② 身份 profile(表读写)
233
+ identity = str(src.get("identity") or "")
234
+ envs = {**read_env_file(fid_env)} if fid_env else {}
235
+ if a.flow == "full":
236
+ identity = str(envs.get("FULL_LARK_PROFILE") or envs.get("LARK_PROFILE") or identity)
237
+ code, out, _ = run(["lark-cli", "profile", "list"])
238
+ names = set()
239
+ try:
240
+ names = {str(p.get("name")) for p in json.loads(out) if isinstance(p, dict)}
241
+ except Exception:
242
+ names = set(__import__("re").findall(r'"name":\s*"([^"]+)"', out or ""))
243
+ if identity and identity not in names:
244
+ r.add("profile", "fail", f"读表身份 `{identity}` 不在 lark-cli profile 列表里",
245
+ f"流程 {a.flow} 声明 identity={identity};CLI 现有 {len(names)} 个 profile", "profile")
246
+ else:
247
+ r.add("profile", "ok", f"读表身份 `{identity or '(未声明)'}` 已配置")
248
+
249
+ # ③ 表可读(可选在线探测)
250
+ if a.online:
251
+ code, out, err = run([sys.executable, str(HERE / "flow_source.py"), "--flow", a.flow,
252
+ "--source", "feishu-base", "--limit", "1", "--skip-gap", "--json",
253
+ "--out-dir", "/tmp/flow-preflight-cases"], timeout=300)
254
+ if code == 2:
255
+ r.add("table", "fail", "读表失败(权限/身份/表 id)",
256
+ (err or out).strip().splitlines()[-1:][0] if (err or out).strip() else "", "table")
257
+ else:
258
+ r.add("table", "ok", "表可读(在线探测通过)")
259
+ else:
260
+ r.add("table", "warn", "未做在线探测(加 --online 真读一次表)", "缺省只查配置,避免每次跑流程都读表")
261
+
262
+ # ④ 推送身份 + 目标群
263
+ cfgj = {}
264
+ try:
265
+ cfgj = json.loads((DATA / "config.json").read_text(encoding="utf-8"))
266
+ except Exception:
267
+ pass
268
+ # 与 feishu-card.mjs 同口径:通知身份/群 id 可能来自**共用**的部署 env(发票流程自己没有 envFile)。
269
+ # ⚠️ 第一版只看本流程 envFile ⇒ 对发票流程误报 FAIL("静默/误报"同类问题)。
270
+ shared = read_env_file("fulfillment.env")
271
+ de = read_env_file("daily-report.env")
272
+ if a.flow == "daily-report":
273
+ notify = de.get("LARK_PROFILE") or cfgj.get("mlDailyProfile") or ""
274
+ chat = de.get("ML_DAILY_CHAT_ID") or cfgj.get("mlDailyChatId") or ""
275
+ else:
276
+ notify = envs.get("NOTIFY_PROFILE") or shared.get("NOTIFY_PROFILE") or \
277
+ cfgj.get("mlDailyAlertProfile") or ""
278
+ chat = envs.get("FULL_INTERNAL_CHAT_ID") or shared.get("FULL_INTERNAL_CHAT_ID") \
279
+ or cfgj.get("feishuChatId") or ""
280
+ notify = notify or (cfgj.get("mlDailyAlertProfile") or "") or "cli_a93b9354c6e35cd1"
281
+ if not notify or (names and notify not in names and not notify.startswith("cli_")):
282
+ r.add("push", "fail", f"推送身份不可用:`{notify or '(未配置)'}`", "卡片/通知会发不出去", "push")
283
+ elif not chat:
284
+ r.add("push", "fail", "推送目标群未配置", "缺 *_CHAT_ID / config 里的群 id", "push")
285
+ else:
286
+ r.add("push", "ok", f"推送身份 `{notify}` + 目标群 `{chat[:12]}…` 已配置")
287
+
288
+ # ⑤ 角色 → preset / BOT
289
+ role = str(cfg.get("role") or "")
290
+ preset = (cfg.get("dispatch") or {}).get("preset") or ""
291
+ roles = {}
292
+ try:
293
+ roles = json.loads((DATA / "roles.json").read_text(encoding="utf-8")).get("presets", {})
294
+ except Exception:
295
+ pass
296
+ if roles.get(role) != preset:
297
+ r.add("role", "fail", f"角色映射不一致:{role} → {roles.get(role) or '(缺)'},流程要 {preset}",
298
+ "角色会挂错 preset", None)
299
+ else:
300
+ bot = ""
301
+ try:
302
+ g = json.loads((DATA / "gateway.json").read_text(encoding="utf-8"))
303
+ for x in (g.get("roles") or []):
304
+ if isinstance(x, dict) and x.get("role") == role:
305
+ bot = x.get("botAppId") or ""
306
+ except Exception:
307
+ pass
308
+ if bot:
309
+ r.add("role", "ok", f"角色 {role} → {preset}(BOT {bot})")
310
+ else:
311
+ r.add("role", "warn", f"角色 {role} 没有自己的 BOT(流程照样跑;但飞书里 @ 不到它、也不能以自己身份发言)",
312
+ f"角色 {role} → {preset};通知可共用主 bot(NOTIFY_PROFILE)", "role-bot")
313
+ # ⑥ 写守卫一致性(注册表声明 vs 实际写手;2026-09-20 迭代1-步骤4)
314
+ check_write_guards(cfg, r)
315
+ check_lease(cfg, r) # 批 C4:能力租约(未启用强制时不制造噪音)
316
+ # ⑦ 模型凭证(2026-09-29 日报事故固化):缺/死 ⇒ 跑起来也只会 401 空转 ⇒ 提前 FAIL
317
+ check_model_auth(r)
318
+
319
+ return _emit(r, a.json)
320
+
321
+
322
+ def _emit(r: R, as_json: bool) -> int:
323
+ fails = [i for i in r.items if i["level"] == "fail"]
324
+ if as_json:
325
+ print(json.dumps({"checks": r.items, "fail": len(fails)}, ensure_ascii=False, indent=2))
326
+ else:
327
+ icon = {"ok": "✅", "warn": "⚠️", "fail": "❌"}
328
+ for i in r.items:
329
+ print(f" {icon[i['level']]} {i['title']}" + (f"\n {i['detail']}" if i["detail"] else ""))
330
+ if i["level"] == "fail" and i.get("guide"):
331
+ g = i["guide"]
332
+ print(f" ↳ **需要人操作**({g['who']}):")
333
+ for s in g["steps"]:
334
+ print(f" · {s}")
335
+ return 1 if fails else 0
336
+
337
+
338
+ if __name__ == "__main__":
339
+ sys.exit(main())