{"_id":"dsh-notice-center","_rev":"6-763bce00b638f91f2a2759892faa390e","name":"dsh-notice-center","dist-tags":{"next":"1.3.0-rc.1","latest":"1.4.2"},"versions":{"1.2.0":{"name":"dsh-notice-center","version":"1.2.0","keywords":["dsh","dsh-plugin","deepseek-harness","notification","system-notification","favicon"],"license":"MIT","_id":"dsh-notice-center@1.2.0","maintainers":[{"name":"mangobo","email":"2369117751@qq.com"}],"homepage":"https://github.com/SCP-QQ/dsh-notice-center#readme","bugs":{"url":"https://github.com/SCP-QQ/dsh-notice-center/issues"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"},"client":{"inject":["@deepseek-ai/dsh-client-locale","@deepseek-ai/dsh-client-ui-settings","@deepseek-ai/dsh-client-ui-session"],"platform":"web"}},"dist":{"shasum":"8c0d416d69f51b251e953d35db62171d7a780fe8","tarball":"https://registry.npmjs.org/dsh-notice-center/-/dsh-notice-center-1.2.0.tgz","fileCount":52,"integrity":"sha512-W3A7kAxGCU0G4Kh9ri+yUrULbrCyv3UlHworQBtxH22phna5RelRKK+TpzLsCeD94AgeBSQorZqahZNAGI/YOw==","signatures":[{"sig":"MEYCIQD3sm5nY1Mwcg9GG0SNwgGWwBp4sfY/2gmPQ0yg13QaMgIhALS/wy2JC6NDZKSIgSvduZzuLSN0J7PlQd8rI21wkrGF","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":351652},"main":"lib/index.mjs","type":"module","exports":{".":{"default":"./lib/index.mjs"},"./client":{"default":"./lib/client.cjs"},"./package.json":"./package.json","./cordis.patch.yml":"./cordis.patch.yml"},"gitHead":"40521ef49a287175a2c4f41c2f2315977f2e00a7","scripts":{"test":"node test/host-half.smoke.mjs && node test/client-half.smoke.mjs","test:host":"node test/host-half.smoke.mjs","test:client":"node test/client-half.smoke.mjs","prepublishOnly":"npm test"},"_npmUser":{"name":"mangobo","email":"2369117751@qq.com"},"repository":{"url":"git+https://github.com/SCP-QQ/dsh-notice-center.git","type":"git"},"_npmVersion":"11.17.0","description":"DeepSeek Harness 通知中心：标签页鲸鱼状态灯（绿=跑完 / 琥珀=待处理）+ 浏览器系统通知（完成/待处理提示、45 个 opencode 音效可选、音量可配）。","directories":{},"_nodeVersion":"24.19.0","dependencies":{"@deepseek-ai/schemastery":"^3.18.2"},"_hasShrinkwrap":false,"peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/dsh-settings":"^0.1.2-rc.1","@deepseek-ai/dsh-client-locale":"^0.1.2-rc.1","@deepseek-ai/dsh-client-ui-session":"^0.1.2-rc.1","@deepseek-ai/dsh-client-ui-settings":"^0.1.2-rc.1"},"_npmOperationalInternal":{"tmp":"tmp/dsh-notice-center_1.2.0_1789803244020_0.9655398763030194","host":"s3://npm-registry-packages-npm-production"}},"1.3.0-rc.1":{"name":"dsh-notice-center","version":"1.3.0-rc.1","keywords":["dsh","dsh-plugin","deepseek-harness","notification","system-notification","favicon"],"license":"MIT","_id":"dsh-notice-center@1.3.0-rc.1","maintainers":[{"name":"mangobo","email":"2369117751@qq.com"}],"homepage":"https://github.com/SCP-QQ/dsh-notice-center#readme","bugs":{"url":"https://github.com/SCP-QQ/dsh-notice-center/issues"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"},"client":{"inject":["@deepseek-ai/dsh-client-locale","@deepseek-ai/dsh-client-ui-settings","@deepseek-ai/dsh-client-ui-session"],"platform":"web"}},"dist":{"shasum":"d6e8e120175e5084c3987daa48b0692bdae3e64d","tarball":"https://registry.npmjs.org/dsh-notice-center/-/dsh-notice-center-1.3.0-rc.1.tgz","fileCount":52,"integrity":"sha512-P7Aota0ujXE2xsOohvPb98KleLNXpASDLWAkwzIPvePk3v0PkGFqIiiF59SZnVxL+FKr9kYJaEf8IvtvZr3Bcw==","signatures":[{"sig":"MEYCIQDHDc96bS57h2xnMcou1KVipZBryTnxfZjtx1TrYNhidwIhAMLmrQoo/o8PMiQlkLt5f5RO8J1dfINTrGRSpqB7D8Yo","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQDm+gtjeRxXOgHtBDfe9kp7PpPCiBx6YQahjuXKI+1bQgIhAOE4YV1IC8lAiO8SkI+mji8nr45inx9BnjeR0g9COQsm","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/dsh-notice-center@1.3.0-rc.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":354281},"main":"lib/index.mjs","type":"module","exports":{".":{"default":"./lib/index.mjs"},"./client":{"default":"./lib/client.cjs"},"./package.json":"./package.json","./cordis.patch.yml":"./cordis.patch.yml"},"gitHead":"9543a41846de564501a5352505d202035ae522f8","scripts":{"test":"node test/host-half.smoke.mjs && node test/client-half.smoke.mjs","test:host":"node test/host-half.smoke.mjs","test:client":"node test/client-half.smoke.mjs","prepublishOnly":"npm test"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:8e8651a0-a87e-4a8e-be26-9e24a0ff5d3c"}},"repository":{"url":"git+https://github.com/SCP-QQ/dsh-notice-center.git","type":"git"},"_npmVersion":"11.19.0","description":"DeepSeek Harness 通知中心：标签页鲸鱼状态灯（绿=跑完 / 琥珀=待处理）+ 浏览器系统通知（完成/待处理提示、45 个 opencode 音效可选、音量可配）。","directories":{},"_nodeVersion":"24.20.0","dependencies":{"@deepseek-ai/schemastery":"^3.18.2"},"_hasShrinkwrap":false,"readmeFilename":"README.md","peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/dsh-settings":"^0.1.2-rc.1","@deepseek-ai/dsh-client-locale":"^0.1.2-rc.1","@deepseek-ai/dsh-client-ui-session":"^0.1.2-rc.1","@deepseek-ai/dsh-client-ui-settings":"^0.1.2-rc.1"},"_npmOperationalInternal":{"tmp":"tmp/dsh-notice-center_1.3.0-rc.1_1789807407823_0.21937660571010387","host":"s3://npm-registry-packages-npm-production"}},"1.3.0":{"name":"dsh-notice-center","version":"1.3.0","keywords":["dsh","dsh-plugin","deepseek-harness","notification","system-notification","favicon"],"license":"MIT","_id":"dsh-notice-center@1.3.0","maintainers":[{"name":"mangobo","email":"2369117751@qq.com"}],"homepage":"https://github.com/SCP-QQ/dsh-notice-center#readme","bugs":{"url":"https://github.com/SCP-QQ/dsh-notice-center/issues"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"},"client":{"inject":["@deepseek-ai/dsh-client-locale","@deepseek-ai/dsh-client-ui-settings","@deepseek-ai/dsh-client-ui-session"],"platform":"web"}},"dist":{"shasum":"eb8895a493e849a24fa4d32006921dd51154c848","tarball":"https://registry.npmjs.org/dsh-notice-center/-/dsh-notice-center-1.3.0.tgz","fileCount":53,"integrity":"sha512-aJGueiTOIOvKtu1Mn7IRVaStSualK/7enzQ8Bm+1qt9FlMgoiOCdl83EwDEdcmhn5fKqPh+8tcXL8eCXzO74Jw==","signatures":[{"sig":"MEUCIQDm0iBBFT2d6RBgZc680gzw6hxYaLM9TL4QGP7MCNU9SQIgUZUZ9b8MyWytoM9zqLLEHPSTtdjKDfgKNfQTdj8lg0w=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEYCIQCEvc1zZUbqgjiwnCD/nClN4vTj6bYV8ZsxQRaXNR40SQIhAJlf/4IMXUE0rRawrPrH0BhtF4hq6YziZ0LwHXPY8xO/","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/dsh-notice-center@1.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":377022},"main":"lib/index.mjs","type":"module","exports":{".":{"default":"./lib/index.mjs"},"./client":{"default":"./lib/client.cjs"},"./package.json":"./package.json","./cordis.patch.yml":"./cordis.patch.yml"},"gitHead":"38826e5e5adb3f680f98b8ccdaefa8772f986bcf","scripts":{"test":"node test/host-half.smoke.mjs && node test/client-half.smoke.mjs","test:host":"node test/host-half.smoke.mjs","test:client":"node test/client-half.smoke.mjs","prepublishOnly":"npm test"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:8e8651a0-a87e-4a8e-be26-9e24a0ff5d3c"}},"repository":{"url":"git+https://github.com/SCP-QQ/dsh-notice-center.git","type":"git"},"_npmVersion":"11.19.0","description":"DeepSeek Harness 通知中心：标签页鲸鱼状态灯（绿=跑完 / 琥珀=待处理）+ 浏览器系统通知（完成/待处理提示、45 个 opencode 音效可选、音量可配）。","directories":{},"_nodeVersion":"24.20.0","dependencies":{"@deepseek-ai/schemastery":"^3.18.2"},"_hasShrinkwrap":false,"peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/dsh-settings":"^0.1.2-rc.1","@deepseek-ai/dsh-client-locale":"^0.1.2-rc.1","@deepseek-ai/dsh-client-ui-session":"^0.1.2-rc.1","@deepseek-ai/dsh-client-ui-settings":"^0.1.2-rc.1"},"_npmOperationalInternal":{"tmp":"tmp/dsh-notice-center_1.3.0_1789824511658_0.6495039224469363","host":"s3://npm-registry-packages-npm-production"}},"1.3.1":{"name":"dsh-notice-center","version":"1.3.1","keywords":["dsh","dsh-plugin","deepseek-harness","notification","system-notification","favicon"],"license":"MIT","_id":"dsh-notice-center@1.3.1","maintainers":[{"name":"mangobo","email":"2369117751@qq.com"}],"homepage":"https://github.com/SCP-QQ/dsh-notice-center#readme","bugs":{"url":"https://github.com/SCP-QQ/dsh-notice-center/issues"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"},"client":{"inject":["@deepseek-ai/dsh-client-locale","@deepseek-ai/dsh-client-ui-settings","@deepseek-ai/dsh-client-ui-session"],"platform":"web"}},"dist":{"shasum":"8f12e5ee5d1e25ff8f8b35fbc05ca7f134e7394b","tarball":"https://registry.npmjs.org/dsh-notice-center/-/dsh-notice-center-1.3.1.tgz","fileCount":53,"integrity":"sha512-Et8S/dQbBX1MyFA1UZn10Hrv2dUPkte/EdTunum5EXND3mspNFvGAkxJ+WWG2Rtoh1/MRk1J+BEXY3izzXjL/g==","signatures":[{"sig":"MEYCIQCn6eEgr56uu7cPex7cpmGfeC46sVTyRZSHxncx78z7HwIhAMhuAKKBuy5THSlv+IkX7TRDfRAiOe8jcgB/hsqCEZ9Q","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEQCIFsXbFI8kKwA70k1sKwNelTkMeF2X2/Ledl4BkiIyFAiAiBMVp8OSTyYbGmh99aORi7hq7HA9HOW1pOWKWCH6Rf7ZA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/dsh-notice-center@1.3.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":399782},"main":"lib/index.mjs","type":"module","exports":{".":{"default":"./lib/index.mjs"},"./client":{"default":"./lib/client.cjs"},"./package.json":"./package.json","./cordis.patch.yml":"./cordis.patch.yml"},"gitHead":"471e44c38697705d0161ea2c567003e860212edf","scripts":{"test":"node test/host-half.smoke.mjs && node test/client-half.smoke.mjs","test:host":"node test/host-half.smoke.mjs","test:client":"node test/client-half.smoke.mjs","prepublishOnly":"npm test"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:8e8651a0-a87e-4a8e-be26-9e24a0ff5d3c"}},"repository":{"url":"git+https://github.com/SCP-QQ/dsh-notice-center.git","type":"git"},"_npmVersion":"11.19.0","description":"DeepSeek Harness 通知中心：标签页鲸鱼状态灯（绿=跑完 / 琥珀=待处理）+ 浏览器系统通知（完成/待处理提示、45 个 opencode 音效可选、音量可配）。","directories":{},"_nodeVersion":"24.20.0","dependencies":{"@deepseek-ai/schemastery":"^3.18.2"},"_hasShrinkwrap":false,"peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/dsh-settings":"^0.1.2-rc.1","@deepseek-ai/dsh-client-locale":"^0.1.2-rc.1","@deepseek-ai/dsh-client-ui-session":"^0.1.2-rc.1","@deepseek-ai/dsh-client-ui-settings":"^0.1.2-rc.1"},"_npmOperationalInternal":{"tmp":"tmp/dsh-notice-center_1.3.1_1790234999137_0.6610568946272604","host":"s3://npm-registry-packages-npm-production"}},"1.4.0":{"name":"dsh-notice-center","version":"1.4.0","keywords":["dsh","dsh-plugin","deepseek-harness","notification","system-notification","favicon"],"license":"MIT","_id":"dsh-notice-center@1.4.0","maintainers":[{"name":"mangobo","email":"2369117751@qq.com"}],"homepage":"https://github.com/SCP-QQ/dsh-notice-center#readme","bugs":{"url":"https://github.com/SCP-QQ/dsh-notice-center/issues"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"},"client":{"inject":["@deepseek-ai/dsh-client-locale","@deepseek-ai/dsh-client-ui-settings","@deepseek-ai/dsh-client-ui-session"],"platform":"web"}},"dist":{"shasum":"b498cef28b0f470caad7182881fe2a08fcd460cc","tarball":"https://registry.npmjs.org/dsh-notice-center/-/dsh-notice-center-1.4.0.tgz","fileCount":54,"integrity":"sha512-4UVhjqX6yYqiX3vWTFpoTxNvgNQOFPqyvN0B91X97WEL2dH7hOJV+iBbFRRh8m3N/dV8OUt+hE+6Nr8h9/8Qww==","signatures":[{"sig":"MEUCIQCrtSVoNi/HPjrQz80zdh4ja2pUdqWWOlBTNTo5pwW9aQIgEMV7TMFOBDuFR8f7ewcft9P3ElwV/8zSTdDC/1hXg4w=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIEtC4g/vcxwg2gr2m6tyHweC55EJDqQiS7n5LK+d9iGIAiEA50E1WnLcPTSYw2u2/MkaBPJ/IE4TUo5h+sAYsCAqJ2Q=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/dsh-notice-center@1.4.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":428730},"main":"lib/index.mjs","type":"module","engines":{"dsh":">=0.1.7-rc.2 <0.2.0-0"},"exports":{".":{"default":"./lib/index.mjs"},"./client":{"default":"./lib/client.cjs"},"./package.json":"./package.json","./cordis.patch.yml":"./cordis.patch.yml"},"gitHead":"73a8b7bfd1cdb88648d9b890d7b358c96ee27a55","scripts":{"test":"node test/host-half.smoke.mjs && node test/client-half.smoke.mjs && node test/compat-range.smoke.mjs","test:host":"node test/host-half.smoke.mjs","test:client":"node test/client-half.smoke.mjs","test:compat":"node test/compat-range.smoke.mjs","prepublishOnly":"npm test"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:8e8651a0-a87e-4a8e-be26-9e24a0ff5d3c"}},"repository":{"url":"git+https://github.com/SCP-QQ/dsh-notice-center.git","type":"git"},"_npmVersion":"11.19.0","description":"DeepSeek Harness 通知中心：标签页鲸鱼状态灯（绿=跑完 / 琥珀=待处理）+ 浏览器系统通知（完成/待处理提示、45 个 opencode 音效可选、音量可配）。","directories":{},"_nodeVersion":"24.21.0","dependencies":{"@deepseek-ai/schemastery":"^3.18.4"},"_hasShrinkwrap":false,"devDependencies":{"@deepseek-ai/cosmokit":"^1.8.5"},"peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/dsh-settings":">=0.1.7-rc.2 <0.2.0-0","@deepseek-ai/dsh-client-locale":">=0.1.7-rc.2 <0.2.0-0","@deepseek-ai/dsh-client-ui-session":">=0.1.7-rc.2 <0.2.0-0","@deepseek-ai/dsh-client-ui-settings":">=0.1.7-rc.2 <0.2.0-0"},"_npmOperationalInternal":{"tmp":"tmp/dsh-notice-center_1.4.0_1790476861905_0.10885446784917341","host":"s3://npm-registry-packages-npm-production"}},"1.4.2":{"_id":"dsh-notice-center@1.4.2","dsh":{"bundle":{"patch":"./cordis.patch.yml"},"client":{"inject":["@deepseek-ai/dsh-client-locale","@deepseek-ai/dsh-client-ui-settings","@deepseek-ai/dsh-client-ui-session"],"platform":"web"}},"bugs":{"url":"https://github.com/SCP-QQ/dsh-notice-center/issues"},"dist":{"shasum":"1b1f20644af09f2d2f922529d2c8f2124871ff05","tarball":"https://registry.npmjs.org/dsh-notice-center/-/dsh-notice-center-1.4.2.tgz","fileCount":55,"integrity":"sha512-7vPyio9EfTj0P4fzNSmWEHXRkgtAYERcfDeVSGKyVl+c9h7T58yP9e/L1LTMRrkmaoV93VzlEI2gX8k8MlyNCA==","signatures":[{"sig":"MEUCIEEQa+HHwUcG0EDtrd7VE60z6LWm7f67WO3LEQBvivVBAiEAop2kkVXn3q8ZLXQ6RXG4BF6ujlkce0x6inWJSCJZLf0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIHIdlq4q1eRiSYSdYgNXUouNCXFIi4BcLFGlZkXc1h2PAiADDpadXLluCyxziiGdxYAzGZDovsv8aIlXeKAY3RTA0A=="}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/dsh-notice-center@1.4.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":471299},"icon":"assets/icon.svg","main":"lib/index.mjs","name":"dsh-notice-center","type":"module","engines":{"dsh":">=0.1.7-rc.2 <0.2.0-0"},"exports":{".":{"default":"./lib/index.mjs"},"./client":{"default":"./lib/client.cjs"},"./package.json":"./package.json","./cordis.patch.yml":"./cordis.patch.yml"},"gitHead":"83961559486c80eaee7f6a84f0cf8d4cd9d8ec5d","license":"MIT","scripts":{"test":"node test/host-half.smoke.mjs && node test/client-half.smoke.mjs && node test/compat-range.smoke.mjs","test:host":"node test/host-half.smoke.mjs","test:client":"node test/client-half.smoke.mjs","test:compat":"node test/compat-range.smoke.mjs","prepublishOnly":"npm test"},"version":"1.4.2","_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:8e8651a0-a87e-4a8e-be26-9e24a0ff5d3c"}},"homepage":"https://github.com/SCP-QQ/dsh-notice-center#readme","keywords":["dsh","dsh-plugin","deepseek-harness","notification","system-notification","favicon"],"repository":{"url":"git+https://github.com/SCP-QQ/dsh-notice-center.git","type":"git"},"_npmVersion":"11.19.0","description":"DeepSeek Harness 通知中心：标签页鲸鱼状态灯（绿=跑完 / 琥珀=待处理）+ 浏览器系统通知（完成/待处理提示、45 个 opencode 音效可选、音量可配）。","directories":{},"maintainers":[{"name":"mangobo","email":"2369117751@qq.com"}],"_nodeVersion":"24.21.0","dependencies":{"@deepseek-ai/schemastery":"^3.18.4"},"_hasShrinkwrap":false,"devDependencies":{"@deepseek-ai/cosmokit":"^1.8.5"},"peerDependencies":{"@deepseek-ai/cordis":"^4.0.2","@deepseek-ai/dsh-settings":">=0.1.7-rc.2 <0.2.0-0","@deepseek-ai/dsh-client-locale":">=0.1.7-rc.2 <0.2.0-0","@deepseek-ai/dsh-client-ui-session":">=0.1.7-rc.2 <0.2.0-0","@deepseek-ai/dsh-client-ui-settings":">=0.1.7-rc.2 <0.2.0-0"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/dsh-notice-center_1.4.2_1790493262042_0.05179751756299833"}}},"time":{"created":"2026-09-19T07:34:03.962Z","modified":"2026-09-27T07:14:22.441Z","1.2.0":"2026-09-19T07:34:04.182Z","1.3.0-rc.1":"2026-09-19T08:43:27.937Z","1.3.0":"2026-09-19T13:28:31.751Z","1.3.1":"2026-09-24T07:29:59.243Z","1.4.0":"2026-09-27T02:41:02.031Z","1.4.2":"2026-09-27T07:14:22.145Z"},"bugs":{"url":"https://github.com/SCP-QQ/dsh-notice-center/issues"},"license":"MIT","homepage":"https://github.com/SCP-QQ/dsh-notice-center#readme","keywords":["dsh","dsh-plugin","deepseek-harness","notification","system-notification","favicon"],"repository":{"url":"git+https://github.com/SCP-QQ/dsh-notice-center.git","type":"git"},"description":"DeepSeek Harness 通知中心：标签页鲸鱼状态灯（绿=跑完 / 琥珀=待处理）+ 浏览器系统通知（完成/待处理提示、45 个 opencode 音效可选、音量可配）。","maintainers":[{"name":"mangobo","email":"2369117751@qq.com"}],"readme":"# dsh-notice-center 🔔🐋\n\n**中文** | [English](./README.en.md)\n\n[![test](https://github.com/SCP-QQ/dsh-notice-center/actions/workflows/test.yml/badge.svg)](https://github.com/SCP-QQ/dsh-notice-center/actions/workflows/test.yml)\n[![npm](https://img.shields.io/npm/v/dsh-notice-center.svg)](https://www.npmjs.com/package/dsh-notice-center)\n\n<img src=\"docs/images/banner.jpg\" alt=\"dsh-notice-center 会话通知 —— 让每一条消息，都不错过\" width=\"100%\">\n\n**一句话**：DeepSeek Harness 的**通知中心**——把标签页上的鲸鱼图标变成状态灯，并在你不在看的时候主动提醒你。\n\n| | |\n|---|---|\n| 包名 | `dsh-notice-center` |\n| 插件实例 id | `notice-center` |\n| 设置命名空间 | `notice-center` |\n| 安装形态 | npm 包 / GitHub 仓库 / tarball / 本地 link，四种都支持 |\n\n## 目录\n\n**使用**\n\n- [为什么需要它](#为什么需要它)\n- [功能特性](#功能特性)\n- [安装](#安装)\n- [上手三步](#上手三步)\n- [设置项详解](#设置项详解)\n- [常见问题](#常见问题)\n- [已知限制](#已知限制)\n\n**开发**\n\n- [架构总览](#架构总览)\n- [目录结构](#目录结构)\n- [一条通知的生命周期](#一条通知的生命周期)\n- [本地开发](#本地开发)\n- [测试](#测试)\n- [发版](#发版)\n- [更新记录](./CHANGELOG.md)\n- [设计约束](#设计约束)\n\n## 为什么需要它\n\n在 Harness 里，「会话跑完了」和「有事等你拍板」这两个信号，只出现在**侧边栏的小圆点**和**会话本身**上。你一旦切到别的标签页、别的应用，就看不见了。\n\n长任务尤其难受：你去干别的，回来才发现早就跑完；或者一个审批请求已经晾了十分钟。\n\n这个插件把这两个信号搬到你能看到的地方：\n\n| 你不在 DSH 页面时 | 你会看到 |\n|---|---|\n| 会话跑完了 | 标签页鲸鱼变**绿**，并弹出系统通知（单独一条时附本轮总用时） |\n| 有事等你处理 | 标签页鲸鱼变**琥珀**，并弹出系统通知（写明是审批 / 提问 / 计划审核） |\n\n## 功能特性\n\n### 1. 鲸鱼状态灯\n\n三种颜色直接编码在标签页图标上，和侧边栏的绿点、琥珀点**用的是同一份官方信号**，永远同步：\n\n| 鲸鱼颜色 | 含义 | 什么时候恢复 |\n|---|---|---|\n| <img src=\"docs/images/whale-green.svg\" width=\"20\" alt=\"绿色\"> 绿色 | 有会话在你没看它的时候**跑完了** | 该会话点开后自动恢复；全部点开过一遍即回到默认状态 |\n| <img src=\"docs/images/whale-amber.svg\" width=\"20\" alt=\"琥珀色\"> 琥珀色 | 有会话**有事等你处理**：提问 / 审批 / 计划审核 | 处理完后自动消失 |\n| <img src=\"docs/images/whale-black.svg\" width=\"20\" alt=\"黑色\"> 黑色 | 一切正常（官方原版图标） | 默认状态 |\n\n![标签页状态灯：自上而下为完成（绿）、待处理（琥珀）、默认（黑）](docs/images/tab-status-light.png)\n\n- 只统计**主会话**，子代理不计入\n- 绿色与琥珀同时存在时**琥珀优先**——待处理是首要状态，有会话卡住等你时，不会因为别的会话刚跑完而被掩盖\n- 三种颜色都能改（含「默认色」：不配置就沿用官方原版图标）\n\n### 2. 系统通知\n\n两种事件会触发通知，**默认只在你不在看的时候弹**：\n\n| 事件 | 触发时机 | 通知长什么样 |\n|---|---|---|\n| **完成通知** | 会话跑完 | 标题＝会话名；正文＝`会话已完成`，单独一条时附本轮总用时（如 `会话已完成 · 本轮总用时 2分13秒`） |\n| **待处理通知** | 出现新的待处理交互 | 标题＝会话名；正文＝交互类型：`待审批 · <工具名>` / `请你选择`（多选则 `请你多选`、无选项则 `请你填写`、多问题则 `向你提问（N 个）`）/ `计划待审核`；认不出的类型回退为 `有交互等待处理` |\n\n| 完成通知（绿） | 待处理通知（琥珀） |\n|---|---|\n| ![完成通知](docs/images/notification-done.png) | ![待处理通知](docs/images/notification-pending.png) |\n\n> 通知由浏览器发出（本机是 Chrome），所以卡片上显示浏览器与站点 `127.0.0.1:3080`——这是正常的。\n\n其余行为：\n\n- **点击通知** = 聚焦窗口并打开对应会话\n- **只在你不看的时候弹**——「前台」＝标签页可见**且**窗口有焦点；切到别的标签页、最小化、被别的应用压在后面时都会提醒。想在前台也提醒（人还停在会话里、却已离开屏幕，例如在刷手机），打开设置里的「前台提醒」\n- **多条聚合**：300ms 内的事件合并为一条，标题补 `+N`\n- **可常驻**：关掉「自动隐藏」后，通知会一直留在屏幕上，直到你点掉它\n- 通知图标跟随你配置的状态灯颜色\n\n### 3. 提示音\n\n完成与待处理各有独立下拉，共 **47 个条目**：2 个插件内置合成音 + 45 个取自 opencode 内置音效库的 mp3。\n\n| 音效包 | 条目 |\n|---|---|\n| 内置（合成音） | `Chime Up`（完成默认，上行双音）、`Chime Down`（待处理默认，下行双音） |\n| Alert | Alert 01–10 |\n| Bip-bop | Bip-bop 01–10 |\n| Staplebops | Staplebops 01–07 |\n| Nope | Nope 01–12 |\n| Yup | Yup 01–06 |\n\n- **悬浮即试听**：鼠标划过下拉条目就播该音效（120ms 防抖，扫过整列不会连成一片）\n- **调完音量即试听**：拖动音量条松手后，会按新音量播一次完成提示音\n- 开启提示音后，**系统默认提示音会被静音**，改播插件音效\n- 宿主半通过 `/notice-center-sounds/<id>.mp3` 提供音频；路由不可用时**自动回退内置合成音**，不会变哑\n- 老配置无需迁移：没配过音效时仍用 `Chime Up` / `Chime Down`\n\n## 安装\n\n### 前置要求\n\n- **官方版本的 DeepSeek Harness**：`1.4.0` 起要求 **`0.1.7-rc.2+`**；`1.3.x` 支持 `0.1.2-rc.1+`\n  - 兼容范围写在 `engines.dsh` 与 `@deepseek-ai/dsh-*` peer 上，由 `test/compat-range.smoke.mjs` 守护。两条线按宿主版本自动分流：**插件市场不会把 1.4.0 推给旧宿主，DSH 核心在加载前也会拒绝它**——旧宿主原地留在 `1.3.x`，不会收到更新提示。\n  - 版本闸门只比版本号，查不出 API 被删（0.1.7 删掉了 `settings.register`，旧声明在那上面照样 PASS），所以别只靠它当兼容性保障。\n- 系统通知需要**安全上下文**——`http://127.0.0.1:3080` 或 `localhost` 可用；用**局域网 IP** 访问时浏览器的 Notification API 不可用（这是浏览器限制，不是插件问题）\n\n### 方式一：从 npm 安装（推荐）\n\n```sh\ndsh plugin --profile web add dsh-notice-center\n```\n\n包页：<https://www.npmjs.com/package/dsh-notice-center>（`latest` 为稳定版，预发布版在 `next` 通道，用 `dsh-notice-center@next` 装）\n\n### 方式二：直接从 GitHub 安装\n\n```sh\ndsh plugin --profile web add github:SCP-QQ/dsh-notice-center\n# 或走 SSH（本机 HTTPS 受代理影响时）\ndsh plugin --profile web add git+ssh://git@github.com/SCP-QQ/dsh-notice-center.git\n```\n\n### 方式三：从 tarball 安装（离线 / 内网分发）\n\n```sh\nnpm pack                                        # 生成 dsh-notice-center-<版本>.tgz\ndsh plugin --profile web add ./dsh-notice-center-<版本>.tgz\n```\n\n### 方式四：本地 link（改代码时用）\n\n在 profile 的 `package.json` 里：`dependencies` 加 `\"dsh-notice-center\": \"link:<项目目录>\"`，`dsh.profile.bundles` 加 `\"dsh-notice-center\"`，然后在 profile 目录跑 `pnpm install`。\n\n> **四种方式装完都要重启 Harness 才生效。**\n> 从 npm / GitHub 安装时不需要额外提供任何 `@deepseek-ai/*` 包——宿主半的运行时依赖只有 `@deepseek-ai/schemastery`（npm 上有）。\n\n### 卸载\n\n```sh\ndsh plugin --profile web remove dsh-notice-center\n```\n\n移除依赖与 `dsh.profile.bundles` 条目后重启，即无残留。\n\n## 上手三步\n\n1. **打开设置页** —— 设置 → **通知中心**（侧栏导航项）\n2. **授权系统通知** —— 总开关**默认就是开的**：打开页面后，你**第一次点击或按键**时，插件会自动向浏览器请求一次通知授权（浏览器**不允许**没有用户手势的请求，页面自己弹不出来，所以只能借你的一次交互），选「允许」，同时会收到一条「通知已开启」的确认。频率规则：\n\n   - **每次打开页面最多问一次**（同一次会话里点多少下都只问一次，不会连环弹）；\n   - 你在授权窗上选了「允许」或「阻止」→ **不会再问**（权限有定论了）；\n   - 你只是点了 **× / Esc**（既没允许也没阻止）→ 不算做出选择，**下次刷新页面会再问一次**，直到你选为止；\n   - 想彻底不被打扰：把「系统通知」开关**关掉**，或在授权窗里选「阻止」。\n\n   之后想补授权，用开关**正下方**那枚状态 chip（短状态常驻、鼠标悬浮或键盘聚焦问号/叹号看完整说明）：\n\n   | 状态 | chip 长什么样 | 怎么办 |\n   |---|---|---|\n   | **未授权**（自动请求被你关掉了，或从没问过） | 「未授权 · 授权」可点 | 点它，浏览器会重新弹授权窗 |\n   | **已被拒绝** | 叹号 +「已被拒绝」 | 浏览器**不会二次弹窗**（网页也无权打开站点设置页）：悬浮看恢复路径 —— 点地址栏左侧的图标 → 通知 → 允许，或打开 `chrome://settings/content/notifications` |\n   | **当前浏览器不支持** | 一行小字 | 多半是**安全上下文**问题（见「安装 → 前置要求」），用 `http://127.0.0.1:3080` 访问即可 |\n   | 已授权 | 不显示（行保持干净） | — |\n\n   开关本身始终可切（未授权时也能把通知关掉，关掉后就不会再自动请求）；你在站点设置里改完权限回到页面，chip 会立刻跟上。\n3. **按需微调** —— 展开两个分组：调颜色、选音效、调音量、开关「前台提醒」/「自动隐藏」\n\n<img src=\"docs/images/settings.png\" width=\"440\" alt=\"通知中心设置页\">\n\n之后你切走或最小化时，会话跑完 / 有事等你都会收到通知，点通知直接跳回那个会话。\n\n## 设置项详解\n\n| 分组 | 设置项 | 配置键 | 默认值 | 说明 |\n|---|---|---|---|---|\n| 鲸鱼状态灯 | 总开关 | `colorsEnabled` | 开 | 关闭后保持官方原版图标 |\n| | 完成 | `green` | `#22C55E` | 完成状态灯颜色（官方侧边栏色） |\n| | 待处理 | `amber` | `#F59E0B` | 待处理状态灯颜色（官方侧边栏色） |\n| | 默认色 | `black` | 未设置 | 不设置＝沿用官方原版 `/favicon.svg` |\n| 系统通知 | 总开关 | `notifyEnabled` | **开** | 默认开启；首次交互自动请求浏览器授权，未授权时开关下方给状态 chip |\n| | 自动隐藏 | `notifyAutoHide` | 开 | 关＝通知常驻屏幕，需手动关闭 |\n| | 前台提醒 | `notifyForeground` | 关 | 开＝你正看着页面时也提醒 |\n| | 提示音 | `notifySound` | 开 | 开启后静音系统提示音，改播插件音效 |\n| | 音量 | `notifyVolume` | `0.6` | 0–1 |\n| | 完成提示音 | `notifyDoneSound` | `builtin-up` | 47 个可选 |\n| | 待处理提示音 | `notifyPendingSound` | `builtin-down` | 47 个可选 |\n\n配置由 Harness 的 settings 服务持久化到 `<DSH_HOME>/settings.yaml` 的 `notice-center:` 段。\n设置页**最上方**还有一行页脚：插件名 + 版本号（如「通知中心 v1.3.0」），点一下在新标签页打开仓库。\n\n## 常见问题\n\n| 现象 | 原因与处理 |\n|---|---|\n| 设置里找不到「通知中心」 | 插件没加载成功。确认装完**重启过 Harness**，再看 Harness 控制台有没有 `settings namespace \"notice-center\" registered` 这行日志 |\n| 开关点了没反应 / 加了新设置项不生效 | 改过**宿主半**（`lib/index.mjs`）后必须重启 Harness——设置写入要过宿主 schema 校验 |\n| 装完插件后第一次点页面就弹出授权窗 | 通知开关默认开启，插件借你**第一次交互**（点击/按键）自动请求一次授权 —— 浏览器不允许没有用户手势的请求，页面自己弹不出来。不想授权就点「阻止」，之后可在设置页用状态 chip 补授权 |\n| 完全不弹通知 | 三个条件缺一不可：① 系统通知总开关已打开；② 浏览器权限为「允许」；③ 触发时页面不在前台（默认策略，可用「前台提醒」放宽） |\n| 打开开关没弹授权窗 | 只有权限处于「还没问过」时浏览器才会弹；已经「拒绝」过就**不会再弹**，页面会给出站点设置的恢复路径。另外授权请求必须在点击里发起、且要安全上下文（`127.0.0.1` / `localhost`） |\n| 用局域网 IP 打开时不弹 | 非安全上下文，浏览器禁用 Notification API，系统通知**完全不可用**（与「前台提醒」无关）。改用 `127.0.0.1` / `localhost`；局域网下只能靠标签页状态灯 |\n| 标签页关掉后收不到 | 已知限制，见下文 |\n| 刷新页面后绿灯变回黑色 | 正常。该状态是官方信号的内存态，刷新即丢 |\n| 通知一闪而过看不到 | 关掉「自动隐藏」，通知会常驻直到你点掉它 |\n| 没有声音 | 依次查：提示音开关、音量是否为 0、系统音效路由是否可用（不可用时会回退内置合成音，不会完全没声） |\n| 通知被系统吞掉 | Windows「专注助手 / 勿扰」会拦截，插件无法感知 |\n\n## 已知限制\n\n- **浏览器标签页关闭后收不到通知**——Web Push 需要服务端 + HTTPS，本地插件场景不现实\n- **非安全上下文（局域网 IP）下 Notification API 不可用**\n- **刷新页面后绿色状态丢失**——该状态只存在内存中，属官方信号本身的行为\n- **系统级勿扰模式会吞掉通知**（Windows 专注助手等），插件无法感知\n- **自动隐藏的时长不可配**——Web Notification 规范没有时长参数，桌面端由系统决定（约 5–20 秒）\n- **通知卡片的外观不可定制**——卡片由浏览器渲染，没有 CSS / 主题入口，只能控制标题、正文与图标\n\n---\n\n# 开发文档\n\n> 以下是给维护者的内容：架构、本地开发、测试与发版。只想用插件的读者可以到此为止。\n\n## 架构总览\n\n插件由**两半**组成，各自跑在不同进程里，通过 Harness 的 settings 服务交换配置：\n\n| 组成 | 文件 | 跑在哪 | 职责 |\n|---|---|---|---|\n| **宿主半** | `lib/index.mjs` | Harness 主进程（Node） | ① 声明 `Config` schema（设置表单、写入校验、旧 `settings.yaml` 迁移都由它派生）；② 挂载 `/notice-center-sounds/<id>.mp3` 静态音效路由 |\n| **浏览器半** | `lib/client.cjs` | 浏览器（插件 bundle） | favicon 状态机 + 通知状态机 + 音效库 + 设置页 |\n| **bundle patch** | `cordis.patch.yml` | Loader 层 | 往插件树里插入一行 `id: notice-center`（这个 id 就是设置命名空间） |\n\n**宿主半的两个「可选通道」**：\n\n- `ctx.inject([\"settings\"], …)` —— 声明「本插件自带设置页」：`settings.configure({ auto: false }, ctx.fiber)`。owner 必须是插件自身的 fiber（`describe()` 按 `entry.fiber` 查这份策略，而 `inject` 子 fiber 是另一个 fiber）\n- `ctx.inject([\"webServer\"], …)` —— 挂载音效路由。服务缺席时不挂载，浏览器半自动回退到内置合成音\n\n**设置契约（0.1.7 起，这是本插件最容易静默踩坏的地方）**：\n\n- 表单由**插件自己的 Config** 派生：dsh-settings 的 `describe()` 读入口 fiber 的 `runtime.Config`，条目 id 就是命名空间 —— 插件**不再注册命名空间**（旧的 `settings.register(ns, schema)` 在 0.1.7 已删除）。\n- **每个字段都要 `.volatile()`**：`volatileForm()` 只投影「最近的可变祖先」下的字段，漏标一个就等于那个设置项在设置页里整条消失（`test/host-half.smoke.mjs` 为此逐字段断言）。`.volatile()` 需要 **schemastery ≥ 3.18.4**。\n- 老用户设置无需手工迁移：dsh-settings 启动时会读 `<DSH_HOME>/settings.yaml`，把每个 section 按名字写进**同 id** 的条目，再把原文件改名为 `settings.yaml.imported`。我们的段名正好等于条目 id（`notice-center`）。\n\n**为什么宿主半不 import `@deepseek-ai/dsh-settings`**：宿主半的运行时依赖只剩 `@deepseek-ai/schemastery`——而 profile 默认 `autoInstallPeers: false`，真去解析任何 `@deepseek-ai` peer 反而会因 npm 上的版本不匹配而加载失败。这是「能从 registry 干净安装」的关键。\n\n**浏览器半的数据来源**（都是官方客户端服务，插件不自持状态）：\n\n| 服务 | 提供包 | 用途 |\n|---|---|---|\n| `configForms` | `@deepseek-ai/dsh-client-ui-settings` | `configForms.get(entryId)` 读写设置（旧的 `settingsScope` 在 0.1.7 已删除）；快照带 `status` / `writable` |\n| `sessions` | `@deepseek-ai/dsh-api-session-controller/client` | 会话列表快照：`origin` / `running` / `displayTitle` |\n| `uiSession` | `@deepseek-ai/dsh-client-ui-session` | `sessionStatus`：`Map<sessionId, { running, pendingInteraction, completionUnread }>` —— 0.1.7 的 `completed` / `pendingInteraction` 行字段与 `pendingInteractions` store 都已删除，官方 workspace 的会话行用的是同一套映射（`completed` ≡ `completionUnread`） |\n\n音效路由的安全约束：只放行 `^[a-z0-9-]+\\.mp3$` 的文件名（杜绝路径穿越），音频是随包常量故用 `immutable` 长缓存。\n\n## 目录结构\n\n```\npackage.json                    包元数据（scripts: test / test:host / test:client）\ncordis.patch.yml                bundle patch 层（insert id: notice-center）\nlib/index.mjs                   宿主半：settings schema + 音效静态路由\nlib/client.cjs                  浏览器半：favicon 状态机 + 通知状态机 + 音效库 + 设置页\nassets/audio/*.mp3              45 个 opencode 音效（MIT，来源见 assets/audio/README.md）\ndocs/images/                    README 截图、主图与社交预览图\ntest/host-half.smoke.mjs        宿主半冒烟（164 行）\ntest/client-half.smoke.mjs      浏览器半冒烟：状态机 + 设置页真渲染（687 行）\n.github/workflows/test.yml      CI：push / PR 跑 pnpm test\n.github/workflows/publish.yml   发布：打 tag 触发，OIDC 无令牌\n```\n\n## 一条通知的生命周期\n\n```\nsessions.list 变化\n   └─ sync()\n        ├─ trackEdges()        运行状态 true→false 边沿（当前会话在前台跑完的补偿路径）\n        ├─ detectTransitions() 官方 completed false→true；pendingInteractions 新增会话\n        │     └─ queueNotification(kind, sessionId, label, typeLabel)\n        │          ├─ 总开关关闭 → 丢弃\n        │          ├─ 同一次完成已入队 → 丢弃（两条检测路径不得重复发）\n        │          └─ 入队 + 300ms 聚合窗口\n        └─ targetOf() → favicon 换成 绿 / 琥珀 / 默认\n\n300ms 后 flushNotifications()\n   ├─ 权限未授权 → 丢弃\n   ├─ 页面在前台且未开「前台提醒」→ 丢弃\n   ├─ 按 kind 分组 → 每组一条 Notification（标题＝会话名，正文＝通知类型）\n   └─ 播放所选音效\n```\n\n通知**不设置 `tag`**：同一会话反复跑完会复用同一个 tag，Windows/Chrome 会把后一条当成「更新已有通知」而静默替换、不再弹横幅。\n\n## 本地开发\n\n```sh\npnpm install          # 唯一运行时依赖是 @deepseek-ai/schemastery\nnpm test              # 宿主半 + 浏览器半冒烟\n```\n\n**重启要求分两半——这是本项目最容易踩的坑：**\n\n| 改了什么 | 要不要重启 Harness | 为什么 |\n|---|---|---|\n| `lib/client.cjs`（浏览器半） | **不用**，刷新页面最干净 | 客户端 HMR 会 stat-poll 到 bundle 变化并通知浏览器重载该插件 |\n| `lib/index.mjs`（宿主半） | **必须重启** | 宿主半热重载依赖 `cordis-plugin-hmr`（需 loader 带 `--expose-internals`），实测未生效。**改 schema（增删设置项）同样必须重启**——否则设置页写入过不了校验，表现为「开关点不动」 |\n| 首次安装、任何改名 | **必须重启** | 插件树与 bundle 列表变了 |\n\n调试提示：浏览器半的报错都在 DevTools Console；宿主半注册成功会在 Harness 控制台打一行 `dsh-notice-center: settings namespace \"notice-center\" registered`。\n\n## 测试\n\n```sh\nnpm test            # 两个都跑（CI 跑的也是这个）\nnpm run test:host   # 只跑宿主半\nnpm run test:client # 只跑浏览器半\n```\n\n两个冒烟测试都是**零依赖、纯 Node**，不需要浏览器：\n\n- **宿主半**（164 行）：`apply()` 真执行一遍、断言只注入预期服务、schema 默认值与校验、音效路由（能取到 mp3 / 不存在 404 / 拒绝路径穿越 / 随包 45 个齐全）、settings.yaml 存量配置过 schema 且**逐项原样保留**\n- **浏览器半**（687 行）：桩掉 `window.__ModuleLoader__` / `document` / `Notification`，evaluate bundle 后取 factory，用假 `ctx` 装配 `apply()`，然后驱动状态跃迁断言 Notification 的构造参数；设置页用**记录型桩**真渲染（React 元素树），断言开关顺序、只写对应字段、折叠行为、页脚等\n\n被测试钉死的不变量（改代码时别破坏）：\n\n- `lib/client.cjs` 里的 `PLUGIN_VERSION` / `PLUGIN_NAME` / `PLUGIN_REPO` 必须与 `package.json` 一致\n- 音效库 `SOUND_PACKS` 必须与 `assets/audio/` 里的文件**一一对应**；新增音效要同步改 `lib/client.cjs` 与 `test/client-half.smoke.mjs` **两处**\n- `zh` / `en` 两套文案的 key 集合必须一致\n\n## 发版\n\n发布由 **tag 触发**的 [`publish.yml`](.github/workflows/publish.yml) 负责——日常 commit / push **不会发包**：\n\n| 意图 | 命令 | 结果 |\n|---|---|---|\n| 只提交（功能没验证完） | `git commit` + `git push` | 只跑 `test.yml`，npm 上毫无动静 |\n| 预发布（给人试用） | 版本改 `1.3.0-rc.1` → commit → `git tag v1.3.0-rc.1 && git push origin v1.3.0-rc.1` | 发到 **`next`** 通道，`latest` 不变 |\n| 正式发版 | 版本改 `1.3.0` → commit → `git tag v1.3.0 && git push origin v1.3.0` | 发到 **`latest`**，自动附带 provenance |\n| 只验证发布流程 | Actions → publish → Run workflow | 装依赖 + 跑测试 + `npm pack --dry-run`，**不发布** |\n\n工作流内建**三道闸**，任一不过就发不出去：\n\n1. tag 与 `package.json` 版本必须一致\n2. tag 指向的提交必须已在 `main` 上\n3. 测试必须通过\n\n另外发布步骤**幂等**：该版本已在 registry 上就跳过，重复打 tag / 重跑工作流不会红。\n\n发版前先在本仓库 [`CHANGELOG.md`](./CHANGELOG.md) 补上这一版（用户可见改动 + 兼容性）再打 tag ——\n它是 npm 包页与 GitHub Release 上那份「更新说明」的来源。\n\n### 一次性配置：npm Trusted Publishing (OIDC)\n\n发布不需要任何 npm 令牌（也就没有令牌过期 / 泄漏问题）。打开包管理页 → **Publishing Access** → *Trusted publishers* → **Add a trusted publisher** → 选 **GitHub Actions**：\n\n<https://www.npmjs.com/package/dsh-notice-center/access>\n\n| 字段 | 值 |\n|---|---|\n| Organization or user | `SCP-QQ` |\n| Repository | `dsh-notice-center` |\n| Workflow filename | `publish.yml`（**只填文件名**，不带路径；重命名该文件必须同步改这里，否则 403） |\n| Environment name | `npm`（与工作流里的 `environment:` 一致） |\n| **Allowed actions → Allow npm publish** | ✅ **必须勾** |\n\n> ⚠️ 那个勾选框是 npm 的新行为：trusted publisher **默认只允许 `npm stage publish`（暂存）**，不勾 *Allow npm publish* 的话，工作流里的 `npm publish` 会被拒。\n> 若你更想要「只能暂存、必须人工在浏览器批准才真发布」，就别勾，并把工作流末步改成 `npm stage publish`。\n\n- 走 OIDC 发布时 npm **自动附带 provenance**（无需 `--provenance`），包页会显示来源证明\n- 想要「tag 推上去还要人工点一下才发」：仓库 Settings → Environments → `npm` → 加 **Required reviewers**；不加也能正常发布\n- 本机手动发布仍可用 granular token 兜底：在项目根放一个 `.npmrc` 写 `//registry.npmjs.org/:_authToken=<token>`。该文件已在 `.gitignore` 里，**绝不要提交**\n\n## 设计约束\n\n改代码前请先读这几条，它们都是踩过坑换来的：\n\n1. **通知不带 `tag`**——同 tag 会被系统当成「更新已有通知」静默替换（详见上文「一条通知的生命周期」）\n2. **「前台」判定是 `标签页可见 && 窗口有焦点`**——只看 `visibilityState` 会把「浏览器被别的应用压在后面」误判成正在看，而那恰恰是最该提醒的时候\n3. **状态灯琥珀优先于绿**——与官方 `sessionStatuses` 一致，待处理是首要状态\n4. **通知时长来自观察 `running` 边沿**——刷新页面时已经在跑的会话算不出起点，就不显示这个数（不猜）\n5. **宿主半保持零 `@deepseek-ai` 运行时依赖**——只 import `schemastery`，否则 registry 安装会因 peer 解析失败而挂掉\n6. **音效路由只放行 `^[a-z0-9-]+\\.mp3$`**——文件名直接参与 path join，必须白名单\n\n## 反馈与贡献\n\n- 问题与建议：<https://github.com/SCP-QQ/dsh-notice-center/issues>\n- 改动请先跑 `npm test`；涉及设置项的改动记得同步 `test/*.smoke.mjs` 的断言\n- 音效素材来自 [anomalyco/opencode](https://github.com/anomalyco/opencode)（MIT），替换或移除请同步 [`assets/audio/README.md`](./assets/audio/README.md)\n\n## License\n\nMIT，完整许可文本见 [`LICENSE`](./LICENSE)。\n\n音效素材（`assets/audio/*.mp3`，45 个）取自 [anomalyco/opencode](https://github.com/anomalyco/opencode) 的 `packages/ui/src/assets/audio/`，上游以 MIT 许可发布，这里保留同样的许可与署名；若上游调整授权，请同步替换或移除本目录。\n","readmeFilename":"README.md"}