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.
- package/README.md +152 -0
- package/install.ps1 +22 -0
- package/install.sh +19 -0
- package/package.json +44 -0
- package/src/agent.js +226 -0
- package/src/commands.js +193 -0
- package/src/index.js +86 -0
- package/src/ollama.js +126 -0
- package/src/registry.js +112 -0
- package/src/tools/context.js +432 -0
- package/src/tools/deep-research.js +425 -0
- package/src/tools/documents.js +299 -0
- package/src/tools/filesystem.js +402 -0
- package/src/tools/shell.js +134 -0
- package/src/tools/system.js +379 -0
- package/src/tools/web.js +433 -0
- package/src/ui/charts.js +213 -0
- package/src/ui/export.js +141 -0
- package/src/ui/formatter.js +365 -0
- package/src/ui/images.js +153 -0
- package/src/ui/panels.js +150 -0
- package/src/ui/progress.js +131 -0
- package/src/ui/repl.js +477 -0
- package/src/ui/spinner.js +99 -0
- package/src/ui/table.js +145 -0
|
@@ -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
|
+
};
|