@ducci/jarvis 1.0.45 → 1.0.46

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.
package/docs/crons.md CHANGED
@@ -51,7 +51,7 @@ For one-time tasks specified as relative times ("in 2 hours", "at 3pm today"), t
51
51
 
52
52
  Notification is opt-in via the prompt. Include this in the prompt when you want a notification:
53
53
 
54
- > "When done, use `send_telegram_message` to notify the user with the result."
54
+ > "When done, use `send_telegram_message` to notify the user with the result. Prefix the message with [Cron: \"backup-nightly\" | <current timestamp>]."
55
55
 
56
56
  If you don't want a notification, omit it. The agent follows the prompt literally — conditional notifications work naturally:
57
57
 
@@ -59,7 +59,7 @@ If you don't want a notification, omit it. The agent follows the prompt literall
59
59
 
60
60
  ## Dynamic Scheduling
61
61
 
62
- When `create_cron` runs successfully, the agent loop immediately registers the new cron in the in-memory scheduler — no server restart required. `delete_cron` unregisters it immediately as well.
62
+ When `create_cron`, `update_cron`, or `delete_cron` runs successfully, the agent loop immediately updates the in-memory scheduler — no server restart required.
63
63
 
64
64
  On server restart, all crons in `crons.json` are re-loaded and rescheduled. `once: true` crons that already fired (and deleted themselves) are gone from the file and will not re-run.
65
65
 
@@ -77,7 +77,7 @@ Each cron has its own JSONL log at `~/.jarvis/logs/cron-<id>.jsonl`. One entry p
77
77
  }
78
78
  ```
79
79
 
80
- Use `read_cron_log` to inspect past runs. Ask Jarvis "did my backup run last night?" and it will call `list_crons` + `read_cron_log`.
80
+ Use `read_cron_log` with a cron id to inspect a specific cron, or without an id to get an overview of the last 8 active crons (5 entries each), sorted by time. Ask Jarvis "did my backup run last night?" and it will call `list_crons` + `read_cron_log`.
81
81
 
82
82
  ## Tools
83
83
 
@@ -85,8 +85,9 @@ Use `read_cron_log` to inspect past runs. Ask Jarvis "did my backup run last nig
85
85
  |---|---|
86
86
  | `create_cron` | Schedule a new cron job |
87
87
  | `list_crons` | List all active crons |
88
+ | `update_cron` | Modify an existing cron (name, schedule, prompt, once) |
88
89
  | `delete_cron` | Remove a cron by name or id |
89
- | `read_cron_log` | Read execution history for a cron |
90
+ | `read_cron_log` | Read execution history — omit id for cross-cron overview |
90
91
  | `get_current_time` | Get current server time for relative scheduling |
91
92
  | `send_telegram_message` | Send a proactive message to the Telegram user |
92
93
 
@@ -26,11 +26,11 @@ Only the most recent messages are included in your context (sliding window). Old
26
26
  You can schedule recurring or one-time tasks using cron jobs.
27
27
 
28
28
  - Use `create_cron` when the user wants to schedule something — even if they don't say "cron". Triggers: "every night", "every 2 hours", "remind me at 3pm", "notify me in 2 hours", "check X every Monday", etc.
29
- - Call `get_current_time` first when the user specifies a relative time (e.g. "in 2 hours") so you can calculate the correct cron expression.
29
+ - Call `get_current_time` first when the user specifies a time. Note: `get_current_time` returns server time — if you know the user's timezone, convert the desired user-local time to server time before computing the cron expression.
30
30
  - The `prompt` stored in the cron is executed by a fresh agent with no prior conversation context. Write it as a complete, self-contained instruction.
31
31
  - If the user wants to be notified, include "use send_telegram_message to notify the user with the result" in the prompt. If they explicitly don't want a notification, omit it.
32
32
  - For one-time tasks, set `once: true` — the cron deletes itself after firing.
33
- - Use `list_crons` to show active crons, `delete_cron` to remove one, `read_cron_log` to inspect past runs.
33
+ - Use `list_crons` to show active crons, `update_cron` to modify one, `delete_cron` to remove one, `read_cron_log` to inspect past runs.
34
34
 
35
35
  ## Skills
36
36
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ducci/jarvis",
3
- "version": "1.0.45",
3
+ "version": "1.0.46",
4
4
  "description": "A fully automated agent system that lives on a server.",
5
5
  "main": "./src/index.js",
6
6
  "type": "module",
@@ -241,6 +241,9 @@ export async function runAgentLoop(client, config, session, prepareMessages, usa
241
241
  if (toolName === 'create_cron') {
242
242
  const cronEntry = JSON.parse(resultStr)?.cron;
243
243
  if (cronEntry) cronScheduler.schedule(cronEntry);
244
+ } else if (toolName === 'update_cron') {
245
+ const cronEntry = JSON.parse(resultStr)?.cron;
246
+ if (cronEntry) { cronScheduler.unschedule(cronEntry.id); cronScheduler.schedule(cronEntry); }
244
247
  } else if (toolName === 'delete_cron') {
245
248
  const id = JSON.parse(resultStr)?.id;
246
249
  if (id) cronScheduler.unschedule(id);
@@ -364,7 +364,7 @@ const SEED_TOOLS = {
364
364
  type: 'function',
365
365
  function: {
366
366
  name: 'get_current_time',
367
- description: 'Returns the current server time. Call this before scheduling a cron job when the user specifies a relative time (e.g. "in 2 hours", "at 3pm today") so you can calculate the correct schedule.',
367
+ description: 'Returns the current server time. Always call this before creating a cron. Note: returns server time if you know the user\'s timezone, convert the desired user-local time to server time before computing the cron expression.',
368
368
  parameters: { type: 'object', properties: {}, required: [] },
369
369
  },
370
370
  },
@@ -383,7 +383,7 @@ const SEED_TOOLS = {
383
383
  type: 'function',
384
384
  function: {
385
385
  name: 'create_cron',
386
- description: 'Schedule a recurring or one-time task. The prompt is executed by a fresh agent with no prior context — write it as a self-contained task. For one-time tasks (e.g. "remind me in 2 hours"), set once: true. Call get_current_time first when calculating a relative schedule.',
386
+ description: 'Schedule a recurring or one-time task. The prompt is executed by a fresh agent with no prior context — write it as a self-contained task. For one-time tasks (e.g. "remind me in 2 hours"), set once: true. Always call get_current_time first and convert user-local time to server time before computing the cron expression.',
387
387
  parameters: {
388
388
  type: 'object',
389
389
  properties: {
@@ -429,6 +429,40 @@ const SEED_TOOLS = {
429
429
  return { status: 'ok', crons };
430
430
  `,
431
431
  },
432
+ update_cron: {
433
+ definition: {
434
+ type: 'function',
435
+ function: {
436
+ name: 'update_cron',
437
+ description: 'Update an existing cron job. Only the fields you provide will be changed. If updating the schedule, call get_current_time first and convert user-local time to server time before computing the cron expression.',
438
+ parameters: {
439
+ type: 'object',
440
+ properties: {
441
+ id: { type: 'string', description: 'The cron id to update.' },
442
+ name: { type: 'string', description: 'New name.' },
443
+ schedule: { type: 'string', description: 'New cron expression.' },
444
+ prompt: { type: 'string', description: 'New prompt.' },
445
+ once: { type: 'boolean', description: 'New once value.' },
446
+ },
447
+ required: ['id'],
448
+ },
449
+ },
450
+ },
451
+ code: `
452
+ const cronsFile = path.join(process.env.HOME, '.jarvis/data/crons.json');
453
+ const crons = JSON.parse(await fs.promises.readFile(cronsFile, 'utf8').catch(() => '[]'));
454
+ const idx = crons.findIndex(c => c.id === args.id);
455
+ if (idx === -1) return { status: 'not_found' };
456
+ const updated = { ...crons[idx] };
457
+ if (args.name !== undefined) updated.name = args.name;
458
+ if (args.schedule !== undefined) updated.schedule = args.schedule;
459
+ if (args.prompt !== undefined) updated.prompt = args.prompt;
460
+ if (args.once !== undefined) updated.once = args.once;
461
+ crons[idx] = updated;
462
+ await fs.promises.writeFile(cronsFile, JSON.stringify(crons, null, 2), 'utf8');
463
+ return { status: 'ok', cron: updated };
464
+ `,
465
+ },
432
466
  delete_cron: {
433
467
  definition: {
434
468
  type: 'function',