@danceiny/gotry 0.0.1-rc.9 → 0.2.0-rc.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (507) hide show
  1. package/README.md +172 -219
  2. package/README.zh-CN.md +222 -0
  3. package/bin/gotry-backend.js +53 -0
  4. package/bin/gotry-booking-copilot.js +53 -0
  5. package/bin/gotry-bootstrap.js +1744 -0
  6. package/bin/gotry-inner.js +733 -83
  7. package/bin/gotry-process-liveness.d.ts +27 -0
  8. package/bin/gotry-process-liveness.js +97 -0
  9. package/bin/gotry-runtime-resolution.d.ts +27 -0
  10. package/bin/gotry-runtime-resolution.js +49 -0
  11. package/bin/gotry.js +1 -1
  12. package/client/client.js +203 -0
  13. package/cordis.gotry-patch.yml +80 -56
  14. package/data/airline-airports.json +39 -0
  15. package/data/stations-12306-verify.json +524 -0
  16. package/dist/capabilities/agent-reach-deep.js +45 -122
  17. package/dist/capabilities/agent-reach.js +101 -146
  18. package/dist/capabilities/anything.js +135 -94
  19. package/dist/capabilities/artifacts.js +370 -0
  20. package/dist/capabilities/channel-health.js +131 -0
  21. package/dist/capabilities/channel-registry.js +256 -0
  22. package/dist/capabilities/doctor.js +546 -0
  23. package/dist/capabilities/effect.js +394 -0
  24. package/dist/capabilities/external-event.js +149 -0
  25. package/dist/capabilities/fact-log.js +55 -0
  26. package/dist/capabilities/flyai-config.js +337 -0
  27. package/dist/capabilities/flyai.js +947 -110
  28. package/dist/capabilities/fx-contract.js +293 -0
  29. package/dist/capabilities/geo-atlas.js +246 -0
  30. package/dist/capabilities/ground-transfer.js +509 -0
  31. package/dist/capabilities/hbcli.js +260 -123
  32. package/dist/capabilities/hotelbyte-transaction.js +194 -0
  33. package/dist/capabilities/incident-log.js +131 -61
  34. package/dist/capabilities/itinerary-artifact.js +190 -0
  35. package/dist/capabilities/itinerary-deck-artifact.js +194 -0
  36. package/dist/capabilities/itinerary-deck-export.js +339 -0
  37. package/dist/capabilities/lavish-local.js +924 -0
  38. package/dist/capabilities/model-override.js +38 -0
  39. package/dist/capabilities/opensky.js +54 -43
  40. package/dist/capabilities/resilience.js +191 -0
  41. package/dist/capabilities/session/action-cache.js +50 -44
  42. package/dist/capabilities/session/adapters/ctrip-flight.js +120 -62
  43. package/dist/capabilities/session/adapters/ctrip-hotel.js +222 -0
  44. package/dist/capabilities/session/adapters/dida-portal.js +274 -0
  45. package/dist/capabilities/session/adapters/meituan-local.js +35 -54
  46. package/dist/capabilities/session/adapters/rail-12306.js +342 -0
  47. package/dist/capabilities/session/benchmark.js +189 -0
  48. package/dist/capabilities/session/bridge-ledger.js +224 -0
  49. package/dist/capabilities/session/extension-bridge.js +636 -0
  50. package/dist/capabilities/session/extension-channel.js +109 -0
  51. package/dist/capabilities/session/extension-distribution.js +230 -0
  52. package/dist/capabilities/session/extract.js +31 -21
  53. package/dist/capabilities/session/golden-score.js +114 -0
  54. package/dist/capabilities/session/health-watch.js +215 -0
  55. package/dist/capabilities/session/read-guard.js +75 -24
  56. package/dist/capabilities/session/static-flight-golden.js +150 -0
  57. package/dist/capabilities/session/transport.js +97 -83
  58. package/dist/capabilities/session/wizard.js +117 -0
  59. package/dist/capabilities/session-consent.js +178 -0
  60. package/dist/capabilities/session-login.js +170 -0
  61. package/dist/capabilities/session-search.js +635 -44
  62. package/dist/capabilities/spawn-bounded.js +203 -0
  63. package/dist/capabilities/sponsor-plugin.js +341 -0
  64. package/dist/capabilities/visa-policy.js +140 -0
  65. package/dist/capabilities/weather.js +243 -138
  66. package/dist/data/session-golden-20.json +25 -0
  67. package/dist/data/sf-golden-manifest.json +103 -0
  68. package/dist/data/sf-static-routes.json +91 -0
  69. package/dist/scripts/action-cache-tests.js +24 -59
  70. package/dist/scripts/agent-planning-turn-deadline-e2e.js +242 -0
  71. package/dist/scripts/agent-planning-turn-deadline-tests.js +185 -0
  72. package/dist/scripts/agent-reach-deep-tests.js +30 -40
  73. package/dist/scripts/agent-reach-error-tests.js +354 -0
  74. package/dist/scripts/agent-reach-tests.js +26 -18
  75. package/dist/scripts/agent-reach-wrapper-tests.js +50 -50
  76. package/dist/scripts/anything-tests.js +116 -60
  77. package/dist/scripts/artifact-client-contract-tests.js +220 -0
  78. package/dist/scripts/artifacts-capability-tests.js +727 -0
  79. package/dist/scripts/async-collect.js +50 -11
  80. package/dist/scripts/benchmark-environment-bridge-e2e.js +741 -0
  81. package/dist/scripts/benchmark-environment-bridge-tests.js +1452 -0
  82. package/dist/scripts/booking-copilot-availability-ledger-binding-tests.js +126 -0
  83. package/dist/scripts/booking-copilot-availability-policy-tests.js +265 -0
  84. package/dist/scripts/booking-copilot-bin-proof-tests.js +66 -0
  85. package/dist/scripts/booking-copilot-cleanup-proof-helper.js +76 -0
  86. package/dist/scripts/booking-copilot-crossrepo-fixture-server.js +144 -0
  87. package/dist/scripts/booking-copilot-dsh-core-proof-tests.js +424 -0
  88. package/dist/scripts/booking-copilot-dsh-planner-proof-tests.js +2839 -0
  89. package/dist/scripts/booking-copilot-dsh-plugin-proof-tests.js +309 -0
  90. package/dist/scripts/booking-copilot-dsh-readiness-proof.js +238 -0
  91. package/dist/scripts/booking-copilot-dsh-warmer-proof.js +123 -0
  92. package/dist/scripts/booking-copilot-event-sequence-concurrency-proof-tests.js +156 -0
  93. package/dist/scripts/booking-copilot-gap-code-contract-proof-tests.js +70 -0
  94. package/dist/scripts/booking-copilot-intent-proof-tests.js +422 -0
  95. package/dist/scripts/booking-copilot-operation-ledger-concurrency-proof-tests.js +184 -0
  96. package/dist/scripts/booking-copilot-planner-live-probe.js +95 -0
  97. package/dist/scripts/booking-copilot-proof-runtime.js +42 -0
  98. package/dist/scripts/booking-copilot-receipt-ledger-concurrency-proof-tests.js +210 -0
  99. package/dist/scripts/booking-copilot-runtime-proof-tests.js +2349 -0
  100. package/dist/scripts/booking-copilot-server-proof-tests.js +784 -0
  101. package/dist/scripts/booking-copilot-startup-proof-tests.js +94 -0
  102. package/dist/scripts/booking-executor-tests.js +80 -0
  103. package/dist/scripts/booking-recovery-chain-tests.js +182 -0
  104. package/dist/scripts/booking-saga-tests.js +125 -0
  105. package/dist/scripts/booking-surface-contract-proof-tests.js +212 -0
  106. package/dist/scripts/bootstrap-tests.js +1479 -0
  107. package/dist/scripts/bridge-events-tests.js +239 -0
  108. package/dist/scripts/bridge-ledger-tests.js +428 -0
  109. package/dist/scripts/build-changelog.js +238 -0
  110. package/dist/scripts/build-metrics-report.js +331 -0
  111. package/dist/scripts/changelog-tests.js +118 -0
  112. package/dist/scripts/channel-probe-tests.js +103 -0
  113. package/dist/scripts/channel-probe.js +169 -0
  114. package/dist/scripts/channel-registry-tests.js +208 -0
  115. package/dist/scripts/companion-tests.js +25 -70
  116. package/dist/scripts/dida-cookie-probe.js +87 -0
  117. package/dist/scripts/dida-runner-stop-tests.js +311 -0
  118. package/dist/scripts/dida-sw-probe.js +114 -0
  119. package/dist/scripts/diff-test.js +17 -12
  120. package/dist/scripts/doctor-tests.js +564 -0
  121. package/dist/scripts/dsh-artifact-e2e.js +279 -0
  122. package/dist/scripts/dsh-artifact-web-e2e.js +675 -0
  123. package/dist/scripts/dsh-http-proxy-sse-proof.js +90 -0
  124. package/dist/scripts/dsh-runtime-closure-tests.js +182 -0
  125. package/dist/scripts/dsh-runtime-closure.js +162 -0
  126. package/dist/scripts/dsh-session-v3-migration-proof.js +109 -0
  127. package/dist/scripts/dsh-subprocess-local-proof.js +150 -0
  128. package/dist/scripts/dsh-target-closure-proof.js +178 -0
  129. package/dist/scripts/effect-tests.js +539 -0
  130. package/dist/scripts/engine-run.js +1 -3
  131. package/dist/scripts/engine-tests.js +16 -10
  132. package/dist/scripts/evaluation-cadence-tests.js +174 -0
  133. package/dist/scripts/evaluation-contract-tests.js +268 -0
  134. package/dist/scripts/extension-distribution-cli.js +39 -0
  135. package/dist/scripts/extension-distribution-tests.js +443 -0
  136. package/dist/scripts/extension-tests.js +988 -0
  137. package/dist/scripts/external-event-tests.js +350 -0
  138. package/dist/scripts/fact-gate-tests.js +869 -0
  139. package/dist/scripts/fixtures/extension-bridge-unref-child.mjs +21 -0
  140. package/dist/scripts/flight-hotel-anchor-363-registered-e2e.js +169 -0
  141. package/dist/scripts/flight-malformed-tests.js +159 -0
  142. package/dist/scripts/flyai-setup-tests.js +228 -0
  143. package/dist/scripts/flyai-setup-tool-tests.js +54 -0
  144. package/dist/scripts/flyai-tests.js +692 -0
  145. package/dist/scripts/flyai-tool-registration-contract-tests.js +91 -0
  146. package/dist/scripts/fx-contract-tests.js +201 -0
  147. package/dist/scripts/g5-guard-tests.js +131 -0
  148. package/dist/scripts/g5-guard.js +189 -0
  149. package/dist/scripts/gen-lunar-anchors.js +106 -0
  150. package/dist/scripts/geo-atlas-tests.js +283 -0
  151. package/dist/scripts/gotry-backend-kernel-tests.js +206 -0
  152. package/dist/scripts/gotry-try-demo-tests.js +79 -0
  153. package/dist/scripts/gotry-try-demo.js +49 -0
  154. package/dist/scripts/ground-transfer-tests.js +956 -0
  155. package/dist/scripts/hbcli-e2e-tests.js +159 -0
  156. package/dist/scripts/hbcli-live-optin-tests.js +96 -0
  157. package/dist/scripts/hbcli-release-contract-tests.js +122 -0
  158. package/dist/scripts/hbcli-tests.js +121 -69
  159. package/dist/scripts/health-watch-cli.js +73 -0
  160. package/dist/scripts/hotel-date-gate-tests.js +496 -0
  161. package/dist/scripts/hotelbyte-reconcile-tests.js +141 -0
  162. package/dist/scripts/hotelbyte-spawn-e2e-tests.js +373 -0
  163. package/dist/scripts/i18n-tests.js +41 -0
  164. package/dist/scripts/incident-tests.js +281 -87
  165. package/dist/scripts/issue-194-job-id-guard-tests.js +106 -0
  166. package/dist/scripts/issue-233-cancel-refund-commission-tests.js +392 -0
  167. package/dist/scripts/issue-271-liveness-tests.js +569 -0
  168. package/dist/scripts/issue-289-model-retry-real-tests.js +296 -0
  169. package/dist/scripts/issue-289-model-retry-tests.js +441 -0
  170. package/dist/scripts/issue-289-web-retry-e2e.js +630 -0
  171. package/dist/scripts/issue-338-home-city-e2e.js +577 -0
  172. package/dist/scripts/issue343-real-entry-e2e.js +160 -0
  173. package/dist/scripts/issue436-persisted-routing-e2e.js +247 -0
  174. package/dist/scripts/itinerary-artifact-tests.js +368 -0
  175. package/dist/scripts/itinerary-deck-artifact-tests.js +416 -0
  176. package/dist/scripts/itinerary-deck-export-tests.js +552 -0
  177. package/dist/scripts/itinerary-deck-tests.js +435 -0
  178. package/dist/scripts/itinerary-html-tests.js +426 -0
  179. package/dist/scripts/journey-tests.js +22 -27
  180. package/dist/scripts/kernel-manifest-evidence.js +109 -0
  181. package/dist/scripts/kernel-manifest-gate.js +126 -0
  182. package/dist/scripts/kernel-manifest-tests.js +212 -0
  183. package/dist/scripts/kernel-manifest-trace-entry.js +7 -0
  184. package/dist/scripts/kernel-manifest-trace-hook.mjs +28 -0
  185. package/dist/scripts/kernel-manifest.js +369 -0
  186. package/dist/scripts/lavish-local-tests.js +1226 -0
  187. package/dist/scripts/lavish-product-tools-tests.js +537 -0
  188. package/dist/scripts/ledger-repair-apply-tests.js +316 -0
  189. package/dist/scripts/ledger-repair-plan-tests.js +375 -0
  190. package/dist/scripts/ledger-tests.js +382 -246
  191. package/dist/scripts/ledger-workflow-crash.js +10 -20
  192. package/dist/scripts/managed-dsh-cleanup-diagnostic-proof.js +184 -0
  193. package/dist/scripts/managed-dsh-close-failure-proof.js +172 -0
  194. package/dist/scripts/managed-dsh-run-port-proof.js +153 -0
  195. package/dist/scripts/managed-dsh-terminal-proof.js +252 -0
  196. package/dist/scripts/map-tools-vendor-package-proof.js +365 -0
  197. package/dist/scripts/memory-capture-tests.js +242 -61
  198. package/dist/scripts/memory-decay-tests.js +18 -52
  199. package/dist/scripts/memory-lifecycle-tests.js +657 -0
  200. package/dist/scripts/memory-lifecycle.js +196 -0
  201. package/dist/scripts/memory-metrics.js +24 -12
  202. package/dist/scripts/memory-value-report.js +631 -0
  203. package/dist/scripts/memory-value-tests.js +328 -0
  204. package/dist/scripts/metrics-report-tests.js +151 -0
  205. package/dist/scripts/model-override-e2e.js +137 -0
  206. package/dist/scripts/nightly-evidence-tests.js +161 -0
  207. package/dist/scripts/nightly-evidence.js +286 -0
  208. package/dist/scripts/nudge-digest.js +39 -28
  209. package/dist/scripts/observability-tests.js +381 -0
  210. package/dist/scripts/onboarding-tests.js +161 -0
  211. package/dist/scripts/opensky-check.js +18 -13
  212. package/dist/scripts/opensky-tests.js +28 -28
  213. package/dist/scripts/persona-surface-guard-tests.js +49 -0
  214. package/dist/scripts/pnpm-dsh-closure-proof.js +17 -0
  215. package/dist/scripts/policy-anchor-359-registered-e2e.js +214 -0
  216. package/dist/scripts/price-drift-tests.js +340 -0
  217. package/dist/scripts/price-drift-watch.js +447 -0
  218. package/dist/scripts/probe-poi-tests.js +53 -45
  219. package/dist/scripts/product-metrics.js +483 -0
  220. package/dist/scripts/publish-preverify.js +110 -0
  221. package/dist/scripts/realtime-pricing-tests.js +76 -0
  222. package/dist/scripts/recall-tests.js +513 -0
  223. package/dist/scripts/replay-async.js +20 -18
  224. package/dist/scripts/replay-real.js +18 -18
  225. package/dist/scripts/replay.js +52 -82
  226. package/dist/scripts/session-attach-diagnose.js +20 -20
  227. package/dist/scripts/session-attach-poc.js +34 -37
  228. package/dist/scripts/session-benchmark.js +180 -0
  229. package/dist/scripts/session-dida-live-e2e.js +199 -0
  230. package/dist/scripts/session-extract-tests.js +14 -35
  231. package/dist/scripts/session-link-tests.js +478 -0
  232. package/dist/scripts/session-login.js +27 -46
  233. package/dist/scripts/session-tests.js +796 -96
  234. package/dist/scripts/session-zones-tests.js +358 -0
  235. package/dist/scripts/sf-live-benchmark.js +367 -0
  236. package/dist/scripts/sf-live-challenge-stop-tests.js +453 -0
  237. package/dist/scripts/sf-live-cli-tests.js +92 -0
  238. package/dist/scripts/sf-live-options.js +46 -0
  239. package/dist/scripts/sf-manifest-tests.js +30 -0
  240. package/dist/scripts/sf-manifest.js +33 -0
  241. package/dist/scripts/sf-soft-score-tests.js +67 -0
  242. package/dist/scripts/sf-summary-tests.js +324 -0
  243. package/dist/scripts/sf-summary.js +525 -0
  244. package/dist/scripts/share-tests.js +432 -0
  245. package/dist/scripts/skeleton-check.js +16 -14
  246. package/dist/scripts/skeleton-integration-test.js +28 -11
  247. package/dist/scripts/skills-contract-tests.js +51 -46
  248. package/dist/scripts/smoke-session-gate-tests.js +21 -0
  249. package/dist/scripts/smoke.js +690 -246
  250. package/dist/scripts/spawn-bounded-abort-tests.js +241 -0
  251. package/dist/scripts/sponsor-reuse-tests.js +262 -0
  252. package/dist/scripts/state-cli-tests.js +226 -101
  253. package/dist/scripts/state-cli.js +550 -199
  254. package/dist/scripts/state-repair-cli.js +66 -0
  255. package/dist/scripts/state-repair-tests.js +140 -0
  256. package/dist/scripts/static-golden-tests.js +165 -0
  257. package/dist/scripts/time-eval-tests.js +210 -192
  258. package/dist/scripts/travel-timeline-tests.js +29 -93
  259. package/dist/scripts/turn-handoff-collect-tests.js +169 -0
  260. package/dist/scripts/turn-handoff-collect.js +161 -0
  261. package/dist/scripts/turn-policy-tests.js +55 -0
  262. package/dist/scripts/typed-contract-canary.js +176 -0
  263. package/dist/scripts/tz-resolver-sanity.js +50 -0
  264. package/dist/scripts/tz-resolver-tests.js +584 -0
  265. package/dist/scripts/unified-tests.js +23 -19
  266. package/dist/scripts/visa-policy-tests.js +62 -0
  267. package/dist/scripts/weather-tests.js +276 -41
  268. package/dist/scripts/wish-channel-gate-tests.js +54 -0
  269. package/dist/scripts/write-gate-tests.js +522 -0
  270. package/dist/scripts/z3-lifecycle-fault-tests.js +188 -0
  271. package/dist/scripts/z3-lifecycle-tests.js +170 -0
  272. package/dist/scripts/z3-race-repeat-tests.js +39 -0
  273. package/dist/scripts/z3-race-tests.js +41 -0
  274. package/dist/src/artifact-gate.js +829 -0
  275. package/dist/src/backend/kernel.js +91 -0
  276. package/dist/src/backend/modules/booking-copilot.js +92 -0
  277. package/dist/src/backend/modules/booking-executor.js +124 -0
  278. package/dist/src/backend/modules/session-search.js +551 -0
  279. package/dist/src/benchmark-agent-conformance.js +578 -0
  280. package/dist/src/benchmark-environment-bridge.js +515 -0
  281. package/dist/src/benchmark-headless-child-diagnostics.js +166 -0
  282. package/dist/src/benchmark-tool-isolation.js +151 -0
  283. package/dist/src/bookable-facts.js +533 -0
  284. package/dist/src/booking-saga.js +97 -0
  285. package/dist/src/booking-surface/availability-policy.js +697 -0
  286. package/dist/src/booking-surface/booking-intent.js +43 -0
  287. package/dist/src/booking-surface/cancel-refund-commission.js +379 -0
  288. package/dist/src/booking-surface/canonical-schema.js +116 -0
  289. package/dist/src/booking-surface/contracts.js +75 -0
  290. package/dist/src/booking-surface/dsh-planner.js +1854 -0
  291. package/dist/src/booking-surface/dsh-plugin.js +378 -0
  292. package/dist/src/booking-surface/dsh-worker.js +98 -0
  293. package/dist/src/booking-surface/error-codes.js +231 -0
  294. package/dist/src/booking-surface/index.js +9 -0
  295. package/dist/src/booking-surface/managed-dsh-cleanup-diagnostic.js +97 -0
  296. package/dist/src/booking-surface/managed-dsh-run-port.js +244 -0
  297. package/dist/src/booking-surface/profile.js +24 -0
  298. package/dist/src/booking-surface/recovery-chain.js +367 -0
  299. package/dist/src/booking-surface/runtime.js +1968 -0
  300. package/dist/src/booking-surface/server.js +674 -0
  301. package/dist/src/booking-surface/startup.js +168 -0
  302. package/dist/src/booking-surface/validation.js +261 -0
  303. package/dist/src/bridge.js +20 -13
  304. package/dist/src/companions.js +48 -74
  305. package/dist/src/contracts.js +21 -43
  306. package/dist/src/dsh-llm.js +97 -111
  307. package/dist/src/engine.js +276 -193
  308. package/dist/src/evaluation-cadence.js +97 -0
  309. package/dist/src/evaluation-contracts.js +283 -0
  310. package/dist/src/flight-pack-adapter.js +54 -0
  311. package/dist/src/flight-pack-contract.js +2 -0
  312. package/dist/src/flyai-setup-tool.js +70 -0
  313. package/dist/src/gotry-backend.js +125 -0
  314. package/dist/src/hotel-date-gate.js +118 -0
  315. package/dist/src/i18n.js +88 -0
  316. package/dist/src/index.js +2227 -882
  317. package/dist/src/itinerary-deck.js +139 -0
  318. package/dist/src/itinerary-doc-shared.js +661 -0
  319. package/dist/src/itinerary-html.js +131 -0
  320. package/dist/src/journey.js +155 -108
  321. package/dist/src/lavish-tools.js +400 -0
  322. package/dist/src/ledger-repair-apply.js +538 -0
  323. package/dist/src/ledger-repair-plan.js +463 -0
  324. package/dist/src/loop.js +319 -160
  325. package/dist/src/memory-capture.js +180 -32
  326. package/dist/src/memory-decay.js +30 -14
  327. package/dist/src/memory-lifecycle.js +1310 -0
  328. package/dist/src/memory-utility.js +27 -40
  329. package/dist/src/mock-llm.js +36 -61
  330. package/dist/src/model.js +81 -36
  331. package/dist/src/realtime-pricing.js +103 -0
  332. package/dist/src/recall/card.js +74 -0
  333. package/dist/src/recall/evaluator.js +140 -0
  334. package/dist/src/recall/integration.js +17 -0
  335. package/dist/src/recall/tick.js +166 -0
  336. package/dist/src/session-link/plan-it-action.js +48 -0
  337. package/dist/src/session-link/session-link.js +248 -0
  338. package/dist/src/session-zones.js +507 -0
  339. package/dist/src/share/adapters.js +51 -0
  340. package/dist/src/share/share-consent.js +76 -0
  341. package/dist/src/share/share-deck.js +58 -0
  342. package/dist/src/share/share-token.js +146 -0
  343. package/dist/src/slot-spec.js +84 -106
  344. package/dist/src/state-ledger.js +435 -516
  345. package/dist/src/state-repair.js +299 -0
  346. package/dist/src/subagent-job-id-guard.js +58 -0
  347. package/dist/src/time-anchor.js +231 -33
  348. package/dist/src/tool-packet.js +20 -8
  349. package/dist/src/travel-slots.js +58 -35
  350. package/dist/src/travel-timeline.js +44 -63
  351. package/dist/src/turn-deadline.js +287 -0
  352. package/dist/src/turn-policy.js +118 -0
  353. package/dist/src/tz-resolver.js +143 -0
  354. package/dist/src/unified.js +535 -359
  355. package/dist/src/wish-pool.js +42 -12
  356. package/dist/src/write-gate.js +495 -0
  357. package/dist/src/z3-shared.js +284 -0
  358. package/extension/README.md +21 -0
  359. package/extension/README.zh-CN.md +21 -0
  360. package/extension/background.js +463 -0
  361. package/extension/content-bridge.js +270 -0
  362. package/extension/content-main.js +111 -0
  363. package/extension/manifest.json +60 -0
  364. package/package.json +407 -14
  365. package/schemas/booking.intent.schema.json +193 -0
  366. package/schemas/booking.surface.schema.json +2622 -0
  367. package/ts/capabilities/agent-reach-deep.ts +114 -0
  368. package/ts/capabilities/agent-reach.ts +198 -0
  369. package/ts/capabilities/anything.ts +255 -0
  370. package/ts/capabilities/artifacts.ts +428 -0
  371. package/ts/capabilities/fact-log.ts +54 -0
  372. package/ts/capabilities/flyai-config.ts +388 -0
  373. package/ts/capabilities/flyai.ts +1274 -0
  374. package/ts/capabilities/hbcli.ts +253 -71
  375. package/ts/capabilities/incident-log.ts +88 -59
  376. package/ts/capabilities/itinerary-artifact.ts +214 -0
  377. package/ts/capabilities/itinerary-deck-artifact.ts +218 -0
  378. package/ts/capabilities/itinerary-deck-export.ts +378 -0
  379. package/ts/capabilities/opensky.ts +121 -0
  380. package/ts/capabilities/session/action-cache.ts +148 -0
  381. package/ts/capabilities/session/adapters/ctrip-flight.ts +181 -0
  382. package/ts/capabilities/session/adapters/ctrip-hotel.ts +238 -0
  383. package/ts/capabilities/session/adapters/dida-portal.ts +338 -0
  384. package/ts/capabilities/session/adapters/meituan-local.ts +70 -0
  385. package/ts/capabilities/session/adapters/rail-12306.ts +392 -0
  386. package/ts/capabilities/session/benchmark.ts +276 -0
  387. package/ts/capabilities/session/bridge-ledger.ts +333 -0
  388. package/ts/capabilities/session/extension-bridge.ts +794 -0
  389. package/ts/capabilities/session/extension-channel.ts +144 -0
  390. package/ts/capabilities/session/extension-distribution.ts +266 -0
  391. package/ts/capabilities/session/extract.ts +54 -0
  392. package/ts/capabilities/session/golden-score.ts +139 -0
  393. package/ts/capabilities/session/health-watch.ts +264 -0
  394. package/ts/capabilities/session/read-guard.ts +141 -0
  395. package/ts/capabilities/session/static-flight-golden.ts +209 -0
  396. package/ts/capabilities/session/transport.ts +146 -0
  397. package/ts/capabilities/session/wizard.ts +140 -0
  398. package/ts/capabilities/session-consent.ts +211 -0
  399. package/ts/capabilities/session-login.ts +208 -0
  400. package/ts/capabilities/session-search.ts +893 -0
  401. package/ts/capabilities/weather.ts +330 -0
  402. package/ts/dsh-runtime/vendor/README.md +68 -0
  403. package/ts/dsh-runtime/vendor/dsh-map-tools/LICENSE +21 -0
  404. package/ts/dsh-runtime/vendor/dsh-map-tools/README.en.md +405 -0
  405. package/ts/dsh-runtime/vendor/dsh-map-tools/README.md +404 -0
  406. package/ts/dsh-runtime/vendor/dsh-map-tools/client/client.js +1584 -0
  407. package/ts/dsh-runtime/vendor/dsh-map-tools/cordis.patch.yml +5 -0
  408. package/ts/dsh-runtime/vendor/dsh-map-tools/icon.svg +5 -0
  409. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/amap.js +595 -0
  410. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/nominatim.js +63 -0
  411. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/osrm.js +58 -0
  412. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/clients/photon.js +55 -0
  413. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-file.js +87 -0
  414. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config-route.js +131 -0
  415. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/config.js +16 -0
  416. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/geo.js +232 -0
  417. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/index.js +120 -0
  418. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/settings-ns.js +40 -0
  419. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/staticmap-route.js +115 -0
  420. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/geocode.js +127 -0
  421. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/poi.js +84 -0
  422. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/tools/routes.js +267 -0
  423. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/amap.d.ts +90 -0
  424. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/nominatim.d.ts +17 -0
  425. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/osrm.d.ts +15 -0
  426. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/clients/photon.d.ts +22 -0
  427. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-file.d.ts +33 -0
  428. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config-route.d.ts +23 -0
  429. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/config.d.ts +23 -0
  430. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/geo.d.ts +61 -0
  431. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/index.d.ts +18 -0
  432. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/settings-ns.d.ts +14 -0
  433. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/staticmap-route.d.ts +31 -0
  434. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/geocode.d.ts +11 -0
  435. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/poi.d.ts +9 -0
  436. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/tools/routes.d.ts +75 -0
  437. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types/types.d.ts +68 -0
  438. package/ts/dsh-runtime/vendor/dsh-map-tools/lib/types.js +16 -0
  439. package/ts/dsh-runtime/vendor/dsh-map-tools/package.json +97 -0
  440. package/ts/package.json +293 -3
  441. package/ts/scripts/async-collect.ts +91 -0
  442. package/ts/scripts/map-tools-vendor-package-proof.ts +404 -0
  443. package/ts/scripts/skeleton-check.ts +1 -1
  444. package/ts/scripts/skeleton-integration-test.ts +23 -1
  445. package/ts/scripts/state-cli.ts +568 -0
  446. package/ts/scripts/turn-handoff-collect.ts +178 -0
  447. package/ts/src/artifact-gate.ts +991 -0
  448. package/ts/src/benchmark-agent-conformance.ts +619 -0
  449. package/ts/src/benchmark-environment-bridge.ts +538 -0
  450. package/ts/src/benchmark-headless-child-diagnostics.ts +184 -0
  451. package/ts/src/benchmark-tool-isolation.ts +166 -0
  452. package/ts/src/bookable-facts.ts +837 -0
  453. package/ts/src/booking-saga.ts +133 -0
  454. package/ts/src/booking-surface/availability-policy.ts +522 -0
  455. package/ts/src/booking-surface/booking-intent.ts +86 -0
  456. package/ts/src/booking-surface/cancel-refund-commission.ts +488 -0
  457. package/ts/src/booking-surface/canonical-schema.js +116 -0
  458. package/ts/src/booking-surface/contracts.ts +475 -0
  459. package/ts/src/booking-surface/dsh-planner.ts +1949 -0
  460. package/ts/src/booking-surface/dsh-plugin.js +378 -0
  461. package/ts/src/booking-surface/dsh-worker.ts +110 -0
  462. package/ts/src/booking-surface/error-codes.ts +241 -0
  463. package/ts/src/booking-surface/index.ts +9 -0
  464. package/ts/src/booking-surface/managed-dsh-cleanup-diagnostic.ts +151 -0
  465. package/ts/src/booking-surface/managed-dsh-run-port.ts +273 -0
  466. package/ts/src/booking-surface/profile.ts +42 -0
  467. package/ts/src/booking-surface/recovery-chain.ts +409 -0
  468. package/ts/src/booking-surface/runtime.ts +1793 -0
  469. package/ts/src/booking-surface/server.ts +733 -0
  470. package/ts/src/booking-surface/startup.ts +201 -0
  471. package/ts/src/booking-surface/validation.ts +217 -0
  472. package/ts/src/companions.ts +113 -0
  473. package/ts/src/contracts.ts +13 -3
  474. package/ts/src/dsh-llm.ts +44 -11
  475. package/ts/src/flyai-setup-tool.ts +77 -0
  476. package/ts/src/index.ts +1948 -198
  477. package/ts/src/itinerary-deck.ts +189 -0
  478. package/ts/src/itinerary-doc-shared.ts +741 -0
  479. package/ts/src/itinerary-html.ts +171 -0
  480. package/ts/src/loop.ts +223 -25
  481. package/ts/src/memory-capture.ts +283 -0
  482. package/ts/src/memory-decay.ts +55 -0
  483. package/ts/src/memory-utility.ts +70 -0
  484. package/ts/src/mock-llm.ts +4 -8
  485. package/ts/src/model.ts +88 -2
  486. package/ts/src/recall/card.ts +106 -0
  487. package/ts/src/recall/evaluator.ts +170 -0
  488. package/ts/src/recall/integration.ts +35 -0
  489. package/ts/src/recall/tick.ts +213 -0
  490. package/ts/src/session-link/plan-it-action.ts +78 -0
  491. package/ts/src/session-link/session-link.ts +275 -0
  492. package/ts/src/share/adapters.ts +93 -0
  493. package/ts/src/share/share-consent.ts +105 -0
  494. package/ts/src/share/share-deck.ts +85 -0
  495. package/ts/src/share/share-token.ts +166 -0
  496. package/ts/src/slot-spec.ts +172 -0
  497. package/ts/src/state-ledger.ts +912 -0
  498. package/ts/src/subagent-job-id-guard.ts +72 -0
  499. package/ts/src/time-anchor.ts +338 -0
  500. package/ts/src/tool-packet.ts +32 -0
  501. package/ts/src/travel-slots.ts +219 -0
  502. package/ts/src/travel-timeline.ts +83 -0
  503. package/ts/src/turn-deadline.ts +366 -0
  504. package/ts/src/turn-policy.ts +154 -0
  505. package/ts/src/unified.ts +354 -88
  506. package/ts/src/wish-pool.ts +79 -0
  507. package/dist/scripts/session-attach-wait.js +0 -41
@@ -0,0 +1,569 @@
1
+ /**
2
+ * Maintained installed-dsh liveness proof for issue #271.
3
+ *
4
+ * Each case is an external bounded parent of a real Node24 dsh package child,
5
+ * with a fresh private HOME/DSH_HOME/state directory. The dsh fixture starts a
6
+ * real descendant so a direct-child-only cleanup cannot pass. No model,
7
+ * provider, Chrome session, credential, or shared GoTry state is used.
8
+ */
9
+ import assert from 'node:assert/strict';
10
+ import { spawn } from 'node:child_process';
11
+ import { createRequire } from 'node:module';
12
+ import { copyFileSync, existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, symlinkSync, writeFileSync } from 'node:fs';
13
+ import { tmpdir } from 'node:os';
14
+ import { join } from 'node:path';
15
+ import { fileURLToPath, pathToFileURL } from 'node:url';
16
+ import { Context } from '@deepseek-ai/cordis';
17
+ import { LocalSubprocessRuntime } from '@deepseek-ai/dsh-subprocess-local';
18
+ import { recordIncident, resolveIncidentsPath } from '../capabilities/incident-log.js';
19
+ import { PROCESS_LIVENESS_BOUNDS, isOwnedProcessGroupEmpty, spawnOwnedChild, terminateOwnedChild, } from '../../bin/gotry-process-liveness.js';
20
+ const require = createRequire(import.meta.url);
21
+ const dshBin = require.resolve('@deepseek-ai/dsh/lib/bin.js');
22
+ const dshVersion = JSON.parse(readFileSync(require.resolve('@deepseek-ai/dsh/package.json'), 'utf8')).version;
23
+ const repoRoot = fileURLToPath(new URL('../../', import.meta.url));
24
+ const node24 = process.execPath;
25
+ const EXTERNAL_BOUND_MS = 8_000;
26
+ assert.equal(dshVersion, '0.2.0-rc.2', 'proof must run against the lock-selected installed dsh package');
27
+ function privateEnv(root) {
28
+ return {
29
+ PATH: process.env.PATH,
30
+ HOME: root,
31
+ DSH_HOME: join(root, 'dsh-home'),
32
+ TMPDIR: root,
33
+ TEMP: root,
34
+ TMP: root,
35
+ };
36
+ }
37
+ function waitForClose(child, timeoutMs) {
38
+ return new Promise((resolve) => {
39
+ let settled = false;
40
+ const timer = setTimeout(() => {
41
+ if (settled)
42
+ return;
43
+ settled = true;
44
+ resolve({ timedOut: true });
45
+ }, timeoutMs);
46
+ child.once('close', (code, signal) => {
47
+ if (settled)
48
+ return;
49
+ settled = true;
50
+ clearTimeout(timer);
51
+ resolve({ code, signal });
52
+ });
53
+ child.once('error', (error) => {
54
+ if (settled)
55
+ return;
56
+ settled = true;
57
+ clearTimeout(timer);
58
+ resolve({ code: null, signal: null, error: error instanceof Error ? error.message : String(error) });
59
+ });
60
+ });
61
+ }
62
+ function withExternalBound(promise, timeoutMs, label) {
63
+ return new Promise((resolve, reject) => {
64
+ const timer = setTimeout(() => reject(new Error(`${label} exceeded external ${timeoutMs}ms bound`)), timeoutMs);
65
+ promise.then((value) => { clearTimeout(timer); resolve(value); }, (error) => { clearTimeout(timer); reject(error); });
66
+ });
67
+ }
68
+ async function waitForFile(path, timeoutMs) {
69
+ const deadline = Date.now() + timeoutMs;
70
+ while (Date.now() < deadline) {
71
+ if (existsSync(path))
72
+ return;
73
+ await new Promise((resolve) => setTimeout(resolve, 20));
74
+ }
75
+ throw new Error(`fixture readiness timeout: ${path}`);
76
+ }
77
+ function pidAlive(pid) {
78
+ try {
79
+ process.kill(pid, 0);
80
+ return true;
81
+ }
82
+ catch {
83
+ return false;
84
+ }
85
+ }
86
+ function incidentLines(stateRoot) {
87
+ const path = resolveIncidentsPath(stateRoot);
88
+ if (!existsSync(path))
89
+ return [];
90
+ return readFileSync(path, 'utf8').trim().split(/\r?\n/).filter(Boolean);
91
+ }
92
+ function writeFailureFixture(root, name, marker, pidFile) {
93
+ const trigger = name === 'child-crash'
94
+ ? "throw new Error('issue271-child-crash')"
95
+ : "Promise.reject(new Error('issue271-rejected-promise'))";
96
+ const plugin = join(root, `${name}.mjs`);
97
+ writeFileSync(plugin, [
98
+ "import { spawn } from 'node:child_process'",
99
+ "import { writeFileSync } from 'node:fs'",
100
+ `export const name = 'issue271-${name}'`,
101
+ 'export const inject = []',
102
+ 'export function apply() {',
103
+ ` const descendant = spawn(process.execPath, ['-e', 'setInterval(() => {}, 60000)'], { stdio: 'ignore' })`,
104
+ ` writeFileSync(${JSON.stringify(pidFile)}, String(descendant.pid))`,
105
+ ` setTimeout(() => writeFileSync(${JSON.stringify(marker)}, 'unsafe-continuation'), 250)`,
106
+ ` ${trigger}`,
107
+ '}',
108
+ '',
109
+ ].join('\n'));
110
+ const patch = join(root, `${name}.patch.yml`);
111
+ writeFileSync(patch, `- insert:\n - id: issue271-${name}\n name: '${plugin}'\n`);
112
+ return patch;
113
+ }
114
+ async function runDshFailureCase(name) {
115
+ const root = mkdtempSync(join(tmpdir(), `gotry-271-${name}-`));
116
+ const marker = join(root, 'unsafe.marker');
117
+ const pidFile = join(root, 'descendant.pid');
118
+ const patch = writeFailureFixture(root, name, marker, pidFile);
119
+ const owned = spawnOwnedChild(node24, [dshBin, '--profile', 'sdk-minimal', '--patch', patch], {
120
+ cwd: root,
121
+ env: privateEnv(root),
122
+ stdio: ['ignore', 'pipe', 'pipe'],
123
+ });
124
+ let stderr = '';
125
+ owned.child.stderr?.setEncoding('utf8');
126
+ owned.child.stderr?.on('data', (chunk) => { stderr += chunk.toString(); });
127
+ // 0.2.0-rc.2 起可选插件 apply 失败是 fail-soft:宿主保持存活,错误留在 stderr
128
+ // (`dsh: warning: N entry did not activate` + 插件错误栈),由宿主的监督者
129
+ // (spawnOwnedChild 的进程组)负责清收;0.1.5-rc.1 是 fail-loud 自行 exit 1。
130
+ // 两条路径都证明同一契约:错误有 stderr 证据 + 受控树被完整清收,不假设宿主必须自尽。
131
+ const evidencePattern = new RegExp(`issue271-${name.replace('-', '[- ]')}`);
132
+ let selfExit;
133
+ const deadline = Date.now() + EXTERNAL_BOUND_MS;
134
+ while (Date.now() < deadline) {
135
+ if (evidencePattern.test(stderr))
136
+ break;
137
+ const probe = await waitForClose(owned.child, 200);
138
+ if (!('timedOut' in probe)) {
139
+ selfExit = probe;
140
+ break;
141
+ }
142
+ }
143
+ const sawEvidence = evidencePattern.test(stderr);
144
+ if (!sawEvidence && !selfExit)
145
+ throw new Error(`${name} exceeded external ${EXTERNAL_BOUND_MS}ms bound`);
146
+ const cleanup = await terminateOwnedChild({ child: owned.child, groupPid: owned.groupPid, ...PROCESS_LIVENESS_BOUNDS });
147
+ const closeAfterCleanup = await waitForClose(owned.child, 2_000);
148
+ await new Promise((resolve) => setTimeout(resolve, 350));
149
+ const descendantPid = Number(readFileSync(pidFile, 'utf8'));
150
+ if (selfExit && !sawEvidence) {
151
+ // fail-loud 自退路径必须仍是 exit 1 且未执行失败后续标记(0.1.5 行为回归栅栏)。
152
+ assert.equal(selfExit.code, 1, `${name} dsh child must exit 1: ${JSON.stringify(selfExit)}`);
153
+ assert.equal(selfExit.signal, null, `${name} dsh child must not report a signal: ${JSON.stringify(selfExit)}`);
154
+ assert.equal(existsSync(marker), false, `${name} must not execute the post-failure marker`);
155
+ }
156
+ assert.match(stderr, evidencePattern, `${name} must preserve dsh stderr evidence`);
157
+ assert.equal(pidAlive(descendantPid), false, `${name} descendant ${descendantPid} must be gone after bounded cleanup`);
158
+ assert.equal(isOwnedProcessGroupEmpty(owned.groupPid), true, `${name} process group must be empty`);
159
+ const finalOutcome = selfExit
160
+ ?? ('timedOut' in closeAfterCleanup ? { code: null, signal: null } : closeAfterCleanup);
161
+ const stateRoot = join(root, 'state');
162
+ assert.equal(recordIncident({
163
+ ts: new Date().toISOString(),
164
+ kind: 'plugin_error',
165
+ message: `issue271 ${name}: child exit=${finalOutcome.code} signal=${finalOutcome.signal}`,
166
+ source: 'issue-271-liveness-test',
167
+ }, stateRoot), true);
168
+ const lines = incidentLines(stateRoot);
169
+ assert.equal(lines.length, 1, `${name} incident evidence must be append-only and single-line`);
170
+ assert.match(lines[0], new RegExp(`"message":"issue271 ${name}: child exit=`));
171
+ const result = { case: name, dshVersion, externalBoundMs: EXTERNAL_BOUND_MS, child: finalOutcome, failSoft: sawEvidence && !selfExit, stderr: stderr.slice(-4_000), incidentLines: lines, descendantPid, cleanup };
172
+ rmSync(root, { recursive: true, force: true });
173
+ return result;
174
+ }
175
+ async function runSpawnErrorCase() {
176
+ const root = mkdtempSync(join(tmpdir(), 'gotry-271-spawn-error-'));
177
+ const ctx = new Context();
178
+ const fiber = ctx.plugin(LocalSubprocessRuntime);
179
+ await fiber;
180
+ const stateRoot = join(root, 'state');
181
+ try {
182
+ const handle = ctx.subprocess.spawn({
183
+ argv: [join(root, 'missing-executable')],
184
+ cwd: root,
185
+ stdio: { stdin: 'ignore', stdout: { maxBytes: 1_024 }, stderr: { maxBytes: 4_096 } },
186
+ graceMs: 100,
187
+ });
188
+ let errorMessage = '';
189
+ await assert.rejects(withExternalBound(handle.done, EXTERNAL_BOUND_MS, 'spawn-error done'), (error) => {
190
+ errorMessage = error instanceof Error ? error.message : String(error);
191
+ return /ENOENT/.test(errorMessage);
192
+ }, 'installed subprocess provider must preserve spawn ENOENT as a rejected done promise');
193
+ assert.equal(await handle.waitForExit(AbortSignal.timeout(EXTERNAL_BOUND_MS)), true, 'spawn-error managed range must be empty');
194
+ assert.equal(recordIncident({
195
+ ts: new Date().toISOString(),
196
+ kind: 'plugin_error',
197
+ message: `issue271 spawn-error: ${errorMessage}`,
198
+ source: 'issue271-liveness-test',
199
+ }, stateRoot), true);
200
+ const lines = incidentLines(stateRoot);
201
+ assert.equal(lines.length, 1);
202
+ assert.match(lines[0], /issue271 spawn-error: spawn .* ENOENT/);
203
+ const result = { case: 'spawn-error', dshVersion, externalBoundMs: EXTERNAL_BOUND_MS, child: { exitCode: null, signal: null, doneRejected: true }, stderr: errorMessage, incidentLines: lines, managedRangeEmpty: true };
204
+ await ctx.fiber.dispose();
205
+ rmSync(root, { recursive: true, force: true });
206
+ return result;
207
+ }
208
+ catch (error) {
209
+ await ctx.fiber.dispose().catch(() => { });
210
+ rmSync(root, { recursive: true, force: true });
211
+ throw error;
212
+ }
213
+ }
214
+ function writeSignalHost(root, signal, marker, pidFile) {
215
+ const helperUrl = pathToFileURL(join(repoRoot, 'bin/gotry-process-liveness.js')).href;
216
+ const host = join(root, `signal-host-${signal}.mjs`);
217
+ writeFileSync(host, [
218
+ `import { spawnOwnedChild, terminateOwnedChild, PROCESS_LIVENESS_BOUNDS } from ${JSON.stringify(helperUrl)}`,
219
+ "import { existsSync, writeFileSync } from 'node:fs'",
220
+ `const dsh = spawnOwnedChild(process.execPath, [${JSON.stringify(dshBin)}, '--profile', 'sdk-minimal', '--patch', ${JSON.stringify(join(root, 'signal.patch.yml'))}], { cwd: ${JSON.stringify(root)}, env: process.env, stdio: ['pipe', 'ignore', 'pipe'] })`,
221
+ "dsh.child.stderr?.resume()",
222
+ `let stopping = false; const onSignal = () => { if (stopping) return; stopping = true; void (async () => { await terminateOwnedChild({ child: dsh.child, groupPid: dsh.groupPid, signal: ${JSON.stringify(signal)}, ...PROCESS_LIVENESS_BOUNDS }); process.off(${JSON.stringify(signal)}, onSignal); process.kill(process.pid, ${JSON.stringify(signal)}) })() }; process.on(${JSON.stringify(signal)}, onSignal)`,
223
+ `const deadline = Date.now() + ${EXTERNAL_BOUND_MS}`,
224
+ `const ready = setInterval(() => { if (Date.now() > deadline) { clearInterval(ready); process.exit(124) }; try { if (existsSync(${JSON.stringify(pidFile)})) { clearInterval(ready); process.stdout.write('READY\\n'); setTimeout(() => writeFileSync(${JSON.stringify(marker)}, 'unsafe-continuation'), 300) } } catch {} }, 20)`,
225
+ '',
226
+ ].join('\n'));
227
+ return host;
228
+ }
229
+ async function runParentSignalCase(signal) {
230
+ const root = mkdtempSync(join(tmpdir(), `gotry-271-${signal}-`));
231
+ const marker = join(root, 'unsafe.marker');
232
+ const pidFile = join(root, 'descendant.pid');
233
+ const plugin = join(root, 'signal-plugin.mjs');
234
+ writeFileSync(plugin, [
235
+ "import { spawn } from 'node:child_process'",
236
+ "import { writeFileSync } from 'node:fs'",
237
+ "export const name = 'issue271-parent-signal'",
238
+ 'export const inject = []',
239
+ 'export function apply() {',
240
+ ` const descendant = spawn(process.execPath, ['-e', 'setInterval(() => {}, 60000)'], { stdio: 'ignore' })`,
241
+ ` writeFileSync(${JSON.stringify(pidFile)}, String(descendant.pid))`,
242
+ '}',
243
+ '',
244
+ ].join('\n'));
245
+ writeFileSync(join(root, 'signal.patch.yml'), `- insert:\n - id: issue271-parent-signal\n name: '${plugin}'\n`);
246
+ const host = writeSignalHost(root, signal, marker, pidFile);
247
+ const parent = spawn(node24, [host], { cwd: root, env: privateEnv(root), stdio: ['ignore', 'pipe', 'pipe'] });
248
+ let stdout = '';
249
+ let stderr = '';
250
+ parent.stdout?.setEncoding('utf8');
251
+ parent.stdout?.on('data', (chunk) => { stdout += chunk; });
252
+ parent.stderr?.setEncoding('utf8');
253
+ parent.stderr?.on('data', (chunk) => { stderr += chunk; });
254
+ await waitForFile(pidFile, EXTERNAL_BOUND_MS);
255
+ process.kill(parent.pid, signal);
256
+ const outcome = await waitForClose(parent, EXTERNAL_BOUND_MS);
257
+ if ('timedOut' in outcome)
258
+ throw new Error(`${signal} parent exceeded external ${EXTERNAL_BOUND_MS}ms bound`);
259
+ const descendantPid = Number(readFileSync(pidFile, 'utf8'));
260
+ assert.equal(outcome.code, null, `${signal} parent must preserve signal termination: ${JSON.stringify(outcome)}`);
261
+ assert.equal(outcome.signal, signal, `${signal} parent must report its original signal: ${JSON.stringify(outcome)}`);
262
+ assert.match(stdout, /READY/, `${signal} case must observe a ready real dsh child`);
263
+ assert.equal(existsSync(marker), false, `${signal} must not execute the post-failure marker`);
264
+ assert.equal(pidAlive(descendantPid), false, `${signal} descendant ${descendantPid} must be gone`);
265
+ const stateRoot = join(root, 'state');
266
+ assert.equal(recordIncident({
267
+ ts: new Date().toISOString(),
268
+ kind: 'plugin_error',
269
+ message: `issue271 parent signal=${signal}; parent exit=${outcome.code} signal=${outcome.signal}`,
270
+ source: 'issue271-liveness-test',
271
+ }, stateRoot), true);
272
+ const lines = incidentLines(stateRoot);
273
+ assert.equal(lines.length, 1);
274
+ assert.match(lines[0], new RegExp(`parent signal=${signal}`));
275
+ const result = { case: signal, dshVersion, externalBoundMs: EXTERNAL_BOUND_MS, parent: outcome, stdout, stderr: stderr.slice(-4_000), incidentLines: lines, descendantPid, processGroupEmpty: true };
276
+ rmSync(root, { recursive: true, force: true });
277
+ return result;
278
+ }
279
+ const PRODUCT_EXTERNAL_BOUND_MS = 8_000;
280
+ function forceKillGroup(pid) {
281
+ if (!pid || process.platform === 'win32')
282
+ return;
283
+ try {
284
+ process.kill(-pid, 'SIGKILL');
285
+ }
286
+ catch { /* already gone */ }
287
+ }
288
+ function writeProductFixture(root, options = { writeTerminalOutput: false, mode: 'web' }) {
289
+ const binDir = join(root, 'bin');
290
+ const tsSrcDir = join(root, 'ts', 'src');
291
+ const tsCapabilitiesDir = join(root, 'ts', 'capabilities');
292
+ const dshDir = join(root, 'node_modules', '@deepseek-ai', 'dsh');
293
+ mkdirSync(binDir, { recursive: true });
294
+ mkdirSync(tsSrcDir, { recursive: true });
295
+ mkdirSync(tsCapabilitiesDir, { recursive: true });
296
+ mkdirSync(join(dshDir, 'lib'), { recursive: true });
297
+ for (const file of ['gotry-inner.js', 'gotry-bootstrap.js', 'gotry-runtime-resolution.js', 'gotry-process-liveness.js']) {
298
+ copyFileSync(join(repoRoot, 'bin', file), join(binDir, file));
299
+ }
300
+ copyFileSync(join(repoRoot, 'ts', 'capabilities', 'incident-log.ts'), join(tsCapabilitiesDir, 'incident-log.ts'));
301
+ copyFileSync(join(repoRoot, 'ts', 'src', 'tool-packet.ts'), join(tsSrcDir, 'tool-packet.ts'));
302
+ copyFileSync(join(repoRoot, 'cordis.gotry-patch.yml'), join(root, 'cordis.gotry-patch.yml'));
303
+ // Symlink dist so benchmark mode loads its bridge/diagnostic/conformance modules
304
+ // without needing a tsx loader inside the fixture (gotry-inner spawns node directly).
305
+ // The fixture is a fresh private stateRoot; only the read-only built JS is reused.
306
+ try {
307
+ symlinkSync(join(repoRoot, 'dist'), join(root, 'dist'), 'dir');
308
+ }
309
+ catch { /* dist already present or unsupported */ }
310
+ writeFileSync(join(tsSrcDir, 'index.ts'), 'export {}\n');
311
+ writeFileSync(join(root, 'package.json'), JSON.stringify({ name: 'gotry-issue271-fixture', type: 'module', version: '0.0.0' }) + '\n');
312
+ writeFileSync(join(dshDir, 'package.json'), JSON.stringify({ name: '@deepseek-ai/dsh', type: 'module', version: dshVersion }) + '\n');
313
+ let configPath;
314
+ if (options.writeTerminalOutput) {
315
+ const lookupInputSchema = { type: 'object', properties: { city: { type: 'string', description: 'A city name' } }, required: ['city'], additionalProperties: false };
316
+ const terminalBodySchema = { type: 'object', properties: { status: { type: 'string' }, payload: { type: 'string' } }, required: [], additionalProperties: false };
317
+ const benchmarkConfig = {
318
+ schema_version: 'gotry_benchmark_environment_bridge_v4',
319
+ enabled: true,
320
+ executable: process.execPath,
321
+ cwd: root,
322
+ argv_prefix: ['true'],
323
+ tools: [{
324
+ name: 'lookup',
325
+ description: 'Stub lookup tool for inherited-pipe liveness proof',
326
+ input_schema: lookupInputSchema,
327
+ output_keys: ['marker', 'leaked'],
328
+ domain_outcomes: [{ status: 'miss', code: 'NOT_FOUND', recovery: 'none' }],
329
+ }],
330
+ timeout_ms: 10_000,
331
+ max_output_bytes: 4_096,
332
+ terminal_output: { tag: 'benchmark_terminal', max_bytes: 4_096, body_schema: terminalBodySchema },
333
+ isolation: { mode: 'host-enforced', writes: 'forbidden', network: 'denied' },
334
+ };
335
+ configPath = join(root, 'benchmark-env-config.json');
336
+ writeFileSync(configPath, JSON.stringify(benchmarkConfig) + '\n');
337
+ }
338
+ const leaderPid = join(root, 'dsh-leader.pid');
339
+ const leaderExit = join(root, 'dsh-leader.exit');
340
+ const ready = join(root, 'fixture.ready');
341
+ const descendantPid = join(root, 'descendant.pid');
342
+ const marker = join(root, 'unsafe.marker');
343
+ const descendantCode = [
344
+ "import { writeFileSync } from 'node:fs'",
345
+ `const marker = ${JSON.stringify(marker)}`,
346
+ "if (process.env.GOTRY_271_RESIST_TERM === '1') { process.on('SIGTERM', () => {}); process.on('SIGINT', () => {}) }",
347
+ "setTimeout(() => writeFileSync(marker, 'unsafe-continuation'), Number(process.env.GOTRY_271_MARKER_DELAY_MS ?? '300'))",
348
+ 'setInterval(() => {}, 60_000)',
349
+ ].join(';');
350
+ writeFileSync(join(dshDir, 'lib', 'bin.js'), [
351
+ "import { spawn } from 'node:child_process'",
352
+ "import { writeFileSync } from 'node:fs'",
353
+ `const leaderPid = ${JSON.stringify(leaderPid)}`,
354
+ `const leaderExit = ${JSON.stringify(leaderExit)}`,
355
+ `const ready = ${JSON.stringify(ready)}`,
356
+ `const descendantPid = ${JSON.stringify(descendantPid)}`,
357
+ `const descendant = spawn(process.execPath, ['--input-type=module', '-e', ${JSON.stringify(descendantCode)}], { stdio: 'inherit', env: process.env })`,
358
+ options.writeTerminalOutput
359
+ ? "if (process.env.GOTRY_271_LEADER_TERMINAL === '1') process.stdout.write('<benchmark_terminal>{\\\"status\\\":\\\"succeeded\\\"}</benchmark_terminal>\\n')"
360
+ : '',
361
+ 'writeFileSync(leaderPid, String(process.pid))',
362
+ 'writeFileSync(descendantPid, String(descendant.pid))',
363
+ 'writeFileSync(ready, \'ready\')',
364
+ "process.on('exit', () => writeFileSync(leaderExit, 'exit'))",
365
+ "setTimeout(() => { writeFileSync(leaderExit, 'exit'); process.exit(Number(process.env.GOTRY_271_LEADER_EXIT ?? '1')) }, 60)",
366
+ '',
367
+ ].filter(Boolean).join('\n'));
368
+ return { entrypoint: join(binDir, 'gotry-inner.js'), leaderPid, leaderExit, ready, descendantPid, marker, configPath };
369
+ }
370
+ async function runProductEntrypointCase(name, exitCode, resistant) {
371
+ const root = mkdtempSync(join(tmpdir(), `gotry-271-followup-${name}-`));
372
+ const fixture = writeProductFixture(root);
373
+ const parent = spawn(node24, [fixture.entrypoint, 'web', '--no-open'], {
374
+ cwd: root,
375
+ env: {
376
+ ...privateEnv(root),
377
+ GOTRY_ONBOARDING_SKIP: '1',
378
+ GOTRY_SESSION_LIVE: '0',
379
+ GOTRY_HBCLI_LIVE: '0',
380
+ GOTRY_HOTELBYTE_SKILLS_LIVE: '0',
381
+ GOTRY_271_LEADER_EXIT: String(exitCode),
382
+ GOTRY_271_RESIST_TERM: resistant ? '1' : '0',
383
+ GOTRY_271_MARKER_DELAY_MS: resistant ? '7000' : '300',
384
+ },
385
+ detached: process.platform !== 'win32',
386
+ stdio: ['ignore', 'pipe', 'pipe'],
387
+ });
388
+ let stdout = '';
389
+ let stderr = '';
390
+ parent.stdout?.setEncoding('utf8');
391
+ parent.stdout?.on('data', (chunk) => { stdout += chunk; });
392
+ parent.stderr?.setEncoding('utf8');
393
+ parent.stderr?.on('data', (chunk) => { stderr += chunk; });
394
+ const startedAt = Date.now();
395
+ const deadline = startedAt + PRODUCT_EXTERNAL_BOUND_MS;
396
+ const remainingBound = () => Math.max(1, deadline - Date.now());
397
+ let outcome;
398
+ let before = {};
399
+ try {
400
+ await waitForFile(fixture.ready, remainingBound());
401
+ await waitForFile(fixture.leaderExit, remainingBound());
402
+ const leader = Number(readFileSync(fixture.leaderPid, 'utf8'));
403
+ const descendant = Number(readFileSync(fixture.descendantPid, 'utf8'));
404
+ before = {
405
+ leaderExitObserved: true,
406
+ leaderPid: leader,
407
+ descendantPid: descendant,
408
+ descendantAlive: pidAlive(descendant),
409
+ processGroupEmpty: isOwnedProcessGroupEmpty(leader),
410
+ closeDelayedBoundary: pidAlive(descendant),
411
+ };
412
+ outcome = await waitForClose(parent, remainingBound());
413
+ if ('timedOut' in outcome) {
414
+ const snapshot = {
415
+ case: name,
416
+ externalBoundMs: PRODUCT_EXTERNAL_BOUND_MS,
417
+ parent: outcome,
418
+ before,
419
+ marker: existsSync(fixture.marker),
420
+ incidentLines: incidentLines(root),
421
+ stderr: stderr.slice(-4_000),
422
+ };
423
+ throw new Error(`product entrypoint liveness regression: ${JSON.stringify(snapshot)}`);
424
+ }
425
+ await new Promise((resolve) => setTimeout(resolve, 350));
426
+ const afterLeader = Number(readFileSync(fixture.leaderPid, 'utf8'));
427
+ const afterDescendant = Number(readFileSync(fixture.descendantPid, 'utf8'));
428
+ const lines = incidentLines(root);
429
+ const after = {
430
+ parentAlive: pidAlive(parent.pid ?? -1),
431
+ leader: { code: exitCode, signal: null },
432
+ descendantAlive: pidAlive(afterDescendant),
433
+ processGroupEmpty: isOwnedProcessGroupEmpty(afterLeader),
434
+ marker: existsSync(fixture.marker),
435
+ };
436
+ assert.equal(outcome.code, exitCode, `${name} product must preserve leader exit code: ${JSON.stringify(outcome)}`);
437
+ assert.equal(outcome.signal, null, `${name} product must preserve a normal leader exit: ${JSON.stringify(outcome)}`);
438
+ assert.equal(after.parentAlive, false, `${name} product parent must be gone within the external bound`);
439
+ assert.equal(after.descendantAlive, false, `${name} must reap the inherited-pipe descendant`);
440
+ assert.equal(after.processGroupEmpty, true, `${name} owned dsh group must be empty`);
441
+ assert.equal(after.marker, false, `${name} must not run the post-failure marker`);
442
+ if (exitCode !== 0) {
443
+ assert.equal(lines.length, 1, `${name} product must append exactly one incident`);
444
+ assert.match(lines[0], new RegExp(`gotry spawn exit: web code=${exitCode} signal=null`));
445
+ }
446
+ else {
447
+ assert.equal(lines.length, 0, `${name} clean exit must not invent an incident`);
448
+ }
449
+ return {
450
+ case: name,
451
+ productEntrypoint: fixture.entrypoint,
452
+ externalBoundMs: PRODUCT_EXTERNAL_BOUND_MS,
453
+ elapsedMs: Date.now() - startedAt,
454
+ parent: outcome,
455
+ stderr: stderr.slice(-4_000),
456
+ incidentLines: lines,
457
+ before,
458
+ after,
459
+ };
460
+ }
461
+ finally {
462
+ forceKillGroup(parent.pid ?? null);
463
+ forceKillGroup(Number(existsSync(fixture.leaderPid) ? readFileSync(fixture.leaderPid, 'utf8') : 0));
464
+ rmSync(root, { recursive: true, force: true });
465
+ }
466
+ }
467
+ async function runBenchmarkSuccessCase(name, resistant) {
468
+ const root = mkdtempSync(join(tmpdir(), `gotry-271-followup-${name}-`));
469
+ const fixture = writeProductFixture(root, { writeTerminalOutput: true, mode: 'headless' });
470
+ if (!fixture.configPath)
471
+ throw new Error('benchmark fixture must produce a config path');
472
+ const parent = spawn(node24, [fixture.entrypoint, 'bridge smoke'], {
473
+ cwd: root,
474
+ env: {
475
+ ...privateEnv(root),
476
+ GOTRY_BENCHMARK_ENV_CONFIG: fixture.configPath,
477
+ GOTRY_271_LEADER_EXIT: '0',
478
+ GOTRY_271_LEADER_TERMINAL: '1',
479
+ GOTRY_271_RESIST_TERM: resistant ? '1' : '0',
480
+ GOTRY_271_MARKER_DELAY_MS: resistant ? '7000' : '300',
481
+ },
482
+ detached: process.platform !== 'win32',
483
+ stdio: ['ignore', 'pipe', 'pipe'],
484
+ });
485
+ let stdout = '';
486
+ let stderr = '';
487
+ parent.stdout?.setEncoding('utf8');
488
+ parent.stdout?.on('data', (chunk) => { stdout += chunk; });
489
+ parent.stderr?.setEncoding('utf8');
490
+ parent.stderr?.on('data', (chunk) => { stderr += chunk; });
491
+ const startedAt = Date.now();
492
+ const deadline = startedAt + PRODUCT_EXTERNAL_BOUND_MS;
493
+ const remainingBound = () => Math.max(1, deadline - Date.now());
494
+ let outcome;
495
+ let before = {};
496
+ try {
497
+ await waitForFile(fixture.ready, remainingBound());
498
+ await waitForFile(fixture.leaderExit, remainingBound());
499
+ const leader = Number(readFileSync(fixture.leaderPid, 'utf8'));
500
+ const descendant = Number(readFileSync(fixture.descendantPid, 'utf8'));
501
+ before = {
502
+ leaderExitObserved: true,
503
+ leaderPid: leader,
504
+ descendantPid: descendant,
505
+ descendantAlive: pidAlive(descendant),
506
+ processGroupEmpty: isOwnedProcessGroupEmpty(leader),
507
+ closeDelayedBoundary: pidAlive(descendant),
508
+ };
509
+ outcome = await waitForClose(parent, remainingBound());
510
+ if ('timedOut' in outcome) {
511
+ const snapshot = {
512
+ case: name,
513
+ externalBoundMs: PRODUCT_EXTERNAL_BOUND_MS,
514
+ parent: outcome,
515
+ before,
516
+ marker: existsSync(fixture.marker),
517
+ stdoutTail: stdout.slice(-2_000),
518
+ stderr: stderr.slice(-4_000),
519
+ };
520
+ throw new Error(`benchmark success liveness regression: ${JSON.stringify(snapshot)}`);
521
+ }
522
+ await new Promise((resolve) => setTimeout(resolve, 350));
523
+ const afterLeader = Number(readFileSync(fixture.leaderPid, 'utf8'));
524
+ const afterDescendant = Number(readFileSync(fixture.descendantPid, 'utf8'));
525
+ const after = {
526
+ parentAlive: pidAlive(parent.pid ?? -1),
527
+ leader: { code: 0, signal: null },
528
+ descendantAlive: pidAlive(afterDescendant),
529
+ processGroupEmpty: isOwnedProcessGroupEmpty(afterLeader),
530
+ marker: existsSync(fixture.marker),
531
+ };
532
+ assert.equal(outcome.code, 0, `${name} benchmark must preserve leader exit 0: ${JSON.stringify(outcome)}`);
533
+ assert.equal(outcome.signal, null, `${name} benchmark must preserve a normal leader exit: ${JSON.stringify(outcome)}`);
534
+ assert.equal(after.parentAlive, false, `${name} product parent must be gone within the external bound`);
535
+ assert.equal(after.descendantAlive, false, `${name} must reap the inherited-pipe descendant`);
536
+ assert.equal(after.processGroupEmpty, true, `${name} owned dsh group must be empty`);
537
+ assert.equal(after.marker, false, `${name} must not run the post-failure marker`);
538
+ assert.match(stdout, /<benchmark_terminal>/, `${name} must surface the captured terminal tag on parent stdout`);
539
+ return {
540
+ case: name,
541
+ productEntrypoint: fixture.entrypoint,
542
+ configPath: fixture.configPath,
543
+ externalBoundMs: PRODUCT_EXTERNAL_BOUND_MS,
544
+ elapsedMs: Date.now() - startedAt,
545
+ parent: outcome,
546
+ stdoutTail: stdout.slice(-2_000),
547
+ stderr: stderr.slice(-4_000),
548
+ before,
549
+ after,
550
+ };
551
+ }
552
+ finally {
553
+ forceKillGroup(parent.pid ?? null);
554
+ forceKillGroup(Number(existsSync(fixture.leaderPid) ? readFileSync(fixture.leaderPid, 'utf8') : 0));
555
+ rmSync(root, { recursive: true, force: true });
556
+ }
557
+ }
558
+ const results = [
559
+ await runDshFailureCase('child-crash'),
560
+ await runDshFailureCase('rejected-promise'),
561
+ await runSpawnErrorCase(),
562
+ await runParentSignalCase('SIGINT'),
563
+ await runParentSignalCase('SIGTERM'),
564
+ await runProductEntrypointCase('failure-inherited-pipe', 7, false),
565
+ await runProductEntrypointCase('normal-zero-inherited-pipe', 0, false),
566
+ await runProductEntrypointCase('term-resistant-inherited-pipe', 7, true),
567
+ await runBenchmarkSuccessCase('benchmark-inherited-pipe-resist-term', true),
568
+ ];
569
+ console.log(`ISSUE 271 LIVENESS: ${JSON.stringify(results)}`);