@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,264 @@
1
+ {
2
+ "_doc": "配置目录 · 通知与投递域(引擎级)。声明格式与四道门禁见 docs/Argent-宿主适配契约.md §7。webhook / 群 ID 这类「拿到就能发消息」的值按 secret 处理(页面只显示已配置/未配置)。",
3
+ "domain": "notify",
4
+ "order": 20,
5
+ "items": [
6
+ {
7
+ "key": "notify.feishu.chat_id",
8
+ "label": "飞书推送群(通用兜底)",
9
+ "category": "通知与投递",
10
+ "type": "string",
11
+ "source": "json",
12
+ "secret": true,
13
+ "required": false,
14
+ "validation": {
15
+ "pattern": "^oc_[A-Za-z0-9]+$|^ou_[A-Za-z0-9]+$"
16
+ },
17
+ "capability": null,
18
+ "vertical": null,
19
+ "editable": true,
20
+ "help": "流程通知/告警的兜底落点(能被 @ 到就能被投递,故按密钥处理)。",
21
+ "binding": {
22
+ "kind": "json",
23
+ "file": "config.json",
24
+ "field": "feishuChatId"
25
+ }
26
+ },
27
+ {
28
+ "key": "notify.daily.chat_id",
29
+ "label": "日报推送群",
30
+ "category": "通知与投递",
31
+ "type": "string",
32
+ "source": "json",
33
+ "secret": true,
34
+ "required": false,
35
+ "validation": {
36
+ "pattern": "^oc_[A-Za-z0-9]+$|^ou_[A-Za-z0-9]+$"
37
+ },
38
+ "capability": "daily-report",
39
+ "vertical": "mercadolibre",
40
+ "editable": true,
41
+ "help": "日报专属落点;留空则回落通用群。",
42
+ "binding": {
43
+ "kind": "json",
44
+ "file": "config.json",
45
+ "field": "mlDailyChatId"
46
+ },
47
+ "todayChain": [
48
+ "json",
49
+ "env"
50
+ ]
51
+ },
52
+ {
53
+ "key": "notify.daily.profile",
54
+ "label": "日报投递身份",
55
+ "category": "通知与投递",
56
+ "type": "string",
57
+ "source": "json",
58
+ "secret": false,
59
+ "required": false,
60
+ "capability": "daily-report",
61
+ "vertical": "mercadolibre",
62
+ "editable": true,
63
+ "help": "用哪个机器人身份发日报(客户端身份名)。",
64
+ "binding": {
65
+ "kind": "json",
66
+ "file": "config.json",
67
+ "field": "mlDailyProfile"
68
+ },
69
+ "todayChain": [
70
+ "json",
71
+ "env"
72
+ ]
73
+ },
74
+ {
75
+ "key": "notify.daily.webhook",
76
+ "label": "日报自定义 Webhook",
77
+ "category": "通知与投递",
78
+ "type": "string",
79
+ "source": "json",
80
+ "secret": true,
81
+ "required": false,
82
+ "capability": "daily-report",
83
+ "vertical": "mercadolibre",
84
+ "editable": true,
85
+ "help": "非飞书通道的自定义投递地址(URL 本身就是凭据)。",
86
+ "binding": {
87
+ "kind": "json",
88
+ "file": "config.json",
89
+ "field": "mlDailyWebhook"
90
+ },
91
+ "todayChain": [
92
+ "json",
93
+ "env"
94
+ ]
95
+ },
96
+ {
97
+ "key": "notify.daily.alert_chat_id",
98
+ "label": "日报告警群",
99
+ "category": "通知与投递",
100
+ "type": "string",
101
+ "source": "json",
102
+ "secret": true,
103
+ "required": false,
104
+ "capability": "daily-report",
105
+ "vertical": "mercadolibre",
106
+ "editable": true,
107
+ "help": "日报失败/异常告警的落点(与日报正文分开,避免刷屏)。",
108
+ "binding": {
109
+ "kind": "json",
110
+ "file": "config.json",
111
+ "field": "mlDailyAlertChatId"
112
+ },
113
+ "todayChain": [
114
+ "env",
115
+ "json"
116
+ ],
117
+ "_note": "批 3-1(2026-10-09)声明纠正:原写 [json,env],与代码事实**相反**。读取点为证 —— scripts/daily-report.mjs:1006 逐字是 `env.ML_DAILY_ALERT_CHAT_ID || (cfg && cfg.mlDailyAlertChatId) || ML_DAILY_ALERT_CHAT_ID`(最后一项是内部群常量)⇒ 实际是 env 优先。本批**代码零改动**;链首级纠正为 env 后与规范链首级一致 ⇒ 设置页「旧优先级」提示自然消失。⛔ 这不是删提示,是声明与代码事实一致后才消失的。"
118
+ },
119
+ {
120
+ "key": "notify.daily.alert_profile",
121
+ "label": "日报告警身份",
122
+ "category": "通知与投递",
123
+ "type": "string",
124
+ "source": "json",
125
+ "secret": false,
126
+ "required": false,
127
+ "capability": "daily-report",
128
+ "vertical": "mercadolibre",
129
+ "editable": true,
130
+ "help": "用哪个机器人身份发日报告警。",
131
+ "binding": {
132
+ "kind": "json",
133
+ "file": "config.json",
134
+ "field": "mlDailyAlertProfile"
135
+ },
136
+ "todayChain": [
137
+ "env",
138
+ "json"
139
+ ],
140
+ "_note": "批 3-1(2026-10-09)声明纠正:同 notify.daily.alert_chat_id —— 原写 [json,env],与代码事实相反。**5 个读取点全部 env 优先**:scripts/daily-report.mjs:1007(`env.ML_DAILY_ALERT_PROFILE || cfg.mlDailyAlertProfile`)、scripts/feishu-card.mjs:174(`dailyEnv.LARK_PROFILE || cfg.mlDailyAlertProfile`)、scripts/feishu-card.mjs:177(`fullEnv.NOTIFY_PROFILE || cfg.mlDailyAlertProfile`)、scripts/flow_preflight.py:277 与 scripts/flow_preflight.py:280(envs/shared 的 *_PROFILE 优先,cfgj.mlDailyAlertProfile 作回落)⇒ 实际是 env 优先。⚠️ feishu-card / flow_preflight 读的 env 名与声明登记的 ML_DAILY_ALERT_PROFILE 并不一致(已知缺陷,调查产物 #13 的 regression 已单列,⛔ 不在本批改)—— 此处只纠正**层级次序**,不涉及 env 名。本批代码零改动;提示因声明与事实一致而消失。"
141
+ },
142
+ {
143
+ "key": "notify.flow.profile",
144
+ "label": "流程通知身份",
145
+ "category": "通知与投递",
146
+ "type": "string",
147
+ "source": "envfile",
148
+ "secret": false,
149
+ "required": false,
150
+ "capability": null,
151
+ "vertical": null,
152
+ "editable": false,
153
+ "help": "流程通知默认用哪个身份投递。",
154
+ "binding": {
155
+ "kind": "envfile",
156
+ "file": "fulfillment.env",
157
+ "env": "NOTIFY_PROFILE",
158
+ "vertical": "mercadolibre"
159
+ }
160
+ },
161
+ {
162
+ "key": "notify.flow.lark_profile",
163
+ "label": "流程读表身份",
164
+ "category": "通知与投递",
165
+ "type": "string",
166
+ "source": "envfile",
167
+ "secret": false,
168
+ "required": false,
169
+ "capability": null,
170
+ "vertical": null,
171
+ "editable": false,
172
+ "help": "流程读写飞书表默认用的 CLI 身份。",
173
+ "binding": {
174
+ "kind": "envfile",
175
+ "file": "fulfillment.env",
176
+ "env": "LARK_PROFILE",
177
+ "vertical": "mercadolibre"
178
+ }
179
+ },
180
+ {
181
+ "key": "notify.full.internal_chat_id",
182
+ "label": "货件流程内部群",
183
+ "category": "通知与投递",
184
+ "type": "string",
185
+ "source": "envfile",
186
+ "secret": true,
187
+ "required": false,
188
+ "capability": "full",
189
+ "vertical": "mercadolibre",
190
+ "editable": false,
191
+ "help": "货件流程的过程通知落点(内部群)。",
192
+ "binding": {
193
+ "kind": "envfile",
194
+ "file": "fulfillment.env",
195
+ "env": "FULL_INTERNAL_CHAT_ID",
196
+ "vertical": "mercadolibre"
197
+ }
198
+ },
199
+ {
200
+ "key": "notify.full.done_chat_id",
201
+ "label": "货件完成通知群",
202
+ "category": "通知与投递",
203
+ "type": "string",
204
+ "source": "envfile",
205
+ "secret": true,
206
+ "required": false,
207
+ "capability": "full",
208
+ "vertical": "mercadolibre",
209
+ "editable": false,
210
+ "help": "货件完成后的对外通知落点。",
211
+ "binding": {
212
+ "kind": "envfile",
213
+ "file": "fulfillment.env",
214
+ "env": "FULL_DONE_CHAT_ID",
215
+ "vertical": "mercadolibre"
216
+ }
217
+ },
218
+ {
219
+ "key": "notify.full.done_profile",
220
+ "label": "货件完成通知身份",
221
+ "category": "通知与投递",
222
+ "type": "string",
223
+ "source": "envfile",
224
+ "secret": false,
225
+ "required": false,
226
+ "capability": "full",
227
+ "vertical": "mercadolibre",
228
+ "editable": false,
229
+ "help": "货件完成通知用哪个身份投递。",
230
+ "binding": {
231
+ "kind": "envfile",
232
+ "file": "fulfillment.env",
233
+ "env": "FULL_DONE_PROFILE",
234
+ "vertical": "mercadolibre"
235
+ }
236
+ },
237
+ {
238
+ "key": "notify.full.mode",
239
+ "label": "货件通知模式",
240
+ "category": "通知与投递",
241
+ "type": "enum",
242
+ "source": "envfile",
243
+ "secret": false,
244
+ "required": false,
245
+ "validation": {
246
+ "enum": [
247
+ "final",
248
+ "feishu"
249
+ ]
250
+ },
251
+ "capability": "full",
252
+ "vertical": "mercadolibre",
253
+ "editable": false,
254
+ "help": "final = 只在终态通知;feishu = 恢复旧行为(每步都发)。",
255
+ "binding": {
256
+ "kind": "envfile",
257
+ "file": "fulfillment.env",
258
+ "env": "FULL_NOTIFY_MODE",
259
+ "vertical": "mercadolibre"
260
+ }
261
+ }
262
+ ],
263
+ "entries": []
264
+ }
@@ -0,0 +1,277 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Argent 单入口(0.3 P1)—— `argent <verb> [args…]`
4
+ *
5
+ * 目的:把宿主(dsh / 未来任何 agent / 云端 MCP)对 Argent 的依赖**收敛成一条命令族**,
6
+ * 而不是散落的 `scripts/*.py|mjs` 文件名 —— 这是"抽离基座"的第一步。
7
+ *
8
+ * ⚠️ **薄别名层**:本文件**不复制任何业务逻辑**,只把 verb 映射到既有脚本(或 core/lib 里的共享实现)
9
+ * 并把参数原样透传 ⇒ 行为与今天直接调脚本**完全一致**(P1 的红线:不动现网行为)。
10
+ * 契约见 core/contracts/argent.contracts.json。
11
+ *
12
+ * 2026-10-03 修两处"假绿"缺陷(均有复现原文,见各自模块头注释):
13
+ * · D1 `ledger` 返回假空 ⇒ 走 `core/lib/ledger.mjs`(读全量 → 过滤 → 再取末尾 N 行;回显生效条件)
14
+ * · D3 解释器单候选 + 空 catch 吞异常 ⇒ 走 `core/lib/python.mjs`(多候选 + 响亮失败)
15
+ *
16
+ * 2026-10-03 P1 第二批:
17
+ * · `license` 组落地(status|verify|install|request|renew|explain,§3.5①):判定点唯一在 CLI 进程内、
18
+ * 离线可验;**旧行为**(恒 `ok:true` 只回计费巡检文本)正是 §2.2④ 要修的假绿;
19
+ * · **写类 verb 接许可闸门**(`flow claim --apply` / `writeback --yes`):调既有
20
+ * `scripts/license-gate.mjs`(**不复制判据**),默认 `observe`(只留证据不拦),`enforce` 才拒写;
21
+ * · `--help --json` 改为报**代码里实际存在**的 verb/子命令(此前直接照抄契约 ⇒ 门禁的
22
+ * "契约声明了、CLI 里没有"这一向恒绿,是假绿空间)。
23
+ *
24
+ * 2026-10-03 P1 第三批(M1 外围三件):
25
+ * · `notify`(P2 webhook 一条):端口 + 通道实现落在 `core/lib/notify/`,**判据与投递分离**
26
+ * (去重/审计/dry-run 在 verb 层,通道只负责"送到没送到");默认 dry-run,真发要 `--apply`;
27
+ * · `init`(数据目录画像,默认 dry-run,`--apply` 才建目录;⛔ 不写 settings/credentials)、
28
+ * `versions`(五面对账)、`audit`(4 处审计 JSONL 只读汇总)、`flow list`(注册表只读清单)。
29
+ *
30
+ * 2026-10-03 P1 首批(`flow claim`):
31
+ * · `claim` 从"其实是分诊"改成**真正的原子认领**(包 `scripts/flow_claim.py`,退出码 3 ⇒ 0 + empty:true);
32
+ * 旧行为逐字保留在 `flow triage` / `claim --plan-only`;
33
+ * · 新增 `flow` 组(claim|triage)+ `triage` 别名;适配层在 `core/lib/claim.mjs`(A1/A2/A3 口径);
34
+ * · `--help --json` 输出机器可读的 verb 清单(门禁 `scripts/check-judgment-drift.mjs` 的"代码侧"来源)。
35
+ *
36
+ * 2026-10-03 P4 收尾(M1 判据③):
37
+ * · `doctor --customer` = **客户机一页式自检**(`core/lib/doctor-customer.mjs`):整机、只读、
38
+ * **不要求本机装 dsh**(无宿主 ⇒ 宿主档事实记 `applicable:false`「本档不适用」,**不算 FAIL**);
39
+ * 退出码按 A1:全 ok/warn ⇒ `0`(warn 只在 JSON 标记)、存在 fail ⇒ `1`、用法错误 ⇒ `2`;
40
+ * · `doctor --flow <id> [--online]` 的旧行为**逐字保留**(仍转发 `scripts/flow_preflight.py`,判据不重复);
41
+ * · ⚠️ `doctor --help` 现在打**自检形态**的用法(那份用法里同时写了单流程形态的出口);
42
+ * 单流程的前置检查帮助仍可直接跑 `python3 scripts/flow_preflight.py --help`。
43
+ */
44
+ import { execFileSync } from 'node:child_process'
45
+ import { readFileSync } from 'node:fs'
46
+ import { dirname, join, resolve } from 'node:path'
47
+ import { fileURLToPath } from 'node:url'
48
+ import { resolveSop } from '../lib/sop.mjs'
49
+ import { queryLedger, resolveLedgerFlow } from '../lib/ledger.mjs'
50
+ import { pickPython } from '../lib/python.mjs'
51
+ import { resolveDataDir } from '../lib/argent-datadir.mjs'
52
+ import { buildInvocation, runFlowVerb } from '../lib/claim.mjs'
53
+ import { runLicenseVerb, LICENSE_SUBCOMMANDS } from '../lib/license.mjs'
54
+ import { applyGate, gateWrite } from '../lib/license-guard.mjs'
55
+ import { loadRegistry, resolveFlow } from '../lib/flow-registry.mjs'
56
+ import { runNotifyVerb } from '../lib/notify/verb.mjs'
57
+ import { runInitVerb } from '../lib/init.mjs'
58
+ import { runVersionsVerb } from '../lib/versions.mjs'
59
+ import { runAuditVerb } from '../lib/audit.mjs'
60
+ import { runFlowListVerb } from '../lib/flow-list.mjs'
61
+ import { runDoctorCustomerVerb } from '../lib/doctor-customer.mjs'
62
+
63
+ const HERE = dirname(fileURLToPath(import.meta.url))
64
+ const REPO = resolve(HERE, '..', '..')
65
+ // 数据目录:内核三级链(唯一判据)
66
+ const DATA_DIR = resolveDataDir({ env: process.env }).dir
67
+ const script = (p) => join(REPO, p)
68
+
69
+ // 解释器(D3):**多候选 + 响亮失败**。惰性解析 —— 不用 Python 的 verb(version/license,
70
+ // 以及不带 --flow 的 ledger)既不付探测开销,也不因缺解释器而失败("无宿主机器上 version 仍可用")。
71
+ let _py = null
72
+ const python = () => (_py ||= pickPython({ env: process.env, dataDir: DATA_DIR, repo: REPO }))
73
+ const pyPath = () => { const p = python(); return p.ok ? p.path : '' }
74
+ const pyFailure = () => { const p = python(); return p.ok ? null : p.diagnostics }
75
+
76
+ /** `flow claim` / `flow triage` / `claim --plan-only`:同一个适配层(退出码翻译 + A2 回显)。 */
77
+ const flowVerb = (args) => runFlowVerb(args, { repo: REPO, py: pyPath(), pyFailure: pyFailure() })
78
+
79
+ // ── 写类 verb 的许可闸门(P1 第二批,§3.6① 第 4 步)──────────────────────────
80
+ // **不复制判据**:调既有 `scripts/license-gate.mjs`(flow-trigger.sh:238 用的同一个;判定↔取证一份),
81
+ // 本层只决定"这次调用是不是真写"以及"被拒时怎么回"。默认 `observe` ⇒ **只留证据、不拦**。
82
+ const CONFIRM = ['--apply', '--confirm', '--yes', '--write']
83
+ const isRealWrite = (args) => CONFIRM.some((f) => args.includes(f)) && !args.includes('--dry-run')
84
+
85
+ /**
86
+ * 闸门上下文:能力 id 与业务线**从注册表解析**(与 flow-trigger.sh 用 `flow_config.py --get capability`
87
+ * 同源)。注册表读不到 ⇒ 退化为"以流程名当能力"并**如实标注**(宁可不拦 / 不可误停,与 flow-trigger.sh
88
+ * 的 `LICENSE_CAP="$CAP"; [ -n "$LICENSE_CAP" ] || LICENSE_CAP="$FLOW"` 逐字同口径)。
89
+ */
90
+ function gateContext(flow) {
91
+ const py = pyPath()
92
+ if (!py) return { cap: flow, vertical: null, capSource: 'fallback_no_python' }
93
+ const reg = loadRegistry({ repo: REPO, py })
94
+ if (!reg.ok) return { cap: flow, vertical: null, capSource: `fallback_registry:${reg.reason}` }
95
+ const r = resolveFlow({ input: flow, doc: reg.doc })
96
+ const f = (reg.doc.flows || {})[r.canonical] || {}
97
+ const vertical = r.canonical.includes('.') ? r.canonical.split('.')[0] : null
98
+ return { cap: String(f.capability || r.local || flow), vertical, capSource: 'registry' }
99
+ }
100
+
101
+ const runGate = (flow) => {
102
+ const ctx = gateContext(flow)
103
+ const gate = gateWrite({ repo: REPO, flow, cap: ctx.cap, vertical: ctx.vertical, env: process.env })
104
+ return { ...gate, capSource: ctx.capSource, cap: ctx.cap, vertical: ctx.vertical, flow }
105
+ }
106
+
107
+ /** 被闸门拒绝(只在 `enforce` 下发生):**整体拒绝 + 零副作用**(不认领、不回写、不落台账)。 */
108
+ const deniedEnvelope = (name, flow, gate) => {
109
+ const json = applyGate({ ok: true, empty: false, code: 0, reason: null, verb: name, flow }, gate)
110
+ return {
111
+ json,
112
+ human: `⛔ 许可闸门[enforce]:${gate.human || gate.reason} ⇒ 拒绝 ${name}(零副作用:没有写任何东西)`,
113
+ stderr: '', exit: 1,
114
+ }
115
+ }
116
+
117
+ /** `claim`(含 `flow claim`):真写前过闸门;dry-run 不查(不打扰只读路径,也不污染证据)。 */
118
+ function gatedClaim(args) {
119
+ const built = buildInvocation(args)
120
+ const flow = built.ok ? built.echo.flow : (argOf(args, '--flow') || '?')
121
+ const gate = built.ok && !built.dryRun ? runGate(flow) : null
122
+ if (gate && gate.blocked) return deniedEnvelope('claim', flow, gate)
123
+ const res = flowVerb(args)
124
+ if (gate) res.json = applyGate(res.json, gate)
125
+ return res
126
+ }
127
+
128
+ /** `writeback`:真写(`--yes`/`--write`)前过闸门;默认 dry-run 不查。 */
129
+ function gatedWriteback(args) {
130
+ const flow = argOf(args, '--flow') || 'wenyao-invoice' // 该回写器服务的就是文鳐发票流程
131
+ const gate = isRealWrite(args) ? runGate(flow) : null
132
+ if (gate && gate.blocked) return deniedEnvelope('writeback', flow, gate)
133
+ const out = run('node', [script('scripts/wenyao-invoice-writeback.mjs'), ...args])
134
+ return gate ? applyGate(out, gate) : out
135
+ }
136
+
137
+
138
+ /** 未知子命令:A1 的"用法错误"(2)+ A2 的 reason(**不是**静默成功)。 */
139
+ const unknownSub = (sub) => ({
140
+ json: { ok: false, empty: false, code: 2, reason: 'unknown_subcommand',
141
+ error: `未知子命令:${sub || '(缺)'}(可用:claim、triage、list)`,
142
+ flow: null, flowPrefix: null, flowKnown: false, dryRun: null, casesFromDir: null },
143
+ human: `❌ unknown_subcommand:未知子命令 ${sub || '(缺)'}(可用:claim、triage、list)`,
144
+ stderr: '', exit: 2,
145
+ })
146
+
147
+ /** `argent flow <claim|triage|list> …` —— 组 verb 只做分派,不另立判据。 */
148
+ const flowGroup = (args) => {
149
+ const [sub, ...rest] = args
150
+ if (sub === 'claim') return gatedClaim(rest)
151
+ if (sub === 'triage') return flowVerb(rest.includes('--plan-only') ? rest : [...rest, '--plan-only'])
152
+ // P1 第三批:`flow list` = 注册表只读清单(薄包 flow_registry.py --json,不实现合并)
153
+ if (sub === 'list') return runFlowListVerb(rest, { repo: REPO, env: process.env })
154
+ if (sub === '--help' || sub === '-h') { // 组帮助不是"用法错误":列出子命令后 exit 0
155
+ const contracts = JSON.parse(readFileSync(join(HERE, '..', 'contracts', 'argent.contracts.json'), 'utf8'))
156
+ return { json: { ok: true, flow: 'flow', subcommands: Object.keys(contracts.verbs.flow.subcommands || {}) },
157
+ human: `argent flow <子命令> —— ${contracts.verbs.flow.desc}\n`
158
+ + Object.entries(contracts.verbs.flow.subcommands || {}).map(([s, d]) => ` ${s.padEnd(8)} ${d}`).join('\n'),
159
+ stderr: '', exit: 0 }
160
+ }
161
+ return unknownSub(sub)
162
+ }
163
+
164
+ /** verb → 具体实现(薄映射;后续逐步把实现搬进 core/,宿主侧不用改) */
165
+ const VERBS = {
166
+ version: () => {
167
+ const argent = (readFileSync(script('VERSION'), 'utf8') || '').trim()
168
+ let dsh = ''
169
+ try { dsh = execFileSync('dsh', ['--version'], { encoding: 'utf8' }).trim() } catch { /* 不在 PATH */ }
170
+ return { ok: true, argent, dsh }
171
+ },
172
+ sop: (args) => resolveSop(argOf(args, '--flow') || 'full', { repo: REPO, py: pyPath(), pyFailure: pyFailure() }),
173
+ source: (args) => runPy([script('scripts/flow_source.py'), ...args]),
174
+ flow: (args) => flowGroup(args),
175
+ // P1 首批:`claim` = **真认领**(默认 dry-run;`--plan-only` 走旧的分诊行为)
176
+ // P1 第二批:**真写**(--apply/--confirm)前过许可闸门(observe 只留证据;enforce 直接拒绝)
177
+ claim: (args) => gatedClaim(args),
178
+ // 旧 `claim` 的行为(只出计划)——名字还给它,行为逐字保留
179
+ triage: (args) => flowVerb(args.includes('--plan-only') ? args : [...args, '--plan-only']),
180
+ gap: (args) => runPy([script('scripts/flow_preflight.py'), ...args]),
181
+ // 真写(--yes/--write)前过许可闸门;dry-run(默认)不查 —— 写操作的判据一致,读操作不打扰
182
+ writeback: (args) => gatedWriteback(args),
183
+ report: (args) => runPy([script('scripts/flow_failure.py'), ...args]),
184
+ // D1:读全量 → 过滤 → 再取末尾 N 行;`flow` 回显**实际生效**的过滤条件(null = 未过滤)
185
+ ledger: (args) => queryLedger({
186
+ file: join(DATA_DIR, 'flow-ledger.jsonl'),
187
+ flow: argOf(args, '--flow'),
188
+ tailInput: argOf(args, '--tail'),
189
+ resolveFilter: (f) => resolveLedgerFlow(f, { repo: REPO, py: pyPath(), pyFailure: pyFailure() }),
190
+ }),
191
+ // P1 第二批:许可组(status|verify|install|request|renew|explain)——判定点唯一在 CLI 进程内
192
+ license: (args) => runLicenseVerb(args, { repo: REPO, env: process.env }),
193
+ // `doctor`:**两种形态,判据不重复**。
194
+ // · `doctor --customer`(M1 判据③)= 客户机一页式自检:整机、**只读**、**不要求 dsh**
195
+ // (无宿主 ⇒ 宿主档事实记「本档不适用」,不算 FAIL)—— 见 core/lib/doctor-customer.mjs;
196
+ // · `doctor --flow <id> [--online]`(旧行为,逐字保留)= 单流程前置检查:仍转发
197
+ // `scripts/flow_preflight.py`(同一个脚本,`--customer` 之前它要求 `--flow` ⇒ exit 2)。
198
+ doctor: (args) => (args.includes('--customer') || args.includes('--help') || args.includes('-h')
199
+ ? runDoctorCustomerVerb(args, { repo: REPO, env: process.env })
200
+ : runPy([script('scripts/flow_preflight.py'), ...args])),
201
+ // ── P1 第三批(2026-10-03):补齐 M1 判据的外围三件 ──────────────────────────
202
+ // notify:通道选择 + 幂等 + dry-run(判断⑩;适配层在 core/lib/notify/,通道实现可替换)
203
+ notify: (args) => runNotifyVerb(args, { repo: REPO, env: process.env }),
204
+ // init:数据目录画像(判断⑧);默认 dry-run,--apply 才建目录(⛔ 不写 settings/credentials)
205
+ init: (args) => runInitVerb(args, { repo: REPO, env: process.env }),
206
+ // versions:CLI/内核/契约/补丁/能力包版本对账(只读)
207
+ versions: (args) => runVersionsVerb(args, { repo: REPO, env: process.env }),
208
+ // audit:审计 JSONL 只读汇总(先全量→过滤→排序→取末尾 N 行,不回退成"先截断")
209
+ audit: (args) => runAuditVerb(args, { repo: REPO, env: process.env }),
210
+ }
211
+
212
+ function run(bin, argv) {
213
+ try {
214
+ const out = execFileSync(bin, argv, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] })
215
+ return { ok: true, output: out }
216
+ } catch (e) {
217
+ return { ok: false, code: e.status ?? 1, output: String(e.stdout || ''), error: String(e.stderr || e.message).slice(0, 400) }
218
+ }
219
+ }
220
+
221
+ /** 需要 Python 的 verb:解释器不可用时**响亮失败**(不 exec 一个不存在的路径当"没结果")。 */
222
+ function runPy(argv) {
223
+ const p = python()
224
+ if (!p.ok) return { ok: false, code: 2, reason: 'python_unavailable', error: p.diagnostics }
225
+ return run(p.path, argv)
226
+ }
227
+
228
+ const argOf = (args, name) => { const i = args.indexOf(name); return i > -1 ? args[i + 1] : '' }
229
+
230
+ const [verb, ...args] = process.argv.slice(2)
231
+ if (!verb || verb === '--help' || verb === '-h') {
232
+ const contracts = JSON.parse(readFileSync(join(HERE, '..', 'contracts', 'argent.contracts.json'), 'utf8'))
233
+ // ⚠️ **代码侧清单**:列 `VERBS` 里**真的有实现**的(P1 第二批改)——此前直接照抄契约,
234
+ // 于是门禁 `check-judgment-drift` 的 "契约声明了 verb,CLI 里没有"(R1a)**恒绿**(假绿空间)。
235
+ // 子命令同理:只报本进程真的分派得动的那些。
236
+ const SUBCOMMANDS = { flow: ['claim', 'triage', 'list'], license: [...LICENSE_SUBCOMMANDS] }
237
+ const implemented = Object.keys(VERBS)
238
+ const meta = (name) => {
239
+ const c = contracts.verbs[name] || {}
240
+ return { kind: c.kind || 'read', desc: c.desc || '(未在契约声明 —— 门禁会报 R1b 漂移)' }
241
+ }
242
+ // `--help --json`:机器可读的 verb 清单(门禁/宿主用它拿"代码里实际存在什么",不用解析人话)
243
+ if (args.includes('--json')) {
244
+ const verbs = implemented.map((name) => ({
245
+ name, ...meta(name),
246
+ ...(SUBCOMMANDS[name] ? { subcommands: SUBCOMMANDS[name] } : {}),
247
+ ...((contracts.verbs[name] || {}).aliases ? { aliases: contracts.verbs[name].aliases } : {}),
248
+ }))
249
+ console.log(JSON.stringify({ ok: true, argent: (readFileSync(script('VERSION'), 'utf8') || '').trim(), verbs }, null, 2))
250
+ process.exit(0)
251
+ }
252
+ console.log('argent <verb> [args…] —— Argent 单入口(0.3 P1,薄别名层)\n')
253
+ for (const name of implemented) {
254
+ const c = meta(name)
255
+ console.log(` ${name.padEnd(10)} [${c.kind}] ${c.desc}`)
256
+ for (const s of SUBCOMMANDS[name] || []) console.log(` · ${s.padEnd(8)} ${(contracts.verbs[name]?.subcommands || {})[s] || ''}`)
257
+ }
258
+ process.exit(0)
259
+ }
260
+ const fn = VERBS[verb]
261
+ if (!fn) { console.error(`未知 verb:${verb}(可用:${Object.keys(VERBS).join(', ')})`); process.exit(2) }
262
+ const AS_JSON = args.includes('--json') || ['version', 'ledger'].includes(verb)
263
+ // P1 第三批:`notify` 的投递是异步的(`--json <payload>` 与 A2 开关同名,由 parseNotifyArgs 自己判形态)
264
+ // ⇒ 顶层 await(本文件是 ESM);同步 verb 不受影响(await 一个非 Promise 值是恒等的)。
265
+ const raw = await fn(args)
266
+ // 适配层 verb 返回信封 `{json, human, stderr}`:人类输出与 JSON 载荷分离 ⇒ `--json` 时 stdout 只有合同字段
267
+ const isEnvelope = Boolean(raw && typeof raw === 'object' && raw.json && typeof raw.json === 'object')
268
+ const out = isEnvelope ? raw.json : raw
269
+ const human = isEnvelope ? raw.human : null
270
+ if (isEnvelope && raw.stderr) process.stderr.write(raw.stderr.endsWith('\n') ? raw.stderr : `${raw.stderr}\n`)
271
+ if (AS_JSON) console.log(JSON.stringify(out, null, 2))
272
+ else console.log(human !== null ? human : (typeof out === 'string' ? out : (out.output || JSON.stringify(out, null, 2))))
273
+ // 失败一律**留痕**(D3:诊断必须看得见;退出码沿用既有口径:ok:false ⇒ code 或 1)
274
+ if (out && out.ok === false && out.error) console.error(String(out.error))
275
+ // A1:`3` **只**表示许可宽限放行 —— 写类 verb 在宽限期内照常完成,但必须用 3 让调用方上报
276
+ const exitCode = out && out.ok === false ? (out.code || 1) : (out && out.code === 3 ? 3 : 0)
277
+ process.exit(exitCode)