{"_id":"@dennisrongo/dsh-todo","_rev":"8-b590f9ef9a322343d7937c46efc76c4a","name":"@dennisrongo/dsh-todo","dist-tags":{"latest":"0.5.2"},"versions":{"0.1.0":{"name":"@dennisrongo/dsh-todo","version":"0.1.0","author":{"name":"Dennis Rongo"},"license":"MIT","_id":"@dennisrongo/dsh-todo@0.1.0","maintainers":[{"name":"dennisrongo","email":"dennis@menacestudio.com"}],"homepage":"https://github.com/dennisrongo/dsh-plugins/tree/main/plugins/dsh-todo#readme","bugs":{"url":"https://github.com/dennisrongo/dsh-plugins/issues"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"},"client":{"inject":["@deepseek-ai/dsh-client-runtime"],"platform":"web","immediately":true}},"dist":{"shasum":"3225b9d71edb8bc302738321626c69e0f5f1b909","tarball":"https://registry.npmjs.org/@dennisrongo/dsh-todo/-/dsh-todo-0.1.0.tgz","fileCount":6,"integrity":"sha512-Nru6tSLzcHNBLUMdNN/Fiz45eAJ68WPXr6PwGrTYTAUlbeiNt0C+SzvtdSLtsUZ+vJOLw9hmwI+0jIYbZ0ZOPA==","signatures":[{"sig":"MEYCIQDBdqJER/jQ8M0CpKSvwj6Uq51QxpkU4YsBHL+aC5uUDQIhAJn2ovAUViTjRpvmTRhdDUPDf4FucZ9U8qzpROq3QN2t","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dennisrongo%2fdsh-todo@0.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":375870},"main":"lib/index.js","pnpm":{"onlyBuiltDependencies":["esbuild"]},"type":"module","exports":{".":{"default":"./lib/index.js"},"./client":{"default":"./lib/client.js"},"./typert":{"default":"./lib/typert.host.js"},"./package.json":"./package.json"},"gitHead":"af2fc63d3ef2600cff8b0f1f03bfb89aa8ed5c88","scripts":{"test":"node test/smoke.mjs","build":"node build/build.mjs","typecheck":"tsc --noEmit"},"_npmUser":{"name":"dennisrongo","email":"dennis@menacestudio.com"},"repository":{"url":"git+https://github.com/dennisrongo/dsh-plugins.git","type":"git","directory":"plugins/dsh-todo"},"_npmVersion":"10.9.8","description":"Todo list for DeepSeek Harness (dsh) — a per-workspace task list persisted on disk by the host","directories":{},"_nodeVersion":"22.23.2","dependencies":{"zod":"^4.4.3"},"_hasShrinkwrap":false,"devDependencies":{"react":"^18.3.0","esbuild":"^0.24.0","react-dom":"^18.3.0","typescript":"^5.6.0","@types/node":"^22.20.1","@types/react":"^18.3.0"},"peerDependencies":{"@deepseek-ai/cordis":"^4.0.1","@deepseek-ai/dsh-storage-domain":"^0.1.1-rc.2","@deepseek-ai/dsh-typert-protocol":"^0.1.1-rc.2"},"_npmOperationalInternal":{"tmp":"tmp/dsh-todo_0.1.0_1787867489049_0.7461175270337084","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@dennisrongo/dsh-todo","version":"0.2.0","author":{"name":"Dennis Rongo"},"license":"MIT","_id":"@dennisrongo/dsh-todo@0.2.0","maintainers":[{"name":"dennisrongo","email":"dennis@menacestudio.com"}],"homepage":"https://github.com/dennisrongo/dsh-plugins/tree/main/plugins/dsh-todo#readme","bugs":{"url":"https://github.com/dennisrongo/dsh-plugins/issues"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"},"client":{"inject":["@deepseek-ai/dsh-client-runtime"],"platform":"web","immediately":true}},"dist":{"shasum":"1212235855835ef95f1812faf96d25826f725ef7","tarball":"https://registry.npmjs.org/@dennisrongo/dsh-todo/-/dsh-todo-0.2.0.tgz","fileCount":6,"integrity":"sha512-Q6W3QnBu6b1HL+zzWVjYMuFMdUUc11t4vUhIbBX+piAFFVg5lx5qyfn7nXUFCpFHokSveb8RanooYg/NSt3e+g==","signatures":[{"sig":"MEQCIBkKbxIrvut0dvbCVVJlTeO7zyS2cgUFcFe5t2g7stq/AiBo4KZ5LyeFUoOvsCvrAXlqFH4667tVJJoEWASH313j7A==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dennisrongo%2fdsh-todo@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":375870},"main":"lib/index.js","pnpm":{"onlyBuiltDependencies":["esbuild"]},"type":"module","exports":{".":{"default":"./lib/index.js"},"./client":{"default":"./lib/client.js"},"./typert":{"default":"./lib/typert.host.js"},"./package.json":"./package.json"},"gitHead":"e8ade9e9fdfff3981b3cd9753c3f79b0a4ba11e6","scripts":{"test":"node test/smoke.mjs","build":"node build/build.mjs","typecheck":"tsc --noEmit"},"_npmUser":{"name":"dennisrongo","email":"dennis@menacestudio.com"},"repository":{"url":"git+https://github.com/dennisrongo/dsh-plugins.git","type":"git","directory":"plugins/dsh-todo"},"_npmVersion":"10.9.8","description":"Todo list for DeepSeek Harness (dsh) — a per-workspace task list persisted on disk by the host","directories":{},"_nodeVersion":"22.23.2","dependencies":{"zod":"^4.4.3"},"_hasShrinkwrap":false,"devDependencies":{"react":"^18.3.0","esbuild":"^0.24.0","react-dom":"^18.3.0","typescript":"^5.6.0","@types/node":"^22.20.1","@types/react":"^18.3.0"},"peerDependencies":{"@deepseek-ai/cordis":"^4.0.1","@deepseek-ai/dsh-storage-domain":"^0.1.1-rc.2","@deepseek-ai/dsh-typert-protocol":"^0.1.1-rc.2"},"_npmOperationalInternal":{"tmp":"tmp/dsh-todo_0.2.0_1787880931648_0.11565364843496995","host":"s3://npm-registry-packages-npm-production"}},"0.3.0":{"name":"@dennisrongo/dsh-todo","version":"0.3.0","author":{"name":"Dennis Rongo"},"license":"MIT","_id":"@dennisrongo/dsh-todo@0.3.0","maintainers":[{"name":"dennisrongo","email":"dennis@menacestudio.com"}],"homepage":"https://github.com/dennisrongo/dsh-plugins/tree/main/plugins/dsh-todo#readme","bugs":{"url":"https://github.com/dennisrongo/dsh-plugins/issues"},"bin":{"dsh-todo":"lib/bin.js"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"},"client":{"inject":["@deepseek-ai/dsh-client-runtime"],"platform":"web","immediately":true}},"dist":{"shasum":"7e74b9e305b9d11ba365a039be14e31a3eff12f9","tarball":"https://registry.npmjs.org/@dennisrongo/dsh-todo/-/dsh-todo-0.3.0.tgz","fileCount":8,"integrity":"sha512-yk0zqW7myvYgfwNZr+3YmddPLEKXmjWdaQdSUQ/Aa9Yi0t9dAigrI7+jy2aeHKvw1QvWqZ7CCnY7L4tpBHy+Qw==","signatures":[{"sig":"MEQCIEv74n2oJlD6ZdkP5BaeOdLTNB/UTZWWqxPp4jYki1eGAiBiTUoprn7r7bp29sG8iPDZWAHQa/mo4/xH3up/+0eslw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dennisrongo%2fdsh-todo@0.3.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":457099},"main":"lib/index.js","pnpm":{"onlyBuiltDependencies":["esbuild"]},"type":"module","exports":{".":{"default":"./lib/index.js"},"./cli":{"default":"./lib/cli.js"},"./client":{"default":"./lib/client.js"},"./typert":{"default":"./lib/typert.host.js"},"./package.json":"./package.json"},"gitHead":"377c8ef55a1bc9a64a99d08a7b73c398ae83b113","scripts":{"test":"node test/smoke.mjs && node test/cli.test.mjs","build":"node build/build.mjs","test:cli":"node test/cli.test.mjs","typecheck":"tsc --noEmit","test:icons":"node test/icon-probe.mjs","test:modal":"node test/modal-probe.mjs"},"_npmUser":{"name":"dennisrongo","email":"dennis@menacestudio.com"},"repository":{"url":"git+https://github.com/dennisrongo/dsh-plugins.git","type":"git","directory":"plugins/dsh-todo"},"_npmVersion":"10.9.8","description":"Todo list for DeepSeek Harness (dsh) — a per-workspace task list persisted on disk by the host","directories":{},"_nodeVersion":"22.23.2","dependencies":{"zod":"^4.4.3"},"_hasShrinkwrap":false,"devDependencies":{"react":"^18.3.0","esbuild":"^0.24.0","react-dom":"^18.3.0","typescript":"^5.6.0","@types/node":"^22.20.1","@types/react":"^18.3.0","@types/react-dom":"^18.3.0"},"peerDependencies":{"@deepseek-ai/cordis":"^4.0.1","@deepseek-ai/dsh-storage-domain":"^0.1.1-rc.2","@deepseek-ai/dsh-typert-protocol":"^0.1.1-rc.2"},"_npmOperationalInternal":{"tmp":"tmp/dsh-todo_0.3.0_1787891184030_0.3836849327558487","host":"s3://npm-registry-packages-npm-production"}},"0.4.0":{"name":"@dennisrongo/dsh-todo","version":"0.4.0","author":{"name":"Dennis Rongo"},"license":"MIT","_id":"@dennisrongo/dsh-todo@0.4.0","maintainers":[{"name":"dennisrongo","email":"dennis@menacestudio.com"}],"homepage":"https://github.com/dennisrongo/dsh-plugins/tree/main/plugins/dsh-todo#readme","bugs":{"url":"https://github.com/dennisrongo/dsh-plugins/issues"},"bin":{"dsh-todo":"lib/bin.js"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"},"client":{"inject":["@deepseek-ai/dsh-client-runtime"],"platform":"web","immediately":true}},"dist":{"shasum":"14a2d4142e087b472eeb2814322c56c3f7a15313","tarball":"https://registry.npmjs.org/@dennisrongo/dsh-todo/-/dsh-todo-0.4.0.tgz","fileCount":8,"integrity":"sha512-al65xxX+kZeSajCyiDeQHaR1t84lzkYyVvNixShU5E4ECJ/QTd4tHI8e9Z0D42Y7TJDsIedR7CdOyi10EvT4jA==","signatures":[{"sig":"MEYCIQCWNTJmIe9REai2ZUmojXHufXVMU57dD04bHknepI3OzAIhALRDbzqAHgFPSzcvIbcQ0f+MDtEToIyvpcsezPHoJIL9","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dennisrongo%2fdsh-todo@0.4.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":458189},"main":"lib/index.js","pnpm":{"onlyBuiltDependencies":["esbuild"]},"type":"module","exports":{".":{"default":"./lib/index.js"},"./cli":{"default":"./lib/cli.js"},"./client":{"default":"./lib/client.js"},"./typert":{"default":"./lib/typert.host.js"},"./package.json":"./package.json"},"gitHead":"95502da7aac802c5e846caefdd9bb9c2e5961a56","scripts":{"test":"node build/build.mjs && node test/smoke.mjs && node test/cli.test.mjs","build":"node build/build.mjs","test:cli":"node test/cli.test.mjs","typecheck":"tsc --noEmit","test:icons":"node test/icon-probe.mjs","test:modal":"node test/modal-probe.mjs"},"_npmUser":{"name":"dennisrongo","email":"dennis@menacestudio.com"},"repository":{"url":"git+https://github.com/dennisrongo/dsh-plugins.git","type":"git","directory":"plugins/dsh-todo"},"_npmVersion":"10.9.8","description":"Todo list for DeepSeek Harness (dsh) — a per-workspace task list persisted on disk by the host","directories":{},"_nodeVersion":"22.23.2","dependencies":{"zod":"^4.4.3"},"_hasShrinkwrap":false,"devDependencies":{"react":"^18.3.0","esbuild":"^0.24.0","react-dom":"^18.3.0","typescript":"^5.6.0","@types/node":"^22.20.1","@types/react":"^18.3.0","@types/react-dom":"^18.3.0"},"peerDependencies":{"@deepseek-ai/cordis":"^4.0.1","@deepseek-ai/dsh-storage-domain":"^0.1.1-rc.2","@deepseek-ai/dsh-typert-protocol":"^0.1.1-rc.2"},"_npmOperationalInternal":{"tmp":"tmp/dsh-todo_0.4.0_1787979883749_0.32985103062070276","host":"s3://npm-registry-packages-npm-production"}},"0.4.1":{"name":"@dennisrongo/dsh-todo","version":"0.4.1","author":{"name":"Dennis Rongo"},"license":"MIT","_id":"@dennisrongo/dsh-todo@0.4.1","maintainers":[{"name":"dennisrongo","email":"dennis@menacestudio.com"}],"homepage":"https://github.com/dennisrongo/dsh-plugins/tree/main/plugins/dsh-todo#readme","bugs":{"url":"https://github.com/dennisrongo/dsh-plugins/issues"},"bin":{"dsh-todo":"lib/bin.js"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"},"client":{"inject":["@deepseek-ai/dsh-client-runtime"],"platform":"web","immediately":true}},"dist":{"shasum":"1e56bd1ab051934f5139bf7a31b952749a7d15b1","tarball":"https://registry.npmjs.org/@dennisrongo/dsh-todo/-/dsh-todo-0.4.1.tgz","fileCount":9,"integrity":"sha512-q9DuHHV5C8OlCb9BzChec7IZ302LavbMikxRh+o1wu+ou2EgmbHkp9ABt7C9JPrx7+xsdp92bVRkUezDrLqrzw==","signatures":[{"sig":"MEUCIQCIvSaQyyo1rV331lG3ZSlZw0IzaSg22Wyph02X8c17JwIgA3xEOkZvojF1hwpiptIapGcJFDDif//3AHE0JfNwvVk=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dennisrongo%2fdsh-todo@0.4.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":484398},"main":"lib/index.js","pnpm":{"onlyBuiltDependencies":["esbuild"]},"type":"module","exports":{".":{"default":"./lib/index.js"},"./cli":{"default":"./lib/cli.js"},"./client":{"default":"./lib/client.js"},"./typert":{"default":"./lib/typert.host.js"},"./package.json":"./package.json"},"gitHead":"2edee11439b729563525e8424ee57cc152a036ac","scripts":{"test":"node build/build.mjs && node test/smoke.mjs && node test/context-probe.mjs && node test/launch-effect.mjs && node test/launch-lifecycle.mjs && node test/cli.test.mjs && node test/cli-integration.mjs","build":"node build/build.mjs","test:cli":"node test/cli.test.mjs","typecheck":"tsc --noEmit","test:agent":"node test/verify-agent.mjs","test:icons":"node test/icon-probe.mjs","test:modal":"node test/modal-probe.mjs","test:integration":"node test/cli-integration.mjs"},"_npmUser":{"name":"dennisrongo","email":"dennis@menacestudio.com"},"repository":{"url":"git+https://github.com/dennisrongo/dsh-plugins.git","type":"git","directory":"plugins/dsh-todo"},"_npmVersion":"10.9.8","description":"Todo list for DeepSeek Harness (dsh) — a per-workspace task list persisted on disk by the host","directories":{},"_nodeVersion":"22.23.2","dependencies":{"zod":"^4.4.3"},"_hasShrinkwrap":false,"devDependencies":{"react":"^18.3.0","esbuild":"^0.24.0","react-dom":"^18.3.0","typescript":"^5.6.0","@types/node":"^22.20.1","@types/react":"^18.3.0","@types/react-dom":"^18.3.0"},"peerDependencies":{"@deepseek-ai/cordis":"^4.0.1","@deepseek-ai/dsh-storage-domain":"^0.1.1-rc.2","@deepseek-ai/dsh-typert-protocol":"^0.1.1-rc.2"},"_npmOperationalInternal":{"tmp":"tmp/dsh-todo_0.4.1_1788138346298_0.19268736574701117","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@dennisrongo/dsh-todo","version":"0.5.0","author":{"name":"Dennis Rongo"},"license":"MIT","_id":"@dennisrongo/dsh-todo@0.5.0","maintainers":[{"name":"dennisrongo","email":"dennis@menacestudio.com"}],"homepage":"https://github.com/dennisrongo/dsh-plugins/tree/main/plugins/dsh-todo#readme","bugs":{"url":"https://github.com/dennisrongo/dsh-plugins/issues"},"bin":{"dsh-todo":"lib/bin.js"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"},"client":{"inject":["@deepseek-ai/dsh-client-runtime"],"platform":"web","immediately":true}},"dist":{"shasum":"3d1c6e85525b40e1e30347ab78370b6c89994d94","tarball":"https://registry.npmjs.org/@dennisrongo/dsh-todo/-/dsh-todo-0.5.0.tgz","fileCount":11,"integrity":"sha512-y8XX36ns6D19FQYvG6byRaG5Bymmf6reHom0k2YGat42op4gI+8r27HC0hwh7DPUI5CrW8333C+Lz6KZ+h1q5Q==","signatures":[{"sig":"MEUCIQDJ8zR9jjBqcp9/JjYxEmjc5HLsfNiL+M20Zkoxp371kAIgZrqMibQLn/ZLQcvdowz6oJp9nwRoq4GWNna9z2Chw3g=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dennisrongo%2fdsh-todo@0.5.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":530590},"main":"lib/index.js","pnpm":{"onlyBuiltDependencies":["esbuild"]},"type":"module","exports":{".":{"default":"./lib/index.js"},"./cli":{"default":"./lib/cli.js"},"./client":{"default":"./lib/client.js"},"./typert":{"default":"./lib/typert.host.js"},"./package.json":"./package.json"},"gitHead":"6232633674e5d46bcdf24d2f0e40b65ff186d80e","scripts":{"test":"node build/build.mjs && node test/smoke.mjs && node test/context-probe.mjs && node test/launch-effect.mjs && node test/launch-lifecycle.mjs && node test/suggest-lifecycle.mjs && node test/suggest.test.mjs && node test/scan.test.mjs && node test/cli.test.mjs && node test/cli-integration.mjs","build":"node build/build.mjs","test:cli":"node test/cli.test.mjs","typecheck":"tsc --noEmit","test:agent":"node test/verify-agent.mjs","test:icons":"node test/icon-probe.mjs","test:modal":"node test/modal-probe.mjs","test:integration":"node test/cli-integration.mjs"},"_npmUser":{"name":"dennisrongo","email":"dennis@menacestudio.com"},"repository":{"url":"git+https://github.com/dennisrongo/dsh-plugins.git","type":"git","directory":"plugins/dsh-todo"},"_npmVersion":"10.9.8","description":"Todo list for DeepSeek Harness (dsh) — a per-workspace task list persisted on disk by the host","directories":{},"_nodeVersion":"22.23.2","dependencies":{"zod":"^4.4.3"},"_hasShrinkwrap":false,"devDependencies":{"react":"^18.3.0","esbuild":"^0.24.0","react-dom":"^18.3.0","typescript":"^5.6.0","@types/node":"^22.20.1","@types/react":"^18.3.0","@types/react-dom":"^18.3.0"},"peerDependencies":{"@deepseek-ai/cordis":"^4.0.1","@deepseek-ai/dsh-storage-domain":"^0.1.1-rc.2","@deepseek-ai/dsh-typert-protocol":"^0.1.1-rc.2"},"_npmOperationalInternal":{"tmp":"tmp/dsh-todo_0.5.0_1788284305703_0.46192044798743703","host":"s3://npm-registry-packages-npm-production"}},"0.5.1":{"name":"@dennisrongo/dsh-todo","version":"0.5.1","author":{"name":"Dennis Rongo"},"license":"MIT","_id":"@dennisrongo/dsh-todo@0.5.1","maintainers":[{"name":"dennisrongo","email":"dennis@menacestudio.com"}],"homepage":"https://github.com/dennisrongo/dsh-plugins/tree/main/plugins/dsh-todo#readme","bugs":{"url":"https://github.com/dennisrongo/dsh-plugins/issues"},"bin":{"dsh-todo":"lib/bin.js"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"},"client":{"inject":["@deepseek-ai/dsh-client-runtime"],"platform":"web","immediately":true}},"dist":{"shasum":"12cb7354516e71509ad57f04d6d8f0253cb5e46f","tarball":"https://registry.npmjs.org/@dennisrongo/dsh-todo/-/dsh-todo-0.5.1.tgz","fileCount":11,"integrity":"sha512-VSY8fV0H77JQUiHd2J+O/tM5l/7admHLJBlUJ047XDTrUog58twA0/WmxQhytKFQJtaowZlqxLOnwqd2jcYDsw==","signatures":[{"sig":"MEYCIQCXn1fXIG1u2pzLYsnL1mzpS9XxUMFUajSwApdRBmRCuQIhAMo6p+Z/pHfMXQfPXRKr3f4Cc4THe/7sa42Rr7OwD8Eh","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dennisrongo%2fdsh-todo@0.5.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":531848},"main":"lib/index.js","pnpm":{"onlyBuiltDependencies":["esbuild"]},"type":"module","exports":{".":{"default":"./lib/index.js"},"./cli":{"default":"./lib/cli.js"},"./client":{"default":"./lib/client.js"},"./typert":{"default":"./lib/typert.host.js"},"./package.json":"./package.json"},"gitHead":"b037914e62a2b12d5c76d3387b218f96319d7a54","scripts":{"test":"node build/build.mjs && node test/smoke.mjs && node test/context-probe.mjs && node test/launch-effect.mjs && node test/launch-lifecycle.mjs && node test/suggest-lifecycle.mjs && node test/suggest.test.mjs && node test/scan.test.mjs && node test/cli.test.mjs && node test/cli-integration.mjs","build":"node build/build.mjs","test:cli":"node test/cli.test.mjs","typecheck":"tsc --noEmit","test:agent":"node test/verify-agent.mjs","test:icons":"node test/icon-probe.mjs","test:modal":"node test/modal-probe.mjs","test:integration":"node test/cli-integration.mjs"},"_npmUser":{"name":"dennisrongo","email":"dennis@menacestudio.com"},"repository":{"url":"git+https://github.com/dennisrongo/dsh-plugins.git","type":"git","directory":"plugins/dsh-todo"},"_npmVersion":"10.9.8","description":"Todo list for DeepSeek Harness (dsh) — a per-workspace task list persisted on disk by the host","directories":{},"_nodeVersion":"22.23.2","dependencies":{"zod":"^4.4.3"},"_hasShrinkwrap":false,"devDependencies":{"react":"^18.3.0","esbuild":"^0.24.0","react-dom":"^18.3.0","typescript":"^5.6.0","@types/node":"^22.20.1","@types/react":"^18.3.0","@types/react-dom":"^18.3.0"},"peerDependencies":{"@deepseek-ai/cordis":"^4.0.1","@deepseek-ai/dsh-storage-domain":"^0.1.1-rc.2","@deepseek-ai/dsh-typert-protocol":"^0.1.1-rc.2"},"_npmOperationalInternal":{"tmp":"tmp/dsh-todo_0.5.1_1788288075902_0.016331725265756214","host":"s3://npm-registry-packages-npm-production"}},"0.5.2":{"name":"@dennisrongo/dsh-todo","version":"0.5.2","description":"Todo list for DeepSeek Harness (dsh) — a per-workspace task list persisted on disk by the host","type":"module","license":"MIT","author":{"name":"Dennis Rongo"},"main":"lib/index.js","bin":{"dsh-todo":"lib/bin.js"},"exports":{".":{"default":"./lib/index.js"},"./client":{"default":"./lib/client.js"},"./typert":{"default":"./lib/typert.host.js"},"./cli":{"default":"./lib/cli.js"},"./package.json":"./package.json"},"scripts":{"build":"node build/build.mjs","typecheck":"tsc --noEmit","test":"node build/build.mjs && node test/smoke.mjs && node test/context-probe.mjs && node test/launch-effect.mjs && node test/launch-lifecycle.mjs && node test/suggest-lifecycle.mjs && node test/suggest.test.mjs && node test/scan.test.mjs && node test/cli.test.mjs && node test/cli-integration.mjs","test:icons":"node test/icon-probe.mjs","test:modal":"node test/modal-probe.mjs","test:cli":"node test/cli.test.mjs","test:integration":"node test/cli-integration.mjs","test:agent":"node test/verify-agent.mjs"},"dsh":{"bundle":{"patch":"./cordis.patch.yml"},"client":{"platform":"web","inject":["@deepseek-ai/dsh-client-runtime"],"immediately":true}},"pnpm":{"onlyBuiltDependencies":["esbuild"]},"dependencies":{"zod":"^4.4.3"},"peerDependencies":{"@deepseek-ai/cordis":"^4.0.1","@deepseek-ai/dsh-storage-domain":"^0.1.1-rc.2","@deepseek-ai/dsh-typert-protocol":"^0.1.1-rc.2"},"devDependencies":{"@types/node":"^22.20.1","@types/react":"^18.3.0","@types/react-dom":"^18.3.0","esbuild":"^0.24.0","react":"^18.3.0","react-dom":"^18.3.0","typescript":"^5.6.0"},"repository":{"type":"git","url":"git+https://github.com/dennisrongo/dsh-plugins.git","directory":"plugins/dsh-todo"},"homepage":"https://github.com/dennisrongo/dsh-plugins/tree/main/plugins/dsh-todo#readme","bugs":{"url":"https://github.com/dennisrongo/dsh-plugins/issues"},"_id":"@dennisrongo/dsh-todo@0.5.2","gitHead":"b64fb9dee30e58b9425a81cc34ff9c1c31e893c3","_nodeVersion":"22.23.2","_npmVersion":"10.9.8","dist":{"integrity":"sha512-a0ZaE7NSxq49gk7tZ+bHH0RMh2YDAr+lejGI/1HFFIOYCr3h3+AI32O1zA5r+7GREZ8DV4oYhY+z6akmFTfdPw==","shasum":"7b846e954b9fe3e4b25e07dd7c58cdb1d96f339b","tarball":"https://registry.npmjs.org/@dennisrongo/dsh-todo/-/dsh-todo-0.5.2.tgz","fileCount":11,"unpackedSize":532131,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@dennisrongo%2fdsh-todo@0.5.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDfPorkUEWro+dezPQEkIEt3ng+vWqhvEXDfH5H4U3XnwIhALIt6xCAyXeAPBPIs78iEf0Ux23v1kzCQc/ayhyVvDcU"}]},"_npmUser":{"name":"dennisrongo","email":"dennis@menacestudio.com"},"directories":{},"maintainers":[{"name":"dennisrongo","email":"dennis@menacestudio.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/dsh-todo_0.5.2_1788292683010_0.3348477331845887"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-27T21:51:28.912Z","modified":"2026-09-01T19:58:03.460Z","0.1.0":"2026-08-27T21:51:29.205Z","0.2.0":"2026-08-28T01:35:31.798Z","0.3.0":"2026-08-28T04:26:24.159Z","0.4.0":"2026-08-29T05:04:43.899Z","0.4.1":"2026-08-31T01:05:46.471Z","0.5.0":"2026-09-01T17:38:25.845Z","0.5.1":"2026-09-01T18:41:16.049Z","0.5.2":"2026-09-01T19:58:03.142Z"},"bugs":{"url":"https://github.com/dennisrongo/dsh-plugins/issues"},"author":{"name":"Dennis Rongo"},"license":"MIT","homepage":"https://github.com/dennisrongo/dsh-plugins/tree/main/plugins/dsh-todo#readme","repository":{"type":"git","url":"git+https://github.com/dennisrongo/dsh-plugins.git","directory":"plugins/dsh-todo"},"description":"Todo list for DeepSeek Harness (dsh) — a per-workspace task list persisted on disk by the host","maintainers":[{"name":"dennisrongo","email":"dennis@menacestudio.com"}],"readme":"# @dennisrongo/dsh-todo\n\n[![npm](https://img.shields.io/npm/v/@dennisrongo/dsh-todo)](https://www.npmjs.com/package/@dennisrongo/dsh-todo)\n\n**npm:** [`@dennisrongo/dsh-todo`](https://www.npmjs.com/package/@dennisrongo/dsh-todo) ·\n**source:** [dennisrongo/dsh-plugins](https://github.com/dennisrongo/dsh-plugins/tree/main/plugins/dsh-todo)\n\nA todo list for the [DeepSeek Harness](https://github.com/deepseek-ai) (dsh) web UI.\n\nRegisters into the additive `conversation.view` slot — the conversation view\nring — so it appears as its **own tab beside Chat and Trajectory** (`order: 20`,\nafter chat at `0` and trajectory at `10`) and fills the session pane when\nselected.\n\nA **sprint/roadmap task list**, not just a checklist: each task carries a status,\na priority, and optional release and sprint labels, so a real backlog can live\nnext to the code it describes.\n\n## Features\n\n- **Persisted on disk by the host** — one SQLite database per project at\n  `<workspace>/.dsh/todo.db`, not in the browser. It survives a restart, a\n  cleared browser cache, and a different browser entirely, and it travels with\n  the project.\n- **Per-workspace** — each workspace has its own list, keyed by workspace id.\n- **Safe against races** — every write carries the revision it observed; a\n  losing write is refused and the view adopts the authoritative list, so two\n  open tabs can never silently clobber each other.\n- **Real workflow states** — `backlog · todo · in-progress · blocked · done`,\n  changed from a pill on the row. A boolean cannot express the two things a\n  standup actually asks about: what is moving, and what is stuck.\n- **Priority** — `P0`–`P3`, shown as a chip. Only P0/P1 are coloured, so the\n  list flags what is urgent instead of turning into a rainbow.\n- **Release and sprint** — two independent numeric labels: what ships\n  together (`1.5`, `0.5.1`) and when it is worked (`24`). A task can be in\n  both. A **release** takes up to three numbers, so a patch release has a label\n  of its own; a **sprint** is a single decimal. Never alpha (`v1.5` is\n  refused), so labels sort by version — `1.10` above `1.9`, `0.5.1` above\n  `0.5`. The inputs accept only digits and a dot as you type; a value that is\n  still not a valid label is flagged with an inline error and never saved.\n- **Group by** — None · Status · Release · Sprint · Priority, with collapsible\n  section headers carrying their own `done/total` and progress bar. Grouping by\n  status gives you a kanban board without drag-and-drop.\n- **Task detail modal** — click a task's title to open the full dialog: a\n  roomy description box plus status, priority, release, sprint and due date.\n  Focus is trapped inside and returned to the row you came from, and text edits\n  commit on close so a stray click never loses them. **Done is the save**: it is\n  the only control that refuses to proceed while a release or sprint is invalid.\n  Esc, the backdrop and the X always let you out, discarding an unsaved bad\n  label rather than trapping you in the dialog.\n- **Expandable rows** — the chevron still gives a quick in-row peek without\n  leaving the list. Double-click a title to rename it inline. One scannable line\n  collapsed is what lets a task carry nine fields without becoming a wall of text.\n- **Due dates** — stored as calendar days, so \"due the 14th\" reads as the 14th\n  in every timezone. Overdue tasks are flagged red on the row, due-today amber,\n  and a finished task is never overdue.\n- **Own tab** — full-pane view with a progress header and `done/total` score,\n  plus live in-progress and blocked counts.\n- **Filter ring** — All · Open · In Progress · Blocked · Backlog · Done ·\n  Archive, with live counts; empty states are hidden rather than shown at zero.\n- **Archive, not delete** — check items off, then \"Archive completed\" files them\n  away. Archived items leave every active view but stay in the record, and can be\n  restored (↩) or permanently deleted from the Archive view.\n- **Full editing** — add, check off, click-to-edit the title, edit the\n  description and labels, reorder (▲/▼), archive, and delete. Release and sprint\n  inputs suggest labels already in use, so values converge on a shared\n  vocabulary without a releases table to administer.\n- **Suggest** — a button in the tab header scans the workspace and proposes\n  concrete next tasks: unresolved `TODO`/`FIXME`/`HACK` comments, features the\n  docs promise but the code does not implement, and modules with no tests. Each\n  proposal comes with a one-line rationale, a priority, and a `file:line`\n  pointer where one exists. Tick the ones you want and **Add selected** files\n  them into the backlog. Never automatic — it runs only when you click it.\n- **Themed** — colors come only from the shell's `--dsw-*` tokens, so it follows\n  light/dark automatically. Respects `prefers-reduced-motion`.\n\n## Architecture\n\nThis is a **dual-face plugin**. Both halves ship from one package.\n\n| Half | File | Role |\n| --- | --- | --- |\n| Host | `src/index.ts` | `TodoService`, a `TypertRemoteService` that owns the per-workspace SQLite database and exports `list` / `replace` as `@Remote` methods. |\n| Client | `src/client.tsx` | The React tab. Mounts the host contract and calls it as `ctx.remote.dshTodo.*`. |\n| Bridge | `src/remote.ts` | The Typert Remote descriptor the client mounts. |\n| Shared | `src/types.ts` | Dependency-free vocabulary used by both halves. |\n\nThe browser holds no authority over the data: it renders an optimistic echo and\nthe committed host revision always wins.\n\n### Two build constraints that are easy to break\n\nBoth are asserted by the smoke test, because both fail silently at runtime:\n\n1. **The host half must not be minified.** The Typert gateway discovers a\n   `@Remote` method's wire fields by reading its *parameter names* out of\n   `Function.prototype.toString()`. Minifying `request` to `e` changes the wire\n   contract.\n2. **The host half must target `es2021`.** `@Remote` is a TC39 *standard*\n   decorator, and Node 22 cannot yet parse native decorator syntax. esbuild only\n   downlevels decorators when the target predates them; at `es2022+` it emits\n   them verbatim and the host half fails to load.\n\n### Peer dependencies, not dependencies\n\n`@deepseek-ai/cordis`, `dsh-typert-protocol`, and `dsh-storage-domain` are\ndeclared as **peer** dependencies and marked external in the host build. They\nmust resolve to the *running dsh install's* copies — a second cordis instance\nwould register into a different registry and the service would never appear.\ndsh profiles set `autoInstallPeers: false`, so this resolves correctly.\n\n## Commands\n\n```bash\npnpm install\npnpm run build      # node build/build.mjs — emits lib/index.js + lib/client.js\npnpm run typecheck  # tsc --noEmit\npnpm test                # offline: client + CLI, exercising the BUILT lib/ output\npnpm run test:cli        # just the in-process CLI suite\npnpm run test:integration # spawns the real bin — one full agent workflow\npnpm run test:icons      # headless Chrome: icon sizes and the 40px row budget\npnpm run test:modal      # headless Chrome: the dialog escapes the list's scroll container\npnpm run test:agent      # OPT-IN: a real model drives the CLI (needs a key; costs tokens)\n```\n\n`pnpm test` asserts against `lib/`, so **build before testing** (the script rebuilds first).\n\nThe CLI has two layers on purpose. `test/cli.test.mjs` calls into `lib/cli.js` in-process;\n`test/cli-integration.mjs` **spawns the real binary** for one realistic agent workflow — plan a\nrelease, inspect it, hit a refusal, recover from the payload alone, finish and archive — because\nthe in-process suite cannot see the shebang'd entry point, `process.exitCode`, the stdout/stderr\nsplit, or argv as a shell delivers it.\n\n`pnpm run test:agent` is the odd one out and is **not** part of `pnpm test`: it hands a real\nmodel nothing but the binary path and a goal, then asserts on the resulting database rather than\non anything the model said. It answers a question no offline test can — is `help` enough to\ndrive this thing, and is a refusal message enough to recover from? It needs `DEEPSEEK_API_KEY`\nexported (it runs the harness in a throwaway `DSH_HOME`, which has no stored credentials).\n\n## Install into a dsh profile\n\nThe profile must already compose the workspace registry, which `@deepseek-ai/dsh-web-app`\ndoes by default.\n\n```bash\ncd ~/.dsh/profiles/<profile>\npnpm add \"file:/absolute/path/to/dsh-plugins/plugins/dsh-todo\"\n```\n\nthen add the row to `cordis.patch.yml`:\n\n```yaml\n- insert:\n    - id: dsh-todo\n      name: '@dennisrongo/dsh-todo'\n```\n\nand restart the profile. The single row mounts both halves: the host service\nand the browser tab.\n\n> The profile installs `file:` dependencies as a **copy**, not a symlink, so\n> after `pnpm run build` you must re-run `pnpm install` in the profile to pick\n> up the new artifacts.\n\n## Archiving\n\nCompleted work is **archived, not deleted**. An item carries an optional\n`archivedAt` epoch-ms stamp; its *presence* is the archived state, so there is\none source of truth and no way to store an archived item without a date.\n\n| Action | Where | Effect |\n| --- | --- | --- |\n| Archive completed | footer, any active view | Stamps every done item. Recoverable. |\n| Archive (⌸) | row hover, completed items | Stamps one item. Recoverable. |\n| Restore (↩) | row hover, Archive view | Clears the stamp, returning it to the list. |\n| Delete (✕) | row hover | Removes one item outright, after a confirmation dialog naming the task. |\n| Delete archived | footer, Archive view | Permanently drops every archived item — the only destructive bulk action, and the only one that asks for confirmation. |\n\nArchived items are excluded from the progress bar and the done/total score, so\ntidying up never makes progress appear to regress. They sort newest-archived\nfirst, so the Archive view reads as a log. Reordering is computed in\nactive-list space, so a hidden archived entry between two visible rows cannot\nswallow a move.\n\n`clearCompleted` (hard delete of done items) is still exported for callers that\nwant it, but it is no longer wired to a button.\n\n## Suggest — what to work on next\n\nThe list holds work someone already thought of. Deciding what to do *next*\nusually happens somewhere else — reading the code and noticing what is missing.\n**Suggest**, in the tab header, moves that into the tab.\n\nClicking it reads the workspace and proposes concrete tasks from three kinds of\nevidence:\n\n- **Unresolved comments** — `TODO`, `FIXME` and `HACK`, with the file and line.\n- **Docs-vs-implementation gaps** — the README and the file tree together, so\n  what is promised but absent has somewhere to show up.\n- **Untested modules** — source files with no matching test file. A name-based\n  hint rather than a coverage run, so it is offered as a hint.\n\nEach suggestion arrives as a checkbox row: a title, a one-line rationale, a\npriority, and a `file:line` pointer where there is one to give. Nothing is\nticked by default — you opted into scanning, not into the results. **Add\nselected** writes the ticked rows into the backlog as real tasks, with the\nrationale as the description. Until then they are **proposals**: nothing is\nstored, and closing the dialog discards them.\n\n**Refresh returns genuinely new ideas, not a reshuffle.** Every title already\nshown joins the exclusion set, alongside every unfinished task already in the\nbacklog, so the scan is told what not to repeat. Rows you have already ticked\nsurvive a refresh — the selection is yours, not the model's.\n\n> **A scan spends tokens.** It runs a real model session in the background —\n> created, prompted, and archived when the scan finishes or you close the\n> dialog; it never appears in the sidebar and is never navigated to. Nothing is\n> scheduled and nothing is automatic: a scan happens when you click **Suggest**\n> or **Refresh**, and only then.\n\nWhat is sent is a **bounded digest**, not the repository: a capped file tree, a\ncapped list of comment matches one line each, and a leading slice of the README\nand `package.json`. Vendored and generated directories (`node_modules`, `lib`,\n`dist`, `vendor`, `target` and the rest) never enter it. Anything left out is\nmarked in the digest rather than dropped quietly, so a big repository yields a\nsmaller scan rather than a confident one about code it never read.\n\n## CLI — for you and for AI agents\n\nThe same list is reachable from a terminal, so an agent can shell out and manage your tasks\n(and so can you). It targets a workspace **directory** and needs no profile, no session and\nno running server — it works offline and in CI.\n\n### Getting the command\n\nThe plugin ships a `dsh-todo` binary. If the package is already installed into a dsh\nprofile, that profile's `node_modules/.bin` has it; otherwise reach it directly:\n\n```bash\nnpx @dennisrongo/dsh-todo list          # no install\npnpm add -g @dennisrongo/dsh-todo       # then just: dsh-todo list\nnode /path/to/plugins/dsh-todo/lib/bin.js list   # from a checkout\n```\n\nRequires **Node 22+** — storage is `node:sqlite`, which is built in (and still prints an\nexperimental-feature warning on stderr; it is harmless, and `2>/dev/null` silences it).\n\n### Everyday use\n\n```bash\ncd ~/projects/my-app          # the workspace IS the current directory\n\ndsh-todo add \"Fix token refresh\" --priority p0 --release 1.5 --due 2026-03-14\ndsh-todo add \"Write migration guide\" --sprint 24\ndsh-todo list\n```\n\n```text\n[ ] tmtcfbutukp4j todo        p0 Fix token refresh  (release=1.5 due=2026-03-14)\n[ ] tmtcfbuxr5y9x todo        p2 Write migration guide  (sprint=24)\n[ ] tmtcfbv071e6w in-progress p2 Ship it\n```\n\nOne task per line: checkbox, id, status, priority, title, then any labels in parentheses.\nThat is the whole display contract — it stays greppable and diffable.\n\nMove work along, then file it away:\n\n```bash\ndsh-todo update tmtcfbut --status in-progress --sprint 24\ndsh-todo show tmtcfbut                  # everything about one task\ndsh-todo done tmtcfbut\ndsh-todo archive                        # archive EVERY completed task\n```\n\nWork on a project you are not `cd`'d into with `--workspace`:\n\n```bash\ndsh-todo --workspace ~/projects/other list --open\n```\n\n### Commands\n\n| Command | Does |\n| --- | --- |\n| `list` | Show tasks — active only unless `--archived` |\n| `add <title>` | Create a task; every field flag is accepted |\n| `update <id>` | Change one or more fields; needs at least one |\n| `done` / `reopen` | Flip completion, stamping or clearing `completedAt` to match |\n| `rm <id>` | Delete outright — no confirmation, no archive |\n| `archive [<id>]` | Archive one task, or every completed one when no id is given |\n| `show <id>` | Print one task in full, including description and timestamps |\n| `help` | The same reference, in the terminal |\n\n### Options\n\n| Option | Applies to | Notes |\n| --- | --- | --- |\n| `--workspace <dir>` | all | Workspace directory. Defaults to cwd, and is used **as given** — no upward search for a `.dsh`, so an agent in a subdirectory targets the project it was pointed at. |\n| `--json` | all | Machine-readable output, **including on errors** |\n| `--status <s>` | add, update, list | `backlog` · `todo` · `in-progress` · `blocked` · `done` |\n| `--priority <p>` | add, update, list | `p0`–`p3` (default `p2`) |\n| `--release <n[.n[.n]]>` | add, update, list | Numbers only, up to three: `1`, `1.5`, `0.5.1`; `v1.5` is refused |\n| `--sprint <n[.n]>` | add, update, list | Numbers only, one dot at most: `24`, `1.5`; `0.5.1` is refused |\n| `--due <YYYY-MM-DD>` | add, update | A calendar day; impossible dates are refused |\n| `--description <text>` | add, update | Body text — acceptance criteria, repro steps |\n| `--title <text>` | update | Rename |\n| `--open` | list | Everything unfinished, whatever stage |\n| `--archived` | list | Show archived tasks *instead of* active ones |\n\nFilters combine, so `list --open --priority p0 --release 1.5` is an AND across all three.\n`--key value` and `--key=value` are both accepted.\n\n### Driving it from a script or an agent\n\n**`--json` is the one to use from a script.** It prints structured output on the error path\ntoo, so a caller never has to parse a human sentence to find out what went wrong:\n\n```bash\ndsh-todo list --open --json\n```\n\n```json\n{\n  \"ok\": true,\n  \"count\": 3,\n  \"items\": [\n    {\n      \"id\": \"tmtcfbutukp4j\",\n      \"title\": \"Fix token refresh\",\n      \"status\": \"todo\",\n      \"priority\": \"p0\",\n      \"release\": \"1.5\",\n      \"dueDate\": \"2026-03-14\",\n      \"createdAt\": 1787889639378\n    }\n  ]\n}\n```\n\n**Every payload leads with `ok`**, so a caller never has to infer the verdict from the\nshape of what came back. On success `ok` is `true` and the command's own keys follow:\n`list` adds `{ count, items }`; `add` / `update` / `done` / `reopen` / `rm` add\n`{ item, revision }` — the stored task, so a write can be confirmed without a second\ncall; `archive` adds `{ archived, revision }`; `show` adds the task itself.\n\nA failure returns `ok: false` with `error` and `code`, and exits with that code:\n\n```bash\n$ dsh-todo update nope --status done --json; echo \"exit=$?\"\n{\n  \"ok\": false,\n  \"error\": \"no task matching \\\"nope\\\"\",\n  \"code\": 3\n}\nexit=3\n```\n\nA **refused value** says which field it refused, what that field accepts, and what it was\ngiven — enough for an agent to correct itself without parsing the sentence. Nothing is\nwritten when a value is refused:\n\n```bash\n$ dsh-todo add \"Ship it\" --release v1.5 --json; echo \"exit=$?\"\n{\n  \"ok\": false,\n  \"error\": \"--release must be a version number like 1.5 or 0.5.1 (up to three numbers) (got \\\"v1.5\\\") — nothing was saved\",\n  \"code\": 2,\n  \"field\": \"release\",\n  \"expected\": \"a version number like 1.5 or 0.5.1 (up to three numbers)\",\n  \"got\": \"v1.5\"\n}\nexit=2\n```\n\nExit codes are distinct so a script can branch on **why** a command failed:\n\n| Code | Means |\n| --- | --- |\n| `0` | Success |\n| `2` | Usage — unknown command, bad flag, malformed value |\n| `3` | Not found — a well-formed request that matched no task |\n\nPiping into `jq` covers most agent work:\n\n```bash\n# ids of everything blocked\ndsh-todo list --status blocked --json | jq -r '.items[].id'\n\n# fail CI if any P0 is still open\ntest \"$(dsh-todo list --open --priority p0 --json | jq '.count')\" -eq 0\n```\n\nIds accept any **unambiguous prefix** — `dsh-todo done tmtcfbut`. Ids are time-ordered so\nshort prefixes collide; an ambiguous one is an **error listing the candidates** rather than a\nguess at which task you meant.\n\nAn **empty value clears a field**: `--release \"\"` removes the release. From a shell there is\nno other way to say \"unset this\" as opposed to \"leave it alone\".\n\n> **PowerShell drops empty arguments.** `--release \"\"` arrives at Node as a bare `--release`\n> flag, so the field is left untouched instead of cleared. Use the `--release=` form there,\n> which survives intact on every shell.\n\nInvalid values are **refused, never dropped** — `--due 2026-02-31` exits `2` instead of\nquietly storing nothing, because an agent would otherwise never learn its date was ignored.\n\n### Is it safe alongside the running app?\n\nYes, and it is tested. SQLite is a multi-process database: the file lock refuses a writer that\nlands inside another process's transaction rather than letting it interleave, and the CLI sets\na `busy_timeout` so it waits for the harness to commit instead of failing. Verified live — the\nCLI wrote while a running server held its handle, and the API returned the new task with no\nrestart.\n\nThe one visible effect is that an **already-open browser tab** may need a refresh: every write\nbumps a revision token, so the tab's next write is refused and it adopts the authoritative\nlist. That is the designed reconciliation, not lost data.\n\n## The task model\n\n```ts\n{ id, title, description?, status, priority, release?, sprint?, dueDate?,\n  createdAt, completedAt?, archivedAt? }\n```\n\n| Field | Notes |\n| --- | --- |\n| `title` | Short and scannable — the one line a collapsed row shows. Capped at 500. |\n| `description` | The body: acceptance criteria, repro steps, links. Its own 5000 cap, because reusing the title's 500 would silently truncate real notes. |\n| `status` | `backlog \\| todo \\| in-progress \\| blocked \\| done`. **The source of truth** — there is no separate `done` flag to fall out of sync. |\n| `priority` | `p0`–`p3`, default `p2` so an unranked task sits mid-pile rather than jumping the queue. |\n| `release` | What ships together, e.g. `1.5` or `0.5.1`. One to three numbers. |\n| `sprint` | When it is worked, e.g. `24`. A single decimal — no patch segment. |\n| `dueDate` | `YYYY-MM-DD`. A calendar day, not an instant — an epoch would bind it to a timezone and let one task read as two different days. Impossible dates like `2025-02-31` are rejected rather than rolled forward. |\n\n**Release and sprint are separate on purpose.** A task can be worked in sprint 24\nand ship in 1.3; collapsing them into one field loses the ability to answer\neither question. Both are **numeric labels** rather than entities, refused at\nevery write path — CLI and UI alike — if they are anything else, so grouping and\nfiltering work with no releases table, no CRUD, and no migration to rename one.\n\nThe two shapes differ, because the fields mean different things:\n\n| Field | Pattern | Passes | Refused |\n| --- | --- | --- | --- |\n| `release` | `^\\d+(\\.\\d+){0,2}$` | `1`, `1.5`, `0.5.1` | `v1.5`, `1.2.3.4`, `1.` |\n| `sprint` | `^\\d+(\\.\\d+)?$` | `1`, `1.5`, `24` | `Sprint 24`, `0.5.1` |\n\nA release carries a **patch segment** so a fix shipping on top of 0.5 gets its own\nlabel; a sprint is a point on a calendar, not a shipped artefact, so it takes none.\nBeing numeric means labels sort by **version semantics** — compared segment by\nsegment, so `1.10` ranks above `1.9` and `0.5.1` sits between `0.5` and `0.6`.\nLabels stored before the rule still load, group, and display unchanged.\n\n`completedAt` is written only by the status transition, so it can never claim a\ntask is finished that isn't. Absent optional fields are absent *keys*, never\n`''`, so \"no release\" has exactly one representation.\n\n## Storage\n\n| Location | Contents |\n| --- | --- |\n| `<workspace>/.dsh/todo.db` | SQLite: one `todo` row per task, plus a `meta` table holding `revision` and `updatedAt`. |\n\nArchived items live in the same table — archiving never moves data between\ncollections, so nothing can be lost in a partial write.\n\n### Upgrading from the checklist version\n\nExisting databases are migrated **in place** on first open: the new columns are\nadded with `ALTER TABLE`, `title` is backfilled from the old `text`, and\n`done = 1` becomes `status = 'done'`. Nothing is dropped, and a list written by\nthe old version keeps its order, its completion stamps and its archive.\n\nThe old `text`/`done` columns are still written alongside their replacements, so\ndowngrading to the previous version still reads a sane list.\n\n### Migration from the old browser-only version\n\nEarlier versions stored todos in `localStorage` under `dsh-todo:items`. On first\nrun, that list is imported **once** into the first workspace that opens with an\nempty stored list, and the import is then marked with `dsh-todo:migrated`. The\noriginal key is deliberately left in place rather than deleted.\n\n## Notes\n\n- The host half publishes a service, so it belongs to the profile's host\n  composition — not to an agent preset.\n","readmeFilename":"README.md"}