@danceiny/gotry 0.0.1-rc.8 → 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 (506) hide show
  1. package/README.md +172 -217
  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 -49
  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 +968 -0
  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 +126 -0
  42. package/dist/capabilities/session/adapters/ctrip-flight.js +141 -0
  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 +54 -0
  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 +50 -0
  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 +107 -0
  56. package/dist/capabilities/session/static-flight-golden.js +150 -0
  57. package/dist/capabilities/session/transport.js +109 -0
  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 +686 -0
  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 +72 -0
  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 +68 -10
  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 +67 -0
  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 +480 -0
  191. package/dist/scripts/ledger-workflow-crash.js +32 -0
  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 +49 -0
  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 +29 -31
  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 +43 -42
  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 +31 -0
  227. package/dist/scripts/session-attach-poc.js +62 -0
  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 +60 -0
  231. package/dist/scripts/session-link-tests.js +478 -0
  232. package/dist/scripts/session-login.js +29 -0
  233. package/dist/scripts/session-tests.js +862 -0
  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 +703 -219
  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 +261 -0
  253. package/dist/scripts/state-cli.js +585 -0
  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 +59 -0
  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 +86 -0
  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 +2305 -731
  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 +358 -162
  325. package/dist/src/memory-capture.js +180 -32
  326. package/dist/src/memory-decay.js +47 -0
  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 +767 -0
  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 +59 -0
  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 +538 -360
  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 +296 -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 +2107 -224
  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 +278 -40
  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 +360 -89
  506. package/ts/src/wish-pool.ts +79 -0
@@ -0,0 +1,184 @@
1
+ import assert from 'node:assert/strict';
2
+ import { spawn, spawnSync } from 'node:child_process';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { ManagedDshRunPort } from '../src/booking-surface/managed-dsh-run-port.js';
5
+ import { ManagedDshCleanupError, managedDshGroupIsQuiescent, parseManagedDshGroupSnapshot, readManagedDshWorkerStart, snapshotManagedDshGroup, } from '../src/booking-surface/managed-dsh-cleanup-diagnostic.js';
6
+ const workerPath = fileURLToPath(new URL('./fixtures/managed-dsh-worker-fixture.mjs', import.meta.url));
7
+ async function proveFailedObservation(kind) {
8
+ const port = new ManagedDshRunPort({ workerPath, graceMs: 50, cleanupRole: kind === 'timeout' ? 'task' : 'warmer' });
9
+ // This seam injects an observation failure, not a real process-cleanup bug.
10
+ // Launch and termination still use the installed runtime and real child tree.
11
+ const handle = port.handle;
12
+ const waitForExit = handle.waitForExit.bind(handle);
13
+ try {
14
+ const result = await port.run('fixture', { sessionId: 'cleanup-diagnostic-proof' });
15
+ const descendant = result.events[0].grandchildPid;
16
+ handle.waitForExit = async () => {
17
+ if (kind === 'rejected')
18
+ throw new Error('PRIVATE_PROVIDER_TOKEN_DO_NOT_EXPOSE');
19
+ return false;
20
+ };
21
+ const closing = port.close();
22
+ assert.strictEqual(port.close(), closing, 'failure remains sticky for every close caller');
23
+ const error = await closing.then(() => undefined, (reason) => reason);
24
+ assert.ok(error instanceof ManagedDshCleanupError, 'failure carries a typed safe diagnostic');
25
+ const diagnostic = error.diagnostic;
26
+ assert.equal(diagnostic.role, kind === 'timeout' ? 'task' : 'warmer');
27
+ assert.equal(diagnostic.schemaVersion, 'managed-dsh-cleanup.v2');
28
+ if (process.platform === 'darwin')
29
+ assert.ok(Number.isSafeInteger(diagnostic.workerPid) && diagnostic.workerPid > 0, 'direct fallback receipt identifies the worker');
30
+ assert.equal(diagnostic.deadlineMs, 1_000, 'existing minimum teardown deadline is preserved');
31
+ assert.equal(diagnostic.graceMs, 50);
32
+ assert.ok(diagnostic.elapsedMs >= 0);
33
+ assert.ok(['pending', 'exited', 'failed'].includes(diagnostic.workerOutcome.state));
34
+ assert.equal(diagnostic.processGroup.expectedPgid, process.platform === 'darwin' ? diagnostic.workerPid : null);
35
+ assert.equal(JSON.stringify(error).includes('PRIVATE_'), false, 'provider observation errors are not forwarded');
36
+ const log = spawnSync(process.execPath, ['--input-type=module', '-e',
37
+ 'let error = new Error(process.argv[1]); for (let i = 0; i < 3; i++) error = new AggregateError([error], "nested cleanup"); throw error',
38
+ error.message], { encoding: 'utf8', timeout: 5_000 });
39
+ assert.equal(log.status, 1, 'nested uncaught error child fails as intended');
40
+ assert.ok(log.stderr.includes(`diagnostic=${JSON.stringify(diagnostic)}`), 'default nested error log retains every safe diagnostic value');
41
+ assert.equal(log.stderr.includes('PRIVATE_'), false, 'nested log does not expose provider errors');
42
+ for (const member of diagnostic.processGroup.members) {
43
+ assert.equal(member.pgid, diagnostic.workerPid, 'only the owned process group is returned');
44
+ assert.deepEqual(Object.keys(member).sort(), ['pgid', 'pid', 'ppid', 'startedAt', 'state', 'zombie']);
45
+ assert.equal(member.zombie, member.state.startsWith('Z'), 'zombie flag matches the observed state letter');
46
+ }
47
+ if (kind === 'timeout' && diagnostic.processGroup.status === 'observed') {
48
+ // Right after terminate() the real fixture tree still holds live members,
49
+ // so the safe snapshot must classify it as not quiescent.
50
+ assert.equal(diagnostic.processGroup.classification, 'has-live-members');
51
+ assert.ok(diagnostic.processGroup.liveMemberCount >= 1);
52
+ assert.equal(managedDshGroupIsQuiescent(diagnostic.processGroup), false);
53
+ }
54
+ assert.equal(await waitForExit(AbortSignal.timeout(2_000)), true, 'actual runtime still reaps the worker tree');
55
+ if (process.platform !== 'win32')
56
+ assert.throws(() => process.kill(descendant, 0), 'grandchild is reaped');
57
+ console.log(`MANAGED DSH CLEANUP DIAGNOSTIC: ${kind} observation preserves ${diagnostic.role} identity and actual tree teardown`);
58
+ }
59
+ finally {
60
+ handle.waitForExit = waitForExit;
61
+ handle.terminate();
62
+ assert.equal(await waitForExit(AbortSignal.timeout(2_000)), true, 'proof cleans its own processes even after an assertion failure');
63
+ }
64
+ }
65
+ /** Classify crafted ps tables without signalling anything. */
66
+ async function proveSyntheticClassification() {
67
+ const anchor = 'Sun Sep 20 19:59:16 2026';
68
+ const zombieOnly = parseManagedDshGroupSnapshot(' 4242 1 4242 Z Sun Sep 20 19:59:16 2026', 4242, anchor);
69
+ assert.equal(zombieOnly.status, 'observed');
70
+ assert.equal(zombieOnly.classification, 'zombie-only');
71
+ assert.deepEqual([zombieOnly.liveMemberCount, zombieOnly.zombieMemberCount], [0, 1]);
72
+ assert.equal(zombieOnly.workerIdentity, 'match');
73
+ assert.equal(managedDshGroupIsQuiescent(zombieOnly), true, 'a group holding only un-reaped zombies is quiescent');
74
+ const reused = parseManagedDshGroupSnapshot(' 4242 1 4242 Z Mon Dec 1 08:00:00 2025', 4242, anchor);
75
+ assert.equal(reused.workerIdentity, 'mismatch', 'a start time that differs from the live anchor proves PID reuse');
76
+ const live = parseManagedDshGroupSnapshot(' 4242 1 4242 Ss Sun Sep 20 19:59:16 2026\n 4243 4242 4242 R Sun Sep 20 19:59:17 2026', 4242, anchor);
77
+ assert.equal(live.classification, 'has-live-members');
78
+ assert.deepEqual([live.liveMemberCount, live.zombieMemberCount], [2, 0]);
79
+ assert.equal(live.workerIdentity, 'match');
80
+ assert.equal(managedDshGroupIsQuiescent(live), false);
81
+ const mixed = parseManagedDshGroupSnapshot(' 4242 1 4242 Z Sun Sep 20 19:59:16 2026\n 4243 4242 4242 U Sun Sep 20 19:59:17 2026', 4242, null);
82
+ assert.equal(mixed.classification, 'has-live-members', 'an uninterruptible member is live, never zombie');
83
+ assert.equal(mixed.workerIdentity, 'unknown', 'without a live anchor identity stays unknown');
84
+ const empty = parseManagedDshGroupSnapshot('', 4242, anchor);
85
+ assert.equal(empty.classification, 'empty');
86
+ assert.equal(managedDshGroupIsQuiescent(empty), true);
87
+ assert.equal(parseManagedDshGroupSnapshot('4243 1 999 Z Sun Sep 20 19:59:16 2026', 4242).classification, 'empty', 'foreign groups are excluded');
88
+ console.log('MANAGED DSH CLEANUP DIAGNOSTIC: synthetic tables classify zombie-only, live, uninterruptible, empty and reused identities');
89
+ }
90
+ /**
91
+ * A live process that never reaps its child keeps a real zombie inside its own
92
+ * process group for as long as it lives: `sh -c 'sleep 0.3 & exec sleep 600'`
93
+ * leaves the exited background job owned by the exec'd sleep.
94
+ */
95
+ async function proveRealGroupClassification() {
96
+ if (process.platform !== 'darwin') {
97
+ console.log('MANAGED DSH CLEANUP DIAGNOSTIC: real group classification is Darwin-only, skipped');
98
+ return;
99
+ }
100
+ const holder = spawn('/bin/sh', ['-c', 'sleep 0.3 & exec sleep 600'], { detached: true, stdio: 'ignore' });
101
+ try {
102
+ const anchor = await readManagedDshWorkerStart(holder.pid);
103
+ assert.ok(anchor, 'live holder reports its start-time anchor');
104
+ const deadline = Date.now() + 2_000;
105
+ let group;
106
+ while (Date.now() < deadline) {
107
+ group = await snapshotManagedDshGroup(holder.pid, anchor);
108
+ if (group.status === 'observed' && group.zombieMemberCount >= 1)
109
+ break;
110
+ await new Promise((resolve) => setTimeout(resolve, 50));
111
+ }
112
+ assert.equal(group.status, 'observed');
113
+ assert.equal(group.classification, 'has-live-members', 'a live member holding a zombie is not zombie-only');
114
+ assert.ok(group.liveMemberCount >= 1 && group.zombieMemberCount >= 1, 'the real group holds one live holder and one real zombie');
115
+ for (const member of group.members) {
116
+ assert.ok(member.startedAt, 'every real member carries a start time');
117
+ assert.equal(member.zombie, member.state.startsWith('Z'));
118
+ }
119
+ assert.equal(group.workerIdentity, 'match', 'the live anchor matches the observed holder identity');
120
+ assert.equal(managedDshGroupIsQuiescent(group), false);
121
+ console.log(`MANAGED DSH CLEANUP DIAGNOSTIC: real group ${holder.pid} classified with live holder and real zombie member`);
122
+ }
123
+ finally {
124
+ try {
125
+ process.kill(-holder.pid, 'SIGKILL');
126
+ }
127
+ catch { /* already gone */ }
128
+ const reaped = Date.now() + 2_000;
129
+ while (Date.now() < reaped) {
130
+ try {
131
+ process.kill(-holder.pid, 0);
132
+ await new Promise((resolve) => setTimeout(resolve, 50));
133
+ }
134
+ catch {
135
+ break;
136
+ }
137
+ }
138
+ }
139
+ }
140
+ /** The close verdict: an observation deadline plus a quiescent group is a successful cleanup, not a timeout. */
141
+ async function proveCloseVerdict(classification) {
142
+ let observedPgid = null;
143
+ const port = new ManagedDshRunPort({
144
+ workerPath, graceMs: 50, cleanupRole: 'task',
145
+ groupObserver: async (pid) => {
146
+ observedPgid = pid;
147
+ const table = classification === 'empty' ? '' : ` ${pid} 1 ${pid} ${classification === 'zombie-only' ? 'Z' : 'Ss'} Sun Sep 20 19:59:16 2026`;
148
+ return parseManagedDshGroupSnapshot(table, pid, null);
149
+ },
150
+ });
151
+ const handle = port.handle;
152
+ const waitForExit = handle.waitForExit.bind(handle);
153
+ try {
154
+ await port.run('fixture', { sessionId: 'cleanup-verdict-proof' });
155
+ handle.waitForExit = async () => false;
156
+ const closing = port.close();
157
+ if (classification === 'has-live-members') {
158
+ const error = await closing.then(() => undefined, (reason) => reason);
159
+ assert.ok(error instanceof ManagedDshCleanupError, 'a live member still converts the deadline into a failure');
160
+ assert.equal(error.message.split(';')[0], 'managed DSH process tree cleanup timeout');
161
+ assert.equal(error.diagnostic.processGroup.classification, 'has-live-members');
162
+ assert.equal(error.diagnostic.processGroup.liveMemberCount, 1);
163
+ }
164
+ else {
165
+ await closing;
166
+ }
167
+ assert.ok(Number.isInteger(observedPgid) && observedPgid > 0, 'the verdict observer receives the owned worker identity');
168
+ assert.equal(await waitForExit(AbortSignal.timeout(2_000)), true, 'the real runtime still reaps the tree in every verdict case');
169
+ }
170
+ finally {
171
+ handle.waitForExit = waitForExit;
172
+ handle.terminate();
173
+ assert.equal(await waitForExit(AbortSignal.timeout(2_000)), true, 'proof cleans its own processes even after an assertion failure');
174
+ }
175
+ }
176
+ await proveFailedObservation('timeout');
177
+ await proveFailedObservation('rejected');
178
+ await proveSyntheticClassification();
179
+ await proveRealGroupClassification();
180
+ await proveCloseVerdict('zombie-only');
181
+ await proveCloseVerdict('empty');
182
+ await proveCloseVerdict('has-live-members');
183
+ assert.equal((await snapshotManagedDshGroup(null)).status, 'unknown_worker');
184
+ console.log('MANAGED DSH CLEANUP DIAGNOSTIC PROOF: observation failures, zombie classification, identity anchors and verdict-by-quiescence OK');
@@ -0,0 +1,172 @@
1
+ import assert from 'node:assert/strict';
2
+ import { spawn as nodeSpawn } from 'node:child_process';
3
+ import { mkdtempSync, rmSync } from 'node:fs';
4
+ import { tmpdir } from 'node:os';
5
+ import { join } from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+ import LocalSubprocessRuntime from '@deepseek-ai/dsh-subprocess-local';
8
+ import { ManagedDshRunPort } from '../src/booking-surface/managed-dsh-run-port.js';
9
+ import { ManagedDshCleanupError } from '../src/booking-surface/managed-dsh-cleanup-diagnostic.js';
10
+ const workerPath = fileURLToPath(new URL('./fixtures/managed-dsh-pending-worker-fixture.mjs', import.meta.url));
11
+ function observe(promise) {
12
+ return promise.then((value) => ({ status: 'fulfilled', value }), (reason) => ({ status: 'rejected', reason }));
13
+ }
14
+ async function bounded(promise, timeoutMs, label) {
15
+ let timer;
16
+ try {
17
+ return await Promise.race([
18
+ promise,
19
+ new Promise((_, reject) => {
20
+ timer = setTimeout(() => reject(new Error(label)), timeoutMs);
21
+ }),
22
+ ]);
23
+ }
24
+ finally {
25
+ clearTimeout(timer);
26
+ }
27
+ }
28
+ function reasonMessage(reason) {
29
+ return reason instanceof Error ? reason.message : String(reason);
30
+ }
31
+ async function assertRejected(promise, expected, label) {
32
+ const outcome = await bounded(promise, 2_000, `${label}: close did not settle`);
33
+ assert.equal(outcome.status, 'rejected', `${label}: close must reject`);
34
+ const reason = outcome.reason;
35
+ // Since #518 close failures carry the typed safe diagnostic; the stable
36
+ // public meaning lives before its appended diagnostic payload.
37
+ assert.ok(reason instanceof ManagedDshCleanupError, `${label}: close failure carries the typed cleanup diagnostic`);
38
+ assert.equal(reason.message.split(';')[0], expected, `${label}: stable close error`);
39
+ }
40
+ async function settleInjectedHandle(port, originalWaitForExit, doneOutcome) {
41
+ const handle = port.handle;
42
+ handle.waitForExit = originalWaitForExit;
43
+ // The pinned fallback owner makes the real observation deterministic: the
44
+ // spawn never produced a child (no pid), so the owner's liveness probe is
45
+ // immediately false and confirmed-empty arrives without any provider-side
46
+ // wait. The bounded window stays as harness safety, not as a contract.
47
+ const rangeEmpty = await bounded(originalWaitForExit(AbortSignal.timeout(12_000)), 13_500, 'real handle cleanup did not settle');
48
+ assert.equal(rangeEmpty, true, 'real handle cleanup must confirm the range empty (deterministic fallback owner)');
49
+ const done = await bounded(doneOutcome, 2_500, 'real handle done did not settle');
50
+ assert.equal(done.status, 'rejected', 'real spawn-failure handle.done rejects');
51
+ await bounded(observe(port.close()), 2_500, 'sticky close promise did not settle');
52
+ }
53
+ const runtimeProto = LocalSubprocessRuntime.prototype;
54
+ /**
55
+ * Construct the port with the runtime's PUBLIC test hooks pinned to the POSIX
56
+ * fallback owner for the one synchronous spawn the constructor performs.
57
+ * `platform: 'darwin'` routes selectContainmentMode away from the linux-scope
58
+ * owner whose uncancellable shared wait can hang the runner; the recorded
59
+ * `spawn` hook delegates to the real node spawn so the missing-cwd failure is
60
+ * genuine. Prototype and per-instance internals are restored before any
61
+ * asynchronous assertion can observe them.
62
+ */
63
+ function constructPortWithFallbackOwner(options) {
64
+ const spawnCalls = [];
65
+ let pinnedInternals = null;
66
+ const originalProtoSpawn = runtimeProto.spawn;
67
+ runtimeProto.spawn = function (spec) {
68
+ pinnedInternals = this.internals;
69
+ const hadPlatform = Object.hasOwn(this.internals, 'platform');
70
+ const previousPlatform = this.internals.platform;
71
+ const previousSpawn = this.internals.spawn;
72
+ this.internals.platform = 'darwin';
73
+ this.internals.spawn = (program, args, opts) => {
74
+ spawnCalls.push({ program, args: [...args], options: opts });
75
+ return (previousSpawn ?? nodeSpawn)(program, args, opts);
76
+ };
77
+ try {
78
+ return originalProtoSpawn.call(this, spec);
79
+ }
80
+ finally {
81
+ if (previousSpawn !== undefined)
82
+ this.internals.spawn = previousSpawn;
83
+ else
84
+ delete this.internals.spawn;
85
+ if (hadPlatform)
86
+ this.internals.platform = previousPlatform;
87
+ else
88
+ delete this.internals.platform;
89
+ }
90
+ };
91
+ let port;
92
+ try {
93
+ port = new ManagedDshRunPort(options);
94
+ }
95
+ finally {
96
+ runtimeProto.spawn = originalProtoSpawn;
97
+ }
98
+ return { port, spawnCalls, pinnedInternals, prototypeRestored: runtimeProto.spawn === originalProtoSpawn };
99
+ }
100
+ async function proveCloseFailure(mode, expected, unhandled) {
101
+ const root = mkdtempSync(join(tmpdir(), `gotry-510-close-${mode}-`));
102
+ const missingCwd = join(root, 'missing-cwd');
103
+ const { port, spawnCalls, pinnedInternals, prototypeRestored } = constructPortWithFallbackOwner({
104
+ cwd: missingCwd,
105
+ workerPath,
106
+ graceMs: 50,
107
+ });
108
+ // Containment-selection coverage: the pinned platform hook must have routed
109
+ // this spawn through the POSIX fallback owner — the ordinary spawn hook
110
+ // fired exactly once for the real Node executable with the real missing
111
+ // cwd and detached POSIX options (the native linux-scope branch would have
112
+ // exec'd systemd-run instead).
113
+ assert.equal(spawnCalls.length, 1, `${mode}: ordinary spawn fired exactly once (fallback owner selected)`);
114
+ assert.equal(spawnCalls[0].program, process.execPath, `${mode}: real worker executable spawned`);
115
+ assert.equal(spawnCalls[0].args.at(-1), workerPath, `${mode}: real worker path spawned`);
116
+ assert.equal(spawnCalls[0].options.cwd, missingCwd, `${mode}: real missing cwd passed to the real spawn`);
117
+ assert.equal(spawnCalls[0].options.detached, true, `${mode}: detached POSIX fallback owner selected`);
118
+ // Hook restoration coverage: nothing observable of the test hooks may
119
+ // outlive the synchronous construction.
120
+ assert.ok(prototypeRestored, `${mode}: runtime prototype spawn restored`);
121
+ assert.ok(pinnedInternals !== null && !Object.hasOwn(pinnedInternals, 'platform') && !Object.hasOwn(pinnedInternals, 'spawn'), `${mode}: internals test hooks restored`);
122
+ const handle = port.handle;
123
+ const originalWaitForExit = handle.waitForExit.bind(handle);
124
+ const doneOutcome = observe(handle.done);
125
+ const unhandledAtStart = unhandled.length;
126
+ const injected = mode === 'reject'
127
+ ? () => Promise.reject(new Error('fault-injected observation failure'))
128
+ : () => Promise.resolve(false);
129
+ handle.waitForExit = injected;
130
+ try {
131
+ const closePromise = port.close();
132
+ const repeatedClosePromise = port.close();
133
+ assert.strictEqual(repeatedClosePromise, closePromise, `${mode}: repeated close returns one Promise`);
134
+ await assertRejected(observe(closePromise), expected, mode);
135
+ await assertRejected(observe(repeatedClosePromise), expected, `${mode} repeated close`);
136
+ await settleInjectedHandle(port, originalWaitForExit, doneOutcome);
137
+ // Give the real done rejection a turn to expose an unhandled derived
138
+ // outcome Promise. The proof itself observes every public close Promise.
139
+ await new Promise((resolve) => setImmediate(resolve));
140
+ await new Promise((resolve) => setImmediate(resolve));
141
+ assert.equal(unhandled.length, unhandledAtStart, `${mode}: no unhandled rejection from close cleanup (${unhandled.slice(unhandledAtStart).map(reasonMessage).join('; ')})`);
142
+ }
143
+ finally {
144
+ handle.waitForExit = originalWaitForExit;
145
+ await bounded(observe(port.close()), 2_500, `${mode}: final cleanup did not settle`);
146
+ rmSync(root, { recursive: true, force: true });
147
+ }
148
+ }
149
+ const unhandled = [];
150
+ const onUnhandled = (reason) => { unhandled.push(reason); };
151
+ process.on('unhandledRejection', onUnhandled);
152
+ try {
153
+ const failures = [];
154
+ for (const [mode, expected] of [
155
+ ['reject', 'managed DSH process tree observation failed'],
156
+ ['false', 'managed DSH process tree cleanup timeout'],
157
+ ]) {
158
+ try {
159
+ await proveCloseFailure(mode, expected, unhandled);
160
+ }
161
+ catch (error) {
162
+ failures.push(error);
163
+ console.error(`MANAGED DSH CLOSE FAILURE PROOF RED (${mode}):`, error);
164
+ }
165
+ }
166
+ if (failures.length > 0)
167
+ throw new AggregateError(failures, 'managed DSH close failure proof failed');
168
+ console.log('MANAGED DSH CLOSE FAILURE PROOF: observation reject/timeout are bounded, idempotent, and handled');
169
+ }
170
+ finally {
171
+ process.off('unhandledRejection', onUnhandled);
172
+ }
@@ -0,0 +1,153 @@
1
+ import assert from 'node:assert/strict';
2
+ import { existsSync, mkdtempSync, readFileSync, rmSync } from 'node:fs';
3
+ import { tmpdir } from 'node:os';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { join } from 'node:path';
6
+ import { ManagedDshRunPort } from '../src/booking-surface/managed-dsh-run-port.js';
7
+ const workerPath = fileURLToPath(new URL('./fixtures/managed-dsh-worker-fixture.mjs', import.meta.url));
8
+ const port = new ManagedDshRunPort({ workerPath, graceMs: 50 });
9
+ const result = await port.run('fixture', { sessionId: 'managed-dsh-proof' });
10
+ const pid = result.events[0].grandchildPid;
11
+ assert.ok(Number.isInteger(pid) && pid > 0, 'fixture reports its grandchild pid');
12
+ const started = Date.now();
13
+ await port.close();
14
+ assert.ok(Date.now() - started < 2_000, 'tree teardown is bounded');
15
+ const deadline = Date.now() + 1_000;
16
+ let alive = true;
17
+ while (alive && Date.now() < deadline) {
18
+ try {
19
+ process.kill(pid, 0);
20
+ }
21
+ catch {
22
+ alive = false;
23
+ }
24
+ if (alive)
25
+ await new Promise((resolve) => setTimeout(resolve, 25));
26
+ }
27
+ assert.equal(alive, false, `TERM-resistant grandchild ${pid} must be reaped with its worker tree`);
28
+ assert.ok(existsSync(join(process.cwd(), 'node_modules/@deepseek-ai/dsh-subprocess-local')), 'proof uses installed dsh subprocess-local runtime');
29
+ console.log('MANAGED DSH RUN PORT TREE PROOF: bounded close reaps TERM-resistant grandchild');
30
+ const pendingWorkerPath = fileURLToPath(new URL('./fixtures/managed-dsh-pending-worker-fixture.mjs', import.meta.url));
31
+ async function waitForFile(path, timeoutMs) {
32
+ const deadline = Date.now() + timeoutMs;
33
+ while (!existsSync(path)) {
34
+ if (Date.now() >= deadline)
35
+ throw new Error(`fixture marker did not appear: ${path}`);
36
+ await new Promise((resolve) => setTimeout(resolve, 10));
37
+ }
38
+ }
39
+ async function waitForFileText(path, expected, timeoutMs) {
40
+ const deadline = Date.now() + timeoutMs;
41
+ while (!existsSync(path) || readFileSync(path, 'utf8') !== expected) {
42
+ if (Date.now() >= deadline)
43
+ throw new Error(`fixture marker did not reach ${expected}: ${path}`);
44
+ await new Promise((resolve) => setTimeout(resolve, 10));
45
+ }
46
+ }
47
+ async function waitForDead(pid, timeoutMs) {
48
+ const deadline = Date.now() + timeoutMs;
49
+ while (true) {
50
+ try {
51
+ process.kill(pid, 0);
52
+ }
53
+ catch {
54
+ return;
55
+ }
56
+ if (Date.now() >= deadline)
57
+ throw new Error(`fixture process ${pid} was not reaped`);
58
+ await new Promise((resolve) => setTimeout(resolve, 25));
59
+ }
60
+ }
61
+ async function bounded(promise, timeoutMs, label) {
62
+ let timer;
63
+ try {
64
+ return await Promise.race([
65
+ promise,
66
+ new Promise((_, reject) => { timer = setTimeout(() => reject(new Error(label)), timeoutMs); }),
67
+ ]);
68
+ }
69
+ finally {
70
+ clearTimeout(timer);
71
+ }
72
+ }
73
+ async function assertPendingRejected(settledPromise, expected, label) {
74
+ const settled = await bounded(settledPromise, 1_500, `${label}: pending requests did not settle`);
75
+ assert.equal(settled.length, expected, `${label}: every pending request settled`);
76
+ assert.ok(settled.every((entry) => entry.status === 'rejected'), `${label}: every pending request rejected`);
77
+ }
78
+ async function proveWorkerExitRejectsPending() {
79
+ const root = mkdtempSync(join(tmpdir(), 'gotry-managed-dsh-exit-'));
80
+ const pidFile = join(root, 'pid.json');
81
+ const requestFile = join(root, 'requests');
82
+ const statusFile = join(root, 'status.json');
83
+ const port = new ManagedDshRunPort({
84
+ workerPath: pendingWorkerPath,
85
+ graceMs: 50,
86
+ env: {
87
+ ...process.env,
88
+ MANAGED_DSH_FIXTURE_PID_FILE: pidFile,
89
+ MANAGED_DSH_FIXTURE_REQUEST_FILE: requestFile,
90
+ MANAGED_DSH_FIXTURE_STATUS_FILE: statusFile,
91
+ MANAGED_DSH_FIXTURE_EXIT_AFTER_REQUESTS: '3',
92
+ MANAGED_DSH_FIXTURE_EXIT_CODE: '23',
93
+ },
94
+ });
95
+ try {
96
+ await waitForFile(pidFile, 1_000);
97
+ const pending = [
98
+ port.run('first pending run', { sessionId: 'managed-dsh-exit-1' }),
99
+ port.run('second pending run', { sessionId: 'managed-dsh-exit-2' }),
100
+ port.warmup(),
101
+ ];
102
+ const settledPromise = Promise.allSettled(pending);
103
+ await waitForFileText(requestFile, '3', 1_000);
104
+ await assertPendingRejected(settledPromise, pending.length, 'worker exit');
105
+ await waitForFile(statusFile, 1_000);
106
+ const status = JSON.parse(readFileSync(statusFile, 'utf8'));
107
+ assert.equal(status.exitCode, 23, 'fixture exit code is recorded');
108
+ assert.equal(status.signal, null, 'fixture exited without a signal');
109
+ assert.ok(status.stderr.length <= 128, 'fixture stderr evidence is bounded');
110
+ assert.equal(status.stderr.includes('PRIVATE_'), false, 'fixture stderr evidence contains no sensitive marker');
111
+ }
112
+ finally {
113
+ await port.close().catch(() => undefined);
114
+ rmSync(root, { recursive: true, force: true });
115
+ }
116
+ }
117
+ async function proveCloseRejectsPendingAndReapsTree() {
118
+ const root = mkdtempSync(join(tmpdir(), 'gotry-managed-dsh-close-'));
119
+ const pidFile = join(root, 'pid.json');
120
+ const requestFile = join(root, 'requests');
121
+ const port = new ManagedDshRunPort({
122
+ workerPath: pendingWorkerPath,
123
+ graceMs: 50,
124
+ env: { ...process.env, MANAGED_DSH_FIXTURE_PID_FILE: pidFile, MANAGED_DSH_FIXTURE_REQUEST_FILE: requestFile },
125
+ });
126
+ try {
127
+ await waitForFile(pidFile, 1_000);
128
+ const pids = JSON.parse(readFileSync(pidFile, 'utf8'));
129
+ assert.ok(Number.isInteger(pids.workerPid) && Number.isInteger(pids.grandchildPid), 'pending fixture reports its worker tree');
130
+ const pending = [
131
+ port.run('first close run', { sessionId: 'managed-dsh-close-1' }),
132
+ port.run('second close run', { sessionId: 'managed-dsh-close-2' }),
133
+ port.warmup(),
134
+ ];
135
+ const settledPromise = Promise.allSettled(pending);
136
+ await waitForFileText(requestFile, '3', 1_000);
137
+ const closeStarted = Date.now();
138
+ const closePromise = port.close();
139
+ assert.strictEqual(port.close(), closePromise, 'repeated close returns the same cleanup promise');
140
+ await assertPendingRejected(settledPromise, pending.length, 'caller close');
141
+ await closePromise;
142
+ assert.ok(Date.now() - closeStarted < 2_000, 'caller close and pending rejection are bounded');
143
+ await waitForDead(pids.workerPid, 1_000);
144
+ await waitForDead(pids.grandchildPid, 1_000);
145
+ }
146
+ finally {
147
+ await port.close().catch(() => undefined);
148
+ rmSync(root, { recursive: true, force: true });
149
+ }
150
+ }
151
+ await proveWorkerExitRejectsPending();
152
+ await proveCloseRejectsPendingAndReapsTree();
153
+ console.log('MANAGED DSH RUN PORT PENDING PROOF: worker exit and caller close reject two runs plus warmup; tree cleanup remains bounded');