@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,16 @@
1
+ /**
2
+ * 脚本侧入口 → **唯一判据在内核** `core/lib/argent-datadir.mjs`。
3
+ *
4
+ * ⚠️ 本文件**不含任何判据**,只是一行再导出(别名):`scripts/**` 用 `./argent-datadir.mjs`
5
+ * 更顺手,而实现必须只有一份 —— 三级链/安全阀的判据、注释、测试都在内核那份里。
6
+ * 改判据请改内核文件,**不要**在这里补逻辑(那就会出现第二份判据)。
7
+ *
8
+ * 为什么判据放内核(而不是直接放 `scripts/lib/`):
9
+ * · `plugins/**`(L2 宿主壳)在 profile 里是 `node_modules/<pkg>` 下的独立包,
10
+ * 按契约**不能 import scripts/**(`scripts/` 是引擎侧),而"壳 import 内核"正是
11
+ * 分层要的方向(`docs/Argent-宿主适配契约.md`);
12
+ * · `core/**` 只用 node 内建,可被任何宿主复用(hermes/Android 同样要用这条链)。
13
+ *
14
+ * 跑法(回归):`node scripts/tests/argent-datadir.test.mjs`
15
+ */
16
+ export * from '../../core/lib/argent-datadir.mjs'
@@ -0,0 +1,262 @@
1
+ #!/usr/bin/env python3
2
+ """Argent 数据目录 —— **Python 侧唯一实现,勿在别处复制判据**。
3
+
4
+ ══════════════════════════════════════════════════════════════════════════
5
+ 〇、这份文件是什么(以及为什么必须有它)
6
+ ══════════════════════════════════════════════════════════════════════════
7
+ JS 内核 `core/lib/argent-datadir.mjs` 是**唯一判据**(三级链 + 隔离安全阀)。
8
+ 但引擎的 Python/shell 面(`scripts/flow_*.py`、`scripts/*.sh`、cron 直跑路径)
9
+ **没法 import 一个 .mjs**,此前各自写着**两级**链:
10
+
11
+ ARGENT_DATA_DIR → ~/.dsh/argent ← 旧写法(**不认 DSH_HOME**)
12
+
13
+ 于是以 `DSH_HOME=<隔离 home>` 起的实例里:插件(JS)写隔离目录、
14
+ CLI/cron(Python/shell)写**生产**目录 —— 正是 2026-10-01 桌面端隔离事故的形态。
15
+ 本模块把 Python/shell 面收敛到与 JS 内核**同语义**的一份实现上:
16
+
17
+ ARGENT_DATA_DIR → $DSH_HOME/argent → ~/.dsh/argent
18
+
19
+ ⚠️ **不允许**在任何 `.py`/`.sh` 里再写一遍这条链(哪怕只有两级)。
20
+ 直跑脚本要用数据目录 ⇒ `from argent_datadir import resolve_data_dir`;
21
+ shell 用 `"$PY" scripts/argent-datadir.py`(CLI 包装)。
22
+ 漂移由门禁 `scripts/tests/argent-datadir-parity.test.mjs` 守住(JS 与 Python **逐字段**比对)。
23
+
24
+ ══════════════════════════════════════════════════════════════════════════
25
+ 一、与 JS 内核的语义对齐(**逐条**,改这里必须同步改内核,反之亦然)
26
+ ══════════════════════════════════════════════════════════════════════════
27
+ · 三级链优先级:`ARGENT_DATA_DIR` > `$DSH_HOME/argent` > `~/.dsh/argent`;
28
+ · `defaultDir` **锚在 OS home**(只认 `$HOME`,**故意不认 `DSH_HOME`**)——
29
+ 否则隔离实例会把自己当成"默认",安全阀失效;
30
+ · **默认目录两步走**(实施方案 P1③ / §6.2 Q6 选项 B,2026-10-03):**老机器**(`~/.dsh/argent`
31
+ **已存在**)**存在即沿用**;不存在(新装、无宿主)⇒ `~/.argent`。判据锚在 OS home,
32
+ 优先级链**不变**(只改"默认"这一级的取值)。本文件与 JS 内核**同批**改、**同夹具**对拍;
33
+ · `isolated = (解析结果 ≠ defaultDir)`:`ARGENT_DATA_DIR` 指回默认目录**不算隔离**
34
+ (不误伤"只是显式写了默认值"的部署);
35
+ · 安全阀:隔离且 `ARGENT_ALLOW_ISOLATED_PUMP` **精确等于 `1`** 才放行(`true`/`01`/空 都不算);
36
+ · fail-closed:解析器不可用(`None` / `dir` 为空)⇒ **暂停**,绝不猜目录;
37
+ · 空串按**未设**处理(`''` 不覆盖下一级);`source` 只在**非空**时才报该级;
38
+ · 相对路径 / 尾部斜杠 / `..`:`os.path.abspath` 与 JS `path.resolve` 语义一致
39
+ (都按 cwd 解析 + 规范化 + 去尾斜杠,都**不**解符号链接);
40
+ · `~` **不做展开**:JS `path.resolve('~/x')` = `<cwd>/~/x`,这里必须一致
41
+ (shell 里不加引号的 `~` 本来就由 shell 展开;加了引号就应当与 JS 同解,
42
+ 否则同一个值在插件里和在 cron 里会解析成**两个不同目录** = 又一处劈叉)。
43
+ · 返回 **camelCase 键**(`dir/source/isolated/defaultDir/dshHome`):这是与 JS 内核的
44
+ **数据契约**,键名必须逐字相同(门禁按字段比对,改名即红)。
45
+
46
+ 分层:本文件是 **L1 内核**(只用 stdlib,不 import 宿主模块)。
47
+ 跑法(回归):`node scripts/tests/argent-datadir-parity.test.mjs`(由 run-tests.sh 收录)
48
+ """
49
+
50
+ from __future__ import annotations
51
+
52
+ import os
53
+ import os.path as _p
54
+
55
+ __all__ = [
56
+ "ENV_DATA_DIR", "ENV_DSH_HOME", "ENV_ALLOW_ISOLATED_PUMP", "DATA_DIR_SEGMENTS",
57
+ "os_home", "dsh_home_of", "legacy_data_dir", "legacy_data_dir_exists",
58
+ "default_data_dir", "resolve_data_dir",
59
+ "describe_data_dir", "loop_gate_for_dir", "loop_gate",
60
+ ]
61
+
62
+ #: 显式数据目录(最高优先级)。
63
+ ENV_DATA_DIR = "ARGENT_DATA_DIR"
64
+ #: 宿主 home(dsh 多实例隔离开关)。
65
+ ENV_DSH_HOME = "DSH_HOME"
66
+ #: 隔离目录下**显式**放开失败回路的开关(必须精确等于 `1`)。
67
+ ENV_ALLOW_ISOLATED_PUMP = "ARGENT_ALLOW_ISOLATED_PUMP"
68
+
69
+ #: **老机器**的数据目录(`~/.dsh/argent`):存在即沿用 —— 这一级同时是"客户机现状"。
70
+ DATA_DIR_SEGMENTS = (".dsh", "argent")
71
+ #: **新装(无宿主)**的默认目录:`~/.argent`(§6.2 Q6 选项 B);只在老位置不存在时生效。
72
+ NO_HOST_DATA_DIR_SEGMENTS = (".argent",)
73
+
74
+
75
+ def _env(env=None):
76
+ """夹具注入点:`env=None` ⇒ 进程环境(与 JS `opts.env || process.env` 同义)。"""
77
+ return os.environ if env is None else env
78
+
79
+
80
+ def _get(env, key) -> str:
81
+ """取环境变量的**真值口径**(与 JS 一致):缺失 / `None` / 空串 ⇒ `''`,其余 `str()`。"""
82
+ v = env.get(key) if hasattr(env, "get") else None
83
+ return str(v) if v else ""
84
+
85
+
86
+ def _join(*parts) -> str:
87
+ """JS `path.join()` 的等价物(**不是** `os.path.join`)。
88
+
89
+ 为什么要单独包一层(门禁夹具 ⑥e 抓出来的真实漂移):
90
+ `os.path.join('/a/iso//', 'argent')` = `'/a/iso//argent'`(**不折叠重复斜杠**),
91
+ 而 JS `path.join('/a/iso//', 'argent')` = `'/a/iso/argent'` ⇒ `raw` 字段两边不同。
92
+ `dir/defaultDir` 因为都过了一遍 resolve/abspath 而看不出差别,`raw` 会。
93
+ """
94
+ return _p.normpath(_p.join(*parts))
95
+
96
+
97
+ def _homedir_fallback() -> str:
98
+ """`os.homedir()` 的 Python 等价(只给"`HOME` 未定义"的兜底用)。
99
+
100
+ 与 node/libuv 同口径:`HOME` **已定义**(哪怕空串)就用它的值;**未定义**才查 passwd。
101
+ """
102
+ if "HOME" in os.environ:
103
+ return str(os.environ.get("HOME") or "")
104
+ try:
105
+ import pwd # POSIX only;仓库只跑 macOS/Linux
106
+ return pwd.getpwuid(os.getuid()).pw_dir
107
+ except Exception: # noqa: BLE001
108
+ return os.path.expanduser("~")
109
+
110
+
111
+ def os_home(env=None) -> str:
112
+ """OS 用户 home(只认 `$HOME`,**故意不认 `DSH_HOME`**)。
113
+
114
+ 判据"是否偏离默认目录"必须锚在 OS home 上,否则隔离实例会把自己当成默认。
115
+ """
116
+ h = _get(_env(env), "HOME")
117
+ return h if h else _homedir_fallback()
118
+
119
+
120
+ def dsh_home_of(env=None, home=None) -> str:
121
+ """宿主 home:`$DSH_HOME` → `~/.dsh`(dsh 多实例隔离:每个实例独立 home)。
122
+
123
+ 注意这不是数据目录,是**数据目录的父目录**。
124
+ """
125
+ e = _env(env)
126
+ return _get(e, ENV_DSH_HOME) or _join(home or os_home(e), ".dsh")
127
+
128
+
129
+ def legacy_data_dir(env=None, home=None) -> str:
130
+ """**老位置** `~/.dsh/argent`(**只算路径,不看存在性**)。"""
131
+ e = _env(env)
132
+ return _join(home or os_home(e), *DATA_DIR_SEGMENTS)
133
+
134
+
135
+ def legacy_data_dir_exists(env=None, home=None) -> bool:
136
+ """**"存在即沿用"的判据本体**:老位置 `~/.dsh/argent` 在不在?
137
+
138
+ 与 JS `legacyDataDirExists()`(`fs.existsSync`)**逐字同解**:用 `os.path.exists`
139
+ (**不是** `os.path.isdir` —— 存在性判据不许两边各写一套;文件也算"存在")。
140
+ """
141
+ return os.path.exists(legacy_data_dir(env, home))
142
+
143
+
144
+ def default_data_dir(env=None, home=None) -> str:
145
+ """默认数据目录(**两步走**,实施方案 P1③ / §6.2 Q6 选项 B,2026-10-03 已批准):
146
+ · ① **存在即沿用**:`~/.dsh/argent` **已存在** ⇒ 它就是默认目录(**老机器永不被误判隔离**);
147
+ · ② 不存在(**新装、无宿主**)⇒ `~/.argent`。
148
+ 与 JS 内核 `core/lib/argent-datadir.mjs#defaultDataDir` **同批、同夹具**对拍
149
+ (`scripts/tests/argent-datadir-parity.test.mjs`);优先级链**不变**。
150
+ """
151
+ if legacy_data_dir_exists(env, home):
152
+ return legacy_data_dir(env, home) # ① 存在即沿用(老机器)
153
+ return _join(home or os_home(_env(env)), *NO_HOST_DATA_DIR_SEGMENTS) # ② 新装(无宿主)⇒ ~/.argent
154
+
155
+
156
+ def resolve_data_dir(env=None, home=None) -> dict:
157
+ """三级链解析(**唯一实现**)。
158
+
159
+ :param env: 环境映射(缺省 `os.environ`;测试夹具传 dict)
160
+ :param home: OS home 覆盖(缺省由 `os_home(env)` 推出)
161
+ :returns: `{"dir", "raw", "source", "isolated", "defaultDir", "dshHome"}`
162
+ · `dir` 解析结果(绝对路径;相对值按 **cwd** 解析)
163
+ · `source` 命中链上的哪一级(日志/面板用)
164
+ · `isolated` `dir` **不等于**默认目录(`default_data_dir()`:老机器 = `~/.dsh/argent`)⇒ 隔离态
165
+ """
166
+ e = _env(env)
167
+ home_ = home or os_home(e)
168
+ default_dir = default_data_dir(e, home_)
169
+ dsh_home = dsh_home_of(e, home_)
170
+ explicit = _get(e, ENV_DATA_DIR)
171
+ if explicit:
172
+ raw = explicit
173
+ elif _get(e, ENV_DSH_HOME):
174
+ raw = _join(dsh_home, "argent")
175
+ else:
176
+ raw = default_dir
177
+ directory = _p.abspath(raw)
178
+ return {
179
+ "dir": directory,
180
+ "raw": raw,
181
+ "source": ENV_DATA_DIR if explicit else (ENV_DSH_HOME if _get(e, ENV_DSH_HOME) else "default"),
182
+ "isolated": directory != _p.abspath(default_dir),
183
+ "defaultDir": _p.abspath(default_dir),
184
+ "dshHome": dsh_home,
185
+ }
186
+
187
+
188
+ def describe_data_dir(resolved) -> str:
189
+ """解析结果的单行描述(日志用)。**文案与 JS 内核逐字相同**(两边日志能对着读)。"""
190
+ if not resolved or not resolved.get("dir"):
191
+ return "数据目录未解析(内核解析器不可用)"
192
+ return f"{resolved['dir']}(来源={resolved.get('source')}{',隔离' if resolved.get('isolated') else ''})"
193
+
194
+
195
+ def loop_gate_for_dir(directory, env=None, home=None) -> dict:
196
+ """对**任意**数据目录求安全阀(宿主把 `dataDir` 放在配置里显式指定时用)。
197
+
198
+ 判据仍在内核:这里只把"配置里的目录"包装成与 `resolve_data_dir()` 同形的结果,
199
+ 隔离判定**不**在调用方重写。
200
+ """
201
+ e = _env(env)
202
+ home_ = home or os_home(e)
203
+ raw = str(directory or "")
204
+ if not raw:
205
+ return loop_gate(None, env=e)
206
+ default_dir = _p.abspath(default_data_dir(e, home_))
207
+ abs_dir = _p.abspath(raw)
208
+ return loop_gate({
209
+ "dir": abs_dir,
210
+ "raw": raw,
211
+ "source": "config",
212
+ "isolated": abs_dir != default_dir,
213
+ "defaultDir": default_dir,
214
+ "dshHome": dsh_home_of(e, home_),
215
+ }, env=e)
216
+
217
+
218
+ def loop_gate(resolved, env=None) -> dict:
219
+ """**隔离安全阀**:失败回路该不该跑。
220
+
221
+ 规则(唯一判据,调用方不得自行判断):
222
+ · 解析器不可用(`resolved` 为空 / `dir` 为空)⇒ **暂停**(fail-closed);
223
+ · `isolated`(数据目录 ≠ 默认目录,判据 = `default_data_dir()`)且未显式
224
+ `ARGENT_ALLOW_ISOLATED_PUMP=1` ⇒ **暂停**,并给出可照做的开启提示;
225
+ · 其余 ⇒ 允许运行。
226
+
227
+ :returns: `{"enabled", "paused", "reason", "isolated", "dir", "notice"}`
228
+ """
229
+ e = _env(env)
230
+ allow = _get(e, ENV_ALLOW_ISOLATED_PUMP) == "1"
231
+ enabled_text = f"设 {ENV_ALLOW_ISOLATED_PUMP}=1 可开启"
232
+ if not resolved or not resolved.get("dir"):
233
+ return {
234
+ "enabled": False,
235
+ "paused": True,
236
+ "reason": "datadir-unresolved",
237
+ "isolated": True,
238
+ "dir": "",
239
+ "notice": "失败回路保持暂停:内核数据目录解析器不可用(core/lib/argent-datadir.mjs 没找到)"
240
+ "⇒ 不敢猜目录。修好后重启即可。",
241
+ }
242
+ if resolved.get("isolated") and not allow:
243
+ return {
244
+ "enabled": False,
245
+ "paused": True,
246
+ "reason": "isolated-data-dir",
247
+ "isolated": True,
248
+ "dir": resolved["dir"],
249
+ "notice": f"失败回路因隔离数据目录而默认暂停({describe_data_dir(resolved)});"
250
+ f"隔离目录通常没有 PAUSE_FLOW_WATCH,默认运行会误扫/派发生产流程 ⇒ {enabled_text}",
251
+ }
252
+ isolated = bool(resolved.get("isolated"))
253
+ return {
254
+ "enabled": True,
255
+ "paused": False,
256
+ "reason": "isolated-allowed" if isolated else "default-dir",
257
+ "isolated": isolated,
258
+ "dir": resolved["dir"],
259
+ "notice": (f"失败回路已按 {ENV_ALLOW_ISOLATED_PUMP}=1 在隔离数据目录上开启"
260
+ f"({describe_data_dir(resolved)})——请确认它扫的是隔离源,不是生产")
261
+ if isolated else "",
262
+ }