@danceiny/gotry 0.0.1-rc.21 → 0.0.1-rc.24
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/README.md +102 -194
- package/README.zh-CN.md +115 -210
- package/bin/gotry-backend.js +53 -0
- package/bin/gotry-bootstrap.js +466 -35
- package/bin/gotry-inner.js +255 -36
- package/bin/gotry-process-liveness.d.ts +27 -0
- package/bin/gotry-process-liveness.js +97 -0
- package/bin/gotry-runtime-resolution.d.ts +1 -1
- package/bin/gotry-runtime-resolution.js +2 -2
- package/client/client.js +174 -0
- package/cordis.gotry-patch.yml +70 -93
- package/dist/capabilities/agent-reach-deep.js +45 -122
- package/dist/capabilities/agent-reach.js +63 -148
- package/dist/capabilities/anything.js +89 -75
- package/dist/capabilities/artifacts.js +123 -104
- package/dist/capabilities/channel-health.js +65 -45
- package/dist/capabilities/channel-registry.js +108 -87
- package/dist/capabilities/doctor.js +357 -235
- package/dist/capabilities/effect.js +223 -309
- package/dist/capabilities/fact-log.js +28 -14
- package/dist/capabilities/flyai.js +245 -156
- package/dist/capabilities/ground-transfer.js +509 -0
- package/dist/capabilities/hbcli.js +144 -148
- package/dist/capabilities/hotelbyte-transaction.js +194 -0
- package/dist/capabilities/incident-log.js +131 -61
- package/dist/capabilities/model-override.js +30 -10
- package/dist/capabilities/opensky.js +54 -43
- package/dist/capabilities/resilience.js +50 -32
- package/dist/capabilities/session/action-cache.js +50 -44
- package/dist/capabilities/session/adapters/ctrip-flight.js +119 -62
- package/dist/capabilities/session/adapters/ctrip-hotel.js +125 -110
- package/dist/capabilities/session/adapters/dida-portal.js +206 -0
- package/dist/capabilities/session/adapters/meituan-local.js +35 -54
- package/dist/capabilities/session/adapters/rail-12306.js +169 -112
- package/dist/capabilities/session/benchmark.js +85 -149
- package/dist/capabilities/session/extension-bridge.js +320 -259
- package/dist/capabilities/session/extension-channel.js +57 -76
- package/dist/capabilities/session/extension-distribution.js +115 -119
- package/dist/capabilities/session/extract.js +31 -21
- package/dist/capabilities/session/golden-score.js +55 -33
- package/dist/capabilities/session/health-watch.js +146 -154
- package/dist/capabilities/session/read-guard.js +55 -47
- package/dist/capabilities/session/static-flight-golden.js +49 -36
- package/dist/capabilities/session/transport.js +54 -61
- package/dist/capabilities/session/wizard.js +63 -93
- package/dist/capabilities/session-consent.js +143 -47
- package/dist/capabilities/session-login.js +95 -126
- package/dist/capabilities/session-search.js +391 -253
- package/dist/capabilities/sponsor-plugin.js +341 -0
- package/dist/capabilities/visa-policy.js +87 -73
- package/dist/capabilities/weather.js +163 -235
- package/dist/scripts/action-cache-tests.js +24 -59
- package/dist/scripts/agent-planning-turn-deadline-e2e.js +91 -142
- package/dist/scripts/agent-planning-turn-deadline-tests.js +80 -176
- package/dist/scripts/agent-reach-deep-tests.js +30 -40
- package/dist/scripts/agent-reach-tests.js +26 -18
- package/dist/scripts/agent-reach-wrapper-tests.js +46 -50
- package/dist/scripts/anything-tests.js +58 -62
- package/dist/scripts/artifact-client-contract-tests.js +69 -0
- package/dist/scripts/artifacts-capability-tests.js +235 -0
- package/dist/scripts/async-collect.js +26 -15
- package/dist/scripts/benchmark-environment-bridge-e2e.js +287 -684
- package/dist/scripts/benchmark-environment-bridge-tests.js +818 -3123
- package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +66 -279
- package/dist/scripts/booking-copilot-availability-policy-tests.js +153 -1257
- package/dist/scripts/booking-copilot-bin-proof-tests.js +22 -45
- package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +64 -76
- package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +69 -199
- package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +393 -759
- package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +33 -75
- package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +60 -110
- package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +28 -66
- package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +72 -271
- package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +73 -275
- package/dist/scripts/booking-copilot-runtime-proof-tests.js +784 -3398
- package/dist/scripts/booking-copilot-server-proof-tests.js +63 -168
- package/dist/scripts/booking-copilot-startup-proof-tests.js +38 -124
- package/dist/scripts/booking-executor-tests.js +80 -0
- package/dist/scripts/booking-recovery-chain-tests.js +182 -0
- package/dist/scripts/booking-saga-tests.js +61 -123
- package/dist/scripts/booking-surface-contract-proof-tests.js +152 -1167
- package/dist/scripts/bootstrap-tests.js +1383 -128
- package/dist/scripts/build-changelog.js +89 -130
- package/dist/scripts/build-metrics-report.js +135 -143
- package/dist/scripts/changelog-tests.js +35 -82
- package/dist/scripts/channel-probe-tests.js +44 -116
- package/dist/scripts/channel-probe.js +84 -167
- package/dist/scripts/channel-registry-tests.js +97 -185
- package/dist/scripts/companion-tests.js +25 -70
- package/dist/scripts/dida-cookie-probe.js +87 -0
- package/dist/scripts/dida-sw-probe.js +114 -0
- package/dist/scripts/diff-test.js +17 -12
- package/dist/scripts/doctor-tests.js +428 -120
- package/dist/scripts/dsh-artifact-e2e.js +150 -0
- package/dist/scripts/dsh-artifact-web-e2e.js +443 -0
- package/dist/scripts/dsh-http-proxy-sse-proof.js +90 -0
- package/dist/scripts/dsh-runtime-closure-tests.js +110 -153
- package/dist/scripts/dsh-runtime-closure.js +75 -63
- package/dist/scripts/dsh-session-v3-migration-proof.js +106 -0
- package/dist/scripts/dsh-subprocess-local-proof.js +149 -0
- package/dist/scripts/dsh-target-closure-proof.js +178 -0
- package/dist/scripts/effect-tests.js +165 -552
- package/dist/scripts/engine-run.js +1 -3
- package/dist/scripts/engine-tests.js +16 -10
- package/dist/scripts/evaluation-cadence-tests.js +69 -242
- package/dist/scripts/evaluation-contract-tests.js +193 -499
- package/dist/scripts/extension-distribution-cli.js +19 -15
- package/dist/scripts/extension-distribution-tests.js +98 -211
- package/dist/scripts/extension-tests.js +366 -389
- package/dist/scripts/fact-gate-tests.js +725 -263
- package/dist/scripts/fixtures/extension-bridge-unref-child.mjs +21 -0
- package/dist/scripts/flight-hotel-anchor-363-registered-e2e.js +169 -0
- package/dist/scripts/flight-malformed-tests.js +159 -0
- package/dist/scripts/flyai-tests.js +325 -68
- package/dist/scripts/g5-guard-tests.js +131 -0
- package/dist/scripts/g5-guard.js +189 -0
- package/dist/scripts/gen-lunar-anchors.js +106 -0
- package/dist/scripts/gotry-backend-kernel-tests.js +79 -0
- package/dist/scripts/ground-transfer-tests.js +956 -0
- package/dist/scripts/hbcli-e2e-tests.js +71 -90
- package/dist/scripts/hbcli-live-optin-tests.js +96 -0
- package/dist/scripts/hbcli-release-contract-tests.js +122 -0
- package/dist/scripts/hbcli-tests.js +41 -115
- package/dist/scripts/health-watch-cli.js +42 -28
- package/dist/scripts/hotel-date-gate-tests.js +496 -0
- package/dist/scripts/hotelbyte-reconcile-tests.js +141 -0
- package/dist/scripts/hotelbyte-spawn-e2e-tests.js +373 -0
- package/dist/scripts/i18n-tests.js +16 -9
- package/dist/scripts/incident-tests.js +281 -87
- package/dist/scripts/issue-194-job-id-guard-tests.js +106 -0
- package/dist/scripts/issue-233-cancel-refund-commission-tests.js +392 -0
- package/dist/scripts/issue-271-liveness-tests.js +547 -0
- package/dist/scripts/issue-289-model-retry-real-tests.js +296 -0
- package/dist/scripts/issue-289-model-retry-tests.js +441 -0
- package/dist/scripts/issue-289-web-retry-e2e.js +630 -0
- package/dist/scripts/issue-338-home-city-e2e.js +577 -0
- package/dist/scripts/issue343-real-entry-e2e.js +160 -0
- package/dist/scripts/journey-tests.js +22 -27
- package/dist/scripts/kernel-manifest-evidence.js +109 -0
- package/dist/scripts/kernel-manifest-gate.js +126 -0
- package/dist/scripts/kernel-manifest-tests.js +212 -0
- package/dist/scripts/kernel-manifest-trace-entry.js +7 -0
- package/dist/scripts/kernel-manifest-trace-hook.mjs +28 -0
- package/dist/scripts/kernel-manifest.js +369 -0
- package/dist/scripts/ledger-repair-apply-tests.js +316 -0
- package/dist/scripts/ledger-repair-plan-tests.js +375 -0
- package/dist/scripts/ledger-tests.js +325 -340
- package/dist/scripts/ledger-workflow-crash.js +10 -20
- package/dist/scripts/map-tools-vendor-package-proof.js +206 -134
- package/dist/scripts/memory-capture-tests.js +242 -61
- package/dist/scripts/memory-decay-tests.js +18 -52
- package/dist/scripts/memory-lifecycle-tests.js +657 -0
- package/dist/scripts/memory-lifecycle.js +196 -0
- package/dist/scripts/memory-metrics.js +24 -12
- package/dist/scripts/memory-value-report.js +474 -222
- package/dist/scripts/memory-value-tests.js +328 -0
- package/dist/scripts/metrics-report-tests.js +62 -199
- package/dist/scripts/model-override-e2e.js +66 -105
- package/dist/scripts/nightly-evidence-tests.js +64 -89
- package/dist/scripts/nightly-evidence.js +108 -111
- package/dist/scripts/nudge-digest.js +39 -28
- package/dist/scripts/onboarding-tests.js +63 -88
- package/dist/scripts/opensky-check.js +18 -13
- package/dist/scripts/opensky-tests.js +28 -28
- package/dist/scripts/persona-surface-guard-tests.js +37 -12
- package/dist/scripts/pnpm-dsh-closure-proof.js +2 -5
- package/dist/scripts/policy-anchor-359-registered-e2e.js +214 -0
- package/dist/scripts/price-drift-tests.js +126 -227
- package/dist/scripts/price-drift-watch.js +209 -253
- package/dist/scripts/probe-poi-tests.js +52 -45
- package/dist/scripts/product-metrics.js +187 -273
- package/dist/scripts/publish-preverify.js +47 -41
- package/dist/scripts/realtime-pricing-tests.js +37 -76
- package/dist/scripts/replay-async.js +20 -18
- package/dist/scripts/replay-real.js +16 -18
- package/dist/scripts/replay.js +52 -82
- package/dist/scripts/session-attach-diagnose.js +16 -12
- package/dist/scripts/session-attach-poc.js +34 -37
- package/dist/scripts/session-benchmark.js +66 -147
- package/dist/scripts/session-dida-live-e2e.js +151 -0
- package/dist/scripts/session-extract-tests.js +14 -35
- package/dist/scripts/session-login.js +14 -13
- package/dist/scripts/session-tests.js +545 -583
- package/dist/scripts/sf-live-benchmark.js +92 -110
- package/dist/scripts/sf-live-cli-tests.js +2 -9
- package/dist/scripts/sf-soft-score-tests.js +19 -60
- package/dist/scripts/sf-summary-tests.js +149 -0
- package/dist/scripts/sf-summary.js +466 -84
- package/dist/scripts/skeleton-check.js +16 -14
- package/dist/scripts/skeleton-integration-test.js +11 -10
- package/dist/scripts/skills-contract-tests.js +51 -46
- package/dist/scripts/smoke-session-gate-tests.js +12 -20
- package/dist/scripts/smoke.js +541 -422
- package/dist/scripts/sponsor-reuse-tests.js +262 -0
- package/dist/scripts/state-cli-tests.js +226 -101
- package/dist/scripts/state-cli.js +549 -212
- package/dist/scripts/static-golden-tests.js +46 -180
- package/dist/scripts/time-eval-tests.js +210 -192
- package/dist/scripts/travel-timeline-tests.js +29 -93
- package/dist/scripts/turn-handoff-collect-tests.js +46 -93
- package/dist/scripts/turn-handoff-collect.js +71 -99
- package/dist/scripts/turn-policy-tests.js +28 -29
- package/dist/scripts/typed-contract-canary.js +77 -162
- package/dist/scripts/tz-resolver-sanity.js +50 -0
- package/dist/scripts/tz-resolver-tests.js +584 -0
- package/dist/scripts/unified-tests.js +23 -19
- package/dist/scripts/visa-policy-tests.js +31 -44
- package/dist/scripts/weather-tests.js +121 -543
- package/dist/scripts/wish-channel-gate-tests.js +29 -86
- package/dist/scripts/write-gate-tests.js +522 -0
- package/dist/scripts/z3-lifecycle-fault-tests.js +188 -0
- package/dist/scripts/z3-lifecycle-tests.js +170 -0
- package/dist/scripts/z3-race-repeat-tests.js +39 -0
- package/dist/scripts/z3-race-tests.js +18 -12
- package/dist/src/artifact-gate.js +652 -221
- package/dist/src/backend/kernel.js +91 -0
- package/dist/src/backend/modules/booking-copilot.js +55 -0
- package/dist/src/backend/modules/booking-executor.js +124 -0
- package/dist/src/backend/modules/session-search.js +194 -0
- package/dist/src/benchmark-agent-conformance.js +296 -262
- package/dist/src/benchmark-environment-bridge.js +298 -413
- package/dist/src/benchmark-headless-child-diagnostics.js +93 -100
- package/dist/src/benchmark-tool-isolation.js +94 -67
- package/dist/src/bookable-facts.js +299 -174
- package/dist/src/booking-saga.js +64 -120
- package/dist/src/booking-surface/availability-policy.js +443 -576
- package/dist/src/booking-surface/cancel-refund-commission.js +379 -0
- package/dist/src/booking-surface/contracts.js +24 -80
- package/dist/src/booking-surface/dsh-planner.js +510 -281
- package/dist/src/booking-surface/dsh-plugin.js +17 -1
- package/dist/src/booking-surface/error-codes.js +82 -10
- package/dist/src/booking-surface/index.js +0 -3
- package/dist/src/booking-surface/profile.js +10 -54
- package/dist/src/booking-surface/recovery-chain.js +367 -0
- package/dist/src/booking-surface/runtime.js +765 -891
- package/dist/src/booking-surface/server.js +200 -251
- package/dist/src/booking-surface/startup.js +58 -54
- package/dist/src/booking-surface/validation.js +150 -218
- package/dist/src/bridge.js +20 -13
- package/dist/src/companions.js +48 -74
- package/dist/src/contracts.js +21 -43
- package/dist/src/dsh-llm.js +82 -120
- package/dist/src/engine.js +253 -239
- package/dist/src/evaluation-cadence.js +72 -209
- package/dist/src/evaluation-contracts.js +220 -843
- package/dist/src/flight-pack-adapter.js +54 -0
- package/dist/src/flight-pack-contract.js +2 -0
- package/dist/src/gotry-backend.js +70 -0
- package/dist/src/hotel-date-gate.js +118 -0
- package/dist/src/i18n.js +18 -7
- package/dist/src/index.js +1425 -1629
- package/dist/src/journey.js +132 -81
- package/dist/src/ledger-repair-apply.js +538 -0
- package/dist/src/ledger-repair-plan.js +463 -0
- package/dist/src/loop.js +257 -166
- package/dist/src/memory-capture.js +180 -32
- package/dist/src/memory-decay.js +30 -14
- package/dist/src/memory-lifecycle.js +1310 -0
- package/dist/src/memory-utility.js +27 -40
- package/dist/src/mock-llm.js +36 -61
- package/dist/src/model.js +81 -36
- package/dist/src/realtime-pricing.js +63 -72
- package/dist/src/slot-spec.js +84 -106
- package/dist/src/state-ledger.js +310 -471
- package/dist/src/subagent-job-id-guard.js +58 -0
- package/dist/src/time-anchor.js +231 -33
- package/dist/src/tool-packet.js +20 -8
- package/dist/src/travel-slots.js +58 -35
- package/dist/src/travel-timeline.js +44 -63
- package/dist/src/turn-deadline.js +121 -127
- package/dist/src/turn-policy.js +61 -89
- package/dist/src/tz-resolver.js +143 -0
- package/dist/src/unified.js +504 -381
- package/dist/src/wish-pool.js +39 -14
- package/dist/src/write-gate.js +495 -0
- package/dist/src/z3-shared.js +273 -7
- package/extension/README.md +4 -3
- package/extension/background.js +125 -14
- package/extension/content-bridge.js +23 -1
- package/extension/content-main.js +15 -4
- package/extension/manifest.json +16 -8
- package/package.json +251 -220
- package/ts/capabilities/agent-reach.ts +4 -4
- package/ts/capabilities/anything.ts +1 -1
- package/ts/capabilities/artifacts.ts +46 -9
- package/ts/capabilities/flyai.ts +156 -37
- package/ts/capabilities/hbcli.ts +1 -1
- package/ts/capabilities/incident-log.ts +88 -59
- package/ts/capabilities/session/adapters/ctrip-flight.ts +99 -36
- package/ts/capabilities/session/adapters/dida-portal.ts +250 -0
- package/ts/capabilities/session/adapters/rail-12306.ts +123 -24
- package/ts/capabilities/session/extension-bridge.ts +226 -101
- package/ts/capabilities/session/extension-channel.ts +22 -9
- package/ts/capabilities/session/wizard.ts +2 -2
- package/ts/capabilities/session-consent.ts +98 -14
- package/ts/capabilities/session-login.ts +1 -0
- package/ts/capabilities/session-search.ts +315 -31
- package/ts/dsh-runtime/vendor/README.md +8 -4
- package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +7 -1
- package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +5 -3
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +1 -1
- package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +1 -1
- package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +6 -6
- package/ts/package.json +236 -16
- package/ts/scripts/map-tools-vendor-package-proof.ts +152 -31
- package/ts/scripts/state-cli.ts +418 -51
- package/ts/src/artifact-gate.ts +561 -15
- package/ts/src/benchmark-environment-bridge.ts +37 -20
- package/ts/src/bookable-facts.ts +183 -7
- package/ts/src/booking-surface/cancel-refund-commission.ts +488 -0
- package/ts/src/booking-surface/dsh-planner.ts +240 -32
- package/ts/src/booking-surface/dsh-plugin.js +17 -1
- package/ts/src/booking-surface/error-codes.ts +75 -0
- package/ts/src/booking-surface/recovery-chain.ts +409 -0
- package/ts/src/booking-surface/server.ts +84 -51
- package/ts/src/booking-surface/validation.ts +2 -0
- package/ts/src/contracts.ts +12 -2
- package/ts/src/dsh-llm.ts +4 -8
- package/ts/src/index.ts +609 -90
- package/ts/src/loop.ts +116 -7
- package/ts/src/memory-capture.ts +227 -3
- package/ts/src/mock-llm.ts +4 -8
- package/ts/src/model.ts +88 -2
- package/ts/src/state-ledger.ts +47 -29
- package/ts/src/subagent-job-id-guard.ts +72 -0
- package/ts/src/time-anchor.ts +217 -13
- package/ts/src/unified.ts +316 -54
|
@@ -1,204 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agent-reach wrapper —— 上游 Panniantong/Agent-Reach 的薄壳(零渠道知识)。
|
|
3
|
+
*
|
|
4
|
+
* 分工(2026-08-22 founder 纠偏「wrapper 不是 router」):
|
|
5
|
+
* - 知识(渠道清单/方法签名/setup 指引)→ 上游:agent_reach.channels 注册表 + Channel.check() + guides/
|
|
6
|
+
* - 决策(该调哪个渠道哪个方法) → dsh 里的 LLM(靠本 wrapper 的自描述错误拿清单)
|
|
7
|
+
* - 管道(spawn/超时/永不抛错/证据链) → 本文件 + agent-reach-bridge.py,上游加渠道零改动
|
|
8
|
+
*
|
|
9
|
+
* 上游设计意图(Channel 基类原话):"After installation, agents call upstream tools directly."
|
|
10
|
+
* - python-API 渠道(web.read / v2ex.get_hot_topics / xueqiu.get_stock_quote / youtube.transcribe ...)
|
|
11
|
+
* 走本文件 reach() 的反射桥
|
|
12
|
+
* - 外部 CLI 工具渠道(github→gh / youtube 字幕→yt-dlp 等)由专用 dsh 工具(gotry_github_search /
|
|
13
|
+
* gotry_video_subtitle,见 agent-reach-deep.ts)充当执行面;上游无 python API 的不再自行拼命令
|
|
14
|
+
*
|
|
15
|
+
* 契约(L4 不变量,与 anything/weather/opensky 同构):
|
|
16
|
+
* - 永不抛错;verdict: found / not-installed / needs-setup / error
|
|
17
|
+
* - needs-setup 的 setup 文案 = 上游 check() 原话透传,不转述
|
|
18
|
+
* - 证据链 [agent-reach:<channel>.<method>@ts]
|
|
19
|
+
*/
|
|
1
20
|
import { spawn } from 'node:child_process';
|
|
2
21
|
import { existsSync } from 'node:fs';
|
|
3
22
|
import { resolve } from 'node:path';
|
|
4
|
-
const ts = ()=>new Date().toISOString();
|
|
5
|
-
const repoRoot = ()=>resolve(import.meta.dirname, '..', '..');
|
|
6
|
-
const venvPython = ()=>resolve(repoRoot(), '.venv/bin/python');
|
|
7
|
-
const bridgeScript = ()=>resolve(import.meta.dirname, 'agent-reach-bridge.py');
|
|
23
|
+
const ts = () => new Date().toISOString();
|
|
24
|
+
const repoRoot = () => resolve(import.meta.dirname, '..', '..');
|
|
25
|
+
const venvPython = () => resolve(repoRoot(), '.venv/bin/python');
|
|
26
|
+
const bridgeScript = () => resolve(import.meta.dirname, 'agent-reach-bridge.py');
|
|
8
27
|
function run(bin, args, timeoutMs) {
|
|
9
|
-
return new Promise((resolveRun)=>{
|
|
10
|
-
const child = spawn(bin, args, {
|
|
11
|
-
env: process.env
|
|
12
|
-
});
|
|
28
|
+
return new Promise((resolveRun) => {
|
|
29
|
+
const child = spawn(bin, args, { env: process.env });
|
|
13
30
|
let stdout = '';
|
|
14
31
|
let stderr = '';
|
|
15
32
|
let err;
|
|
16
|
-
const timer = setTimeout(()=>{
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
child.
|
|
22
|
-
|
|
23
|
-
});
|
|
24
|
-
child.stderr.on('data', (d)=>{
|
|
25
|
-
stderr += d.toString();
|
|
26
|
-
});
|
|
27
|
-
child.on('error', (e)=>{
|
|
28
|
-
err = e.message;
|
|
29
|
-
});
|
|
30
|
-
child.on('close', (code)=>{
|
|
31
|
-
clearTimeout(timer);
|
|
32
|
-
resolveRun({
|
|
33
|
-
code,
|
|
34
|
-
stdout,
|
|
35
|
-
stderr,
|
|
36
|
-
err
|
|
37
|
-
});
|
|
38
|
-
});
|
|
33
|
+
const timer = setTimeout(() => { try {
|
|
34
|
+
child.kill('SIGKILL');
|
|
35
|
+
}
|
|
36
|
+
catch { /* ignore */ } }, timeoutMs);
|
|
37
|
+
child.stdout.on('data', (d) => { stdout += d.toString(); });
|
|
38
|
+
child.stderr.on('data', (d) => { stderr += d.toString(); });
|
|
39
|
+
child.on('error', (e) => { err = e.message; });
|
|
40
|
+
child.on('close', (code) => { clearTimeout(timer); resolveRun({ code, stdout, stderr, err }); });
|
|
39
41
|
});
|
|
40
42
|
}
|
|
43
|
+
/** 通用入口:反射调上游任意渠道方法;永不抛错 */
|
|
41
44
|
export async function reach(q) {
|
|
42
45
|
const started = Date.now();
|
|
43
|
-
const evidence = (state)
|
|
44
|
-
const base = {
|
|
45
|
-
channel: q.channel,
|
|
46
|
-
method: q.method
|
|
47
|
-
};
|
|
46
|
+
const evidence = (state) => `[agent-reach:${q.channel}.${q.method}@${state === 'found' ? ts() : `${state}@${ts()}`}]`;
|
|
47
|
+
const base = { channel: q.channel, method: q.method };
|
|
48
48
|
if (!q.channel || !q.method) {
|
|
49
|
-
return {
|
|
50
|
-
...base,
|
|
51
|
-
ok: false,
|
|
52
|
-
verdict: 'error',
|
|
53
|
-
evidence: evidence('error'),
|
|
54
|
-
latencyMs: 0,
|
|
55
|
-
error: 'channel 与 method 必填(渠道/方法清单:先随便调一次,inventory 会带回上游清单)'
|
|
56
|
-
};
|
|
49
|
+
return { ...base, ok: false, verdict: 'error', evidence: evidence('error'), latencyMs: 0, error: 'channel 与 method 必填(渠道/方法清单:先随便调一次,inventory 会带回上游清单)' };
|
|
57
50
|
}
|
|
58
51
|
const py = venvPython();
|
|
59
52
|
if (!existsSync(py)) {
|
|
60
|
-
return {
|
|
61
|
-
...base,
|
|
62
|
-
ok: false,
|
|
63
|
-
verdict: 'not-installed',
|
|
64
|
-
evidence: evidence('not-installed'),
|
|
65
|
-
latencyMs: 0,
|
|
66
|
-
setup: 'gotry .venv 缺 python——可选依赖未装配。补装:终端跑 npx gotry doctor --fix,或让用户看体检报告 npx gotry doctor'
|
|
67
|
-
};
|
|
53
|
+
return { ...base, ok: false, verdict: 'not-installed', evidence: evidence('not-installed'), latencyMs: 0, setup: 'gotry .venv 缺 python——可选依赖未装配。补装:终端跑 npx @danceiny/gotry doctor --fix,或让用户看体检报告 npx @danceiny/gotry doctor' };
|
|
68
54
|
}
|
|
69
|
-
const args = Array.isArray(q.args) ? q.args : q.args ? q.args.split(/\s+/).filter(Boolean) : [];
|
|
70
|
-
const r = await run(py, [
|
|
71
|
-
bridgeScript(),
|
|
72
|
-
q.channel,
|
|
73
|
-
q.method,
|
|
74
|
-
...args
|
|
75
|
-
], q.timeoutMs ?? 30_000);
|
|
55
|
+
const args = Array.isArray(q.args) ? q.args : (q.args ? q.args.split(/\s+/).filter(Boolean) : []);
|
|
56
|
+
const r = await run(py, [bridgeScript(), q.channel, q.method, ...args], q.timeoutMs ?? 30_000);
|
|
76
57
|
const latencyMs = Date.now() - started;
|
|
77
58
|
let parsed = {};
|
|
78
59
|
try {
|
|
79
60
|
parsed = JSON.parse((r.stdout || '').trim().split('\n').filter(Boolean).pop() ?? '{}');
|
|
80
|
-
}
|
|
61
|
+
}
|
|
62
|
+
catch { /* 走下面的兜底 */ }
|
|
81
63
|
if (r.err?.includes('ENOENT')) {
|
|
82
|
-
return {
|
|
83
|
-
...base,
|
|
84
|
-
ok: false,
|
|
85
|
-
verdict: 'not-installed',
|
|
86
|
-
evidence: evidence('not-installed'),
|
|
87
|
-
latencyMs,
|
|
88
|
-
setup: '.venv/bin/python 不可执行——补装:终端跑 npx gotry doctor --fix'
|
|
89
|
-
};
|
|
64
|
+
return { ...base, ok: false, verdict: 'not-installed', evidence: evidence('not-installed'), latencyMs, setup: '.venv/bin/python 不可执行——补装:终端跑 npx @danceiny/gotry doctor --fix' };
|
|
90
65
|
}
|
|
91
66
|
if (parsed.ok === true) {
|
|
92
|
-
return {
|
|
93
|
-
...base,
|
|
94
|
-
ok: true,
|
|
95
|
-
verdict: 'found',
|
|
96
|
-
evidence: evidence('found'),
|
|
97
|
-
latencyMs,
|
|
98
|
-
data: parsed.data
|
|
99
|
-
};
|
|
67
|
+
return { ...base, ok: true, verdict: 'found', evidence: evidence('found'), latencyMs, data: parsed.data };
|
|
100
68
|
}
|
|
69
|
+
// 上游 agent_reach 包未装(bridge 自己的 exit 3 输出)
|
|
101
70
|
if (parsed.error?.includes('agent_reach 未安装')) {
|
|
102
|
-
return {
|
|
103
|
-
...base,
|
|
104
|
-
ok: false,
|
|
105
|
-
verdict: 'not-installed',
|
|
106
|
-
evidence: evidence('not-installed'),
|
|
107
|
-
latencyMs,
|
|
108
|
-
setup: '.venv 缺 agent-reach 包——补装:终端跑 npx gotry doctor --fix'
|
|
109
|
-
};
|
|
71
|
+
return { ...base, ok: false, verdict: 'not-installed', evidence: evidence('not-installed'), latencyMs, setup: '.venv 缺 agent-reach 包——补装:终端跑 npx @danceiny/gotry doctor --fix' };
|
|
110
72
|
}
|
|
73
|
+
// 未知渠道/方法:自描述,附上游清单(不拦 LLM,让它看清单自纠)
|
|
111
74
|
if (r.code === 2) {
|
|
112
75
|
return {
|
|
113
|
-
...base,
|
|
114
|
-
ok: false,
|
|
115
|
-
verdict: 'error',
|
|
116
|
-
evidence: evidence('error'),
|
|
117
|
-
latencyMs,
|
|
76
|
+
...base, ok: false, verdict: 'error', evidence: evidence('error'), latencyMs,
|
|
118
77
|
error: parsed.error,
|
|
119
|
-
inventory: parsed.channels ? {
|
|
120
|
-
channels: parsed.channels
|
|
121
|
-
} : {
|
|
122
|
-
channel: parsed.channel,
|
|
123
|
-
methods: parsed.methods
|
|
124
|
-
}
|
|
78
|
+
inventory: parsed.channels ? { channels: parsed.channels } : { channel: parsed.channel, methods: parsed.methods },
|
|
125
79
|
};
|
|
126
80
|
}
|
|
81
|
+
// 调用抛错:若上游 check() 给出 warn/off,把上游原话作为 setup 透传
|
|
127
82
|
const checkStatus = parsed.check?.status;
|
|
128
83
|
if (checkStatus === 'warn' || checkStatus === 'off') {
|
|
129
|
-
return {
|
|
130
|
-
...base,
|
|
131
|
-
ok: false,
|
|
132
|
-
verdict: 'needs-setup',
|
|
133
|
-
evidence: evidence('needs-setup'),
|
|
134
|
-
latencyMs,
|
|
135
|
-
error: parsed.error,
|
|
136
|
-
setup: parsed.check?.message
|
|
137
|
-
};
|
|
84
|
+
return { ...base, ok: false, verdict: 'needs-setup', evidence: evidence('needs-setup'), latencyMs, error: parsed.error, setup: parsed.check?.message };
|
|
138
85
|
}
|
|
139
|
-
return {
|
|
140
|
-
...base,
|
|
141
|
-
ok: false,
|
|
142
|
-
verdict: 'error',
|
|
143
|
-
evidence: evidence('error'),
|
|
144
|
-
latencyMs,
|
|
145
|
-
error: parsed.error ?? r.stderr.slice(0, 200)
|
|
146
|
-
};
|
|
86
|
+
return { ...base, ok: false, verdict: 'error', evidence: evidence('error'), latencyMs, error: parsed.error ?? r.stderr.slice(0, 200) };
|
|
147
87
|
}
|
|
88
|
+
/** 读网页:委托上游 WebChannel.read(Jina Reader 后端);供 gotry web 读取工具使用 */
|
|
148
89
|
export async function readUrl(q) {
|
|
149
90
|
if (!/^https?:\/\//.test(q.url.trim())) {
|
|
150
|
-
return {
|
|
151
|
-
ok: false,
|
|
152
|
-
via: 'r.jina.ai-error',
|
|
153
|
-
evidence: `[agent-reach:web.read@error@${ts()}] 非法 URL(需 http(s)://)`,
|
|
154
|
-
latencyMs: 0,
|
|
155
|
-
error: 'url 必须以 http(s):// 开头'
|
|
156
|
-
};
|
|
91
|
+
return { ok: false, via: 'r.jina.ai-error', evidence: `[agent-reach:web.read@error@${ts()}] 非法 URL(需 http(s)://)`, latencyMs: 0, error: 'url 必须以 http(s):// 开头' };
|
|
157
92
|
}
|
|
158
|
-
const r = await reach({
|
|
159
|
-
channel: 'web',
|
|
160
|
-
method: 'read',
|
|
161
|
-
args: [
|
|
162
|
-
q.url.trim()
|
|
163
|
-
],
|
|
164
|
-
timeoutMs: q.timeoutMs
|
|
165
|
-
});
|
|
93
|
+
const r = await reach({ channel: 'web', method: 'read', args: [q.url.trim()], timeoutMs: q.timeoutMs });
|
|
166
94
|
const content = typeof r.data === 'string' ? r.data.slice(0, 8000) : undefined;
|
|
95
|
+
// 上游 Jina Reader 输出首行 "Title: ...",提取为标题(展示层逻辑,非渠道知识)
|
|
167
96
|
const title = content?.match(/^Title: (.+)$/m)?.[1];
|
|
168
97
|
return {
|
|
169
|
-
ok: r.ok,
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
content,
|
|
173
|
-
evidence: r.evidence,
|
|
174
|
-
latencyMs: r.latencyMs,
|
|
175
|
-
error: r.error
|
|
98
|
+
ok: r.ok, via: r.ok ? 'r.jina.ai' : 'r.jina.ai-error',
|
|
99
|
+
title, content, evidence: r.evidence, latencyMs: r.latencyMs,
|
|
100
|
+
error: r.error,
|
|
176
101
|
};
|
|
177
102
|
}
|
|
103
|
+
/** 渠道体检:spawn 真 agent-reach doctor,输出原样透传 */
|
|
178
104
|
export async function reachStatus(timeoutMs = 90_000) {
|
|
179
105
|
const started = Date.now();
|
|
180
106
|
const bin = resolve(repoRoot(), '.venv/bin/agent-reach');
|
|
181
107
|
if (!existsSync(bin)) {
|
|
182
|
-
return {
|
|
183
|
-
ok: false,
|
|
184
|
-
via: 'not-installed',
|
|
185
|
-
evidence: `[agent-reach:doctor@not-installed@${ts()}]`,
|
|
186
|
-
latencyMs: 0,
|
|
187
|
-
output: 'Agent Reach 未装配(.venv 缺失)——可选依赖,补装:终端跑 npx gotry doctor --fix;或让助手调 gotry_doctor 看整体体检报告'
|
|
188
|
-
};
|
|
108
|
+
return { ok: false, via: 'not-installed', evidence: `[agent-reach:doctor@not-installed@${ts()}]`, latencyMs: 0, output: 'Agent Reach 未装配(.venv 缺失)——可选依赖,补装:终端跑 npx @danceiny/gotry doctor --fix;或让助手调 gotry_doctor 看整体体检报告' };
|
|
189
109
|
}
|
|
190
|
-
const r = await run(bin, [
|
|
191
|
-
'doctor'
|
|
192
|
-
], timeoutMs);
|
|
110
|
+
const r = await run(bin, ['doctor'], timeoutMs);
|
|
193
111
|
const output = (r.stdout || r.stderr).trim();
|
|
194
112
|
return {
|
|
195
113
|
ok: !r.err?.includes('ENOENT') && r.code === 0,
|
|
196
114
|
via: 'agent-reach-cli',
|
|
197
115
|
evidence: `[agent-reach:doctor@${ts()}] via .venv/bin/agent-reach`,
|
|
198
116
|
latencyMs: Date.now() - started,
|
|
199
|
-
output: output.slice(0, 4000)
|
|
117
|
+
output: output.slice(0, 4000),
|
|
200
118
|
};
|
|
201
119
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
//# sourceURL=ts/capabilities/agent-reach.ts
|
|
@@ -1,114 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Anything 通用搜索能力层:hbcli → hotel-be Anything 函数。
|
|
3
|
+
*
|
|
4
|
+
* 链路(同构 hbcli.ts):
|
|
5
|
+
* gotry capabilities/anything.ts
|
|
6
|
+
* → spawn hbcli --json search anything <kw> [opts]
|
|
7
|
+
* → hotel-be /api/search/anything(httpdispatch 自动注册;httpdispatch 路由面)
|
|
8
|
+
* → search/service/geography.go func Anything (mixed 城市+酒店搜索)
|
|
9
|
+
*
|
|
10
|
+
* wire 契约(2026-09-07 对齐上游源码;SearchItem = FuzzySearchItem + hotel):
|
|
11
|
+
* req { keyword, contentType?, context.destinationId?, minHotelCount? }
|
|
12
|
+
* resp { candidates: [{ type: 'city'|'place'|'hotel',
|
|
13
|
+
* region?: { id, name:{en,zh,ar}, coordinates:{centerLat,centerLng}, countryCode, … },
|
|
14
|
+
* place?: { latlngCoordinator },
|
|
15
|
+
* matchScore?, hotel?: { id, name:{en,zh,ar}, star, latlngCoordinator:{google|gaode:{lat,lng} } } }] }
|
|
16
|
+
*
|
|
17
|
+
* 三值语义:
|
|
18
|
+
* - hit: 命中候选(混合 city/hotel,maybe-coords)
|
|
19
|
+
* - miss: hbcli exit 0,但 candidates 为空(查无结果)
|
|
20
|
+
* - err: hbcli exit ≠ 0 或超时(降级,降级产物 标 [实时API:hbcli-anything@error@ts])
|
|
21
|
+
*
|
|
22
|
+
* 契约(与 hbcli/weather/opensky 同构,L4 不变量):
|
|
23
|
+
* - 永不抛错:网络/超时/解析失败一律降级返回;
|
|
24
|
+
* - 证据链标注:成功 [实时API:hbcli-anything@ts];失败 [实时API:hbcli-anything@error@ts];
|
|
25
|
+
* - 永不阻塞调用方:周边有 12s 默认超时,LLM 不等。
|
|
26
|
+
*
|
|
27
|
+
* 第 7 个能力层(与 hbcli.ts / weather.ts / opensky.ts 平级),data-sources.md §4
|
|
28
|
+
* Google Place 链路的「酒店-be 中间层」入口。
|
|
29
|
+
*/
|
|
1
30
|
import { spawn } from 'node:child_process';
|
|
2
31
|
import { hbcliBinCandidates } from './hbcli.js';
|
|
3
32
|
function i18nText(v) {
|
|
4
|
-
if (!v)
|
|
5
|
-
|
|
33
|
+
if (!v)
|
|
34
|
+
return '';
|
|
35
|
+
if (typeof v === 'string')
|
|
36
|
+
return v;
|
|
6
37
|
return v.zh || v.en || v.ar || '';
|
|
7
38
|
}
|
|
39
|
+
/** hotel-be Latlng:{lat,lng};google/gaode 双源取先非零者 */
|
|
8
40
|
function latlngOf(coord) {
|
|
9
|
-
for (const src of [
|
|
10
|
-
coord?.google,
|
|
11
|
-
coord?.gaode
|
|
12
|
-
]){
|
|
41
|
+
for (const src of [coord?.google, coord?.gaode]) {
|
|
13
42
|
const lat = typeof src?.lat === 'number' ? src.lat : undefined;
|
|
14
43
|
const lng = typeof src?.lng === 'number' ? src.lng : undefined;
|
|
15
|
-
if (lat !== undefined && lng !== undefined && (lat !== 0 || lng !== 0))
|
|
16
|
-
latitude: lat,
|
|
17
|
-
longitude: lng
|
|
18
|
-
};
|
|
44
|
+
if (lat !== undefined && lng !== undefined && (lat !== 0 || lng !== 0))
|
|
45
|
+
return { latitude: lat, longitude: lng };
|
|
19
46
|
}
|
|
20
47
|
return {};
|
|
21
48
|
}
|
|
22
49
|
function sh(cmd, args, opts) {
|
|
23
50
|
const ctrl = new AbortController();
|
|
24
|
-
const timer = setTimeout(()=>{
|
|
51
|
+
const timer = setTimeout(() => {
|
|
25
52
|
ctrl.abort();
|
|
53
|
+
// AbortSignal on spawn 会发 SIGTERM;对于不响应 SIGTERM 的子进程,需要在外部再发一次 SIGKILL。
|
|
54
|
+
// Node 不能直接通过 AbortController 拿 child pid,所以需要借助外部变量保存 child。
|
|
26
55
|
}, opts.timeoutMs);
|
|
27
56
|
let child = null;
|
|
28
57
|
let killTimer = null;
|
|
29
|
-
return new Promise((resolve)=>{
|
|
58
|
+
return new Promise((resolve) => {
|
|
30
59
|
child = spawn(cmd, args, {
|
|
31
60
|
env: opts.env,
|
|
32
61
|
cwd: process.cwd(),
|
|
33
|
-
signal: ctrl.signal
|
|
62
|
+
signal: ctrl.signal,
|
|
34
63
|
});
|
|
35
64
|
let stdout = '';
|
|
36
65
|
let stderr = '';
|
|
37
66
|
let error;
|
|
38
67
|
let killed = false;
|
|
39
|
-
child.stdout?.on('data', (d)=>{
|
|
40
|
-
|
|
41
|
-
});
|
|
42
|
-
child.
|
|
43
|
-
stderr += d.toString();
|
|
44
|
-
});
|
|
45
|
-
child.on('error', (e)=>{
|
|
46
|
-
error = e.message.slice(0, 200);
|
|
47
|
-
});
|
|
48
|
-
child.on('close', (code)=>{
|
|
68
|
+
child.stdout?.on('data', (d) => { stdout += d.toString(); });
|
|
69
|
+
child.stderr?.on('data', (d) => { stderr += d.toString(); });
|
|
70
|
+
child.on('error', (e) => { error = e.message.slice(0, 200); });
|
|
71
|
+
child.on('close', (code) => {
|
|
49
72
|
clearTimeout(timer);
|
|
50
|
-
if (killTimer)
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
stdout,
|
|
54
|
-
stderr,
|
|
55
|
-
error
|
|
56
|
-
});
|
|
73
|
+
if (killTimer)
|
|
74
|
+
clearTimeout(killTimer);
|
|
75
|
+
resolve({ code: killed ? -2 : (code ?? -1), stdout, stderr, error });
|
|
57
76
|
});
|
|
58
|
-
|
|
59
|
-
|
|
77
|
+
// Abort 后 500ms 内若子进程仍活,发 SIGKILL 强杀。
|
|
78
|
+
ctrl.signal.addEventListener('abort', () => {
|
|
79
|
+
if (!child)
|
|
80
|
+
return;
|
|
60
81
|
try {
|
|
61
82
|
child.kill('SIGTERM');
|
|
62
|
-
}
|
|
63
|
-
|
|
83
|
+
}
|
|
84
|
+
catch { /* ignore */ }
|
|
85
|
+
killTimer = setTimeout(() => {
|
|
64
86
|
try {
|
|
65
87
|
child?.kill('SIGKILL');
|
|
66
|
-
}
|
|
88
|
+
}
|
|
89
|
+
catch { /* ignore */ }
|
|
67
90
|
}, 500);
|
|
68
91
|
});
|
|
69
92
|
});
|
|
70
93
|
}
|
|
94
|
+
/** --json 必须在子命令前(cli.ts 全局旗标预扫描只认子命令前位置;JSON 错误也走结构化 stderr) */
|
|
71
95
|
function buildArgs(keyword, q) {
|
|
72
|
-
const args = [
|
|
73
|
-
|
|
74
|
-
'
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
];
|
|
78
|
-
if (q.contentType) args.push('--content-type', q.contentType);
|
|
79
|
-
if (q.parentDestinationId !== undefined) args.push('--destination-id', String(q.parentDestinationId));
|
|
96
|
+
const args = ['--json', 'search', 'anything', keyword];
|
|
97
|
+
if (q.contentType)
|
|
98
|
+
args.push('--content-type', q.contentType);
|
|
99
|
+
if (q.parentDestinationId !== undefined)
|
|
100
|
+
args.push('--destination-id', String(q.parentDestinationId));
|
|
80
101
|
return args;
|
|
81
102
|
}
|
|
103
|
+
/** 旧版 CLI 无 search anything 子命令时的可行动升级指引(issue #195:裸 unknown command 读起来像工具坏了) */
|
|
82
104
|
function upgradeHint(stderr) {
|
|
83
|
-
return /unknown command/i.test(stderr)
|
|
105
|
+
return /unknown command/i.test(stderr)
|
|
106
|
+
? 'hbcli 版本过旧(无 search anything 子命令)——请升级:hbcli update,或重跑 npx @danceiny/gotry setup'
|
|
107
|
+
: null;
|
|
84
108
|
}
|
|
109
|
+
/** Anything 通用搜索 — 任何搜索失败走降级;不抛错 */
|
|
85
110
|
export async function anythingSearch(q) {
|
|
86
111
|
const started = Date.now();
|
|
87
112
|
const ts = new Date().toISOString();
|
|
88
113
|
const kw = (q.keyword ?? '').trim();
|
|
89
114
|
if (!kw) {
|
|
90
115
|
return {
|
|
91
|
-
ok: false,
|
|
92
|
-
via: 'hbcli-anything-error',
|
|
116
|
+
ok: false, via: 'hbcli-anything-error',
|
|
93
117
|
evidence: `[实时API:hbcli-anything@error@${ts}] keyword empty`,
|
|
94
|
-
latencyMs: Date.now() - started,
|
|
95
|
-
|
|
96
|
-
error: 'keyword is required'
|
|
118
|
+
latencyMs: Date.now() - started, verdict: 'error',
|
|
119
|
+
error: 'keyword is required',
|
|
97
120
|
};
|
|
98
121
|
}
|
|
99
122
|
const args = buildArgs(kw, q);
|
|
123
|
+
// spawn 级失败(ENOENT)按已知安装位回退(hbcli.ts callHbcliJson 同款);其余失败无重试意义
|
|
100
124
|
const candidates = hbcliBinCandidates(q.hbcliBin ?? 'hbcli');
|
|
101
|
-
let r = {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
for(let i = 0; i < candidates.length; i++){
|
|
107
|
-
r = await sh(candidates[i], args, {
|
|
108
|
-
timeoutMs: q.timeoutMs ?? 12_000,
|
|
109
|
-
env: process.env
|
|
110
|
-
});
|
|
111
|
-
if (!(r.error && i < candidates.length - 1)) break;
|
|
125
|
+
let r = { code: -1, stdout: '', stderr: '' };
|
|
126
|
+
for (let i = 0; i < candidates.length; i++) {
|
|
127
|
+
r = await sh(candidates[i], args, { timeoutMs: q.timeoutMs ?? 12_000, env: process.env });
|
|
128
|
+
if (!(r.error && i < candidates.length - 1))
|
|
129
|
+
break;
|
|
112
130
|
}
|
|
113
131
|
const latencyMs = Date.now() - started;
|
|
114
132
|
if (r.error || r.code !== 0) {
|
|
@@ -119,7 +137,7 @@ export async function anythingSearch(q) {
|
|
|
119
137
|
evidence: `[实时API:hbcli-anything@error@${ts}] ${raw}`,
|
|
120
138
|
latencyMs,
|
|
121
139
|
verdict: 'error',
|
|
122
|
-
error: upgradeHint(r.stderr) ?? raw
|
|
140
|
+
error: upgradeHint(r.stderr) ?? raw,
|
|
123
141
|
};
|
|
124
142
|
}
|
|
125
143
|
let data;
|
|
@@ -127,18 +145,18 @@ export async function anythingSearch(q) {
|
|
|
127
145
|
const jStart = r.stdout.indexOf('{') >= 0 ? r.stdout.indexOf('{') : r.stdout.indexOf('[');
|
|
128
146
|
const json = jStart >= 0 ? r.stdout.slice(jStart) : r.stdout;
|
|
129
147
|
data = JSON.parse(json);
|
|
130
|
-
}
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
131
150
|
return {
|
|
132
|
-
ok: false,
|
|
133
|
-
via: 'hbcli-anything-error',
|
|
151
|
+
ok: false, via: 'hbcli-anything-error',
|
|
134
152
|
evidence: `[实时API:hbcli-anything@error@${ts}] parse failed`,
|
|
135
153
|
latencyMs,
|
|
136
154
|
verdict: 'error',
|
|
137
|
-
error: 'failed to parse hbcli output as JSON'
|
|
155
|
+
error: 'failed to parse hbcli output as JSON',
|
|
138
156
|
};
|
|
139
157
|
}
|
|
140
158
|
const rawItems = data.candidates ?? [];
|
|
141
|
-
const hits = rawItems.map((it)=>{
|
|
159
|
+
const hits = rawItems.map((it) => {
|
|
142
160
|
const region = it.region ?? {};
|
|
143
161
|
const hotel = it.hotel ?? {};
|
|
144
162
|
const isHotel = it.type === 'hotel' || Boolean(hotel.id);
|
|
@@ -146,27 +164,23 @@ export async function anythingSearch(q) {
|
|
|
146
164
|
const placeCoords = latlngOf(it.place?.latlngCoordinator);
|
|
147
165
|
const center = region.coordinates ?? {};
|
|
148
166
|
return {
|
|
149
|
-
type: isHotel ? 'hotel' : it.type === 'place' ? 'place' : 'city',
|
|
167
|
+
type: (isHotel ? 'hotel' : (it.type === 'place' ? 'place' : 'city')),
|
|
150
168
|
name: i18nText(hotel.name) || i18nText(region.name) || '?',
|
|
151
169
|
score: it.matchScore,
|
|
152
170
|
latitude: hotelCoords.latitude ?? placeCoords.latitude ?? (typeof center.centerLat === 'number' ? center.centerLat : undefined),
|
|
153
171
|
longitude: hotelCoords.longitude ?? placeCoords.longitude ?? (typeof center.centerLng === 'number' ? center.centerLng : undefined),
|
|
154
|
-
destinationId: hotel.destinationId !== undefined ? String(hotel.destinationId) : region.id !== undefined ? String(region.id) : undefined,
|
|
172
|
+
destinationId: hotel.destinationId !== undefined ? String(hotel.destinationId) : (region.id !== undefined ? String(region.id) : undefined),
|
|
155
173
|
hotelId: hotel.id !== undefined ? String(hotel.id) : undefined,
|
|
156
|
-
star: typeof hotel.star === 'number' && hotel.star > 0 ? hotel.star : undefined
|
|
174
|
+
star: typeof hotel.star === 'number' && hotel.star > 0 ? hotel.star : undefined,
|
|
157
175
|
};
|
|
158
176
|
});
|
|
159
177
|
const verdict = hits.length > 0 ? 'hit' : 'miss';
|
|
160
178
|
return {
|
|
161
|
-
ok: true,
|
|
162
|
-
via: 'hbcli-anything',
|
|
179
|
+
ok: true, via: 'hbcli-anything',
|
|
163
180
|
evidence: `[实时API:hbcli-anything@${ts}] ${hits.length}/${rawItems.length} candidates`,
|
|
164
181
|
latencyMs,
|
|
165
182
|
verdict,
|
|
166
183
|
hits,
|
|
167
|
-
totalCandidates: rawItems.length
|
|
184
|
+
totalCandidates: rawItems.length,
|
|
168
185
|
};
|
|
169
186
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
//# sourceURL=ts/capabilities/anything.ts
|