prior-cli 1.4.4 → 1.5.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/bin/prior.js +71 -3
- package/lib/agent.js +1 -1
- package/lib/tools.js +42 -3
- package/package.json +1 -1
package/bin/prior.js
CHANGED
|
@@ -390,7 +390,69 @@ function hyperlink(text, url) {
|
|
|
390
390
|
|
|
391
391
|
const PREVIEW_TOOLS = new Set(['file_read', 'run_command', 'web_search', 'url_fetch']);
|
|
392
392
|
|
|
393
|
-
|
|
393
|
+
// ── Weather condition code → emoji ────────────────────────────
|
|
394
|
+
function weatherIcon(code) {
|
|
395
|
+
if (code === 113) return '☀️ ';
|
|
396
|
+
if (code === 116) return '⛅ ';
|
|
397
|
+
if (code === 119 || code === 122) return '☁️ ';
|
|
398
|
+
if (code === 143 || code === 248 || code === 260) return '🌫️';
|
|
399
|
+
if (code >= 176 && code <= 182) return '🌦️';
|
|
400
|
+
if (code >= 185 && code <= 227) return '🌨️';
|
|
401
|
+
if (code === 230) return '❄️ ';
|
|
402
|
+
if (code >= 248 && code <= 260) return '🌫️';
|
|
403
|
+
if (code >= 263 && code <= 296) return '🌧️';
|
|
404
|
+
if (code >= 299 && code <= 314) return '🌧️';
|
|
405
|
+
if (code >= 317 && code <= 338) return '🌨️';
|
|
406
|
+
if (code >= 350 && code <= 395) return '⛈️ ';
|
|
407
|
+
return '🌡️';
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
function dayLabel(dateStr) {
|
|
411
|
+
if (!dateStr) return ' ';
|
|
412
|
+
const d = new Date(dateStr);
|
|
413
|
+
return ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'][d.getDay()];
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function renderWeatherCard(w) {
|
|
417
|
+
const W = 42;
|
|
418
|
+
const pad = (str, len) => {
|
|
419
|
+
const plain = str.replace(/\x1b\[[0-9;]*m/g, '');
|
|
420
|
+
return str + ' '.repeat(Math.max(0, len - plain.length));
|
|
421
|
+
};
|
|
422
|
+
const line = (content = '') => {
|
|
423
|
+
process.stdout.write(c.muted(' │ ') + content + c.muted(' │') + '\n');
|
|
424
|
+
};
|
|
425
|
+
const rule = ' ├' + '─'.repeat(W) + '┤';
|
|
426
|
+
const top = ' ╭' + '─'.repeat(W) + '╮';
|
|
427
|
+
const bot = ' ╰' + '─'.repeat(W) + '╯';
|
|
428
|
+
|
|
429
|
+
const location = `📍 ${w.city}${w.country ? ', ' + w.country : ''}`;
|
|
430
|
+
const icon = weatherIcon(w.code);
|
|
431
|
+
const condLine = `${icon} ${w.desc}`;
|
|
432
|
+
const tempLine = `🌡 ${w.tempC}°C ${c.dim(`feels like ${w.feelsC}°C`)}`;
|
|
433
|
+
const infoLine = `💧 ${w.humidity}% 💨 ${w.windKmph} km/h`;
|
|
434
|
+
|
|
435
|
+
process.stdout.write(c.muted(top) + '\n');
|
|
436
|
+
line(pad(c.bold(location), W));
|
|
437
|
+
line();
|
|
438
|
+
line(pad(condLine, W));
|
|
439
|
+
line(pad(tempLine, W + 9)); // +9 for dim escape codes
|
|
440
|
+
line(pad(c.dim(infoLine), W + 9));
|
|
441
|
+
|
|
442
|
+
if (w.forecast && w.forecast.length) {
|
|
443
|
+
process.stdout.write(c.muted(rule) + '\n');
|
|
444
|
+
const days = w.forecast.map(f => pad(c.dim(dayLabel(f.date)), 12)).join(' ');
|
|
445
|
+
const icons = w.forecast.map(f => pad(weatherIcon(f.code), 12)).join(' ');
|
|
446
|
+
const temps = w.forecast.map(f => pad(c.dim(`${f.maxC}° / ${f.minC}°`), 12 + 9)).join(' ');
|
|
447
|
+
line(days);
|
|
448
|
+
line(icons);
|
|
449
|
+
line(temps);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
process.stdout.write(c.muted(bot) + '\n');
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
function renderToolDone(name, summary, preview, weatherData) {
|
|
394
456
|
const took = _toolStartTime ? c.dim(` · ${elapsed(Date.now() - _toolStartTime)}`) : '';
|
|
395
457
|
let display = summary || '';
|
|
396
458
|
if (/^[a-zA-Z]:[/\\]/.test(display) || display.startsWith('/')) {
|
|
@@ -401,6 +463,12 @@ function renderToolDone(name, summary, preview) {
|
|
|
401
463
|
}
|
|
402
464
|
process.stdout.write(` ${c.ok('✓')} ${c.muted(name)} ${display}${took}\n`);
|
|
403
465
|
|
|
466
|
+
// Weather card
|
|
467
|
+
if (name === 'get_weather' && weatherData) {
|
|
468
|
+
renderWeatherCard(weatherData);
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
|
|
404
472
|
// Rich preview for certain tools
|
|
405
473
|
if (preview && PREVIEW_TOOLS.has(name)) {
|
|
406
474
|
const lines = String(preview).split('\n').filter(l => l.trim());
|
|
@@ -927,7 +995,7 @@ Keep it under 350 words. Write prior.md now.`;
|
|
|
927
995
|
renderToolStart(ev.name, ev.args);
|
|
928
996
|
spinStart('working…');
|
|
929
997
|
break;
|
|
930
|
-
case 'tool_done': spinStop(); renderToolDone(ev.name, ev.summary, ev.preview); break;
|
|
998
|
+
case 'tool_done': spinStop(); renderToolDone(ev.name, ev.summary, ev.preview, ev.weather); break;
|
|
931
999
|
case 'tool_error': spinStop(); renderToolError(ev.name, ev.error); break;
|
|
932
1000
|
case 'text':
|
|
933
1001
|
spinStop();
|
|
@@ -1094,7 +1162,7 @@ Keep it under 350 words. Write prior.md now.`;
|
|
|
1094
1162
|
|
|
1095
1163
|
case 'tool_done':
|
|
1096
1164
|
spinStop();
|
|
1097
|
-
renderToolDone(ev.name, ev.summary, ev.preview);
|
|
1165
|
+
renderToolDone(ev.name, ev.summary, ev.preview, ev.weather);
|
|
1098
1166
|
break;
|
|
1099
1167
|
|
|
1100
1168
|
case 'tool_skip':
|
package/lib/agent.js
CHANGED
|
@@ -289,7 +289,7 @@ async function runAgent({ messages, model, uncensored, cwd, projectContext, imag
|
|
|
289
289
|
try {
|
|
290
290
|
const toolResult = await executeTool(call.name, call.args, { cwd, token, send });
|
|
291
291
|
// Pass output snippet so the CLI can show a rich preview
|
|
292
|
-
send({ type: 'tool_done', name: call.name, summary: toolResult.summary, preview: toolResult.output });
|
|
292
|
+
send({ type: 'tool_done', name: call.name, summary: toolResult.summary, preview: toolResult.output, weather: toolResult.weather });
|
|
293
293
|
resultParts.push(`<tool_result name="${call.name}">\n${toolResult.output}\n</tool_result>`);
|
|
294
294
|
} catch (err) {
|
|
295
295
|
send({ type: 'tool_error', name: call.name, error: err.message });
|
package/lib/tools.js
CHANGED
|
@@ -160,6 +160,45 @@ const TOOLS = {
|
|
|
160
160
|
};
|
|
161
161
|
},
|
|
162
162
|
|
|
163
|
+
async get_weather({ location }, {}) {
|
|
164
|
+
if (!location) throw new Error('"location" is required');
|
|
165
|
+
const encoded = encodeURIComponent(location);
|
|
166
|
+
const res = await fetch(`https://wttr.in/${encoded}?format=j1`, {
|
|
167
|
+
headers: { 'User-Agent': 'prior-cli/1.0' },
|
|
168
|
+
timeout: 10000,
|
|
169
|
+
});
|
|
170
|
+
if (!res.ok) throw new Error(`Weather service error: HTTP ${res.status}`);
|
|
171
|
+
const data = await res.json();
|
|
172
|
+
|
|
173
|
+
const cur = data.current_condition?.[0] || {};
|
|
174
|
+
const area = data.nearest_area?.[0] || {};
|
|
175
|
+
const city = area.areaName?.[0]?.value || location;
|
|
176
|
+
const country = area.country?.[0]?.value || '';
|
|
177
|
+
|
|
178
|
+
const tempC = cur.temp_C || '?';
|
|
179
|
+
const feelsC = cur.FeelsLikeC || '?';
|
|
180
|
+
const humidity = cur.humidity || '?';
|
|
181
|
+
const windKmph = cur.windspeedKmph || '?';
|
|
182
|
+
const desc = cur.weatherDesc?.[0]?.value || '?';
|
|
183
|
+
const code = parseInt(cur.weatherCode || '113');
|
|
184
|
+
|
|
185
|
+
const forecast = (data.weather || []).slice(0, 3).map(d => ({
|
|
186
|
+
date: d.date,
|
|
187
|
+
maxC: d.maxtempC,
|
|
188
|
+
minC: d.mintempC,
|
|
189
|
+
desc: d.hourly?.[4]?.weatherDesc?.[0]?.value || '',
|
|
190
|
+
code: parseInt(d.hourly?.[4]?.weatherCode || '113'),
|
|
191
|
+
}));
|
|
192
|
+
|
|
193
|
+
// Build structured output for CLI to render as a card
|
|
194
|
+
const result = { city, country, tempC, feelsC, humidity, windKmph, desc, code, forecast };
|
|
195
|
+
return {
|
|
196
|
+
output: JSON.stringify(result),
|
|
197
|
+
summary: `${city}${country ? ', ' + country : ''} · ${tempC}°C · ${desc}`,
|
|
198
|
+
weather: result,
|
|
199
|
+
};
|
|
200
|
+
},
|
|
201
|
+
|
|
163
202
|
async web_search({ query }, { token }) {
|
|
164
203
|
if (!query) throw new Error('"query" is required');
|
|
165
204
|
const res = await fetch(`${CLI_BASE}/api/web-search`, {
|
|
@@ -328,10 +367,10 @@ const TOOLS = {
|
|
|
328
367
|
return {
|
|
329
368
|
output: [
|
|
330
369
|
`Username : @${u.username || '?'}`,
|
|
331
|
-
`Display Name : ${u.display_name || u.username || '?'}`,
|
|
370
|
+
`Display Name : ${u.display_name || u.displayName || u.username || '?'}`,
|
|
332
371
|
`Bio : ${u.bio || '(none)'}`,
|
|
333
|
-
`Posts : ${u.post_count ?? 0}`,
|
|
334
|
-
`Friends : ${u.friend_count ?? 0}`,
|
|
372
|
+
`Posts : ${u.post_count ?? u.posts_count ?? 0}`,
|
|
373
|
+
`Friends : ${u.friend_count ?? u.friends_count ?? 0}`,
|
|
335
374
|
`Joined : ${u.created_at ? new Date(u.created_at).toLocaleDateString() : 'unknown'}`,
|
|
336
375
|
].join('\n'),
|
|
337
376
|
summary: `@${u.username || '?'}`,
|