prior-cli 1.4.5 → 1.5.1
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 +57 -3
- package/lib/agent.js +1 -1
- package/lib/tools.js +39 -0
- package/package.json +1 -1
package/bin/prior.js
CHANGED
|
@@ -390,7 +390,55 @@ 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
|
+
// Use left-border-only style — avoids emoji column-width alignment issues
|
|
418
|
+
const L = ' │ ';
|
|
419
|
+
const hr = ' ├─────────────────────────────────────\n';
|
|
420
|
+
|
|
421
|
+
process.stdout.write(c.muted(' ┌─────────────────────────────────────\n'));
|
|
422
|
+
process.stdout.write(c.muted(L) + c.bold(`📍 ${w.city}${w.country ? ', ' + w.country : ''}`) + '\n');
|
|
423
|
+
process.stdout.write(c.muted(L) + '\n');
|
|
424
|
+
process.stdout.write(c.muted(L) + `${weatherIcon(w.code)} ${w.desc}` + '\n');
|
|
425
|
+
process.stdout.write(c.muted(L) + `🌡 ${c.bold(w.tempC + '°C')} ${c.dim('feels like ' + w.feelsC + '°C')}` + '\n');
|
|
426
|
+
process.stdout.write(c.muted(L) + c.dim(`💧 ${w.humidity}% 💨 ${w.windKmph} km/h`) + '\n');
|
|
427
|
+
|
|
428
|
+
if (w.forecast && w.forecast.length) {
|
|
429
|
+
process.stdout.write(c.muted(hr));
|
|
430
|
+
for (const f of w.forecast) {
|
|
431
|
+
const day = dayLabel(f.date).padEnd(4);
|
|
432
|
+
const icon = weatherIcon(f.code);
|
|
433
|
+
const tmp = `${f.maxC}° / ${f.minC}°`;
|
|
434
|
+
process.stdout.write(c.muted(L) + c.dim(day) + ` ${icon} ` + c.dim(tmp) + '\n');
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
process.stdout.write(c.muted(' └─────────────────────────────────────\n'));
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
function renderToolDone(name, summary, preview, weatherData) {
|
|
394
442
|
const took = _toolStartTime ? c.dim(` · ${elapsed(Date.now() - _toolStartTime)}`) : '';
|
|
395
443
|
let display = summary || '';
|
|
396
444
|
if (/^[a-zA-Z]:[/\\]/.test(display) || display.startsWith('/')) {
|
|
@@ -401,6 +449,12 @@ function renderToolDone(name, summary, preview) {
|
|
|
401
449
|
}
|
|
402
450
|
process.stdout.write(` ${c.ok('✓')} ${c.muted(name)} ${display}${took}\n`);
|
|
403
451
|
|
|
452
|
+
// Weather card
|
|
453
|
+
if (name === 'get_weather' && weatherData) {
|
|
454
|
+
renderWeatherCard(weatherData);
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
|
|
404
458
|
// Rich preview for certain tools
|
|
405
459
|
if (preview && PREVIEW_TOOLS.has(name)) {
|
|
406
460
|
const lines = String(preview).split('\n').filter(l => l.trim());
|
|
@@ -927,7 +981,7 @@ Keep it under 350 words. Write prior.md now.`;
|
|
|
927
981
|
renderToolStart(ev.name, ev.args);
|
|
928
982
|
spinStart('working…');
|
|
929
983
|
break;
|
|
930
|
-
case 'tool_done': spinStop(); renderToolDone(ev.name, ev.summary, ev.preview); break;
|
|
984
|
+
case 'tool_done': spinStop(); renderToolDone(ev.name, ev.summary, ev.preview, ev.weather); break;
|
|
931
985
|
case 'tool_error': spinStop(); renderToolError(ev.name, ev.error); break;
|
|
932
986
|
case 'text':
|
|
933
987
|
spinStop();
|
|
@@ -1094,7 +1148,7 @@ Keep it under 350 words. Write prior.md now.`;
|
|
|
1094
1148
|
|
|
1095
1149
|
case 'tool_done':
|
|
1096
1150
|
spinStop();
|
|
1097
|
-
renderToolDone(ev.name, ev.summary, ev.preview);
|
|
1151
|
+
renderToolDone(ev.name, ev.summary, ev.preview, ev.weather);
|
|
1098
1152
|
break;
|
|
1099
1153
|
|
|
1100
1154
|
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`, {
|