@whyshu/argent-engine 0.0.0-stage → 0.6.1

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 (340) hide show
  1. package/MANIFEST.json +341 -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 +576 -0
  55. package/engine/scripts/billing-mode-daily.sh +13 -0
  56. package/engine/scripts/build-engine-package.mjs +126 -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 +378 -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/collect-evidence.mjs +42 -0
  81. package/engine/scripts/config-explain.mjs +278 -0
  82. package/engine/scripts/configure-provider.rb +29 -0
  83. package/engine/scripts/customer-config-migrate.mjs +179 -0
  84. package/engine/scripts/customer-preflight.py +892 -0
  85. package/engine/scripts/customer-readiness.sh +135 -0
  86. package/engine/scripts/daily-report-inbox.py +242 -0
  87. package/engine/scripts/daily-report-reconcile.mjs +312 -0
  88. package/engine/scripts/daily-report.mjs +1310 -0
  89. package/engine/scripts/daily-report.sh +47 -0
  90. package/engine/scripts/data/lip-product-dict.json +306 -0
  91. package/engine/scripts/deliver-customer.mjs +932 -0
  92. package/engine/scripts/delivery-faces.txt +31 -0
  93. package/engine/scripts/desktop-trial.sh +146 -0
  94. package/engine/scripts/dev-window.sh +261 -0
  95. package/engine/scripts/drill-clean-machine.sh +315 -0
  96. package/engine/scripts/dsh-api-client.mjs +215 -0
  97. package/engine/scripts/dsh-backup-scope.sh +83 -0
  98. package/engine/scripts/dsh-offline-pack.mjs +77 -0
  99. package/engine/scripts/dsh-overlay-pin.sh +87 -0
  100. package/engine/scripts/dsh-plane.mjs +153 -0
  101. package/engine/scripts/dsh-portforward.py +223 -0
  102. package/engine/scripts/dsh-preflight.mjs +179 -0
  103. package/engine/scripts/dsh-release-watch-daily.sh +19 -0
  104. package/engine/scripts/dsh-release-watch.mjs +458 -0
  105. package/engine/scripts/dsh-remote-check.sh +99 -0
  106. package/engine/scripts/dsh-restart.sh +179 -0
  107. package/engine/scripts/dsh-restore.sh +111 -0
  108. package/engine/scripts/dsh-scope-rewire.mjs +803 -0
  109. package/engine/scripts/dsh-snapshot.mjs +116 -0
  110. package/engine/scripts/dsh-upgrade-readiness.mjs +165 -0
  111. package/engine/scripts/dsh-upgrade.mjs +612 -0
  112. package/engine/scripts/dsh-url.sh +86 -0
  113. package/engine/scripts/dsh-web-launch.mjs +155 -0
  114. package/engine/scripts/ensure-store-windows.py +509 -0
  115. package/engine/scripts/entitlements.py +458 -0
  116. package/engine/scripts/env_probe.py +411 -0
  117. package/engine/scripts/feishu-card.mjs +252 -0
  118. package/engine/scripts/final-check.mjs +43 -0
  119. package/engine/scripts/fix-skill-frontmatter.py +209 -0
  120. package/engine/scripts/flow-auto-retry.py +454 -0
  121. package/engine/scripts/flow-requirements.json +735 -0
  122. package/engine/scripts/flow-scaffold.py +275 -0
  123. package/engine/scripts/flow-timers-plist.sh +87 -0
  124. package/engine/scripts/flow-timers.sh +184 -0
  125. package/engine/scripts/flow-trigger-wake.mjs +284 -0
  126. package/engine/scripts/flow-trigger.sh +571 -0
  127. package/engine/scripts/flow_billing.py +354 -0
  128. package/engine/scripts/flow_capability_stats.py +314 -0
  129. package/engine/scripts/flow_case.py +194 -0
  130. package/engine/scripts/flow_claim.py +497 -0
  131. package/engine/scripts/flow_config.py +1025 -0
  132. package/engine/scripts/flow_failure.py +588 -0
  133. package/engine/scripts/flow_learn.py +105 -0
  134. package/engine/scripts/flow_ledger.py +235 -0
  135. package/engine/scripts/flow_policy.py +238 -0
  136. package/engine/scripts/flow_preflight.py +339 -0
  137. package/engine/scripts/flow_registry.py +341 -0
  138. package/engine/scripts/flow_retry.py +304 -0
  139. package/engine/scripts/flow_return_to_ops.py +191 -0
  140. package/engine/scripts/flow_source.py +315 -0
  141. package/engine/scripts/flow_sources/__init__.py +53 -0
  142. package/engine/scripts/flow_sources/cases_json.py +106 -0
  143. package/engine/scripts/flow_sources/common.py +428 -0
  144. package/engine/scripts/flow_sources/feishu_base.py +273 -0
  145. package/engine/scripts/flow_stale.py +185 -0
  146. package/engine/scripts/flow_status_reconcile.py +344 -0
  147. package/engine/scripts/flow_triage.py +849 -0
  148. package/engine/scripts/flow_write_verify.py +496 -0
  149. package/engine/scripts/fulfillment.js +586 -0
  150. package/engine/scripts/gen-agent-bundles.mjs +276 -0
  151. package/engine/scripts/gen-preset-rows.mjs +259 -0
  152. package/engine/scripts/init-ml.sh +2278 -0
  153. package/engine/scripts/install-internal-role.sh +190 -0
  154. package/engine/scripts/install-license.mjs +641 -0
  155. package/engine/scripts/install-one-shot.mjs +665 -0
  156. package/engine/scripts/integration_contract.py +220 -0
  157. package/engine/scripts/integrations/wenyao/adapter.py +98 -0
  158. package/engine/scripts/integrations/xzh/adapter.py +75 -0
  159. package/engine/scripts/invoice-mapping.example.json +40 -0
  160. package/engine/scripts/invoice-table.sh +195 -0
  161. package/engine/scripts/invoice_carrier_notice.py +279 -0
  162. package/engine/scripts/invoice_fail_closeout.py +297 -0
  163. package/engine/scripts/invoice_lip_runner.py +1508 -0
  164. package/engine/scripts/invoice_lip_runner.py.bak-20260922-1710-freready +1090 -0
  165. package/engine/scripts/invoice_ready_audit.py +191 -0
  166. package/engine/scripts/invoice_runner.py +675 -0
  167. package/engine/scripts/invoice_stageb.py +516 -0
  168. package/engine/scripts/launchd/com.whyshu.argent-bridge.plist.example +42 -0
  169. package/engine/scripts/launchd/com.whyshu.fulfillment-poll.plist.example +29 -0
  170. package/engine/scripts/lease.py +377 -0
  171. package/engine/scripts/lib/agent-install.mjs +649 -0
  172. package/engine/scripts/lib/argent-datadir.mjs +16 -0
  173. package/engine/scripts/lib/argent-datadir.sh +18 -0
  174. package/engine/scripts/lib/argent_datadir.py +285 -0
  175. package/engine/scripts/lib/argent_filelock.py +507 -0
  176. package/engine/scripts/lib/bootcheck-wiring.mjs +510 -0
  177. package/engine/scripts/lib/cdp_ports.py +197 -0
  178. package/engine/scripts/lib/customer-env.mjs +102 -0
  179. package/engine/scripts/lib/daily-report-core.mjs +517 -0
  180. package/engine/scripts/lib/dep-declaration.mjs +81 -0
  181. package/engine/scripts/lib/deps-migrate.mjs +310 -0
  182. package/engine/scripts/lib/dsh-host-resolve.mjs +109 -0
  183. package/engine/scripts/lib/dsh-scope.mjs +500 -0
  184. package/engine/scripts/lib/dsh-snapshot-path.mjs +35 -0
  185. package/engine/scripts/lib/dsh-versions.mjs +96 -0
  186. package/engine/scripts/lib/dsh-web-probe.mjs +214 -0
  187. package/engine/scripts/lib/is-direct-run.mjs +61 -0
  188. package/engine/scripts/lib/patch-compose.mjs +241 -0
  189. package/engine/scripts/lib/patch-target.mjs +35 -0
  190. package/engine/scripts/lib/plugin-lifecycle.mjs +128 -0
  191. package/engine/scripts/lib/plugin-packages.mjs +332 -0
  192. package/engine/scripts/lib/preset-compat.mjs +127 -0
  193. package/engine/scripts/lib/preset-install.mjs +575 -0
  194. package/engine/scripts/lib/preset-mechanism.mjs +56 -0
  195. package/engine/scripts/lib/preset-sync.mjs +59 -0
  196. package/engine/scripts/lib/profile-retire.mjs +97 -0
  197. package/engine/scripts/lib/python-runtime.mjs +190 -0
  198. package/engine/scripts/lib/registry.mjs +72 -0
  199. package/engine/scripts/lib/repo-root.sh +56 -0
  200. package/engine/scripts/lib/schedule-mechanism.mjs +659 -0
  201. package/engine/scripts/lib/schedule-probe.mjs +835 -0
  202. package/engine/scripts/lib/scope-pointer.mjs +164 -0
  203. package/engine/scripts/lib/settings-panels.mjs +816 -0
  204. package/engine/scripts/lib/stdio_utf8.py +86 -0
  205. package/engine/scripts/lib/wake-auth.mjs +392 -0
  206. package/engine/scripts/lib/webdriver_ipc.py +264 -0
  207. package/engine/scripts/lib/zstd-frames.mjs +104 -0
  208. package/engine/scripts/license-e2e-drill.mjs +426 -0
  209. package/engine/scripts/license-gate.mjs +245 -0
  210. package/engine/scripts/lip_backlog.py +171 -0
  211. package/engine/scripts/lip_table.py +185 -0
  212. package/engine/scripts/local-usage.mjs +214 -0
  213. package/engine/scripts/migrate-providers.mjs +127 -0
  214. package/engine/scripts/migrate-skills.sh +65 -0
  215. package/engine/scripts/ml-oauth-setup.mjs +550 -0
  216. package/engine/scripts/ml-store-ids.json +26 -0
  217. package/engine/scripts/ml_artifact_attribution.py +333 -0
  218. package/engine/scripts/ml_capacity_probe.py +1158 -0
  219. package/engine/scripts/ml_hub_status.py +1556 -0
  220. package/engine/scripts/ml_schema_check.py +115 -0
  221. package/engine/scripts/ml_store_ids.py +139 -0
  222. package/engine/scripts/npm-publish-argent.mjs +499 -0
  223. package/engine/scripts/npm-publish-argent.sh +20 -0
  224. package/engine/scripts/orchestrator.py +13811 -0
  225. package/engine/scripts/pack-plugins.mjs +140 -0
  226. package/engine/scripts/patches/dsh-llm-deepseek--transport-diagnostics.patch +297 -0
  227. package/engine/scripts/patches/dsh-session--append-message-shape.patch +15 -0
  228. package/engine/scripts/patches/dsh-session--tool-result-block-017.patch +28 -0
  229. package/engine/scripts/patches/dsh-session-format-v0-to-v1--permission-preset-origin.patch +11 -0
  230. package/engine/scripts/patches/dsh-session-format-v3-to-v4--turn-outside-replace.patch +20 -0
  231. package/engine/scripts/patches/dsh-session-persistence-jsonl--worker-bundled-migrators.patch +39 -0
  232. package/engine/scripts/patches/dsh-tools--render-return-shape.patch +50 -0
  233. package/engine/scripts/patches/verify-bundled-migrators.mjs +79 -0
  234. package/engine/scripts/patches/verify-hardening.mjs +167 -0
  235. package/engine/scripts/patches/verify-session-migration.mjs +149 -0
  236. package/engine/scripts/patches/verify-transport-diagnostics.mjs +227 -0
  237. package/engine/scripts/plan-role-rename.mjs +125 -0
  238. package/engine/scripts/plugin-bootcheck.mjs +451 -0
  239. package/engine/scripts/plugin-composition.json +15 -0
  240. package/engine/scripts/poc-mcp-host.mjs +455 -0
  241. package/engine/scripts/poll-fulfillment.sh +295 -0
  242. package/engine/scripts/poll-invoice.sh +76 -0
  243. package/engine/scripts/profile-doctor.mjs +686 -0
  244. package/engine/scripts/provider-select.sh +71 -0
  245. package/engine/scripts/provider-switch.sh +146 -0
  246. package/engine/scripts/provider-sync-target.check.mjs +64 -0
  247. package/engine/scripts/python-runtime.sh +78 -0
  248. package/engine/scripts/query_runner.py +310 -0
  249. package/engine/scripts/release-argent.sh +574 -0
  250. package/engine/scripts/repair-unresolved-tools.mjs +178 -0
  251. package/engine/scripts/retire-inventory.mjs +40 -0
  252. package/engine/scripts/run-tests.sh +257 -0
  253. package/engine/scripts/s1-audit.mjs +85 -0
  254. package/engine/scripts/self-sign-license.mjs +179 -0
  255. package/engine/scripts/session-health-scan.mjs +63 -0
  256. package/engine/scripts/session-repair-tool-result-content.mjs +181 -0
  257. package/engine/scripts/setup.sh +22 -0
  258. package/engine/scripts/skill-install.mjs +629 -0
  259. package/engine/scripts/sku_translate.py +148 -0
  260. package/engine/scripts/sync-plugins.sh +90 -0
  261. package/engine/scripts/sync-presets.sh +27 -0
  262. package/engine/scripts/sync-scripts.sh +445 -0
  263. package/engine/scripts/telemetry.py +873 -0
  264. package/engine/scripts/ui-copy-count.mjs +220 -0
  265. package/engine/scripts/usage-anchor.sh +137 -0
  266. package/engine/scripts/usage_report.py +531 -0
  267. package/engine/scripts/validate-preset-schema.mjs +208 -0
  268. package/engine/scripts/vertical-init.mjs +323 -0
  269. package/engine/scripts/vertical-lint.mjs +482 -0
  270. package/engine/scripts/wenyao-browser.sh +74 -0
  271. package/engine/scripts/wenyao-fixture-export.py +116 -0
  272. package/engine/scripts/wenyao-invoice-writeback.mjs +540 -0
  273. package/engine/scripts/wenyao-login.sh +35 -0
  274. package/engine/scripts/wenyao-template-map.json +292 -0
  275. package/engine/scripts/wenyao_attach.py +131 -0
  276. package/engine/scripts/wenyao_download_template.py +144 -0
  277. package/engine/scripts/wenyao_fill_template.py +568 -0
  278. package/engine/scripts/wenyao_login.py +145 -0
  279. package/engine/scripts/wenyao_portal.py +633 -0
  280. package/engine/scripts/wenyao_recon.py +230 -0
  281. package/engine/scripts/wenyao_run.py +503 -0
  282. package/engine/scripts/wenyao_shadow_diff.py +160 -0
  283. package/engine/scripts/wenyao_skill_contract.py +156 -0
  284. package/engine/scripts/wenyao_template_fetch.py +175 -0
  285. package/engine/scripts/win/dsh-web-autostart.ps1 +372 -0
  286. package/engine/scripts/ziniao-auth-probe.sh +268 -0
  287. package/engine/scripts/ziniao-keepalive.sh +217 -0
  288. package/engine/scripts/ziniao-post-upgrade-check.sh +121 -0
  289. package/engine/scripts/ziniao-windows.sh +154 -0
  290. package/engine/skills/README.md +86 -0
  291. package/engine/skills/argent-dev/SKILL.md +41 -0
  292. package/engine/skills/internal.json +37 -0
  293. package/engine/skills/lktop-pm/SKILL.md +35 -0
  294. package/engine/skills/lktopapp-dev/SKILL.md +34 -0
  295. package/engine/skills/ml-config-guide/SKILL.md +50 -0
  296. package/engine/skills/ml-fulfillment-sop/SKILL.md +178 -0
  297. package/engine/skills/ml-fulfillment-sop/references/andes-components.md +69 -0
  298. package/engine/skills/ml-fulfillment-sop/references/cdp-port-mapping.md +35 -0
  299. package/engine/skills/ml-fulfillment-sop/references/feishu-base-fulfillment-schema.md +136 -0
  300. package/engine/skills/ml-fulfillment-sop/references/multi-window-concurrency.md +69 -0
  301. package/engine/skills/ml-fulfillment-sop/references/pitfalls.md +77 -0
  302. package/engine/skills/ml-fulfillment-sop/references/selectors.md +243 -0
  303. package/engine/skills/ml-fulfillment-sop/scripts/fulfillment.js +586 -0
  304. package/engine/skills/ml-fulfillment-sop/scripts/poll-and-execute.sh +271 -0
  305. package/engine/skills/ml-fulfillment-sop/templates/report.md +55 -0
  306. package/engine/skills/ml-invoice/SKILL.md +506 -0
  307. package/engine/skills/ml-invoice/references/pitfalls.md +268 -0
  308. package/engine/skills/ml-invoice/references/portal-flow.md +360 -0
  309. package/engine/skills/ml-invoice/references/template-fill-contract.md +133 -0
  310. package/engine/skills/ml-invoice-xzh/SKILL.md +133 -0
  311. package/engine/skills/ml-invoice-xzh/references/pitfalls.md +230 -0
  312. package/engine/skills/ml-store-daily-report/SKILL.md +224 -0
  313. package/engine/skills/ml-store-daily-report/scripts/README.md +25 -0
  314. package/engine/skills/ml-store-daily-report/scripts/extract.js +691 -0
  315. package/engine/skills/ml-store-daily-report/scripts/generate.js +299 -0
  316. package/engine/skills/pet-dev/SKILL.md +42 -0
  317. package/engine/skills/whyshu-pm/SKILL.md +35 -0
  318. package/engine/skills/whyshu-web-dev/SKILL.md +50 -0
  319. package/engine/version.mjs +1 -0
  320. package/engine/verticals/README.md +103 -0
  321. package/engine/verticals/_engine-words.baseline.txt +237 -0
  322. package/engine/verticals/_engine-words.json +19 -0
  323. package/engine/verticals/mercadolibre/README.md +43 -0
  324. package/engine/verticals/mercadolibre/config.json +709 -0
  325. package/engine/verticals/mercadolibre/flows.json +738 -0
  326. package/engine/verticals/mercadolibre/manifest.json +538 -0
  327. package/engine/verticals/mercadolibre/migrate-machine-state.mjs +138 -0
  328. package/engine/verticals/mercadolibre/preflight.py +143 -0
  329. package/engine/verticals/mercadolibre/prompts/daily-report.failure.md +69 -0
  330. package/engine/verticals/mercadolibre/prompts/daily-report.md +47 -0
  331. package/engine/verticals/mercadolibre/prompts/daily-report.scheduled.md +79 -0
  332. package/engine/verticals/mercadolibre/prompts/full.failure.md +125 -0
  333. package/engine/verticals/mercadolibre/prompts/full.md +91 -0
  334. package/engine/verticals/mercadolibre/prompts/wenyao-invoice.failure.md +88 -0
  335. package/engine/verticals/mercadolibre/prompts/wenyao-invoice.md +64 -0
  336. package/engine/verticals/mercadolibre/prompts/xzh-invoice.failure.md +91 -0
  337. package/engine/verticals/mercadolibre/prompts/xzh-invoice.md +46 -0
  338. package/package.json +22 -4
  339. package/requirements.txt +5 -0
  340. package/README.md +0 -3
@@ -0,0 +1,576 @@
1
+ #!/bin/bash
2
+ . "$(dirname "$0")/lib/argent-datadir.sh" # 0.7.0 W8/S1:数据根唯一判据
3
+ # ============================================================
4
+ # base-bootstrap.sh — 飞书多维表格「FULL任务」自动代建脚本 v2(模板复制路径)
5
+ #
6
+ # 路径 A(默认,推荐):BOT 从生产 FULL 模板 Base 复制新 Base
7
+ # lark-cli base +base-copy --as bot --without-content
8
+ # → 新 Base 100% 继承模板结构:12 字段 + 3 视图(表格/待处理/运营填写)
9
+ # (实测验证:字段名/类型/视图与模板完全一致,0 条记录)
10
+ # → permission.public patch → link_share_entity=tenant_editable(企业内全员可编辑,
11
+ # 无需逐个授权,无需转移所有者)
12
+ # → 复制后 CLI 自动给当前 CLI 用户 full_access(可管理权限)
13
+ # → 回读字段验证 + 测试记录写入/清理(确认 BOT 可写)
14
+ # → 写 fulfillment.env:BASE_TOKEN/TABLE_ID/FEISHU_BASE_TOKEN/FEISHU_TABLE_ID
15
+ #
16
+ # 实测记录(2026-08-18):
17
+ # · 复制继承结构(12 字段 + 3 视图)✅;不继承「历史记录」开关
18
+ # (源模板开 → 副本关;飞书无公开 API 可读写该开关,已排查 bitable app /
19
+ # drive file-version / record-history 均不涉及)——开关延后,需人工在 UI 打开
20
+ # (副本创建者/BOT 可管理权限账号可在「··· → 历史记录」开启)
21
+ # · BOT 读历史记录能力 ✅(record-history-list 实测返回完整字段变更审计)
22
+ # · 生产模板 MKsLbkFfmahoEGsZSKKcXHrbnDA 为只读复制源,永不修改
23
+ # (hermes 智能体正在使用,复制不会触碰源)
24
+ #
25
+ # 路径 B(--url):客户已有 Base 内创建「FULL任务」表(12 字段 + 3 视图)——
26
+ # 旧版兼容路径,需先把应用加为该 Base 协作者
27
+ #
28
+ # 身份:一律 --as bot,沿用 lark-cli 当前全局应用(本机为 hermes 旧应用
29
+ # cli_a93b9354c6e35cd1,hermes agent 正在使用)——⚠️ 禁止任何 lark-cli config init
30
+ # 切换应用,否则会打断运行中的 hermes agent。本脚本不触碰全局配置。
31
+ # 兼容 bash 3.2(macOS 默认):中文变量一律 ${VAR} 花括号形式。
32
+ #
33
+ # 用法:
34
+ # base-bootstrap.sh [--base-name <名称>] [--owner-email <邮箱>]
35
+ # [--owner-openid <open_id>] [--url <base_url>]
36
+ # [--env-file <path>] [--domain <host>]
37
+ # [--force] [--skip-test] [--json] [--non-interactive]
38
+ # --base-name <名称> 新 Base 名称(默认 Argent 货件管理)
39
+ # --owner-email/-openid 可选:写入 env(FEISHU_OWNER_*),不做授权/转移
40
+ # --url <base_url> 路径 B:在客户已有 Base 内建表(需先加应用为协作者)
41
+ # --env-file <path> 输出 env 文件(默认 ~/.dsh/argent/fulfillment.env)
42
+ # --domain <host> 租户域名(默认 lcn33f9yunjm.feishu.cn,用于生成链接)
43
+ # --force 路径 B:表已存在时删除重建
44
+ # --skip-test 跳过测试记录写入
45
+ # --json 末尾输出一行 RESULT_JSON: {...}(机器可读,隐含 --non-interactive)
46
+ # --non-interactive 不询问确认,直接执行
47
+ # ============================================================
48
+ set -euo pipefail
49
+
50
+ RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[0;33m'; CYAN='\033[0;36m'; BOLD='\033[1m'; NC='\033[0m'
51
+ log_info() { echo -e "${CYAN}→${NC} $*"; }
52
+ log_ok() { echo -e "${GREEN}✓${NC} $*"; }
53
+ log_warn() { echo -e "${YELLOW}⚠${NC} $*"; }
54
+ log_err() { echo -e "${RED}✗${NC} $*"; }
55
+
56
+ # ── 常量 ──────────────────────────────────────────────
57
+ TEMPLATE_BASE_TOKEN="MKsLbkFfmahoEGsZSKKcXHrbnDA" # 生产 FULL 模板(只读源,永不修改)
58
+ TEMPLATE_TABLE_NAME="FULL任务"
59
+
60
+ # ── 参数解析 ──────────────────────────────────────────
61
+ BASE_URL=""
62
+ OWNER_EMAIL=""
63
+ OWNER_OPENID=""
64
+ BASE_NAME=""
65
+ ENV_FILE="$ARGENT_DATA_DIR_RESOLVED/fulfillment.env"
66
+ DOMAIN="lcn33f9yunjm.feishu.cn"
67
+ FORCE=0
68
+ SKIP_TEST=0
69
+ JSON_OUT=0
70
+ NON_INTERACTIVE=0
71
+ while [ "$#" -gt 0 ]; do
72
+ case "$1" in
73
+ --help|-h)
74
+ echo "用法: base-bootstrap.sh [选项]"
75
+ echo ""
76
+ echo " 飞书多维表格「FULL任务」自动代建脚本 v2(默认:从生产模板复制)"
77
+ echo ""
78
+ echo " --base-name <名称> 新 Base 名称(默认 Argent 货件管理)"
79
+ echo " --owner-email <邮箱> 可选:写入 env 的 FEISHU_OWNER_EMAIL(不做授权/转移)"
80
+ echo " --owner-openid <open_id> 可选:写入 env 的 FEISHU_OWNER_OPENID"
81
+ echo " --url <base_url> 路径 B:在客户已有 Base 内建表(需手动加应用为协作者)"
82
+ echo " --env-file <path> 输出 env 文件(默认 ~/.dsh/argent/fulfillment.env)"
83
+ echo " --domain <host> 租户域名(默认 lcn33f9yunjm.feishu.cn,生成链接用)"
84
+ echo " --force 路径 B:表已存在时删除重建"
85
+ echo " --skip-test 跳过测试记录写入"
86
+ echo " --json 末尾输出 RESULT_JSON 行(机器可读)"
87
+ echo " --non-interactive 非交互模式:不询问确认,直接执行"
88
+ echo ""
89
+ echo " 注意:本脚本沿用 lark-cli 当前全局应用(--as bot),绝不执行 config init"
90
+ echo " (本机 hermes agent 正在使用该应用,切换会打断它)。"
91
+ echo ""
92
+ echo " 示例:"
93
+ echo " base-bootstrap.sh --base-name 'Argent 货件管理(华东仓)'"
94
+ echo " base-bootstrap.sh --url https://xxx.feishu.cn/base/XXX --non-interactive"
95
+ exit 0 ;;
96
+ --url) BASE_URL="${2:-}"; shift 2 ;;
97
+ --owner-email) OWNER_EMAIL="${2:-}"; shift 2 ;;
98
+ --owner-openid) OWNER_OPENID="${2:-}"; shift 2 ;;
99
+ --base-name) BASE_NAME="${2:-}"; shift 2 ;;
100
+ --env-file) ENV_FILE="${2:-}"; shift 2 ;;
101
+ --domain) DOMAIN="${2:-}"; shift 2 ;;
102
+ --force) FORCE=1; shift ;;
103
+ --skip-test) SKIP_TEST=1; shift ;;
104
+ --json) JSON_OUT=1; NON_INTERACTIVE=1; shift ;;
105
+ --non-interactive) NON_INTERACTIVE=1; shift ;;
106
+ *) log_err "未知参数: ${1}"; exit 1 ;;
107
+ esac
108
+ done
109
+ BASE_NAME="${BASE_NAME:-Argent 货件管理}"
110
+
111
+ # ── 交互确认(默认 Yes)──
112
+ _confirm() {
113
+ [ "$NON_INTERACTIVE" = "1" ] && return 0
114
+ local ans
115
+ read -r -p "$1 [Y/n]: " ans
116
+ case "$(echo "$ans" | tr '[:upper:]' '[:lower:]')" in
117
+ ""|y|yes) return 0 ;;
118
+ *) return 1 ;;
119
+ esac
120
+ }
121
+
122
+ # ── 工具:JSON 提取(python3 读文件,避免管道安全拦截)──
123
+ # 容忍 stderr 混入文件头部的 Warning 行:从第一个 { 或 [ 起解析
124
+ _json_get() { # $1=文件路径 $2=python 表达式(d 为已解析 dict)
125
+ python3 -c "
126
+ import json
127
+ s = open('$1').read()
128
+ i = s.find('{')
129
+ if i < 0:
130
+ i = s.find('[')
131
+ d = json.loads(s[i:]) if i >= 0 else {}
132
+ print($2)
133
+ " 2>/dev/null || true
134
+ }
135
+
136
+ # ── 1. bot 身份就绪检查(--as bot)──────────────────────
137
+ AUTH_JSON=$(mktemp -t lark-auth.XXXXXX.json)
138
+ trap 'rm -f "$AUTH_JSON"' EXIT
139
+ lark-cli auth status > "$AUTH_JSON" 2>/dev/null || true
140
+ BOT_STATUS=$(python3 -c "
141
+ import json
142
+ try:
143
+ d = json.load(open('$AUTH_JSON'))
144
+ print(d.get('identities', {}).get('bot', {}).get('status', 'missing'))
145
+ except Exception:
146
+ print('missing')
147
+ ")
148
+
149
+ if [ "$BOT_STATUS" != "ready" ]; then
150
+ echo ""
151
+ echo "════════════════════════════════════════════════"
152
+ echo " 飞书应用(bot 身份)未就绪"
153
+ echo "════════════════════════════════════════════════"
154
+ log_err "lark-cli 的 bot 身份未就绪(当前状态: ${BOT_STATUS})——建表/授权需要以应用身份执行。"
155
+ echo ""
156
+ echo " 请检查飞书应用配置(Web 设置页保存 App ID/Secret 即可自动初始化):"
157
+ echo " ① ~/.dsh/argent/config.json 的 feishuAppId / feishuAppSecret 是否正确、已绑定"
158
+ echo " ② 确认已开通权限:bitable:app(查看评论编辑管理多维表格)、"
159
+ echo " drive:drive(查看评论编辑管理云空间文件)"
160
+ echo " ③ 确认应用已发布(开放平台 → 版本管理与发布 → 发布)"
161
+ echo " ④ 修复后重跑本脚本"
162
+ exit 1
163
+ fi
164
+ log_ok "bot 身份就绪"
165
+
166
+ # ── 2. 分支:路径 A(模板复制)/路径 B(--url 已有 Base)──
167
+ if [ -z "$BASE_URL" ]; then
168
+ # ═══════════════ 路径 A:模板复制(默认) ═══════════════
169
+ echo ""
170
+ echo "════════════════════════════════════════════════"
171
+ echo " 📋 从生产模板复制 Base(12 字段 + 3 视图,仅结构)"
172
+ echo "════════════════════════════════════════════════"
173
+ log_info "模板: ${TEMPLATE_BASE_TOKEN}(只读源,永不修改)"
174
+ if ! _confirm " 确认从模板复制新 Base「${BASE_NAME}」?"; then
175
+ log_err "已取消"; exit 1
176
+ fi
177
+
178
+ COPY_JSON=$(mktemp -t lark-base-copy.XXXXXX.json)
179
+ if ! lark-cli base +base-copy \
180
+ --as bot \
181
+ --base-token "$TEMPLATE_BASE_TOKEN" \
182
+ --name "${BASE_NAME}" \
183
+ --without-content \
184
+ --format json > "$COPY_JSON" 2>&1; then
185
+ log_err "模板复制失败:"
186
+ head -8 "$COPY_JSON"
187
+ log_err "请检查:① 应用是否有模板 Base 的访问权限(tenant_editable 或协作者);"
188
+ echo " ② 是否已开通 bitable:app 与 drive:drive;③ 应用是否已发布"
189
+ exit 1
190
+ fi
191
+ # 新 Base token 解析(兼容多种返回结构)
192
+ BASE_TOKEN=$(_json_get "$COPY_JSON" "d.get('data', {}).get('base', {}).get('base_token') or d.get('data', {}).get('base_token') or d.get('data', {}).get('app', {}).get('app_token') or ''")
193
+ # 复制后 CLI 尝试给当前 CLI 用户 full_access(可管理)——成功/跳过都必须告知
194
+ GRANT_STATUS=$(_json_get "$COPY_JSON" "d.get('permission_grant', {}).get('status') or ''")
195
+ PERM_GRANT=$(_json_get "$COPY_JSON" "json.dumps(d.get('permission_grant'), ensure_ascii=False) if d.get('permission_grant') else ''")
196
+ rm -f "$COPY_JSON"
197
+ if [ -z "$BASE_TOKEN" ]; then
198
+ log_err "复制成功但无法解析 Base Token——请检查模板访问权限后重试"
199
+ exit 1
200
+ fi
201
+ log_ok "新 Base 已创建: ${BASE_TOKEN}"
202
+ if [ "$GRANT_STATUS" = "skipped" ]; then
203
+ log_warn "自动授予当前用户 full_access 被跳过(lark-cli 无已登录用户会话)"
204
+ log_warn "如需管理员权限:可在网页端给账号加可管理协作者,或执行 lark-cli auth login 后重跑"
205
+ log_warn "(历史记录开关等管理操作需要该权限;企业内链接可编辑已由 tenant_editable 覆盖)"
206
+ elif [ -n "$PERM_GRANT" ]; then
207
+ log_info "permission_grant: ${PERM_GRANT}"
208
+ fi
209
+
210
+ # 解析表 ID(复制品含模板的 FULL任务 表,按名回查;复制后短暂时延需重试)
211
+ TABLE_ID=""
212
+ for _try in 1 2 3 4 5; do
213
+ [ -z "$TABLE_ID" ] || break
214
+ sleep 2
215
+ TABLES_JSON=$(mktemp -t lark-tables.XXXXXX.json)
216
+ lark-cli base +table-list --base-token "$BASE_TOKEN" --as bot --format json > "$TABLES_JSON" 2>/dev/null || true
217
+ TABLE_ID=$(python3 -c "
218
+ import json
219
+ try:
220
+ d = json.load(open('$TABLES_JSON'))
221
+ ts = [t.get('id', '') for t in d.get('data', {}).get('tables', []) if t.get('name') == '$TEMPLATE_TABLE_NAME']
222
+ print(ts[0] if ts else '')
223
+ except Exception:
224
+ print('')
225
+ ")
226
+ rm -f "$TABLES_JSON"
227
+ done
228
+ if [ -z "$TABLE_ID" ]; then
229
+ log_err "无法确定「${TEMPLATE_TABLE_NAME}」表 ID——请检查复制品结构"
230
+ exit 1
231
+ fi
232
+ log_ok "表「${TEMPLATE_TABLE_NAME}」: ${TABLE_ID}"
233
+
234
+ # ── 开放企业内可编辑(tenant_editable)────────────────
235
+ echo ""
236
+ echo "════════════════════════════════════════════════"
237
+ echo " 🔓 开放企业内可编辑(link_share_entity=tenant_editable)"
238
+ echo "════════════════════════════════════════════════"
239
+ PUB_JSON=$(mktemp -t lark-pub.XXXXXX.json)
240
+ PUB_OK=0
241
+ for _try in 1 2; do
242
+ if lark-cli drive permission.public patch --as bot --yes \
243
+ --params "{\"token\":\"${BASE_TOKEN}\",\"type\":\"bitable\"}" \
244
+ --data '{"link_share_entity":"tenant_editable"}' \
245
+ --format json > "$PUB_JSON" 2>&1; then
246
+ PUB_OK=1
247
+ break
248
+ fi
249
+ sleep 3
250
+ done
251
+ if [ "$PUB_OK" = "1" ]; then
252
+ log_ok "已开放:企业内成员通过链接可编辑(无需逐个授权/转移所有者)"
253
+ else
254
+ log_warn "开放企业内可编辑失败(可稍后手动处理):"
255
+ head -6 "$PUB_JSON"
256
+ fi
257
+ rm -f "$PUB_JSON"
258
+ else
259
+ # ═══════════════ 路径 B:--url 已有 Base 建表(legacy) ═══════════════
260
+ echo ""
261
+ echo "════════════════════════════════════════════════"
262
+ echo " 📋 在已有 Base 中创建「${TEMPLATE_TABLE_NAME}」表(12 字段 + 3 视图)"
263
+ echo "════════════════════════════════════════════════"
264
+ BASE_TOKEN=$(echo "$BASE_URL" | python3 -c "
265
+ import re, sys
266
+ u = sys.stdin.read().strip()
267
+ m = re.search(r'/base/([A-Za-z0-9]+)', u)
268
+ print(m[1] if m else '')
269
+ ")
270
+ if [ -z "$BASE_TOKEN" ]; then
271
+ log_err "无法从 URL 解析 Base Token——请确认格式: https://xxx.feishu.cn/base/XXX"
272
+ exit 1
273
+ fi
274
+ log_warn "该 Base 需手动把飞书应用添加为协作者(可管理权限),否则后续 bot 操作会失败"
275
+
276
+ # 字段 schema(对齐模板字段;SKU 主字段)
277
+ FIELDS_JSON='[
278
+ {"type":"text","name":"SKU"},
279
+ {"type":"select","name":"状态","options":[{"name":"Pending"},{"name":"运行中"},{"name":"已完成"},{"name":"失败"}]},
280
+ {"type":"select","name":"店铺名称","options":[{"name":"3店-主账号"},{"name":"2店-子账号"},{"name":"1店-子账号"}]},
281
+ {"type":"text","name":"品名"},
282
+ {"type":"number","name":"数量","style":{"type":"plain","precision":2}},
283
+ {"type":"number","name":"箱数","style":{"type":"plain","precision":2}},
284
+ {"type":"checkbox","name":"就绪"},
285
+ {"type":"created_at","name":"创建时间"},
286
+ {"type":"text","name":"当前步骤"},
287
+ {"type":"text","name":"货件号"},
288
+ {"type":"attachment","name":"产品标签"},
289
+ {"type":"attachment","name":"箱唛"}
290
+ ]'
291
+
292
+ # 建表前检查:是否已有同名表
293
+ TABLES_JSON=$(mktemp -t lark-tables.XXXXXX.json)
294
+ lark-cli base +table-list --base-token "$BASE_TOKEN" --as bot --format json > "$TABLES_JSON" 2>/dev/null || true
295
+ HAS_TABLE=$(python3 -c "
296
+ import json
297
+ try:
298
+ d = json.load(open('$TABLES_JSON'))
299
+ print('yes' if any(t.get('name') == '$TEMPLATE_TABLE_NAME' for t in d.get('data', {}).get('tables', [])) else 'no')
300
+ except Exception:
301
+ print('no')
302
+ ")
303
+ rm -f "$TABLES_JSON"
304
+ if [ "$HAS_TABLE" = "yes" ]; then
305
+ if [ "$FORCE" = "1" ]; then
306
+ log_warn "检测到已有「${TEMPLATE_TABLE_NAME}」表,--force 将删除重建"
307
+ if ! _confirm " 确认删除旧表并重建?"; then
308
+ log_err "已取消"; exit 1
309
+ fi
310
+ lark-cli base +table-delete --base-token "$BASE_TOKEN" --table-id "$TEMPLATE_TABLE_NAME" --yes --as bot --format json >/dev/null 2>&1 || true
311
+ log_ok "旧表已删除"
312
+ else
313
+ log_err "该 Base 中已存在「${TEMPLATE_TABLE_NAME}」表——为避免误覆盖,脚本已中止。"
314
+ echo " 如需重建请加 --force(会删除旧表,请确认没有在用数据)。"
315
+ exit 1
316
+ fi
317
+ fi
318
+
319
+ CREATE_JSON=$(mktemp -t lark-create.XXXXXX.json)
320
+ if ! lark-cli base +table-create \
321
+ --base-token "$BASE_TOKEN" \
322
+ --name "$TEMPLATE_TABLE_NAME" \
323
+ --fields "$FIELDS_JSON" \
324
+ --as bot --format json > "$CREATE_JSON" 2>&1; then
325
+ log_err "建表失败:"
326
+ head -5 "$CREATE_JSON"
327
+ exit 1
328
+ fi
329
+ TABLE_ID=$(_json_get "$CREATE_JSON" "d.get('data', {}).get('table', {}).get('id') or ''")
330
+ rm -f "$CREATE_JSON"
331
+ if [ -z "$TABLE_ID" ]; then
332
+ log_err "建表成功但无法解析 Table ID——请检查上表是否存在"
333
+ exit 1
334
+ fi
335
+ log_ok "「${TEMPLATE_TABLE_NAME}」表已创建: ${TABLE_ID}(12 字段)"
336
+
337
+ # 视图(路径 B 需手工建;路径 A 由模板自带)
338
+ VIEW_JSON=$(mktemp -t lark-views.XXXXXX.json)
339
+ lark-cli base +view-list --base-token "$BASE_TOKEN" --table-id "$TABLE_ID" --as bot --format json > "$VIEW_JSON" 2>/dev/null || true
340
+ DEFAULT_VIEW_ID=$(_json_get "$VIEW_JSON" "d.get('data', {}).get('views', [{}])[0].get('id') or ''")
341
+ rm -f "$VIEW_JSON"
342
+ if [ -n "$DEFAULT_VIEW_ID" ]; then
343
+ lark-cli base +view-rename --base-token "$BASE_TOKEN" --table-id "$TABLE_ID" \
344
+ --view-id "$DEFAULT_VIEW_ID" --name "表格" --as bot --format json >/dev/null 2>&1 || \
345
+ log_warn "默认视图改名「表格」失败(可忽略)"
346
+ fi
347
+ VIEW2_JSON=$(mktemp -t lark-view2.XXXXXX.json)
348
+ lark-cli base +view-create --base-token "$BASE_TOKEN" --table-id "$TABLE_ID" \
349
+ --json '{"name":"待处理","type":"grid"}' --as bot --format json > "$VIEW2_JSON" 2>&1
350
+ if grep -q '"ok": true' "$VIEW2_JSON"; then
351
+ lark-cli base +view-set-filter --base-token "$BASE_TOKEN" --table-id "$TABLE_ID" \
352
+ --view-id "待处理" --json '{"logic":"and","conditions":[["就绪","==",true]]}' \
353
+ --as bot --format json >/dev/null 2>&1 && \
354
+ log_ok "视图「待处理」就绪(筛选 就绪=true)" || \
355
+ log_warn "「待处理」视图筛选设置失败,请手动设置"
356
+ else
357
+ log_warn "「待处理」视图创建失败(可稍后手动创建)"
358
+ fi
359
+ rm -f "$VIEW2_JSON"
360
+ VIEW3_JSON=$(mktemp -t lark-view3.XXXXXX.json)
361
+ lark-cli base +view-create --base-token "$BASE_TOKEN" --table-id "$TABLE_ID" \
362
+ --json '{"name":"运营填写","type":"grid"}' --as bot --format json > "$VIEW3_JSON" 2>&1
363
+ if grep -q '"ok": true' "$VIEW3_JSON"; then
364
+ VIEWLIST_JSON=$(mktemp -t lark-viewlist.XXXXXX.json)
365
+ lark-cli base +view-list --base-token "$BASE_TOKEN" --table-id "$TABLE_ID" \
366
+ --as bot --format json > "$VIEWLIST_JSON" 2>/dev/null || true
367
+ FULFILL_VIEW_ID=$(python3 -c "
368
+ import json
369
+ d = json.load(open('$VIEWLIST_JSON'))
370
+ vid = ''
371
+ for v in d.get('data', {}).get('views', []):
372
+ if isinstance(v, dict) and v.get('name') == '运营填写':
373
+ vid = v.get('id') or ''
374
+ break
375
+ print(vid)
376
+ " 2>/dev/null || true)
377
+ rm -f "$VIEWLIST_JSON"
378
+ if [ -n "$FULFILL_VIEW_ID" ]; then
379
+ lark-cli base +view-set-visible-fields --base-token "$BASE_TOKEN" --table-id "$TABLE_ID" \
380
+ --view-id "$FULFILL_VIEW_ID" \
381
+ --json '{"visible_fields":["店铺名称","SKU","品名","数量","箱数"]}' \
382
+ --as bot --format json >/dev/null 2>&1 && \
383
+ log_ok "视图「运营填写」就绪(仅运营 5 字段)" || \
384
+ log_warn "「运营填写」视图可见字段设置失败,请手动设置"
385
+ fi
386
+ else
387
+ log_warn "「运营填写」视图创建失败(可稍后手动创建)"
388
+ fi
389
+ rm -f "$VIEW3_JSON"
390
+ fi
391
+
392
+ # ── 3. 验证闭环:回读字段与模板 schema 对比 ─────────────
393
+ echo ""
394
+ echo "════════════════════════════════════════════════"
395
+ echo " 🔍 验证闭环:回读字段清单与模板 schema 对比"
396
+ echo "════════════════════════════════════════════════"
397
+ # 期望 schema(与生产模板实测一致;创建时间模板为 datetime)
398
+ FIELDS_READ=$(mktemp -t lark-fields-read.XXXXXX.json)
399
+ lark-cli base +field-list --base-token "$BASE_TOKEN" --table-id "$TABLE_ID" --as bot --format json > "$FIELDS_READ" 2>/dev/null || true
400
+ # 复制后时延:字段清单为空时重试一次
401
+ if ! grep -q '"fields"' "$FIELDS_READ" 2>/dev/null; then
402
+ sleep 2
403
+ lark-cli base +field-list --base-token "$BASE_TOKEN" --table-id "$TABLE_ID" --as bot --format json > "$FIELDS_READ" 2>/dev/null || true
404
+ fi
405
+ VERIFY=$(python3 -c "
406
+ import json
407
+ d = json.load(open('$FIELDS_READ'))
408
+ fields = {f['name']: f for f in d.get('data', {}).get('fields', [])}
409
+ expect = {
410
+ 'SKU': 'text', '当前步骤': 'text',
411
+ '箱数': 'number', '状态': 'select',
412
+ '创建时间': 'datetime', '货件号': 'text',
413
+ '店铺名称': 'select', '就绪': 'checkbox',
414
+ '品名': 'text', '箱唛': 'attachment',
415
+ '数量': 'number', '产品标签': 'attachment',
416
+ }
417
+ diffs = []
418
+ for n in expect:
419
+ if n not in fields:
420
+ diffs.append('缺字段: ' + n)
421
+ elif fields[n].get('type') != expect[n]:
422
+ diffs.append('字段「%s」类型不符: 期望 %s, 实际 %s' % (n, expect[n], fields[n].get('type')))
423
+ # select 字段至少 1 个选项(选项以模板为准,不强制精确匹配)
424
+ for n in ('状态', '店铺名称'):
425
+ if n in fields and fields[n].get('type') == 'select' and not fields[n].get('options'):
426
+ diffs.append('字段「%s」无 select 选项' % n)
427
+ print('OK' if not diffs else '\n'.join(diffs))
428
+ ")
429
+ rm -f "$FIELDS_READ"
430
+ if [ "$VERIFY" = "OK" ]; then
431
+ log_ok "字段验证通过:12/12 字段名、类型与模板完全一致"
432
+ else
433
+ log_warn "字段验证发现差异:"
434
+ echo "$VERIFY" | sed 's/^/ /'
435
+ log_warn "请人工检查上表字段是否需要修正"
436
+ fi
437
+
438
+ # ── 4. 测试记录:写入 1 条 → 确认 → 删除 → 确认清理 ────
439
+ if [ "$SKIP_TEST" = "1" ]; then
440
+ log_warn "已跳过测试记录写入(--skip-test)"
441
+ else
442
+ echo ""
443
+ echo "════════════════════════════════════════════════"
444
+ echo " 🧪 测试纪律:写入 1 条测试记录并清理"
445
+ echo "════════════════════════════════════════════════"
446
+ TEST_JSON=$(mktemp -t lark-test.XXXXXX.json)
447
+ lark-cli base +record-batch-create \
448
+ --base-token "$BASE_TOKEN" --table-id "$TABLE_ID" \
449
+ --json '{"fields":["SKU","品名","货件号","状态"],"rows":[["TEST-验证","测试",null,"Pending"]]}' \
450
+ --as bot --format json > "$TEST_JSON" 2>&1
451
+ TEST_REC_ID=$(_json_get "$TEST_JSON" "d.get('data', {}).get('record_id_list', [''])[0] or ''")
452
+ rm -f "$TEST_JSON"
453
+ if [ -z "$TEST_REC_ID" ]; then
454
+ log_err "测试记录写入失败——请检查字段配置与 bot 权限(bitable:app)"
455
+ exit 1
456
+ fi
457
+ log_ok "测试记录已写入: ${TEST_REC_ID}(SKU=TEST-验证,品名=测试,货件号留空)"
458
+
459
+ sleep 2
460
+ READ_TEST=$(mktemp -t lark-test-read.XXXXXX.json)
461
+ lark-cli base +record-list \
462
+ --base-token "$BASE_TOKEN" --table-id "$TABLE_ID" \
463
+ --filter-json '{"logic":"and","conditions":[["SKU","==","TEST-验证"]]}' \
464
+ --as bot --format json --limit 5 > "$READ_TEST" 2>/dev/null || true
465
+ TEST_FOUND=$(python3 -c "
466
+ import json
467
+ try:
468
+ d = json.load(open('$READ_TEST'))
469
+ print('yes' if d.get('data', {}).get('data') else 'no')
470
+ except Exception:
471
+ print('no')
472
+ ")
473
+ rm -f "$READ_TEST"
474
+ if [ "$TEST_FOUND" != "yes" ]; then
475
+ log_warn "回读测试记录未找到(可能有时延)——继续尝试删除"
476
+ else
477
+ log_ok "回读确认:测试记录可读可写"
478
+ fi
479
+
480
+ lark-cli base +record-delete \
481
+ --base-token "$BASE_TOKEN" --table-id "$TABLE_ID" \
482
+ --record-id "$TEST_REC_ID" --yes \
483
+ --as bot --format json >/dev/null 2>&1 || log_warn "测试记录删除请求失败,请手动删除 rec: ${TEST_REC_ID}"
484
+ sleep 3
485
+ CONFIRM_EMPTY=$(mktemp -t lark-test-empty.XXXXXX.json)
486
+ lark-cli base +record-list \
487
+ --base-token "$BASE_TOKEN" --table-id "$TABLE_ID" \
488
+ --filter-json '{"logic":"and","conditions":[["SKU","==","TEST-验证"]]}' \
489
+ --as bot --format json --limit 5 > "$CONFIRM_EMPTY" 2>/dev/null || true
490
+ EMPTY=$(python3 -c "
491
+ import json
492
+ try:
493
+ d = json.load(open('$CONFIRM_EMPTY'))
494
+ rows = d.get('data', {}).get('data', [])
495
+ print('clean' if not rows else 'left:' + str(len(rows)))
496
+ except Exception:
497
+ print('unknown')
498
+ ")
499
+ rm -f "$CONFIRM_EMPTY"
500
+ if [ "$EMPTY" = "clean" ]; then
501
+ log_ok "测试记录已删除,表内无 TEST-验证 残留"
502
+ else
503
+ log_warn "测试记录清理未确认(${EMPTY})——请手动检查并清理"
504
+ fi
505
+ fi
506
+
507
+ # ── 5. 输出 BASE_TOKEN/TABLE_ID 写入 fulfillment.env ────
508
+ echo ""
509
+ echo "════════════════════════════════════════════════"
510
+ echo " 💾 写入配置: ${ENV_FILE}"
511
+ echo "════════════════════════════════════════════════"
512
+ mkdir -p "$(dirname "$ENV_FILE")"
513
+ [ -f "$ENV_FILE" ] || touch "$ENV_FILE"
514
+
515
+ # 安全追加:只更新/追加目标键,绝不触碰其他键(含已有 FEISHU_* 等配置)
516
+ update_env_key() {
517
+ local key="$1" val="$2" file="$3"
518
+ if grep -qE "^${key}=" "$file"; then
519
+ if [ "$(uname -s)" = "Darwin" ]; then
520
+ sed -i '' "s|^${key}=.*|${key}=${val}|" "$file"
521
+ else
522
+ sed -i "s|^${key}=.*|${key}=${val}|" "$file"
523
+ fi
524
+ else
525
+ printf '%s=%s\n' "$key" "$val" >> "$file"
526
+ fi
527
+ }
528
+ update_env_key "BASE_TOKEN" "$BASE_TOKEN" "$ENV_FILE"
529
+ update_env_key "TABLE_ID" "$TABLE_ID" "$ENV_FILE"
530
+ # 兼容 orchestrator 生态键名(FEISHU_BASE_TOKEN / FEISHU_TABLE_ID 同值)
531
+ update_env_key "FEISHU_BASE_TOKEN" "$BASE_TOKEN" "$ENV_FILE"
532
+ update_env_key "FEISHU_TABLE_ID" "$TABLE_ID" "$ENV_FILE"
533
+ if [ -n "${OWNER_EMAIL:-}" ]; then
534
+ update_env_key "FEISHU_OWNER_EMAIL" "$OWNER_EMAIL" "$ENV_FILE"
535
+ fi
536
+ if [ -n "${OWNER_OPENID:-}" ]; then
537
+ update_env_key "FEISHU_OWNER_OPENID" "$OWNER_OPENID" "$ENV_FILE"
538
+ fi
539
+ log_ok "已写入 BASE_TOKEN / TABLE_ID(及 FEISHU_BASE_TOKEN / FEISHU_TABLE_ID 生态别名)"
540
+ [ -n "${OWNER_EMAIL:-}" ] && log_ok "已写入 FEISHU_OWNER_EMAIL"
541
+ [ -n "${OWNER_OPENID:-}" ] && log_ok "已写入 FEISHU_OWNER_OPENID"
542
+
543
+ BASE_URL_FULL="https://${DOMAIN}/base/${BASE_TOKEN}"
544
+
545
+ echo ""
546
+ echo "════════════════════════════════════════════════"
547
+ echo " 🎉 全部完成!"
548
+ echo "════════════════════════════════════════════════"
549
+ echo " Base: ${BASE_URL_FULL}"
550
+ echo " 表: ${TEMPLATE_TABLE_NAME}(${TABLE_ID})"
551
+ echo " 字段: 12 个(模板复制,已验证一致)"
552
+ echo " 视图: 表格 · 待处理(筛选 就绪=true)· 运营填写(仅运营 5 字段)"
553
+ echo " 权限: 企业内链接可编辑(tenant_editable)"
554
+ echo " 配置: ${ENV_FILE}"
555
+ echo ""
556
+ echo " 使用方式:在表格中新增记录 → 勾选「就绪」→ 编排器自动捡取执行"
557
+ echo " 提示:历史记录开关复制不继承(模板开→副本关),需要时由管理员在"
558
+ echo " 副本「··· → 历史记录」手动开启(BOT/管理员可管理权限可开)"
559
+
560
+ # ── 6. 机器可读输出(--json)───────────────────────────
561
+ if [ "$JSON_OUT" = "1" ]; then
562
+ python3 -c "
563
+ import json
564
+ print('RESULT_JSON: ' + json.dumps({
565
+ 'ok': True,
566
+ 'base_token': '$BASE_TOKEN',
567
+ 'table_id': '$TABLE_ID',
568
+ 'base_url': '$BASE_URL_FULL',
569
+ 'base_name': '$BASE_NAME',
570
+ 'table_name': '$TEMPLATE_TABLE_NAME',
571
+ 'env_file': '$ENV_FILE',
572
+ 'owner_email': '${OWNER_EMAIL:-}',
573
+ 'owner_openid': '${OWNER_OPENID:-}',
574
+ }, ensure_ascii=False))
575
+ "
576
+ fi
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env bash
2
+ . "$(dirname "$0")/lib/argent-datadir.sh" # 0.7.0 W8/S1:数据根唯一判据
3
+ # 每日 provider 装配巡检(2026-09-29;2026-10-02 口径更新 = 组合声明的 provider 有没有装上)。
4
+ # 文件名保留 billing-mode-*:LaunchAgent `com.whyshu.billing-mode-check` 指的就是这个路径。
5
+ # 由 LaunchAgent com.whyshu.billing-mode-check 调用(每天 09:20)。
6
+ set -uo pipefail
7
+ REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
8
+ LOG="$ARGENT_DATA_DIR_RESOLVED/logs/billing-mode.log"
9
+ mkdir -p "$(dirname "$LOG")"
10
+ OUT="$(bash "$REPO/scripts/check-billing-mode.sh" 2>&1)"; CODE=$? # 只检查:组合声明了的 provider 是否都装上了(不再改写任何 provider 配置)
11
+ { echo "----- $(date '+%F %T') exit=$CODE"; echo "$OUT"; } >> "$LOG"
12
+ if [ $CODE -ne 0 ]; then logger -t billing-mode "provider 装配异常 exit=${CODE}(详见 ${LOG})"; fi
13
+ exit 0