scorpion-cli 0.1.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.
@@ -0,0 +1,432 @@
1
+ /**
2
+ * Context Tools
3
+ * Real-time context awareness - date, time, current state of the world
4
+ * This is what makes AI more human-like - knowing "now"
5
+ */
6
+
7
+ import { jinaSearch, jinaFetch } from './web.js';
8
+
9
+ /**
10
+ * Get current date/time with various formats
11
+ */
12
+ function getCurrentDateTime() {
13
+ const now = new Date();
14
+
15
+ return {
16
+ // ISO format
17
+ iso: now.toISOString(),
18
+
19
+ // Human readable
20
+ date: now.toLocaleDateString('en-US', {
21
+ weekday: 'long',
22
+ year: 'numeric',
23
+ month: 'long',
24
+ day: 'numeric'
25
+ }),
26
+ time: now.toLocaleTimeString('en-US', {
27
+ hour: '2-digit',
28
+ minute: '2-digit',
29
+ second: '2-digit',
30
+ hour12: true
31
+ }),
32
+
33
+ // Components
34
+ year: now.getFullYear(),
35
+ month: now.getMonth() + 1,
36
+ day: now.getDate(),
37
+ hour: now.getHours(),
38
+ minute: now.getMinutes(),
39
+ dayOfWeek: now.toLocaleDateString('en-US', { weekday: 'long' }),
40
+
41
+ // Unix timestamp
42
+ timestamp: now.getTime(),
43
+
44
+ // Timezone
45
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
46
+ timezoneOffset: now.getTimezoneOffset()
47
+ };
48
+ }
49
+
50
+ // Tool: get_current_datetime
51
+ export const getCurrentDatetime = {
52
+ schema: {
53
+ type: 'function',
54
+ function: {
55
+ name: 'get_current_datetime',
56
+ description: 'Get the current date and time. Use this whenever you need to know the current date, time, day of week, or year. This provides real-time information.',
57
+ parameters: {
58
+ type: 'object',
59
+ properties: {
60
+ format: {
61
+ type: 'string',
62
+ enum: ['full', 'date', 'time', 'year'],
63
+ description: 'What format to return (default: full)'
64
+ }
65
+ }
66
+ }
67
+ }
68
+ },
69
+ execute: async ({ format = 'full' } = {}) => {
70
+ const dt = getCurrentDateTime();
71
+
72
+ switch (format) {
73
+ case 'date':
74
+ return JSON.stringify({
75
+ success: true,
76
+ date: dt.date,
77
+ dayOfWeek: dt.dayOfWeek,
78
+ year: dt.year
79
+ });
80
+ case 'time':
81
+ return JSON.stringify({
82
+ success: true,
83
+ time: dt.time,
84
+ timezone: dt.timezone
85
+ });
86
+ case 'year':
87
+ return JSON.stringify({
88
+ success: true,
89
+ year: dt.year
90
+ });
91
+ default:
92
+ return JSON.stringify({
93
+ success: true,
94
+ ...dt
95
+ });
96
+ }
97
+ }
98
+ };
99
+
100
+ // Tool: get_current_context
101
+ export const getCurrentContext = {
102
+ schema: {
103
+ type: 'function',
104
+ function: {
105
+ name: 'get_current_context',
106
+ description: 'Get current real-world context including date, time, and user environment. Call this to ground yourself in reality and know what "now" means.',
107
+ parameters: {
108
+ type: 'object',
109
+ properties: {}
110
+ }
111
+ }
112
+ },
113
+ execute: async () => {
114
+ const dt = getCurrentDateTime();
115
+ const os = process.platform;
116
+ const cwd = process.cwd();
117
+ const user = process.env.USERNAME || process.env.USER || 'unknown';
118
+ const home = process.env.USERPROFILE || process.env.HOME || '';
119
+
120
+ return JSON.stringify({
121
+ success: true,
122
+ currentTime: {
123
+ date: dt.date,
124
+ time: dt.time,
125
+ year: dt.year,
126
+ timezone: dt.timezone
127
+ },
128
+ environment: {
129
+ os: os === 'win32' ? 'Windows' : os === 'darwin' ? 'macOS' : 'Linux',
130
+ user,
131
+ homeDirectory: home,
132
+ workingDirectory: cwd
133
+ },
134
+ awareness: {
135
+ note: `The current year is ${dt.year}. Any knowledge you have from training may be outdated. Use web search to get latest information.`
136
+ }
137
+ });
138
+ }
139
+ };
140
+
141
+ // Tool: check_latest_version
142
+ export const checkLatestVersion = {
143
+ schema: {
144
+ type: 'function',
145
+ function: {
146
+ name: 'check_latest_version',
147
+ description: 'Check for the latest version of a software, package, or tool. Use this when you need to know if something has been updated since your training data.',
148
+ parameters: {
149
+ type: 'object',
150
+ required: ['name'],
151
+ properties: {
152
+ name: {
153
+ type: 'string',
154
+ description: 'Name of the software/package to check (e.g., "Node.js", "Python", "React")'
155
+ },
156
+ type: {
157
+ type: 'string',
158
+ enum: ['software', 'npm', 'python', 'general'],
159
+ description: 'Type of package (default: general)'
160
+ }
161
+ }
162
+ }
163
+ }
164
+ },
165
+ execute: async ({ name, type = 'general' }) => {
166
+ try {
167
+ const currentYear = new Date().getFullYear();
168
+
169
+ // Search for latest version
170
+ const query = `${name} latest version ${currentYear}`;
171
+ let results;
172
+
173
+ try {
174
+ results = await jinaSearch(query, 3);
175
+ } catch (e) {
176
+ results = [];
177
+ }
178
+
179
+ // For npm packages, also try the npm registry
180
+ let npmInfo = null;
181
+ if (type === 'npm') {
182
+ try {
183
+ const response = await fetch(`https://registry.npmjs.org/${name}/latest`, {
184
+ headers: { 'Accept': 'application/json' }
185
+ });
186
+ if (response.ok) {
187
+ const data = await response.json();
188
+ npmInfo = {
189
+ name: data.name,
190
+ version: data.version,
191
+ description: data.description,
192
+ lastPublish: data.time?.modified || 'unknown'
193
+ };
194
+ }
195
+ } catch (e) {
196
+ // npm check failed, continue with search results
197
+ }
198
+ }
199
+
200
+ // For Python packages, try PyPI
201
+ let pypiInfo = null;
202
+ if (type === 'python') {
203
+ try {
204
+ const response = await fetch(`https://pypi.org/pypi/${name}/json`);
205
+ if (response.ok) {
206
+ const data = await response.json();
207
+ pypiInfo = {
208
+ name: data.info.name,
209
+ version: data.info.version,
210
+ summary: data.info.summary,
211
+ releaseDate: Object.keys(data.releases).pop()
212
+ };
213
+ }
214
+ } catch (e) {
215
+ // PyPI check failed
216
+ }
217
+ }
218
+
219
+ return JSON.stringify({
220
+ success: true,
221
+ name,
222
+ currentYear,
223
+ note: `Checked on ${new Date().toLocaleDateString()}`,
224
+ npmPackage: npmInfo,
225
+ pypiPackage: pypiInfo,
226
+ searchResults: results.map(r => ({
227
+ title: r.title,
228
+ url: r.url,
229
+ snippet: r.snippet
230
+ })),
231
+ recommendation: `If your knowledge is outdated, trust the search results above for the latest information about ${name}.`
232
+ });
233
+ } catch (error) {
234
+ return JSON.stringify({
235
+ success: false,
236
+ error: error.message,
237
+ name
238
+ });
239
+ }
240
+ }
241
+ };
242
+
243
+ // Tool: calculate_time_difference
244
+ export const calculateTimeDifference = {
245
+ schema: {
246
+ type: 'function',
247
+ function: {
248
+ name: 'calculate_time_difference',
249
+ description: 'Calculate the time difference between two dates or from a date to now. Useful for knowing how old something is.',
250
+ parameters: {
251
+ type: 'object',
252
+ required: ['from_date'],
253
+ properties: {
254
+ from_date: {
255
+ type: 'string',
256
+ description: 'The starting date (ISO format or natural like "2023-01-15")'
257
+ },
258
+ to_date: {
259
+ type: 'string',
260
+ description: 'The ending date (default: now)'
261
+ }
262
+ }
263
+ }
264
+ }
265
+ },
266
+ execute: async ({ from_date, to_date }) => {
267
+ try {
268
+ const from = new Date(from_date);
269
+ const to = to_date ? new Date(to_date) : new Date();
270
+
271
+ if (isNaN(from.getTime())) {
272
+ throw new Error('Invalid from_date');
273
+ }
274
+ if (isNaN(to.getTime())) {
275
+ throw new Error('Invalid to_date');
276
+ }
277
+
278
+ const diffMs = to.getTime() - from.getTime();
279
+ const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
280
+ const diffMonths = Math.floor(diffDays / 30);
281
+ const diffYears = Math.floor(diffDays / 365);
282
+
283
+ let humanReadable = '';
284
+ if (diffYears > 0) {
285
+ humanReadable = `${diffYears} year${diffYears > 1 ? 's' : ''}`;
286
+ const remainingMonths = diffMonths - (diffYears * 12);
287
+ if (remainingMonths > 0) {
288
+ humanReadable += ` and ${remainingMonths} month${remainingMonths > 1 ? 's' : ''}`;
289
+ }
290
+ } else if (diffMonths > 0) {
291
+ humanReadable = `${diffMonths} month${diffMonths > 1 ? 's' : ''}`;
292
+ } else {
293
+ humanReadable = `${diffDays} day${diffDays !== 1 ? 's' : ''}`;
294
+ }
295
+
296
+ return JSON.stringify({
297
+ success: true,
298
+ from: from.toISOString(),
299
+ to: to.toISOString(),
300
+ difference: {
301
+ days: diffDays,
302
+ months: diffMonths,
303
+ years: diffYears,
304
+ humanReadable
305
+ },
306
+ isInPast: diffMs > 0,
307
+ isInFuture: diffMs < 0
308
+ });
309
+ } catch (error) {
310
+ return JSON.stringify({
311
+ success: false,
312
+ error: error.message
313
+ });
314
+ }
315
+ }
316
+ };
317
+
318
+ // Tool: get_timezone_time
319
+ export const getTimezoneTime = {
320
+ schema: {
321
+ type: 'function',
322
+ function: {
323
+ name: 'get_timezone_time',
324
+ description: 'Get the current time in a specific timezone. Useful for knowing what time it is in different parts of the world.',
325
+ parameters: {
326
+ type: 'object',
327
+ required: ['timezone'],
328
+ properties: {
329
+ timezone: {
330
+ type: 'string',
331
+ description: 'Timezone name (e.g., "America/New_York", "Europe/London", "Asia/Tokyo")'
332
+ }
333
+ }
334
+ }
335
+ }
336
+ },
337
+ execute: async ({ timezone }) => {
338
+ try {
339
+ const now = new Date();
340
+
341
+ const options = {
342
+ timeZone: timezone,
343
+ year: 'numeric',
344
+ month: 'long',
345
+ day: 'numeric',
346
+ weekday: 'long',
347
+ hour: '2-digit',
348
+ minute: '2-digit',
349
+ second: '2-digit',
350
+ hour12: true
351
+ };
352
+
353
+ const formatted = now.toLocaleString('en-US', options);
354
+
355
+ return JSON.stringify({
356
+ success: true,
357
+ timezone,
358
+ datetime: formatted,
359
+ iso: now.toLocaleString('en-CA', { timeZone: timezone }).replace(', ', 'T')
360
+ });
361
+ } catch (error) {
362
+ return JSON.stringify({
363
+ success: false,
364
+ error: `Invalid timezone: ${timezone}. Use format like "America/New_York" or "Asia/Tokyo".`
365
+ });
366
+ }
367
+ }
368
+ };
369
+
370
+ // Tool: set_reminder (stores in memory for session)
371
+ const reminders = [];
372
+
373
+ export const setReminder = {
374
+ schema: {
375
+ type: 'function',
376
+ function: {
377
+ name: 'set_reminder',
378
+ description: 'Set a reminder for the current session. Note: Reminders only persist during this session.',
379
+ parameters: {
380
+ type: 'object',
381
+ required: ['message'],
382
+ properties: {
383
+ message: {
384
+ type: 'string',
385
+ description: 'The reminder message'
386
+ },
387
+ time: {
388
+ type: 'string',
389
+ description: 'When to remind (optional, for reference)'
390
+ }
391
+ }
392
+ }
393
+ }
394
+ },
395
+ execute: async ({ message, time }) => {
396
+ const reminder = {
397
+ id: reminders.length + 1,
398
+ message,
399
+ time: time || 'unspecified',
400
+ createdAt: new Date().toISOString()
401
+ };
402
+ reminders.push(reminder);
403
+
404
+ return JSON.stringify({
405
+ success: true,
406
+ reminder,
407
+ totalReminders: reminders.length,
408
+ note: 'Reminder saved for this session'
409
+ });
410
+ }
411
+ };
412
+
413
+ export const listReminders = {
414
+ schema: {
415
+ type: 'function',
416
+ function: {
417
+ name: 'list_reminders',
418
+ description: 'List all reminders set during this session.',
419
+ parameters: {
420
+ type: 'object',
421
+ properties: {}
422
+ }
423
+ }
424
+ },
425
+ execute: async () => {
426
+ return JSON.stringify({
427
+ success: true,
428
+ count: reminders.length,
429
+ reminders
430
+ });
431
+ }
432
+ };