{"_id":"@argszero/cordis-plugin-schedule-cron","_rev":"4-0b26e4e2b0d86d225bf1d65d7152abf2","name":"@argszero/cordis-plugin-schedule-cron","dist-tags":{"next":"0.1.0","latest":"0.1.2"},"versions":{"0.1.0":{"name":"@argszero/cordis-plugin-schedule-cron","version":"0.1.0","keywords":["deepseek","dsh","cordis","plugin","schedule","cron","task-runner","autonomous","scheduler"],"license":"MIT","_id":"@argszero/cordis-plugin-schedule-cron@0.1.0","maintainers":[{"name":"argszero","email":"argszero.reg@gmail.com"}],"homepage":"https://github.com/argszero/cordis-plugin-schedule-cron#readme","bugs":{"url":"https://github.com/argszero/cordis-plugin-schedule-cron/issues"},"dist":{"shasum":"d0b73179912441afefe402350727bea118eae9f4","tarball":"https://registry.npmjs.org/@argszero/cordis-plugin-schedule-cron/-/cordis-plugin-schedule-cron-0.1.0.tgz","fileCount":15,"integrity":"sha512-aYtCRyKFFmLSVuS3XIeD8hvUa8uPMGAneIevm3k0ZpTv899j2Qq0xTiTSzXX0ZPq3GlxEkGP/ZOs7aAaAeYw3w==","signatures":[{"sig":"MEQCIAhu4iWuTq7YDsCGB9gvNSQ8LkEh6r7EbKsjLzFt5SUiAiAV4Q8gxqwlJyjVUqdTdxbJxONzQ+nYyeAiW8xZtxjAzQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":32568},"main":"lib/index.js","type":"module","types":"lib/index.d.ts","engines":{"node":"^22.19 || >=24"},"exports":{".":{"types":"./lib/index.d.ts","default":"./lib/index.js"}},"gitHead":"444974a39f2dabf2dd18e0920c8524307502b40c","scripts":{"test":"node test/logic.test.mjs","build":"tsc -p .","prepack":"tsc -p ."},"_npmUser":{"name":"argszero","email":"argszero.reg@gmail.com"},"repository":{"url":"git+https://github.com/argszero/cordis-plugin-schedule-cron.git","type":"git"},"_npmVersion":"11.17.0","description":"Cron-driven autonomous task runs for the dsh harness: fire a calendar cron rule and spawn a fresh agent run via ctx.agents.create(), unlike the official @deepseek-ai/dsh-schedule which only messages the live session.","directories":{},"_nodeVersion":"26.5.0","dependencies":{"croner":"^10.0.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^7.0.2","@types/node":"^26.4.1","@deepseek-ai/cordis":">=4.0.1-rc.4","@deepseek-ai/dsh-llm":"0.1.2-rc.1","@deepseek-ai/dsh-agent":"0.1.2-rc.1","@deepseek-ai/dsh-brand":"0.1.2-rc.1","@deepseek-ai/dsh-tools":"0.1.2-rc.1","@deepseek-ai/dsh-session":"0.1.2-rc.1"},"peerDependencies":{"@deepseek-ai/cordis":">=4.0.0 <5","@deepseek-ai/dsh-llm":">=0.1.0","@deepseek-ai/dsh-agent":">=0.1.0","@deepseek-ai/dsh-brand":">=0.1.0","@deepseek-ai/dsh-tools":">=0.1.0","@deepseek-ai/dsh-session":">=0.1.0"},"_npmOperationalInternal":{"tmp":"tmp/cordis-plugin-schedule-cron_0.1.0_1788529037853_0.6339871675885826","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@argszero/cordis-plugin-schedule-cron","version":"0.1.1","keywords":["deepseek","dsh","cordis","plugin","schedule","cron","task-runner","autonomous","scheduler"],"license":"MIT","_id":"@argszero/cordis-plugin-schedule-cron@0.1.1","maintainers":[{"name":"argszero","email":"argszero.reg@gmail.com"}],"homepage":"https://github.com/argszero/cordis-plugin-schedule-cron#readme","bugs":{"url":"https://github.com/argszero/cordis-plugin-schedule-cron/issues"},"dist":{"shasum":"fd8cf98d5ccecdd93dd00f3ba45fd975e40aefa1","tarball":"https://registry.npmjs.org/@argszero/cordis-plugin-schedule-cron/-/cordis-plugin-schedule-cron-0.1.1.tgz","fileCount":15,"integrity":"sha512-WkC1ruBnTFxpeYmo8kJPMw2rq1p7f+bjKzJ/rLRsnPvJxnLDlxaURg+6i4llLPu2ZcUWpXaUcz09e/aEKdTsMA==","signatures":[{"sig":"MEYCIQDBW15axWbS6Onc/it9SD0WLhzp4Hi51dw9AhnDseTRFQIhALCLDbmwt8SVAd+JUzZOCQj+2N+30Y4FYm/D6Vu8tsOe","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIQDu4J3Z8YelhLF43cHrzzY/gnprwMpgIPF2l8gsms29TgIgZ1IwKztFbl1n2wNtpsb6Tdpg+1osT/QiSbTcVZCapZo=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":33662},"main":"lib/index.js","type":"module","types":"lib/index.d.ts","engines":{"node":"^22.19 || >=24"},"exports":{".":{"types":"./lib/index.d.ts","default":"./lib/index.js"}},"gitHead":"fa266a7ed2065fa9157d4fc66c7bab617072ca07","scripts":{"test":"node test/logic.test.mjs && node --test \"test/*.test.mjs\"","build":"tsc -p .","prepack":"tsc -p ."},"_npmUser":{"name":"argszero","email":"argszero.reg@gmail.com"},"repository":{"url":"git+https://github.com/argszero/cordis-plugin-schedule-cron.git","type":"git"},"_npmVersion":"11.17.0","description":"Cron-driven autonomous task runs for the dsh harness: fire a calendar cron rule and spawn a fresh agent run via ctx.agents.create(), unlike the official @deepseek-ai/dsh-schedule which only messages the live session.","directories":{},"_nodeVersion":"26.5.0","dependencies":{"croner":"^10.0.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^7.0.2","@types/node":"^26.4.1","@deepseek-ai/cordis":">=4.0.1-rc.4","@deepseek-ai/dsh-llm":"0.1.2-rc.1","@deepseek-ai/dsh-agent":"0.1.2-rc.1","@deepseek-ai/dsh-brand":"0.1.2-rc.1","@deepseek-ai/dsh-tools":"0.1.2-rc.1","@deepseek-ai/dsh-session":"0.1.2-rc.1"},"peerDependencies":{"@deepseek-ai/cordis":">=4.0.0 <5","@deepseek-ai/dsh-llm":">=0.1.2-rc.1 <0.2.0 || >=0.1.5-alpha.1 <0.2.0","@deepseek-ai/dsh-agent":">=0.1.2-rc.1 <0.2.0 || >=0.1.5-alpha.1 <0.2.0","@deepseek-ai/dsh-brand":">=0.1.2-rc.1 <0.2.0 || >=0.1.5-alpha.1 <0.2.0","@deepseek-ai/dsh-tools":">=0.1.2-rc.1 <0.2.0 || >=0.1.5-alpha.1 <0.2.0","@deepseek-ai/dsh-session":">=0.1.2-rc.1 <0.2.0 || >=0.1.5-alpha.1 <0.2.0"},"_npmOperationalInternal":{"tmp":"tmp/cordis-plugin-schedule-cron_0.1.1_1789010746007_0.07843472001026464","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"_id":"@argszero/cordis-plugin-schedule-cron@0.1.2","bugs":{"url":"https://github.com/argszero/cordis-plugin-schedule-cron/issues"},"dist":{"shasum":"4d1aaa30805a21d4fe9d45de310814fe145fc967","tarball":"https://registry.npmjs.org/@argszero/cordis-plugin-schedule-cron/-/cordis-plugin-schedule-cron-0.1.2.tgz","fileCount":15,"integrity":"sha512-3IgcxtYQxk03Uj6Svv3iDg9KMEU6SryPdFn92m97AOvDWnpOtLF5eU5bAL2OTZ0I5azhgFmhD4OqO5QiGpupTQ==","signatures":[{"sig":"MEYCIQDTOT4T5DqS6TLiUcAR5nUT7AsXq2pt87q9hBxA2TL0NQIhAKD9pxxq5SUrYV2FctEuiFDREoSqS9IO9XXa6I+gJ6bW","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCtV7KhODE03QoHu7tmUm33ma0zqq7L4pMrH8W2GzmWCwIhANtpY6O+D5dlp+R4gg9azfd+yxpAP5Kr683+x4YRSYGw"}],"unpackedSize":35902},"main":"lib/index.js","name":"@argszero/cordis-plugin-schedule-cron","type":"module","types":"lib/index.d.ts","engines":{"node":"^22.19 || >=24"},"exports":{".":{"types":"./lib/index.d.ts","default":"./lib/index.js"}},"gitHead":"2cffe130a438e8e6a186ec0d8eca7f4c5f91bcc4","license":"MIT","scripts":{"test":"node test/logic.test.mjs && node --test \"test/*.test.mjs\"","build":"tsc -p .","prepack":"tsc -p ."},"version":"0.1.2","_npmUser":{"name":"argszero","email":"argszero.reg@gmail.com"},"homepage":"https://github.com/argszero/cordis-plugin-schedule-cron#readme","keywords":["deepseek","dsh","cordis","plugin","schedule","cron","task-runner","autonomous","scheduler"],"repository":{"url":"git+https://github.com/argszero/cordis-plugin-schedule-cron.git","type":"git"},"_npmVersion":"11.17.0","description":"Cron-driven autonomous task runs for the dsh harness: fire a calendar cron rule and spawn a fresh agent run via ctx.agents.create(), unlike the official @deepseek-ai/dsh-schedule which only messages the live session.","directories":{},"maintainers":[{"name":"argszero","email":"argszero.reg@gmail.com"}],"_nodeVersion":"26.5.0","dependencies":{"croner":"^10.0.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"semver":"^7.6.0","typescript":"^7.0.2","@types/node":"^26.4.1","@deepseek-ai/cordis":">=4.0.1-rc.4","@deepseek-ai/dsh-llm":"0.1.6-alpha.2","@deepseek-ai/dsh-agent":"0.1.6-alpha.2","@deepseek-ai/dsh-brand":"0.1.6-alpha.2","@deepseek-ai/dsh-tools":"0.1.6-alpha.2","@deepseek-ai/dsh-session":"0.1.6-alpha.2"},"peerDependencies":{"@deepseek-ai/cordis":">=4.0.0 <5","@deepseek-ai/dsh-llm":">=0.1.2-rc.1 <0.1.3 || >=0.1.3-alpha.2 <0.1.4 || >=0.1.5-alpha.1 <0.2.0 || >=0.1.6-alpha.1 <0.2.0","@deepseek-ai/dsh-agent":">=0.1.2-rc.1 <0.1.3 || >=0.1.3-alpha.2 <0.1.4 || >=0.1.5-alpha.1 <0.2.0 || >=0.1.6-alpha.1 <0.2.0","@deepseek-ai/dsh-brand":">=0.1.2-rc.1 <0.1.3 || >=0.1.3-alpha.2 <0.1.4 || >=0.1.5-alpha.1 <0.2.0 || >=0.1.6-alpha.1 <0.2.0","@deepseek-ai/dsh-tools":">=0.1.2-rc.1 <0.1.3 || >=0.1.3-alpha.2 <0.1.4 || >=0.1.5-alpha.1 <0.2.0 || >=0.1.6-alpha.1 <0.2.0","@deepseek-ai/dsh-session":">=0.1.2-rc.1 <0.1.3 || >=0.1.3-alpha.2 <0.1.4 || >=0.1.5-alpha.1 <0.2.0 || >=0.1.6-alpha.1 <0.2.0"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/cordis-plugin-schedule-cron_0.1.2_1789715567899_0.8736491690130088"}}},"time":{"created":"2026-09-04T13:37:17.652Z","modified":"2026-09-18T07:12:48.128Z","0.1.0":"2026-09-04T13:37:17.972Z","0.1.1":"2026-09-10T03:25:46.104Z","0.1.2":"2026-09-18T07:12:47.987Z"},"bugs":{"url":"https://github.com/argszero/cordis-plugin-schedule-cron/issues"},"license":"MIT","homepage":"https://github.com/argszero/cordis-plugin-schedule-cron#readme","keywords":["deepseek","dsh","cordis","plugin","schedule","cron","task-runner","autonomous","scheduler"],"repository":{"url":"git+https://github.com/argszero/cordis-plugin-schedule-cron.git","type":"git"},"description":"Cron-driven autonomous task runs for the dsh harness: fire a calendar cron rule and spawn a fresh agent run via ctx.agents.create(), unlike the official @deepseek-ai/dsh-schedule which only messages the live session.","maintainers":[{"name":"argszero","email":"argszero.reg@gmail.com"}],"readme":"# @argszero/cordis-plugin-schedule-cron\n\nCron-driven **autonomous task runs** for the deepseek-harness (`dsh`) agent.\n\nUnlike the official [`@deepseek-ai/dsh-schedule`](https://www.npmjs.com/package/@deepseek-ai/dsh-schedule) — which only **messages the live session** (a follow-up delivered into whatever agent is already running and idle) — this plugin **spawns a fresh agent run** when a calendar fire occurs, so scheduled work actually happens even with no browser session open. It is the \"EMRG-style\" scheduled-task runner: a cron calendar rule awakens a brand-new agent turn.\n\n## Why this exists\n\n`dsh-schedule` explicitly documents the gap:\n\n> \"当交付必须到达会话之外时请避开它...或者当你需要**「每个工作日 9 点」这类日历规则**时：重复提醒**只按固定间隔运行**。\"\n\nThat is, it has:\n- **No calendar rules** — only `after_seconds` / `at` / `every_seconds` fixed intervals.\n- **No autonomous drive** — it delivers into a live session; closed/cold sessions just leave the reminder overdue.\n\n`dsh-cron` fills both: standard 5-field cron calendar rules and a fresh agent run per fire.\n\n## Install\n\n```sh\nnpm install @argszero/cordis-plugin-schedule-cron\n```\n\nThen mount it into your `dsh` profile (a Cordis overlay). For example:\n\n```yaml\n# cordis.yml fragment\nplugins:\n  schedule-cron:\n    cron:\n      - id: daily-triage\n        expression: \"0 9 * * 1-5\"          # 09:00 Mon–Fri\n        task: \"Review the open issues in this repo and summarize anything urgent.\"\n      - id: weekly-report\n        expression: \"0 8 * * 1\"             # 08:00 Monday\n        task: \"Write this week's status report.\"\n        provider: deepseek\n        model: deepseek-chat\n        cwd: /path/to/workspace\n    tickMs: 60000\n```\n\n## How it works\n\nOn a tick (`tickMs`, default `60_000`), the plugin checks each rule. When a rule is due:\n\n1. `ctx.agents.create({ sessionId, meta, agentOptions })` composes a **fresh agent** (a brand new session) — the same primitive the ACP bridge uses for non-interactive sessions.\n2. `agent.followup(createUserMessage({ content: [{ type: 'text', text: task }], source: { kind: 'plugin', plugin: 'schedule-cron' } }))` drives its first turn **autonomously**.\n\nThe fire uses a **monotonic per-rule cursor** (`croner`), so:\n- Each occurrence fires exactly once.\n- On first mount, every cursor anchors to its **next future** occurrence (no backfill burst for past times).\n- A long-downed schedule is capped at `MAX_CATCH_UP_PER_TICK = 4` fires per tick (no burst).\n- Disabled rules (`enabled: false`) are parsed but never fired.\n\nA rule's state is recoverable across a restart via `initialState` (`lastFiredAt` per rule id), so a process restart mid-window resumes forward instead of re-firing.\n\n## API\n\n### Config\n\n| Field | Type | Default | Description |\n|-------|------|---------|-------------|\n| `cron` | `CronRule[]` | `[]` | The rules to fire. |\n| `tickMs` | number | `60000` | How often (ms) to check for due rules. |\n| `initialState` | `CronRuleState[]` | `[]` | Restore `lastFiredAt` baselines across a restart. |\n\n### `CronRule`\n\n| Field | Type | Description |\n|-------|------|-------------|\n| `id` | string | Stable persistence key (defaults to `expr:<expr>`). |\n| `expression` | `string \\| string[]` | 5-field cron; an array acts as alternatives. |\n| `task` | string | Prompt delivered as the spawned agent's first turn. |\n| `provider` | string | Provider route (defaults to harness default). |\n| `model` | string | Model id (defaults to harness default). |\n| `cwd` | string | Working dir for the spawned agent (defaults to harness default). |\n| `enabled` | boolean | `true` if the rule should fire (defaults true). |\n\n### Engine (pure, no harness needed)\n\n```ts\nimport { collectDue, initialCursor, resumeCursor, ruleIdOf, normalizeExpression } from '@argszero/cordis-plugin-schedule-cron'\n```\n\nThe `collectDue(cursors, now)` function is dependency-free and unit-tested, so it can be driven by any timer (not just Cordis).\n\n## Development\n\n```sh\nnpm install\nnpm run build   # tsc emits lib/\nnpm test        # node test/logic.test.mjs (needs build first)\n```\n\n### A note on the peer range\n\nThis package declares every dsh package it reads as a peer, all with the same\nrange:\n\n```\n>=0.1.2-rc.1 <0.1.3 || >=0.1.3-alpha.2 <0.1.4 || >=0.1.5-alpha.1 <0.2.0 || >=0.1.6-alpha.1 <0.2.0\n```\n\nEvery dsh release published today is a **prerelease** (`0.1.2-rc.1`, `0.1.5-alpha.1`,\n`0.1.6-alpha.2`, …), and a semver comparator admits a prerelease only when some\ncomparator **in the same group** shares its `major.minor.patch` tuple. Two\nconsequences follow, and both have already bitten this package:\n\n```jsonc\n// Matches nothing: 0.1.2-rc.1 sorts BELOW 0.1.2, and every other prerelease\n// carries a different tuple.  -> ETARGET, the package cannot be installed.\n\">=0.1.2\"\n\n// Only the 0.1.2-rc tuple. The `<0.2.0` upper bound is INERT for prereleases:\n// it excludes no later line, so every other line gets ERESOLVE.\n\">=0.1.2-rc.1 <0.2.0\"\n```\n\nThe second form is the dangerous one, because it *reads* as though it covered\neverything from `0.1.2-rc.1` onward. It does not — `<0.2.0` never excludes\n`0.1.6-alpha.2`, and no comparator names that tuple. Up to **v0.1.1** the\nshipped range was\n\n```\n>=0.1.2-rc.1 <0.2.0 || >=0.1.5-alpha.1 <0.2.0\n```\n\nwhich admitted the `0.1.2-rc` and `0.1.5` tuples and **nothing else** — 5 of the\n23 published versions. A user on the newest shipped dsh release\n(`0.1.6-alpha.2`) therefore could not install the plugin at all:\n\n```\nnpm error ERESOLVE unable to resolve dependency tree\nnpm error peer @deepseek-ai/dsh-llm@\">=0.1.2-rc.1 <0.2.0 || ...\" from\nnpm error   @argszero/cordis-plugin-schedule-cron@0.1.1\n```\n\nThe plugin's own suite passes on that line (7/7). The dsh packages are\n**peers**, so `--legacy-peer-deps` is not something a consumer can reasonably be\nasked to accept: the install simply fails.\n\n**What we ship:** one comparator per supported tuple, each with its own upper\nbound so the intended span is legible rather than implied.\n\n| clause | admits |\n| --- | --- |\n| `>=0.1.2-rc.1 <0.1.3` | `0.1.2-rc.1` |\n| `>=0.1.3-alpha.2 <0.1.4` | `0.1.3-alpha.2` |\n| `>=0.1.5-alpha.1 <0.2.0` | the whole 0.1.5 line (alpha.1, alpha.2, rc.1, rc.2) |\n| `>=0.1.6-alpha.1 <0.2.0` | the whole 0.1.6 line (alpha.1, alpha.2) |\n\n`test/peer-range` **computes** the admitted set with the real `semver` package\nand asserts it equals exactly the set the suite has been run against — 8\nversions — rather than pattern-matching the range string. An earlier guard only\nchecked that the string mentioned `0.1.2-rc.N` and `0.1.5-alpha.N`; that form\ncannot tell a correct range from an incorrect one, which is how the range above\nshipped green. Asserting the set exactly makes both directions loud: dropping a\nsupported line fails, and admitting an unverified line fails too. The same file\nalso asserts that this README quotes the manifest range verbatim.\n## License\n\nMIT\n","readmeFilename":"README.md"}