praxis-agent 0.43.0 → 0.44.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 +48 -47
- package/dist/application/native-session-projection.d.ts +4 -0
- package/dist/application/native-session-projection.js +135 -0
- package/dist/application/session-service.d.ts +0 -1
- package/dist/application/session-service.js +9 -170
- package/dist/application/top-level-agent-manager.d.ts +7 -0
- package/dist/application/top-level-agent-manager.js +21 -3
- package/dist/cli/controls.js +4 -0
- package/dist/cli/interactive.js +112 -156
- package/dist/cli/protocol.d.ts +5 -0
- package/dist/cli/protocol.js +45 -0
- package/dist/cli/provider-auth-command.d.ts +32 -0
- package/dist/cli/provider-auth-command.js +249 -0
- package/dist/cli/tui/ansi-frame-renderer.d.ts +2 -0
- package/dist/cli/tui/ansi-frame-renderer.js +109 -21
- package/dist/cli/tui/ansi-surface.d.ts +6 -22
- package/dist/cli/tui/ansi-surface.js +6 -126
- package/dist/cli/tui/ansi-theme.d.ts +3 -2
- package/dist/cli/tui/ansi-theme.js +22 -1
- package/dist/cli/tui/quiet-choice-rows.d.ts +26 -0
- package/dist/cli/tui/quiet-choice-rows.js +302 -0
- package/dist/cli/tui/quiet-frame-adapter.d.ts +18 -0
- package/dist/cli/tui/quiet-frame-adapter.js +90 -0
- package/dist/cli/tui/quiet-frame.d.ts +43 -0
- package/dist/cli/tui/quiet-frame.js +346 -0
- package/dist/cli/tui/quiet-operational-rows.d.ts +17 -0
- package/dist/cli/tui/quiet-operational-rows.js +413 -0
- package/dist/cli/tui/quiet-screen-projector.d.ts +25 -0
- package/dist/cli/tui/quiet-screen-projector.js +110 -0
- package/dist/cli/tui/quiet-settings-rows.d.ts +17 -0
- package/dist/cli/tui/quiet-settings-rows.js +490 -0
- package/dist/cli/tui/status-line.d.ts +15 -9
- package/dist/cli/tui/status-line.js +15 -6
- package/dist/cli/tui/theme.js +20 -20
- package/dist/cli/tui/transcript-viewport.d.ts +5 -0
- package/dist/cli/tui/transcript-viewport.js +213 -78
- package/dist/cli/tui/tui-row-ir.js +4 -4
- package/dist/cli/workspace-trust-prompt.js +2 -2
- package/dist/cli-runtime.d.ts +34 -1
- package/dist/cli-runtime.js +587 -184
- package/dist/maintenance/doctor.js +100 -22
- package/dist/persistence/in-memory-transcript-store.js +1 -7
- package/dist/persistence/native-transcript-store.d.ts +0 -9
- package/dist/persistence/native-transcript-store.js +4 -38
- package/dist/persistence/provider-credential-vault.d.ts +72 -0
- package/dist/persistence/provider-credential-vault.js +498 -0
- package/dist/providers/codex-oauth.d.ts +104 -0
- package/dist/providers/codex-oauth.js +770 -0
- package/dist/providers/codex-subscription.d.ts +33 -0
- package/dist/providers/codex-subscription.js +849 -0
- package/dist/providers/provider-auth.d.ts +71 -0
- package/dist/providers/provider-auth.js +149 -0
- package/dist/providers/provider-registry.d.ts +52 -0
- package/dist/providers/provider-registry.js +187 -0
- package/dist/providers/provider-settings.d.ts +38 -0
- package/dist/providers/provider-settings.js +334 -0
- package/dist/security/workspace-trust.d.ts +4 -3
- package/dist/security/workspace-trust.js +35 -1
- package/package.json +8 -4
|
@@ -10,7 +10,7 @@ const rgiEmojiPattern = /^\p{RGI_Emoji}$/v;
|
|
|
10
10
|
const extendedPictographicPattern = /\p{Extended_Pictographic}/gu;
|
|
11
11
|
const spacingMarkPattern = /\p{Spacing_Mark}/v;
|
|
12
12
|
const unqualifiedKeycapPattern = /^[\d#*]\u20e3$/u;
|
|
13
|
-
function
|
|
13
|
+
export function terminalGraphemes(text) {
|
|
14
14
|
return Array.from(graphemeSegmenter.segment(text), ({ segment }) => segment);
|
|
15
15
|
}
|
|
16
16
|
function isPrintableAscii(text) {
|
|
@@ -45,7 +45,7 @@ function isDoubleWidthEmoji(cluster) {
|
|
|
45
45
|
return false;
|
|
46
46
|
return (cluster.match(extendedPictographicPattern)?.length ?? 0) >= 2;
|
|
47
47
|
}
|
|
48
|
-
function
|
|
48
|
+
export function terminalGraphemeWidth(cluster) {
|
|
49
49
|
if (!cluster || zeroWidthClusterPattern.test(cluster))
|
|
50
50
|
return 0;
|
|
51
51
|
if (isDoubleWidthEmoji(cluster))
|
|
@@ -69,7 +69,7 @@ function graphemeWidth(cluster) {
|
|
|
69
69
|
}
|
|
70
70
|
return width;
|
|
71
71
|
}
|
|
72
|
-
function
|
|
72
|
+
export function terminalTextWidth(text) {
|
|
73
73
|
if (isPrintableAscii(text))
|
|
74
74
|
return text.length;
|
|
75
75
|
const first = text.codePointAt(0);
|
|
@@ -80,14 +80,40 @@ function terminalStringWidth(text) {
|
|
|
80
80
|
return 2;
|
|
81
81
|
return first <= 0xffff ? 1 : isDoubleWidthEmoji(text) ? 2 : 1;
|
|
82
82
|
}
|
|
83
|
-
return
|
|
83
|
+
return terminalGraphemes(text).reduce((width, cluster) => width + terminalGraphemeWidth(cluster), 0);
|
|
84
|
+
}
|
|
85
|
+
export function terminalTextHead(text, budget) {
|
|
86
|
+
const limit = Number.isFinite(budget) ? Math.max(0, Math.floor(budget)) : 0;
|
|
87
|
+
let used = 0;
|
|
88
|
+
const result = [];
|
|
89
|
+
for (const { segment: cluster } of graphemeSegmenter.segment(text)) {
|
|
90
|
+
const width = terminalGraphemeWidth(cluster);
|
|
91
|
+
if (used + width > limit)
|
|
92
|
+
break;
|
|
93
|
+
result.push(cluster);
|
|
94
|
+
used += width;
|
|
95
|
+
}
|
|
96
|
+
return result.join('');
|
|
97
|
+
}
|
|
98
|
+
export function terminalTextTail(text, budget) {
|
|
99
|
+
const limit = Number.isFinite(budget) ? Math.max(0, Math.floor(budget)) : 0;
|
|
100
|
+
let used = 0;
|
|
101
|
+
const result = [];
|
|
102
|
+
for (const cluster of [...terminalGraphemes(text)].reverse()) {
|
|
103
|
+
const width = terminalGraphemeWidth(cluster);
|
|
104
|
+
if (used + width > limit)
|
|
105
|
+
break;
|
|
106
|
+
result.unshift(cluster);
|
|
107
|
+
used += width;
|
|
108
|
+
}
|
|
109
|
+
return result.join('');
|
|
84
110
|
}
|
|
85
111
|
function expandTabs(line) {
|
|
86
112
|
if (!line.includes('\t'))
|
|
87
113
|
return line;
|
|
88
114
|
let column = 0;
|
|
89
115
|
let expanded = '';
|
|
90
|
-
for (const cluster of
|
|
116
|
+
for (const cluster of terminalGraphemes(line)) {
|
|
91
117
|
if (cluster === '\t') {
|
|
92
118
|
const spaces = 8 - (column % 8);
|
|
93
119
|
expanded += ' '.repeat(spaces);
|
|
@@ -95,7 +121,7 @@ function expandTabs(line) {
|
|
|
95
121
|
continue;
|
|
96
122
|
}
|
|
97
123
|
expanded += cluster;
|
|
98
|
-
column +=
|
|
124
|
+
column += terminalGraphemeWidth(cluster);
|
|
99
125
|
}
|
|
100
126
|
return expanded;
|
|
101
127
|
}
|
|
@@ -109,11 +135,11 @@ function hardWrappedRows(word, width, startColumn) {
|
|
|
109
135
|
column: occupied % width || width,
|
|
110
136
|
};
|
|
111
137
|
}
|
|
112
|
-
const clusters =
|
|
138
|
+
const clusters = terminalGraphemes(word);
|
|
113
139
|
let rows = 0;
|
|
114
140
|
let column = startColumn;
|
|
115
141
|
for (const [index, cluster] of clusters.entries()) {
|
|
116
|
-
const clusterWidth =
|
|
142
|
+
const clusterWidth = terminalGraphemeWidth(cluster);
|
|
117
143
|
if (column + clusterWidth > width) {
|
|
118
144
|
rows += 1;
|
|
119
145
|
column = clusterWidth;
|
|
@@ -155,9 +181,9 @@ function wrappedLineLayout(line, width, output) {
|
|
|
155
181
|
column = wrapped.column;
|
|
156
182
|
return;
|
|
157
183
|
}
|
|
158
|
-
const clusters =
|
|
184
|
+
const clusters = terminalGraphemes(word);
|
|
159
185
|
for (const [index, cluster] of clusters.entries()) {
|
|
160
|
-
const clusterWidth =
|
|
186
|
+
const clusterWidth = terminalGraphemeWidth(cluster);
|
|
161
187
|
if (column + clusterWidth > width)
|
|
162
188
|
pushRow();
|
|
163
189
|
row += cluster;
|
|
@@ -170,7 +196,7 @@ function wrappedLineLayout(line, width, output) {
|
|
|
170
196
|
const word = words[index] ?? '';
|
|
171
197
|
const wordWidth = isPrintableAscii(word)
|
|
172
198
|
? word.length
|
|
173
|
-
:
|
|
199
|
+
: terminalTextWidth(word);
|
|
174
200
|
if (index > 0) {
|
|
175
201
|
if (column >= width)
|
|
176
202
|
pushRow();
|
|
@@ -271,14 +297,63 @@ function inputString(entry, key) {
|
|
|
271
297
|
const value = entry.item.call.input[key];
|
|
272
298
|
return typeof value === 'string' ? value : '';
|
|
273
299
|
}
|
|
300
|
+
function oneLine(value, max = 160) {
|
|
301
|
+
const text = stripVTControlCharacters(value)
|
|
302
|
+
.replace(/[\r\n\t]+/gu, ' ')
|
|
303
|
+
.replace(/\s+/gu, ' ')
|
|
304
|
+
.trim();
|
|
305
|
+
return text.length > max ? `${text.slice(0, Math.max(1, max - 1))}…` : text;
|
|
306
|
+
}
|
|
274
307
|
function toolHeading(entry) {
|
|
275
308
|
if (entry.item.call.name === 'Edit')
|
|
276
|
-
return `
|
|
309
|
+
return `Edit ${oneLine(inputString(entry, 'file_path'))}`.trimEnd();
|
|
277
310
|
if (entry.item.call.name === 'Read')
|
|
278
|
-
return `Read
|
|
311
|
+
return `Read ${oneLine(inputString(entry, 'file_path'))}`.trimEnd();
|
|
279
312
|
if (entry.item.call.name === 'Bash')
|
|
280
|
-
return `Bash
|
|
281
|
-
return entry.item.call.name;
|
|
313
|
+
return `Bash ${oneLine(inputString(entry, 'command'))}`.trimEnd();
|
|
314
|
+
return oneLine(entry.item.call.name);
|
|
315
|
+
}
|
|
316
|
+
function toolSummary(entry, mode) {
|
|
317
|
+
const state = !entry.result
|
|
318
|
+
? 'running'
|
|
319
|
+
: entry.result.isError
|
|
320
|
+
? 'failed'
|
|
321
|
+
: 'completed';
|
|
322
|
+
const prefix = mode === 'screen-reader'
|
|
323
|
+
? state === 'running'
|
|
324
|
+
? 'Running tool: '
|
|
325
|
+
: state === 'failed'
|
|
326
|
+
? 'Failed tool: '
|
|
327
|
+
: 'Completed tool: '
|
|
328
|
+
: state === 'running'
|
|
329
|
+
? '… '
|
|
330
|
+
: state === 'failed'
|
|
331
|
+
? '! '
|
|
332
|
+
: '✓ ';
|
|
333
|
+
const detail = !['Bash', 'Read', 'Edit'].includes(entry.item.call.name) &&
|
|
334
|
+
entry.item.detail
|
|
335
|
+
? ` · ${oneLine(entry.item.detail, 120)}`
|
|
336
|
+
: '';
|
|
337
|
+
return `${prefix}${toolHeading(entry)}${detail}`;
|
|
338
|
+
}
|
|
339
|
+
function shellSummary(entry, mode) {
|
|
340
|
+
const state = !entry.result
|
|
341
|
+
? 'running'
|
|
342
|
+
: entry.result.isError
|
|
343
|
+
? 'failed'
|
|
344
|
+
: 'completed';
|
|
345
|
+
const prefix = mode === 'screen-reader'
|
|
346
|
+
? state === 'running'
|
|
347
|
+
? 'Running shell command: '
|
|
348
|
+
: state === 'failed'
|
|
349
|
+
? 'Failed shell command: '
|
|
350
|
+
: 'Completed shell command: '
|
|
351
|
+
: state === 'running'
|
|
352
|
+
? '… Bash '
|
|
353
|
+
: state === 'failed'
|
|
354
|
+
? '! Bash '
|
|
355
|
+
: '✓ Bash ';
|
|
356
|
+
return `${prefix}${oneLine(entry.item.command)}`.trimEnd();
|
|
282
357
|
}
|
|
283
358
|
function visibleOutputLineCount(text, width, mode) {
|
|
284
359
|
const lines = contentLines(text);
|
|
@@ -319,7 +394,7 @@ function textTail(text, budget, width) {
|
|
|
319
394
|
}
|
|
320
395
|
const remainingRows = usableBudget - rowsAfter;
|
|
321
396
|
if (remainingRows > 0) {
|
|
322
|
-
const clusters =
|
|
397
|
+
const clusters = terminalGraphemes(line);
|
|
323
398
|
let low = 0;
|
|
324
399
|
let high = clusters.length;
|
|
325
400
|
let suffix = '';
|
|
@@ -336,7 +411,7 @@ function textTail(text, budget, width) {
|
|
|
336
411
|
}
|
|
337
412
|
while (suffix &&
|
|
338
413
|
wrappedLineCount(`${TRANSCRIPT_TRUNCATION_MARKER}${suffix}`, usableWidth) > remainingRows) {
|
|
339
|
-
const suffixClusters =
|
|
414
|
+
const suffixClusters = terminalGraphemes(suffix);
|
|
340
415
|
suffix = suffixClusters.slice(0, -1).join('');
|
|
341
416
|
}
|
|
342
417
|
kept.unshift(suffix);
|
|
@@ -364,7 +439,7 @@ function textHead(text, budget, width) {
|
|
|
364
439
|
return candidate;
|
|
365
440
|
const remaining = Math.max(0, usableBudget - wrappedLineCount(marker, usableWidth));
|
|
366
441
|
const prefix = kept.join('\n');
|
|
367
|
-
const clusters =
|
|
442
|
+
const clusters = terminalGraphemes(prefix);
|
|
368
443
|
let low = 0;
|
|
369
444
|
let high = clusters.length;
|
|
370
445
|
let best = '';
|
|
@@ -416,19 +491,17 @@ function textRange(text, startRow, budget, width) {
|
|
|
416
491
|
}
|
|
417
492
|
function estimateRenderedTranscriptEntryLines(entry, width, mode) {
|
|
418
493
|
if (entry.kind === 'read-summary')
|
|
419
|
-
return wrappedLineCount(
|
|
494
|
+
return wrappedLineCount(`✓ Read ${entry.count} file${entry.count === 1 ? '' : 's'}`, width);
|
|
420
495
|
if (entry.kind === 'item') {
|
|
421
496
|
const item = entry.item;
|
|
422
497
|
if (item.kind === 'user')
|
|
423
498
|
return (1 +
|
|
424
499
|
(mode === 'screen-reader' ? 1 : 0) +
|
|
425
|
-
wrappedLineCount(`${mode === 'screen-reader' ? 'You: ' : '
|
|
500
|
+
wrappedLineCount(`${mode === 'screen-reader' ? 'You: ' : 'you> '}${item.text}`, width));
|
|
426
501
|
if (item.kind === 'assistant')
|
|
427
502
|
return (1 +
|
|
428
503
|
(mode === 'screen-reader' ? 1 : 0) +
|
|
429
|
-
|
|
430
|
-
? Math.max(1, width - 7)
|
|
431
|
-
: markdownContentWidth(width)));
|
|
504
|
+
assistantMarkdownProjectionRows(item.text, width, mode).length);
|
|
432
505
|
if (item.kind === 'thinking') {
|
|
433
506
|
const summary = item.text.replace(/\s+/gu, ' ').trim();
|
|
434
507
|
if (mode === 'normal')
|
|
@@ -473,15 +546,14 @@ function estimateRenderedTranscriptEntryLines(entry, width, mode) {
|
|
|
473
546
|
if (entry.kind === 'orphan-shell-result')
|
|
474
547
|
return wrappedLineCount(`⎿ ${orphanShellOutput(entry.item.stdout, entry.item.stderr)}`, width);
|
|
475
548
|
if (entry.kind === 'tool') {
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
entry.result
|
|
479
|
-
|
|
480
|
-
return
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
rows += wrappedLineCount(` ${entry.item.detail}`, width);
|
|
549
|
+
const summaryRows = wrappedLineCount(toolSummary(entry, mode), width);
|
|
550
|
+
if (mode === 'normal') {
|
|
551
|
+
if (!entry.result || !entry.result.isError)
|
|
552
|
+
return summaryRows;
|
|
553
|
+
return (summaryRows +
|
|
554
|
+
viewportOutputRows(`Error: ${bounded(entry.result.text, 500)}`, width, mode).length);
|
|
555
|
+
}
|
|
556
|
+
let rows = 1 + summaryRows;
|
|
485
557
|
if (!entry.result)
|
|
486
558
|
return rows;
|
|
487
559
|
if (entry.result.isError)
|
|
@@ -491,18 +563,25 @@ function estimateRenderedTranscriptEntryLines(entry, width, mode) {
|
|
|
491
563
|
const newLines = contentLines(inputString(entry, 'new_string'));
|
|
492
564
|
const oldLines = contentLines(inputString(entry, 'old_string'));
|
|
493
565
|
rows += wrappedLineCount(`⎿ Added ${newLines.length} line${newLines.length === 1 ? '' : 's'}, removed ${oldLines.length} line${oldLines.length === 1 ? '' : 's'}`, Math.max(1, width - 2));
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
wrappedLineCount(` ${index + 1} +${line}`, Math.max(1, width - 2)), 0);
|
|
499
|
-
}
|
|
566
|
+
rows += oldLines.reduce((total, line, index) => total +
|
|
567
|
+
wrappedLineCount(` ${index + 1} -${line}`, Math.max(1, width - 2)), 0);
|
|
568
|
+
rows += newLines.reduce((total, line, index) => total +
|
|
569
|
+
wrappedLineCount(` ${index + 1} +${line}`, Math.max(1, width - 2)), 0);
|
|
500
570
|
return rows;
|
|
501
571
|
}
|
|
502
572
|
return rows + visibleOutputLineCount(entry.result.text, width, mode);
|
|
503
573
|
}
|
|
504
|
-
|
|
505
|
-
|
|
574
|
+
const summaryRows = wrappedLineCount(shellSummary(entry, mode), width);
|
|
575
|
+
if (mode === 'normal') {
|
|
576
|
+
if (!entry.result || !entry.result.isError)
|
|
577
|
+
return summaryRows;
|
|
578
|
+
const output = combinedShellOutput(entry.result.stdout, entry.result.stderr);
|
|
579
|
+
return (summaryRows +
|
|
580
|
+
(output
|
|
581
|
+
? viewportOutputRows(output, width, mode).length
|
|
582
|
+
: wrappedLineCount('⎿ ', Math.max(1, width - 2))));
|
|
583
|
+
}
|
|
584
|
+
let rows = 1 + summaryRows;
|
|
506
585
|
if (!entry.result)
|
|
507
586
|
return rows;
|
|
508
587
|
const output = combinedShellOutput(entry.result.stdout, entry.result.stderr);
|
|
@@ -528,18 +607,58 @@ export function transcriptPresentationLineCount(entries, width, mode) {
|
|
|
528
607
|
return entries.reduce((n, entry) => n + estimateTranscriptEntryLines(entry, width, mode), 0);
|
|
529
608
|
}
|
|
530
609
|
function viewportOutputRows(text, width, mode) {
|
|
531
|
-
const lines = contentLines(text);
|
|
532
|
-
const visible = mode === 'normal' ? lines.slice(0, 3) : lines;
|
|
533
610
|
const outputWidth = Math.max(1, width - 2);
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
611
|
+
if (mode !== 'normal') {
|
|
612
|
+
const lines = contentLines(text);
|
|
613
|
+
return lines.flatMap((line, index) => textVisualRows(`${index === 0 ? '⎿ ' : ' '}${line || ' '}`, outputWidth));
|
|
537
614
|
}
|
|
538
|
-
|
|
615
|
+
const rows = [];
|
|
616
|
+
const rowBudget = 8;
|
|
617
|
+
const lines = [];
|
|
618
|
+
let lineStart = 0;
|
|
619
|
+
let omittedLines = 0;
|
|
620
|
+
for (let index = 0; index <= text.length && lines.length < 3; index += 1) {
|
|
621
|
+
if (index !== text.length && text[index] !== '\n')
|
|
622
|
+
continue;
|
|
623
|
+
const line = text.slice(lineStart, index).replace(/\r$/u, '');
|
|
624
|
+
if (!(index === text.length && line === '' && text.endsWith('\n')))
|
|
625
|
+
lines.push(line);
|
|
626
|
+
lineStart = index + 1;
|
|
627
|
+
}
|
|
628
|
+
for (let index = lineStart; index < text.length; index += 1)
|
|
629
|
+
if (text[index] === '\n')
|
|
630
|
+
omittedLines += 1;
|
|
631
|
+
if (lineStart < text.length && !text.endsWith('\n'))
|
|
632
|
+
omittedLines += 1;
|
|
633
|
+
let hidden = omittedLines > 0;
|
|
634
|
+
for (const [index, line] of lines.entries()) {
|
|
635
|
+
const prefix = index === 0 ? '⎿ ' : ' ';
|
|
636
|
+
const remaining = rowBudget - rows.length;
|
|
637
|
+
if (remaining <= 1) {
|
|
638
|
+
hidden = true;
|
|
639
|
+
break;
|
|
640
|
+
}
|
|
641
|
+
const candidate = terminalTextHead(line || ' ', outputWidth * (remaining - 1));
|
|
642
|
+
if (candidate.length < (line || ' ').length)
|
|
643
|
+
hidden = true;
|
|
644
|
+
rows.push(...textVisualRows(`${prefix}${candidate}`, outputWidth).slice(0, remaining - 1));
|
|
645
|
+
if (rows.length >= rowBudget - 1)
|
|
646
|
+
break;
|
|
647
|
+
}
|
|
648
|
+
if (hidden) {
|
|
649
|
+
const marker = textVisualRows(omittedLines > 0
|
|
650
|
+
? ` ${TRANSCRIPT_TRUNCATION_MARKER} +${omittedLines} lines (ctrl+o to expand)`
|
|
651
|
+
: ` ${TRANSCRIPT_TRUNCATION_MARKER}`, outputWidth);
|
|
652
|
+
if (marker.length <= rowBudget - rows.length)
|
|
653
|
+
rows.push(...marker.slice(0, rowBudget - rows.length));
|
|
654
|
+
else
|
|
655
|
+
rows.push(TRANSCRIPT_TRUNCATION_MARKER);
|
|
656
|
+
}
|
|
657
|
+
return rows.slice(0, rowBudget);
|
|
539
658
|
}
|
|
540
659
|
function entryViewportRows(entry, width, mode) {
|
|
541
660
|
if (entry.kind === 'read-summary')
|
|
542
|
-
return textVisualRows(
|
|
661
|
+
return textVisualRows(`✓ Read ${entry.count} file${entry.count === 1 ? '' : 's'}`, width);
|
|
543
662
|
if (entry.kind === 'item') {
|
|
544
663
|
const item = entry.item;
|
|
545
664
|
if (item.kind === 'context')
|
|
@@ -548,15 +667,13 @@ function entryViewportRows(entry, width, mode) {
|
|
|
548
667
|
return [
|
|
549
668
|
'',
|
|
550
669
|
...(mode === 'screen-reader' ? [''] : []),
|
|
551
|
-
...textVisualRows(`${mode === 'screen-reader' ? 'You: ' : '
|
|
670
|
+
...textVisualRows(`${mode === 'screen-reader' ? 'You: ' : 'you> '}${item.text}`, width),
|
|
552
671
|
];
|
|
553
672
|
if (item.kind === 'assistant')
|
|
554
673
|
return [
|
|
555
674
|
'',
|
|
556
675
|
...(mode === 'screen-reader' ? ['Praxis:'] : []),
|
|
557
|
-
...
|
|
558
|
-
? Math.max(1, width - 7)
|
|
559
|
-
: markdownContentWidth(width)),
|
|
676
|
+
...assistantMarkdownProjectionRows(item.text, width, mode).map((row) => row.text),
|
|
560
677
|
];
|
|
561
678
|
if (item.kind === 'thinking') {
|
|
562
679
|
const summary = item.text.replace(/\s+/gu, ' ').trim();
|
|
@@ -605,10 +722,19 @@ function entryViewportRows(entry, width, mode) {
|
|
|
605
722
|
if (entry.kind === 'orphan-shell-result')
|
|
606
723
|
return textVisualRows(`⎿ ${orphanShellOutput(entry.item.stdout, entry.item.stderr)}`, width);
|
|
607
724
|
if (entry.kind === 'shell') {
|
|
608
|
-
const
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
725
|
+
const summaryRows = textVisualRows(shellSummary(entry, mode), width);
|
|
726
|
+
if (mode === 'normal') {
|
|
727
|
+
if (!entry.result || !entry.result.isError)
|
|
728
|
+
return summaryRows;
|
|
729
|
+
const output = combinedShellOutput(entry.result.stdout, entry.result.stderr);
|
|
730
|
+
return [
|
|
731
|
+
...summaryRows,
|
|
732
|
+
...(output
|
|
733
|
+
? viewportOutputRows(output, width, mode)
|
|
734
|
+
: textVisualRows('⎿ ', Math.max(1, width - 2))),
|
|
735
|
+
];
|
|
736
|
+
}
|
|
737
|
+
const rows = ['', ...summaryRows];
|
|
612
738
|
if (!entry.result)
|
|
613
739
|
return rows;
|
|
614
740
|
const output = combinedShellOutput(entry.result.stdout, entry.result.stderr);
|
|
@@ -619,15 +745,16 @@ function entryViewportRows(entry, width, mode) {
|
|
|
619
745
|
: textVisualRows('⎿ ', Math.max(1, width - 2))),
|
|
620
746
|
];
|
|
621
747
|
}
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
entry.result
|
|
625
|
-
|
|
626
|
-
return
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
748
|
+
const summaryRows = textVisualRows(toolSummary(entry, mode), width);
|
|
749
|
+
if (mode === 'normal') {
|
|
750
|
+
if (!entry.result || !entry.result.isError)
|
|
751
|
+
return summaryRows;
|
|
752
|
+
return [
|
|
753
|
+
...summaryRows,
|
|
754
|
+
...viewportOutputRows(`Error: ${bounded(entry.result.text, 500)}`, width, mode),
|
|
755
|
+
];
|
|
756
|
+
}
|
|
757
|
+
const rows = ['', ...summaryRows];
|
|
631
758
|
if (!entry.result)
|
|
632
759
|
return rows;
|
|
633
760
|
if (entry.result.isError) {
|
|
@@ -638,12 +765,10 @@ function entryViewportRows(entry, width, mode) {
|
|
|
638
765
|
const oldLines = contentLines(inputString(entry, 'old_string'));
|
|
639
766
|
const newLines = contentLines(inputString(entry, 'new_string'));
|
|
640
767
|
rows.push(...textVisualRows(`⎿ Added ${newLines.length} line${newLines.length === 1 ? '' : 's'}, removed ${oldLines.length} line${oldLines.length === 1 ? '' : 's'}`, Math.max(1, width - 2)));
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
rows.push(...textVisualRows(` ${index + 1} +${line}`, Math.max(1, width - 2)));
|
|
646
|
-
}
|
|
768
|
+
for (const [index, line] of oldLines.entries())
|
|
769
|
+
rows.push(...textVisualRows(` ${index + 1} -${line}`, Math.max(1, width - 2)));
|
|
770
|
+
for (const [index, line] of newLines.entries())
|
|
771
|
+
rows.push(...textVisualRows(` ${index + 1} +${line}`, Math.max(1, width - 2)));
|
|
647
772
|
return rows;
|
|
648
773
|
}
|
|
649
774
|
rows.push(...viewportOutputRows(entry.result.text, width, mode));
|
|
@@ -680,12 +805,25 @@ function markdownViewportRows(text, width) {
|
|
|
680
805
|
}
|
|
681
806
|
return rows;
|
|
682
807
|
}
|
|
808
|
+
function assistantMarkdownProjectionRows(text, width, mode) {
|
|
809
|
+
const contentWidth = mode === 'screen-reader'
|
|
810
|
+
? Math.max(1, width - 7)
|
|
811
|
+
: markdownContentWidth(width);
|
|
812
|
+
const rows = markdownViewportRows(text, contentWidth);
|
|
813
|
+
if (mode === 'screen-reader')
|
|
814
|
+
return rows;
|
|
815
|
+
const first = rows[0] ?? {
|
|
816
|
+
text: '',
|
|
817
|
+
fenceBefore: false,
|
|
818
|
+
fenceAfter: false,
|
|
819
|
+
fenceLabel: 'code',
|
|
820
|
+
};
|
|
821
|
+
const prefixed = textVisualRows(`praxis> ${first.text.trimEnd()}`, width).map((rowText) => ({ ...first, text: rowText }));
|
|
822
|
+
return [...prefixed, ...rows.slice(1)];
|
|
823
|
+
}
|
|
683
824
|
export function createTranscriptEntryViewportIndex(entry, width, mode) {
|
|
684
825
|
if (entry.kind === 'item' && entry.item.kind === 'assistant') {
|
|
685
|
-
const
|
|
686
|
-
? Math.max(1, width - 7)
|
|
687
|
-
: markdownContentWidth(width);
|
|
688
|
-
const assistantMarkdownRows = markdownViewportRows(entry.item.text, contentWidth);
|
|
826
|
+
const assistantMarkdownRows = assistantMarkdownProjectionRows(entry.item.text, width, mode);
|
|
689
827
|
return {
|
|
690
828
|
entry,
|
|
691
829
|
width,
|
|
@@ -712,12 +850,9 @@ function projectAssistantMarkdownSlice(source, sourceText, startRow, budget, wid
|
|
|
712
850
|
const marginTop = startRow <= 0 ? 1 : 0;
|
|
713
851
|
const projectedChromeRows = marginTop + (mode === 'screen-reader' ? 1 : 0);
|
|
714
852
|
const contentBudget = Math.max(1, limit - projectedChromeRows);
|
|
715
|
-
const contentWidth = mode === 'screen-reader'
|
|
716
|
-
? Math.max(1, width - 7)
|
|
717
|
-
: markdownContentWidth(width);
|
|
718
853
|
const sourceRows = matchingViewportIndex(viewportIndex, source, width, mode)
|
|
719
854
|
?.assistantMarkdownRows ??
|
|
720
|
-
|
|
855
|
+
assistantMarkdownProjectionRows(sourceText ?? '', width, mode);
|
|
721
856
|
const contentStart = Math.min(Math.max(0, startRow - sourceChromeRows + (startRow > 0 ? 1 : 0)), sourceRows.length);
|
|
722
857
|
const clippedBefore = contentStart > 0 && contentBudget > 1;
|
|
723
858
|
let remaining = Math.max(1, contentBudget - (clippedBefore ? 1 : 0));
|
|
@@ -15,7 +15,7 @@ function entryText(entry) {
|
|
|
15
15
|
if (entry.kind === 'read-summary')
|
|
16
16
|
return {
|
|
17
17
|
text: `Read ${entry.count} file${entry.count === 1 ? '' : 's'}`,
|
|
18
|
-
role: '
|
|
18
|
+
role: 'success',
|
|
19
19
|
};
|
|
20
20
|
if (entry.kind === 'item') {
|
|
21
21
|
const item = entry.item;
|
|
@@ -28,7 +28,7 @@ function entryText(entry) {
|
|
|
28
28
|
if (item.kind === 'notice')
|
|
29
29
|
return { text: `· ${item.text}`, role: 'muted' };
|
|
30
30
|
if (item.kind === 'warning')
|
|
31
|
-
return { text: `⚠ ${item.text}`, role: '
|
|
31
|
+
return { text: `⚠ ${item.text}`, role: 'warning' };
|
|
32
32
|
if (item.kind === 'local-result')
|
|
33
33
|
return { text: `⎿ ${item.text}`, role: 'muted' };
|
|
34
34
|
if (item.kind === 'compact')
|
|
@@ -51,7 +51,7 @@ function entryText(entry) {
|
|
|
51
51
|
: '';
|
|
52
52
|
return {
|
|
53
53
|
text: `⏺ ${toolHeading(entry.item)}${entry.item.detail ? `\n ${entry.item.detail}` : ''}${output}`,
|
|
54
|
-
role: result
|
|
54
|
+
role: result ? (result.isError ? 'error' : 'success') : 'muted',
|
|
55
55
|
};
|
|
56
56
|
}
|
|
57
57
|
if (entry.kind === 'shell') {
|
|
@@ -61,7 +61,7 @@ function entryText(entry) {
|
|
|
61
61
|
: '';
|
|
62
62
|
return {
|
|
63
63
|
text: `! ${entry.item.command}${output}`,
|
|
64
|
-
role: result
|
|
64
|
+
role: result ? (result.isError ? 'error' : 'success') : 'muted',
|
|
65
65
|
};
|
|
66
66
|
}
|
|
67
67
|
if (entry.kind === 'orphan-tool-result')
|
|
@@ -23,10 +23,10 @@ export async function promptWorkspaceTrust(inventory, io = {}) {
|
|
|
23
23
|
const output = io.output ?? ((text) => process.stderr.write(text));
|
|
24
24
|
if (io.signal?.aborted)
|
|
25
25
|
return false;
|
|
26
|
-
output(`Workspace
|
|
26
|
+
output(`Workspace-controlled resources/configuration found for ${safeWorkspaceTrustDisplayField(inventory.canonicalPath)}\n`);
|
|
27
27
|
for (const origin of inventory.origins)
|
|
28
28
|
output(` ${origin.kind} (${origin.scope}) ${safeWorkspaceTrustDisplayField(origin.path)}: ${safeWorkspaceTrustDisplayField(origin.label)}\n`);
|
|
29
|
-
output('Trust these workspace
|
|
29
|
+
output('Trust these workspace-controlled resources/configuration? [y/N] ');
|
|
30
30
|
const input = io.input ?? process.stdin;
|
|
31
31
|
const iterator = input[Symbol.asyncIterator]();
|
|
32
32
|
const abortedResult = Symbol('workspace-trust-prompt-aborted');
|
package/dist/cli-runtime.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ import type { TuiSlashCommand } from './cli/tui/slash-commands.js';
|
|
|
11
11
|
import { type TuiHookConfiguration } from './cli/tui/hook-settings.js';
|
|
12
12
|
import { type PraxisRuntimeSettings } from './cli/tui/runtime-settings.js';
|
|
13
13
|
import { type ClaudePermissionMode } from './permissions/claude-permission-resolver.js';
|
|
14
|
-
import { type WorkspaceTrustInventory } from './security/workspace-trust.js';
|
|
14
|
+
import { type WorkspaceTrustAssessment, type WorkspaceTrustInventory } from './security/workspace-trust.js';
|
|
15
15
|
import { type ClaudeMcpServerStatus, type ClaudeMcpToolInspection } from './mcp/claude-mcp-tools.js';
|
|
16
16
|
import { authenticateMcpServer } from './mcp/claude-mcp-oauth.js';
|
|
17
17
|
import { servePraxisMcpStdio } from './mcp/praxis-mcp-server.js';
|
|
@@ -20,6 +20,7 @@ import { type ClaudeInteractiveToolCallbacks } from './tools/claude-interactive-
|
|
|
20
20
|
import { type TopLevelAgentSummary } from './application/top-level-agent-manager.js';
|
|
21
21
|
import { launchTmuxWorktree } from './platform/tmux-worktree.js';
|
|
22
22
|
import { type CliControls, type CliRuntimeInfo, type CliElicitationRequest, type CliElicitationResult } from './cli/protocol.js';
|
|
23
|
+
import { executeProviderAuthCommand } from './cli/provider-auth-command.js';
|
|
23
24
|
import { type PluginEvalDependencies } from './plugins/claude-plugin-eval.js';
|
|
24
25
|
import { type SelfUpdateResult } from './maintenance/self-update.js';
|
|
25
26
|
export { parseContextEnvironment, parseProviderEnvironment };
|
|
@@ -28,6 +29,7 @@ export interface CliIO {
|
|
|
28
29
|
stderr(message: string): void;
|
|
29
30
|
isTTY?: boolean;
|
|
30
31
|
readStdinLines?: () => AsyncIterable<string | Uint8Array>;
|
|
32
|
+
readSecret?: (prompt: string, signal?: AbortSignal) => Promise<string>;
|
|
31
33
|
}
|
|
32
34
|
interface SessionCommands {
|
|
33
35
|
teamLeadOperations?: TeamLeadOperations;
|
|
@@ -143,6 +145,8 @@ export interface CliDependencies extends InteractiveServiceFactory {
|
|
|
143
145
|
}): Promise<SessionCommands>;
|
|
144
146
|
createAutoModeCritic?(options: {
|
|
145
147
|
model?: string;
|
|
148
|
+
provider?: string;
|
|
149
|
+
providerProfile?: string;
|
|
146
150
|
dataPlane?: DataPlane;
|
|
147
151
|
configRoot?: string;
|
|
148
152
|
statePath?: string;
|
|
@@ -170,6 +174,7 @@ export interface CliDependencies extends InteractiveServiceFactory {
|
|
|
170
174
|
launchTmux?: typeof launchTmuxWorktree;
|
|
171
175
|
mcpAuthenticate?: typeof authenticateMcpServer;
|
|
172
176
|
mcpServe?: typeof servePraxisMcpStdio;
|
|
177
|
+
executeProviderAuthCommand?: typeof executeProviderAuthCommand;
|
|
173
178
|
selfUpdate?: (options: {
|
|
174
179
|
operation: 'install' | 'update';
|
|
175
180
|
target?: string;
|
|
@@ -177,6 +182,20 @@ export interface CliDependencies extends InteractiveServiceFactory {
|
|
|
177
182
|
signal?: AbortSignal;
|
|
178
183
|
}) => Promise<SelfUpdateResult>;
|
|
179
184
|
}
|
|
185
|
+
interface ConsoleSecretInput extends AsyncIterable<string | Uint8Array> {
|
|
186
|
+
readonly isTTY?: boolean;
|
|
187
|
+
readonly isRaw?: boolean;
|
|
188
|
+
isPaused(): boolean;
|
|
189
|
+
setRawMode?(enabled: boolean): unknown;
|
|
190
|
+
pause(): unknown;
|
|
191
|
+
resume(): unknown;
|
|
192
|
+
on(event: 'data', listener: (chunk: Buffer | string) => void): unknown;
|
|
193
|
+
removeListener(event: 'data', listener: (chunk: Buffer | string) => void): unknown;
|
|
194
|
+
}
|
|
195
|
+
interface ConsoleSecretOutput {
|
|
196
|
+
write(message: string): unknown;
|
|
197
|
+
}
|
|
198
|
+
export declare function readConsoleSecret(prompt: string, signal?: AbortSignal, input?: ConsoleSecretInput, output?: ConsoleSecretOutput): Promise<string>;
|
|
180
199
|
/**
|
|
181
200
|
* Shared runtime model precedence used by every consumer (provider
|
|
182
201
|
* construction, status/doctor output, and the interactive display):
|
|
@@ -194,9 +213,23 @@ export declare function resolveInteractiveRuntimeSettingsLocation(dataPlane: Dat
|
|
|
194
213
|
statePath: string;
|
|
195
214
|
};
|
|
196
215
|
export declare function resolveUnknownCostSidecarPath(dataPlane: DataPlane, configRoot: string): string;
|
|
216
|
+
export declare function resolveInteractiveProviderStartup(options: {
|
|
217
|
+
controls: CliControls;
|
|
218
|
+
configRoot: string;
|
|
219
|
+
statePath: string;
|
|
220
|
+
cwd: string;
|
|
221
|
+
environment?: NodeJS.ProcessEnv;
|
|
222
|
+
approveWorkspaceTrust?: (assessment: WorkspaceTrustAssessment) => boolean | Promise<boolean>;
|
|
223
|
+
}): Promise<{
|
|
224
|
+
effectiveModel: string | undefined;
|
|
225
|
+
trustProjectRequestAvailable: boolean;
|
|
226
|
+
}>;
|
|
197
227
|
export declare function createDefaultDependencies(entrypoint?: string): CliDependencies;
|
|
198
228
|
export declare function createBackgroundWorkerRuntime(workerSink: RuntimeEventSink, dispatch: {
|
|
199
229
|
argv: string[];
|
|
200
230
|
}, createService?: CliDependencies['createService']): Promise<Awaited<ReturnType<CliDependencies['createService']>>>;
|
|
231
|
+
export declare function agentDashboardWorkerArgv(invocation: CliControls & {
|
|
232
|
+
agent: string | undefined;
|
|
233
|
+
}): string[];
|
|
201
234
|
export declare function run(argv: readonly string[], io?: CliIO, dependencies?: CliDependencies, signal?: AbortSignal): Promise<number>;
|
|
202
235
|
//# sourceMappingURL=cli-runtime.d.ts.map
|