@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.
- package/MANIFEST.json +341 -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 +576 -0
- package/engine/scripts/billing-mode-daily.sh +13 -0
- package/engine/scripts/build-engine-package.mjs +126 -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 +378 -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/collect-evidence.mjs +42 -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 +135 -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 +47 -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 +261 -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/final-check.mjs +43 -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 +735 -0
- package/engine/scripts/flow-scaffold.py +275 -0
- package/engine/scripts/flow-timers-plist.sh +87 -0
- package/engine/scripts/flow-timers.sh +184 -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 +1025 -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 +2278 -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 +195 -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.sh +18 -0
- package/engine/scripts/lib/argent_datadir.py +285 -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 +295 -0
- package/engine/scripts/poll-invoice.sh +76 -0
- package/engine/scripts/profile-doctor.mjs +686 -0
- package/engine/scripts/provider-select.sh +71 -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/retire-inventory.mjs +40 -0
- package/engine/scripts/run-tests.sh +257 -0
- package/engine/scripts/s1-audit.mjs +85 -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 +137 -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 +74 -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 +35 -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 +217 -0
- package/engine/scripts/ziniao-post-upgrade-check.sh +121 -0
- package/engine/scripts/ziniao-windows.sh +154 -0
- package/engine/skills/README.md +86 -0
- package/engine/skills/argent-dev/SKILL.md +41 -0
- package/engine/skills/internal.json +37 -0
- package/engine/skills/lktop-pm/SKILL.md +35 -0
- package/engine/skills/lktopapp-dev/SKILL.md +34 -0
- package/engine/skills/ml-config-guide/SKILL.md +50 -0
- package/engine/skills/ml-fulfillment-sop/SKILL.md +178 -0
- package/engine/skills/ml-fulfillment-sop/references/andes-components.md +69 -0
- package/engine/skills/ml-fulfillment-sop/references/cdp-port-mapping.md +35 -0
- package/engine/skills/ml-fulfillment-sop/references/feishu-base-fulfillment-schema.md +136 -0
- package/engine/skills/ml-fulfillment-sop/references/multi-window-concurrency.md +69 -0
- package/engine/skills/ml-fulfillment-sop/references/pitfalls.md +77 -0
- package/engine/skills/ml-fulfillment-sop/references/selectors.md +243 -0
- package/engine/skills/ml-fulfillment-sop/scripts/fulfillment.js +586 -0
- package/engine/skills/ml-fulfillment-sop/scripts/poll-and-execute.sh +271 -0
- package/engine/skills/ml-fulfillment-sop/templates/report.md +55 -0
- package/engine/skills/ml-invoice/SKILL.md +506 -0
- package/engine/skills/ml-invoice/references/pitfalls.md +268 -0
- package/engine/skills/ml-invoice/references/portal-flow.md +360 -0
- package/engine/skills/ml-invoice/references/template-fill-contract.md +133 -0
- package/engine/skills/ml-invoice-xzh/SKILL.md +133 -0
- package/engine/skills/ml-invoice-xzh/references/pitfalls.md +230 -0
- package/engine/skills/ml-store-daily-report/SKILL.md +224 -0
- package/engine/skills/ml-store-daily-report/scripts/README.md +25 -0
- package/engine/skills/ml-store-daily-report/scripts/extract.js +691 -0
- package/engine/skills/ml-store-daily-report/scripts/generate.js +299 -0
- package/engine/skills/pet-dev/SKILL.md +42 -0
- package/engine/skills/whyshu-pm/SKILL.md +35 -0
- package/engine/skills/whyshu-web-dev/SKILL.md +50 -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 +738 -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 +22 -4
- package/requirements.txt +5 -0
- package/README.md +0 -3
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 运行时 preset 清理(**唯一真源**,纯函数、可离线测试)。
|
|
3
|
+
*
|
|
4
|
+
* 由来(2026-09-28 客户机 P3):客户机 `~/.dsh/.agent-presets/` 里留着 4 个**旧版残留**角色
|
|
5
|
+
* (argent-lktop-reviewer / argent-ml-seller / argent-vision / argent-whyshu-reviewer),
|
|
6
|
+
* 它们的 persona 行是 `text:`;0.1.5 的 `dsh-persona` 只认 `prefix:` ⇒ preset 挂载失败
|
|
7
|
+
* ⇒ **dsh web 起不来**(KeepAlive 下 crash loop)。升级必须顺手把这些残留清掉。
|
|
8
|
+
*
|
|
9
|
+
* 判定「这是我们的角色」= 目录里有 `format-version.txt`(安装器写入的标记);
|
|
10
|
+
* **用户自建角色没有该文件,一律不碰**。
|
|
11
|
+
*
|
|
12
|
+
* ⚠️ 致命边界:若仓库侧清单为空(源目录缺失/为空),绝不能把全部角色当"残留"删光 ——
|
|
13
|
+
* 所以 `shipped` 为空时本函数**直接返回空结果**。
|
|
14
|
+
*/
|
|
15
|
+
import { cpSync, existsSync, mkdirSync, readdirSync, rmSync } from 'node:fs'
|
|
16
|
+
import { join } from 'node:path'
|
|
17
|
+
|
|
18
|
+
/** 我们安装的角色标记文件。 */
|
|
19
|
+
export const OURS_MARKER = 'format-version.txt'
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* 列出运行时 preset 里的"自家角色"(带标记文件的目录)。
|
|
23
|
+
*/
|
|
24
|
+
export function ownPresets(presetRoot) {
|
|
25
|
+
if (!existsSync(presetRoot)) return []
|
|
26
|
+
return readdirSync(presetRoot).filter((name) => existsSync(join(presetRoot, name, OURS_MARKER)))
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* 清理「自家标记 + 不在仓库清单」的残留角色(先整体备份,再删)。
|
|
31
|
+
* @param {object} o
|
|
32
|
+
* @param {string} o.presetRoot 运行时 preset 根(~/.dsh/.agent-presets)
|
|
33
|
+
* @param {Iterable<string>} o.shipped 仓库当前提供的角色名(本次同步成功的那些)
|
|
34
|
+
* @param {string} o.backupDir 备份根(会创建 <backupDir>/stale-presets-<stamp>/)
|
|
35
|
+
* @param {string} [o.stamp] 备份目录时间戳(测试可注入,保证可断言)
|
|
36
|
+
* @param {(s: string) => void} [o.log]
|
|
37
|
+
* @returns {{ stale: string[], backup: string|null, skipped: boolean }}
|
|
38
|
+
*/
|
|
39
|
+
export function pruneStalePresets({ presetRoot, shipped, backupDir, stamp, log = () => {} }) {
|
|
40
|
+
const keep = new Set(shipped)
|
|
41
|
+
if (keep.size === 0) {
|
|
42
|
+
return { stale: [], backup: null, skipped: true } // 保险:清单为空 ⇒ 什么都不做
|
|
43
|
+
}
|
|
44
|
+
const stale = ownPresets(presetRoot).filter((name) => !keep.has(name))
|
|
45
|
+
if (stale.length === 0) return { stale: [], backup: null, skipped: false }
|
|
46
|
+
|
|
47
|
+
let backup = null
|
|
48
|
+
const ts = stamp || new Date().toISOString().replace(/[:.]/g, '-')
|
|
49
|
+
try {
|
|
50
|
+
backup = join(backupDir, `stale-presets-${ts}`)
|
|
51
|
+
mkdirSync(backup, { recursive: true })
|
|
52
|
+
for (const name of stale) cpSync(join(presetRoot, name), join(backup, name), { recursive: true })
|
|
53
|
+
} catch { backup = null } // 备份失败不阻断,但如实返回 null 供调用方告警
|
|
54
|
+
for (const name of stale) {
|
|
55
|
+
rmSync(join(presetRoot, name), { recursive: true, force: true })
|
|
56
|
+
log(` 旧版残留角色已删:${name}`)
|
|
57
|
+
}
|
|
58
|
+
return { stale, backup, skipped: false }
|
|
59
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* profile 插件收敛(**唯一真源**:悬挂插件依赖 / 退役插件副本)。
|
|
3
|
+
*
|
|
4
|
+
* 由来(2026-09-28 客户机 P3 实测):升级器的 syncPlugins 只**复制目标插件**,从不清理
|
|
5
|
+
* 已消失的 ⇒ 客户机 `~/.dsh/profiles/web/node_modules/` 里躺着 argent-files 等 9 个
|
|
6
|
+
* 旧副本,`package.json` 的 `file:` 依赖还指着**已从仓库删除**的插件目录 ⇒
|
|
7
|
+
* profile-doctor 报 `dep-missing-unfixable` ⇒ 重启前门禁不通过 ⇒ 升级卡死无法重启。
|
|
8
|
+
*
|
|
9
|
+
* ⚠️ 收敛判据是「**悬挂**」(依赖/副本指向的源码已不存在),**不是**「不在目标组合里」——
|
|
10
|
+
* 后者会把活着的插件误删(本机 `argent-flow` 不在 business 组合里但在用;客户机
|
|
11
|
+
* `argent-ml` 同理)。宁可少删,也不许把能跑的东西删掉。
|
|
12
|
+
*
|
|
13
|
+
* 规则:
|
|
14
|
+
* - 只看 `argent-*`(dsh 官方包一概不碰);
|
|
15
|
+
* - `*-bak-*` 一律不动(人工排障留的现场);
|
|
16
|
+
* - 副本:不在目标组合 **且** 规范根里找不到源码 ⇒ 删;
|
|
17
|
+
* - 依赖:`file:` 目标不存在 ⇒ 摘(这是 doctor 报 dep-missing 的直接原因);
|
|
18
|
+
* - 改前备份 package.json,无改动时**字节级不动**。
|
|
19
|
+
*/
|
|
20
|
+
import { copyFileSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
|
21
|
+
import { isAbsolute, join, resolve } from 'node:path'
|
|
22
|
+
|
|
23
|
+
/** 判断某个插件名的源码是否还在(规范根之一里存在同名目录)。 */
|
|
24
|
+
function sourceExists(name, canonicalRoots) {
|
|
25
|
+
return canonicalRoots.some((root) => {
|
|
26
|
+
try { return existsSync(join(root, name)) } catch { return false }
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** 解析依赖值里的本地路径(`file:` 前缀;相对路径按 profileDir 解析)。 */
|
|
31
|
+
function localDepPath(value, profileDir) {
|
|
32
|
+
const v = String(value || '')
|
|
33
|
+
if (!v.startsWith('file:')) return null
|
|
34
|
+
const p = v.slice('file:'.length)
|
|
35
|
+
return isAbsolute(p) ? p : resolve(profileDir, p)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @param {object} o
|
|
40
|
+
* @param {string} o.profileNm profile 的 node_modules 目录
|
|
41
|
+
* @param {string} o.profileDir profile 根目录(含 package.json)
|
|
42
|
+
* @param {string[]} o.target 目标组合(保留名单)
|
|
43
|
+
* @param {string[]} o.canonicalRoots 规范插件根(默认含 <repo>/plugins 的调用方传入)
|
|
44
|
+
* @param {string} o.backupDir package.json 备份目录
|
|
45
|
+
* @param {(s: string) => void} [o.log]
|
|
46
|
+
* @returns {{ removed: string[], depsDropped: string[], kept: string[], backup: string|null }}
|
|
47
|
+
*/
|
|
48
|
+
export function retirePlugins({ profileNm, profileDir, target, canonicalRoots = [], backupDir, log = () => {} }) {
|
|
49
|
+
const keep = new Set(target)
|
|
50
|
+
const removed = []
|
|
51
|
+
const kept = []
|
|
52
|
+
|
|
53
|
+
// ── 1) 悬挂副本:不在组合里,且源码已不存在
|
|
54
|
+
let entries = []
|
|
55
|
+
try { entries = readdirSync(profileNm) } catch { return { removed, depsDropped: [], kept, backup: null } }
|
|
56
|
+
for (const name of entries) {
|
|
57
|
+
if (!/^argent-/.test(name) || keep.has(name) || /-bak-/.test(name)) continue
|
|
58
|
+
if (sourceExists(name, canonicalRoots)) { kept.push(name); continue } // 活着的插件:不动
|
|
59
|
+
rmSync(join(profileNm, name), { recursive: true, force: true })
|
|
60
|
+
removed.push(name)
|
|
61
|
+
log(` 悬挂插件副本已删:${name}(规范根里已无源码)`)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// ── 2) 悬挂依赖:file: 目标不存在 ⇒ 摘(doctor 的 dep-missing 就报在这里)
|
|
65
|
+
const pkgPath = join(profileDir, 'package.json')
|
|
66
|
+
const depsDropped = []
|
|
67
|
+
let backup = null
|
|
68
|
+
let pkg = null
|
|
69
|
+
try { pkg = JSON.parse(readFileSync(pkgPath, 'utf8')) } catch { pkg = null }
|
|
70
|
+
if (pkg && pkg.dependencies && typeof pkg.dependencies === 'object') {
|
|
71
|
+
for (const [dep, value] of Object.entries(pkg.dependencies)) {
|
|
72
|
+
if (!/^argent-/.test(dep) || keep.has(dep)) continue
|
|
73
|
+
const local = localDepPath(value, profileDir)
|
|
74
|
+
const dangling = local ? !existsSync(local) : false
|
|
75
|
+
if (dangling || (local === null && !sourceExists(dep, canonicalRoots))) {
|
|
76
|
+
delete pkg.dependencies[dep]
|
|
77
|
+
depsDropped.push(dep)
|
|
78
|
+
log(` 悬挂依赖已摘:${dep} → ${value}(目标不存在)`)
|
|
79
|
+
} else {
|
|
80
|
+
kept.push(dep)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (depsDropped.length) {
|
|
84
|
+
try {
|
|
85
|
+
mkdirSync(backupDir, { recursive: true })
|
|
86
|
+
const stamp = new Date().toISOString().replace(/[:.]/g, '-')
|
|
87
|
+
backup = join(backupDir, `profile-package.json.${stamp}`)
|
|
88
|
+
copyFileSync(pkgPath, backup)
|
|
89
|
+
} catch { backup = null } // 备份失败不阻断,但如实返回 null 供调用方告警
|
|
90
|
+
const ordered = {}
|
|
91
|
+
for (const k of Object.keys(pkg.dependencies).sort()) ordered[k] = pkg.dependencies[k]
|
|
92
|
+
pkg.dependencies = ordered
|
|
93
|
+
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n', 'utf8')
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return { removed, depsDropped, kept, backup }
|
|
97
|
+
}
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Python 解释器选择(**唯一真源**,纯函数 + 依赖注入 → 可离线测试)。
|
|
3
|
+
*
|
|
4
|
+
* 事故(2026-09-28 客户机 P4/P9):`install-argent.mjs` 的 base python 默认取 PATH 上的
|
|
5
|
+
* `python3`,**不做版本门禁** ⇒ 客户机(系统 python 3.9.6,而机器上另有 uv 装的 3.11.15)
|
|
6
|
+
* 上建出 3.9.6 的 venv;更糟的是"就绪"判定只看 `import openpyxl, yaml, PIL, playwright`
|
|
7
|
+
* 能否通过 —— 3.9.6 装得动这些包 ⇒ 被判"就绪",**版本不足被完全掩盖**,
|
|
8
|
+
* 直到客户机预检才以「流程脚本需要 ≥3.10」的形式暴露出来。
|
|
9
|
+
*
|
|
10
|
+
* 因此两件事都要修:① 多候选 + 版本门禁地选解释器;② venv"就绪"必须**含版本**。
|
|
11
|
+
*/
|
|
12
|
+
import { existsSync, readdirSync } from 'node:fs'
|
|
13
|
+
import { homedir } from 'node:os'
|
|
14
|
+
import { join } from 'node:path'
|
|
15
|
+
import { spawnSync } from 'node:child_process'
|
|
16
|
+
|
|
17
|
+
/** 流程引擎要求的最低版本(3.10 起有 match / 结构化模式匹配等)。 */
|
|
18
|
+
export const MIN_PYTHON = [3, 10]
|
|
19
|
+
|
|
20
|
+
/** "3.9.6" / "3.11.15" → [3,9,6];解析失败返回 null。 */
|
|
21
|
+
export function parseVersion(text) {
|
|
22
|
+
const m = /(\d+)\.(\d+)(?:\.(\d+))?/.exec(String(text || ''))
|
|
23
|
+
return m ? [Number(m[1]), Number(m[2]), Number(m[3] || 0)] : null
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** a ≥ b(逐段比较)。 */
|
|
27
|
+
export function versionAtLeast(a, b) {
|
|
28
|
+
if (!a || !b) return false
|
|
29
|
+
for (let i = 0; i < Math.max(a.length, b.length); i += 1) {
|
|
30
|
+
const x = a[i] || 0
|
|
31
|
+
const y = b[i] || 0
|
|
32
|
+
if (x > y) return true
|
|
33
|
+
if (x < y) return false
|
|
34
|
+
}
|
|
35
|
+
return true
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* venv 的**平台布局**(唯一真源,P0-③ 2026-10-08)。
|
|
40
|
+
*
|
|
41
|
+
* POSIX:`<venv>/bin/python3` + `<venv>/bin/pip`;Windows:`<venv>\Scripts\python.exe` + `<venv>\Scripts\pip.exe`。
|
|
42
|
+
* 此前安装器把 `venv/bin/python3` 写死在四处 ⇒ Windows 上 `spawnSync` 直接 ENOENT
|
|
43
|
+
* ⇒ `✗ 装 Python 依赖失败` ⇒ `exit 1` **中断整个安装**(provider/插件/装机清单全跑不到),
|
|
44
|
+
* 而它给用户的手动补救命令 `…\venv\bin\pip install …` 在 Windows 上**根本不存在**(实测现场见
|
|
45
|
+
* docs/Argent-Windows-安装与HR能力验证-2026-10-08.md §3.3)。
|
|
46
|
+
*
|
|
47
|
+
* @param {string} venvDir venv 根目录
|
|
48
|
+
* @param {{ platform?: string }} [opts] 平台(默认 process.platform;显式传入便于三平台回归)
|
|
49
|
+
* @returns {{ isWin: boolean, binDir: string, python: string, pip: string, activate: string }}
|
|
50
|
+
*/
|
|
51
|
+
export function venvLayout(venvDir, { platform = process.platform } = {}) {
|
|
52
|
+
const isWin = platform === 'win32'
|
|
53
|
+
const binDir = join(venvDir, isWin ? 'Scripts' : 'bin')
|
|
54
|
+
return {
|
|
55
|
+
isWin,
|
|
56
|
+
binDir,
|
|
57
|
+
python: join(binDir, isWin ? 'python.exe' : 'python3'),
|
|
58
|
+
pip: join(binDir, isWin ? 'pip.exe' : 'pip'),
|
|
59
|
+
activate: join(binDir, isWin ? 'activate.bat' : 'activate'),
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* 探测某个解释器路径的版本;不可用返回 null。
|
|
65
|
+
*/
|
|
66
|
+
export function probeVersion(bin, run = realRun) {
|
|
67
|
+
const r = run(bin, ['-c', 'import sys; print("%d.%d.%d" % sys.version_info[:3])'])
|
|
68
|
+
if (r.status !== 0) return null
|
|
69
|
+
return parseVersion(r.stdout)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* 候选解释器(**按优先级**):
|
|
74
|
+
* 显式指定 → PATH 上的版本化名字(3.13…3.10)→ uv 管理的 cpython → PATH 的 python3
|
|
75
|
+
* → homebrew / usr-local 常见位置 → 最后才是裸 python3(可能 <3.10,会被门禁拒)。
|
|
76
|
+
*
|
|
77
|
+
* Windows(P0-⑦ 2026-10-08):POSIX 的名字在 Windows 上基本不存在(`python3.12` 没有、
|
|
78
|
+
* `python3` 往往是 **Microsoft Store 占位符**,运行即失败/弹商店)⇒ 单列 win32 口径:
|
|
79
|
+
* `python`(python.org 安装器的真身)→ C:\Python3xx\ → %LOCALAPPDATA%\Programs\Python\Python3xx\。
|
|
80
|
+
* (`py` 启动器需要 `-3` 之类参数,不能用同一个 run(bin, args) 形态,故不收。)
|
|
81
|
+
*/
|
|
82
|
+
export function candidateInterpreters({ explicit = '', env = process.env, home = homedir(), exists = existsSync, listDir = readdirSync, isWin = process.platform === 'win32' } = {}) {
|
|
83
|
+
const out = []
|
|
84
|
+
const push = (p) => { if (p && !out.includes(p)) out.push(p) }
|
|
85
|
+
push(explicit)
|
|
86
|
+
if (isWin) {
|
|
87
|
+
push('python')
|
|
88
|
+
// python.org 安装器的两个默认落点(PATH 里没有 python 时靠它们兜底)
|
|
89
|
+
const roots = ['C:\\', join(env.LOCALAPPDATA || join(home, 'AppData', 'Local'), 'Programs', 'Python')]
|
|
90
|
+
for (const root of roots) {
|
|
91
|
+
try {
|
|
92
|
+
for (const d of listDir(root)) {
|
|
93
|
+
if (!/^Python3(1[0-9]|[2-9][0-9])/.test(d)) continue
|
|
94
|
+
const p = join(root, d, 'python.exe')
|
|
95
|
+
if (exists(p)) push(p)
|
|
96
|
+
}
|
|
97
|
+
} catch { /* 没有该目录 */ }
|
|
98
|
+
}
|
|
99
|
+
// 少数玩家把 python3.exe 也装了(本机曾手工放一个)——仍作为候选,但排在真身之后
|
|
100
|
+
push('python3')
|
|
101
|
+
return out
|
|
102
|
+
}
|
|
103
|
+
for (const v of ['3.13', '3.12', '3.11', '3.10']) push(`python${v}`)
|
|
104
|
+
// uv 管理的解释器(客户机就是这种:~/.local/share/uv/python/cpython-3.11-*/bin/python3.11)
|
|
105
|
+
const uvRoot = join(home, '.local', 'share', 'uv', 'python')
|
|
106
|
+
try {
|
|
107
|
+
for (const d of listDir(uvRoot)) {
|
|
108
|
+
if (!/^cpython-3\.(1[0-9]|[2-9][0-9])/.test(d)) continue
|
|
109
|
+
for (const name of ['python3', 'python3.11', 'python3.12', 'python3.13']) {
|
|
110
|
+
const p = join(uvRoot, d, 'bin', name)
|
|
111
|
+
if (exists(p)) { push(p); break }
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
} catch { /* 没有 uv 目录 */ }
|
|
115
|
+
push(join(home, 'node', 'bin', 'python3'))
|
|
116
|
+
push('/opt/homebrew/bin/python3')
|
|
117
|
+
push('/usr/local/bin/python3')
|
|
118
|
+
push('python3')
|
|
119
|
+
return out
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* 选出**第一个满足 ≥ MIN_PYTHON** 的解释器。
|
|
124
|
+
* @returns {{ bin: string, version: number[], tried: {bin: string, version: number[]|null}[] } | { bin: null, tried: [] }}
|
|
125
|
+
*/
|
|
126
|
+
export function selectInterpreter({ candidates, run = realRun, min = MIN_PYTHON, explicit = '' }) {
|
|
127
|
+
const tried = []
|
|
128
|
+
for (const bin of candidates) {
|
|
129
|
+
const version = probeVersion(bin, run)
|
|
130
|
+
tried.push({ bin, version })
|
|
131
|
+
if (explicit && bin === explicit) {
|
|
132
|
+
// 显式指定(--python-bin / ARGENT_BASE_PYTHON)必须**要么用上、要么响亮失败** ——
|
|
133
|
+
// 悄悄换一个别的解释器会让"我明明指定了"变成谎话(2026-09-28 修)。
|
|
134
|
+
if (version && versionAtLeast(version, min)) return { bin, version, tried }
|
|
135
|
+
return { bin: null, version, tried, explicitFailed: true }
|
|
136
|
+
}
|
|
137
|
+
if (version && versionAtLeast(version, min)) return { bin, version, tried }
|
|
138
|
+
}
|
|
139
|
+
return { bin: null, version: null, tried }
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* 「只需要一个能跑标准库脚本的解释器」时的唯一入口(P0-⑦ 2026-10-08)。
|
|
144
|
+
*
|
|
145
|
+
* 用途:安装器/体检脚本要跑 `scripts/capability_pack.py --describe` 这类**纯标准库**脚本 ——
|
|
146
|
+
* 此前它们硬编码 `python3`,而 Windows 上 `python3` 常是 **Microsoft Store 占位符**(无输出、
|
|
147
|
+
* 不可用)⇒ 所有能力 `integrity: unverified`、`files` 空(实测现场见
|
|
148
|
+
* docs/Argent-Windows-安装与HR能力验证-2026-10-08.md §3.5)。仓库**早已有**这套多候选口径,
|
|
149
|
+
* 只是这几处没用上。
|
|
150
|
+
*
|
|
151
|
+
* 语义:① 优先 ≥ MIN_PYTHON 的第一个;② 都达不到版本门禁时,退而取**第一个能跑**的
|
|
152
|
+
* (只跑标准库脚本的调用方,老解释器也比"占位符"强);③ 显式指定(ARGENT_PY)不达标 ⇒
|
|
153
|
+
* 返回空串("我明明指定了"必须响亮失败,不许悄悄换一个)。
|
|
154
|
+
* @returns {string} 解释器路径/命令名;找不到返回 ''
|
|
155
|
+
*/
|
|
156
|
+
export function resolveInterpreterPath({ explicit = '', run = realRun, min = MIN_PYTHON, ...candidatesOpts } = {}) {
|
|
157
|
+
const picked = selectInterpreter({ candidates: candidateInterpreters({ explicit, ...candidatesOpts }), run, min, explicit })
|
|
158
|
+
if (picked.bin) return picked.bin
|
|
159
|
+
if (picked.explicitFailed) return ''
|
|
160
|
+
const runnable = picked.tried.find((t) => t.version)
|
|
161
|
+
return runnable ? runnable.bin : ''
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** 真实 runner。 */
|
|
165
|
+
export function realRun(cmd, args) {
|
|
166
|
+
const r = spawnSync(cmd, args, { encoding: 'utf8', timeout: 30000 })
|
|
167
|
+
return { status: r.status ?? 1, stdout: `${r.stdout || ''}${r.stderr || ''}` }
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* venv 是否**真的**可用:版本 ≥ 3.10 **且** 关键依赖可 import。
|
|
172
|
+
* (只看 import 会把 3.9.6 的 venv 判成就绪 —— 客户机就是这么漏过去的。)
|
|
173
|
+
*
|
|
174
|
+
* ⚠️ `pkgs` 必须与安装器的 `pythonRuntimePlan().pkgs` **同一份清单**:这里是
|
|
175
|
+
* `install-argent.mjs --venv-only`(= `python-runtime.sh ensure`)判"要不要补装"的入口 ——
|
|
176
|
+
* 清单少了 `selenium`(P0-1,2026-10-08)时,老 venv 会被判"就绪"⇒ ensure 空转 ⇒
|
|
177
|
+
* 官方推荐的 selenium 档位永远装不上("开关撒谎"的根因之一)。
|
|
178
|
+
*/
|
|
179
|
+
export function venvUsable(venvPython, { run = realRun, min = MIN_PYTHON, exists = existsSync,
|
|
180
|
+
pkgs = ['openpyxl', 'yaml', 'PIL', 'playwright', 'selenium'] } = {}) {
|
|
181
|
+
if (!exists(venvPython)) return { ok: false, reason: 'venv 不存在', version: null }
|
|
182
|
+
const version = probeVersion(venvPython, run)
|
|
183
|
+
if (!version) return { ok: false, reason: '解释器不可用', version: null }
|
|
184
|
+
if (!versionAtLeast(version, min)) {
|
|
185
|
+
return { ok: false, reason: `版本 ${version.join('.')} < ${min.join('.')}`, version }
|
|
186
|
+
}
|
|
187
|
+
const r = run(venvPython, ['-c', `import ${pkgs.join(', ')}`])
|
|
188
|
+
if (r.status !== 0) return { ok: false, reason: `缺依赖(${pkgs.join('/')})`, version }
|
|
189
|
+
return { ok: true, reason: 'ok', version }
|
|
190
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* registry.mjs —— Node 侧读注册表的**唯一入口**(P2a,2026-09-29)。
|
|
3
|
+
*
|
|
4
|
+
* 为什么要有它:注册表已拆成「引擎级 base + 每条业务线一份」,合并/冲突/别名解析都是
|
|
5
|
+
* `scripts/flow_registry.py` 的职责(唯一真源)。Node 侧**不要自己实现合并**,也不要
|
|
6
|
+
* 直接读 `scripts/flow-requirements.json`(那会漏掉业务线流程 —— 2026-09-29 P2a 实测:
|
|
7
|
+
* 分诊/打包/预检多处直读 base,业务线落位后集体"未知流程")。
|
|
8
|
+
*
|
|
9
|
+
* 用法:
|
|
10
|
+
* import { loadRegistryDoc, resolveFlowId } from './lib/registry.mjs'
|
|
11
|
+
* const doc = loadRegistryDoc() // 合并后的完整注册表
|
|
12
|
+
* resolveFlowId(shortName, doc) // 短名 → 规范 id `<vertical>.<flow>`
|
|
13
|
+
*/
|
|
14
|
+
import { execFileSync } from 'node:child_process'
|
|
15
|
+
import { dirname, join } from 'node:path'
|
|
16
|
+
import { fileURLToPath } from 'node:url'
|
|
17
|
+
import { resolveInterpreterPath } from './python-runtime.mjs'
|
|
18
|
+
|
|
19
|
+
const HERE = dirname(fileURLToPath(import.meta.url))
|
|
20
|
+
export const REPO = join(HERE, '..', '..')
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* 读合并后的注册表文档。
|
|
24
|
+
* @param {{root?: string, env?: Record<string,string>, registry?: string, py?: string}} [opts]
|
|
25
|
+
* root:仓库根(默认本仓库;测试可指向夹具)
|
|
26
|
+
* registry:显式单文件(保持"传注册表路径"的历史语义)
|
|
27
|
+
* py:解释器路径。**内核侧(`core/`)必须传已选定的解释器** ——
|
|
28
|
+
* 否则"没有 PATH python3、但有 venv"的机器读不到注册表(2026-10-03 D3 同源问题)。
|
|
29
|
+
* 缺省走共享多候选(见下);`ARGENT_PY` 显式指定时最优先。
|
|
30
|
+
*/
|
|
31
|
+
export function loadRegistryDoc(opts = {}) {
|
|
32
|
+
const root = opts.root || REPO
|
|
33
|
+
// P0-⑦ 同源(2026-10-08 实机):裸 `python3` 在 Windows 上通常是 **Microsoft Store 占位符**
|
|
34
|
+
// (exit 9009)⇒ `execFileSync` 抛错 ⇒ 读不到注册表 ⇒ `argent-catalog.mjs` / 能力页 / 任何
|
|
35
|
+
// `JSON.parse(stdout)` 的调用方全挂。这里与 describeCapability 同一口径:多候选 + 版本门禁
|
|
36
|
+
// (`ARGENT_PY` 仍最优先,最后才退到旧的裸 `python3`)。
|
|
37
|
+
const py = opts.py || process.env.ARGENT_PY || resolveInterpreterPath({}) || 'python3'
|
|
38
|
+
const args = [join(root, 'scripts', 'flow_registry.py'), '--json']
|
|
39
|
+
if (opts.registry) args.push('--registry', opts.registry)
|
|
40
|
+
const out = execFileSync(py, args, {
|
|
41
|
+
encoding: 'utf8',
|
|
42
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
43
|
+
env: { ...process.env, ARGENT_REGISTRY_ROOT: root, ...(opts.env || {}) },
|
|
44
|
+
})
|
|
45
|
+
return JSON.parse(out)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** 别名 → 规范 flow id(无别名时原样返回)。 */
|
|
49
|
+
export function resolveFlowId(flowId, doc) {
|
|
50
|
+
return ((doc && doc.aliases) || {})[flowId] || flowId
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** 取单条 flow(自动做别名解析);不存在返回 undefined。 */
|
|
54
|
+
export function flowSpec(flowId, doc) {
|
|
55
|
+
const d = doc || loadRegistryDoc()
|
|
56
|
+
return (d.flows || {})[resolveFlowId(flowId, d)]
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* 取某条流程的**宿主排程声明**(`trigger.schedule`,P1-A 2026-10-12);未声明返回 `null`。
|
|
61
|
+
*
|
|
62
|
+
* 为什么单独给一个取值函数:排程声明的读取方有三个(`scripts/argent-schedule.mjs`、
|
|
63
|
+
* `scripts/check-production-home.mjs` 的排程面体检、`scripts/argent-doctor.mjs`),
|
|
64
|
+
* 而"声明在哪儿"(`trigger.schedule`,别名解析后)是**一件**事实 ⇒ 只在这一个地方说一次。
|
|
65
|
+
* ⚠️ 本函数**不做任何合并/校验**:合并仍是 `flow_registry.py` 的职责;校验是
|
|
66
|
+
* `vertical-lint.mjs`(装配期)与 `flow_config.py`(运行期)的职责(两边同一套判据)。
|
|
67
|
+
*/
|
|
68
|
+
export function flowSchedule(flowId, doc) {
|
|
69
|
+
const spec = flowSpec(flowId, doc)
|
|
70
|
+
const s = spec && spec.trigger && spec.trigger.schedule
|
|
71
|
+
return s && typeof s === 'object' ? s : null
|
|
72
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# 仓库根解析(**唯一真源**,供各脚本 source)。
|
|
3
|
+
#
|
|
4
|
+
# 由来(2026-09-28 客户机实测):一批脚本把仓库路径默认写成 `$HOME/Code/argent-dsh`
|
|
5
|
+
# (开发机的克隆位置),而客户机的克隆在 `~/.argent-dsh` ⇒ plist 指向不存在的脚本、
|
|
6
|
+
# agent 每 180s 静默 127,探测脚本也找不到 `$REPO/scripts/*.py`。
|
|
7
|
+
#
|
|
8
|
+
# 判据顺序:ARGENT_DSH_REPO → **脚本自身位置**(谁装的就在哪,最可靠)→ 常见克隆位置。
|
|
9
|
+
# 用法:
|
|
10
|
+
# . "$(dirname "${BASH_SOURCE[0]}")/lib/repo-root.sh"
|
|
11
|
+
# REPO="$(argent_repo_root "${BASH_SOURCE[0]}")"
|
|
12
|
+
argent_repo_root() {
|
|
13
|
+
local self="${1:-${BASH_SOURCE[0]}}"
|
|
14
|
+
local self_dir=""
|
|
15
|
+
[ -n "$self" ] && self_dir="$(cd "$(dirname "$self")/.." 2>/dev/null && pwd)"
|
|
16
|
+
local c
|
|
17
|
+
for c in "${ARGENT_DSH_REPO:-}" "$self_dir" "$HOME/.argent-dsh" "$HOME/Code/argent-dsh"; do
|
|
18
|
+
[ -n "$c" ] || continue
|
|
19
|
+
# 认一个稳定的仓内文件,避免误认半个目录
|
|
20
|
+
[ -f "$c/scripts/flow_config.py" ] && { printf '%s' "$c"; return 0; }
|
|
21
|
+
done
|
|
22
|
+
printf '%s' "${ARGENT_DSH_REPO:-${self_dir:-$HOME/.argent-dsh}}"
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
# 生成 launchd 用的 PATH:优先本机真实的 node / lark-cli 目录(launchd 的 PATH 极简)。
|
|
26
|
+
argent_agent_path() {
|
|
27
|
+
local out="" d p c
|
|
28
|
+
# ⚠️ 不能写 `dirname "$(command -v node || echo /nonexistent)"` —— 找不到时
|
|
29
|
+
# dirname 会给出 `/`,而 `/` 存在 ⇒ PATH 里多一个垃圾根目录(2026-09-28 门禁实测)。
|
|
30
|
+
for c in node lark-cli; do
|
|
31
|
+
p="$(command -v "$c" 2>/dev/null || true)"
|
|
32
|
+
[ -n "$p" ] || continue
|
|
33
|
+
d="$(dirname "$p")"
|
|
34
|
+
case ":$out:" in *":$d:"*) continue ;; esac
|
|
35
|
+
[ -d "$d" ] && out="${out:+$out:}$d"
|
|
36
|
+
done
|
|
37
|
+
# 硬编码兜底候选(`command -v` 在 launchd 的极简 PATH 下通常找不到 node,走这里)。
|
|
38
|
+
#
|
|
39
|
+
# ⚠️ 2026-10-02(客户机 Huangwei 生产):这里原本第一项是 `"$HOME/node/bin"` —— 那是
|
|
40
|
+
# **旧遗留 node 前缀**(客户机 `~/node` = node v24.19.0 + dsh 0.1.5-rc.1),它与现役
|
|
41
|
+
# `~/.local/node`(v24.21.0 + dsh 0.1.7-rc.2)并存时,生成的 plist PATH 会把**旧 node 排第一**
|
|
42
|
+
# ⇒ `dsh-web.plist` 与本函数生成 PATH 的**另一个常驻守护 plist** 双双中招,且**只改 plist 会被下次重生成写回**。
|
|
43
|
+
# 该前缀已移除,并换成**现役前缀 `"$HOME/.local/node/bin"`**(不是简单删掉:删掉后 launchd 下
|
|
44
|
+
# node 完全不可达 —— 其余候选只剩 ~/.local/bin、/opt/homebrew/bin、系统目录)。
|
|
45
|
+
# 判据顺序与理由:
|
|
46
|
+
# ① PATH 上真实可达的 node / lark-cli 目录(最可靠:谁装的用谁,天然跟着现役前缀走);
|
|
47
|
+
# ② `"$HOME/.local/node/bin"`(现役 node 前缀;与 flow-timers.sh 生成的 4 个 flow-trigger
|
|
48
|
+
# plist 首位一致 —— 那 4 个的 PATH 就是 `/Users/huangwei/.local/node/bin:…`);
|
|
49
|
+
# ③ `"$HOME/.local/bin"`(lark-cli 所在;launchd 下 lark-cli 必须可达);
|
|
50
|
+
# ④ `/opt/homebrew/bin`(开发机的 Homebrew node/npm)。
|
|
51
|
+
for d in "$HOME/.local/node/bin" "$HOME/.local/bin" /opt/homebrew/bin; do
|
|
52
|
+
case ":$out:" in *":$d:"*) continue ;; esac
|
|
53
|
+
[ -d "$d" ] && out="${out:+$out:}$d"
|
|
54
|
+
done
|
|
55
|
+
printf '%s' "${out:+$out:}/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
|
|
56
|
+
}
|