{"_id":"dsh-push-host","_rev":"24-ab7bcdf4f2be6cc1bfb6021a772ecce5","name":"dsh-push-host","dist-tags":{"latest":"0.7.13"},"versions":{"0.0.0-stage":{"name":"dsh-push-host","version":"0.0.0-stage","_id":"dsh-push-host@0.0.0-stage","stub":true,"maintainers":[{"name":"cnop","email":"2059678566@qq.com"}],"dist":{"shasum":"7e77ebf10f2f3c91e1dfbb4c97dc5662ff7018d7","tarball":"https://registry.npmjs.org/dsh-push-host/-/dsh-push-host-0.0.0-stage.tgz","fileCount":2,"integrity":"sha512-BPBoVYfdTbQhY3WDyNVXHyM93plq1N7ua2+zJao5TO/zFQmxPEP4qB3lGOUg7ULOqaezOwF0vo766H6BeeRkzg==","signatures":[{"sig":"MEUCIQCio3aLdnGHDB9coZIgpxeo9SnpDNGLSxQdAfnWd19QIgIgGt0OS14iAEJHyOGK5+HAVvJJTYLc0RvyT0kbLGzL+2o=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":335},"_npmUser":{"name":"cnop","email":"2059678566@qq.com"},"description":"Temporary package placeholder for staged publishing","directories":{}},"0.3.1":{"name":"dsh-push-host","version":"0.3.1","keywords":["dsh","dsh-plugin","deepseek-harness","cordis","push","ntfy","notification"],"author":{"url":"https://github.com/thiscp","name":"cpyh"},"license":"MIT","_id":"dsh-push-host@0.3.1","maintainers":[{"name":"cnop","email":"2059678566@qq.com"}],"contributors":[{"name":"DeepSeek Harness agents"}],"homepage":"https://github.com/thiscp/dsh-push/tree/main/host-plugin#readme","bugs":{"url":"https://github.com/thiscp/dsh-push/issues"},"bin":{"dsh-push-pair":"lib/pairing.mjs"},"dsh":{"bundle":{"patch":"./cordis.patch.yml","version":"1"},"client":{"platform":"web"}},"dist":{"shasum":"5e2cab2d1faea276e8cd7221aa2921b3c5de87c9","tarball":"https://registry.npmjs.org/dsh-push-host/-/dsh-push-host-0.3.1.tgz","fileCount":10,"integrity":"sha512-vGMD3P/uMjRX7lVTi9ua2vRDNdX2rx9mxX2wOdWm2iDVKu65XY32jQRvHdFnCZz36+v1w0LuRxv4vBjUqRxalQ==","signatures":[{"sig":"MEQCIC/GSS0MRwf7y/UV8Zqf0vmXtOjpPAiYRSJGgGOT5UpAAiB7Bm2XaQedKgJT9g9gpvMXNOdM0EW+70r6/Eo6qlBfcA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIAnOaQXRvFgGXT7Fv8/yNKTm1VtpJJPNKTrugJFLCuM/AiEAisNQyQdRVlY0a/3LANS8tct/BpjhBdfm/MT/gxxnYm0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":173162},"main":"lib/index.js","type":"module","engines":{"node":">=20.11"},"exports":{".":"./lib/index.js","./relay":"./lib/relay.js","./client":"./lib/client.js","./pairing":"./lib/pairing.mjs","./credentials":"./lib/credentials.mjs","./pairing-lib":"./lib/pairing-lib.mjs","./package.json":"./package.json","./cordis.patch.yml":"./cordis.patch.yml"},"gitHead":"83fc97e0f0609627d9e136152b4a2956f376e577","scripts":{"pair":"node lib/pairing.mjs","test":"node plugin-selftest.mjs"},"_npmUser":{"name":"cnop","email":"2059678566@qq.com"},"repository":{"url":"git+https://github.com/thiscp/dsh-push.git","type":"git","directory":"host-plugin"},"_npmVersion":"10.9.2","description":"DSH host-side phone push: question events to ntfy + in-process answering via relay polling (replaces the external notifier + answer bridge)","directories":{},"_nodeVersion":"22.14.0","publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/schemastery":"^3.18.2"},"_npmOperationalInternal":{"tmp":"tmp/dsh-push-host_0.3.1_1793073738236_0.7487671268888426","host":"s3://npm-registry-packages-npm-production"}},"0.3.2":{"name":"dsh-push-host","version":"0.3.2","keywords":["dsh","dsh-plugin","deepseek-harness","cordis","push","ntfy","notification"],"author":{"url":"https://github.com/thiscp","name":"cpyh"},"license":"MIT","_id":"dsh-push-host@0.3.2","maintainers":[{"name":"cnop","email":"2059678566@qq.com"}],"contributors":[{"name":"DeepSeek Harness agents"}],"homepage":"https://github.com/thiscp/dsh-push/tree/main/host-plugin#readme","bugs":{"url":"https://github.com/thiscp/dsh-push/issues"},"bin":{"dsh-push-pair":"lib/pairing.mjs"},"dsh":{"bundle":{"patch":"./cordis.patch.yml","version":"1"},"client":{"platform":"web"}},"dist":{"shasum":"23ea68ddce0741dbb46498a22c809c2c2e6513ca","tarball":"https://registry.npmjs.org/dsh-push-host/-/dsh-push-host-0.3.2.tgz","fileCount":10,"integrity":"sha512-Llf19DdAp12M+xejPuodUffHjhA6vxRyeXGYTcz8cZOToeXyvSmc0r/zwCW2qanyohZFkkhqrYrtIwMJ2CGsTg==","signatures":[{"sig":"MEQCIG06CThKOc6PCu+Plhd9ShLirP2jNrxE3vpjbXRqLq4oAiB24XBJzDSEb5EJErB6ASjjzl2C1sP1xh/494oUfZY1Xw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIC7YXSOc+p5lR3SQ+3YoMbArIEziStdc98fWk0Gwu8zwAiEAun9A6QZOb7RQ0W20LrYFQ3O8LMGsRihPJrhwlhu3x8Q=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":173771},"main":"lib/index.js","type":"module","engines":{"node":">=20.11"},"exports":{".":"./lib/index.js","./relay":"./lib/relay.js","./client":"./lib/client.js","./pairing":"./lib/pairing.mjs","./credentials":"./lib/credentials.mjs","./pairing-lib":"./lib/pairing-lib.mjs","./package.json":"./package.json","./cordis.patch.yml":"./cordis.patch.yml"},"gitHead":"60c76e14062cb967ec046a80dece36d5ec330ac6","scripts":{"pair":"node lib/pairing.mjs","test":"node plugin-selftest.mjs"},"_npmUser":{"name":"cnop","email":"2059678566@qq.com"},"repository":{"url":"git+https://github.com/thiscp/dsh-push.git","type":"git","directory":"host-plugin"},"_npmVersion":"10.9.2","description":"DSH host-side phone push: question events to ntfy + in-process answering via relay polling (replaces the external notifier + answer bridge)","directories":{},"_nodeVersion":"22.14.0","publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/schemastery":"^3.18.2"},"_npmOperationalInternal":{"tmp":"tmp/dsh-push-host_0.3.2_1793076859866_0.18915734150972086","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"dsh-push-host","version":"0.4.0","keywords":["dsh","dsh-plugin","deepseek-harness","cordis","push","ntfy","notification"],"author":{"url":"https://github.com/thiscp","name":"cpyh"},"license":"MIT","_id":"dsh-push-host@0.4.0","maintainers":[{"name":"cnop","email":"2059678566@qq.com"}],"contributors":[{"name":"DeepSeek Harness agents"}],"homepage":"https://github.com/thiscp/dsh-push/tree/main/host-plugin#readme","bugs":{"url":"https://github.com/thiscp/dsh-push/issues"},"bin":{"dsh-push-pair":"lib/pairing.mjs"},"dsh":{"bundle":{"patch":"./cordis.patch.yml","version":"1"},"client":{"platform":"web"}},"dist":{"shasum":"022a56b44ef94c3258b95435c7d83a672a6606c7","tarball":"https://registry.npmjs.org/dsh-push-host/-/dsh-push-host-0.4.0.tgz","fileCount":11,"integrity":"sha512-Je14Hl8xXMGBwoCzWnUo+Sg+mxI2/8REsCijEfg1ziaPGPro15raPXMYXsBkuLQcnGHNu1HtGvqxAnMg9O3mQA==","signatures":[{"sig":"MEQCIEzx0ChFc8mw9voQbn5piImxKTZV1w+NOBSqcS9lRNC+AiAt1QUVa6F3FhyWlYe+XL+nqlFpFVja8MGndNjDzGvIBw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIEyNGObEGPwzmtIhvLcZVaRXwQpaTbnw9i98TLCSJIBaAiEA48KOgbN48I69+sSGZWL5vybmwX1jcvyQc9CeiVY+QMI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":225535},"main":"lib/index.js","type":"module","engines":{"node":">=20.11"},"exports":{".":"./lib/index.js","./relay":"./lib/relay.js","./client":"./lib/client.js","./remote":"./lib/remote.js","./pairing":"./lib/pairing.mjs","./credentials":"./lib/credentials.mjs","./pairing-lib":"./lib/pairing-lib.mjs","./package.json":"./package.json","./cordis.patch.yml":"./cordis.patch.yml"},"gitHead":"ea95e1fd54deffd4e0bbbcf1e8041c1b9f6bc92a","scripts":{"pair":"node lib/pairing.mjs","test":"node plugin-selftest.mjs"},"_npmUser":{"name":"cnop","email":"2059678566@qq.com"},"repository":{"url":"git+https://github.com/thiscp/dsh-push.git","type":"git","directory":"host-plugin"},"_npmVersion":"10.9.2","description":"DSH host-side phone push: question events to ntfy + in-process answering via relay polling (replaces the external notifier + answer bridge)","directories":{},"_nodeVersion":"22.14.0","publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/schemastery":"^3.18.2"},"_npmOperationalInternal":{"tmp":"tmp/dsh-push-host_0.4.0_1793164322213_0.8475224704185638","host":"s3://npm-registry-packages-npm-production"}},"0.4.1":{"name":"dsh-push-host","version":"0.4.1","keywords":["dsh","dsh-plugin","deepseek-harness","cordis","push","ntfy","notification"],"author":{"url":"https://github.com/thiscp","name":"cpyh"},"license":"MIT","_id":"dsh-push-host@0.4.1","maintainers":[{"name":"cnop","email":"2059678566@qq.com"}],"contributors":[{"name":"DeepSeek Harness agents"}],"homepage":"https://github.com/thiscp/dsh-push/tree/main/host-plugin#readme","bugs":{"url":"https://github.com/thiscp/dsh-push/issues"},"bin":{"dsh-push-pair":"lib/pairing.mjs"},"dsh":{"bundle":{"patch":"./cordis.patch.yml","version":"1"},"client":{"platform":"web"}},"dist":{"shasum":"1c33b9f835fb236b2f7ed60edf89379048b588da","tarball":"https://registry.npmjs.org/dsh-push-host/-/dsh-push-host-0.4.1.tgz","fileCount":11,"integrity":"sha512-Q9i9hIvo2I4VJnT2RNe2PVv60sODSK6yN9Jw16+JE1q7TNFSivuWhP7jP2z5falhhP5iIVsnVkei6T8GgfU5+w==","signatures":[{"sig":"MEYCIQCbgkr9XEEr80wUn3MJqUTLtOCMr0NALuFBf6U+wkCwgwIhAKGDw+MDdr647u+XE0TlPMGqtb5kSDFgSC+nlmPZRfzj","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQCvku7ONkTY7KWdPSKrjZDLzh/n4eXtTF2BKZDsz2T49QIhANBE0OlTs+HGe3N8vfEx9CZT2vgZmTvwYpb6bA+dMVh1","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":228051},"main":"lib/index.js","type":"module","engines":{"node":">=20.11"},"exports":{".":"./lib/index.js","./relay":"./lib/relay.js","./client":"./lib/client.js","./remote":"./lib/remote.js","./pairing":"./lib/pairing.mjs","./credentials":"./lib/credentials.mjs","./pairing-lib":"./lib/pairing-lib.mjs","./package.json":"./package.json","./cordis.patch.yml":"./cordis.patch.yml"},"gitHead":"71c7970f782ca4cac8c9e77cee6803dce1e78905","scripts":{"pair":"node lib/pairing.mjs","test":"node plugin-selftest.mjs"},"_npmUser":{"name":"cnop","email":"2059678566@qq.com"},"repository":{"url":"git+https://github.com/thiscp/dsh-push.git","type":"git","directory":"host-plugin"},"_npmVersion":"10.9.2","description":"DSH host-side phone push: question events to ntfy + in-process answering via relay polling (replaces the external notifier + answer bridge)","directories":{},"_nodeVersion":"22.14.0","publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/schemastery":"^3.18.2"},"_npmOperationalInternal":{"tmp":"tmp/dsh-push-host_0.4.1_1793165611186_0.18814101609935463","host":"s3://npm-registry-packages-npm-production"}},"0.4.2":{"name":"dsh-push-host","version":"0.4.2","keywords":["dsh","dsh-plugin","deepseek-harness","cordis","push","ntfy","notification"],"author":{"url":"https://github.com/thiscp","name":"cpyh"},"license":"MIT","_id":"dsh-push-host@0.4.2","maintainers":[{"name":"cnop","email":"2059678566@qq.com"}],"contributors":[{"name":"DeepSeek Harness agents"}],"homepage":"https://github.com/thiscp/dsh-push/tree/main/host-plugin#readme","bugs":{"url":"https://github.com/thiscp/dsh-push/issues"},"bin":{"dsh-push-pair":"lib/pairing.mjs"},"dsh":{"bundle":{"patch":"./cordis.patch.yml","version":"1"},"client":{"platform":"web"}},"dist":{"shasum":"f7e847a06a72afbd8a81e4cfac7295c6942c566f","tarball":"https://registry.npmjs.org/dsh-push-host/-/dsh-push-host-0.4.2.tgz","fileCount":11,"integrity":"sha512-r4/VpIkUFS5eh6hact6KCu2Z9rGBuq67PONjkDV+0MRa/FP4KRZ003h/Rnb1h0IGlBrjL4bY4sUDZSDNjVt/Tw==","signatures":[{"sig":"MEQCIB2ibmrlcHCmWzzxy0pIEglmJUhor6AXGouKekZAbMyKAiAdjYockZf9tiwmdd3S4/C91Qxna0vjACmOlr8J4QgCyg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIBA2zdmCyaxlecmt5wyg0Qsgw9kNU+aRDuvqXv4c8cCrAiAPdSsNPc/kuEn2p6wJxSYGiAcoLT4pfddhPDvmySbsbA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":228940},"main":"lib/index.js","type":"module","engines":{"node":">=20.11"},"exports":{".":"./lib/index.js","./relay":"./lib/relay.js","./client":"./lib/client.js","./remote":"./lib/remote.js","./pairing":"./lib/pairing.mjs","./credentials":"./lib/credentials.mjs","./pairing-lib":"./lib/pairing-lib.mjs","./package.json":"./package.json","./cordis.patch.yml":"./cordis.patch.yml"},"gitHead":"c7105bb5b02776690c68603c9b123198a284776c","scripts":{"pair":"node lib/pairing.mjs","test":"node plugin-selftest.mjs"},"_npmUser":{"name":"cnop","email":"2059678566@qq.com"},"repository":{"url":"git+https://github.com/thiscp/dsh-push.git","type":"git","directory":"host-plugin"},"_npmVersion":"10.9.2","description":"DSH host-side phone push: question events to ntfy + in-process answering via relay polling (replaces the external notifier + answer bridge)","directories":{},"_nodeVersion":"22.14.0","publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/schemastery":"^3.18.2"},"_npmOperationalInternal":{"tmp":"tmp/dsh-push-host_0.4.2_1793166135870_0.2425464790200419","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"dsh-push-host","version":"0.5.0","keywords":["dsh","dsh-plugin","deepseek-harness","cordis","push","ntfy","notification"],"author":{"url":"https://github.com/thiscp","name":"cpyh"},"license":"MIT","_id":"dsh-push-host@0.5.0","maintainers":[{"name":"cnop","email":"2059678566@qq.com"}],"contributors":[{"name":"DeepSeek Harness agents"}],"homepage":"https://github.com/thiscp/dsh-push/tree/main/host-plugin#readme","bugs":{"url":"https://github.com/thiscp/dsh-push/issues"},"bin":{"dsh-push-pair":"lib/pairing.mjs"},"dsh":{"bundle":{"patch":"./cordis.patch.yml","version":"1"},"client":{"platform":"web"}},"dist":{"shasum":"5b0bd601d70acb434765d35eac02938ffb0cc048","tarball":"https://registry.npmjs.org/dsh-push-host/-/dsh-push-host-0.5.0.tgz","fileCount":12,"integrity":"sha512-dwwtH//5xgk6D6uG5W/CjknQ+4/P2C3/5pQS6n6Lcm5afwtMou+vXatdwD2xytP5fXnlmO6pD9uBrRJX7WAKjg==","signatures":[{"sig":"MEYCIQDisbuqhCc+yVbNEIt7Kk1mNvrP5VyJ8wEpA7REtIGU0QIhAL+yEsQpmL32Ik0Adxt6EVexgDCFphkSJF5juiICVg5b","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIDggECy6u2EgnKa38pGpjuM706sytp7qmJkSa8sEl4NgAiEA8ociNrVpdJHXHJUmSIqCZqXCOeZezI0Ld/E7+IrdmYI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":251813},"main":"lib/index.js","type":"module","engines":{"node":">=20.11"},"exports":{".":"./lib/index.js","./relay":"./lib/relay.js","./client":"./lib/client.js","./remote":"./lib/remote.js","./pairing":"./lib/pairing.mjs","./cloudflared":"./lib/cloudflared.mjs","./credentials":"./lib/credentials.mjs","./pairing-lib":"./lib/pairing-lib.mjs","./package.json":"./package.json","./cordis.patch.yml":"./cordis.patch.yml"},"gitHead":"7d35a685d739fa67d9cbb1cb3ee4b5187b2d5c6f","scripts":{"pair":"node lib/pairing.mjs","test":"node plugin-selftest.mjs"},"_npmUser":{"name":"cnop","email":"2059678566@qq.com"},"repository":{"url":"git+https://github.com/thiscp/dsh-push.git","type":"git","directory":"host-plugin"},"_npmVersion":"10.9.2","description":"DSH host-side phone push: question events to ntfy + in-process answering via relay polling (replaces the external notifier + answer bridge)","directories":{},"_nodeVersion":"22.14.0","publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/schemastery":"^3.18.2"},"_npmOperationalInternal":{"tmp":"tmp/dsh-push-host_0.5.0_1793169647402_0.7157915252467286","host":"s3://npm-registry-packages-npm-production"}},"0.5.1":{"name":"dsh-push-host","version":"0.5.1","keywords":["dsh","dsh-plugin","deepseek-harness","cordis","push","ntfy","notification"],"author":{"url":"https://github.com/thiscp","name":"cpyh"},"license":"MIT","_id":"dsh-push-host@0.5.1","maintainers":[{"name":"cnop","email":"2059678566@qq.com"}],"contributors":[{"name":"DeepSeek Harness agents"}],"homepage":"https://github.com/thiscp/dsh-push/tree/main/host-plugin#readme","bugs":{"url":"https://github.com/thiscp/dsh-push/issues"},"bin":{"dsh-push-pair":"lib/pairing.mjs"},"dsh":{"bundle":{"patch":"./cordis.patch.yml","version":"1"},"client":{"platform":"web"}},"dist":{"shasum":"f2799ef23b5b9d6ada58ca258bfe7509670a2f53","tarball":"https://registry.npmjs.org/dsh-push-host/-/dsh-push-host-0.5.1.tgz","fileCount":12,"integrity":"sha512-vHNK5Y9wdMtoSVJco7yqT7Jh90xd5pQR8DfXM7yCFygRLvIOWMorJEYRdzqGnpwHtMc1V+ehiFGAe4Jpq8m2Lg==","signatures":[{"sig":"MEQCID0in7GPQRaK1hhuGJmSaKNdmUHAZpZ8R6BtELw2myrRAiB05Ofyh9eBmqZeXN+1DJc3DvHbDPgVeXBzF269x8/sJA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIFiBN8Co7MMXEfPImnaCGl5cbSomv31M5mTARZwIhn1uAiEA03w/4taXCPkUBBEPeNFELQIoB/TAu9RX9+CQ3E0d6x4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":253938},"main":"lib/index.js","type":"module","engines":{"node":">=20.11"},"exports":{".":"./lib/index.js","./relay":"./lib/relay.js","./client":"./lib/client.js","./remote":"./lib/remote.js","./pairing":"./lib/pairing.mjs","./cloudflared":"./lib/cloudflared.mjs","./credentials":"./lib/credentials.mjs","./pairing-lib":"./lib/pairing-lib.mjs","./package.json":"./package.json","./cordis.patch.yml":"./cordis.patch.yml"},"gitHead":"741cd5f4a7f67d363e3e072c98c2657a277b0098","scripts":{"pair":"node lib/pairing.mjs","test":"node plugin-selftest.mjs"},"_npmUser":{"name":"cnop","email":"2059678566@qq.com"},"repository":{"url":"git+https://github.com/thiscp/dsh-push.git","type":"git","directory":"host-plugin"},"_npmVersion":"10.9.2","description":"DSH host-side phone push: question events to ntfy + in-process answering via relay polling (replaces the external notifier + answer bridge)","directories":{},"_nodeVersion":"22.14.0","publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/schemastery":"^3.18.2"},"_npmOperationalInternal":{"tmp":"tmp/dsh-push-host_0.5.1_1793172909659_0.04873443035188618","host":"s3://npm-registry-packages-npm-production"}},"0.6.0":{"name":"dsh-push-host","version":"0.6.0","keywords":["dsh","dsh-plugin","deepseek-harness","cordis","push","ntfy","notification"],"author":{"url":"https://github.com/thiscp","name":"cpyh"},"license":"MIT","_id":"dsh-push-host@0.6.0","maintainers":[{"name":"cnop","email":"2059678566@qq.com"}],"contributors":[{"name":"DeepSeek Harness agents"}],"homepage":"https://github.com/thiscp/dsh-push/tree/main/host-plugin#readme","bugs":{"url":"https://github.com/thiscp/dsh-push/issues"},"bin":{"dsh-push-pair":"lib/pairing.mjs"},"dsh":{"bundle":{"patch":"./cordis.patch.yml","version":"1"},"client":{"platform":"web"}},"dist":{"shasum":"9a79b6064220d5ed161f088d40d8c92a0b5d7f04","tarball":"https://registry.npmjs.org/dsh-push-host/-/dsh-push-host-0.6.0.tgz","fileCount":13,"integrity":"sha512-XXUYKtGFPCwhyFr3pepHPoe+nkGO4360EL22t1iqUg8KsKigMOWTQVGO+Qi6kdHwkimVlNm4lg0/UGZNV2KShQ==","signatures":[{"sig":"MEUCIQDO5t3JWQOtUN69mx3JS315Wa3jxgH/Igywzg2kLYDQeAIgHPxLgMSHnWIWUmhzXsSD+sMwx4ewNTKhIptLAfh0QgI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQDqJsMEuP4znl5OzwBtSfyn+GSrvZ77Jo/wzbYpPoeUiQIhAOn78EGTOCrifFqz8p+FBfIvQ6yMluD/AuMr6u8W7kIi","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":272984},"main":"lib/index.js","type":"module","engines":{"node":">=20.11"},"exports":{".":"./lib/index.js","./relay":"./lib/relay.js","./client":"./lib/client.js","./pairqr":"./lib/pairqr.mjs","./remote":"./lib/remote.js","./pairing":"./lib/pairing.mjs","./cloudflared":"./lib/cloudflared.mjs","./credentials":"./lib/credentials.mjs","./pairing-lib":"./lib/pairing-lib.mjs","./package.json":"./package.json","./cordis.patch.yml":"./cordis.patch.yml"},"gitHead":"8bd77adc19fb618064e9dfe91758926d7bbffee0","scripts":{"pair":"node lib/pairing.mjs","test":"node plugin-selftest.mjs && node selftest-pair.mjs && node selftest-remote-bin.mjs"},"_npmUser":{"name":"cnop","email":"2059678566@qq.com"},"repository":{"url":"git+https://github.com/thiscp/dsh-push.git","type":"git","directory":"host-plugin"},"_npmVersion":"11.21.1","description":"DSH host-side phone push: question events to ntfy + in-process answering via relay polling (replaces the external notifier + answer bridge)","directories":{},"_nodeVersion":"22.14.0","dependencies":{"qrcode-generator":"^2.0.4"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/schemastery":"^3.18.2"},"_npmOperationalInternal":{"tmp":"tmp/dsh-push-host_0.6.0_1793189967229_0.7066864954832521","host":"s3://npm-registry-packages-npm-production"}},"0.6.1":{"name":"dsh-push-host","version":"0.6.1","keywords":["dsh","dsh-plugin","deepseek-harness","cordis","push","ntfy","notification"],"author":{"url":"https://github.com/thiscp","name":"cpyh"},"license":"MIT","_id":"dsh-push-host@0.6.1","maintainers":[{"name":"cnop","email":"2059678566@qq.com"}],"contributors":[{"name":"DeepSeek Harness agents"}],"homepage":"https://github.com/thiscp/dsh-push/tree/main/host-plugin#readme","bugs":{"url":"https://github.com/thiscp/dsh-push/issues"},"bin":{"dsh-push-pair":"lib/pairing.mjs"},"dsh":{"bundle":{"patch":"./cordis.patch.yml","version":"1"},"client":{"platform":"web"}},"dist":{"shasum":"0de4b37f18259bc6bc2f08d4a47cc57168d7370b","tarball":"https://registry.npmjs.org/dsh-push-host/-/dsh-push-host-0.6.1.tgz","fileCount":13,"integrity":"sha512-WWtKpQBgTKJfVpm9qyjwsIBVDpDL2XeeKF/H8oIM4ju2yrD9EBt9VxGhx6pQiAUQUSTrBTohiMCoXboy9aHWrQ==","signatures":[{"sig":"MEQCIEsB/NnJdlfdY9IUD59G7kpud118KcRlglL1bA/rwftDAiBeQihHgXq5Txae3HRcAXZn9XtG9ph9G3GJy1nwL2nNPQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQCJilzuGbIEaXbvb/BL/8AcBZxCkXUN8zjAPAjnWMUW6QIgSIkYivaf8fnQTdmaQDX+SAMnl1E0RckPmVXmNIvZXRU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":276554},"main":"lib/index.js","type":"module","engines":{"node":">=20.11"},"exports":{".":"./lib/index.js","./relay":"./lib/relay.js","./client":"./lib/client.js","./pairqr":"./lib/pairqr.mjs","./remote":"./lib/remote.js","./pairing":"./lib/pairing.mjs","./cloudflared":"./lib/cloudflared.mjs","./credentials":"./lib/credentials.mjs","./pairing-lib":"./lib/pairing-lib.mjs","./package.json":"./package.json","./cordis.patch.yml":"./cordis.patch.yml"},"gitHead":"dd7907b44b90054d14eec5a817299ecdece351df","scripts":{"pair":"node lib/pairing.mjs","test":"node plugin-selftest.mjs && node selftest-pair.mjs && node selftest-remote-bin.mjs"},"_npmUser":{"name":"cnop","email":"2059678566@qq.com"},"repository":{"url":"git+https://github.com/thiscp/dsh-push.git","type":"git","directory":"host-plugin"},"_npmVersion":"11.21.1","description":"DSH host-side phone push: question events to ntfy + in-process answering via relay polling (replaces the external notifier + answer bridge)","directories":{},"_nodeVersion":"22.14.0","dependencies":{"qrcode-generator":"^2.0.4"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/schemastery":"^3.18.2"},"_npmOperationalInternal":{"tmp":"tmp/dsh-push-host_0.6.1_1793200968061_0.7534876768415086","host":"s3://npm-registry-packages-npm-production"}},"0.7.0":{"name":"dsh-push-host","version":"0.7.0","keywords":["dsh","dsh-plugin","deepseek-harness","cordis","push","ntfy","notification"],"author":{"url":"https://github.com/thiscp","name":"cpyh"},"license":"MIT","_id":"dsh-push-host@0.7.0","maintainers":[{"name":"cnop","email":"2059678566@qq.com"}],"contributors":[{"name":"DeepSeek Harness agents"}],"homepage":"https://github.com/thiscp/dsh-push/tree/main/host-plugin#readme","bugs":{"url":"https://github.com/thiscp/dsh-push/issues"},"bin":{"dsh-push-pair":"lib/pairing.mjs"},"dsh":{"bundle":{"patch":"./cordis.patch.yml","version":"1"},"client":{"platform":"web"}},"dist":{"shasum":"4c862781b7478721c20e13d39d3776337e456f0b","tarball":"https://registry.npmjs.org/dsh-push-host/-/dsh-push-host-0.7.0.tgz","fileCount":13,"integrity":"sha512-m5YzyAGhxYLc4MMKtsNpiJ1bwScCezYCMUSYv5A6lWj8DoNVEABazndXdGKFXQLhDR4L6+/Kj6KBWzuUX/lDCw==","signatures":[{"sig":"MEUCIQCk/uFTm2SfP+Bc8mJPAhJ8QjVghcopRplIZJBPTixW/gIgRR2uBKp0zIqygzgWPaUh+9lnXMqG2SSfVdOOkSIAd1k=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQCyyj6X832mP0lBD34bHhHfZWYapnecUObNsBepJXS4owIgWz9qvImZMzzLk2dVCCeX8d8mgMszZ5FoP+kZg1wez2U=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":286097},"main":"lib/index.js","type":"module","engines":{"node":">=20.11"},"exports":{".":"./lib/index.js","./relay":"./lib/relay.js","./client":"./lib/client.js","./pairqr":"./lib/pairqr.mjs","./remote":"./lib/remote.js","./pairing":"./lib/pairing.mjs","./cloudflared":"./lib/cloudflared.mjs","./credentials":"./lib/credentials.mjs","./pairing-lib":"./lib/pairing-lib.mjs","./package.json":"./package.json","./cordis.patch.yml":"./cordis.patch.yml"},"gitHead":"f66d3787a0d75c8cf42444da2db6ca759882c27b","scripts":{"pair":"node lib/pairing.mjs","test":"node plugin-selftest.mjs && node selftest-pair.mjs && node selftest-remote-bin.mjs"},"_npmUser":{"name":"cnop","email":"2059678566@qq.com"},"repository":{"url":"git+https://github.com/thiscp/dsh-push.git","type":"git","directory":"host-plugin"},"_npmVersion":"11.21.1","description":"DSH host-side phone push: question events to ntfy + in-process answering via relay polling (replaces the external notifier + answer bridge)","directories":{},"_nodeVersion":"22.14.0","dependencies":{"qrcode-generator":"^2.0.4"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/schemastery":"^3.18.2"},"_npmOperationalInternal":{"tmp":"tmp/dsh-push-host_0.7.0_1793257394065_0.758285938694981","host":"s3://npm-registry-packages-npm-production"}},"0.7.1":{"name":"dsh-push-host","version":"0.7.1","keywords":["dsh","dsh-plugin","deepseek-harness","cordis","push","ntfy","notification"],"author":{"url":"https://github.com/thiscp","name":"cpyh"},"license":"MIT","_id":"dsh-push-host@0.7.1","maintainers":[{"name":"cnop","email":"2059678566@qq.com"}],"contributors":[{"name":"DeepSeek Harness agents"}],"homepage":"https://github.com/thiscp/dsh-push/tree/main/host-plugin#readme","bugs":{"url":"https://github.com/thiscp/dsh-push/issues"},"bin":{"dsh-push-pair":"lib/pairing.mjs"},"dsh":{"bundle":{"patch":"./cordis.patch.yml","version":"1"},"client":{"platform":"web"}},"dist":{"shasum":"7bc7a84c347518e25a9501d4a343e9bf5cee9b28","tarball":"https://registry.npmjs.org/dsh-push-host/-/dsh-push-host-0.7.1.tgz","fileCount":13,"integrity":"sha512-34ec4p96hxvEMLDY71Fqf/4em6NQXFFS/g+hkauejuslxA4v+OYxOvfZeVWNT336lE80KU1bPOx4+yhUokT8bw==","signatures":[{"sig":"MEYCIQCjcMS5S0raUVn0BKduFiOyCPkGiUnMjYoM4rbMqGsNqQIhAMaG2LHeF6CgCLzyb/QjHbRD1f3OI8wUpEANI5jCCYLD","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQCVuTIsk1l989aHjrnz/sWnfHfnkLExuhOfdqLkELdUjgIgbodNQ3NhUnvOpASP7UROn5SkTQNo1/qilcUltjAGSJ0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":286930},"main":"lib/index.js","type":"module","engines":{"node":">=20.11"},"exports":{".":"./lib/index.js","./relay":"./lib/relay.js","./client":"./lib/client.js","./pairqr":"./lib/pairqr.mjs","./remote":"./lib/remote.js","./pairing":"./lib/pairing.mjs","./cloudflared":"./lib/cloudflared.mjs","./credentials":"./lib/credentials.mjs","./pairing-lib":"./lib/pairing-lib.mjs","./package.json":"./package.json","./cordis.patch.yml":"./cordis.patch.yml"},"gitHead":"f66d3787a0d75c8cf42444da2db6ca759882c27b","scripts":{"pair":"node lib/pairing.mjs","test":"node plugin-selftest.mjs && node selftest-pair.mjs && node selftest-remote-bin.mjs"},"_npmUser":{"name":"cnop","email":"2059678566@qq.com"},"repository":{"url":"git+https://github.com/thiscp/dsh-push.git","type":"git","directory":"host-plugin"},"_npmVersion":"11.21.1","description":"DSH host-side phone push: question events to ntfy + in-process answering via relay polling (replaces the external notifier + answer bridge)","directories":{},"_nodeVersion":"22.14.0","dependencies":{"qrcode-generator":"^2.0.4"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/schemastery":"^3.18.2"},"_npmOperationalInternal":{"tmp":"tmp/dsh-push-host_0.7.1_1793260140281_0.9376143262579533","host":"s3://npm-registry-packages-npm-production"}},"0.7.2":{"name":"dsh-push-host","version":"0.7.2","keywords":["dsh","dsh-plugin","deepseek-harness","cordis","push","ntfy","notification"],"author":{"url":"https://github.com/thiscp","name":"cpyh"},"license":"MIT","_id":"dsh-push-host@0.7.2","maintainers":[{"name":"cnop","email":"2059678566@qq.com"}],"contributors":[{"name":"DeepSeek Harness agents"}],"homepage":"https://github.com/thiscp/dsh-push/tree/main/host-plugin#readme","bugs":{"url":"https://github.com/thiscp/dsh-push/issues"},"bin":{"dsh-push-pair":"lib/pairing.mjs"},"dsh":{"bundle":{"patch":"./cordis.patch.yml","version":"1"},"client":{"platform":"web"}},"dist":{"shasum":"374268e49ab0b7f8fbe5becb4d65109c5a5b80be","tarball":"https://registry.npmjs.org/dsh-push-host/-/dsh-push-host-0.7.2.tgz","fileCount":13,"integrity":"sha512-DKdTcYpKyOls5ZlOsbwN0bySc83XrnJdmARMzd2GloojasyxGZyEyCNIaqHXkFMUW71lcBk/09O00uehmpbZzQ==","signatures":[{"sig":"MEUCIQCIMEJxi6Lfje8XBK8113szSSgNGjCf7iIn412Fi/CsMgIgOCpf9udNGzFsQQNjohrSBdcWlsvE7xmYfoBBwU6vAk4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIGrgWw0ke58Jkp2s1SLt28WGXMXh2n75kWJeRqurYc+7AiABN7mYRrjvf/gyvyNUtv2Boee+vfBr+hXphzGTvpU2zg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":287412},"main":"lib/index.js","type":"module","engines":{"node":">=20.11"},"exports":{".":"./lib/index.js","./relay":"./lib/relay.js","./client":"./lib/client.js","./pairqr":"./lib/pairqr.mjs","./remote":"./lib/remote.js","./pairing":"./lib/pairing.mjs","./cloudflared":"./lib/cloudflared.mjs","./credentials":"./lib/credentials.mjs","./pairing-lib":"./lib/pairing-lib.mjs","./package.json":"./package.json","./cordis.patch.yml":"./cordis.patch.yml"},"gitHead":"f66d3787a0d75c8cf42444da2db6ca759882c27b","scripts":{"pair":"node lib/pairing.mjs","test":"node plugin-selftest.mjs && node selftest-pair.mjs && node selftest-remote-bin.mjs"},"_npmUser":{"name":"cnop","email":"2059678566@qq.com"},"repository":{"url":"git+https://github.com/thiscp/dsh-push.git","type":"git","directory":"host-plugin"},"_npmVersion":"11.21.1","description":"DSH host-side phone push: question events to ntfy + in-process answering via relay polling (replaces the external notifier + answer bridge)","directories":{},"_nodeVersion":"22.14.0","dependencies":{"qrcode-generator":"^2.0.4"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/schemastery":"^3.18.2"},"_npmOperationalInternal":{"tmp":"tmp/dsh-push-host_0.7.2_1793260803726_0.15075792488811135","host":"s3://npm-registry-packages-npm-production"}},"0.7.3":{"name":"dsh-push-host","version":"0.7.3","keywords":["dsh","dsh-plugin","deepseek-harness","cordis","push","ntfy","notification"],"author":{"url":"https://github.com/thiscp","name":"cpyh"},"license":"MIT","_id":"dsh-push-host@0.7.3","maintainers":[{"name":"cnop","email":"2059678566@qq.com"}],"contributors":[{"name":"DeepSeek Harness agents"}],"homepage":"https://github.com/thiscp/dsh-push/tree/main/host-plugin#readme","bugs":{"url":"https://github.com/thiscp/dsh-push/issues"},"bin":{"dsh-push-pair":"lib/pairing.mjs"},"dsh":{"bundle":{"patch":"./cordis.patch.yml","version":"1"},"client":{"platform":"web"}},"dist":{"shasum":"1fb7a7993c94d96489fdfa7389063c1ecfd1ec87","tarball":"https://registry.npmjs.org/dsh-push-host/-/dsh-push-host-0.7.3.tgz","fileCount":13,"integrity":"sha512-SsyunEOIvNGLzhNxtW5H7ojVeqOq3Bi8HnnqSlzxeZLBIX0bBE9WoHK2JxFvVtjkNXJ+tyTYPzPXrevP/jffSA==","signatures":[{"sig":"MEQCID1mz09I/nmi04GtATeiLEj3B4hjZEFeSDgWbJ/dwubJAiAeki64Kzy1MHIBOTaE8X6CDfUfk4jkw3AAnMSgipDEVQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQDCo5URF73hT5bnjT9MoEtmjfsRtnHA5hqtDvJkZhmYmwIhAOtGgzBIM3oWzref66frXuWSQDh6gcOF69sf5IFmypQA","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":289421},"main":"lib/index.js","type":"module","engines":{"node":">=20.11"},"exports":{".":"./lib/index.js","./relay":"./lib/relay.js","./client":"./lib/client.js","./pairqr":"./lib/pairqr.mjs","./remote":"./lib/remote.js","./pairing":"./lib/pairing.mjs","./cloudflared":"./lib/cloudflared.mjs","./credentials":"./lib/credentials.mjs","./pairing-lib":"./lib/pairing-lib.mjs","./package.json":"./package.json","./cordis.patch.yml":"./cordis.patch.yml"},"gitHead":"b6d2c794ccc9adc93e1f48973ae1c86aad023152","scripts":{"pair":"node lib/pairing.mjs","test":"node plugin-selftest.mjs && node selftest-pair.mjs && node selftest-remote-bin.mjs"},"_npmUser":{"name":"cnop","email":"2059678566@qq.com"},"repository":{"url":"git+https://github.com/thiscp/dsh-push.git","type":"git","directory":"host-plugin"},"_npmVersion":"11.21.1","description":"DSH host-side phone push: question events to ntfy + in-process answering via relay polling (replaces the external notifier + answer bridge)","directories":{},"_nodeVersion":"22.14.0","dependencies":{"qrcode-generator":"^2.0.4"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/schemastery":"^3.18.2"},"_npmOperationalInternal":{"tmp":"tmp/dsh-push-host_0.7.3_1793263879673_0.9100939390662889","host":"s3://npm-registry-packages-npm-production"}},"0.7.4":{"name":"dsh-push-host","version":"0.7.4","keywords":["dsh","dsh-plugin","deepseek-harness","cordis","push","ntfy","notification"],"author":{"url":"https://github.com/thiscp","name":"cpyh"},"license":"MIT","_id":"dsh-push-host@0.7.4","maintainers":[{"name":"cnop","email":"2059678566@qq.com"}],"contributors":[{"name":"DeepSeek Harness agents"}],"homepage":"https://github.com/thiscp/dsh-push/tree/main/host-plugin#readme","bugs":{"url":"https://github.com/thiscp/dsh-push/issues"},"bin":{"dsh-push-pair":"lib/pairing.mjs"},"dsh":{"bundle":{"patch":"./cordis.patch.yml","version":"1"},"client":{"platform":"web"}},"dist":{"shasum":"b7bc898715783af4472e66901af788c0e50ca59b","tarball":"https://registry.npmjs.org/dsh-push-host/-/dsh-push-host-0.7.4.tgz","fileCount":13,"integrity":"sha512-QsbcEsl6h8TF4AULNjJTblHshfXcZfCQ5E9M9QTsv7ey+3JIAlIm3J7cI1ZcroQWJCyLx96IHQr/c5Uyh7U52Q==","signatures":[{"sig":"MEUCIAH8/pAgt5mI4EWWHyffcDxXZE+afMeA0r/MPa0e04UNAiEA9I/8smaiWsB1LxdS38zAcISCEwGEXGeGlS2JjKnP2o4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIHDsd03W4Tm8VEQv6YrzVOZ1y32rj+kGOs3USL41/5wsAiAnogwnir53BMWKAr1Jl0ibR2K3yGsJ21ZCWQylu69c6A==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":292693},"main":"lib/index.js","type":"module","engines":{"node":">=20.11"},"exports":{".":"./lib/index.js","./relay":"./lib/relay.js","./client":"./lib/client.js","./pairqr":"./lib/pairqr.mjs","./remote":"./lib/remote.js","./pairing":"./lib/pairing.mjs","./cloudflared":"./lib/cloudflared.mjs","./credentials":"./lib/credentials.mjs","./pairing-lib":"./lib/pairing-lib.mjs","./package.json":"./package.json","./cordis.patch.yml":"./cordis.patch.yml"},"gitHead":"49f7ec54e291a5bc0ee386098760bc52f2b02e07","scripts":{"pair":"node lib/pairing.mjs","test":"node plugin-selftest.mjs && node selftest-pair.mjs && node selftest-remote-bin.mjs"},"_npmUser":{"name":"cnop","email":"2059678566@qq.com"},"repository":{"url":"git+https://github.com/thiscp/dsh-push.git","type":"git","directory":"host-plugin"},"_npmVersion":"11.21.1","description":"DSH host-side phone push: question events to ntfy + in-process answering via relay polling (replaces the external notifier + answer bridge)","directories":{},"_nodeVersion":"22.14.0","dependencies":{"qrcode-generator":"^2.0.4"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/schemastery":"^3.18.2"},"_npmOperationalInternal":{"tmp":"tmp/dsh-push-host_0.7.4_1793266125510_0.36990114912488936","host":"s3://npm-registry-packages-npm-production"}},"0.7.5":{"name":"dsh-push-host","version":"0.7.5","keywords":["dsh","dsh-plugin","deepseek-harness","cordis","push","ntfy","notification"],"author":{"url":"https://github.com/thiscp","name":"cpyh"},"license":"MIT","_id":"dsh-push-host@0.7.5","maintainers":[{"name":"cnop","email":"2059678566@qq.com"}],"contributors":[{"name":"DeepSeek Harness agents"}],"homepage":"https://github.com/thiscp/dsh-push/tree/main/host-plugin#readme","bugs":{"url":"https://github.com/thiscp/dsh-push/issues"},"bin":{"dsh-push-pair":"lib/pairing.mjs"},"dsh":{"bundle":{"patch":"./cordis.patch.yml","version":"1"},"client":{"platform":"web"}},"dist":{"shasum":"682ffefe693a82730241e3f614d919fe8c5f01b0","tarball":"https://registry.npmjs.org/dsh-push-host/-/dsh-push-host-0.7.5.tgz","fileCount":13,"integrity":"sha512-86+DVHQp7JHM8sGu36T9mzpmsUEIXONCr2nG1EeO6Ykfv96wt394/JtBEsDARwd2nGQCkSDfoYYWPt8R5AlBMg==","signatures":[{"sig":"MEQCIEU3hysz4P7ymrsUai2ZRCayA1VY5VJ2SoqAW7FREb8hAiB7BJNtAXFBIDjF9Rd/Oiw9u8wonJHgxai3O/e/VYM6qw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIEBHi2+QgZkOTfeZwv+1TCOHdKBKjyUz4TXJ4BpU11d7AiAUigMv0GRMugC/fAzIlc4rf8mXSgdPTCxuB/CKu1C0Jw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":290909},"main":"lib/index.js","type":"module","engines":{"node":">=20.11"},"exports":{".":"./lib/index.js","./relay":"./lib/relay.js","./client":"./lib/client.js","./pairqr":"./lib/pairqr.mjs","./remote":"./lib/remote.js","./pairing":"./lib/pairing.mjs","./cloudflared":"./lib/cloudflared.mjs","./credentials":"./lib/credentials.mjs","./pairing-lib":"./lib/pairing-lib.mjs","./package.json":"./package.json","./cordis.patch.yml":"./cordis.patch.yml"},"gitHead":"49f7ec54e291a5bc0ee386098760bc52f2b02e07","scripts":{"pair":"node lib/pairing.mjs","test":"node plugin-selftest.mjs && node selftest-pair.mjs && node selftest-remote-bin.mjs"},"_npmUser":{"name":"cnop","email":"2059678566@qq.com"},"repository":{"url":"git+https://github.com/thiscp/dsh-push.git","type":"git","directory":"host-plugin"},"_npmVersion":"11.21.1","description":"DSH host-side phone push: question events to ntfy + in-process answering via relay polling (replaces the external notifier + answer bridge)","directories":{},"_nodeVersion":"22.14.0","dependencies":{"qrcode-generator":"^2.0.4"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/schemastery":"^3.18.2"},"_npmOperationalInternal":{"tmp":"tmp/dsh-push-host_0.7.5_1793267187710_0.7402265956847683","host":"s3://npm-registry-packages-npm-production"}},"0.7.6":{"name":"dsh-push-host","version":"0.7.6","keywords":["dsh","dsh-plugin","deepseek-harness","cordis","push","ntfy","notification"],"author":{"url":"https://github.com/thiscp","name":"cpyh"},"license":"MIT","_id":"dsh-push-host@0.7.6","maintainers":[{"name":"cnop","email":"2059678566@qq.com"}],"contributors":[{"name":"DeepSeek Harness agents"}],"homepage":"https://github.com/thiscp/dsh-push/tree/main/host-plugin#readme","bugs":{"url":"https://github.com/thiscp/dsh-push/issues"},"bin":{"dsh-push-pair":"lib/pairing.mjs"},"dsh":{"bundle":{"patch":"./cordis.patch.yml","version":"1"},"client":{"platform":"web"}},"dist":{"shasum":"a07b90091517258d31fe3e207197381f84a6f558","tarball":"https://registry.npmjs.org/dsh-push-host/-/dsh-push-host-0.7.6.tgz","fileCount":13,"integrity":"sha512-LZCZ1v+/3Fd7lomMQWabv1Y2LN2dNsNP05pypYOiEXISlKe4P0BeY/IJ7AtVpzZ8FWTzeRjSR8vy6eu2E/2+JQ==","signatures":[{"sig":"MEYCIQCu1Wal8wsZA02pXfcaCN6gavT8RRn+uO2yLRBCEn2MiwIhAI42DVFyv3+MDa29iQdGsir5oSW/oJ0dIz2Ra428mga2","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIGx9S3VFXy+xzMbcwvF2ytsw00M5U5AXMVom7C/kK1Y6AiAo6/XRZKVqCl24xJEfNNAOVMmAOARkjqHhdaXxQruiHA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":295739},"main":"lib/index.js","type":"module","engines":{"node":">=20.11"},"exports":{".":"./lib/index.js","./relay":"./lib/relay.js","./client":"./lib/client.js","./pairqr":"./lib/pairqr.mjs","./remote":"./lib/remote.js","./pairing":"./lib/pairing.mjs","./cloudflared":"./lib/cloudflared.mjs","./credentials":"./lib/credentials.mjs","./pairing-lib":"./lib/pairing-lib.mjs","./package.json":"./package.json","./cordis.patch.yml":"./cordis.patch.yml"},"gitHead":"68a7b8893c154370163254097d7375443048964b","scripts":{"pair":"node lib/pairing.mjs","test":"node plugin-selftest.mjs && node selftest-pair.mjs && node selftest-remote-bin.mjs"},"_npmUser":{"name":"cnop","email":"2059678566@qq.com"},"repository":{"url":"git+https://github.com/thiscp/dsh-push.git","type":"git","directory":"host-plugin"},"_npmVersion":"11.21.1","description":"DSH host-side phone push: question events to ntfy + in-process answering via relay polling (replaces the external notifier + answer bridge)","directories":{},"_nodeVersion":"22.14.0","dependencies":{"qrcode-generator":"^2.0.4"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/schemastery":"^3.18.2"},"_npmOperationalInternal":{"tmp":"tmp/dsh-push-host_0.7.6_1793272415726_0.5996078286212553","host":"s3://npm-registry-packages-npm-production"}},"0.7.7":{"name":"dsh-push-host","version":"0.7.7","keywords":["dsh","dsh-plugin","deepseek-harness","cordis","push","ntfy","notification"],"author":{"url":"https://github.com/thiscp","name":"cpyh"},"license":"MIT","_id":"dsh-push-host@0.7.7","maintainers":[{"name":"cnop","email":"2059678566@qq.com"}],"contributors":[{"name":"DeepSeek Harness agents"}],"homepage":"https://github.com/thiscp/dsh-push/tree/main/host-plugin#readme","bugs":{"url":"https://github.com/thiscp/dsh-push/issues"},"bin":{"dsh-push-pair":"lib/pairing.mjs"},"dsh":{"bundle":{"patch":"./cordis.patch.yml","version":"1"},"client":{"platform":"web"}},"dist":{"shasum":"2aef4585842b15cf0123a989a63515b360dd8fb9","tarball":"https://registry.npmjs.org/dsh-push-host/-/dsh-push-host-0.7.7.tgz","fileCount":13,"integrity":"sha512-AD0XBTH8f8tYwc4LTgLXbO+HWll/uglQ/Nj6dmnqF+RxPWT1CKoMTNMGas1wbq8c4QKdvjh7rg2/yllAH8f4HQ==","signatures":[{"sig":"MEUCIQD3SAZYZbtCyOe3w0Jw/fb/ZMo2gEc4/TabNUhVau+cTQIgWH+3Iua8zXAIm/hh3S0hohRMUwOb6LAYzQQMtFpYxUk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQDJb81MEZwmra5+FN1Ca8WErTxzDv8C3hh3shZ0OrAxWQIhALmDHxvAh7vDkP6IYJ2L3kWG6m1QHcIHeQlO/fWToiFa","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":296453},"main":"lib/index.js","type":"module","engines":{"node":">=20.11"},"exports":{".":"./lib/index.js","./relay":"./lib/relay.js","./client":"./lib/client.js","./pairqr":"./lib/pairqr.mjs","./remote":"./lib/remote.js","./pairing":"./lib/pairing.mjs","./cloudflared":"./lib/cloudflared.mjs","./credentials":"./lib/credentials.mjs","./pairing-lib":"./lib/pairing-lib.mjs","./package.json":"./package.json","./cordis.patch.yml":"./cordis.patch.yml"},"gitHead":"68a7b8893c154370163254097d7375443048964b","scripts":{"pair":"node lib/pairing.mjs","test":"node plugin-selftest.mjs && node selftest-pair.mjs && node selftest-remote-bin.mjs"},"_npmUser":{"name":"cnop","email":"2059678566@qq.com"},"repository":{"url":"git+https://github.com/thiscp/dsh-push.git","type":"git","directory":"host-plugin"},"_npmVersion":"11.21.1","description":"DSH host-side phone push: question events to ntfy + in-process answering via relay polling (replaces the external notifier + answer bridge)","directories":{},"_nodeVersion":"22.14.0","dependencies":{"qrcode-generator":"^2.0.4"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/schemastery":"^3.18.2"},"_npmOperationalInternal":{"tmp":"tmp/dsh-push-host_0.7.7_1793272837105_0.2835207204541704","host":"s3://npm-registry-packages-npm-production"}},"0.7.8":{"name":"dsh-push-host","version":"0.7.8","keywords":["dsh","dsh-plugin","deepseek-harness","cordis","push","ntfy","notification"],"author":{"url":"https://github.com/thiscp","name":"cpyh"},"license":"MIT","_id":"dsh-push-host@0.7.8","maintainers":[{"name":"cnop","email":"2059678566@qq.com"}],"contributors":[{"name":"DeepSeek Harness agents"}],"homepage":"https://github.com/thiscp/dsh-push/tree/main/host-plugin#readme","bugs":{"url":"https://github.com/thiscp/dsh-push/issues"},"bin":{"dsh-push-pair":"lib/pairing.mjs"},"dsh":{"bundle":{"patch":"./cordis.patch.yml","version":"1"},"client":{"platform":"web"}},"dist":{"shasum":"7c8ebf65f7a2d407f0de741cf6abe751b156a3aa","tarball":"https://registry.npmjs.org/dsh-push-host/-/dsh-push-host-0.7.8.tgz","fileCount":13,"integrity":"sha512-I9FD8d2C3LqQ+X5AayOv2NVcry/NQy7j+bmv+AoKWODBzjOMhsCgZlkqrN4144flYMRw3FWxkpOBTPdufDBbDQ==","signatures":[{"sig":"MEYCIQDSCbhhurBTf1rc8BmaW5MSJki67dsdJRnQx5cqH5haQQIhAPXzTeXj3FPMfRs5G6zc9syAzJ/TREr5YVkiDi76tl84","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQCDEjuNtsQVJkmkT4owjfSKRvVOtUP9fainIEDRfLu9GwIgNfHYo1bHsOp14VfOmFyWjHet4mcq+ePdtvUvbpU/yyE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":301435},"main":"lib/index.js","type":"module","engines":{"node":">=20.11"},"exports":{".":"./lib/index.js","./relay":"./lib/relay.js","./client":"./lib/client.js","./pairqr":"./lib/pairqr.mjs","./remote":"./lib/remote.js","./pairing":"./lib/pairing.mjs","./cloudflared":"./lib/cloudflared.mjs","./credentials":"./lib/credentials.mjs","./pairing-lib":"./lib/pairing-lib.mjs","./package.json":"./package.json","./cordis.patch.yml":"./cordis.patch.yml"},"gitHead":"1dabb12e9a05599fdfd7138de182931f57d2bdfb","scripts":{"pair":"node lib/pairing.mjs","test":"node plugin-selftest.mjs && node selftest-pair.mjs && node selftest-remote-bin.mjs"},"_npmUser":{"name":"cnop","email":"2059678566@qq.com"},"repository":{"url":"git+https://github.com/thiscp/dsh-push.git","type":"git","directory":"host-plugin"},"_npmVersion":"10.9.2","description":"DSH host-side phone push: question events to ntfy + in-process answering via relay polling (replaces the external notifier + answer bridge)","directories":{},"_nodeVersion":"22.14.0","dependencies":{"qrcode-generator":"^2.0.4"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/schemastery":"^3.18.2"},"_npmOperationalInternal":{"tmp":"tmp/dsh-push-host_0.7.8_1793274617400_0.8832042415152089","host":"s3://npm-registry-packages-npm-production"}},"0.7.9":{"name":"dsh-push-host","version":"0.7.9","keywords":["dsh","dsh-plugin","deepseek-harness","cordis","push","ntfy","notification"],"author":{"url":"https://github.com/thiscp","name":"cpyh"},"license":"MIT","_id":"dsh-push-host@0.7.9","maintainers":[{"name":"cnop","email":"2059678566@qq.com"}],"contributors":[{"name":"DeepSeek Harness agents"}],"homepage":"https://github.com/thiscp/dsh-push/tree/main/host-plugin#readme","bugs":{"url":"https://github.com/thiscp/dsh-push/issues"},"bin":{"dsh-push-pair":"lib/pairing.mjs"},"dsh":{"bundle":{"patch":"./cordis.patch.yml","version":"1"},"client":{"platform":"web"}},"dist":{"shasum":"b203681997a72759533fc42f8d56c1e5af88ef16","tarball":"https://registry.npmjs.org/dsh-push-host/-/dsh-push-host-0.7.9.tgz","fileCount":13,"integrity":"sha512-jIfsIRqP6Xjg8H8Xt/w2Vx7cBaPqsZSiJPMCXoMMAba5YAe3NeRKiW14yLv/gV7sSnVxqQm/qpCYFT9hHq4sYA==","signatures":[{"sig":"MEYCIQCubcwQ8gcCwqeSdRc/VsEqu+Qm7KtqELytgPv8vbCkqAIhAPZ/X2k95eSmPeO0BnVdN6KX9NIV7Mj+GrOtTN9AsgRc","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIB8wOOvSGnE7fZD6zZ2Bk4vBtu+a+wnPWUnD5oPd5Wk9AiEAwauoomo/xOtxBostQARdaLP/e1AK/gTc6ytJjeIgbXA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":304754},"main":"lib/index.js","type":"module","engines":{"node":">=20.11"},"exports":{".":"./lib/index.js","./relay":"./lib/relay.js","./client":"./lib/client.js","./pairqr":"./lib/pairqr.mjs","./remote":"./lib/remote.js","./pairing":"./lib/pairing.mjs","./cloudflared":"./lib/cloudflared.mjs","./credentials":"./lib/credentials.mjs","./pairing-lib":"./lib/pairing-lib.mjs","./package.json":"./package.json","./cordis.patch.yml":"./cordis.patch.yml"},"gitHead":"609ddfaee061f384ea2f3486b8a1428af8aa9845","scripts":{"pair":"node lib/pairing.mjs","test":"node plugin-selftest.mjs && node selftest-pair.mjs && node selftest-remote-bin.mjs"},"_npmUser":{"name":"cnop","email":"2059678566@qq.com"},"repository":{"url":"git+https://github.com/thiscp/dsh-push.git","type":"git","directory":"host-plugin"},"_npmVersion":"10.9.2","description":"DSH host-side phone push: question events to ntfy + in-process answering via relay polling (replaces the external notifier + answer bridge)","directories":{},"_nodeVersion":"22.14.0","dependencies":{"qrcode-generator":"^2.0.4"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/schemastery":"^3.18.2"},"_npmOperationalInternal":{"tmp":"tmp/dsh-push-host_0.7.9_1793275800445_0.9730310178171575","host":"s3://npm-registry-packages-npm-production"}},"0.7.10":{"name":"dsh-push-host","version":"0.7.10","keywords":["dsh","dsh-plugin","deepseek-harness","cordis","push","ntfy","notification"],"author":{"url":"https://github.com/thiscp","name":"cpyh"},"license":"MIT","_id":"dsh-push-host@0.7.10","maintainers":[{"name":"cnop","email":"2059678566@qq.com"}],"contributors":[{"name":"DeepSeek Harness agents"}],"homepage":"https://github.com/thiscp/dsh-push/tree/main/host-plugin#readme","bugs":{"url":"https://github.com/thiscp/dsh-push/issues"},"bin":{"dsh-push-pair":"lib/pairing.mjs"},"dsh":{"bundle":{"patch":"./cordis.patch.yml","version":"1"},"client":{"platform":"web"}},"dist":{"shasum":"14a1e2df2baba9f88e415791933ebc1998a6b7ae","tarball":"https://registry.npmjs.org/dsh-push-host/-/dsh-push-host-0.7.10.tgz","fileCount":13,"integrity":"sha512-NDXHg7XpZmVk+hnIjH/RPrG3X/lEVgIDfNlJBGGxCFNQDse6sDF5K875fQke7kQRd/EZknq5rj9yYvagQBVysQ==","signatures":[{"sig":"MEUCIARsMSpA1AY2XM2i9OoPPghzNcDQT/J3R0lU1kVYN/MmAiEA16b2neep71ZKWnZLPAnDOVNyoFiKpxK8zj3/d6uKa/w=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQC0KqIcxWRQ7txncKEdPd6oU/FGiJ5O0PQehtcdyGx+qAIgLHZYjt+fRpkuyC09kgwysg3/gj5VHwlgwApZ6YlIkdU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":304755},"main":"lib/index.js","type":"module","engines":{"node":">=20.11"},"exports":{".":"./lib/index.js","./relay":"./lib/relay.js","./client":"./lib/client.js","./pairqr":"./lib/pairqr.mjs","./remote":"./lib/remote.js","./pairing":"./lib/pairing.mjs","./cloudflared":"./lib/cloudflared.mjs","./credentials":"./lib/credentials.mjs","./pairing-lib":"./lib/pairing-lib.mjs","./package.json":"./package.json","./cordis.patch.yml":"./cordis.patch.yml"},"gitHead":"609ddfaee061f384ea2f3486b8a1428af8aa9845","scripts":{"pair":"node lib/pairing.mjs","test":"node plugin-selftest.mjs && node selftest-pair.mjs && node selftest-remote-bin.mjs"},"_npmUser":{"name":"cnop","email":"2059678566@qq.com"},"repository":{"url":"git+https://github.com/thiscp/dsh-push.git","type":"git","directory":"host-plugin"},"_npmVersion":"10.9.2","description":"DSH host-side phone push: question events to ntfy + in-process answering via relay polling (replaces the external notifier + answer bridge)","directories":{},"_nodeVersion":"22.14.0","dependencies":{"qrcode-generator":"^2.0.4"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/schemastery":"^3.18.2"},"_npmOperationalInternal":{"tmp":"tmp/dsh-push-host_0.7.10_1793275889628_0.37291282861701336","host":"s3://npm-registry-packages-npm-production"}},"0.7.11":{"name":"dsh-push-host","version":"0.7.11","keywords":["dsh","dsh-plugin","deepseek-harness","cordis","push","ntfy","notification"],"author":{"url":"https://github.com/thiscp","name":"cpyh"},"license":"MIT","_id":"dsh-push-host@0.7.11","maintainers":[{"name":"cnop","email":"2059678566@qq.com"}],"contributors":[{"name":"DeepSeek Harness agents"}],"homepage":"https://github.com/thiscp/dsh-push/tree/main/host-plugin#readme","bugs":{"url":"https://github.com/thiscp/dsh-push/issues"},"bin":{"dsh-push-pair":"lib/pairing.mjs"},"dsh":{"bundle":{"patch":"./cordis.patch.yml","version":"1"},"client":{"platform":"web"}},"dist":{"shasum":"2cfd331fafc7420d7ae0dfd3d7e1202f574553ef","tarball":"https://registry.npmjs.org/dsh-push-host/-/dsh-push-host-0.7.11.tgz","fileCount":13,"integrity":"sha512-3iJc8p69K/l5FBQ3KDOlQ+xzm68YsLsvSAFYtISIvBXdPCGz1mUCEqVsh8Vqaket7e7B9DFZERchMAingz+qRw==","signatures":[{"sig":"MEQCIC5WUe+ypGQ9iGPtjztx3jHPwzEQWr/qqzBf02Ex5sVhAiByz6jCnKR8mfG9FVazvteuSHYh2Tk56e30H/AYMviY9A==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQC/i+9iHsE0Y+SoCwAwvDPJMW9gE2oRKA2pB6nv39RNzQIgQbE5YCQDGSE2wZWQ2eY2gigEGaqko0vu6CEf4djp7jo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":310134},"main":"lib/index.js","type":"module","engines":{"node":">=20.11"},"exports":{".":"./lib/index.js","./relay":"./lib/relay.js","./client":"./lib/client.js","./pairqr":"./lib/pairqr.mjs","./remote":"./lib/remote.js","./pairing":"./lib/pairing.mjs","./cloudflared":"./lib/cloudflared.mjs","./credentials":"./lib/credentials.mjs","./pairing-lib":"./lib/pairing-lib.mjs","./package.json":"./package.json","./cordis.patch.yml":"./cordis.patch.yml"},"gitHead":"9aef1870ebd48fdab2e2dd0b66d060daeb67ec60","scripts":{"pair":"node lib/pairing.mjs","test":"node plugin-selftest.mjs && node selftest-pair.mjs && node selftest-remote-bin.mjs && node selftest-remote-status.mjs"},"_npmUser":{"name":"cnop","email":"2059678566@qq.com"},"repository":{"url":"git+https://github.com/thiscp/dsh-push.git","type":"git","directory":"host-plugin"},"_npmVersion":"10.9.2","description":"DSH host-side phone push: question events to ntfy + in-process answering via relay polling (replaces the external notifier + answer bridge)","directories":{},"_nodeVersion":"22.14.0","dependencies":{"qrcode-generator":"^2.0.4"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/schemastery":"^3.18.2"},"_npmOperationalInternal":{"tmp":"tmp/dsh-push-host_0.7.11_1793325916899_0.757929989362035","host":"s3://npm-registry-packages-npm-production"}},"0.7.12":{"name":"dsh-push-host","version":"0.7.12","keywords":["dsh","dsh-plugin","deepseek-harness","cordis","push","ntfy","notification"],"author":{"url":"https://github.com/thiscp","name":"cpyh"},"license":"MIT","_id":"dsh-push-host@0.7.12","maintainers":[{"name":"cnop","email":"2059678566@qq.com"}],"contributors":[{"name":"DeepSeek Harness agents"}],"homepage":"https://github.com/thiscp/dsh-push/tree/main/host-plugin#readme","bugs":{"url":"https://github.com/thiscp/dsh-push/issues"},"bin":{"dsh-push-pair":"lib/pairing.mjs"},"dsh":{"bundle":{"patch":"./cordis.patch.yml","version":"1"},"client":{"platform":"web"}},"dist":{"shasum":"c8a22d27d7ee753c0ec13d8d6a577dda5304a1ec","tarball":"https://registry.npmjs.org/dsh-push-host/-/dsh-push-host-0.7.12.tgz","fileCount":13,"integrity":"sha512-hUywlBe/dhQZIcE15iPwzvnyeHQwlJOwZClH4TpDKLNCpWvTbpLew6CpRMQk+Ulm0X1Q2xlA4es7yh7nz/F9gQ==","signatures":[{"sig":"MEUCIQDUuJjESMgnyoq2yKPotToiDrIoNwCNI4UIhgcyePKfDgIgRDR52evbvxyycei9YMDWiVC8P54R4p4/GBpWffgh+tc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCICsADr46xNFBwdGRfhkH7/3NjBUfVnhCgCOocXDdMkZwAiEAwfQmTE6vNMWcHdSjVtz27CqBxWr0RDEK5hFLmOG6hZ4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":317389},"main":"lib/index.js","type":"module","engines":{"node":">=20.11"},"exports":{".":"./lib/index.js","./relay":"./lib/relay.js","./client":"./lib/client.js","./pairqr":"./lib/pairqr.mjs","./remote":"./lib/remote.js","./pairing":"./lib/pairing.mjs","./cloudflared":"./lib/cloudflared.mjs","./credentials":"./lib/credentials.mjs","./pairing-lib":"./lib/pairing-lib.mjs","./package.json":"./package.json","./cordis.patch.yml":"./cordis.patch.yml"},"gitHead":"95574505ba75be5b49893f437609aae8e8b2b81b","scripts":{"pair":"node lib/pairing.mjs","test":"node plugin-selftest.mjs && node selftest-pair.mjs && node selftest-remote-bin.mjs && node selftest-remote-status.mjs"},"_npmUser":{"name":"cnop","email":"2059678566@qq.com"},"repository":{"url":"git+https://github.com/thiscp/dsh-push.git","type":"git","directory":"host-plugin"},"_npmVersion":"10.9.2","description":"DSH host-side phone push: question events to ntfy + in-process answering via relay polling (replaces the external notifier + answer bridge)","directories":{},"_nodeVersion":"22.14.0","dependencies":{"qrcode-generator":"^2.0.4"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/schemastery":"^3.18.2"},"_npmOperationalInternal":{"tmp":"tmp/dsh-push-host_0.7.12_1793332829076_0.6761353019633538","host":"s3://npm-registry-packages-npm-production"}},"0.7.13":{"_id":"dsh-push-host@0.7.13","bin":{"dsh-push-pair":"lib/pairing.mjs"},"dsh":{"bundle":{"patch":"./cordis.patch.yml","version":"1"},"client":{"platform":"web"}},"bugs":{"url":"https://github.com/thiscp/dsh-push/issues"},"dist":{"shasum":"c839721e0c4018420519b885b33568393b91b096","tarball":"https://registry.npmjs.org/dsh-push-host/-/dsh-push-host-0.7.13.tgz","fileCount":13,"integrity":"sha512-+WpZIOGHfu0K+mjNobbImqpE0rjjj7F7Mn5HCWqvGSnvnA666Wikl9PlLDLNI+v053hidsGkldMSwSDOrq0iUQ==","signatures":[{"sig":"MEQCIG9cfFZdZZV9mByGin4WE0v7cwLDQNemAJh7NaEhmyHnAiBKJ1XOK6rcZvVWUB358q9Iy9laXUvAARR3KAa7cGABRg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQC65l4rcMWWkwXWsA79zRKtj4lpWcyfiL4oizsEEvR+CgIgLcs4nkSv1jtaazWw82geBVWUkiITWjseFm8jrWkIHPk="}],"unpackedSize":317739},"main":"lib/index.js","name":"dsh-push-host","type":"module","author":{"url":"https://github.com/thiscp","name":"cpyh"},"engines":{"node":">=20.11"},"exports":{".":"./lib/index.js","./relay":"./lib/relay.js","./client":"./lib/client.js","./pairqr":"./lib/pairqr.mjs","./remote":"./lib/remote.js","./pairing":"./lib/pairing.mjs","./cloudflared":"./lib/cloudflared.mjs","./credentials":"./lib/credentials.mjs","./pairing-lib":"./lib/pairing-lib.mjs","./package.json":"./package.json","./cordis.patch.yml":"./cordis.patch.yml"},"gitHead":"a7f234ca79e847473c87c62b365f75b1b6240fa2","license":"MIT","scripts":{"pair":"node lib/pairing.mjs","test":"node plugin-selftest.mjs && node selftest-pair.mjs && node selftest-remote-bin.mjs && node selftest-remote-status.mjs"},"version":"0.7.13","_npmUser":{"name":"cnop","email":"2059678566@qq.com"},"homepage":"https://github.com/thiscp/dsh-push/tree/main/host-plugin#readme","keywords":["dsh","dsh-plugin","deepseek-harness","cordis","push","ntfy","notification"],"repository":{"url":"git+https://github.com/thiscp/dsh-push.git","type":"git","directory":"host-plugin"},"_npmVersion":"10.9.2","description":"DSH host-side phone push: question events to ntfy + in-process answering via relay polling (replaces the external notifier + answer bridge)","directories":{},"maintainers":[{"name":"cnop","email":"2059678566@qq.com"}],"_nodeVersion":"22.14.0","contributors":[{"name":"DeepSeek Harness agents"}],"dependencies":{"qrcode-generator":"^2.0.4"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org/"},"_hasShrinkwrap":false,"peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/schemastery":"^3.18.2"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/dsh-push-host_0.7.13_1793333395338_0.9972638442591427"}}},"time":{"created":"2026-10-27T04:01:21.709Z","modified":"2026-10-30T04:09:55.594Z","0.0.0-stage":"2026-10-27T04:01:21.709Z","0.3.1":"2026-10-27T04:02:18.330Z","0.3.2":"2026-10-27T04:54:20.021Z","0.4.0":"2026-10-28T05:12:02.334Z","0.4.1":"2026-10-28T05:33:31.487Z","0.4.2":"2026-10-28T05:42:15.979Z","0.5.0":"2026-10-28T06:40:47.542Z","0.5.1":"2026-10-28T07:35:09.801Z","0.6.0":"2026-10-28T12:19:27.408Z","0.6.1":"2026-10-28T15:22:48.204Z","0.7.0":"2026-10-29T07:03:14.157Z","0.7.1":"2026-10-29T07:49:00.366Z","0.7.2":"2026-10-29T08:00:03.860Z","0.7.3":"2026-10-29T08:51:19.768Z","0.7.4":"2026-10-29T09:28:45.638Z","0.7.5":"2026-10-29T09:46:27.828Z","0.7.6":"2026-10-29T11:13:35.814Z","0.7.7":"2026-10-29T11:20:37.205Z","0.7.8":"2026-10-29T11:50:17.534Z","0.7.9":"2026-10-29T12:10:00.539Z","0.7.10":"2026-10-29T12:11:29.718Z","0.7.11":"2026-10-30T02:05:17.046Z","0.7.12":"2026-10-30T04:00:29.194Z","0.7.13":"2026-10-30T04:09:55.447Z"},"bugs":{"url":"https://github.com/thiscp/dsh-push/issues"},"author":{"url":"https://github.com/thiscp","name":"cpyh"},"license":"MIT","homepage":"https://github.com/thiscp/dsh-push/tree/main/host-plugin#readme","keywords":["dsh","dsh-plugin","deepseek-harness","cordis","push","ntfy","notification"],"repository":{"url":"git+https://github.com/thiscp/dsh-push.git","type":"git","directory":"host-plugin"},"description":"DSH host-side phone push: question events to ntfy + in-process answering via relay polling (replaces the external notifier + answer bridge)","contributors":[{"name":"DeepSeek Harness agents"}],"maintainers":[{"name":"cnop","email":"2059678566@qq.com"}],"readme":"# dsh-push-host\n\nDSH 宿主插件：**进程内**把待答问题推到手机（ntfy），并把手机迟到作答灌回 agent。\n它是\"外部通知器 + 外部作答桥\"这条老链路的替代品 —— 插件跑在 DSH 自己进程里，用 DSH 的\n`userQuestions` seam，不再需要 cookie、`/api/remote.mux`、RPC，也不再需要伺候 token 轮换。\n\n```\nask_user_question (工具, 进程内)\n  └─ ctx.waterfall(\"user-questions/request\")\n       ├─ dsh-push-host 监听器（prepend）\n       │    ├─ POST relay /answer/register  {callId, agentId, questions, hostId}   ← 手机能答\n       │    ├─ POST relay /            (ntfy JSON: 标题/正文/#qid/#opts/#web/#name) ← 手机收到\n       │    └─ return next()            ← 前台作答权仍归 DSH Web UI（插件不抢）\n       └─ Web UI 作答器（浏览器在线时照旧作答）\n     轮询环 ctx.interval(s)\n       └─ GET relay /answer/pending?host=X (X-Host-Token)\n            ├─ 问题仍在 open 窗口 → 不 ack，留在 relay 队列里等（答案不丢）\n            └─ 问题已 continued   → ctx.userQuestions.answer(活根 agent, callId, {answers})\n                                   → agent.steer(答案消息) → ack\n```\n\n## 两条硬约束（先读，不然会白跑）\n\n1. **`request.wait.timed` 必须为 true，手机作答才可能生效。**\n   `answer()` 只能答 **continued** 态（`dsh-user-questions` 的投影只 fold `wait.timed === true` 的调用）。\n   而 `ask_user_question` 只有在 `tool-ask-user` 配 `mode: timed` 时才会走 `askTimed()`。\n   **本机实测（2026-10-12）**：`web` / `desktop` / `headless` 三个 profile 的 `tool-ask-user`\n   都是默认 `mode: legacy`（`--dump-config` 里该条目无 `config`），所以现状是\n   `wait = { callId }`、`timed=false` → 投影永远空 → 手机作答无法落地（只能弹通知）。\n   插件对每个问题都打 `timed=` 并在 `timed=false` 时明确拒绝（把该答案 ack 掉并打印原因），\n   不会静默丢答案。\n   要开：`tool-ask-user` 加 `config: { mode: timed, timeout: <秒> }`（0 选项窗口消失，\n   工具到点先返回 `pending`、agent 继续干活，之后手机答案以 user 消息形式插回 agent）。\n2. **不要和老的 hook 推送同时开。** `deploy/windows/hooks.json` 的 `PreToolUse` 推送与\n   本插件是同一件事的两条路径，同时开会双推（通知栏两条卡片）。任务结束（`Stop`）推送目前\n   仍归 hook 路径，本插件只做\"提问 → 作答\"这一环。\n\n## 三个踩过的坑（都在这份代码里修掉了，别改回去）\n\n1. **同一个 URL 反复 GET 会被喂回第一次的响应。** 轮询环最初用固定 URL\n   `…/answer/pending?host=X`，实测（2026-10-12 真机）：relay 队列里明明有两三条待答，\n   插件却反复只处理最早那一条、新的永远不出现。给 URL 追加一个每次都不同的\n   `&_=<毫秒时间戳>` 后立刻正常。**结论：走 DSH 的 fetch（自带代理层）做轮询，URL 必须唯一化。**\n   证据：加 `_` 之前日志只有 `delivery deferred for <旧 callId>`；加之后立刻出现\n   `queue: 2 item(s) [旧 新]`，两条都被处理。\n2. **投影状态是嵌套的。** `sessionProjections.stateOf(session, 'userQuestions')` 返回的是\n   fold 的内部 state：`{ timed, questions: { active, settled } }` —— active/settled 在\n   **`questions` 下面**（照抄 `dsh-user-questions` 自己 `continued()` 的写法）。少写一层会拿到\n   `undefined`，而早期代码把 `undefined` 当\"问题已结束\"→ 把仍在等待中的问题的答案静默 ack 掉。\n   **现在的判据是：只有 `settled` 里明确有该 callId 才丢弃，读不到状态一律留在队列里重试**\n   （relay TTL 1h 兜底，日志按 callId 节流）。\n3. **前台窗口期内的答案要\"扣着\"。** `answer()` 只认 `state === 'continued'`；`state === 'open'`\n   时调用它返回 `false`。此时**不 ack**、留在队列里，等前台等待结束（timed 的 timeout / UI 作答）\n   下一轮再投。\n\n## 发布后从 npm 装回来时踩的坑（2026-10-27，第六个）\n\n1. **`priority` 只能是整数 1–5，字符串 `'default'` 会被 relay 判成非法 JSON。**\n   `RelayClient.push()` 的默认值原来是字符串 `'default'`（那是 ntfy **请求头**写法里的取值），\n   而 ntfy 的 **JSON body** 只接受数字 ⇒ 服务端回\n   `400 {\"code\":40024,\"error\":\"invalid request: request body must be valid JSON\"}`。\n   这条报错把人往\"body 不是合法 JSON\"上引，实际 body 完全合法，只是 `priority` 类型不对。\n   插件内部三个调用点都显式传了 `4 / 1 / 3`，所以线上一直没暴露；**只有\"没传 priority\"的外部\n   调用方（自己写脚本验证、第三方集成）会踩**。0.3.2 起默认值改成整数 `3`。\n   同一条规则也解释了为什么 `priority: 'high'`、`priority: '4'` 都 400，而 `3`、`4`、`\"4\"` 之外\n   的数字全 200 —— **别把请求头的取值抄进 JSON body。**\n\n## 生产切换踩过的坑（2026-10-12/13，五个，都在这份代码里修掉了）\n\n1. **schema 校验后的空默认值会盖掉凭据文件。** `apply()` 拿到的 `config` 已经过 schema 校验，\n   空串默认值（`host: ''`、`hostToken: ''`、`ntfyToken: ''`、`regToken: ''`…）**全都在**，\n   于是 `{...fromCredentials, ...config}` 把文件贡献的每个值都擦成空 → 插件在**完全正常的**\n   凭据文件上打 `relay disabled`（旧 hook 已退役 = 手机彻底收不到通知）。\n   修法：空串/`undefined`/`null` 一律算\"没设置\"，`false` 仍然有效（`explicit` 过滤）。\n   回归断言：`plugin-selftest-credentials.mjs` 的「① 空 schema 默认值不覆盖凭据文件」\n   与「① 显式非空仍赢，`false` 不被当成 unset」两条 —— 用**整份 schema 形状的 config**\n   （每个字段都带默认值）打 `resolvePluginConfig`，这是唯一能复现该 bug 的输入形状。\n2. **`regToken` 必须同时在两张表里。** `lib/index.js` 的 `CREDENTIAL_CONFIG_KEYS`（决定哪些键\n   *可以*来自文件）与 `lib/credentials.mjs` 的 `CREDENTIAL_KEYS`（决定文件里的键怎么*读进来*）\n   是两处独立白名单。只改前者 = 文件里的 `regToken` 从来不会出现在 `file.value` 里，\n   `pickConfigKeys` 什么也挑不到，`X-Reg-Token` 发空串 →\n   `POST /answer/register` 永远 `401 bad reg token`（relay 侧判据：\n   `X-Reg-Token != open(\"/etc/answer-relay/regtoken\").read().strip()`）。\n   回归断言：`② 每个 CREDENTIAL_KEYS 字段都在 CREDENTIAL_CONFIG_KEYS 里` +\n   「`POST /answer/register` 真的带上文件里的 `X-Reg-Token`」（线级断言，不是看 getter）。\n3. **`dsh plugin add` 会重写 profile 的 `cordis.patch.yml`**（注释被丢、行尾换成 LF），\n   而且**同版本 `file:` 再 add 一次是 no-op**（\"Already up to date\"，代码不会替换）。\n   改完代码要生效必须：`Remove-Item -Recurse ~\\.dsh\\profiles\\<p>\\node_modules\\<包>` →\n   `dsh plugin --profile <p> add <tarball|dir>` →（热加载不生效，见下）重启宿主。\n   `hmr` 插件**不会**重载 profile 的 node_modules 里的 bundle 插件：实测改一行注释后\n   web.log 十分钟没有新的 `relay ready`。所以「改代码 → 重启」是硬路径。\n4. **顶层按 id patch `tool-ask-user` 会 `entry not found`。** 它不在 profile 根节点上，而是\n   **嵌在 agent preset 的 `plugins:` 列表里**（`preset-standard` / `preset-ptc` / …，一份 profile\n   里可以有好几个同名节点）。改它要么**改进那份 preset 的完整声明里**（patch 会整块替换\n   `config`，所以必须逐字重述整份 preset，见 `profiles/web/cordis.patch.yml` 里由\n   `make-preset-override.mjs` 生成的那份），要么用顶层 `- insert:` 插一个新节点。\n   **`--dump-config` 退出码 0 不等于挂上了**：先看目标 id 那一行的内容。\n5. **日志里的 `timed=false` 不一定是真的。** `tools/pre-execute`（竞位兜底触发点）在 waterfall\n   之前跑，只能从**工具入参**猜 `timed`（`args.timeout`）；而模型通常**不传**那个可选参数 →\n   猜到 `false`，随后真正权威的 `user-questions/request`（看 `wait.timed`）被 `announce()` 的\n   去重挡掉，于是\"唯一的证据\"就是那条错的 `timed=false` + 那句\"没 timed wait\"的 note。\n   2026-10-13 排查 ② 时被它误导过一轮。修法：`timed` 被 waterfall 校正回 `true` 时补打\n   `question <callId> timed corrected to true by the request waterfall (…)`，并且\n   **register 成功也打一行 `register <callId> -> HTTP 200`**（原来只打失败，401 反而藏在\n   \"没有 200 那行\"里）。\n   **权威判据只有两个**：probe/waterfall 打出来的 `wait.timed`，以及\"问题到点后返回\n   `{pending:true}`\"（legacy 模式永远返回不了 pending，它要么等到 UI 作答、要么 `NO_PROVIDER`）。\n   反过来，模型显式传 `timeout: -1`（\"必须等到答案\"）时走的是 **legacy** 路径 ——\n   那时 `timed=false` 是真的，手机作答确实落不了地（`{\"error\":\"no user-questions answerer\n   accepted the request\"}`），这不是配置错。\n6. **默认凭据路径曾经是 cwd 相对路径。** `CREDENTIALS_FILE` 原为\n   `.config/dsh-push/credentials.json`（相对），经 `path.resolve()` 后**跟着进程 cwd 走**：\n   web 实例的 cwd 恰好是 `C:\\Users\\cnop` 所以一直没事；换个目录起 DSH（工作区、仓库根、\n   快捷方式的\"起始位置\"）就**静默丢失凭据**（缺文件 = 干净 no-op，日志里只剩一句\n   `relay disabled`）。修法：默认值改成 `~/.config/dsh-push/credentials.json`（显式 `~`，\n   由 `expandHome` 拼到 home）；用户自己写的相对路径仍是 cwd 相对。\n   回归断言：`⑤ 默认路径锚在 home 目录，不跟 cwd 走`；另外 `plugin-selftest.mjs` 第 5 节\n   现在**显式钉一个不存在的 credentialsFile**——修好路径之后，它才会去读开发机真实的凭据文件。\n\n## 网页提问卡的生命周期：legacy 提问为什么会僵卡锁 composer（2026-10-14，源码级根因，用户真机实遇）\n\n现场：`claimForeground=on` 下手机抢答成功（`answered (foreground)`、工具当场返回、会话继续），\n但 DSH Web 的提问卡停在可交互未答态**霸占 composer**，用户发不出新消息只能点「跳过」；**刷新也不会好**\n（gateway 把仍挂着的转发请求重投给重连浏览器，未答卡原样重现）。服务端没有任何错：答案已按\n`tool/result` 落 transcript，对已结算 callId 再点跳过是无害空操作\n（`UserQuestionService.answer` 对不在 `continued` 的直接 `return false`）。\n\n根因（三层同时失效，缺一都不会僵）：\n\n1. **没人取消转发给浏览器的那条 dispatch**：插件（prepend listener）race 赢过 `next()` 提前结算\n   瀑布后，`dsh-api-remotes` 的 `forwardWaterfall` 没有\"上游已结算\"的取消路径，dispatch 悬挂；\n2. **cancel 帧不发**：gateway 的 cancel 只由 `request.signal` abort 触发，而 legacy 的 signal 是\n   回合 phase 信号，正常完成**永不 abort**（新 phase 只替换 AbortController 不 abort 旧的）；\n3. **投影不含 legacy**：`userQuestions` 投影按设计只折叠 `timed` 调用（判据=会话 header 记录的\n   工具 schema 是否声明 `timeout`），legacy 提问连 callId 都不带（匿名卡），reconcile 的删除\n   通道直接跳过它。\n\n**会话代际钉死**（最容易误判的一点）：ask_user_question 的 timed/legacy 变体在**会话创建时**\n钉进会话 header，**改 profile + 重启都不换**老会话的变体。所以 `mode: timed` 配好之后：\n新建会话双向同步正常（手机答→wait 关→signal abort→cancel 帧→卡片即关；网页答→回声→手机卡转已答，\n2026-10-14 用户真机验收过）；老会话仍是 legacy，僵卡照旧点「跳过」无害解锁。\n判据：web.log 该 callId 行 `timed=` 值（注意坑 5 的校正假象，权威判据仍是 `wait.timed`）。\n\n**根治 legacy 的最小补丁**（DSH 源码仓，`packages/user-questions`，编译层\n`dsh-user-questions/lib/index.js` 的 `ask()`）：新建 `const dispatchDone = new AbortController()`，\n向 waterfall 传 `signal: AbortSignal.any([request.signal, dispatchDone.signal])`，`finally` 里\n`dispatchDone.abort()`——瀑布被**任何**应答者（含进程内抢答）结算即触发 gateway cancel 帧关卡，\ntimed 路径行为不变。插件侧修不了（`firstOf` 赢后够不着那条 dispatch，别在插件里补）。\n\n## 端到端验收记录（2026-10-12，真 agent + 真 relay + 真 ntfy）\n\n测试 profile `pushtest`（`--from-default-profile headless` 新建），覆盖层插入\n`tool-ask-user`（`mode: timed, timeout: 60`）与本插件，让一个真 agent 连问两个问题；\n在第一个问题的**前台窗口期内**用 curl 从手机侧提交答案：\n\n| 观测 | 证据 |\n|---|---|\n| 通知层推送 | ntfy topic 收到 `DSH 等你选择 [1054fc8c]`，正文含 `📱 作答: …/answer/<callId>` + `#qid q1` + `#opts q1=first\\|second` + `#name win-test`，priority 4 |\n| 注册生效 | `GET …/answer/<callId>` 返回作答页；`POST /answer/submit` 回 `{\"ok\":true,\"queued\":true,\"host\":\"test1\"}` |\n| 窗口期内扣住 | `not answerable yet (state=open); keeping the phone answer queued and retrying` |\n| 超时后投递 | `answered (continued) call_00_5Y7r…`（`ctx.userQuestions.answer()` 返回 true）→ ack → 队列清空 |\n| **agent 真的收到** | agent 最终回复：*\"The first call returned pending (no answer before the 60-second timeout); the user later answered it with \\\"second\\\".\"* |\n| 手机清通知 | topic 收到 `DSH 已答` + `#ans <callId> second`，priority 1 |\n| **任务结束推送** | topic 收到 `DSH 任务结束 [1150afd5]`，正文 `目录: F:\\work\\work_dsh` + `#name win-test`，priority 3（同轮只发一次） |\n| **UI/任意端作答回声** | 真工具调用返回答案后 topic 收到 `DSH 已答` + `#ans <callId> first`，priority 1（`tools/post-execute` 路径） |\n| 挂载验收 | `--dump-config` 尾部 `# == dsh-push-host` / `- id: push-host` / `name: dsh-push-host` |\n| 纯逻辑回归 | `node plugin-selftest.mjs` → `48/48 checks passed` |\n\n## 分发（npm 包）\n\n本包按可发布的 npm 包组织（`package.json` 带 `repository` / `homepage` / `bugs` / `author` /\n`publishConfig.access: public` / `engines` / `files` 白名单，MIT `LICENSE` 随包）。\n用户侧只需 `dsh plugin add`：\n\n**已发布到 npm：`dsh-push-host@0.3.2`（2026-10-27）** — https://registry.npmjs.org/dsh-push-host\n（`latest` 即最新版；`repository.directory = host-plugin`，市场据此自动关联 npm 包）\n\n```powershell\n# 从 npm 装（推荐，免 allowBuilds 构建授权）\n& $dsh plugin --profile <profile> add dsh-push-host\n\n# 从 tarball 装（离线/内网，等价路径，已实测）\n& $dsh plugin --profile <profile> add ./dsh-push-host-0.3.2.tgz\n\n# 从本地目录装（开发期，改完立即生效）\n& $dsh plugin --profile <profile> add \"link:<仓库>/host-plugin\"\n```\n\n三种方式在 profile 里的落点完全相同：`package.json` 的 `dependencies` 多一项、`dsh.profile.bundles`\n多一项（DSH 读到本包的 `dsh.bundle.patch` 自动登记 bundle 层）。\n\n**打包**：有 npm 的机器直接 `npm pack`（`files` 白名单已配好）。\nDSH 运行时只带 pnpm 的机器上，仓库里配了等价工具，输出同样的 `npm notice` 清单与 sha1：\n\n```powershell\n& $node tools/pack-npm-tarball.mjs host-plugin --dry-run   # 只看清单，不落盘\n& $node tools/pack-npm-tarball.mjs host-plugin             # 落盘 host-plugin/dsh-push-host-0.3.2.tgz\n```\n\n实测产物 9 个文件：`LICENSE`、`README.md`、`cordis.patch.yml`、`package.json`、\n`lib/{index.js,relay.js,credentials.mjs,pairing-lib.mjs,pairing.mjs}`（合计 85,706 B，tarball 30,300 B）。\n`package.json` 里的 `files` 白名单决定这份清单；两个 `*-selftest*.mjs` 与 `relay-selftest.mjs`\n**不进包**，需要验收就 `git clone` 仓库跑。\n\n一条命令复现\"清单 → 打包 → 装进全新 profile → 验挂载 → 验凭据文件\"（8/8）：\n\n```powershell\n& $node tools/verify-distribution.mjs --profile pushdist      # 也可 --profile <新名> 全新建 profile\n```\n\n## 安装（已验证命令序列）\n\n```powershell\n$dsh = '<DSH 安装目录>\\resources\\runtime\\cli\\bin\\dsh.cmd'      # 不在 PATH 上\n\n# 1. 从随附模板新建 profile（别动 web / desktop 这两个在用的）\n& $dsh --profile pushdist --from-default-profile headless --dump-config\n\n# 2. 把包（或 tarball）装进去\n& $dsh plugin --profile pushdist add ./dsh-push-host-0.3.2.tgz\n\n# 3. 验收挂载：看 dump-config 尾部\n& $dsh --profile pushdist --dump-config | Select-Object -Last 3\n#   # == dsh-push-host\n#   - id: push-host\n#     name: dsh-push-host\n```\n\n`dsh plugin add` 后 `profiles/<name>/package.json` 应有两处变化：`dependencies` 多一项、\n`dsh.profile.bundles` 多一项（bundle 机制会读本包 `package.json` 的 `dsh.bundle.patch`）。\n`pnpm` 报 missing peer（`@deepseek-ai/cordis` 等）是**设计如此**：peer 由宿主 closure 提供。\n三个 profile 里 `--dump-config` **不加载**插件（只打印树），所以 dump-config 里看不到插件的\n`credentials file:` / `relay ready` 日志——那是启动时才打的。\n\n**一键版**（给用户用，2026-10-14 实测）：上面三步 + timed 切换 + dump-config 验收打包成一条命令，\n幂等（marker 判重）、改前带备份、新建 profile 的 `[]` 空模板会整体替换而不是追加\n（`[]` 后追加块序列是非法 YAML，实测炸过）：\n\n```powershell\n& powershell -NoProfile -ExecutionPolicy Bypass -File deploy/windows/install-user.ps1 `\n    -Profile <profile> -DshCli \"<DSH 安装目录>\\resources\\runtime\\cli\\bin\\dsh.cmd\" `\n    -Source .\\dsh-push-host-0.3.2.tgz\n# 成功后照打印的 next steps 走：重启 DSH（工具注册是冷的）→ 用新会话（变体钉在会话创建时）\n```\n\n## 设置页开关：手机作答模式（v0.2.1，用户不用碰命令行）\n\n装 0.2.1 后，设置页出现 **dsh-push 手机作答模式** 一行：显示**实际**是 `timed`（手机可作答）\n还是 `legacy`（手机只能收通知），右侧一个「启用」按钮。点一下即完成上面「一键版」里\n`tool-ask-user` 那步的全部工作——**且不需要重启宿主**。\n\n> **0.2.0 是坏版本，别用**（2026-10-14 生产 P0）：它的 `askUserMode` 默认 `legacy`，把\n> 「用户没表态」当成「用户要 legacy」，开机 sync 直接把生产 `tool-ask-user` 从 timed 反向\n> 降级成 legacy 并写进 patch 文件；回滚文件后活进程又被 reconcile 触发再降级两次。0.2.1\n> 的守卫（下面表格）逐条对着这三个缺陷修。\n\n内部链路（都已源码核实 + selftest 覆盖）：\n\n| 环节 | 实现 |\n|---|---|\n| 客户端 UI | `lib/client.js` 手写 `window.__ModuleLoader__.load({id:\"dsh-push-host\"})` 模块，注册 `settings.general.item` 槽行，`whileServed('push-host')` 门控；`package.json` 加 `dsh.client:{platform:\"web\"}` + `exports \"./client\"` |\n| 状态判定与展示 | 宿主侧 `ctx.tools.get(\"ask_user_question\")` 看 schema 是否含 `timeout` 参数（= timed 变体，判据同 DSH 的 `isTimedAskUserQuestionSchema`）；实际态经 `Symbol.for('cosmokit.volatile.write')` 写进 volatile `askUserActual`（**纯内存不落盘**），设置行读它——**不拿期望态当展示值**；`tools/change` 补激活顺序坑 |\n| 客户端→宿主 | 设置行写 push-host 自己的 `.volatile()` 字段 `askUserMode`（**无默认值**：schemastery 不加 `.default/.required` 即 optional——注意它没有 `.optional()` 方法也没有 `z.literal`）；宿主订阅 `ctx.on('loader/volatile-update', paths)`（该事件只投 owning fiber）触发 |\n| 永不降级 | **只有显式 `timed` 会写**；未表态或 `legacy` 完全惰性（零写入零备份）；`configEditor.edit` 前还有最后一道闸断言 `desired === 'timed'` |\n| 每进程一次 | 成功写一次后置 `done`，后续 sync 直接 return——外部修复（还原文件→reconcile）不会被活进程当成漂移再改回去 |\n| HMR 事务 | volatile-update 在 settings RPC 的 HMR 事务内触发，事务里嵌套 `configEditor.edit` 会抛 `HMR transactions cannot be nested`；所有 sync 经 `setTimeout(0)` 延后到事务外合并执行 |\n| 写入 | `ctx.configEditor.edit(tool-ask-user entry, …)`——DSH 官方通道：文件锁 + 原子写 + 失败回滚 + 热 reconcile；写非 volatile 字段会热重启该插件 fiber，timed 工具当场重注册 |\n| 备份 | `configEditor` 无内建 .bak，edit 前自己 `copyFileSync(patchPath, patchPath + '.bak-<ms>')`（撞名加序号） |\n| 失败可见 | 任何失败（含 home 层/CLI overlay 覆盖同 id 的 \"overridden by a home patch\"）经同一 volatile 符号写进 `askUserStatus`（**内存，不落盘**——0.2.0 曾把状态字符串写进用户 patch），设置行直接显示原因 |\n\n生效范围（UI 上明写，也都是平台事实）：**新会话立即生效**；已在跑的老会话保持旧行为——\n`ask_user_question` 的 timed/legacy 变体在**会话创建时**钉进会话 header，改配置/重启都不换\n（见下文「网页提问卡的生命周期」）。若老会话踩到 legacy 僵卡，点卡片「跳过」无害解锁。\n本开关**只升不降**：要回 legacy 手动改 profile 的 `cordis.patch.yml`（`mode: legacy`）。\n\n无 UI 的场景（headless/VM/自动化）继续用 `deploy/windows/install-user.ps1`，两者干的是同一件事。\n\n**selftest 运行时注意**（2026-10-14 实测坑）：必须用 **DSH 自带 runtime 的 node**\n（`<DSH 安装目录>\\resources\\runtime\\primary-runtime\\dependencies\\node\\bin\\node.exe`）。\nharness 自己的 `~\\.dsh\\dsh-runtimes\\...` 那个 node 同为 v24.21.0、`os.tmpdir()` 同为 `C:\\Temp`，\n但 `copyFileSync` 被拒（`EPERM: operation not permitted, copyfile`）；14 段前有 preflight\n探针，撞到这个坑会打印指引并 **exit 2**（不是假 FAIL）。真基线 **136/136**（2026-10-17 复跑实测；v0.2.2 加 3 条 hash 片段断言；v0.3.0 加 32 条发号断言：URL 拼装、通行证文本、名字清洗、HTTP 四种结果、凭据写回与备份与别名同步、面板状态机含「同一个 seq 绝不重复发号」、**列表载荷瘦身后的形状**（每行只有 `name`+`topics`）、**`CREDENTIAL_KEYS` 与 `CREDENTIAL_CONFIG_KEYS` 必须同步**（第三条防线，见下）、fiber 热重启后回灌进程级暂存、垂死 fiber 把结果交接给新 fiber）。\n\n## 点推送直达来源会话（v0.2.2）\n\n用户「通过消息通知上的卡片的 dsh 网页按钮进入网页后，似乎是之前默认的对话，能进入后直接进入推送通知的那个对话吗」。\n\n两半都在本插件里，**不需要改 DSH 本体、不需要发 App 版本**：\n\n1. **服务端半**（`lib/index.js:webUrl(sessionId)`）：把来源会话 id 作为 **URL hash 片段**拼到 `#web` 链接尾\n   （`…?token=X#session-<uuid>`）。两条推送路径都带：提问（`questionBody(callId, questions, sessionId)`）\n   与任务结束（`onTurnStopping`）。\n2. **浏览器半**（`lib/client.js:revealFromHash(ctx)`）：读 hash，若当前会话不是它，就展开侧栏、点\n   `[data-row-key=\"session:<id>\"]` 那一行；到位后把 hash 抹掉（`history.replaceState`），免得用户切走后\n   刷新又被拽回来。\n\n**为什么是 hash 片段而不是查询参数**（两条实测理由，别再改回去）：\n\n- `?token=` 入口回的是 **`303 See Other → Location: ./`**，查询串在这一步被丢掉；而浏览器跨跳转**保留 fragment**。\n- 网页客户端**根本没有路由**（`createRouter` 在 bundle 里 0 命中；`pushState`/`popstate` 的命中都在 lodash 注释里），\n  所以路径和查询串都没人读。\n\n**选择器全是语义化的**（不依赖哈希类名，改版风险低）：当前会话 `[data-conversation-session=\"<id>\"]`、\n侧栏行 `[data-row-key=\"session:<id>\"]`、展开侧栏 `button[aria-label=\"Open sidebar\"]`。这些都是 2026-10-17\n在 VM1 的 DSH Web 上实测出来的（窄屏 360 CSS px，模拟器 WebView + CDP）。\n\n**降级安全**：id 形态不对（不是 `session-<uuid>`）就不拼链接；网页端找不到那一行（会话未加载、分组收起）\n就静默放弃，最多 20s，等于本功能之前的行为。不认识 hash 的旧网页端也完全不受影响。\n\n## 自助通行证发号面板（v0.3.0，多人自由使用）\n\n用户「我希望能在插件里面有按钮什么的自动生成一个给手机用的通行证，这样的话才能让多人都能自由的使用我们的插件」。\n\n**为什么必须有中继侧的服务**（不是插件能自己解决的）：我们的 ntfy 2.29.0 里 access-token 的 HTTP API **根本没编译进去**\n（`grep -a -c /v1/tokens /usr/bin/ntfy` = 0），`POST /v1/users` 能建用户但**静默忽略** topic 授权 ⇒ 按 topic 授权与发 token\n**只能在服务器上跑 ntfy CLI**。所以中继上跑了一个极小的发号服务 `dsh-provd`（见仓库 `relay/README.md`），\n本插件是它的 HTTP 客户端。\n\n**新配置项**：\n\n| 键 | 默认 | 说明 |\n|---|---|---|\n| `provisionBase` | `https://ntfy.cpyh.xyz/provision` | 发号服务基址（经 edge nginx 反代到 `127.0.0.1:2588`） |\n| `provisionToken` | 空 | 发号服务的共享密钥（服务端 `/etc/dsh-provd/secret`）。**优先用环境变量 `DSH_PUSH_PROVISION_TOKEN`**，别写进 git |\n| `provisionTokenEnv` | `DSH_PUSH_PROVISION_TOKEN` | 上面那个环境变量名 |\n\n三项都在 `CREDENTIAL_CONFIG_KEYS` 里 ⇒ 可以放凭据文件（分层：默认 < 凭据文件 < profile < env）。\n\n**面板长在哪**：DSH 网页「设置 → 通用」里新增一行「通行证」（`settings.general.item`，id `push-host-pass-panel`，order 130，\n就在「手机作答模式」下面）。输入框预填宿主建议的名字（`provisionDefault`，由 `host`/`webName` 清洗而来，中文/空名退化成\n`dsh-local`），三个动作：**发通行证**、**刷新列表**、每条已发通行证后面的**吊销**。\n\n**往返机制**（浏览器只能写 volatile 字段，这是实测出来的硬约束）：\n\n```\n浏览器 scope.mutate 写 volatile: provisionAction + provisionSeq(+ provisionName)\n   ↓ ctx.on('loader/volatile-update') 命中 provision* ⇒ setTimeout(0) 出 HMR 事务\n宿主 PassProvisioner.run() ⇒ POST {provisionBase}/issue|revoke、GET /list\n   ↓ setVolatileValue 只写内存镜像（绝不 configEditor，免得把结果字符串写进 cordis.patch.yml）\n浏览器读 provisionResult（通行证文本）/ provisionList（JSON 列表）/ provisionDone（== 本次 seq 就收工）\n```\n\n- **`provisionSeq` 是浏览器生成的请求号**：同一个名字连点两次也必须各得一次结果，所以不能只看 action 字段的变化；\n  宿主对**同一个 seq 绝不重复发号**（selftest 有这条）。页面 busy 用 `done === seq` 判，另加 30s 兜底防宿主不在。\n- **发号成功会写回本机凭据文件**（`topic` + `ntfyToken`=只写 token + `phoneToken`=只读 token），写前自动备份\n  `credentials.json.bak-<ts>`、空值绝不覆盖已有密钥、目录不存在会建好。**重启本插件 fiber 后**才按新 topic 发布。\n- **通行证文本格式**：`dshpush://v1?base=<中继>&topic=<topic>&token=<只读 token>` —— App v1.33.0 起解析它；\n  只粘一串 `tk_…` 的老通行证在 App 里仍按默认 topic `dsh` 处理，所以现有手机不会被这次改动破坏。\n- 发号失败（401 无密钥 / 409 名字占用 / 服务不可达）都在面板上显示中文原因，**不动本机凭据文件、不影响已工作的推送链路**。\n\n## 远程访问：没装 Tailscale 也能从外网打开（v0.4.0 起，v0.5.0 加模式选择）\n\n前面所有能力都假设手机和电脑在同一个 tailnet 里。真实用户经常没有 —— 这一版给一条不依赖\nTailscale 的公网入口，而且**重启后不用重新扫码**。\n\nv0.5.0 起设置行顶部有一个**二选一**（用户 2026-10-28 的要求：「用户可以自行选择是使用公网隧道\n还是 tailscale」）：\n\n| 选项 | 行为 | 适合谁 |\n|---|---|---|\n| **公网隧道（免 Tailscale）** | 起内层网关 + cloudflared 快速隧道 | 没装 Tailscale 的人 |\n| **Tailscale / 自定义地址** | **完全不起网关、不下载任何东西**，通知里的链接就是 `webBase`/`web.log` 的地址 | 已经在用 Tailscale 的人（默认，升级后行为一模一样） |\n\n选「公网隧道」并打开开关，系统会：\n\n0. **先确保本机有 cloudflared**：已经装过（`~/.dsh/bin/` 或 PATH）就直接用，**一次网络请求都不发**；\n   没有才去 GitHub Release 自动下载（约 40 MB），并按 GitHub API 给的 `size` + `sha256` 双重校验；\n1. 在 `127.0.0.1:<随机端口>` 起一个**内层改写网关**；\n2. 用 `cloudflared tunnel` 把它挂到 Cloudflare 的快速隧道，拿到一个 `https://xxx.trycloudflare.com`；\n3. 把 `https://xxx.trycloudflare.com/?k=<口令>` 经 ntfy 推到你手机。\n\n> **为什么校验是硬要求**：cloudflared 的 Release **没有**独立的 `.sha256` 资产，可信摘要只在\n> GitHub API 的 `digest` 字段里；而且从国内网络直连下载**会间歇性截断**（实测拿到过 2,150,400 B\n> 的残包，真包 40,263,303 B），`chmod +x` 之后报「权限不够」。只看下载退出码会把残包当成功 ——\n> 所以 `lib/cloudflared.mjs` 既校 size 又校 sha256，任一不符就换下一个源（直连失败退 `gh-proxy.com`）。\n\n点开这个链接：第一次访问会种一个 **30 天有效**的 cookie，然后 303 把 `?k=` 从地址栏抹掉。\n之后 30 天内换电脑重启、换 DSH token 都不用再扫。\n\n### 为什么不能直接把 3081 暴露出去\n\nDSH 有两道栅栏，都是 2026-10-28 实测的：\n\n| 请求 | Host | Origin | 结果 |\n|---|---|---|---|\n| `GET /api/session/list` | `abc.trycloudflare.com` | — | **403 host-not-trusted** |\n| `GET /api/session/list` | `127.0.0.1:3081` | `https://abc.trycloudflare.com` | **403 origin-not-trusted** |\n\n所以只改 `--trusted-host` 不够，Origin 也要改。网关把 Host/Origin/Referer 全程改写成回环，\n再替客户端注入 DSH 自己的登录 cookie（从 DSH 的启动日志现取，随 DSH 重启自动刷新）——\n**这就是「用户不用重新扫码」的实现方式**：会变的 token 藏在内层，对外只发自己的 30 天口令。\n\n### 几个实现上的硬点（改代码前先读）\n\n- **口令存凭据文件，不进 `cordis.patch.yml`**，且 cookie 里存的是 `HMAC-SHA256(secret)` 而不是口令原文。\n- **`.volatile()` 字段在 `resolvePluginConfig` 里是 cosmokit ref 对象**，既不是 `''` 也不是 `undefined`，\n  会被当成\"用户显式配置\"；`String(ref)` 得到 `[object Object]` 把凭据文件的值盖掉。2026-10-28 就因此\n  每次开机重新生成口令、前一天推的链接当天失效。**必须先用 `volatileValue()` 解开 ref 再判空**。\n- 开关的落盘键是 `remoteEnabled: 'on'|'off'`，**不复用 schema 里的 `remoteAccess` 布尔**（布尔默认值\n  `false` 会反压文件里的 `true`）。\n- 起隧道后 Cloudflare 边缘还要 **3~8 秒**才挂上域名，这期间访问回 **530**。`waitPublic()` 会先自打\n  `/__dshpush/status` 到「不是 5xx」再推链接，否则用户点开就是 Cloudflare 报错页。\n- WebSocket 升级时要**补回 `Connection`/`Upgrade`**（`HOP_BY_HOP` 会剔掉它们，缺了上游不触发 upgrade）。\n- **DSH 不一定由 `dsh web` 直接拉起，`~/.dsh/web.log` 可能是几小时前的旧文件**。2026-10-28 在 VM1\n  实测：DSH 被「市场重启」脚本派生，stdout 被重定向到 `/tmp/dsh-market-restart-*.out.log`，于是\n  `web.log` 停在 10:20 不再更新 —— 只读它会拿到**上一轮的旧 token**，兑换 cookie 恒 401，用户侧\n  表现就是「手机打开链接一直要求重新登录」。现在 `refreshDshCookie()` 会把 `~/.dsh` 与系统临时\n  目录里名字像 `dsh`/`web` 的 `.log` 全当候选（按 mtime 从新到旧），逐个试到真能换出 `dsh-auth-*`。\n- 隧道换了域名会自动重推；`remotePhase` 是给人看的一句话（未开启 / 正在连接 / 隧道建立中 / 已就绪）。\n- **v0.7.11：隧道层的失败必须回到设置行，否则用户永远停在「隧道建立中…」**（用户 2026-10-30\n  m128886 报障）。以前 `spawnTunnel()` 的四种失败（spawn 抛出 / child `exit` / child `error` /\n  60 秒 `giveUp`）只写 `lastError` 进日志，`up()` 又只看 `state.running`、把 `state.error` 丢掉\n  ⇒ 面板上没有任何线索。现在：`reportError()` 通过 `onError` 回调把文案写进 `remoteStatus`，\n  并拼上 `logTail()`（cloudflared 日志里最后一行的 ERR/failed/dial）；连败 **3 次**就停手，文案里\n  直接写「点重建隧道」；再有 75 秒静默兜底 `watchUrl()`，专治「三方都不说话」。\n- **`linkMode` 的 schema 默认值必须是 `''` 而不是 `'tailnet'`**：`resolvePluginConfig` 的 `explicit`\n  只丢掉 `''`/`undefined`/`null`，非空默认值会把凭据文件里用户选的 `tunnel` 反压回去（与\n  `remoteEnabled` 是同一个坑，2026-10-28 第二次踩到）。空串在 `readMode()` 里按 `tunnel` 解释。\n\n### 局限\n\n快速隧道的域名每次重启都变（Cloudflare 免费策略），**但口令不变，所以旧链接仍然可用到过期**；\n域名变了会重推一条新的。想要固定地址需要自己的域名 + 命名隧道，那是下一版的事。\n\n## 给一个真实用户开通（凭据文件 + 配对）\n\n**目标**：开通一个用户，操作者要做的只有两件事 —— 在 relay 上跑一条开号命令、把打印出来的\n配对载荷存成凭据文件。不需要给用户的 DSH 进程配环境变量，也不需要把令牌写进任何 YAML。\n\n```\n① relay 上：bash deploy/relay-user-add.sh alice\n     ├─ ntfy 用户 dsh-alice-pub（topic dsh-alice 只写）/ dsh-alice-phone（同 topic 只读）\n     ├─ relay 主机条目 host=alice + hk_ 队列令牌\n     └─ 打印配对载荷 JSON ──┐\n                            │  存成 ~/.config/dsh-push/credentials.json（原始 JSON 直接存）\n② 用户的 DSH 主机上 ────────┘\n     └─ dsh-push-pair              # 同一份载荷，原样输出给手机\n     └─ dsh-push-pair verify       # 真打 relay/ntfy，逐项 PASS/FAIL\n③ 手机 App：粘/扫 载荷里的 relay + topic + readToken\n```\n\n### 凭据文件（推荐路径，环境变量仍可用）\n\n插件读 `~/.config/dsh-push/credentials.json`（可用 `DSH_PUSH_CREDENTIALS` 或配置项\n`credentialsFile` 指到别处）。**直接就是 `relay-user-add.sh` 打印的那份载荷**，字段名一一对应：\n\n```json\n{\n  \"v\": 1,\n  \"relay\": \"https://ntfy.cpyh.xyz\",\n  \"host\": \"alice\",\n  \"topic\": \"dsh-alice\",\n  \"writeToken\": \"tk_…\",\n  \"readToken\": \"tk_…\",\n  \"hostToken\": \"hk_…\",\n  \"regToken\": \"…\"\n}\n```\n\n> `regToken` 可以写进凭据文件（2026-10-13 起；env 仍优先），因为是**一份文件带走整条链路**这个\n> 设计目标的一部分。不想把服务器侧秘密落到文件里的人，继续用 `DSH_PUSH_REG_TOKEN` 即可 ——\n> 但**两条路至少要有一条**，否则 `POST /answer/register` 会 401，手机只能收通知、不能作答\n> （见下文坑 ②）。\n\n| 载荷字段 | 插件侧含义 | 谁用 |\n|---|---|---|\n| `relay` | `relayBase`（也用来拼手机作答页 `/answer/<callId>`） | 主机 |\n| `host` | `host`，relay 队列的 hostId | 主机 |\n| `topic` | `topic`，本机的 ntfy 主题 | 双方 |\n| `writeToken` | `ntfyToken`，ntfy **写**令牌（只写权限） | 主机（插件推通知） |\n| `readToken` | `phoneToken`，ntfy **读**令牌（只读权限） | 手机 App 订阅 |\n| `hostToken` | `hostToken`，relay 队列 `X-Host-Token` | 主机（取答案/ack） |\n| `regToken` | `regToken`，relay 注册令牌 → `X-Reg-Token` | 主机（注册问题） |\n\n容错与顺序（都实测过）：\n\n- 键名大小写/连字符不敏感，并接受别名：`writeToken`/`ntfyToken`/`pushToken`/`tkPub`、\n  `readToken`/`phoneToken`/`tkRead`、`relay`/`relayBase`/`base`、`host`/`hostId`。\n- 多用户一份文件也行：`{\"relay\": …, \"host\": \"alice\", \"hosts\": { \"alice\": { … }, \"bob\": { … } }}`，\n  根字段是默认值、`hosts[host]` 覆盖它。\n- 覆盖顺序（后者赢）：**内置默认 → 凭据文件 → profile/overlay 配置 → 环境变量**。\n  所以老部署（只给三个环境变量）行为完全不变。反向也成立：**显式写下的空串仍算\"没设置\"**\n  （见下文坑 ①），所以一份正常的凭据文件不会被 profile 里 schema 校验出来的空默认值擦掉。\n- **默认路径锚在 home 目录，与进程 cwd 无关**（2026-10-13 修，见下文坑 ⑥）：\n  `~/.config/dsh-push/credentials.json`。你自己在 `credentialsFile` 里写的**相对**路径仍然\n  按 cwd 解析（老行为不变）。\n- **没有这个文件 = 干净的 no-op**：插件不报错、不抱怨、不打网络，退化成透明监听器（和今天一样）。\n  文件存在但读不了/JSON 坏了，才打一行 `credentials ignored: …` 并继续。\n  ⚠ 正因为是静默 no-op，\"路径算错了\"和\"还没开通\"在日志里长得一模一样：**启动只信\n  `credentials file: <path>` 那一行**（文件被找到才打）。\n\n### 配对载荷：一条命令\n\n`lib/pairing.mjs`（npm bin 名 `dsh-push-pair`，也可 `node <包>/lib/pairing.mjs`）：\n\n```powershell\n& $node dsh-push-host\\lib\\pairing.mjs payload --pretty      # 打印给手机粘的载荷\n& $node dsh-push-host\\lib\\pairing.mjs verify                # 真打 relay/ntfy 自检（5 项）\n& $node dsh-push-host\\lib\\pairing.mjs verify --json         # 机器可读\n& $node dsh-push-host\\lib\\pairing.mjs payload --credentials-file D:\\creds\\alice.json\n# v0.1.1：把网页入口一并写进载荷（存成凭据文件后插件即带 #web 直达链接，基址=手机可达的地址）\n& $node dsh-push-host\\lib\\pairing.mjs payload --pretty --web-base http://100.x.y.z:3080 --web-name 我的机器\n```\n\n`payload` 输出**与 `relay-user-add.sh` 逐字同构**（`v` = 1、同样 7 个字段、同样字段顺序），\n所以不存在第二套 schema；缺字段时**拒绝输出**并列出缺哪几项，不会吐半份。\n`webBase`/`webName` 是**可选追加字段**（v0.1.1）：知道才写、不知道就不写（7 字段老载荷原样），\n`relay-user-add.sh` 不知道用户的网络所以从不输出它们——只有跑配对命令的人知道手机该拨哪个地址。\n\n`verify` 检查（只读 + 最多一条测试通知，不动别人的队列、不改 relay 状态）：\n\n| 检查 | 通过判据 |\n|---|---|\n| `credentials-file` | 文件存在、JSON 合法 |\n| `payload-fields` | 7 个字段都齐 |\n| `relay-host-token` | `GET /answer/pending?host=<host>` + `X-Host-Token` → 200 |\n| `ntfy-read-token` | `GET /<topic>/json?poll=1` + `Bearer readToken` → 200 |\n| `ntfy-write-token` | `POST /`（ntfy JSON 发布）+ `Bearer writeToken` → 200 |\n\n实测（真实 relay，占位/换掉的令牌）：`ntfy-read-token` 用真读令牌 = `HTTP 200`；换成别的 topic\n= `HTTP 403`（ntfy 的 topic 级 ACL）；`relay-host-token` 用假 `hk_` = `HTTP 401 bad host token`。\n即\"令牌对不对\"这件事在手机上动手之前就能判出来。\n\n> **App 侧现状**：App 目前没有导入按钮——relay / topic / readToken 仍要在 App 里手填\n> （见仓库 `README.md` 的\"APP 侧\"）。导入路径的提案（不改 App，只出方案）在\n> `openspec/changes/dsh-push-distribution/specs/companion-app/spec.md`。\n\n### 一个用户跑起来之前需要什么（清单）\n\n1. **relay 上跑过开号命令**：`bash deploy/relay-user-add.sh <user>`（拿到 `hk_` 与两个 `tk_`）。\n2. **载荷存成了凭据文件**：`~/.config/dsh-push/credentials.json`（或 `DSH_PUSH_CREDENTIALS`）。\n3. **`dsh-push-pair verify` 5/5 PASS**（relay/ntfy 都通）。\n4. **插件装进目标 profile**：`dsh plugin --profile <p> add dsh-push-host`，\n   `--dump-config` 尾部有 `- id: push-host`。\n5. **`tool-ask-user` 是 `mode: timed`**（否则手机只能收通知、答案落不了地，见上文硬约束 1）：\n   ```yaml\n   - id: tool-ask-user\n     config: { mode: timed, timeout: 120 }\n   ```\n6. **旧的 hook 提问推送已关**（`deploy/windows/hooks.json` 去掉 `PreToolUse` 那组），否则双推。\n7. **手机 App 已填** relay + topic + readToken 并订阅成功（App 里能看到 ntfy 的连上状态）。\n8. 收尾：让用户提一个真问题、在手机上答一次，确认 agent 真的收到答案。\n\n## 配置\n\n非机密项放 profile 的 `cordis.patch.yml`，或 `--patch` 覆盖层里按 id 定向；**机密项优先走上面的\n凭据文件**（文件优先级低于 profile 配置，所以 YAML 里显式写的值仍然能压过文件）：\n\n```yaml\n- id: push-host\n  config:\n    host: test1            # deploy/relay-user-add.sh 开出来的 hostId\n    topic: dsh-test1       # 该 host 的 ntfy topic\n    webBase: https://<tailnet 网关>   # #web 直达链接基址；不配则回退 web.log 里 DSH 自己打印的 URL（v0.1.1）\n    webName: 台式机         # 多 DSH 入口选择器的显示名（#name）\n    # credentialsFile: D:\\creds\\alice.json   # 不写就用 ~/.config/dsh-push/credentials.json\n```\n\n**令牌不要写进 YAML**：可以来自凭据文件（推荐），也可以来自环境变量（老部署，仍然支持，\n且优先级最高）：\n\n| 环境变量 | 含义 |\n|---|---|\n| `DSH_PUSH_HOST_TOKEN` | `hk_…`，relay 队列端点（`/answer/pending`、`/answer/ack`）的 `X-Host-Token` |\n| `DSH_PUSH_REG_TOKEN` | relay 的注册令牌（服务器 `/etc/answer-relay/regtoken`） |\n| `DSH_PUSH_NTFY_TOKEN` | `tk_…`，该 host 的 ntfy 写令牌（topic 权限 write-only） |\n| `DSH_PUSH_CREDENTIALS` | 凭据文件路径（等价于配置项 `credentialsFile`） |\n\n其余字段（均带默认值，缺省也能挂载，不会拖垮 host 启动）：\n\n| 字段 | 默认 | 说明 |\n|---|---|---|\n| `relayBase` | `https://ntfy.cpyh.xyz` | relay 基址，也用于拼手机作答页 `/answer/<callId>` |\n| `answerBase` | 空 = 用 `relayBase` | 作答页另走别的域名时用 |\n| `host` / `hostToken` | 空 | 二者任一为空 → 整个 relay 侧停用（只当透明监听器） |\n| `credentialsFile` | 空 = 默认路径 | 空串表示 `$DSH_PUSH_CREDENTIALS` 或 `~/.config/dsh-push/credentials.json` |\n| `pollIntervalMs` | `3000` | 队列轮询间隔（500–60000） |\n| `pushQuestions` | `true` | 关掉就只提问不推送 |\n| `notifyTurns` | `true` | 轮次结束（`agent/turn-stopping`）推 `DSH 任务结束`，即旧 `Stop` hook 的等价物 |\n| `echoAnswers` | `true` | 作答后发 `#ans` 静默回声（撤手机通知；relay 自己的回声写死在 topic `dsh`，多租户下到不了你家 topic） |\n| `claimForeground` | `false` | 打开则**抢前台**：把问题挂在 waterfall 上，手机答得更早；代价是与 Web UI 竞速，见下 |\n| `webLog` | `~/.dsh/web.log` | 只用来取最后一个 `?token=` 拼 `#web` |\n| `webBase` / `webName` | 空 | `#web` 直达链接基址 / `#name` 实例名。**`webBase` 留空不再等于没有网页入口**（v0.1.1）：插件直接改用 web.log 里 DSH 自己打印的那条 URL——能不能打开取决于 DSH 实际绑的地址（绑 `127.0.0.1` 就只对本机可达）。手机要从别的网络打开，就把手机可达的地址写进 `webBase` |\n| `log` | `true` | `ctx.logger` + stdout 诊断 |\n\n### `claimForeground` 为什么默认关\n\n通知层骨架的取舍（research 作者建议、本插件采用）：**监听器 prepend + `return next()`**，\n前台作答权留给 DSH Web UI —— 浏览器在线时体验与现在完全一致，插件只在旁边推通知。\n代价是\"窗口期内的手机作答\"必须等前台等待结束（timed 模式的 timeout，或 UI 作答）。\n实测（2026-10-13，台式机 c-full）：timed `timeout:180` 的提问，手机在 t+30s 经 relay 作答 →\n插件日志 `state=open` 排队重试 → t+180s 工具返回 `pending` → 提问进投影（continued）→\n下一轮 poll 立即 `answered (continued)` 折回会话。**手机优先的用户应打开 `claimForeground`**，\n否则每次手机作答都要白等剩余超时时间。\n打开 `claimForeground` 后插件会 hold 住 waterfall 并把手机答案与 UI 答案赛跑（谁先到谁生效），\n`mode: legacy`（无 timeout、永久阻塞）的问题也能被手机答，但它与 UI 抢答权，属于实验开关。\n\n## 三个触发点（旧 hook 的逐项等价物）\n\n| 旧 hook / 外部桥 | 本插件 | 说明 |\n|---|---|---|\n| `PreToolUse`（提问推送）| `user-questions/request` waterfall（prepend） | 拿到的是服务词汇表的问题对象 + `wait.timed`，比读工具入参更准 |\n| 同上（兜底） | `tools/pre-execute` | **竞位兜底**：waterfall 里\"后 prepend 的作答器\"会排到本插件前面，若它直接返回答案而不调 `next()`，waterfall 监听器就永不执行（实测：probe 插件 autoAnswer 就是这样）。两个触发点都按 `exec.callId` 去重，正常情况只推一次，且 waterfall 那次会把 `timed` 校正回来 |\n| `PostToolUse`（作答回声 `#ans`）| `tools/post-execute` | 工具带着答案返回 → 推 `#ans`。**注意**：结果是 `{pending:true}`（timed 等超时未答）时**不推**——那问题还能从手机答，推了会把卡片错误地置为已答（旧 hook 在这里会误推，属已知缺陷） |\n| `Stop`（任务结束推送）| `agent/turn-stopping` | 取 `agent.session.header.id` / `.cwd`，按 `session:turn` 去重，priority 3，正文 `目录: <cwd>` + `#web` + `#name`，与 hook 逐字一致；推送是 fire-and-forget，失败不影响轮次 |\n| 外部 answer bridge | `ctx.interval` 轮询 relay 队列 | 见上文；不依赖 `/api/remote.mux` 与本机 cookie |\n\n## 切到\"正在用的\" profile（生产部署，需用户确认）\n\n**前提**：`tool-ask-user` 在 `mode: timed` 才会 fold 投影 —— 否则手机只能收通知、不能作答（见上文硬约束 1）。\n\n```powershell\n$dsh = '<DSH 安装目录>\\resources\\runtime\\cli\\bin\\dsh.cmd'\n$profile = 'web'                       # 生产 profile 名\n\n# 1. 备份要改的两个文件（它们不在 git 里，没有回滚路径）\nCopy-Item \"<dshHome>\\profiles\\$profile\\cordis.patch.yml\" \"<dshHome>\\profiles\\$profile\\cordis.patch.yml.bak-plugin\"\nCopy-Item \"<dshHome>\\profiles\\$profile\\package.json\"     \"<dshHome>\\profiles\\$profile\\package.json.bak-plugin\"\n\n# 2. tool-ask-user 切 timed：把这段追加到 profiles\\$profile\\cordis.patch.yml\n#    （id 定向 patch 会整块替换该条目的 config，tool-ask-user 本来没有 config，所以只写这两个键）\n#      - id: tool-ask-user\n#        config:\n#          mode: timed\n#          timeout: 120\n# 3. 插件 + 三个令牌（令牌走环境变量，不写 YAML）\n& $dsh plugin --profile $profile add \"link:F:/work/work_dsh/dsh-push/host-plugin\"\n& $dsh --profile $profile --dump-config | Select-Object -Last 3      # 期望看到 - id: push-host\n\n# 4. 关掉 hook 的提问推送（避免双推）：deploy/windows/hooks.json 去掉 PreToolUse 里\n#    ask_user_question / exit_plan_mode 的组，或整体停用该桥插件；Stop 推送可留可撤（插件已接管结束推送）\n\n# 5. 重启宿主，判据是\"端口持有者 PID 变了\"+ dump-config 行内容，不看 status 探针\n```\n\n令牌（给宿主进程的环境，不是给 App 的）：`DSH_PUSH_HOST_TOKEN`（`hk_…`）、`DSH_PUSH_REG_TOKEN`（relay 注册令牌）、\n`DSH_PUSH_NTFY_TOKEN`（该 host 的 ntfy 写令牌）。App 侧继续用生产读令牌 + topic `dsh`（App 的 topic 是硬编码的）。\n\n**回滚**：`dsh plugin --profile web remove <包名>` + 把两个 `.bak-plugin` 覆盖回去 + 重启宿主；\nhook 那边恢复 `hooks.json` 即可回到旧链路（两条链路互不破坏数据）。\n\n## 验收\n\n```powershell\n# 1) 纯逻辑：假 ctx + 假 relay，48 项断言（含 open 期答案必须留在队列里的回归项）\n& $dsh-node host-plugin\\plugin-selftest.mjs\n#   需要本地 node_modules/@deepseek-ai/schemastery（宿主本来自带，测试时用 junction 指过去）\n\n# 1b) 开通层：凭据文件/优先级/缺文件 no-op/坏文件/配对载荷 + 坑 ①⑤ 的回归，54 项断言\n& $dsh-node host-plugin\\plugin-selftest-credentials.mjs\n\n# 2) relay 客户端：真打公网 HTTPS（读/写/错误令牌/ack 空表）\nnode host-plugin\\relay-selftest.mjs <hostToken>\n\n# 2b) 配对自检：真打 relay/ntfy，逐项 PASS/FAIL（只读 + 一条测试通知）\nnode host-plugin\\lib\\pairing.mjs verify\n\n# 3) 真机进程内冒烟：插 probe 插件造一个合成问题，看插件是否推送+注册\n& $dsh --profile pushtest --patch <overlay 见下>\n#   [dsh-push-host] relay ready host=test1 topic=dsh-test1 poll=3000ms\n#   [dsh-push-host] question pq-… agent=(none) timed=false q=[\"probe-q1\"]\n#   ⚠ 这条路**证明不了\"答案落回 agent\"**：合成问题没有活 agent，deliver() 会停在\n#     `no live root agent …`。要验最后一跳用 3b。\n\n# 3b) 【推荐】\"手机真的能答\"的端到端验收 —— 全自动，不需要人碰手机：\npowershell -NoProfile -ExecutionPolicy Bypass -File verify\\host-plugin-phone-answer-e2e.ps1\n#   真 agent 提 timed 问题 → 模拟器里的 App 自己作答 → 断言三处：\n#     register … -> HTTP 200 / probe timed=true / answered (continued) + agent 收到答案\n#   期望输出 `SUMMARY: 11/11 checks passed`（脚本全文见 verify\\host-plugin-phone-answer-e2e.ps1）\n\n# 4) 看手机侧真实收到的内容（用该 topic 的读令牌）\ncurl -H \"Authorization: Bearer <readToken>\" \"https://ntfy.cpyh.xyz/<topic>/json?poll=1&since=10m\"\n\n# 5) 从手机侧作答，看队列闭合\ncurl -X POST -H \"Content-Type: application/json\" \\\n  -d '{\"callId\":\"<callId>\",\"answers\":[{\"id\":\"q1\",\"selected\":[\"second\"]}]}' \\\n  https://ntfy.cpyh.xyz/answer/submit\n#   → {\"ok\": true, \"queued\": true, \"host\": \"test1\"}   插件下一轮轮询取走并 ack\n```\n\n### 无人验收配方（2026-10-13 实弹，probe 只能证明\"推送+注册\"，证明不了\"答案落回 agent\"）\n\n合成问题（probe 的 `selfTest`）**没有活 agent**，所以 `deliver()` 走到\n`no live root agent …` 就停下了 —— 它永远证明不了\"手机答案被 apply 进 agent\"。\n要验这一环必须有一个**真 agent 提一个 timed 问题**，再用模拟器里的 App 作答：\n\n```powershell\n# ① 测试 profile（pushtest = dsh-base + dsh-headless + 本插件 + probe）加一层 overlay：\n#    - insert: tool-ask-user (mode: timed, timeout: 60)   ← headless bundle 里没有这个工具\n#    - id: push-host  config: { webName: e2e-verify, notifyTurns: false }  ← 别往生产 topic 推结束通知\n#    - id: agent-default-model + llm-pi-ai               ← 从 profiles/web/cordis.patch.yml 抄，指向同一个模型路由\n& $dsh --profile pushtest --patch <overlay.yml> --dump-config   # 先验：exit 0 + 尾部 - id: tool-ask-user (mode: timed)\n\n# ② 让真 agent 提一个问题（单行 prompt！多行 here-string 会被 dsh.cmd 吃掉，见坑）\n& $dsh --profile pushtest --patch <overlay.yml> 'Call ask_user_question exactly once ... print RESULT_JSON: ...'\n\n# ③ 同时让模拟器里的 App 作答（笔电 DESKTOP-CPYH 的 emulator-5554，ssh 过去跑）：\n#    轮询 prefs 等带唯一标记的那条 push → 取 callId → 走 App 自己的作答路径\n#      a) UI 路径：am start -n xyz.cpyh.dshpush/.QuickAnswerActivity --es callId <cid> + input tap 选项\n#      b) 通知按钮路径（稳，uiautomator 常挂）：am broadcast -n xyz.cpyh.dshpush/.AnswerReceiver \\\n#           --es callId <cid> --es qid q1 --es label \"<选项>\" --ei nid <mid>\n#    两条路都打 POST https://ntfy.cpyh.xyz/answer/submit（AnswerReceiver 与 QuickAnswerActivity 同协议）\n```\n\n看这三处断言（缺一不可）：\n\n| 断言 | 日志/证据 |\n|---|---|\n| ① 注册通了 | `[dsh-push-host] register <callId> -> HTTP 200` |\n| ② 等待是 timed | probe 的 `callId = … timed=true`（权威）／插件的 `timed corrected to true by the request waterfall` |\n| ③ 答案落回 agent | `[dsh-push-host] answered (continued) <callId>`（= `ctx.userQuestions.answer()` 返回 true）→ 紧接着 agent 侧收到一条 `answer_to_pending_question` user 消息 |\n\n坑：**模型显式传 `timeout: -1`**（\"必须等到答案\"）会走 legacy 路径，问题当场以\n`{\"error\":\"no user-questions answerer accepted the request\"}` 返回 —— 这不是链路坏。\nprompt 里要写明\"不要传 timeout 字段\"。\n\n## 依赖的 relay 契约（`deploy/answer-relay.py`）\n\n| 端点 | 用途 |\n|---|---|\n| `POST /answer/register` | `{callId, agentId, questions:[{id,question,options:[str]}], hostId, ttl}` + `X-Reg-Token`；带 `hostId` 即进入队列模式 |\n| `GET /answer/pending?host=X` | `X-Host-Token` → `{items:[{callId, agentId, qids, answers, ts}]}` |\n| `POST /answer/ack` | `{host, callIds}` + `X-Host-Token` |\n| `POST /answer/submit` | 手机提交；该问题有 `hostId` → 入队并回 `{ok, queued:true}` |\n| `GET /answer/<callId>` | 手机/浏览器作答页（插件推送正文里的链接就是这个） |\n\n推送正文沿用 App 既有语法：`📱 作答: <answerBase>/answer/<callId>` + `#qid` / `#opts qid=a|b|c`\n（仅单问题 2–3 选项且标签不含 `|=#`）/ `#web` / `#name`；作答回声 `#ans <callId> <摘要>`，\n优先级 1（静默）。问题推送优先级 4（App 走紧急通道）。\n\n## 范围与限制\n\n- **三个触发点都在插件里**（提问推送 / 结束推送 / 作答回声）；`deploy/windows/hooks.json` 那条\n  旧 hook **必须保持退役**（现在是 `{\"hooks\":{}}`），否则双推。\n- **`mode: legacy` 下手机只能收通知、不能作答**（见上文硬约束 1）。\n- **模型显式传 `timeout: -1` 时也是 legacy 路径**：那个\"必须等到答案\"的调用没有 timed wait，\n  手机答不了（问题会当场以 `NO_PROVIDER` 结束）。这是调用方的选择，不是链路故障。\n- 手机作答经过 relay 队列，**队列里的 callId 带 `|`**：任何把它交给 shell 的地方都必须引号包住\n  （`--es callId 'call_00_x|uuid'`），否则被当管道符切断、静默失效（2026-10-13 实测踩到）。\n- **不查历史**：插件只处理它自己经手（注册）的问题；别人用 hook 注册的问题没有 `hostId`，\n  走 relay 的老 bridge 转发，不经过本插件（老 bridge 已于 2026-10-13 停用并禁用，\n  回滚：`Enable-ScheduledTask -TaskName DshAnswerBridge` + `Start-ScheduledTask`）。\n- **单实例单 host**：一个进程一个 `host`/`topic`；多台机器用 `deploy/relay-user-add.sh <user>` 各开一条。\n- 令牌从**凭据文件或环境变量**读（都不写进 YAML）；插件与宿主同进程同权限，装之前按第三方插件审一遍代码。\n- **配对只做到\"产出载荷\"**：载荷怎么进 App 由 App 决定；App 目前没有导入按钮（提案见\n  `openspec/changes/dsh-push-distribution/specs/companion-app/spec.md`），所以手机上仍要手填三项。\n- **本包不包含 relay 服务端**：`deploy/` 里的脚本与 `answer-relay.py` 是服务端侧，需要操作者自己在\n  自己的主机上部署（见 `../deploy/README.md`）；默认 `relayBase` 指向本项目的实例，别家部署要改。\n\n## 相关文档\n\n- `../deploy/README.md`：relay/ntfy 服务端部署与每用户开号\n- `../verify/README.md`：App 侧验收流水线与硬事实\n- `F:\\work\\work_dsh\\dsh-plugin-api-research.md`：`userQuestions` seam 的源码级契约（本项目外）\n","readmeFilename":"README.md"}