prior-cli 1.3.12 → 1.4.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 CHANGED
@@ -388,7 +388,9 @@ function hyperlink(text, url) {
388
388
  return `\x1b]8;;${url}\x1b\\${text}\x1b]8;;\x1b\\`;
389
389
  }
390
390
 
391
- function renderToolDone(name, summary) {
391
+ const PREVIEW_TOOLS = new Set(['file_read', 'run_command', 'web_search', 'url_fetch']);
392
+
393
+ function renderToolDone(name, summary, preview) {
392
394
  const took = _toolStartTime ? c.dim(` · ${elapsed(Date.now() - _toolStartTime)}`) : '';
393
395
  let display = summary || '';
394
396
  if (/^[a-zA-Z]:[/\\]/.test(display) || display.startsWith('/')) {
@@ -398,6 +400,19 @@ function renderToolDone(name, summary) {
398
400
  display = c.dim(display);
399
401
  }
400
402
  process.stdout.write(` ${c.ok('✓')} ${c.muted(name)} ${display}${took}\n`);
403
+
404
+ // Rich preview for certain tools
405
+ if (preview && PREVIEW_TOOLS.has(name)) {
406
+ const lines = String(preview).split('\n').filter(l => l.trim());
407
+ const toShow = lines.slice(0, 5);
408
+ const more = lines.length - toShow.length;
409
+ if (toShow.length > 0) {
410
+ drawBox([
411
+ ...toShow.map(l => ({ text: l.slice(0, 80), dim: true })),
412
+ ...(more > 0 ? [{ text: `… ${more} more line${more !== 1 ? 's' : ''}`, dim: true }] : []),
413
+ ]);
414
+ }
415
+ }
401
416
  }
402
417
 
403
418
  function renderToolError(name, error) {
@@ -750,12 +765,25 @@ async function startChat(opts = {}) {
750
765
  process.exit(0);
751
766
  });
752
767
 
753
- const PROMPT = () => c.brand(' ❯ ');
768
+ const PROMPT = () => c.brand(' ❯ ');
769
+ const ML_PROMPT = () => c.brand(' … ');
770
+
771
+ let _mlBuf = []; // multiline accumulation (\ continuation)
754
772
 
755
773
  const loop = () => {
756
- rl.question(PROMPT(), async raw => {
774
+ const isML = _mlBuf.length > 0;
775
+ rl.question(isML ? ML_PROMPT() : PROMPT(), async raw => {
757
776
  clearSuggestions();
758
- const input = raw.trim();
777
+
778
+ // Backslash continuation — collect lines until one doesn't end with \
779
+ if (raw.endsWith('\\')) {
780
+ _mlBuf.push(raw.slice(0, -1));
781
+ return loop();
782
+ }
783
+ _mlBuf.push(raw);
784
+ const input = _mlBuf.join('\n').trim();
785
+ _mlBuf = [];
786
+
759
787
  if (!input) return loop();
760
788
 
761
789
  // ── Slash commands ──────────────────────────────────────
@@ -899,7 +927,7 @@ Keep it under 350 words. Write prior.md now.`;
899
927
  renderToolStart(ev.name, ev.args);
900
928
  spinStart('working…');
901
929
  break;
902
- case 'tool_done': spinStop(); renderToolDone(ev.name, ev.summary); break;
930
+ case 'tool_done': spinStop(); renderToolDone(ev.name, ev.summary, ev.preview); break;
903
931
  case 'tool_error': spinStop(); renderToolError(ev.name, ev.error); break;
904
932
  case 'text':
905
933
  spinStop();
@@ -1032,7 +1060,6 @@ Keep it under 350 words. Write prior.md now.`;
1032
1060
 
1033
1061
  case 'cancelled':
1034
1062
  spinStop();
1035
- process.stdout.write('\n');
1036
1063
  console.log(c.muted(' ✗ Cancelled'));
1037
1064
  break;
1038
1065
 
@@ -1060,7 +1087,7 @@ Keep it under 350 words. Write prior.md now.`;
1060
1087
 
1061
1088
  case 'tool_done':
1062
1089
  spinStop();
1063
- renderToolDone(ev.name, ev.summary);
1090
+ renderToolDone(ev.name, ev.summary, ev.preview);
1064
1091
  break;
1065
1092
 
1066
1093
  case 'tool_skip':
@@ -1091,7 +1118,6 @@ Keep it under 350 words. Write prior.md now.`;
1091
1118
 
1092
1119
  case 'error':
1093
1120
  spinStop();
1094
- process.stdout.write('\n');
1095
1121
  console.error(c.err(` ✗ ${ev.message}`));
1096
1122
  break;
1097
1123
  }
package/lib/agent.js CHANGED
@@ -8,7 +8,7 @@ const CLI_BASE = 'https://prior.ngrok.app/cli-backend';
8
8
  const PRIOR_BASE = 'https://prior.ngrok.app';
9
9
  const MAX_ITER = 14;
10
10
 
11
- // ── Single inference call (server just runs Ollama + returns) ─
11
+ // ── Single inference call ─────────────────────────────────────
12
12
 
13
13
  async function infer(messages, model, token, { cwd, uncensored, projectContext, images } = {}, signal) {
14
14
  const res = await fetch(`${CLI_BASE}/api/infer`, {
@@ -22,7 +22,7 @@ async function infer(messages, model, token, { cwd, uncensored, projectContext,
22
22
  const err = await res.json().catch(() => ({}));
23
23
  throw new Error(err.error || `Server error: HTTP ${res.status}`);
24
24
  }
25
- return await res.json(); // { content, promptTokens, completionTokens }
25
+ return await res.json();
26
26
  }
27
27
 
28
28
  // ── Token usage tracking ──────────────────────────────────────
@@ -201,35 +201,28 @@ function stripToolTags(text) {
201
201
  const CONFIRM_TOOLS = new Set(['run_command', 'file_delete', 'file_write']);
202
202
 
203
203
  async function runAgent({ messages, model, uncensored, cwd, projectContext, images, send, confirm, signal }) {
204
- const token = getToken();
204
+ const token = getToken();
205
205
  const history = [...messages];
206
206
 
207
207
  let totalPromptTokens = 0;
208
208
  let totalCompletionTokens = 0;
209
- let pendingImages = (images && images.length) ? images : null; // only sent on first iteration
209
+ let pendingImages = (images && images.length) ? images : null;
210
210
 
211
211
  for (let iter = 0; iter < MAX_ITER; iter++) {
212
212
 
213
- if (signal?.aborted) {
214
- send({ type: 'cancelled' });
215
- send({ type: 'done' });
216
- return;
217
- }
213
+ if (signal?.aborted) { send({ type: 'cancelled' }); send({ type: 'done' }); return; }
218
214
 
219
215
  send({ type: 'thinking' });
220
216
 
221
- let result;
222
217
  const iterImages = pendingImages;
223
- pendingImages = null; // clear after first use
218
+ pendingImages = null;
219
+
220
+ let result;
224
221
  try {
225
222
  result = await infer(history, model || 'qwen3.5:4b', token, { cwd, uncensored, projectContext, images: iterImages }, signal);
226
223
  } catch (err) {
227
224
  await trackTokenUsage(token, totalPromptTokens, totalCompletionTokens);
228
- if (err.name === 'AbortError' || signal?.aborted) {
229
- send({ type: 'cancelled' });
230
- send({ type: 'done' });
231
- return;
232
- }
225
+ if (err.name === 'AbortError' || signal?.aborted) { send({ type: 'cancelled' }); send({ type: 'done' }); return; }
233
226
  send({ type: 'error', message: err.message });
234
227
  send({ type: 'done' });
235
228
  return;
@@ -252,7 +245,6 @@ async function runAgent({ messages, model, uncensored, cwd, projectContext, imag
252
245
  if (calls.length === 0) {
253
246
  const finalText = stripToolTags(cleaned);
254
247
  if (!finalText && iter < MAX_ITER - 1) {
255
- // Model returned blank (all think tags, no actual output) — nudge once
256
248
  history.push({ role: 'assistant', content: raw });
257
249
  history.push({ role: 'user', content: '(Your response was empty. Please write your reply.)' });
258
250
  continue;
@@ -274,7 +266,6 @@ async function runAgent({ messages, model, uncensored, cwd, projectContext, imag
274
266
  for (const call of calls) {
275
267
  send({ type: 'tool_start', name: call.name, args: call.args });
276
268
 
277
- // Confirmation gate for destructive / side-effect tools
278
269
  if (confirm && CONFIRM_TOOLS.has(call.name)) {
279
270
  const approved = await confirm({ name: call.name, args: call.args });
280
271
  if (!approved) {
@@ -286,7 +277,8 @@ async function runAgent({ messages, model, uncensored, cwd, projectContext, imag
286
277
 
287
278
  try {
288
279
  const toolResult = await executeTool(call.name, call.args, { cwd, token, send });
289
- send({ type: 'tool_done', name: call.name, summary: toolResult.summary });
280
+ // Pass output snippet so the CLI can show a rich preview
281
+ send({ type: 'tool_done', name: call.name, summary: toolResult.summary, preview: toolResult.output });
290
282
  resultParts.push(`<tool_result name="${call.name}">\n${toolResult.output}\n</tool_result>`);
291
283
  } catch (err) {
292
284
  send({ type: 'tool_error', name: call.name, error: err.message });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prior-cli",
3
- "version": "1.3.12",
3
+ "version": "1.4.1",
4
4
  "description": "Prior Network AI — command-line interface",
5
5
  "bin": {
6
6
  "prior": "bin/prior.js"