one-code-extension 0.4.1 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (419) hide show
  1. package/README.md +16 -5
  2. package/agents/general-purpose.md +2 -2
  3. package/docs/guide/README.md +2 -1
  4. package/docs/guide/bring-your-claude-code-setup.md +60 -9
  5. package/docs/guide/configuration.md +48 -14
  6. package/docs/guide/differences-from-claude-code.md +32 -23
  7. package/docs/guide/doctor.md +20 -13
  8. package/docs/guide/hooks.md +18 -3
  9. package/docs/guide/installation.md +27 -4
  10. package/docs/guide/permissions-modes-and-auto-mode.md +225 -49
  11. package/docs/guide/providers-and-models.md +137 -54
  12. package/docs/guide/reference.md +27 -15
  13. package/docs/guide/sessions-and-context.md +69 -16
  14. package/docs/guide/skills-plugins-and-mcp.md +57 -20
  15. package/docs/guide/subagents-and-workflows.md +95 -29
  16. package/docs/guide/tasks-and-background-work.md +101 -26
  17. package/docs/guide/terminal-interface.md +24 -12
  18. package/docs/guide/tools.md +46 -5
  19. package/docs/guide/troubleshooting.md +13 -9
  20. package/docs/guide/windows.md +58 -31
  21. package/extensions/artifacts/gallery.ts +227 -0
  22. package/extensions/artifacts/index.ts +288 -0
  23. package/extensions/artifacts/store.ts +570 -0
  24. package/extensions/artifacts/viewer.ts +199 -0
  25. package/extensions/ask-user/description.ts +67 -0
  26. package/extensions/ask-user/dialogs.ts +80 -0
  27. package/extensions/ask-user/index.ts +37 -33
  28. package/extensions/ask-user/questions.ts +32 -7
  29. package/extensions/ask-user/widget.ts +45 -25
  30. package/extensions/auto-mode/actions.ts +6 -0
  31. package/extensions/auto-mode/cache.ts +88 -0
  32. package/extensions/auto-mode/classifier-prompt.ts +5 -4
  33. package/extensions/auto-mode/classifier.ts +290 -65
  34. package/extensions/auto-mode/config.ts +72 -20
  35. package/extensions/auto-mode/decision-log.ts +2 -0
  36. package/extensions/auto-mode/defaults.ts +1 -1
  37. package/extensions/auto-mode/denials.ts +123 -0
  38. package/extensions/auto-mode/git-checkout-programs.ts +187 -0
  39. package/extensions/auto-mode/git-status-meta.ts +159 -0
  40. package/extensions/auto-mode/history.ts +189 -0
  41. package/extensions/auto-mode/instructions.ts +58 -52
  42. package/extensions/auto-mode/model-select.ts +159 -134
  43. package/extensions/auto-mode/paths.ts +57 -5
  44. package/extensions/auto-mode/pause.ts +57 -2
  45. package/extensions/auto-mode/prompt.ts +37 -21
  46. package/extensions/auto-mode/read-only-options.ts +724 -0
  47. package/extensions/auto-mode/resolved-paths-meta.ts +133 -0
  48. package/extensions/auto-mode/rules.ts +18 -1
  49. package/extensions/auto-mode/safety-floor.ts +361 -18
  50. package/extensions/auto-mode/setup-run.ts +20 -14
  51. package/extensions/auto-mode/shell-analysis.ts +764 -490
  52. package/extensions/auto-mode/shell-parse.ts +885 -0
  53. package/extensions/auto-mode/system-note.ts +33 -0
  54. package/extensions/auto-mode/transcript.ts +80 -51
  55. package/extensions/background/cron.ts +515 -0
  56. package/extensions/background/index.ts +514 -236
  57. package/extensions/background/loop-fire.ts +136 -0
  58. package/extensions/background/loop-preamble.ts +59 -0
  59. package/extensions/background/loop-skill.ts +163 -0
  60. package/extensions/background/monitor-batch.ts +53 -0
  61. package/extensions/background/noop-fold.ts +128 -0
  62. package/extensions/background/switch-guard.ts +52 -0
  63. package/extensions/background/wakeup.ts +159 -55
  64. package/extensions/bash/background.ts +53 -17
  65. package/extensions/bash/child.ts +7 -0
  66. package/extensions/bash/description.ts +188 -0
  67. package/extensions/bash/guards.ts +15 -67
  68. package/extensions/bash/index.ts +88 -35
  69. package/extensions/branding/compaction-keep.ts +63 -0
  70. package/extensions/branding/declined.ts +22 -0
  71. package/extensions/branding/index.ts +133 -9
  72. package/extensions/branding/prompt-editor.ts +53 -6
  73. package/extensions/branding/queued-edit.ts +31 -0
  74. package/extensions/branding/replaced-builtins.ts +68 -0
  75. package/extensions/branding/startup.ts +33 -71
  76. package/extensions/btw/index.ts +229 -71
  77. package/extensions/btw/panel.ts +228 -100
  78. package/extensions/btw/prompt.ts +41 -4
  79. package/extensions/claude-compat/index.ts +7 -11
  80. package/extensions/claude-context/index.ts +446 -58
  81. package/extensions/compaction/cut.ts +157 -0
  82. package/extensions/compaction/index.ts +216 -75
  83. package/extensions/compaction/kept-thinking.ts +62 -0
  84. package/extensions/compaction/prompt.ts +15 -12
  85. package/extensions/context-budget/index.ts +24 -5
  86. package/extensions/context-management/index.ts +25 -0
  87. package/extensions/doctor/build.ts +59 -8
  88. package/extensions/doctor/builtins.ts +84 -0
  89. package/extensions/doctor/cli.ts +7 -1
  90. package/extensions/doctor/compat.ts +88 -23
  91. package/extensions/doctor/dependencies.ts +41 -5
  92. package/extensions/doctor/fix-prompt.ts +9 -2
  93. package/extensions/doctor/index.ts +102 -58
  94. package/extensions/doctor/models.ts +102 -63
  95. package/extensions/doctor/presets.ts +42 -27
  96. package/extensions/doctor/report.ts +19 -2
  97. package/extensions/doctor/viewer.ts +49 -27
  98. package/extensions/effort/index.ts +72 -19
  99. package/extensions/effort/settings.ts +21 -0
  100. package/extensions/effort/slider.ts +24 -20
  101. package/extensions/exit/index.ts +32 -1
  102. package/extensions/file-tracker/index.ts +337 -26
  103. package/extensions/file-tracker/replay.ts +96 -10
  104. package/extensions/file-tracker/restore.ts +63 -0
  105. package/extensions/file-tracker/results.ts +66 -0
  106. package/extensions/file-tracker/shell-reads.ts +211 -0
  107. package/extensions/file-tracker/tracker.ts +32 -15
  108. package/extensions/footer/footer-line.ts +45 -24
  109. package/extensions/footer/index.ts +47 -2
  110. package/extensions/footer/pr.ts +34 -5
  111. package/extensions/hooks/compaction.ts +7 -0
  112. package/extensions/hooks/executor.ts +32 -30
  113. package/extensions/hooks/index.ts +198 -31
  114. package/extensions/hooks/matcher.ts +3 -0
  115. package/extensions/hooks/protocol.ts +41 -3
  116. package/extensions/hooks/settings.ts +50 -19
  117. package/extensions/hooks/subagent-bridge.ts +2 -0
  118. package/extensions/hooks/trust.ts +13 -5
  119. package/extensions/idle-compact/index.ts +119 -0
  120. package/extensions/idle-compact/policy.ts +143 -0
  121. package/extensions/init/index.ts +11 -10
  122. package/extensions/init/prompt.ts +25 -32
  123. package/extensions/interrupted/index.ts +13 -1
  124. package/extensions/kept-thinking/index.ts +27 -0
  125. package/extensions/lib/agent-cron.ts +130 -0
  126. package/extensions/lib/agent-loader.ts +15 -1
  127. package/extensions/lib/agent-view.ts +85 -0
  128. package/extensions/lib/anthropic-payload.ts +82 -1
  129. package/extensions/lib/anthropic-server-call.ts +230 -0
  130. package/extensions/lib/anthropic-server-tools.ts +485 -0
  131. package/extensions/lib/app-launch.mjs +94 -0
  132. package/extensions/lib/argument-hints.ts +190 -0
  133. package/extensions/lib/atomic-write.ts +6 -2
  134. package/extensions/lib/auto-memory.ts +75 -0
  135. package/extensions/lib/bash-parser.ts +84 -0
  136. package/extensions/lib/btw-fork.ts +93 -0
  137. package/extensions/lib/child-extensions.ts +42 -0
  138. package/extensions/lib/child-writes.ts +45 -0
  139. package/extensions/lib/claude-context.ts +515 -100
  140. package/extensions/lib/claude-external-includes.ts +68 -0
  141. package/extensions/lib/claude-id.ts +22 -0
  142. package/extensions/lib/claude-rules.ts +323 -0
  143. package/extensions/lib/claude-settings.ts +76 -4
  144. package/extensions/lib/compaction-boundary.ts +36 -0
  145. package/extensions/lib/compaction-keep.mjs +83 -0
  146. package/extensions/lib/config-mode.ts +112 -0
  147. package/extensions/lib/consent-dialogs.ts +63 -0
  148. package/extensions/lib/consent-preview.ts +5 -1
  149. package/extensions/lib/consent-stores.ts +48 -0
  150. package/extensions/lib/context-facts.ts +78 -0
  151. package/extensions/lib/context-stack.ts +81 -0
  152. package/extensions/lib/deferred.ts +219 -25
  153. package/extensions/lib/dock-rows.ts +60 -0
  154. package/extensions/lib/empty-tool-result.ts +27 -0
  155. package/extensions/lib/environment-block.ts +76 -0
  156. package/extensions/lib/fetch-timeout.ts +24 -6
  157. package/extensions/{system-prompt → lib}/git-status.ts +51 -13
  158. package/extensions/lib/git.ts +75 -13
  159. package/extensions/lib/grammars/LICENSE-tree-sitter-bash +21 -0
  160. package/extensions/lib/grammars/README.md +2 -0
  161. package/extensions/lib/grammars/tree-sitter-bash.wasm +0 -0
  162. package/extensions/lib/guide-docs.ts +45 -0
  163. package/extensions/lib/headless-output.ts +46 -0
  164. package/extensions/lib/hook-gate.ts +7 -7
  165. package/extensions/lib/interrupt.ts +20 -4
  166. package/extensions/lib/key-input.ts +455 -0
  167. package/extensions/lib/keys.ts +14 -1
  168. package/extensions/lib/local-command.ts +47 -13
  169. package/extensions/lib/mcp-overrides.ts +1 -1
  170. package/extensions/lib/mcp-share.ts +46 -0
  171. package/extensions/lib/memory-content.ts +146 -0
  172. package/extensions/lib/memory-index.ts +18 -0
  173. package/extensions/lib/memory.ts +134 -123
  174. package/extensions/lib/model-catalog/huggingface.json +174 -0
  175. package/extensions/lib/model-catalog/models-dev.json +18297 -0
  176. package/extensions/lib/model-catalog/openrouter.json +5252 -0
  177. package/extensions/lib/model-catalog-data.ts +513 -0
  178. package/extensions/lib/model-catalog.ts +462 -0
  179. package/extensions/lib/model-choice-warnings.ts +137 -0
  180. package/extensions/lib/model-pairings.ts +152 -0
  181. package/extensions/{auto-mode → lib}/model-picker.ts +26 -43
  182. package/extensions/lib/model-policy.ts +112 -15
  183. package/extensions/lib/model-tier.ts +283 -355
  184. package/extensions/lib/model-unusable.ts +1 -1
  185. package/extensions/lib/newer-model.ts +100 -0
  186. package/extensions/lib/notices.ts +87 -0
  187. package/extensions/lib/notifications.ts +308 -64
  188. package/extensions/lib/one-code-settings.ts +74 -8
  189. package/extensions/lib/open-browser.ts +63 -0
  190. package/extensions/lib/openrouter-generation.ts +94 -0
  191. package/extensions/lib/operation-deadline.ts +30 -0
  192. package/extensions/lib/original-command.ts +4 -4
  193. package/extensions/lib/package-version.ts +1 -1
  194. package/extensions/lib/panel-focus.ts +134 -0
  195. package/extensions/lib/paths.ts +17 -2
  196. package/extensions/lib/permission-gate.ts +72 -6
  197. package/extensions/lib/persisted-output.ts +60 -8
  198. package/extensions/lib/pi-ai-estimate.ts +19 -3
  199. package/extensions/lib/pi-version.ts +21 -2
  200. package/extensions/lib/plan-mode-channels.ts +20 -5
  201. package/extensions/lib/plugins.ts +26 -17
  202. package/extensions/lib/powershell-parse-script.ts +208 -0
  203. package/extensions/lib/powershell-parser.ts +344 -0
  204. package/extensions/lib/process-tree.ts +131 -8
  205. package/extensions/lib/prompt-options.ts +82 -0
  206. package/extensions/lib/queued-delivery.ts +44 -0
  207. package/extensions/lib/reminders.ts +364 -58
  208. package/extensions/lib/replaced-builtins.mjs +199 -0
  209. package/extensions/lib/replay-call.ts +70 -0
  210. package/extensions/lib/request-replay.ts +439 -0
  211. package/extensions/lib/scratchpad.ts +81 -14
  212. package/extensions/lib/send-now-channel.ts +7 -0
  213. package/extensions/lib/session-model-tier.ts +51 -0
  214. package/extensions/lib/session-work.ts +64 -0
  215. package/extensions/lib/settings-channels.ts +4 -4
  216. package/extensions/lib/shell-exit-semantics.ts +170 -0
  217. package/extensions/lib/shell-quote.ts +11 -0
  218. package/extensions/lib/shell-result.ts +70 -0
  219. package/extensions/lib/shell-spawn.ts +70 -6
  220. package/extensions/lib/shell-tool.ts +75 -25
  221. package/extensions/lib/side-call-cache.ts +124 -0
  222. package/extensions/lib/side-call-run.ts +96 -0
  223. package/extensions/lib/side-call-usage.ts +38 -0
  224. package/extensions/lib/side-call.ts +13 -1
  225. package/extensions/lib/single-flight.ts +18 -0
  226. package/extensions/lib/skill-body.ts +42 -0
  227. package/extensions/lib/skill-scan.ts +63 -24
  228. package/extensions/lib/spill-file.ts +140 -0
  229. package/extensions/lib/subagent-handback.ts +113 -0
  230. package/extensions/lib/system-role.ts +156 -0
  231. package/extensions/lib/terminal-text.ts +114 -0
  232. package/extensions/lib/text-width.ts +47 -16
  233. package/extensions/lib/timer-ops.ts +20 -0
  234. package/extensions/lib/tool-additions.ts +149 -0
  235. package/extensions/lib/tool-call-corruption.ts +134 -0
  236. package/extensions/lib/tool-path.ts +66 -0
  237. package/extensions/lib/tool-variants.ts +69 -0
  238. package/extensions/lib/tui-render.ts +255 -27
  239. package/extensions/lib/turn-budget-layout.ts +143 -0
  240. package/extensions/lib/update-check.mjs +15 -2
  241. package/extensions/lib/usage-bus.ts +1 -1
  242. package/extensions/lib/user-denial.ts +38 -0
  243. package/extensions/lib/workspace-channel.ts +16 -0
  244. package/extensions/lib/worktree-channel.ts +31 -3
  245. package/extensions/lib/worktree-isolation.ts +40 -10
  246. package/extensions/lsp/client.ts +8 -9
  247. package/extensions/lsp/index.ts +70 -4
  248. package/extensions/lsp/keep-alive.ts +1 -1
  249. package/extensions/lsp/trust.ts +119 -0
  250. package/extensions/lsp/watcher.ts +1 -1
  251. package/extensions/mcp/announce.ts +87 -5
  252. package/extensions/mcp/client.ts +161 -48
  253. package/extensions/mcp/config.ts +132 -8
  254. package/extensions/mcp/discovery.ts +19 -0
  255. package/extensions/mcp/index.ts +209 -71
  256. package/extensions/mcp/oauth/browser.ts +38 -17
  257. package/extensions/mcp/oauth/flow.ts +25 -17
  258. package/extensions/mcp/oauth/provider.ts +14 -8
  259. package/extensions/mcp/oauth/store.ts +34 -16
  260. package/extensions/mcp/panel/keys.ts +12 -11
  261. package/extensions/mcp/panel/render.ts +9 -6
  262. package/extensions/mcp/schema.ts +104 -5
  263. package/extensions/mcp/trust.ts +151 -67
  264. package/extensions/memory/entries.ts +23 -14
  265. package/extensions/memory/index.ts +134 -28
  266. package/extensions/memory/open-external.ts +33 -18
  267. package/extensions/memory/panel.ts +135 -26
  268. package/extensions/newer-model/index.ts +31 -0
  269. package/extensions/notebook/description.ts +18 -0
  270. package/extensions/notebook/index.ts +6 -5
  271. package/extensions/notebook/notebook.ts +1 -1
  272. package/extensions/permissions/index.ts +1300 -381
  273. package/extensions/permissions/matcher.ts +425 -74
  274. package/extensions/permissions/modes.ts +6 -4
  275. package/extensions/permissions/panel/host.ts +130 -0
  276. package/extensions/permissions/panel/keys.ts +48 -0
  277. package/extensions/permissions/panel/render.ts +450 -0
  278. package/extensions/permissions/panel/state.ts +550 -0
  279. package/extensions/permissions/powershell-cmdlets.ts +198 -0
  280. package/extensions/permissions/powershell-paths.ts +197 -0
  281. package/extensions/permissions/powershell-rules.ts +207 -280
  282. package/extensions/permissions/powershell-tree.ts +557 -0
  283. package/extensions/permissions/project-trust.ts +27 -11
  284. package/extensions/permissions/protected-paths.ts +14 -2
  285. package/extensions/permissions/session-grant.ts +6 -0
  286. package/extensions/permissions/settings.ts +166 -31
  287. package/extensions/permissions/subagent-gate.ts +25 -0
  288. package/extensions/permissions/workspace.ts +78 -0
  289. package/extensions/plan-mode/index.ts +156 -69
  290. package/extensions/plan-mode/reminder.ts +89 -21
  291. package/extensions/plan-mode/texts.ts +177 -0
  292. package/extensions/plan-mode/viewer.ts +92 -27
  293. package/extensions/plugins/counts.ts +3 -3
  294. package/extensions/plugins/index.ts +61 -46
  295. package/extensions/plugins/install/install.ts +16 -0
  296. package/extensions/plugins/marketplace/sync.ts +9 -3
  297. package/extensions/plugins/marketplace/types.ts +3 -1
  298. package/extensions/plugins/panel/keys.ts +21 -24
  299. package/extensions/plugins/panel/render.ts +12 -6
  300. package/extensions/plugins/shell-expand.ts +107 -0
  301. package/extensions/plugins/template.ts +32 -15
  302. package/extensions/powershell/child.ts +7 -0
  303. package/extensions/powershell/description.ts +38 -6
  304. package/extensions/powershell/guards.ts +1 -1
  305. package/extensions/powershell/index.ts +12 -7
  306. package/extensions/recap/index.ts +65 -60
  307. package/extensions/recap/prompt.ts +2 -2
  308. package/extensions/recap/scheduler.ts +3 -5
  309. package/extensions/search-tools/grep-merge.ts +39 -0
  310. package/extensions/search-tools/index.ts +0 -0
  311. package/extensions/send-now/chord.ts +62 -0
  312. package/extensions/send-now/index.ts +133 -0
  313. package/extensions/session-title/index.ts +3 -0
  314. package/extensions/session-title/title.ts +4 -1
  315. package/extensions/skill/code-review.ts +97 -0
  316. package/extensions/skill/index.ts +421 -101
  317. package/extensions/skill/invoke.ts +128 -18
  318. package/extensions/skill/listing.ts +133 -9
  319. package/extensions/skill/panel/keys.ts +15 -16
  320. package/extensions/skill/panel/render.ts +5 -2
  321. package/extensions/skill/panel/state.ts +12 -1
  322. package/extensions/subagents/agent-args.ts +39 -0
  323. package/extensions/subagents/agent-description.ts +132 -0
  324. package/extensions/subagents/agents.ts +116 -23
  325. package/extensions/subagents/announce.ts +69 -0
  326. package/extensions/subagents/default-model.ts +2 -3
  327. package/extensions/subagents/delegation-steer.ts +4 -4
  328. package/extensions/subagents/fork-cache.ts +76 -0
  329. package/extensions/subagents/guide-agent.ts +189 -0
  330. package/extensions/subagents/hand-back-review.ts +3 -0
  331. package/extensions/subagents/index.ts +1493 -824
  332. package/extensions/subagents/live-runs.ts +26 -6
  333. package/extensions/subagents/model-select.ts +38 -25
  334. package/extensions/subagents/outcome.ts +2 -2
  335. package/extensions/subagents/panel-keys.ts +73 -31
  336. package/extensions/subagents/panel-render.ts +120 -96
  337. package/extensions/subagents/panel-widget.ts +60 -89
  338. package/extensions/subagents/runner.ts +108 -80
  339. package/extensions/subagents/runs.ts +39 -5
  340. package/extensions/subagents/send-to-main-tool.ts +1 -1
  341. package/extensions/subagents/session-turns.ts +32 -8
  342. package/extensions/subagents/shell-panel.ts +36 -178
  343. package/extensions/subagents/tasks-dialog.ts +170 -0
  344. package/extensions/subagents/viewport-mirror.ts +95 -0
  345. package/extensions/subagents/worktree.ts +57 -13
  346. package/extensions/system-prompt/environment.ts +19 -19
  347. package/extensions/system-prompt/idle-turn.ts +65 -0
  348. package/extensions/system-prompt/index.ts +131 -47
  349. package/extensions/system-prompt/template.ts +24 -50
  350. package/extensions/system-prompt/tiers/common.ts +23 -64
  351. package/extensions/system-prompt/tiers/frontier.ts +32 -11
  352. package/extensions/system-prompt/tiers/low.ts +67 -45
  353. package/extensions/system-prompt/tiers/mid.ts +96 -38
  354. package/extensions/system-reminder/index.ts +175 -13
  355. package/extensions/tasks/descriptions.ts +190 -0
  356. package/extensions/tasks/index.ts +120 -41
  357. package/extensions/tasks/store.ts +83 -16
  358. package/extensions/tool-call-corruption/child.ts +7 -0
  359. package/extensions/tool-call-corruption/index.ts +237 -0
  360. package/extensions/tool-search/announce.ts +16 -0
  361. package/extensions/tool-search/index.ts +189 -41
  362. package/extensions/tool-style/index.ts +68 -10
  363. package/extensions/tool-style/write-description.ts +40 -0
  364. package/extensions/tool-style/write-render.ts +237 -0
  365. package/extensions/turn-duration/index.ts +7 -3
  366. package/extensions/turn-duration/line.ts +47 -4
  367. package/extensions/web/backends.ts +6 -9
  368. package/extensions/web/description.ts +50 -0
  369. package/extensions/web/index.ts +118 -53
  370. package/extensions/web/native-call.ts +15 -0
  371. package/extensions/web/native-results.ts +41 -0
  372. package/extensions/web-fetch/description.ts +42 -0
  373. package/extensions/web-fetch/extract.ts +53 -6
  374. package/extensions/web-fetch/index.ts +125 -76
  375. package/extensions/web-fetch/page-content.ts +19 -0
  376. package/extensions/web-fetch/response.ts +49 -0
  377. package/extensions/web-fetch/summarize.ts +9 -10
  378. package/extensions/workflow/agent-session.ts +105 -18
  379. package/extensions/workflow/args.ts +24 -0
  380. package/extensions/workflow/description.ts +67 -0
  381. package/extensions/workflow/globals.ts +17 -3
  382. package/extensions/workflow/index.ts +145 -162
  383. package/extensions/workflow/records.ts +1 -0
  384. package/extensions/workflow/run-manager.ts +29 -6
  385. package/extensions/workflow/saved-workflows.ts +3 -2
  386. package/extensions/workflow/types.ts +22 -1
  387. package/extensions/workflow/viewer.ts +54 -24
  388. package/extensions/workflow/widget.ts +20 -0
  389. package/extensions/worktree/descriptions.ts +91 -0
  390. package/extensions/worktree/guards.ts +316 -54
  391. package/extensions/worktree/index.ts +121 -39
  392. package/extensions/worktree/powershell-guards.ts +167 -0
  393. package/extensions/worktree/rewrite.ts +14 -16
  394. package/package.json +18 -7
  395. package/skills/artifact-design/SKILL.md +85 -0
  396. package/skills/code-review/SKILL.md +20 -20
  397. package/skills/code-review/cells/arguments-and-flags.md +19 -0
  398. package/skills/code-review/cells/high-3x5-recall-verify.md +137 -0
  399. package/skills/code-review/cells/high-8-inline.md +122 -0
  400. package/skills/code-review/cells/low-1-pass-max4.md +27 -0
  401. package/skills/code-review/cells/low-1-pass-min-files-4.md +28 -0
  402. package/skills/code-review/cells/max-5x5-verify-sweep.md +162 -0
  403. package/skills/code-review/cells/medium-3x5-verify.md +132 -0
  404. package/skills/code-review/cells/minimal-prompt.md +32 -0
  405. package/skills/code-review/cells/xhigh-10-inline-sweep.md +149 -0
  406. package/skills/code-review/cells/xhigh-5x5-verify-sweep.md +162 -0
  407. package/skills/fewer-permission-prompts/SKILL.md +1 -1
  408. package/skills/loop/SKILL.md +11 -0
  409. package/skills/security-review/SKILL.md +2 -5
  410. package/skills/simplify/SKILL.md +7 -5
  411. package/skills/workflow-authoring/SKILL.md +143 -0
  412. package/themes/onecode-light.json +1 -1
  413. package/themes/onecode.json +1 -1
  414. package/types/app.d.ts +58 -0
  415. package/types/community-packages.d.ts +26 -1
  416. package/extensions/auto-mode/recoverability.ts +0 -229
  417. package/extensions/lib/capability-index.ts +0 -466
  418. package/extensions/lib/model-facts.generated.json +0 -2675
  419. package/extensions/lib/model-facts.ts +0 -162
@@ -0,0 +1,515 @@
1
+ /**
2
+ * Session cron (pure) — the store behind cron_create / cron_list / cron_delete
3
+ * and fixed-interval /loop.
4
+ *
5
+ * Claude Code's cron is a session-only, in-memory schedule of prompts, each
6
+ * re-invoking the session verbatim when its 5-field local-time expression
7
+ * matches (findings §21). This module holds the parts with no timers: the
8
+ * expression parser, the next-match search, the human cadence text, and the
9
+ * store's due/expiry bookkeeping. The extension owns the single timer and decides WHEN to call
10
+ * `takeDue` (only while idle), so a job due mid-turn fires once at settle.
11
+ *
12
+ * Parsing, matching and cadence text follow Claude Code 2.1.281 exactly:
13
+ * numeric fields only (`*`, `* /n`, `a`, `a-b`, `a-b/n`, lists), day-of-week 7
14
+ * is Sunday, day-of-month and day-of-week OR together when both are
15
+ * restricted, and a job whose expression matches nothing within a year is
16
+ * rejected. Fire times carry Claude Code's deterministic jitter (`JITTER`).
17
+ */
18
+
19
+ import { randomUUID } from "node:crypto";
20
+ import { Type } from "typebox";
21
+ import { sliceColumns, visibleWidth } from "../lib/text-width.ts";
22
+
23
+ /** Claude Code's per-session job cap. */
24
+ export const MAX_JOBS = 50;
25
+ /** Recurring jobs expire after 7 days: they fire one final time, then are deleted. */
26
+ export const RECURRING_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;
27
+ export const RECURRING_MAX_AGE_DAYS = RECURRING_MAX_AGE_MS / 86_400_000;
28
+ /**
29
+ * Claude Code's jitter constants (2.1.282; findings §21). The tool
30
+ * description tells the model "up to 10% of their period late (max 15 min)";
31
+ * the code fires up to 50% late, capped at 30 minutes. We match the code.
32
+ */
33
+ export const JITTER = {
34
+ recurringFrac: 0.5,
35
+ recurringCapMs: 1_800_000,
36
+ oneShotMaxMs: 90_000,
37
+ oneShotFloorMs: 0,
38
+ oneShotMinuteMod: 30,
39
+ /** A plain every-5-minutes job fires this much before the period ends, as Claude Code's does. */
40
+ cacheLeadMs: 15_000,
41
+ } as const;
42
+ const FIVE_MINUTES_MS = 300_000;
43
+ const PLAIN_STEP_MINUTES = /^\*\/\d+ \* \* \* \*$/;
44
+
45
+ /** A job's fixed jitter fraction in [0, 1): its id's first 8 hex digits over 2^32. */
46
+ export function jitterFraction(id: string): number {
47
+ const value = Number.parseInt(id.slice(0, 8), 16) / 4_294_967_296;
48
+ return Number.isFinite(value) ? value : 0;
49
+ }
50
+
51
+ /**
52
+ * A recurring job's next fire after `from`, as Claude Code computes it: the next
53
+ * match plus up to half the period (capped), by the job's fraction. A plain
54
+ * `*\/N` job whose period is exactly 5 minutes (to within the lead) fires 15 s
55
+ * before the period ends instead, measured from `from`.
56
+ */
57
+ export function nextRecurringFire(cron: string, fields: CronFields, from: number, id: string): number | null {
58
+ const first = nextMatch(fields, new Date(from));
59
+ if (!first) return null;
60
+ const second = nextMatch(fields, first);
61
+ if (!second) return first.getTime();
62
+ const period = second.getTime() - first.getTime();
63
+ const lead = JITTER.cacheLeadMs;
64
+ if (PLAIN_STEP_MINUTES.test(cron.trim()) && lead > 0 && lead < period && period >= FIVE_MINUTES_MS && period - lead < FIVE_MINUTES_MS) {
65
+ return from + period - lead;
66
+ }
67
+ return first.getTime() + Math.min(jitterFraction(id) * JITTER.recurringFrac * period, JITTER.recurringCapMs);
68
+ }
69
+
70
+ /**
71
+ * A one-shot job's fire, as Claude Code computes it: its match, or up to 90 s
72
+ * earlier when the match falls on :00 or :30, never before it was created.
73
+ */
74
+ export function oneShotFire(fields: CronFields, createdAt: number, id: string): number | null {
75
+ const match = nextMatch(fields, new Date(createdAt));
76
+ if (!match) return null;
77
+ if (match.getMinutes() % JITTER.oneShotMinuteMod !== 0) return match.getTime();
78
+ const early = JITTER.oneShotFloorMs + jitterFraction(id) * (JITTER.oneShotMaxMs - JITTER.oneShotFloorMs);
79
+ return Math.max(match.getTime() - early, createdAt);
80
+ }
81
+
82
+ /** The next-match search walks at most one leap year of minutes. */
83
+ const SEARCH_LIMIT_MINUTES = 366 * 24 * 60;
84
+
85
+ export interface CronFields {
86
+ minute: number[];
87
+ hour: number[];
88
+ dayOfMonth: number[];
89
+ month: number[];
90
+ dayOfWeek: number[];
91
+ }
92
+
93
+ const FIELD_RANGES = [
94
+ { min: 0, max: 59 },
95
+ { min: 0, max: 23 },
96
+ { min: 1, max: 31 },
97
+ { min: 1, max: 12 },
98
+ { min: 0, max: 6 },
99
+ ] as const;
100
+
101
+ function parseField(text: string, range: { min: number; max: number }): number[] | null {
102
+ const { min, max } = range;
103
+ const isDayOfWeek = min === 0 && max === 6;
104
+ const values = new Set<number>();
105
+ for (const part of text.split(",")) {
106
+ const star = part.match(/^\*(?:\/(\d+))?$/);
107
+ if (star) {
108
+ const step = star[1] ? Number.parseInt(star[1], 10) : 1;
109
+ if (step < 1) return null;
110
+ for (let v = min; v <= max; v += step) values.add(v);
111
+ continue;
112
+ }
113
+ const span = part.match(/^(\d+)-(\d+)(?:\/(\d+))?$/);
114
+ if (span) {
115
+ const lo = Number.parseInt(span[1], 10);
116
+ const hi = Number.parseInt(span[2], 10);
117
+ const step = span[3] ? Number.parseInt(span[3], 10) : 1;
118
+ // Day-of-week accepts 7 as Sunday at the top of a range.
119
+ const top = isDayOfWeek ? 7 : max;
120
+ if (lo > hi || step < 1 || lo < min || hi > top) return null;
121
+ for (let v = lo; v <= hi; v += step) values.add(isDayOfWeek && v === 7 ? 0 : v);
122
+ continue;
123
+ }
124
+ if (/^\d+$/.test(part)) {
125
+ let v = Number.parseInt(part, 10);
126
+ if (isDayOfWeek && v === 7) v = 0;
127
+ if (v < min || v > max) return null;
128
+ values.add(v);
129
+ continue;
130
+ }
131
+ return null;
132
+ }
133
+ if (values.size === 0) return null;
134
+ return [...values].sort((a, b) => a - b);
135
+ }
136
+
137
+ /** Parse a 5-field cron expression; null when it is malformed. */
138
+ export function parseCron(expr: string): CronFields | null {
139
+ const parts = expr.trim().split(/\s+/);
140
+ if (parts.length !== 5) return null;
141
+ const fields: number[][] = [];
142
+ for (let i = 0; i < 5; i++) {
143
+ const values = parseField(parts[i], FIELD_RANGES[i]);
144
+ if (!values) return null;
145
+ fields.push(values);
146
+ }
147
+ return { minute: fields[0], hour: fields[1], dayOfMonth: fields[2], month: fields[3], dayOfWeek: fields[4] };
148
+ }
149
+
150
+ /**
151
+ * The first local-time minute strictly after `from` that matches, or null when
152
+ * nothing matches within a year. Walks forward in local time, skipping whole
153
+ * months, days and hours that cannot match, so DST gaps and repeats follow the
154
+ * platform's `Date` arithmetic the way Claude Code's scheduler does.
155
+ */
156
+ export function nextMatch(fields: CronFields, from: Date): Date | null {
157
+ const minutes = new Set(fields.minute);
158
+ const hours = new Set(fields.hour);
159
+ const doms = new Set(fields.dayOfMonth);
160
+ const months = new Set(fields.month);
161
+ const dows = new Set(fields.dayOfWeek);
162
+ const anyDom = fields.dayOfMonth.length === 31;
163
+ const anyDow = fields.dayOfWeek.length === 7;
164
+ const t = new Date(from.getTime());
165
+ t.setSeconds(0, 0);
166
+ t.setMinutes(t.getMinutes() + 1);
167
+ for (let i = 0; i < SEARCH_LIMIT_MINUTES; i++) {
168
+ if (!months.has(t.getMonth() + 1)) {
169
+ t.setMonth(t.getMonth() + 1, 1);
170
+ t.setHours(0, 0, 0, 0);
171
+ continue;
172
+ }
173
+ const dom = t.getDate();
174
+ const dow = t.getDay();
175
+ const dayMatches = anyDom && anyDow ? true : anyDom ? dows.has(dow) : anyDow ? doms.has(dom) : doms.has(dom) || dows.has(dow);
176
+ if (!dayMatches) {
177
+ t.setDate(t.getDate() + 1);
178
+ t.setHours(0, 0, 0, 0);
179
+ continue;
180
+ }
181
+ if (!hours.has(t.getHours())) {
182
+ t.setHours(t.getHours() + 1, 0, 0, 0);
183
+ continue;
184
+ }
185
+ if (!minutes.has(t.getMinutes())) {
186
+ t.setMinutes(t.getMinutes() + 1);
187
+ continue;
188
+ }
189
+ return t;
190
+ }
191
+ return null;
192
+ }
193
+
194
+ const WEEKDAYS = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
195
+
196
+ function clockTime(minute: number, hour: number): string {
197
+ return new Date(2000, 0, 1, hour, minute).toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit" });
198
+ }
199
+
200
+ /** Claude Code's human-readable cadence ("Every 5 minutes", "Weekdays at 9:00 AM"); the raw expression otherwise. */
201
+ export function describeCadence(expr: string): string {
202
+ const parts = expr.trim().split(/\s+/);
203
+ if (parts.length !== 5) return expr;
204
+ const [min, hour, dom, month, dow] = parts;
205
+ const restAny = dom === "*" && month === "*" && dow === "*";
206
+ if (hour === "*" && restAny) {
207
+ if (min === "*") return "Every minute";
208
+ const step = min.match(/^\*\/(\d+)$/);
209
+ if (step) {
210
+ const n = Number.parseInt(step[1], 10);
211
+ return n === 1 ? "Every minute" : `Every ${n} minutes`;
212
+ }
213
+ }
214
+ if (/^\d+$/.test(min) && hour === "*" && restAny) {
215
+ const m = Number.parseInt(min, 10);
216
+ return m === 0 ? "Every hour" : `Every hour at :${String(m).padStart(2, "0")}`;
217
+ }
218
+ const hourStep = hour.match(/^\*\/(\d+)$/);
219
+ if (/^\d+$/.test(min) && hourStep && restAny) {
220
+ const n = Number.parseInt(hourStep[1], 10);
221
+ const m = Number.parseInt(min, 10);
222
+ const at = m === 0 ? "" : ` at :${String(m).padStart(2, "0")}`;
223
+ return n === 1 ? `Every hour${at}` : `Every ${n} hours${at}`;
224
+ }
225
+ if (!/^\d+$/.test(min) || !/^\d+$/.test(hour)) return expr;
226
+ const time = clockTime(Number.parseInt(min, 10), Number.parseInt(hour, 10));
227
+ if (restAny) return `Every day at ${time}`;
228
+ if (dom === "*" && month === "*" && /^\d$/.test(dow)) {
229
+ const day = WEEKDAYS[Number.parseInt(dow, 10) % 7];
230
+ if (day) return `Every ${day} at ${time}`;
231
+ }
232
+ if (dom === "*" && month === "*" && dow === "1-5") return `Weekdays at ${time}`;
233
+ return expr;
234
+ }
235
+
236
+ /** Who made the job: the model (cron_create, /loop's fixed interval included) or schedule_wakeup (a one-shot, as in Claude Code). */
237
+ export type CronSource = "model" | "wakeup";
238
+
239
+ export interface CronJob {
240
+ id: string;
241
+ cron: string;
242
+ prompt: string;
243
+ recurring: boolean;
244
+ source: CronSource;
245
+ /** A subagent's task id when the job is that agent's (lib/agent-cron.ts). */
246
+ agentId?: string;
247
+ /** A subagent job's working directory, where its fire resolves loop.md and skills. */
248
+ cwd?: string;
249
+ createdAt: number;
250
+ /** Epoch ms of the next fire. */
251
+ nextFireAt: number;
252
+ }
253
+
254
+ export interface CronFire {
255
+ job: CronJob;
256
+ /** The job is gone after this fire: a one-shot, or a recurring job past its 7-day age. */
257
+ final: boolean;
258
+ }
259
+
260
+ export type CreateResult = { ok: true; job: CronJob } | { ok: false; error: string };
261
+
262
+ export interface CronStoreOptions {
263
+ maxJobs?: number;
264
+ maxAgeMs?: number;
265
+ newId?: () => string;
266
+ /** false fires on the exact match (tests); Claude Code's jitter otherwise. */
267
+ jitter?: boolean;
268
+ }
269
+
270
+ /** The session's jobs, keyed by id, with no timers of its own. */
271
+ export class CronStore {
272
+ private readonly jobs = new Map<string, CronJob & { fields: CronFields }>();
273
+ private readonly maxJobs: number;
274
+ private readonly maxAgeMs: number;
275
+ private readonly newId: () => string;
276
+ private readonly jitter: boolean;
277
+
278
+ constructor(options: CronStoreOptions = {}) {
279
+ this.maxJobs = options.maxJobs ?? MAX_JOBS;
280
+ this.maxAgeMs = options.maxAgeMs ?? RECURRING_MAX_AGE_MS;
281
+ this.newId = options.newId ?? (() => randomUUID().slice(0, 8));
282
+ this.jitter = options.jitter ?? true;
283
+ }
284
+
285
+ /** The fire after `from`: the exact next match without jitter, Claude Code's jittered time with it. */
286
+ private fireAfter(job: { id: string; cron: string; recurring: boolean; fields: CronFields }, from: number): number | null {
287
+ if (!this.jitter) return nextMatch(job.fields, new Date(from))?.getTime() ?? null;
288
+ return job.recurring ? nextRecurringFire(job.cron, job.fields, from, job.id) : oneShotFire(job.fields, from, job.id);
289
+ }
290
+
291
+ /** Validate and add a job, with Claude Code's error wording. */
292
+ /**
293
+ * `fireAt` pins the first fire to an exact time instead of the next match: a
294
+ * wakeup fires `delaySeconds` from now, its cron (`M H * * *`) only naming
295
+ * that minute for cron_list, as in Claude Code.
296
+ */
297
+ create(input: { cron: string; prompt: string; recurring?: boolean; source?: CronSource; fireAt?: number; agentId?: string; cwd?: string }, now: number): CreateResult {
298
+ const fields = parseCron(input.cron);
299
+ if (!fields) return { ok: false, error: `Invalid cron expression '${input.cron}'. Expected 5 fields: M H DoM Mon DoW.` };
300
+ if (!nextMatch(fields, new Date(now))) return { ok: false, error: `Cron expression '${input.cron}' does not match any calendar date in the next year.` };
301
+ // The cap is cron_create's check, as in Claude Code; a wakeup is never refused.
302
+ if (input.source !== "wakeup" && this.jobs.size >= this.maxJobs) return { ok: false, error: `Too many scheduled jobs (max ${this.maxJobs}). Cancel one first.` };
303
+ let id = this.newId();
304
+ while (this.jobs.has(id)) id = this.newId();
305
+ const base = { id, cron: input.cron.trim(), recurring: input.recurring ?? true, fields };
306
+ const job = {
307
+ ...base,
308
+ prompt: input.prompt,
309
+ source: input.source ?? "model",
310
+ ...(input.agentId !== undefined && { agentId: input.agentId }),
311
+ ...(input.cwd !== undefined && { cwd: input.cwd }),
312
+ createdAt: now,
313
+ nextFireAt: input.fireAt ?? this.fireAfter(base, now)!,
314
+ };
315
+ this.jobs.set(id, job);
316
+ return { ok: true, job: publicJob(job) };
317
+ }
318
+
319
+ delete(id: string): boolean {
320
+ return this.jobs.delete(id);
321
+ }
322
+
323
+ get(id: string): CronJob | undefined {
324
+ const job = this.jobs.get(id);
325
+ return job && publicJob(job);
326
+ }
327
+
328
+ /** Every job, in creation order. */
329
+ list(): CronJob[] {
330
+ return [...this.jobs.values()].map(publicJob);
331
+ }
332
+
333
+ get size(): number {
334
+ return this.jobs.size;
335
+ }
336
+
337
+ /** Epoch ms of the earliest pending fire, for arming the one timer. */
338
+ nextFireAt(): number | undefined {
339
+ let earliest: number | undefined;
340
+ for (const job of this.jobs.values()) if (earliest === undefined || job.nextFireAt < earliest) earliest = job.nextFireAt;
341
+ return earliest;
342
+ }
343
+
344
+ /**
345
+ * Claim every job due at `now`. Each fires once however many of its matches
346
+ * passed (a turn that ran through three ticks yields one fire, not three);
347
+ * a recurring job re-arms to its next match after `now`, and a one-shot or
348
+ * an expired recurring job is deleted.
349
+ */
350
+ takeDue(now: number): CronFire[] {
351
+ const fires: CronFire[] = [];
352
+ for (const job of this.jobs.values()) {
353
+ if (job.nextFireAt > now) continue;
354
+ const next = job.recurring ? this.fireAfter(job, now) : null;
355
+ const expired = job.recurring && now - job.createdAt >= this.maxAgeMs;
356
+ const final = !job.recurring || expired || next === null;
357
+ fires.push({ job: publicJob(job), final });
358
+ if (final) this.jobs.delete(job.id);
359
+ else job.nextFireAt = next!;
360
+ }
361
+ return fires;
362
+ }
363
+
364
+ /** Remove every job matching `predicate`; returns the removed jobs. */
365
+ deleteWhere(predicate: (job: CronJob) => boolean): CronJob[] {
366
+ const removed: CronJob[] = [];
367
+ for (const job of this.jobs.values()) {
368
+ const view = publicJob(job);
369
+ if (predicate(view)) {
370
+ this.jobs.delete(job.id);
371
+ removed.push(view);
372
+ }
373
+ }
374
+ return removed;
375
+ }
376
+
377
+ clear(): void {
378
+ this.jobs.clear();
379
+ }
380
+ }
381
+
382
+ function publicJob(job: CronJob & { fields?: CronFields }): CronJob {
383
+ const { fields: _fields, ...rest } = job;
384
+ return rest;
385
+ }
386
+
387
+ // ── Model-facing text (Claude Code's wording, our tool names) ───────────────
388
+
389
+ const SESSION_ONLY = "Session-only (not written to disk, dies when this session ends)";
390
+
391
+ export function formatCreateResult(job: CronJob): string {
392
+ const cadence = describeCadence(job.cron);
393
+ return job.recurring
394
+ ? `Scheduled recurring job ${job.id} (${cadence}). ${SESSION_ONLY}. Auto-expires after ${RECURRING_MAX_AGE_DAYS} days. Use cron_delete to cancel sooner.`
395
+ : `Scheduled one-shot task ${job.id} (${cadence}). ${SESSION_ONLY}. It will fire once then auto-delete.`;
396
+ }
397
+
398
+ /**
399
+ * Claude Code's `CronList` clip of a prompt (its `truncate(text, 80, true)`):
400
+ * a multi-line prompt shows its first line plus "…", and a line wider than
401
+ * 80 columns is cut to 79 plus "…". Loosened no-truncation rule:
402
+ * decisions/tools.md, "Model-facing text is persisted past its cap".
403
+ */
404
+ export function clipPrompt(prompt: string, max = 80): string {
405
+ const newline = prompt.indexOf("\n");
406
+ if (newline !== -1) {
407
+ const first = prompt.slice(0, newline);
408
+ return visibleWidth(first) + 1 > max ? cutToWidth(`${first}…`, max) : `${first}…`;
409
+ }
410
+ return visibleWidth(prompt) <= max ? prompt : cutToWidth(prompt, max);
411
+ }
412
+
413
+ /** Claude Code's cut: the text to `max - 1` columns plus "…". */
414
+ function cutToWidth(text: string, max: number): string {
415
+ if (visibleWidth(text) <= max) return text;
416
+ return max <= 1 ? "…" : `${sliceColumns(text, max - 1).text}…`;
417
+ }
418
+
419
+ export function formatJobLine(job: CronJob): string {
420
+ return `${job.id} — ${describeCadence(job.cron)} (${job.recurring ? "recurring" : "one-shot"}) [session-only]: ${clipPrompt(job.prompt)}`;
421
+ }
422
+
423
+ export function formatJobList(jobs: CronJob[]): string {
424
+ return jobs.length ? jobs.map(formatJobLine).join("\n") : "No scheduled jobs.";
425
+ }
426
+
427
+ export function formatDeleteResult(id: string): string {
428
+ return `Cancelled job ${id}.`;
429
+ }
430
+
431
+ export function formatUnknownJob(id: string): string {
432
+ return `No scheduled job with id '${id}'`;
433
+ }
434
+
435
+ export function formatCannotFire(): string {
436
+ return "This is a one-shot session: it ends when this turn does, so the job will never fire.";
437
+ }
438
+
439
+ /**
440
+ * Claude Code's descriptions with the durable feature off, the names swapped
441
+ * to ours and "Claude" read as "this session" (the model behind One Code may
442
+ * be any). The jitter sentence is Claude Code's own, understating its code.
443
+ */
444
+ export const CRON_CREATE_DESCRIPTION = `Schedule a prompt to be enqueued at a future time. Use for both recurring schedules and one-shot reminders.
445
+
446
+ Uses standard 5-field cron in the user's local timezone: minute hour day-of-month month day-of-week. "0 9 * * *" means 9am local — no timezone conversion needed.
447
+
448
+ ## One-shot tasks (recurring: false)
449
+
450
+ For "remind me at X" or "at <time>, do Y" requests — fire once then auto-delete.
451
+ Pin minute/hour/day-of-month/month to specific values:
452
+ "remind me at 2:30pm today to check the deploy" → cron: "30 14 <today_dom> <today_month> *", recurring: false
453
+ "tomorrow morning, run the smoke test" → cron: "57 8 <tomorrow_dom> <tomorrow_month> *", recurring: false
454
+
455
+ ## Recurring jobs (recurring: true, the default)
456
+
457
+ For "every N minutes" / "every hour" / "weekdays at 9am" requests:
458
+ "*/5 * * * *" (every 5 min), "0 * * * *" (hourly), "0 9 * * 1-5" (weekdays at 9am local)
459
+
460
+ ## Avoid the :00 and :30 minute marks when the task allows it
461
+
462
+ Every user who asks for "9am" gets \`0 9\`, and every user who asks for "hourly" gets \`0 *\` — which means requests from across the planet land on the API at the same instant. When the user's request is approximate, pick a minute that is NOT 0 or 30:
463
+ "every morning around 9" → "57 8 * * *" or "3 9 * * *" (not "0 9 * * *")
464
+ "hourly" → "7 * * * *" (not "0 * * * *")
465
+ "in an hour or so, remind me to..." → pick whatever minute you land on, don't round
466
+
467
+ Only use minute 0 or 30 when the user names that exact time and clearly means it ("at 9:00 sharp", "at half past", coordinating with a meeting). When in doubt, nudge a few minutes early or late — the user will not notice, and the fleet will.
468
+
469
+ ## Session-only
470
+
471
+ Jobs live only in this session — nothing is written to disk, and the job is gone when the session ends.
472
+
473
+ ## Not for live watching
474
+
475
+ cron_create re-runs a prompt at fixed wall-clock intervals. To watch a log file, process, or command output and be notified the moment something changes, use the monitor tool instead — monitor streams events as they happen; cron polls on a schedule.
476
+
477
+ ## Runtime behavior
478
+
479
+ Jobs only fire while the REPL is idle (not mid-query). The scheduler adds a small deterministic jitter on top of whatever you pick: recurring tasks fire up to 10% of their period late (max 15 min); one-shot tasks landing on :00 or :30 fire up to 90 s early. Picking an off-minute is still the bigger lever.
480
+
481
+ Recurring tasks auto-expire after ${RECURRING_MAX_AGE_DAYS} days — they fire one final time, then are deleted. This bounds session lifetime. Tell the user about the ${RECURRING_MAX_AGE_DAYS}-day limit when scheduling recurring jobs.
482
+
483
+ Returns a job ID you can pass to cron_delete.`;
484
+
485
+ export const CRON_CREATE_PARAMS = {
486
+ cron: 'Standard 5-field cron expression in local time: "M H DoM Mon DoW" (e.g. "*/5 * * * *" = every 5 minutes, "30 14 28 2 *" = Feb 28 at 2:30pm local once).',
487
+ prompt: "The prompt to enqueue at each fire time.",
488
+ /** Claude Code's text with its durable mode off, as on the account One Code matches (decisions/tools.md, "Session cron"). */
489
+ durable: "Has no effect — durable persistence is not available. All jobs are session-only (in-memory, gone when this session ends).",
490
+ recurring: `true (default) = fire on every cron match until deleted or auto-expired after ${RECURRING_MAX_AGE_DAYS} days. false = fire once at the next match, then auto-delete. Use false for "remind me at X" one-shot requests with pinned minute/hour/dom/month.`,
491
+ };
492
+
493
+ export const CRON_LIST_DESCRIPTION = "List all cron jobs scheduled via cron_create in this session.";
494
+
495
+ /**
496
+ * The three tools' parameters, shared by the main session's tools and a
497
+ * subagent's proxies (lib/agent-cron.ts). `durable` is accepted and ignored,
498
+ * as in Claude Code with its durable mode off; cron_list and cron_delete stay
499
+ * open to stray fields like our other tools (deepseek sends `query` to an
500
+ * empty schema; decisions/tools.md, "Session cron").
501
+ */
502
+ export const CRON_CREATE_PARAMETERS = Type.Object(
503
+ {
504
+ cron: Type.String({ description: CRON_CREATE_PARAMS.cron }),
505
+ prompt: Type.String({ description: CRON_CREATE_PARAMS.prompt }),
506
+ recurring: Type.Optional(Type.Boolean({ description: CRON_CREATE_PARAMS.recurring })),
507
+ durable: Type.Optional(Type.Boolean({ description: CRON_CREATE_PARAMS.durable })),
508
+ },
509
+ { additionalProperties: false },
510
+ );
511
+ export const CRON_LIST_PARAMETERS = Type.Object({});
512
+
513
+ export const CRON_DELETE_DESCRIPTION = "Cancel a cron job previously scheduled with cron_create. Removes it from the in-memory session store.";
514
+ export const CRON_DELETE_ID_DESCRIPTION = "Job ID returned by cron_create.";
515
+ export const CRON_DELETE_PARAMETERS = Type.Object({ id: Type.String({ description: CRON_DELETE_ID_DESCRIPTION }) });