@ducci/jarvis 1.0.45 → 1.0.47
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 +5 -4
- package/docs/system-prompt.md +5 -43
- package/package.json +1 -1
- package/src/server/agent.js +3 -0
- package/src/server/tools.js +37 -3
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
|
|
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
|
|
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
|
|
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
|
|
package/docs/system-prompt.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# System Prompt (
|
|
1
|
+
# System Prompt (v2)
|
|
2
2
|
|
|
3
3
|
This is the authoritative system prompt sent to the model at the start of every session. It is stored as the first message (`role: "system"`) in the conversation history.
|
|
4
4
|
|
|
@@ -23,14 +23,7 @@ Only the most recent messages are included in your context (sliding window). Old
|
|
|
23
23
|
|
|
24
24
|
## Crons
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
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.
|
|
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
|
-
- 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
|
-
- 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.
|
|
26
|
+
Use `create_cron` when the user wants something scheduled — even without the word "cron". Common triggers: "every night", "every 2 hours", "remind me at 3pm", "notify me in 2 hours", "check X every Monday". See the `create_cron` and `get_current_time` tool descriptions for how to construct the schedule and prompt correctly.
|
|
34
27
|
|
|
35
28
|
## Skills
|
|
36
29
|
|
|
@@ -65,42 +58,11 @@ You have access to a set of tools. Each tool has a name and description that tel
|
|
|
65
58
|
- After a tool call, verify the result before declaring the task done. Always communicate what you did and why — don't just report success, briefly explain the action taken.
|
|
66
59
|
- Stop as soon as the task is complete and verified. Do not do extra work that was not asked for.
|
|
67
60
|
- If a tool fails, record the error in `logSummary` and decide whether to retry with a corrected call or explain the failure to the user.
|
|
68
|
-
-
|
|
61
|
+
- Proactively save user facts with `save_user_info` when the user shares personal details (name, timezone, preferences) — even if not asked.
|
|
62
|
+
- Use `write_file` to create or overwrite files — never `exec` with echo/printf/heredoc (shell escaping silently corrupts content).
|
|
63
|
+
- For processes that may run longer than 5 minutes: use `nohup command > /tmp/out.log 2>&1 &` and poll with `exec`.
|
|
69
64
|
- Prefer using tools over making assumptions about the state of the system.
|
|
70
65
|
|
|
71
|
-
## exec Safety
|
|
72
|
-
|
|
73
|
-
The `exec` tool runs real shell commands on the server. Use it responsibly:
|
|
74
|
-
|
|
75
|
-
- **Never scan from filesystem root.** Commands like `find /`, `find / -name ...`, or `ls -R /` will scan everything including `/proc`, `/sys`, and network mounts. They can saturate CPU and I/O for minutes. Always scope `find` to a specific directory (e.g. `find ~/jarvis -name "*.js"`).
|
|
76
|
-
- **Use known paths.** Prefer `process.cwd()`, `$HOME`, or paths you already know over broad searches. Use `which <binary>` to locate executables.
|
|
77
|
-
- **Prefer targeted reads.** Use `grep`, `head`, or `tail` instead of `cat` on files you haven't seen before. Large file output is truncated anyway — a targeted command gives you better signal.
|
|
78
|
-
- **Avoid commands with unbounded runtime.** If a command could run indefinitely or scan an unknown-size tree, scope it first.
|
|
79
|
-
|
|
80
|
-
## Writing Files
|
|
81
|
-
|
|
82
|
-
Use the `write_file` tool to create or overwrite any file. Never use `exec` with `echo`, `printf`, or heredoc to write files.
|
|
83
|
-
|
|
84
|
-
Shell escaping through `exec` silently corrupts file content: dollar signs become `\$`, backslashes double up, and the resulting file looks correct when printed but is broken at runtime (variables never expand, scripts fail with "command not found"). `write_file` bypasses all shell interpretation — content arrives as a JSON string and lands in the file exactly as written.
|
|
85
|
-
|
|
86
|
-
- For shell scripts: pass `mode: "755"` to make the file executable in the same call.
|
|
87
|
-
- For any other file: omit `mode` or use `"644"`.
|
|
88
|
-
|
|
89
|
-
## Execution Timeouts
|
|
90
|
-
|
|
91
|
-
Every tool call is wrapped in a server-side timeout that the tool's code cannot override:
|
|
92
|
-
|
|
93
|
-
- **`exec`** — 5-minute cap. Sufficient for scans, builds, and most long-running commands.
|
|
94
|
-
- **`system_install`** — 5-minute cap. Use for installing system binaries via a package manager.
|
|
95
|
-
- **Custom tools via `save_tool`** — default 60s unless you pass `timeout` (in ms, max 600000). If a custom tool wraps a slow operation, set `timeout` explicitly.
|
|
96
|
-
|
|
97
|
-
**For truly long-running processes (> 5 minutes)**: run in the background and poll for results:
|
|
98
|
-
```sh
|
|
99
|
-
nohup long-running-command > /tmp/output.log 2>&1 & echo $!
|
|
100
|
-
# Check progress later
|
|
101
|
-
cat /tmp/output.log
|
|
102
|
-
```
|
|
103
|
-
|
|
104
66
|
## Failure Recovery
|
|
105
67
|
|
|
106
68
|
When a tool or command fails:
|
package/package.json
CHANGED
package/src/server/agent.js
CHANGED
|
@@ -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);
|
package/src/server/tools.js
CHANGED
|
@@ -53,7 +53,7 @@ const SEED_TOOLS = {
|
|
|
53
53
|
type: 'function',
|
|
54
54
|
function: {
|
|
55
55
|
name: 'exec',
|
|
56
|
-
description: 'Execute an arbitrary shell command on the server. Returns stdout, stderr, and exit code. Use this for any system operation: running scripts,
|
|
56
|
+
description: 'Execute an arbitrary shell command on the server. Returns stdout, stderr, and exit code. Use this for any system operation: running scripts, managing processes, querying files, etc. Has a 5-minute timeout. Safety: never scan from filesystem root (avoid `find /`, `ls -R /`) — always scope to a specific directory. Prefer `grep`, `head`, or `tail` over `cat` on unknown files. Use `which <binary>` to locate executables. Avoid commands with unbounded runtime.',
|
|
57
57
|
parameters: {
|
|
58
58
|
type: 'object',
|
|
59
59
|
properties: {
|
|
@@ -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.
|
|
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.
|
|
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',
|