@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,445 @@
1
+ #!/usr/bin/env bash
2
+ # 把**投递面清单**里的每个面同步到安装克隆(~/.argent-dsh),并校验关键文件 sha 一致。
3
+ # 面清单 = **唯一真源** `scripts/delivery-faces.txt`(2026-10-08 起;⛔ 本脚本不再自带面名单):
4
+ # `scripts/`(引擎与工具)· `core/`(L1 内核)· `configs/`(配置目录:引擎级可配项声明,2026-10-09 加)
5
+ # · `skills/`(L0 技能资产,含归类判据 `skills/internal.json`)
6
+ # · `verticals/`(L0 业务线真源)· `deploy/`(部署/交付件:客户模板 + CI 模板 + MCP 部署件)。
7
+ # 每个面都逐文件核对,缺一个面就不是"同步好了"。
8
+ # 同一份清单也被 `scripts/deliver-customer.mjs` 读(第三件事:客户机/远端克隆)⇒ 加面只改那一个文件。
9
+ #
10
+ # 背景(2026-09-15 实测事故):sync-plugins.sh **只同步 plugins**,克隆里的 scripts 会落后
11
+ # ⇒ 角色按 SKILL 里的 ~/.argent-dsh/scripts/... 跑,用的是**旧脚本**(曾导致缺口检查静默失败、
12
+ # 把缺字段的票误判为可派发)。
13
+ #
14
+ # ⚠️ 缺陷⑲(2026-09-23 夜,ml-fulfillment 发现并给出 md5/行数证据):
15
+ # 旧实现 `REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"` —— **从脚本自身位置推仓库**。
16
+ # 于是从**安装克隆**里跑这份脚本时 `REPO == CLONE` ⇒
17
+ # ① `rsync "$REPO/scripts/" "$CLONE/scripts/"` 变成**自我覆盖**(什么也没同步);
18
+ # ② 随后的 sha 比对变成**自我比对** ⇒ 恒 ✅「已与仓库一致」——**假绿**;
19
+ # ③ `KEY` 清单里**没有 `orchestrator.py`**,而落后最多的正是编排器。
20
+ # 最坏后果:**"修复没生效"被误判成"修复无效"**(当晚角色差点据此下错结论)。
21
+ #
22
+ # 现在的口径(宁可红,不要假绿):
23
+ # 1. `REPO` 只认 `ARGENT_DSH_REPO`(缺省 `~/Code/argent-dsh`),**不再**从 BASH_SOURCE 推;
24
+ # 2. 若本脚本不在 `$REPO/scripts/` 里(即跑的是克隆/profile 副本)⇒ **转交**仓库那份执行
25
+ # (保持 SKILL/交接协议里既有调用方式可用,同时得到真实同步);
26
+ # 3. 仓库不存在 ⇒ 响亮失败(exit 2),绝不打印绿字;
27
+ # 4. `KEY` 补上编排器与查询器:`orchestrator.py` / `query_runner.py` / `flow_policy.py` / `flow_retry.py`。
28
+ #
29
+ # ⚠️ 缺陷⑳(2026-10-02 确认):本脚本只覆盖 `scripts/` 与 `verticals/`,**全文 0 处 `core/`**。
30
+ # 而 `core/` 是 **L1 执行内核的运行时资产**,会被插件/CLI/MCP **从克隆里解析**:
31
+ # · 插件(argent-core/skin/ml/flow/gateway)运行时按 `../../../core/lib/argent-datadir.mjs`
32
+ # 相对 import,候选路径里就有 `~/.argent-dsh`、`~/Code/argent-dsh`(见 plugins/argent-*/src/index.js);
33
+ # · `core/lib/argent-datadir.mjs` 是数据目录的**唯一判据**(2026-10-02 新增)⇒ 克隆里缺它,
34
+ # 插件就 `DATA_DIR=''`:只读退化、写入 fail-closed(core/lib/argent-datadir.mjs:156 的处置口径);
35
+ # · `core/cli/argent.mjs`、`core/mcp/server.mjs`、`core/lib/license-file.mjs` 同理(CLI/MCP/许可)。
36
+ # 本机克隆因**走过 git** 与仓库 0 差异 ⇒ 立刻复现不了;但"只走 sync 的机器"(不 git pull 的形态)
37
+ # 拿不到这些文件 ⇒ 要么 fail-closed、要么直接崩。修法:两处 rsync 都补 `core/`,并**逐文件核对**。
38
+ #
39
+ # ⚠️ 缺陷㉑(2026-10-02 实测,写缺陷⑳ 的纯夹具测试时踩到):`REPO` 是**字符串**而 `SELF_DIR`/`CLONE`
40
+ # 走 `pwd -P`(物理路径)⇒ 路径里含软链(macOS `/tmp`→`/private/tmp`)时两边**永不相等**:
41
+ # ① `SELF_DIR != $REPO/scripts` 恒真 ⇒ **无限 exec 自我转交**(实测 6 秒 491 次、纯 CPU 空转);
42
+ # ② 反向组合会让 `REPO == CLONE` 守卫被**绕过** ⇒ 缺陷⑲ 的自我覆盖式假绿复活。
43
+ # 修法:REPO 归一成物理路径 + 转交加 `ARGENT_SYNC_SCRIPTS_TAKEOVER` 标记(转交过就不再转交,响亮失败)。
44
+ #
45
+ # ⚠️ 缺口㉓(2026-10-04):本脚本此前只投递 `scripts/` + `verticals/` + `core/`,**没有 `skills/`**。
46
+ # 而 `skills/` 是 **L0 业务资产**,其中两处是**运行期真源**:
47
+ # · `skills/internal.json` —— 升级器 `scripts/argent-upgrade.mjs` 用它做**归类判据**(内部角色技能不外发);
48
+ # · `skills/<name>/SKILL.md`(+ 各技能的 `references/`、`scripts/`、模板)—— 角色按 SKILL 干活,
49
+ # 缺一件就是"角色照着半份 SOP 干"(与缺 core/ 的形态同源:**看起来正常**)。
50
+ # 只走 sync(git 拉不动)的机器:外发集仍能从 `verticals/` 正确推导(故不会误发内部技能),
51
+ # 但**归类门禁退化**(读不到 internal.json ⇒ 内部/未归类判据失效)。故 `skills/` 与 `core/` 同待遇:
52
+ # 两条 rsync 路径都投递 + 逐文件 sha 核对 + 结论必须一眼可见(数不到文件 ⇒ 红,绝不假绿)。
53
+ #
54
+ # ⚠️ 缺口㉔(2026-10-08,本批收口):本脚本此前五个面里**独缺 `deploy/`** —— 于是 `deploy/ci/*`
55
+ # (CI 部署件模板)在只走 sync 的机器上**永远拿不到**,而 `deploy/` 下另有两类是**真被读**的资产:
56
+ # · `deploy/customer/roles.spec.json` —— **客户模板**,`scripts/check-role-mapping.mjs:66`(第 ⑥ 项
57
+ # 技能声明面)与 `scripts/customer-config-migrate.mjs` 都按 `REPO/deploy/customer/roles.spec.json` 读;
58
+ # 客户机上跑的是 `~/.argent-dsh/scripts/check-role-mapping.mjs` ⇒ `REPO` = **克隆** ⇒
59
+ # 克隆里缺这份模板时,第 ⑥ 项**静默少查一个声明面**(模板错名会批量复制到每台客户机,正是它要拦的)。
60
+ # · `deploy/mcp/*`、`deploy/ci/*` —— MCP 部署件与自建 CI 的 plist/README(**模板/文档,默认不安装**)。
61
+ # 实测形态(2026-10-08 对账):`deploy/customer`、`deploy/mcp` 因历史原因**已在**克隆里,只有
62
+ # `deploy/ci/` 的 2 个文件缺 —— 这种"半在场"最难发现(对账要么全查、要么看不出来)。
63
+ # 故 `deploy/` 与 `core/`、`skills/` **同待遇**:两条 rsync 路径都投递 + 点名核对 + 逐文件 sha 核对
64
+ # + 计数与结论一眼可见(仓库缺 `deploy/` 或数不到文件 ⇒ 红)。
65
+ # ⛔ 投递面不冲突(已核):`deploy/` 只经**本脚本**进**安装克隆** `~/.argent-dsh`;
66
+ # `scripts/release-argent.sh` 投的是**下载服务器** `${SSH_HOST}:${DL_DIR}`,面 = `install-argent.mjs`
67
+ # /`install-dsh.sh`/`install.ps1`(`--full` 再带 `skills/`、`plugins/`)—— **全文 0 处 `deploy/`**,
68
+ # 两者目标机与用途都不同 ⇒ 无需改 release-argent.sh(取最小方案)。
69
+ # `deploy/` 是**部署/交付资产**(模板与文档,非运行期代码)⇒ **不进 `CORE_KEY`、不进 `pack.engine`**
70
+ # (与 `skills/` 同理:那两个面是"引擎件"的面)。
71
+ #
72
+ # ⚠️ 缺口㉒(2026-10-03):本脚本的 rsync **不带 `--delete`** ⇒ 仓库里**删掉**的文件会**永远留在克隆**里
73
+ # (实测:克隆 scripts/ 曾多出 9 个仓库已删的旧脚本;这类残留此前**无人可见**)。
74
+ # 残留会让"克隆里有什么"与"仓库里有什么"对不上账。口径:**只报告,不清理** ——
75
+ # 克隆里可能还有带外资产(本机专用、不该被同步覆盖),自动删是危险的;
76
+ # 也**不能判红**(仓库删一个文件就红一次 ⇒ 恒红陷阱,清理动作不在本脚本职责内)。
77
+ # 故收尾只打印「克隆多出 N 个非仓库文件 + 前若干条路径」,**exit 仍为 0**。
78
+ #
79
+ # 用法:bash scripts/sync-scripts.sh [--no-pull]
80
+ # ARGENT_DSH_REPO=/path/to/argent-dsh bash scripts/sync-scripts.sh
81
+ set -euo pipefail
82
+
83
+ SELF_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
84
+ REPO="${ARGENT_DSH_REPO:-$HOME/Code/argent-dsh}"
85
+ CLONE="${ARGENT_DISH_HOME:-$HOME/.argent-dsh}"
86
+ # 物理路径归一(缺陷㉑,2026-10-02 实测):`SELF_DIR` 与 `CLONE` 都用 `pwd -P`(**物理**路径),
87
+ # 而 `REPO` 是字符串 ⇒ 只要 `ARGENT_DSH_REPO`/`$HOME` 里含**软链**(macOS `/tmp`→`/private/tmp`、
88
+ # `/var`→`/private/var`,或仓库放在软链后面),两边就**永不相等**:
89
+ # ① `SELF_DIR != $REPO/scripts` 恒真 ⇒ 无限 `exec` 自我转交(实测 6 秒 491 次,纯 CPU 空转);
90
+ # ② 反向的软链组合会让 `REPO == CLONE` 守卫**被绕过** ⇒ 又变回缺陷⑲ 的自我覆盖式假绿。
91
+ # 故 REPO 先归一成物理路径;REPO 不存在时保持原样,让下面"仓库不存在"的分支响亮失败。
92
+ REPO_P="$(cd "$REPO" 2>/dev/null && pwd -P || true)"
93
+ [ -n "$REPO_P" ] && REPO="$REPO_P"
94
+ KEY=(flow_case.py flow_source.py flow_triage.py flow_claim.py flow_config.py flow_failure.py
95
+ flow_ledger.py ml_schema_check.py flow-requirements.json flow-trigger.sh flow-trigger-wake.mjs
96
+ daily-report-inbox.py orchestrator.py query_runner.py flow_policy.py flow_retry.py
97
+ # 日报 OAuth 向导(2026-09-24 修了"管道输入静默失败" + 加非交互/防串店校验):
98
+ # 客户机文档让跑 `node ~/.argent-dsh/scripts/ml-oauth-setup.mjs` ⇒ 修复必须同步到克隆,
99
+ # 否则客户机仍在用会静默烧授权码的旧版。
100
+ # 注:2026-09-27 起日报与 lip 表解耦 ⇒ 曾短暂加入的 sku-names.mjs 已删除、不再同步。
101
+ ml-oauth-setup.mjs
102
+ # ── P3 技能打包与归类门禁(2026-10-03)────────────────────────────────────
103
+ # 归类判据(G1–G8)与安装器都必须在克隆里**同时**存在:只同步安装器会让它 import 不到门禁
104
+ # (`import { classify } from './check-skill-classification.mjs'`)⇒ 装机时直接崩。
105
+ skill-install.mjs check-skill-classification.mjs
106
+ # ── 入口守卫的唯一实现(2026-10-04)────────────────────────────────────────
107
+ # `scripts/lib/is-direct-run.mjs` 被 10 个 CLI import(升级器/安装器/各 check-*/日报/回写/卡片)
108
+ # ⇒ 克隆里缺它 = 那 10 个脚本**当场 import 崩**(不是静默降级)。它同时进 `pack.engine`
109
+ # (能力包面)—— 两个投递面同批登记,漂移由 sync-scripts-core.test.mjs 的 KEY 段守住。
110
+ lib/is-direct-run.mjs
111
+ # ── 干净机器一条命令(D1,2026-10-05)──────────────────────────────────────
112
+ # `install-one-shot.mjs` = D1 的**编排入口**(precheck→install→skills→license→verify);
113
+ # 它调 `install-license.mjs`(许可安装的唯一实现)与 `install-argent.mjs`(装配的唯一实现,
114
+ # 按 `--from-packs` 走离线面)。三者任一缺席 ⇒ 克隆/包装机上"一条命令"直接不可用
115
+ # (不是静默降级)。三个文件同时进 `pack.engine`(能力包面)。
116
+ install-one-shot.mjs install-license.mjs
117
+ # `migrate-providers.mjs` 由安装器第 6 步(provider 迁移)子进程调用 ⇒ 它是
118
+ # `install-argent.mjs` 的**运行期依赖**(install-argent.mjs 进包后由 check-pack-closure
119
+ # 按实际引用推导出来)。克隆里缺它 ⇒ 每次装配都打"provider 迁移脚本未跑成"的警告
120
+ # (静默半成品:装完 provider 没配好)。两处投递面同批登记。
121
+ # 2026-10-08(本批收口):**投递工具自身**也进点名核对 —— `deliver-customer.mjs`(第三件事:
122
+ # 往客户机/远端克隆投递)与它的面清单唯一真源 `delivery-faces.txt`。理由:从**克隆**发起投递
123
+ # 是合法用法(角色按 SKILL 调 ~/.argent-dsh/scripts/...),克隆里缺/旧这两件 ⇒ 用**旧面清单**
124
+ # 投递(正是"加目录忘了进面"的形态),而且不会报错。它们既不进 `CORE_KEY` 也不进 `pack.engine`
125
+ # (不是内核运行期件,也不是能力包件:投递工具只在本机/运维侧跑)。
126
+ deliver-customer.mjs delivery-faces.txt)
127
+
128
+ if [ "$SELF_DIR" != "$REPO/scripts" ]; then
129
+ # 跑的不是仓库那份(典型:角色按 SKILL 调 ~/.argent-dsh/scripts/sync-scripts.sh)
130
+ if [ "${ARGENT_SYNC_SCRIPTS_TAKEOVER:-}" = "1" ]; then
131
+ # 防无限 exec 循环(缺陷㉑ 的兜底):转交过一次仍判定为"非仓库副本"⇒ 说明路径比对本身有问题,
132
+ # 此时再 exec 就是纯 CPU 空转 ⇒ 宁可响亮失败。
133
+ echo " ✗ 转交后仍是非仓库副本(${SELF_DIR} ≠ $REPO/scripts)⇒ 拒绝再次转交(防无限 exec 循环)。" >&2
134
+ exit 2
135
+ fi
136
+ if [ -f "$REPO/scripts/sync-scripts.sh" ]; then
137
+ echo " ▸ 检测到从非仓库副本调用(${SELF_DIR})⇒ 转交仓库那份执行(避免自我覆盖式假绿,缺陷⑲)"
138
+ ARGENT_SYNC_SCRIPTS_TAKEOVER=1 exec bash "$REPO/scripts/sync-scripts.sh" "$@"
139
+ fi
140
+ echo " ✗ 仓库不存在或缺 scripts/:$REPO" >&2
141
+ echo " 设定 ARGENT_DSH_REPO=<仓库路径> 后重试(缺省 ~/Code/argent-dsh)。" >&2
142
+ echo " **不会**回退到「就地自我同步」——那正是缺陷⑲ 的假绿来源。" >&2
143
+ exit 2
144
+ fi
145
+
146
+ if [ ! -d "$CLONE" ]; then echo " ✗ 安装克隆不存在: $CLONE"; exit 1; fi
147
+ if [ "$(cd "$CLONE" && pwd -P)" = "$REPO" ]; then
148
+ echo " ✗ REPO == CLONE(${REPO}):同步源与目标是同一棵树 ⇒ 拒绝执行(缺陷⑲ 假绿)。" >&2
149
+ echo " 请把 ARGENT_DISH_HOME 指向真正的安装克隆,或从仓库目录运行。" >&2
150
+ exit 2
151
+ fi
152
+
153
+ # ── 投递面清单 = **唯一真源** `scripts/delivery-faces.txt`(2026-10-08 起)─────────────────
154
+ # 为什么抽成文件:面清单此前**散在本脚本里**,加一个面要同时改两处 rsync +(可选)核对段 ⇒
155
+ # "加目录忘了进面"踩了三次,且每次都表现为**脚本看起来正常、克隆拿不到**:
156
+ # 缺口⑳ `core/`(2026-10-02,L1 内核资产 ⇒ 插件 DATA_DIR='' 只读退化)、
157
+ # 缺口㉓ `skills/`(2026-10-04,L0 技能资产 ⇒ 归类判据 internal.json 拿不到)、
158
+ # 缺口㉔ `deploy/`(2026-10-08,客户模板被 check-role-mapping 第 ⑥ 项真读)。
159
+ # 现在**同一份清单**被两个投递口读:本脚本(第一件事:本机安装克隆)与
160
+ # `scripts/deliver-customer.mjs`(第三件事:客户机/远端克隆)。⛔ 不许在本脚本里再抄一份面名单。
161
+ # 读不到/读空 ⇒ **响亮失败**("面为空也算同步成功"正是缺陷⑲ 那类假绿的形态);
162
+ # 清单里的每个面都必须被投递 ⇒ 用循环而不是手写 N 行(新增面自动进投递,不会漏)。
163
+ FACES_FILE="$REPO/scripts/delivery-faces.txt"
164
+ FACES=()
165
+ read_faces() {
166
+ local line
167
+ [ -f "$FACES_FILE" ] || return 1
168
+ while IFS= read -r line || [ -n "$line" ]; do
169
+ line="${line%%#*}" # 行尾注释(清单文件里用来写"为什么这个面在面内")
170
+ line="${line//[[:space:]]/}" # 去空白/制表(含全角缩进误入的情况)
171
+ [ -n "$line" ] || continue
172
+ FACES+=("$line")
173
+ done < "$FACES_FILE"
174
+ [ "${#FACES[@]}" -gt 0 ]
175
+ }
176
+ # 逐面投递(顺序 = 清单顺序)。语义与手写 N 行完全一致:`rsync -a --quiet`,**无 `--delete`**(缺口㉒)。
177
+ deliver_faces() {
178
+ local face
179
+ for face in "${FACES[@]}"; do
180
+ # 面清单声明了但仓库里没有 ⇒ **响亮失败**(此前直接 rsync 会以 23「partial transfer」退出,
181
+ # 报错信息与「面配错」毫无关系 —— 2026-10-10 加 agents/presets 面时测试就是这么红的)。
182
+ if [ ! -d "$REPO/$face" ]; then
183
+ echo " ✗ 面不存在(清单声明了但仓库里没有):$face" >&2
184
+ echo " ⛔ 面清单是唯一真源(scripts/delivery-faces.txt);面不存在 ⇒ 不投递、立即退出" >&2
185
+ exit 2
186
+ fi
187
+ rsync -a --quiet "$REPO/$face/" "$CLONE/$face/"
188
+ done
189
+ }
190
+
191
+ # ── 根文件(**面清单之外**,但运行时真读)──────────────────────────────────────
192
+ # ⚠️ 缺口㉖(2026-10-10,**第五次同形态**):A 批新增了仓库**根**资产 ——
193
+ # · `agents/`(智能体目录,安装器 `loadCatalog()` 真读)—— 已随面清单修复(进 `agents` 面);
194
+ # · **根 `VERSION`**:`core/cli/argent.mjs` 用 `readFileSync(script('VERSION'))` 读它 ⇒ 克隆里
195
+ # 停在旧值(实测 0.4.0 的仓库 vs 克隆仍 `0.3.0`),`argent version` 与"检查更新"据此判版本。
196
+ # 面清单只支持**目录**(两处 rsync 都是 `"$REPO/$face/"` 目录语义)⇒ 根文件单独一段,
197
+ # 与面**同待遇**:投递 + 双端 sha 核对(数不到文件即红,绝不假绿)。
198
+ # ⚠️ `install-argent.mjs` 同族(2026-10-10 实测):克隆里它是**旧版**(仓库 ff4069d6 vs 克隆
199
+ # 618f4bbd)⇒ 克隆侧跑 `--agent hr` 报「未知参数: hr」(新 flag 根本不存在)。
200
+ # 它此前只靠 `argent-upgrade.mjs` 自举更新(滞后窗口 = 客户机装到旧安装器的风险)⇒ 一并进根文件清单。
201
+ ROOT_FILES=(VERSION install-argent.mjs)
202
+ deliver_root_files() {
203
+ local f
204
+ for f in "${ROOT_FILES[@]}"; do
205
+ [ -f "$REPO/$f" ] || continue
206
+ rsync -a --quiet "$REPO/$f" "$CLONE/$f"
207
+ done
208
+ }
209
+ if ! read_faces; then
210
+ echo " ✗ 投递面清单读不到或为空:$FACES_FILE" >&2
211
+ echo " 面清单是**唯一真源**(scripts/delivery-faces.txt,一行一个面)——缺它就无法知道该投哪几个面。" >&2
212
+ echo " **不会**退化成本脚本里另抄一份面名单:那正是「加目录忘了进面」的复发路径。" >&2
213
+ exit 2
214
+ fi
215
+
216
+ if [ "${1:-}" != "--no-pull" ] && [ -d "$CLONE/.git" ]; then
217
+ echo " ▸ git -C $CLONE pull --ff-only"
218
+ if ! git -C "$CLONE" pull --ff-only >/tmp/sync-scripts-pull.log 2>&1; then
219
+ echo " ⚠️ pull 失败(可能有本地改动/未跟踪文件),改用 rsync 覆盖投递面"
220
+ tail -3 /tmp/sync-scripts-pull.log | sed 's/^/ /'
221
+ # 业务线真源也要同步(2026-09-29 实测事故):只同步 scripts/ 会让克隆缺 verticals/,
222
+ # 于是任何"读仓库知识"的脚本(如 scripts/argent-catalog.mjs、host 的目录路由)在克隆里
223
+ # **少读一半数据却看起来正常**(业务线 0 条)。克隆是客户机形态的落地处 ⇒ 必须完整。
224
+ # ⚠️ 本分支此前**只投 5 个面里的 4 个**(漏 verticals/);改用循环后两条 rsync 路径的面集**一致**。
225
+ deliver_faces
226
+ deliver_root_files
227
+ fi
228
+ fi
229
+ # 兜底:确保各面与仓库一致(pull 未覆盖到的情况)
230
+ deliver_faces
231
+ deliver_root_files
232
+
233
+ fail=0
234
+ for f in "${KEY[@]}"; do
235
+ a=$(shasum -a 256 "$REPO/scripts/$f" 2>/dev/null | cut -c1-12 || true)
236
+ b=$(shasum -a 256 "$CLONE/scripts/$f" 2>/dev/null | cut -c1-12 || true)
237
+ if [ -n "$a" ] && [ "$a" = "$b" ]; then printf " ✅ %-24s %s\n" "$f" "$a"
238
+ else printf " ✗ %-24s 仓库=%s 克隆=%s\n" "$f" "${a:-无}" "${b:-无}"; fail=1; fi
239
+ done
240
+
241
+ # ── core/ 一致性(缺陷⑳):KEY 清单的语义是「`scripts/` 下的文件名」(循环里硬拼 `$REPO/scripts/`),
242
+ # 所以**不硬塞** `core/…`;改为对 `core/` 单独做「存在 + 与仓库逐文件 sha 一致」核对,结论必须一眼可见。
243
+ # P1 第三批(2026-10-03):CLI 新增五个 verb 的实现模块全部落在 `core/lib/` ——
244
+ # `notify`(P2 通知端口)/`init`/`versions`/`audit`/`flow list` 的实现都在这里。
245
+ # 2026-10-04(§8-③ 一次性激活码):+`core/lib/license-activate.mjs`(CLI `license activate` 的实现;
246
+ # 与 `scripts/flow-requirements.json#pack.engine` 的 core 段**逐项相同**,漂移由 sync-scripts-core.test.mjs 判红)。
247
+ # 2026-10-04(O2 只读运营视图):+`core/lib/license-ops.mjs`(CLI `license ops` 的实现:只读运营巡检,
248
+ # 替代 `mongosh`;同样两处清单逐项一致)。
249
+ # P4 批(2026-10-03):清单扩到 **core 运行期全集**(CLI 入口 + MCP 面 + `core/lib/**` 运行期闭包
250
+ # + 运行期读的两个契约 JSON)—— 与 `scripts/flow-requirements.json#pack.engine` 的 core 段
251
+ # **逐项相同**(同一批运行期文件、两个投递面:能力包 / sync);
252
+ # 两处清单不许各写一份,漂移由 `scripts/tests/sync-scripts-core.test.mjs` 判红。
253
+ # 它们由上面的 `rsync core/` 整体投递(并逐文件核对),本清单只是**点名核对**:
254
+ # 少一个,克隆上的 `argent <verb>` 就是"未知 verb"/import 崩,或 MCP 面起不来(不是静默降级)。
255
+ CORE_KEY=(core/cli/argent.mjs core/mcp/server.mjs core/mcp/http.mjs
256
+ core/contracts/argent.contracts.json core/contracts/verbs.schema.json
257
+ core/lib/argent-datadir.mjs core/lib/flow-registry.mjs core/lib/claim.mjs core/lib/ledger.mjs
258
+ core/lib/python.mjs core/lib/sop.mjs core/lib/audit.mjs core/lib/versions.mjs core/lib/flow-list.mjs
259
+ core/lib/init.mjs core/lib/doctor-customer.mjs core/lib/license.mjs core/lib/license-file.mjs core/lib/license-verdict.mjs
260
+ core/lib/license-device.mjs core/lib/license-guard.mjs core/lib/license-activate.mjs core/lib/license-ops.mjs
261
+ core/lib/notify/index.mjs core/lib/notify/verb.mjs core/lib/notify/dedup.mjs core/lib/notify/webhook.mjs
262
+ core/lib/notify/feishu.mjs core/lib/notify/wecom.mjs
263
+ core/lib/config-catalog.mjs)
264
+ # 2026-10-09(配置地基):+`core/lib/config-catalog.mjs`(配置面的**唯一**读取器;与
265
+ # `scripts/flow-requirements.json#pack.engine` 的 core 段**逐项相同**,漂移由 sync-scripts-core.test.mjs 判红)。
266
+ # ⚠️ 它读的 `configs/*.json` **不在 core 段**(不是 core/ 下的文件)⇒ 由下面的 `configs/` 段单独核对。
267
+ for f in "${CORE_KEY[@]}"; do
268
+ a=$(shasum -a 256 "$REPO/$f" 2>/dev/null | cut -c1-12 || true)
269
+ b=$(shasum -a 256 "$CLONE/$f" 2>/dev/null | cut -c1-12 || true)
270
+ if [ -n "$a" ] && [ "$a" = "$b" ]; then printf " ✅ %-34s %s\n" "$f" "$a"
271
+ else printf " ✗ %-34s 仓库=%s 克隆=%s\n" "$f" "${a:-无}" "${b:-无}"; fail=1; fi
272
+ done
273
+ core_n=0; core_bad=0; core_list=""
274
+ while IFS= read -r rel; do
275
+ [ -n "$rel" ] || continue
276
+ core_n=$((core_n + 1))
277
+ a=$(shasum -a 256 "$REPO/$rel" 2>/dev/null | cut -c1-12 || true)
278
+ b=$(shasum -a 256 "$CLONE/$rel" 2>/dev/null | cut -c1-12 || true)
279
+ if [ -n "$a" ] && [ "$a" = "$b" ]; then continue; fi
280
+ core_bad=$((core_bad + 1)); core_list="$core_list $rel"
281
+ done < <(cd "$REPO" && find core -type f ! -name '.DS_Store' | LC_ALL=C sort)
282
+ if [ ! -d "$REPO/core" ]; then
283
+ printf " ✗ 仓库缺 core/:%s/core(内核资产缺失 ⇒ 克隆不可能正确)\n" "$REPO"; fail=1
284
+ elif [ "$core_n" -eq 0 ]; then
285
+ # 防假绿:数不到文件时**绝不能**打印"一致"(0/0 也算通过是这类自检最常见的翻车方式)
286
+ printf " ✗ 仓库 core/ 下数不到任何文件:%s/core\n" "$REPO"; fail=1
287
+ elif [ "$core_bad" -eq 0 ]; then
288
+ printf " ✅ core: %d 个文件与仓库一致(%s/core;源=%s)\n" "$core_n" "$CLONE" "$REPO"
289
+ else
290
+ printf " ✗ core: %d/%d 个文件与仓库不一致:%s\n" "$core_bad" "$core_n" "$core_list"
291
+ fail=1
292
+ fi
293
+
294
+ # ── skills/ 一致性(缺口㉓,2026-10-04):与 core/ **同待遇** —— 点名核对 + 逐文件 sha + 结论一眼可见。
295
+ # 点名清单(`SKILLS_KEY`)的语义:`skills/internal.json`(升级器的**归类判据**,运行期真源)
296
+ # + `skills/<name>/SKILL.md`(每个技能的入口文件;`fix-skill-frontmatter.py` 的硬约束都在它上面)。
297
+ # ⚠️ SKILL.md **由 `find` 动态枚举**,不手抄清单:① 手抄必然腐烂(新增技能要记得改脚本);
298
+ # ② 技能名是**业务词**,写进 `scripts/` 会被 `scripts/vertical-lint.mjs` 的 engine-words 门禁判红
299
+ # (2026-10-04 实测踩到)——引擎文件不该出现业务线名字。
300
+ # 整树(`references/`、`scripts/`、模板…)由下面的 `find skills` 逐文件核对覆盖 —— 本清单只是点名。
301
+ # ⚠️ 本清单**不进** `CORE_KEY`、也**不进** `pack.engine`:`skills/` 是 **L0 业务资产**,不是引擎件
302
+ # (`sync-scripts-core.test.mjs`【0】只比对两处清单的 `core/` 段,本清单由该测试的 skills 段守)。
303
+ SKILLS_KEY=(skills/internal.json)
304
+ while IFS= read -r rel; do
305
+ [ -n "$rel" ] || continue
306
+ SKILLS_KEY+=("$rel")
307
+ done < <(cd "$REPO" && find skills -mindepth 2 -maxdepth 2 -name 'SKILL.md' | LC_ALL=C sort)
308
+ for f in "${SKILLS_KEY[@]}"; do
309
+ a=$(shasum -a 256 "$REPO/$f" 2>/dev/null | cut -c1-12 || true)
310
+ b=$(shasum -a 256 "$CLONE/$f" 2>/dev/null | cut -c1-12 || true)
311
+ if [ -n "$a" ] && [ "$a" = "$b" ]; then printf " ✅ %-42s %s\n" "$f" "$a"
312
+ else printf " ✗ %-42s 仓库=%s 克隆=%s\n" "$f" "${a:-无}" "${b:-无}"; fail=1; fi
313
+ done
314
+ # 防假绿:连一个技能入口都没数到 ⇒ 点名核对等于没做(skills/ 只剩余件时**不能**算通过)
315
+ if [ "${#SKILLS_KEY[@]}" -le 1 ]; then
316
+ printf " ✗ 仓库 skills/ 下一个 skills/<name>/SKILL.md 都没数到:%s/skills(点名核对落空)\n" "$REPO"; fail=1
317
+ fi
318
+ skills_n=0; skills_bad=0; skills_list=""
319
+ while IFS= read -r rel; do
320
+ [ -n "$rel" ] || continue
321
+ skills_n=$((skills_n + 1))
322
+ a=$(shasum -a 256 "$REPO/$rel" 2>/dev/null | cut -c1-12 || true)
323
+ b=$(shasum -a 256 "$CLONE/$rel" 2>/dev/null | cut -c1-12 || true)
324
+ if [ -n "$a" ] && [ "$a" = "$b" ]; then continue; fi
325
+ skills_bad=$((skills_bad + 1)); skills_list="$skills_list $rel"
326
+ done < <(cd "$REPO" && find skills -type f ! -name '.DS_Store' | LC_ALL=C sort)
327
+ if [ ! -d "$REPO/skills" ]; then
328
+ printf " ✗ 仓库缺 skills/:%s/skills(L0 技能资产缺失 ⇒ 克隆不可能正确)\n" "$REPO"; fail=1
329
+ elif [ "$skills_n" -eq 0 ]; then
330
+ # 防假绿:数不到文件时**绝不能**打印"一致"(0/0 也算通过是这类自检最常见的翻车方式)
331
+ printf " ✗ 仓库 skills/ 下数不到任何文件:%s/skills\n" "$REPO"; fail=1
332
+ elif [ "$skills_bad" -eq 0 ]; then
333
+ printf " ✅ skills: %d 个文件与仓库一致(%s/skills;源=%s)\n" "$skills_n" "${CLONE}" "${REPO}"
334
+ else
335
+ printf " ✗ skills: %d/%d 个文件与仓库不一致:%s\n" "$skills_bad" "$skills_n" "$skills_list"
336
+ fail=1
337
+ fi
338
+
339
+ # ── deploy/ 一致性(缺口㉔,2026-10-08):与 core/、skills/ **同待遇** —— 点名核对 + 逐文件 sha + 结论一眼可见。
340
+ # 点名清单(`DEPLOY_KEY`)的语义:`deploy/` 下**会被运行期读**的那一件 ——
341
+ # `deploy/customer/roles.spec.json`(客户模板:`check-role-mapping.mjs` 第 ⑥ 项的声明面之一,
342
+ # 也是 `customer-config-migrate.mjs` 的并入源)。其余(CI 模板 / MCP 部署件 / README)是**模板与文档,
343
+ # 默认不安装**,由下面的 `find deploy` 逐文件核对覆盖 —— 本清单只是点名。
344
+ # ⚠️ 本清单**不进** `CORE_KEY`、也**不进** `pack.engine`:`deploy/` 是部署/交付资产,不是引擎件
345
+ # (`sync-scripts-core.test.mjs`【0】只比对两处清单的 `core/` 段,本清单由该测试的 deploy 段守)。
346
+ DEPLOY_KEY=(deploy/customer/roles.spec.json)
347
+ for f in "${DEPLOY_KEY[@]}"; do
348
+ a=$(shasum -a 256 "$REPO/$f" 2>/dev/null | cut -c1-12 || true)
349
+ b=$(shasum -a 256 "$CLONE/$f" 2>/dev/null | cut -c1-12 || true)
350
+ if [ -n "$a" ] && [ "$a" = "$b" ]; then printf " ✅ %-42s %s\n" "$f" "$a"
351
+ else printf " ✗ %-42s 仓库=%s 克隆=%s\n" "$f" "${a:-无}" "${b:-无}"; fail=1; fi
352
+ done
353
+ deploy_n=0; deploy_bad=0; deploy_list=""
354
+ while IFS= read -r rel; do
355
+ [ -n "$rel" ] || continue
356
+ deploy_n=$((deploy_n + 1))
357
+ a=$(shasum -a 256 "$REPO/$rel" 2>/dev/null | cut -c1-12 || true)
358
+ b=$(shasum -a 256 "$CLONE/$rel" 2>/dev/null | cut -c1-12 || true)
359
+ if [ -n "$a" ] && [ "$a" = "$b" ]; then continue; fi
360
+ deploy_bad=$((deploy_bad + 1)); deploy_list="$deploy_list $rel"
361
+ done < <(cd "$REPO" && find deploy -type f ! -name '.DS_Store' | LC_ALL=C sort)
362
+ if [ ! -d "$REPO/deploy" ]; then
363
+ printf " ✗ 仓库缺 deploy/:%s/deploy(部署/交付件缺失 ⇒ 克隆上的客户模板与 CI 模板不可能正确)\n" "$REPO"; fail=1
364
+ elif [ "$deploy_n" -eq 0 ]; then
365
+ # 防假绿:数不到文件时**绝不能**打印"一致"(0/0 也算通过是这类自检最常见的翻车方式)
366
+ printf " ✗ 仓库 deploy/ 下数不到任何文件:%s/deploy\n" "$REPO"; fail=1
367
+ elif [ "$deploy_bad" -eq 0 ]; then
368
+ printf " ✅ deploy: %d 个文件与仓库一致(%s/deploy;源=%s)\n" "$deploy_n" "${CLONE}" "${REPO}"
369
+ else
370
+ printf " ✗ deploy: %d/%d 个文件与仓库不一致:%s\n" "$deploy_bad" "$deploy_n" "$deploy_list"
371
+ fail=1
372
+ fi
373
+
374
+ # ── configs/ 一致性(缺口㉕,2026-10-09):与 core/、skills/、deploy/ **同待遇** —— 逐文件 sha + 计数一眼可见。
375
+ # 为什么加它:`configs/` 是**配置目录**(引擎级可配项声明),`core/lib/config-catalog.mjs` 从
376
+ # `<根>/configs/*.json` 读它;业务线级那份在 `verticals/<id>/config.json`(随 verticals/ 面走)。
377
+ # ⚠️ 点名清单**动态枚举**(`find configs -maxdepth 1 -name '*.json'`),⛔ 不手抄:
378
+ # ① 手抄必然腐烂(加一个域文件要记得改脚本);② "加声明即生效"是这一层的**设计目标**
379
+ # (门禁 ④ 的机器判据)—— 手抄清单会把这个目标当场作废。
380
+ # 语义:整个 `configs/` 由 `find configs -type f` 逐文件核对覆盖,点名只是"至少要数到文件"。
381
+ # ⚠️ 克隆里读不到 ⇒ **不是报错而是静默半残**(读取器把空目录当"没有可配项")⇒ 这里必须响亮。
382
+ CONFIGS_KEY=()
383
+ while IFS= read -r rel; do
384
+ [ -n "$rel" ] || continue
385
+ CONFIGS_KEY+=("$rel")
386
+ done < <(cd "$REPO" && find configs -maxdepth 1 -name '*.json' | LC_ALL=C sort)
387
+ for f in ${CONFIGS_KEY[@]+"${CONFIGS_KEY[@]}"}; do
388
+ a=$(shasum -a 256 "$REPO/$f" 2>/dev/null | cut -c1-12 || true)
389
+ b=$(shasum -a 256 "$CLONE/$f" 2>/dev/null | cut -c1-12 || true)
390
+ if [ -n "$a" ] && [ "$a" = "$b" ]; then printf " ✅ %-42s %s\n" "$f" "$a"
391
+ else printf " ✗ %-42s 仓库=%s 克隆=%s\n" "$f" "${a:-无}" "${b:-无}"; fail=1; fi
392
+ done
393
+ configs_n=0; configs_bad=0; configs_list=""
394
+ while IFS= read -r rel; do
395
+ [ -n "$rel" ] || continue
396
+ configs_n=$((configs_n + 1))
397
+ a=$(shasum -a 256 "$REPO/$rel" 2>/dev/null | cut -c1-12 || true)
398
+ b=$(shasum -a 256 "$CLONE/$rel" 2>/dev/null | cut -c1-12 || true)
399
+ if [ -n "$a" ] && [ "$a" = "$b" ]; then continue; fi
400
+ configs_bad=$((configs_bad + 1)); configs_list="$configs_list $rel"
401
+ done < <(cd "$REPO" && find configs -type f ! -name '.DS_Store' | LC_ALL=C sort)
402
+ if [ ! -d "$REPO/configs" ]; then
403
+ printf " ✗ 仓库缺 configs/:%s/configs(配置目录缺失 ⇒ 克隆上可配项整体消失,且不报错)\n" "$REPO"; fail=1
404
+ elif [ "$configs_n" -eq 0 ]; then
405
+ # 防假绿:数不到文件时**绝不能**打印"一致"(0/0 也算通过是这类自检最常见的翻车方式)
406
+ printf " ✗ 仓库 configs/ 下数不到任何文件:%s/configs\n" "$REPO"; fail=1
407
+ elif [ "${#CONFIGS_KEY[@]}" -eq 0 ]; then
408
+ printf " ✗ configs/ 下一个 *.json 都没点名到(点名核对落空)\n"; fail=1
409
+ elif [ "$configs_bad" -eq 0 ]; then
410
+ printf " ✅ configs: %d 个文件与仓库一致(%s/configs;源=%s)\n" "$configs_n" "$CLONE" "$REPO"
411
+ else
412
+ printf " ✗ configs: %d/%d 个文件与仓库不一致:%s\n" "$configs_bad" "$configs_n" "$configs_list"
413
+ fail=1
414
+ fi
415
+
416
+ # ── 只读报告(缺口㉒):克隆里**多出**的非仓库文件 —— 即"仓库里没有这个路径"的文件。
417
+ # ⛔ 三条纪律:① 只报告不清理(克隆可能含带外资产);② **绝不改 `fail`**(判红就成恒红陷阱);
418
+ # ③ 只按**路径存在性**判定(`$REPO/<rel>` 在不在),不做内容比对 —— "内容不同"是上面 sha 核对的职责。
419
+ EXTRA_SHOWN=5
420
+ report_extra() {
421
+ local sub="$1" rel n=0 shown=0 list="" more=0
422
+ [ -d "$REPO/$sub" ] && [ -d "$CLONE/$sub" ] || return 0 # 仓库没这个目录 ⇒ 全是"多出"也没有基准,不报
423
+ while IFS= read -r rel; do
424
+ [ -n "$rel" ] || continue
425
+ if [ -e "$REPO/$rel" ]; then continue; fi
426
+ n=$((n + 1))
427
+ if [ "$shown" -lt "$EXTRA_SHOWN" ]; then list="$list $rel"; shown=$((shown + 1)); else more=$((more + 1)); fi
428
+ done < <(cd "$CLONE" && find "$sub" \( -type f -o -type l \) ! -name '.DS_Store' | LC_ALL=C sort)
429
+ if [ "$n" -gt 0 ]; then
430
+ printf " ℹ️ 克隆多出 %d 个非仓库文件(%s/:仓库已删,仅提示,不自动清理):%s\n" "$n" "$sub" "$list"
431
+ [ "$more" -gt 0 ] && printf " └─ 另有 %d 条未列出(全量:find %s/%s \\( -type f -o -type l \\))\n" "$more" "$CLONE" "$sub"
432
+ fi
433
+ return 0
434
+ }
435
+ report_extra core
436
+ report_extra scripts
437
+ report_extra verticals
438
+ report_extra skills
439
+ report_extra deploy
440
+ report_extra configs
441
+ # 注:收尾行的变量必须写成 `${CLONE}`(带花括号)—— 变量名紧跟全角标点时,C locale 下 bash 会把
442
+ # 高位字节当作变量名的一部分 ⇒ `set -u` 直接报"未绑定的变量"并以 1 退出(本次实测踩到)。
443
+ # 该形态由门禁 scripts/tests/shell-cjk-var.test.py 守着(纯行扫描,注释里的字面量同样会触发)。
444
+ [ "$fail" -eq 0 ] && echo " ✅ ${FACES[*]} 已与仓库一致(${CLONE};源=${REPO})"
445
+ exit $fail