Skip to content

fix(cron): accept week unit in cron once --after durations - #435

Draft
hetaoBackend wants to merge 2 commits into
mainfrom
fix/433-cron-week-duration
Draft

hetaoBackend wants to merge 2 commits into
mainfrom
fix/433-cron-week-duration

Conversation

@hetaoBackend

@hetaoBackend hetaoBackend commented Oct 6, 2026 •

Copy link
Copy Markdown
Collaborator

Change

Fixes #433.

cron once --after 1w (and compound forms such as 1w2d) failed with CRON_VALIDATION_ERROR: Invalid cron once after duration: "1w", even though the shared DURATION_UNIT_MS table already defines w and cron self --every 1w accepts it. Both relative-duration parsers used for cron once only matched ms|s|m|h|d.

  • packages/agent-tools/src/shared/cron-schedule-input.ts: the parseDurationMs token regex now matches ms|s|m|h|d|w. ms stays ahead of m, so 500ms is still read as milliseconds and not as minutes plus a stray s.

  • packages/local-runtime/src/cron/once-time.ts: same regex change. The nested unit ternary (which had no week branch) is replaced with a DURATION_UNIT_MS table that includes w: 604_800_000.

  • Both parsers now consume one start-anchored <number><unit> token at a time (/^(\d+(?:\.\d+)?)(ms|s|m|h|d|w)/ plus slice) instead of running matchAll with an unanchored global pattern and comparing the concatenated matches. CodeQL flagged the touched regex as js/polynomial-redos. The quadratic behavior was already on main: a 50k-digit unit-less after took about 2 s to reject. It now fails in linear time. Accepted and rejected inputs are the same as before.

After this change, 1w resolves to 7 days and 1w2d to 9 days. Existing units and the rejection of malformed input (1week, 1 w, w, 0w, 1y, …) are unchanged.

I grepped for other duration parsers with the same gap. cron self intervals (parseIntervalSeconds) and packages/shared/src/watch-interval.ts already accept w. The TUI headless timeout parser and the permission timeout duration matcher leave out w on purpose (it isn't a valid unit there), so I didn't touch them. The after field description (e.g. "10m" or "1h30m") gives examples rather than a list of units, so the model-visible schema is unchanged.

Thanks to @smartworldarafath for reporting this, finding the root cause in both parsers and proposing the fix. They are credited as co-author on the commit.

Follow-up, not changed here: parseIntervalSeconds (cron self --every) in the same file uses the same unanchored matchAll pattern, so it scales the same way on long digit runs. I kept this PR to the cron once parsers.

  • PR labels: bug, cli.

Validation

  • Before the fix (origin/main 1852771), the new tests fail as expected: 4 week-unit cases fail with Invalid cron once after duration: "1w" / "1w2d", and the other 20 pass.

  • New unit tests, both passing (26/26):

    • packages/agent-tools/src/shared/cron-schedule-input.test.ts
    • packages/local-runtime/test/unit/cron/once-time.test.ts

    They cover a single week (1w, 2W, 1.5w), compound week durations (1w2d, 1w2d3h4m5s6ms, 2d1w), unchanged existing units (250ms, 30s, 10m, 2h, 3d, 1h30m, 1m500ms), rejection of invalid input with the existing error code/status, and a long unit-less digit run ('1'.repeat(50_000) + 'x') rejected in under 500 ms. With the previous unanchored parser, that digit-run test fails in both packages. Both files are registered in test/vitest-suites.json (capability suite), and release/public-source.json was regenerated for the two new files.

  • pnpm verify (full profile, Linux, Node 22.23.3) on daf3050 passed 14 gates. test:capabilities ran 212 files with 5311 passed and 18 skipped. Skipped as not applicable on Linux: test:windows, test:sandbox, test:release-package.

  • Performance: automatic 100-round basic check. This is a parser-only change outside the runtime paths that need perf:full.

  • NOT RUN: Windows/macOS-only gates; no live-service checks.

Publication and contribution checks

  • I have permission to contribute these changes under the existing licenses applicable to the changed files/packages; imported material and its provenance are identified and existing notices are preserved.
  • No credentials, account data, real user content, internal source history or private review material is included.
  • Added/removed source files were reviewed before regenerating release/public-source.json; new tests are declared in test/vitest-suites.json where applicable.
  • Shared English/Chinese documentation and capability/verification records are updated where applicable. Mock/offline results are not described as live-service acceptance.

Maintainer handoff

Publication scope or license changes (if any): none.

Shared-source port: not needed.

`cron once --after 1w` was rejected with CRON_VALIDATION_ERROR even though
DURATION_UNIT_MS defines `w`, because both relative-duration parsers only
matched `ms|s|m|h|d`. Add `w` to the token regex in the shared agent-tools
parser and the local-runtime parser (keeping `ms` ahead of `m`), and replace
the local-runtime nested ternary with a unit table that includes weeks.

Single (`1w`) and compound (`1w2d`) week durations now resolve correctly;
existing units and invalid-input rejection are unchanged and covered by new
unit tests in both packages.

Fixes #433

Co-authored-by: smartworldarafath <153785481+smartworldarafath@users.noreply.github.com>
@hetaoBackend hetaoBackend added bug Something isn't working cli Standalone mcode: TUI, headless, ACP and source builds/tooling labels Oct 6, 2026
CodeQL flagged the `parseDurationMs` token regex (js/polynomial-redos):
matching the unanchored global pattern against `after` retries `\d+` from
every offset, so a long unit-less digit run takes quadratic time (about 2s
for 50k digits). Consume one start-anchored `<number><unit>` token at a time
instead, in both the agent-tools and local-runtime parsers. Accepted and
rejected inputs are unchanged; add a regression test for the digit-run case.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working cli Standalone mcode: TUI, headless, ACP and source builds/tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: cron once --after does not support week duration unit 'w'

1 participant