@ducci/jarvis 1.0.44 → 1.0.45

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/server/tools.js +23 -51
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ducci/jarvis",
3
- "version": "1.0.44",
3
+ "version": "1.0.45",
4
4
  "description": "A fully automated agent system that lives on a server.",
5
5
  "main": "./src/index.js",
6
6
  "type": "module",
@@ -389,7 +389,7 @@ const SEED_TOOLS = {
389
389
  properties: {
390
390
  name: { type: 'string', description: 'Short identifier for this cron, e.g. "backup-nightly".' },
391
391
  schedule: { type: 'string', description: 'Cron expression, e.g. "0 3 * * *" for 3am daily. For a one-time task, compute the exact time from get_current_time and express it as a cron expression.' },
392
- prompt: { type: 'string', description: 'The task prompt the agent will receive when this cron fires. Must be self-contained. Include "use send_telegram_message to notify the user with the result" if notification is desired.' },
392
+ prompt: { type: 'string', description: 'The task prompt the agent will receive when this cron fires. Must be self-contained. If notification is desired, include: "use send_telegram_message to notify the user with the result. Prefix the message with [Cron: \"<name>\" | <timestamp>] where <name> is the cron name and <timestamp> is the current date and time."' },
393
393
  once: { type: 'boolean', description: 'If true, the cron deletes itself after firing once. Use for one-time reminders or tasks.' },
394
394
  },
395
395
  required: ['name', 'schedule', 'prompt'],
@@ -513,24 +513,40 @@ const SEED_TOOLS = {
513
513
  type: 'function',
514
514
  function: {
515
515
  name: 'read_cron_log',
516
- description: 'Read the execution log for a cron job. Returns the most recent runs with status, response, and logSummary.',
516
+ description: 'Read cron execution logs. Without id: returns recent runs across all crons (last 8 most recently active cron files, 5 entries each). With id: returns runs for that specific cron.',
517
517
  parameters: {
518
518
  type: 'object',
519
519
  properties: {
520
- id: { type: 'string', description: 'The cron id.' },
521
- limit: { type: 'number', description: 'Max entries to return. Defaults to 20.' },
520
+ id: { type: 'string', description: 'The cron id. Omit to get an overview across all crons.' },
521
+ limit: { type: 'number', description: 'Max entries to return when reading a specific cron. Defaults to 20.' },
522
522
  },
523
- required: ['id'],
523
+ required: [],
524
524
  },
525
525
  },
526
526
  },
527
527
  code: `
528
528
  const logsDir = path.join(process.env.HOME, '.jarvis/logs');
529
+ if (!args.id) {
530
+ const files = await fs.promises.readdir(logsDir).catch(() => []);
531
+ const cronFiles = files.filter(f => f.startsWith('cron-') && f.endsWith('.jsonl'));
532
+ const withMtime = await Promise.all(cronFiles.map(async f => {
533
+ const stat = await fs.promises.stat(path.join(logsDir, f));
534
+ return { file: f, mtime: stat.mtimeMs };
535
+ }));
536
+ withMtime.sort((a, b) => b.mtime - a.mtime);
537
+ const allEntries = [];
538
+ for (const { file } of withMtime.slice(0, 8)) {
539
+ const content = await fs.promises.readFile(path.join(logsDir, file), 'utf8').catch(() => '');
540
+ const lines = content.trim().split('\\n').filter(Boolean);
541
+ allEntries.push(...lines.slice(-5).map(line => JSON.parse(line)));
542
+ }
543
+ allEntries.sort((a, b) => new Date(b.ts) - new Date(a.ts));
544
+ return { status: 'ok', entries: allEntries };
545
+ }
529
546
  const logFile = path.join(logsDir, 'cron-' + args.id + '.jsonl');
530
547
  const content = await fs.promises.readFile(logFile, 'utf8').catch(() => '');
531
548
  const lines = content.trim().split('\\n').filter(Boolean);
532
- const limit = args.limit || 20;
533
- const entries = lines.slice(-limit).map(line => JSON.parse(line));
549
+ const entries = lines.slice(-(args.limit || 20)).map(line => JSON.parse(line));
534
550
  return { status: 'ok', entries };
535
551
  `,
536
552
  },
@@ -562,50 +578,6 @@ const SEED_TOOLS = {
562
578
  return { status: 'ok', name: args.name, content };
563
579
  `,
564
580
  },
565
- get_recent_sessions: {
566
- definition: {
567
- type: 'function',
568
- function: {
569
- name: 'get_recent_sessions',
570
- description: 'Returns the most recent sessions with their titles and timestamps. Use this to find previous conversations.',
571
- parameters: {
572
- type: 'object',
573
- properties: {
574
- limit: {
575
- type: 'number',
576
- description: 'Number of recent sessions to return. Defaults to 2.',
577
- },
578
- },
579
- required: [],
580
- },
581
- },
582
- },
583
- code: `const logsDir = path.join(process.env.HOME, '.jarvis/logs'); const limit = args.limit || 2; const files = await fs.promises.readdir(logsDir).catch(() => []); const sessionFiles = files.filter(f => f.startsWith('session-') && f.endsWith('.jsonl')); const sessions = []; for (const file of sessionFiles) { const sessionId = file.replace('session-', '').replace('.jsonl', ''); const content = await fs.promises.readFile(path.join(logsDir, file), 'utf8'); const lines = content.trim().split('\\n').filter(Boolean); if (lines.length === 0) continue; const firstEntry = JSON.parse(lines[0]); const lastEntry = JSON.parse(lines[lines.length - 1]); sessions.push({ sessionId, title: (firstEntry.logSummary || '').substring(0, 80), lastTs: lastEntry.ts }); } sessions.sort((a, b) => new Date(b.lastTs) - new Date(a.lastTs)); return { status: 'ok', sessions: sessions.slice(0, limit) };`,
584
- },
585
- read_session_log: {
586
- definition: {
587
- type: 'function',
588
- function: {
589
- name: 'read_session_log',
590
- description: 'Read JSONL log entries for a given session. Use this to inspect what happened in a previous run, including tool calls, errors, and summaries.',
591
- parameters: {
592
- type: 'object',
593
- properties: {
594
- sessionId: {
595
- type: 'string',
596
- description: 'The session ID to read logs for.',
597
- },
598
- limit: {
599
- type: 'number',
600
- description: 'Maximum number of entries to return (from the end). Defaults to 20.',
601
- },
602
- },
603
- required: ['sessionId'],
604
- },
605
- },
606
- },
607
- code: `const logsDir = path.join(process.env.HOME, '.jarvis/logs'); const logFile = path.join(logsDir, 'session-' + args.sessionId + '.jsonl'); const content = await fs.promises.readFile(logFile, 'utf8').catch(() => ''); const lines = content.trim().split('\\n').filter(Boolean); const limit = args.limit || 20; const entries = lines.slice(-limit).map(line => JSON.parse(line)); return { status: 'ok', entries };`,
608
- },
609
581
  };
610
582
 
611
583
  export function seedTools() {