@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.
- package/MANIFEST.json +307 -0
- package/engine/VERSION +1 -0
- package/engine/agents/catalog.json +454 -0
- package/engine/configs/_aliases.proposed.json +651 -0
- package/engine/configs/_migration-plan.proposed.json +899 -0
- package/engine/configs/account.json +272 -0
- package/engine/configs/advanced.json +205 -0
- package/engine/configs/host.json +149 -0
- package/engine/configs/hr.json +27 -0
- package/engine/configs/notify.json +264 -0
- package/engine/core/cli/argent.mjs +277 -0
- package/engine/core/contracts/argent.contracts.json +1065 -0
- package/engine/core/contracts/verbs.schema.json +2539 -0
- package/engine/core/lib/argent-datadir.mjs +223 -0
- package/engine/core/lib/audit.mjs +187 -0
- package/engine/core/lib/claim.mjs +258 -0
- package/engine/core/lib/config-catalog.mjs +1172 -0
- package/engine/core/lib/doctor-customer.mjs +577 -0
- package/engine/core/lib/flow-list.mjs +138 -0
- package/engine/core/lib/flow-registry.mjs +48 -0
- package/engine/core/lib/init.mjs +247 -0
- package/engine/core/lib/ledger.mjs +124 -0
- package/engine/core/lib/license-activate.mjs +813 -0
- package/engine/core/lib/license-device.mjs +314 -0
- package/engine/core/lib/license-file.mjs +349 -0
- package/engine/core/lib/license-guard.mjs +123 -0
- package/engine/core/lib/license-ops.mjs +1645 -0
- package/engine/core/lib/license-verdict.mjs +133 -0
- package/engine/core/lib/license.mjs +577 -0
- package/engine/core/lib/notify/dedup.mjs +101 -0
- package/engine/core/lib/notify/feishu.mjs +38 -0
- package/engine/core/lib/notify/index.mjs +95 -0
- package/engine/core/lib/notify/verb.mjs +327 -0
- package/engine/core/lib/notify/webhook.mjs +135 -0
- package/engine/core/lib/notify/wecom.mjs +36 -0
- package/engine/core/lib/python.mjs +145 -0
- package/engine/core/lib/sop.mjs +116 -0
- package/engine/core/lib/versions.mjs +205 -0
- package/engine/core/mcp/client.mjs +67 -0
- package/engine/core/mcp/http.mjs +138 -0
- package/engine/core/mcp/server.mjs +702 -0
- package/engine/scripts/_engine_rules_probe.py +15 -0
- package/engine/scripts/analyze-full-day.py +568 -0
- package/engine/scripts/archive/feishu-bridge.js +246 -0
- package/engine/scripts/argent-agents.mjs +527 -0
- package/engine/scripts/argent-capabilities.mjs +776 -0
- package/engine/scripts/argent-catalog.mjs +186 -0
- package/engine/scripts/argent-datadir.py +62 -0
- package/engine/scripts/argent-doctor.mjs +624 -0
- package/engine/scripts/argent-env-write.mjs +302 -0
- package/engine/scripts/argent-schedule.mjs +620 -0
- package/engine/scripts/argent-setup-check.mjs +369 -0
- package/engine/scripts/argent-upgrade.mjs +1046 -0
- package/engine/scripts/base-bootstrap.sh +575 -0
- package/engine/scripts/billing-mode-daily.sh +12 -0
- package/engine/scripts/build-engine-package.mjs +123 -0
- package/engine/scripts/capability-packs.lock.json +484 -0
- package/engine/scripts/capability_pack.py +1242 -0
- package/engine/scripts/check-1.0-criteria.mjs +355 -0
- package/engine/scripts/check-agent-catalog.mjs +141 -0
- package/engine/scripts/check-billing-mode.sh +377 -0
- package/engine/scripts/check-child-sessions.mjs +83 -0
- package/engine/scripts/check-config-catalog.mjs +677 -0
- package/engine/scripts/check-docs-drift.mjs +522 -0
- package/engine/scripts/check-dsh-web-expose.sh +98 -0
- package/engine/scripts/check-judgment-drift.mjs +403 -0
- package/engine/scripts/check-license.mjs +199 -0
- package/engine/scripts/check-model-auth.py +443 -0
- package/engine/scripts/check-pack-closure.mjs +661 -0
- package/engine/scripts/check-portable-symbols.mjs +116 -0
- package/engine/scripts/check-preset-landing.mjs +124 -0
- package/engine/scripts/check-production-home.mjs +602 -0
- package/engine/scripts/check-role-mapping.mjs +461 -0
- package/engine/scripts/check-sample-redaction.mjs +320 -0
- package/engine/scripts/check-skill-classification.mjs +188 -0
- package/engine/scripts/check-sop-consistency.mjs +431 -0
- package/engine/scripts/check-test-env-safety.mjs +627 -0
- package/engine/scripts/check-version-consistency.mjs +452 -0
- package/engine/scripts/ci-run.sh +558 -0
- package/engine/scripts/config-explain.mjs +278 -0
- package/engine/scripts/configure-provider.rb +29 -0
- package/engine/scripts/customer-config-migrate.mjs +179 -0
- package/engine/scripts/customer-preflight.py +892 -0
- package/engine/scripts/customer-readiness.sh +134 -0
- package/engine/scripts/daily-report-inbox.py +242 -0
- package/engine/scripts/daily-report-reconcile.mjs +312 -0
- package/engine/scripts/daily-report.mjs +1310 -0
- package/engine/scripts/daily-report.sh +46 -0
- package/engine/scripts/data/lip-product-dict.json +306 -0
- package/engine/scripts/deliver-customer.mjs +932 -0
- package/engine/scripts/delivery-faces.txt +31 -0
- package/engine/scripts/desktop-trial.sh +146 -0
- package/engine/scripts/dev-window.sh +260 -0
- package/engine/scripts/drill-clean-machine.sh +315 -0
- package/engine/scripts/dsh-api-client.mjs +215 -0
- package/engine/scripts/dsh-backup-scope.sh +83 -0
- package/engine/scripts/dsh-offline-pack.mjs +77 -0
- package/engine/scripts/dsh-overlay-pin.sh +87 -0
- package/engine/scripts/dsh-plane.mjs +153 -0
- package/engine/scripts/dsh-portforward.py +223 -0
- package/engine/scripts/dsh-preflight.mjs +179 -0
- package/engine/scripts/dsh-release-watch-daily.sh +19 -0
- package/engine/scripts/dsh-release-watch.mjs +458 -0
- package/engine/scripts/dsh-remote-check.sh +99 -0
- package/engine/scripts/dsh-restart.sh +179 -0
- package/engine/scripts/dsh-restore.sh +111 -0
- package/engine/scripts/dsh-scope-rewire.mjs +803 -0
- package/engine/scripts/dsh-snapshot.mjs +116 -0
- package/engine/scripts/dsh-upgrade-readiness.mjs +165 -0
- package/engine/scripts/dsh-upgrade.mjs +612 -0
- package/engine/scripts/dsh-url.sh +86 -0
- package/engine/scripts/dsh-web-launch.mjs +155 -0
- package/engine/scripts/ensure-store-windows.py +509 -0
- package/engine/scripts/entitlements.py +458 -0
- package/engine/scripts/env_probe.py +411 -0
- package/engine/scripts/feishu-card.mjs +252 -0
- package/engine/scripts/fix-skill-frontmatter.py +209 -0
- package/engine/scripts/flow-auto-retry.py +454 -0
- package/engine/scripts/flow-requirements.json +720 -0
- package/engine/scripts/flow-scaffold.py +275 -0
- package/engine/scripts/flow-timers-plist.sh +86 -0
- package/engine/scripts/flow-timers.sh +182 -0
- package/engine/scripts/flow-trigger-wake.mjs +284 -0
- package/engine/scripts/flow-trigger.sh +571 -0
- package/engine/scripts/flow_billing.py +354 -0
- package/engine/scripts/flow_capability_stats.py +314 -0
- package/engine/scripts/flow_case.py +194 -0
- package/engine/scripts/flow_claim.py +497 -0
- package/engine/scripts/flow_config.py +1024 -0
- package/engine/scripts/flow_failure.py +588 -0
- package/engine/scripts/flow_learn.py +105 -0
- package/engine/scripts/flow_ledger.py +235 -0
- package/engine/scripts/flow_policy.py +238 -0
- package/engine/scripts/flow_preflight.py +339 -0
- package/engine/scripts/flow_registry.py +341 -0
- package/engine/scripts/flow_retry.py +304 -0
- package/engine/scripts/flow_return_to_ops.py +191 -0
- package/engine/scripts/flow_source.py +315 -0
- package/engine/scripts/flow_sources/__init__.py +53 -0
- package/engine/scripts/flow_sources/cases_json.py +106 -0
- package/engine/scripts/flow_sources/common.py +428 -0
- package/engine/scripts/flow_sources/feishu_base.py +273 -0
- package/engine/scripts/flow_stale.py +185 -0
- package/engine/scripts/flow_status_reconcile.py +344 -0
- package/engine/scripts/flow_triage.py +849 -0
- package/engine/scripts/flow_write_verify.py +496 -0
- package/engine/scripts/fulfillment.js +586 -0
- package/engine/scripts/gen-agent-bundles.mjs +276 -0
- package/engine/scripts/gen-preset-rows.mjs +259 -0
- package/engine/scripts/init-ml.sh +2275 -0
- package/engine/scripts/install-internal-role.sh +190 -0
- package/engine/scripts/install-license.mjs +641 -0
- package/engine/scripts/install-one-shot.mjs +665 -0
- package/engine/scripts/integration_contract.py +220 -0
- package/engine/scripts/integrations/wenyao/adapter.py +98 -0
- package/engine/scripts/integrations/xzh/adapter.py +75 -0
- package/engine/scripts/invoice-mapping.example.json +40 -0
- package/engine/scripts/invoice-table.sh +194 -0
- package/engine/scripts/invoice_carrier_notice.py +279 -0
- package/engine/scripts/invoice_fail_closeout.py +297 -0
- package/engine/scripts/invoice_lip_runner.py +1508 -0
- package/engine/scripts/invoice_lip_runner.py.bak-20260922-1710-freready +1090 -0
- package/engine/scripts/invoice_ready_audit.py +191 -0
- package/engine/scripts/invoice_runner.py +675 -0
- package/engine/scripts/invoice_stageb.py +516 -0
- package/engine/scripts/launchd/com.whyshu.argent-bridge.plist.example +42 -0
- package/engine/scripts/launchd/com.whyshu.fulfillment-poll.plist.example +29 -0
- package/engine/scripts/lease.py +377 -0
- package/engine/scripts/lib/agent-install.mjs +649 -0
- package/engine/scripts/lib/argent-datadir.mjs +16 -0
- package/engine/scripts/lib/argent_datadir.py +262 -0
- package/engine/scripts/lib/argent_filelock.py +507 -0
- package/engine/scripts/lib/bootcheck-wiring.mjs +510 -0
- package/engine/scripts/lib/cdp_ports.py +197 -0
- package/engine/scripts/lib/customer-env.mjs +102 -0
- package/engine/scripts/lib/daily-report-core.mjs +517 -0
- package/engine/scripts/lib/dep-declaration.mjs +81 -0
- package/engine/scripts/lib/deps-migrate.mjs +310 -0
- package/engine/scripts/lib/dsh-host-resolve.mjs +109 -0
- package/engine/scripts/lib/dsh-scope.mjs +500 -0
- package/engine/scripts/lib/dsh-snapshot-path.mjs +35 -0
- package/engine/scripts/lib/dsh-versions.mjs +96 -0
- package/engine/scripts/lib/dsh-web-probe.mjs +214 -0
- package/engine/scripts/lib/is-direct-run.mjs +61 -0
- package/engine/scripts/lib/patch-compose.mjs +241 -0
- package/engine/scripts/lib/patch-target.mjs +35 -0
- package/engine/scripts/lib/plugin-lifecycle.mjs +128 -0
- package/engine/scripts/lib/plugin-packages.mjs +332 -0
- package/engine/scripts/lib/preset-compat.mjs +127 -0
- package/engine/scripts/lib/preset-install.mjs +575 -0
- package/engine/scripts/lib/preset-mechanism.mjs +56 -0
- package/engine/scripts/lib/preset-sync.mjs +59 -0
- package/engine/scripts/lib/profile-retire.mjs +97 -0
- package/engine/scripts/lib/python-runtime.mjs +190 -0
- package/engine/scripts/lib/registry.mjs +72 -0
- package/engine/scripts/lib/repo-root.sh +56 -0
- package/engine/scripts/lib/schedule-mechanism.mjs +659 -0
- package/engine/scripts/lib/schedule-probe.mjs +835 -0
- package/engine/scripts/lib/scope-pointer.mjs +164 -0
- package/engine/scripts/lib/settings-panels.mjs +816 -0
- package/engine/scripts/lib/stdio_utf8.py +86 -0
- package/engine/scripts/lib/wake-auth.mjs +392 -0
- package/engine/scripts/lib/webdriver_ipc.py +264 -0
- package/engine/scripts/lib/zstd-frames.mjs +104 -0
- package/engine/scripts/license-e2e-drill.mjs +426 -0
- package/engine/scripts/license-gate.mjs +245 -0
- package/engine/scripts/lip_backlog.py +171 -0
- package/engine/scripts/lip_table.py +185 -0
- package/engine/scripts/local-usage.mjs +214 -0
- package/engine/scripts/migrate-providers.mjs +127 -0
- package/engine/scripts/migrate-skills.sh +65 -0
- package/engine/scripts/ml-oauth-setup.mjs +550 -0
- package/engine/scripts/ml-store-ids.json +26 -0
- package/engine/scripts/ml_artifact_attribution.py +333 -0
- package/engine/scripts/ml_capacity_probe.py +1158 -0
- package/engine/scripts/ml_hub_status.py +1556 -0
- package/engine/scripts/ml_schema_check.py +115 -0
- package/engine/scripts/ml_store_ids.py +139 -0
- package/engine/scripts/npm-publish-argent.mjs +499 -0
- package/engine/scripts/npm-publish-argent.sh +20 -0
- package/engine/scripts/orchestrator.py +13811 -0
- package/engine/scripts/pack-plugins.mjs +140 -0
- package/engine/scripts/patches/dsh-llm-deepseek--transport-diagnostics.patch +297 -0
- package/engine/scripts/patches/dsh-session--append-message-shape.patch +15 -0
- package/engine/scripts/patches/dsh-session--tool-result-block-017.patch +28 -0
- package/engine/scripts/patches/dsh-session-format-v0-to-v1--permission-preset-origin.patch +11 -0
- package/engine/scripts/patches/dsh-session-format-v3-to-v4--turn-outside-replace.patch +20 -0
- package/engine/scripts/patches/dsh-session-persistence-jsonl--worker-bundled-migrators.patch +39 -0
- package/engine/scripts/patches/dsh-tools--render-return-shape.patch +50 -0
- package/engine/scripts/patches/verify-bundled-migrators.mjs +79 -0
- package/engine/scripts/patches/verify-hardening.mjs +167 -0
- package/engine/scripts/patches/verify-session-migration.mjs +149 -0
- package/engine/scripts/patches/verify-transport-diagnostics.mjs +227 -0
- package/engine/scripts/plan-role-rename.mjs +125 -0
- package/engine/scripts/plugin-bootcheck.mjs +451 -0
- package/engine/scripts/plugin-composition.json +15 -0
- package/engine/scripts/poc-mcp-host.mjs +455 -0
- package/engine/scripts/poll-fulfillment.sh +293 -0
- package/engine/scripts/poll-invoice.sh +74 -0
- package/engine/scripts/profile-doctor.mjs +686 -0
- package/engine/scripts/provider-select.sh +70 -0
- package/engine/scripts/provider-switch.sh +146 -0
- package/engine/scripts/provider-sync-target.check.mjs +64 -0
- package/engine/scripts/python-runtime.sh +78 -0
- package/engine/scripts/query_runner.py +310 -0
- package/engine/scripts/release-argent.sh +574 -0
- package/engine/scripts/repair-unresolved-tools.mjs +178 -0
- package/engine/scripts/run-tests.sh +256 -0
- package/engine/scripts/self-sign-license.mjs +179 -0
- package/engine/scripts/session-health-scan.mjs +63 -0
- package/engine/scripts/session-repair-tool-result-content.mjs +181 -0
- package/engine/scripts/setup.sh +22 -0
- package/engine/scripts/skill-install.mjs +629 -0
- package/engine/scripts/sku_translate.py +148 -0
- package/engine/scripts/sync-plugins.sh +90 -0
- package/engine/scripts/sync-presets.sh +27 -0
- package/engine/scripts/sync-scripts.sh +445 -0
- package/engine/scripts/telemetry.py +873 -0
- package/engine/scripts/ui-copy-count.mjs +220 -0
- package/engine/scripts/usage-anchor.sh +136 -0
- package/engine/scripts/usage_report.py +531 -0
- package/engine/scripts/validate-preset-schema.mjs +208 -0
- package/engine/scripts/vertical-init.mjs +323 -0
- package/engine/scripts/vertical-lint.mjs +482 -0
- package/engine/scripts/wenyao-browser.sh +73 -0
- package/engine/scripts/wenyao-fixture-export.py +116 -0
- package/engine/scripts/wenyao-invoice-writeback.mjs +540 -0
- package/engine/scripts/wenyao-login.sh +34 -0
- package/engine/scripts/wenyao-template-map.json +292 -0
- package/engine/scripts/wenyao_attach.py +131 -0
- package/engine/scripts/wenyao_download_template.py +144 -0
- package/engine/scripts/wenyao_fill_template.py +568 -0
- package/engine/scripts/wenyao_login.py +145 -0
- package/engine/scripts/wenyao_portal.py +633 -0
- package/engine/scripts/wenyao_recon.py +230 -0
- package/engine/scripts/wenyao_run.py +503 -0
- package/engine/scripts/wenyao_shadow_diff.py +160 -0
- package/engine/scripts/wenyao_skill_contract.py +156 -0
- package/engine/scripts/wenyao_template_fetch.py +175 -0
- package/engine/scripts/win/dsh-web-autostart.ps1 +372 -0
- package/engine/scripts/ziniao-auth-probe.sh +268 -0
- package/engine/scripts/ziniao-keepalive.sh +216 -0
- package/engine/scripts/ziniao-post-upgrade-check.sh +120 -0
- package/engine/scripts/ziniao-windows.sh +153 -0
- package/engine/version.mjs +1 -0
- package/engine/verticals/README.md +103 -0
- package/engine/verticals/_engine-words.baseline.txt +237 -0
- package/engine/verticals/_engine-words.json +19 -0
- package/engine/verticals/mercadolibre/README.md +43 -0
- package/engine/verticals/mercadolibre/config.json +709 -0
- package/engine/verticals/mercadolibre/flows.json +706 -0
- package/engine/verticals/mercadolibre/manifest.json +538 -0
- package/engine/verticals/mercadolibre/migrate-machine-state.mjs +138 -0
- package/engine/verticals/mercadolibre/preflight.py +143 -0
- package/engine/verticals/mercadolibre/prompts/daily-report.failure.md +69 -0
- package/engine/verticals/mercadolibre/prompts/daily-report.md +47 -0
- package/engine/verticals/mercadolibre/prompts/daily-report.scheduled.md +79 -0
- package/engine/verticals/mercadolibre/prompts/full.failure.md +125 -0
- package/engine/verticals/mercadolibre/prompts/full.md +91 -0
- package/engine/verticals/mercadolibre/prompts/wenyao-invoice.failure.md +88 -0
- package/engine/verticals/mercadolibre/prompts/wenyao-invoice.md +64 -0
- package/engine/verticals/mercadolibre/prompts/xzh-invoice.failure.md +91 -0
- package/engine/verticals/mercadolibre/prompts/xzh-invoice.md +46 -0
- package/package.json +21 -4
- package/README.md +0 -3
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `argent flow claim` / `argent flow triage` 适配层(P1 首批,2026-10-03)
|
|
3
|
+
* —— 把被包脚本(`scripts/flow_claim.py` / `scripts/flow_triage.py`)的**退出码与输出**
|
|
4
|
+
* 翻译成 P0-A 的机器可判口径(A1 退出码 / A2 JSON / A3 dry-run)。
|
|
5
|
+
*
|
|
6
|
+
* ## 为什么必须有这一层(D4 裁定,2026-10-03)
|
|
7
|
+
* `scripts/flow_claim.py:14` 的 `3` 表示**无票可认领**,而 P0-A A1 把 `3` **唯一**留给"许可宽限放行"
|
|
8
|
+
* (`scripts/check-license.mjs:15-19` 与 `scripts/lease.py:15-21` 已是那个语义)。同一个码两个意思,
|
|
9
|
+
* 客户 agent 就没法用 `$?` 分支 —— 但**不能改脚本**(`scripts/flow-trigger.sh` 的 headless 分支
|
|
10
|
+
* 依赖它)⇒ 翻译放在这一层:
|
|
11
|
+
*
|
|
12
|
+
* | 脚本 `$?` | verb `code` | 条件 | 结论 |
|
|
13
|
+
* |---|---|---|---|
|
|
14
|
+
* | `0` | `0` | 有认领 | `ok:true, empty:false` |
|
|
15
|
+
* | `3` | **`0`** | 无票 | `ok:true, empty:true, reason:"no_ticket"`("没票要跑"不是错误) |
|
|
16
|
+
* | `2` | `1` | stderr 是 `triage 失败/超时` | **源读取失败 = 运行失败**(网络、飞书半开连接) |
|
|
17
|
+
* | `2` | `2` | 其余(未知流程/缺 env/参数) | `reason:"missing_declaration"` / `"usage_error"` |
|
|
18
|
+
* | 其它 | `1` | — | `reason:"internal_error"`;输出不可解析 ⇒ `"bad_output"` |
|
|
19
|
+
*
|
|
20
|
+
* ## A3 dry-run
|
|
21
|
+
* **默认即 dry-run**(真写要显式 `--apply`/`--confirm`);`--dry-run` 出现即恒 dry-run
|
|
22
|
+
* (调用方说了算 —— 能靠参数绕过判据就是红)。零副作用由 `scripts/flow_claim.py` 的 dry-run 分支保证,
|
|
23
|
+
* 判据 = 跑两次 dry-run 后数据目录逐字节不变(`scripts/tests/flow-claim-verb.test.mjs`)。
|
|
24
|
+
*
|
|
25
|
+
* 纪律:本文件是**薄适配层**——不复制认领/分诊的任何判据(幂等键、租约、并发、店铺闸门都在脚本里),
|
|
26
|
+
* 只做"参数搬运 + 退出码翻译 + 回显"。
|
|
27
|
+
*/
|
|
28
|
+
import { spawnSync } from 'node:child_process'
|
|
29
|
+
import { join } from 'node:path'
|
|
30
|
+
import { loadRegistry, resolveFlow } from './flow-registry.mjs'
|
|
31
|
+
|
|
32
|
+
/** 需要带值的参数(搬运)。 */
|
|
33
|
+
export const VALUE_FLAGS = ['--flow', '--max', '--lease-min', '--batch', '--per-ip', '--ledger', '--lock', '--cases-from-dir', '--limit']
|
|
34
|
+
/** 布尔参数(搬运)。 */
|
|
35
|
+
export const BOOL_FLAGS = ['--json', '--dry-run', '--no-regenerate']
|
|
36
|
+
/** 本层**自己消费**的参数(不往脚本传)。 */
|
|
37
|
+
export const CONSUMED_FLAGS = ['--apply', '--confirm', '--yes', '--plan-only']
|
|
38
|
+
/** 显式确权(真写)参数。 */
|
|
39
|
+
export const CONFIRM_FLAGS = ['--apply', '--confirm', '--yes']
|
|
40
|
+
|
|
41
|
+
/** 分诊脚本支持的参数子集(`--plan-only` 走这条路)。 */
|
|
42
|
+
const TRIAGE_FLAGS = ['--flow', '--cases-from-dir', '--ledger', '--limit', '--no-regenerate', '--json']
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* 解析 argv → 调用计划(纯函数)。
|
|
46
|
+
* @returns {{ok:true, route:'claim'|'triage', childArgs:string[], echo:object, dryRun:boolean, json:boolean}
|
|
47
|
+
* | {ok:false, code:number, reason:string, error:string}}
|
|
48
|
+
*/
|
|
49
|
+
export function buildInvocation(argv = []) {
|
|
50
|
+
const args = [...argv]
|
|
51
|
+
const has = (f) => args.includes(f)
|
|
52
|
+
const valOf = (f) => { const i = args.indexOf(f); return i >= 0 ? args[i + 1] : undefined }
|
|
53
|
+
|
|
54
|
+
const flow = valOf('--flow')
|
|
55
|
+
if (!flow) return { ok: false, code: 2, reason: 'usage_error', error: '缺必填参数 --flow(用法:argent flow claim --flow <流程> [--max N] [--cases-from-dir <目录>] [--apply])' }
|
|
56
|
+
|
|
57
|
+
// 单值参数必须带值(否则会把下一个 `--xxx` 当值吃进去,错误会推迟到脚本里才暴露)
|
|
58
|
+
for (const f of VALUE_FLAGS) {
|
|
59
|
+
const i = args.indexOf(f)
|
|
60
|
+
if (i >= 0 && (i + 1 >= args.length || String(args[i + 1]).startsWith('--'))) {
|
|
61
|
+
return { ok: false, code: 2, reason: 'usage_error', error: `参数 ${f} 缺值` }
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const json = has('--json')
|
|
65
|
+
const planOnly = has('--plan-only')
|
|
66
|
+
const dryFlag = has('--dry-run')
|
|
67
|
+
const confirmed = CONFIRM_FLAGS.some((f) => has(f))
|
|
68
|
+
const dryRun = dryFlag || !confirmed // A3:默认 dry-run;--dry-run 恒优先(fail-safe)
|
|
69
|
+
const route = planOnly ? 'triage' : 'claim'
|
|
70
|
+
|
|
71
|
+
const keep = new Set(route === 'triage' ? TRIAGE_FLAGS : [...VALUE_FLAGS, ...BOOL_FLAGS])
|
|
72
|
+
const childArgs = []
|
|
73
|
+
for (let i = 0; i < args.length; i++) {
|
|
74
|
+
const t = args[i]
|
|
75
|
+
if (CONSUMED_FLAGS.includes(t)) continue
|
|
76
|
+
if (!keep.has(t)) {
|
|
77
|
+
if (t.startsWith('--')) childArgs.push(t) // 未知参数照传:脚本的 argparse 才是它自己参数的权威(exit 2)
|
|
78
|
+
continue
|
|
79
|
+
}
|
|
80
|
+
childArgs.push(t)
|
|
81
|
+
if (VALUE_FLAGS.includes(t)) { childArgs.push(args[i + 1]); i++ }
|
|
82
|
+
}
|
|
83
|
+
if (route === 'claim' && dryRun) childArgs.push('--dry-run')
|
|
84
|
+
|
|
85
|
+
const echo = {
|
|
86
|
+
flow,
|
|
87
|
+
max: valOf('--max') !== undefined ? Number(valOf('--max')) : null,
|
|
88
|
+
leaseMin: valOf('--lease-min') !== undefined ? Number(valOf('--lease-min')) : null,
|
|
89
|
+
batch: valOf('--batch') !== undefined ? Number(valOf('--batch')) : null,
|
|
90
|
+
perIp: valOf('--per-ip') !== undefined ? Number(valOf('--per-ip')) : null,
|
|
91
|
+
casesFromDir: valOf('--cases-from-dir') ?? null,
|
|
92
|
+
limit: valOf('--limit') !== undefined ? Number(valOf('--limit')) : null,
|
|
93
|
+
ledger: valOf('--ledger') ?? null,
|
|
94
|
+
lock: valOf('--lock') ?? null,
|
|
95
|
+
dryRun,
|
|
96
|
+
planOnly,
|
|
97
|
+
json,
|
|
98
|
+
}
|
|
99
|
+
return { ok: true, route, childArgs, echo, dryRun, json }
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** `--flow` 的实际生效值:规范 id + 局部 id 前缀(回显用;解析不了就如实退化为字面值)。 */
|
|
103
|
+
export function flowEcho(flow, { repo, py, pyFailure = null } = {}) {
|
|
104
|
+
if (pyFailure || !py) {
|
|
105
|
+
return { flow, flowPrefix: null, flowKnown: false, note: '解释器不可用 ⇒ 未做注册表解析,flow 为字面值' }
|
|
106
|
+
}
|
|
107
|
+
const reg = loadRegistry({ repo, py })
|
|
108
|
+
if (!reg.ok) {
|
|
109
|
+
return { flow, flowPrefix: null, flowKnown: false, note: `注册表读不到(${reg.reason})⇒ flow 为字面值` }
|
|
110
|
+
}
|
|
111
|
+
const r = resolveFlow({ input: flow, doc: reg.doc })
|
|
112
|
+
return { flow: r.canonical, flowPrefix: r.local, flowKnown: r.known }
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** 解析脚本 stdout 的 JSON(脚本的 `--json` 输出;失败返回 null)。 */
|
|
116
|
+
export function parseChildJson(stdout) {
|
|
117
|
+
const s = String(stdout || '')
|
|
118
|
+
const i = s.indexOf('{')
|
|
119
|
+
if (i < 0) return null
|
|
120
|
+
try { return JSON.parse(s.slice(i)) } catch { return null }
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* 退出码翻译(A1;唯一实现,claim/triage 共用)。
|
|
125
|
+
* @param {{status:number|null, stdout:string, stderr:string, signal?:string}} child
|
|
126
|
+
*/
|
|
127
|
+
export function classifyChild(child) {
|
|
128
|
+
const status = child.status === null || child.status === undefined ? 1 : Number(child.status)
|
|
129
|
+
const stderr = String(child.stderr || '')
|
|
130
|
+
if (status === 0 || status === 3) return { ok: true, code: 0, scriptStatus: status }
|
|
131
|
+
if (status === 2) {
|
|
132
|
+
// ⚠️ 脚本把"源读取失败/超时"也归在 2 里 —— 按 A1 它属**运行失败**(1),不是用法错误
|
|
133
|
+
if (/triage\s*(失败|超时)/.test(stderr)) return { ok: false, code: 1, reason: 'source_failed', error: stderr.trim().slice(0, 400) }
|
|
134
|
+
if (/flow_source 失败/.test(stderr)) return { ok: false, code: 1, reason: 'source_failed', error: stderr.trim().slice(0, 400) }
|
|
135
|
+
if (/未知流程/.test(stderr)) return { ok: false, code: 2, reason: 'missing_declaration', error: stderr.trim().slice(0, 400) }
|
|
136
|
+
return { ok: false, code: 2, reason: 'usage_error', error: stderr.trim().slice(0, 400) }
|
|
137
|
+
}
|
|
138
|
+
return { ok: false, code: 1, reason: 'internal_error', error: (stderr.trim() || `被包脚本退出码 ${status}`).slice(0, 400) }
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** 认领结果 → A2 JSON(纯函数)。 */
|
|
142
|
+
export function shapeClaim(child, { echo, registryEcho }) {
|
|
143
|
+
// ⚠️ base 里**不含** max/leaseMin:那两个要由"命令行给的 ⇒ 脚本回显的生效值"决定(见下方 pick),
|
|
144
|
+
// 先铺 base 再覆盖会让生效值被 echo 的 null 盖掉(实测踩过:max 恒 null)。
|
|
145
|
+
const base = { ...registryEcho, dryRun: echo.dryRun, casesFromDir: echo.casesFromDir }
|
|
146
|
+
const cls = classifyChild(child)
|
|
147
|
+
if (!cls.ok) return { ok: false, empty: false, code: cls.code, reason: cls.reason, error: cls.error, ...base }
|
|
148
|
+
const parsed = parseChildJson(child.stdout)
|
|
149
|
+
if (!parsed) {
|
|
150
|
+
return { ok: false, empty: false, code: 1, reason: 'bad_output',
|
|
151
|
+
error: `被包脚本输出不可解析:${String(child.stdout || child.stderr || '').trim().slice(0, 300)}`, ...base }
|
|
152
|
+
}
|
|
153
|
+
const claimed = Array.isArray(parsed.claimed) ? parsed.claimed.map(String) : []
|
|
154
|
+
const empty = claimed.length === 0
|
|
155
|
+
const pick = (cliVal, childVal) => (cliVal !== null && cliVal !== undefined ? cliVal : (childVal ?? null))
|
|
156
|
+
return {
|
|
157
|
+
ok: true,
|
|
158
|
+
empty,
|
|
159
|
+
code: 0,
|
|
160
|
+
reason: empty ? 'no_ticket' : null,
|
|
161
|
+
claimed,
|
|
162
|
+
count: claimed.length,
|
|
163
|
+
// 实际生效值:命令行给的优先,否则取**脚本回显的生效值**(可能来自流程配置)
|
|
164
|
+
max: pick(echo.max, parsed.max),
|
|
165
|
+
leaseMin: pick(echo.leaseMin, parsed.leaseMin),
|
|
166
|
+
batch: pick(echo.batch, parsed.batch),
|
|
167
|
+
perIp: pick(echo.perIp, parsed.perIp),
|
|
168
|
+
ledger: echo.ledger || parsed.ledger || null,
|
|
169
|
+
lock: echo.lock || parsed.lock || null,
|
|
170
|
+
planOnly: echo.planOnly,
|
|
171
|
+
...base,
|
|
172
|
+
...(empty && parsed.reason ? { note: String(parsed.reason).slice(0, 500) } : {}),
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/** 分诊结果 → A2 JSON(纯函数)。 */
|
|
177
|
+
export function shapeTriage(child, { echo, registryEcho }) {
|
|
178
|
+
const base = { ...registryEcho, limit: echo.limit, casesFromDir: echo.casesFromDir }
|
|
179
|
+
const cls = classifyChild(child)
|
|
180
|
+
if (!cls.ok) return { ok: false, empty: false, code: cls.code, reason: cls.reason, error: cls.error, ...base }
|
|
181
|
+
const parsed = parseChildJson(child.stdout)
|
|
182
|
+
if (!parsed) {
|
|
183
|
+
return { ok: false, empty: false, code: 1, reason: 'bad_output',
|
|
184
|
+
error: `被包脚本输出不可解析:${String(child.stdout || child.stderr || '').trim().slice(0, 300)}`, ...base }
|
|
185
|
+
}
|
|
186
|
+
const plan = parsed.plan || {}
|
|
187
|
+
const ids = (arr) => (arr || []).map((x) => String((x && x.caseId) || '')).filter(Boolean)
|
|
188
|
+
const toDispatch = ids(plan.to_dispatch)
|
|
189
|
+
const empty = toDispatch.length === 0
|
|
190
|
+
const s = parsed.summary || {}
|
|
191
|
+
return {
|
|
192
|
+
ok: true,
|
|
193
|
+
empty,
|
|
194
|
+
code: 0,
|
|
195
|
+
reason: empty ? 'no_ticket' : null,
|
|
196
|
+
counts: {
|
|
197
|
+
toDispatch: s.to_dispatch ?? toDispatch.length,
|
|
198
|
+
awaitRelease: s.await_release ?? (plan.await_release || []).length,
|
|
199
|
+
needFields: s.need_fields ?? (plan.need_fields || []).length,
|
|
200
|
+
inFlight: s.in_flight ?? (plan.in_flight || []).length,
|
|
201
|
+
stale: s.stale ?? (plan.stale || []).length,
|
|
202
|
+
needsHuman: s.needs_human ?? (plan.needs_human || []).length,
|
|
203
|
+
},
|
|
204
|
+
plan: {
|
|
205
|
+
toDispatch,
|
|
206
|
+
stale: ids(plan.stale),
|
|
207
|
+
inFlight: ids(plan.in_flight),
|
|
208
|
+
needFields: ids(plan.need_fields),
|
|
209
|
+
awaitRelease: ids(plan.await_release),
|
|
210
|
+
},
|
|
211
|
+
...base,
|
|
212
|
+
...((parsed.notes || []).length ? { notes: (parsed.notes || []).map(String).slice(0, 6) } : {}),
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/** 人类可读的一行结论(与 JSON 载荷分离;`--json` 时 stdout 只有 JSON)。 */
|
|
217
|
+
export function humanOf(json) {
|
|
218
|
+
if (!json.ok) return `❌ ${json.reason}:${json.error || ''}`.trim()
|
|
219
|
+
if (json.claimed) {
|
|
220
|
+
if (json.empty) return `本轮无票可认领(no_ticket)${json.note ? `:${json.note}` : ''}`
|
|
221
|
+
return json.dryRun
|
|
222
|
+
? `[dry-run] 将认领 ${json.count} 张(未落台账):${json.claimed.join(', ')}`
|
|
223
|
+
: `✅ 已认领 ${json.count} 张(租约 ${json.leaseMin ?? '?'} 分钟):${json.claimed.join(', ')}`
|
|
224
|
+
}
|
|
225
|
+
const c = json.counts || {}
|
|
226
|
+
if (json.empty) return `本轮无可派发单元(no_ticket)|待放行 ${c.awaitRelease ?? 0}|等人补字段 ${c.needFields ?? 0}|在飞 ${c.inFlight ?? 0}|停滞 ${c.stale ?? 0}`
|
|
227
|
+
return `可派发 ${c.toDispatch ?? 0} 张:${(json.plan?.toDispatch || []).join(', ')}`
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/** 跑脚本(可注入 spawn 便于夹具)。 */
|
|
231
|
+
export function runChild({ py, script, args, env = process.env, spawn = spawnSync, timeout = 0 }) {
|
|
232
|
+
const r = spawn(py, [script, ...args], { encoding: 'utf8', maxBuffer: 64 * 1024 * 1024, env, timeout: timeout || undefined })
|
|
233
|
+
return { status: r.status, stdout: r.stdout || '', stderr: r.stderr || '', signal: r.signal || null }
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* verb 入口:`flow claim` / `flow triage`(route 由 argv 决定)。
|
|
238
|
+
* @returns {{json:object, human:string, stderr:string, exit:number}} 信封(CLI 负责打印与退出码)
|
|
239
|
+
*/
|
|
240
|
+
export function runFlowVerb(argv, { repo, py, pyFailure = null, env = process.env, spawn = spawnSync } = {}) {
|
|
241
|
+
const built = buildInvocation(argv)
|
|
242
|
+
if (!built.ok) {
|
|
243
|
+
const json = { ok: false, empty: false, code: built.code, reason: built.reason, error: built.error, flow: null, flowPrefix: null, flowKnown: false, dryRun: null, casesFromDir: null }
|
|
244
|
+
return { json, human: humanOf(json), stderr: '', exit: built.code }
|
|
245
|
+
}
|
|
246
|
+
if (pyFailure || !py) {
|
|
247
|
+
const json = { ok: false, empty: false, code: 2, reason: 'python_unavailable', error: String(pyFailure || '解释器不可用'),
|
|
248
|
+
flow: built.echo.flow, flowPrefix: null, flowKnown: false, dryRun: built.dryRun, casesFromDir: built.echo.casesFromDir }
|
|
249
|
+
return { json, human: humanOf(json), stderr: '', exit: 2 }
|
|
250
|
+
}
|
|
251
|
+
const script = join(repo, 'scripts', built.route === 'claim' ? 'flow_claim.py' : 'flow_triage.py')
|
|
252
|
+
const child = runChild({ py, script, args: built.childArgs, env, spawn })
|
|
253
|
+
const registryEcho = flowEcho(built.echo.flow, { repo, py })
|
|
254
|
+
const json = built.route === 'claim'
|
|
255
|
+
? shapeClaim(child, { echo: built.echo, registryEcho })
|
|
256
|
+
: shapeTriage(child, { echo: built.echo, registryEcho })
|
|
257
|
+
return { json, human: humanOf(json), stderr: String(child.stderr || ''), exit: Number(json.code) }
|
|
258
|
+
}
|