praxis-agent 0.19.0 → 0.20.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/dist/cli/interactive.d.ts +2 -2
- package/dist/cli/interactive.js +15 -3
- package/dist/cli/tui/doctor-dashboard.d.ts +3 -3
- package/dist/cli/tui/doctor-dashboard.js +1 -1
- package/dist/maintenance/doctor-diagnostic.d.ts +14 -1
- package/dist/maintenance/doctor-diagnostic.js +23 -8
- package/dist/maintenance/doctor.d.ts +6 -1
- package/dist/maintenance/doctor.js +16 -12
- package/package.json +1 -1
|
@@ -14,7 +14,7 @@ import type { AgentColorName } from '../compatibility/claude/agent-color.js';
|
|
|
14
14
|
import type { ClaudeResourceScope } from '../compatibility/claude/shared-resources.js';
|
|
15
15
|
import type { TuiHookConfiguration } from './tui/hook-settings.js';
|
|
16
16
|
import { type TuiSlashCommand } from './tui/slash-commands.js';
|
|
17
|
-
import { type DoctorReport } from '../maintenance/doctor.js';
|
|
17
|
+
import { type DoctorProgressListener, type DoctorReport } from '../maintenance/doctor.js';
|
|
18
18
|
import { type TuiAgentEntry, type TuiFileEntry } from './tui/file-picker.js';
|
|
19
19
|
import { type TuiEditorOptions, type TuiEditorResult } from './tui/external-editor.js';
|
|
20
20
|
import { type TuiClipboardContent } from './tui/clipboard.js';
|
|
@@ -135,7 +135,7 @@ interface InteractiveAppProps {
|
|
|
135
135
|
allowDangerouslySkipPermissions?: boolean;
|
|
136
136
|
additionalDirectories?: readonly string[];
|
|
137
137
|
diffLoader?: () => Promise<TuiDiffSnapshot>;
|
|
138
|
-
doctorLoader?: () => Promise<DoctorReport>;
|
|
138
|
+
doctorLoader?: (onProgress?: DoctorProgressListener) => Promise<DoctorReport>;
|
|
139
139
|
fileLoader?: () => Promise<readonly TuiFileEntry[]>;
|
|
140
140
|
externalEditor?: (prompt: string, options: TuiEditorOptions) => Promise<TuiEditorResult>;
|
|
141
141
|
keybindingsConfigRoot?: string;
|
package/dist/cli/interactive.js
CHANGED
|
@@ -20,7 +20,7 @@ import { addTuiPermissionRule, loadTuiPermissionRules, removeTuiPermissionRule,
|
|
|
20
20
|
import { createRecentlyDeniedStore, } from './tui/recently-denied.js';
|
|
21
21
|
import { agentColorMessage, parseAgentColorInput, } from '../compatibility/claude/agent-color.js';
|
|
22
22
|
import { filterTuiSlashCommands, mergeTuiSlashCommands, slashCommandQuery, } from './tui/slash-commands.js';
|
|
23
|
-
import { runDoctor } from '../maintenance/doctor.js';
|
|
23
|
+
import { runDoctor, } from '../maintenance/doctor.js';
|
|
24
24
|
import { canonicalClaudeCostModelName, formatCostSummary, } from './tui/cost-summary.js';
|
|
25
25
|
import { createComposerEditor, deleteComposerBackward, deleteComposerForward, deleteComposerToEnd, deleteComposerToStart, deleteComposerWordBackward, insertComposerText, moveComposerCursor, moveComposerCursorByWord, } from './tui/composer-editor.js';
|
|
26
26
|
import { applyMentionReference, fileReferenceAtCursor, filterTuiMentionEntries, loadTuiFileEntries, } from './tui/file-picker.js';
|
|
@@ -274,7 +274,7 @@ export function InteractiveApp({ factory, initialSessions, initialPrompt, initia
|
|
|
274
274
|
const runtimeGitignoreRef = useRef(true);
|
|
275
275
|
const loadDiffSnapshot = useMemo(() => diffLoader ?? (() => loadGitDiff(runtimeCwd)), [diffLoader, runtimeCwd]);
|
|
276
276
|
const loadDoctorReport = useMemo(() => doctorLoader ??
|
|
277
|
-
(async () => {
|
|
277
|
+
(async (onProgress) => {
|
|
278
278
|
const configuredRoot = process.env.CLAUDE_CONFIG_DIR || undefined;
|
|
279
279
|
const configRoot = resolve(configuredRoot ?? resolve(homedir(), '.claude'));
|
|
280
280
|
const claudeStatePath = configuredRoot
|
|
@@ -295,6 +295,7 @@ export function InteractiveApp({ factory, initialSessions, initialPrompt, initia
|
|
|
295
295
|
...(process.argv[1] === undefined
|
|
296
296
|
? {}
|
|
297
297
|
: { invokedBinaryPath: process.argv[1] }),
|
|
298
|
+
...(onProgress === undefined ? {} : { onProgress }),
|
|
298
299
|
});
|
|
299
300
|
}), [doctorLoader, runtimeCwd, display.version, configTarget]);
|
|
300
301
|
const loadFiles = useMemo(() => fileLoader ??
|
|
@@ -1849,7 +1850,18 @@ export function InteractiveApp({ factory, initialSessions, initialPrompt, initia
|
|
|
1849
1850
|
const loading = (async () => {
|
|
1850
1851
|
setBusy(true);
|
|
1851
1852
|
try {
|
|
1852
|
-
const report = await loadDoctorReport()
|
|
1853
|
+
const report = await loadDoctorReport((progress) => {
|
|
1854
|
+
const current = menuRef.current;
|
|
1855
|
+
if (current?.kind === 'doctor' && current.generation === generation) {
|
|
1856
|
+
updateMenu({
|
|
1857
|
+
kind: 'doctor',
|
|
1858
|
+
generation,
|
|
1859
|
+
loading: false,
|
|
1860
|
+
report: progress,
|
|
1861
|
+
error: null,
|
|
1862
|
+
});
|
|
1863
|
+
}
|
|
1864
|
+
});
|
|
1853
1865
|
const current = menuRef.current;
|
|
1854
1866
|
if (current?.kind === 'doctor' && current.generation === generation) {
|
|
1855
1867
|
updateMenu({
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import type { DoctorCheck, DoctorReport } from '../../maintenance/doctor.js';
|
|
2
|
+
import type { DoctorCheck, DoctorProgressReport, DoctorReport } from '../../maintenance/doctor.js';
|
|
3
3
|
export interface DoctorWarningGroup {
|
|
4
4
|
heading: string;
|
|
5
5
|
checks: readonly DoctorCheck[];
|
|
6
6
|
}
|
|
7
|
-
export declare function projectDoctorWarningGroups(report: DoctorReport): readonly DoctorWarningGroup[];
|
|
7
|
+
export declare function projectDoctorWarningGroups(report: DoctorReport | DoctorProgressReport): readonly DoctorWarningGroup[];
|
|
8
8
|
export declare function DoctorDashboard({ loading, report, error, width, screenReader, }: {
|
|
9
9
|
loading: boolean;
|
|
10
|
-
report: DoctorReport | null;
|
|
10
|
+
report: DoctorReport | DoctorProgressReport | null;
|
|
11
11
|
error: string | null;
|
|
12
12
|
width: number;
|
|
13
13
|
screenReader: boolean;
|
|
@@ -77,6 +77,6 @@ export function DoctorDashboard({ loading, report, error, width, screenReader, }
|
|
|
77
77
|
if (report === null)
|
|
78
78
|
return null;
|
|
79
79
|
const { diagnostic, updates } = report;
|
|
80
|
-
return (_jsxs(Box, { flexDirection: "column", width: Math.min(100, width), children: [_jsx(Text, { bold: true, children: " Doctor:" }), _jsx(Text, { children: " " }), _jsx(Text, { bold: true, children: " Diagnostics" }), _jsx(Text, { children: `Currently running: Praxis ${diagnostic.version} (${diagnostic.installationType})` }), diagnostic.packageManager !== null && (_jsx(Text, { children: `Package manager: ${diagnostic.packageManager}` })), _jsx(Text, { children: `Path: ${diagnostic.installationPath}` }), _jsx(Text, { children: `Invoked: ${diagnostic.invokedBinary}` }), _jsx(Text, { children: `Config install method: ${diagnostic.configInstallMethod}` }), diagnostic.search.working ? (_jsxs(_Fragment, { children: [_jsx(Text, { children: `Search: OK (${diagnostic.search.mode})` }), diagnostic.search.systemPath !== null && (_jsx(Text, { children: `└ ${diagnostic.search.systemPath}` }))] })) : (_jsx(Text, { children: "Search: unavailable" })), diagnostic.multipleInstallations.length > 1 && (_jsxs(_Fragment, { children: [_jsx(Text, { bold: true, children: "Multiple installations found" }), diagnostic.multipleInstallations.map((path) => (_jsx(Text, { children: `- ${path}` }, path)))] })), diagnostic.recommendation !== null && (_jsx(Text, { children: `Recommendation: ${diagnostic.recommendation}` })), diagnostic.warnings.map((warning) => (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: warning.issue }), _jsx(Text, { children: `└ Fix: ${warning.fix}` })] }, warning.issue))), _jsx(Text, { children: " " }), _jsx(Text, { bold: true, children: " Updates" }), _jsx(Text, { children: `Auto-updates: ${updates.autoUpdates}` }), updates.hasUpdatePermissions !== null && (_jsx(Text, { children: `Update permissions: ${updates.hasUpdatePermissions ? 'yes' : 'no'}` })), _jsx(Text, { children: `Auto-update channel: ${updates.channel}` }), updates.registryStatus === 'available' ? (_jsxs(_Fragment, { children: [updates.stableVersion !== null && (_jsx(Text, { children: `Stable version: ${updates.stableVersion}` })), _jsx(Text, { children: `Latest version: ${updates.latestVersion ?? 'unknown'}` })] })) : (_jsx(Text, { children: "\u2514 Failed to fetch versions" })), _jsx(WarningGroups, { report: report, screenReader: screenReader }), _jsx(Text, { children: " " }), _jsx(Text, { children: doctorSummary(report) }), _jsx(Text, { children: `Summary: ${report.summary.passed} passed, ${report.summary.warnings} warnings, ${report.summary.failed} failed.` }), _jsx(Text, { children: " " }), _jsx(Text, { dimColor: true, children: footer })] }));
|
|
80
|
+
return (_jsxs(Box, { flexDirection: "column", width: Math.min(100, width), children: [_jsx(Text, { bold: true, children: " Doctor:" }), _jsx(Text, { children: " " }), _jsx(Text, { bold: true, children: " Diagnostics" }), _jsx(Text, { children: `Currently running: Praxis ${diagnostic.version} (${diagnostic.installationType})` }), diagnostic.packageManager !== null && (_jsx(Text, { children: `Package manager: ${diagnostic.packageManager}` })), _jsx(Text, { children: `Path: ${diagnostic.installationPath}` }), _jsx(Text, { children: `Invoked: ${diagnostic.invokedBinary}` }), _jsx(Text, { children: `Config install method: ${diagnostic.configInstallMethod}` }), diagnostic.search.working ? (_jsxs(_Fragment, { children: [_jsx(Text, { children: `Search: OK (${diagnostic.search.mode})` }), diagnostic.search.systemPath !== null && (_jsx(Text, { children: `└ ${diagnostic.search.systemPath}` }))] })) : (_jsx(Text, { children: "Search: unavailable" })), diagnostic.multipleInstallations.length > 1 && (_jsxs(_Fragment, { children: [_jsx(Text, { bold: true, children: "Multiple installations found" }), diagnostic.multipleInstallations.map((path) => (_jsx(Text, { children: `- ${path}` }, path)))] })), diagnostic.recommendation !== null && (_jsx(Text, { children: `Recommendation: ${diagnostic.recommendation}` })), diagnostic.warnings.map((warning) => (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: warning.issue }), _jsx(Text, { children: `└ Fix: ${warning.fix}` })] }, warning.issue))), _jsx(Text, { children: " " }), _jsx(Text, { bold: true, children: " Updates" }), _jsx(Text, { children: `Auto-updates: ${updates.autoUpdates}` }), updates.hasUpdatePermissions !== null && (_jsx(Text, { children: `Update permissions: ${updates.hasUpdatePermissions ? 'yes' : 'no'}` })), _jsx(Text, { children: `Auto-update channel: ${updates.channel}` }), updates.registryStatus === 'available' ? (_jsxs(_Fragment, { children: [updates.stableVersion !== null && (_jsx(Text, { children: `Stable version: ${updates.stableVersion}` })), _jsx(Text, { children: `Latest version: ${updates.latestVersion ?? 'unknown'}` })] })) : updates.registryStatus === 'loading' ? (_jsx(Text, { children: "Checking for updates\u2026" })) : (_jsx(Text, { children: "\u2514 Failed to fetch versions" })), _jsx(WarningGroups, { report: report, screenReader: screenReader }), _jsx(Text, { children: " " }), _jsx(Text, { children: doctorSummary(report) }), _jsx(Text, { children: `Summary: ${report.summary.passed} passed, ${report.summary.warnings} warnings, ${report.summary.failed} failed.` }), _jsx(Text, { children: " " }), _jsx(Text, { dimColor: true, children: footer })] }));
|
|
81
81
|
}
|
|
82
82
|
//# sourceMappingURL=doctor-dashboard.js.map
|
|
@@ -20,15 +20,22 @@ export interface DoctorInstallationDiagnostic {
|
|
|
20
20
|
readonly multipleInstallations: readonly string[];
|
|
21
21
|
readonly warnings: readonly DoctorDiagnosticWarning[];
|
|
22
22
|
}
|
|
23
|
-
export interface
|
|
23
|
+
export interface DoctorUpdateBaseDiagnostic {
|
|
24
24
|
readonly autoUpdates: string;
|
|
25
25
|
readonly hasUpdatePermissions: boolean | null;
|
|
26
26
|
readonly channel: 'latest' | 'stable';
|
|
27
|
+
}
|
|
28
|
+
export interface DoctorUpdateDiagnostic extends DoctorUpdateBaseDiagnostic {
|
|
27
29
|
readonly stableVersion: string | null;
|
|
28
30
|
readonly latestVersion: string | null;
|
|
29
31
|
readonly registryStatus: 'available' | 'unavailable';
|
|
30
32
|
readonly error?: string;
|
|
31
33
|
}
|
|
34
|
+
export interface DoctorPendingUpdateDiagnostic extends DoctorUpdateBaseDiagnostic {
|
|
35
|
+
readonly stableVersion: null;
|
|
36
|
+
readonly latestVersion: null;
|
|
37
|
+
readonly registryStatus: 'loading';
|
|
38
|
+
}
|
|
32
39
|
export interface PraxisDistTags {
|
|
33
40
|
stable?: string;
|
|
34
41
|
latest?: string;
|
|
@@ -49,6 +56,12 @@ export interface DoctorDiagnosticsResult {
|
|
|
49
56
|
diagnostic: DoctorInstallationDiagnostic;
|
|
50
57
|
updates: DoctorUpdateDiagnostic;
|
|
51
58
|
}
|
|
59
|
+
export interface DoctorLocalDiagnosticsResult {
|
|
60
|
+
diagnostic: DoctorInstallationDiagnostic;
|
|
61
|
+
updates: DoctorPendingUpdateDiagnostic;
|
|
62
|
+
}
|
|
52
63
|
export declare function loadPraxisDistTags(): Promise<PraxisDistTags>;
|
|
64
|
+
export declare function resolveDoctorUpdates(options: DoctorDiagnosticOptions, pendingUpdates: DoctorPendingUpdateDiagnostic): Promise<DoctorUpdateDiagnostic>;
|
|
65
|
+
export declare function collectDoctorLocalDiagnostics(options: DoctorDiagnosticOptions): Promise<DoctorLocalDiagnosticsResult>;
|
|
53
66
|
export declare function collectDoctorDiagnostics(options: DoctorDiagnosticOptions): Promise<DoctorDiagnosticsResult>;
|
|
54
67
|
//# sourceMappingURL=doctor-diagnostic.d.ts.map
|
|
@@ -96,9 +96,21 @@ async function updatePermissions(directory) {
|
|
|
96
96
|
return code === 'EACCES' || code === 'EPERM' ? false : null;
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
|
-
async function
|
|
99
|
+
async function buildPendingUpdateDiagnostic(options, installation) {
|
|
100
100
|
const checkUpdatePermissions = options.checkUpdatePermissions ?? updatePermissions;
|
|
101
101
|
const hasUpdatePermissions = await checkUpdatePermissions(dirname(installation.invokedBinary));
|
|
102
|
+
return {
|
|
103
|
+
autoUpdates: installation.installationType === 'npm'
|
|
104
|
+
? 'Manual (praxis update)'
|
|
105
|
+
: 'Managed by source checkout',
|
|
106
|
+
hasUpdatePermissions,
|
|
107
|
+
channel: options.autoUpdateChannel,
|
|
108
|
+
stableVersion: null,
|
|
109
|
+
latestVersion: null,
|
|
110
|
+
registryStatus: 'loading',
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
export async function resolveDoctorUpdates(options, pendingUpdates) {
|
|
102
114
|
let stableVersion = null;
|
|
103
115
|
let latestVersion = null;
|
|
104
116
|
let registryStatus = 'unavailable';
|
|
@@ -120,18 +132,16 @@ async function buildUpdateDiagnostic(options, installation) {
|
|
|
120
132
|
error = `${REGISTRY_ERROR}: ${cause instanceof Error ? cause.message : String(cause)}`;
|
|
121
133
|
}
|
|
122
134
|
return {
|
|
123
|
-
autoUpdates:
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
hasUpdatePermissions,
|
|
127
|
-
channel: options.autoUpdateChannel,
|
|
135
|
+
autoUpdates: pendingUpdates.autoUpdates,
|
|
136
|
+
hasUpdatePermissions: pendingUpdates.hasUpdatePermissions,
|
|
137
|
+
channel: pendingUpdates.channel,
|
|
128
138
|
stableVersion,
|
|
129
139
|
latestVersion,
|
|
130
140
|
registryStatus,
|
|
131
141
|
...(error === undefined ? {} : { error }),
|
|
132
142
|
};
|
|
133
143
|
}
|
|
134
|
-
export async function
|
|
144
|
+
export async function collectDoctorLocalDiagnostics(options) {
|
|
135
145
|
const installationPath = await readableExecutable(options.executablePath);
|
|
136
146
|
const invokedBinary = resolve(options.invokedBinaryPath ?? options.executablePath);
|
|
137
147
|
const installationType = installationPath
|
|
@@ -171,10 +181,15 @@ export async function collectDoctorDiagnostics(options) {
|
|
|
171
181
|
multipleInstallations,
|
|
172
182
|
warnings,
|
|
173
183
|
};
|
|
174
|
-
const updates = await
|
|
184
|
+
const updates = await buildPendingUpdateDiagnostic(options, {
|
|
175
185
|
installationType,
|
|
176
186
|
invokedBinary,
|
|
177
187
|
});
|
|
178
188
|
return { diagnostic, updates };
|
|
179
189
|
}
|
|
190
|
+
export async function collectDoctorDiagnostics(options) {
|
|
191
|
+
const local = await collectDoctorLocalDiagnostics(options);
|
|
192
|
+
const updates = await resolveDoctorUpdates(options, local.updates);
|
|
193
|
+
return { diagnostic: local.diagnostic, updates };
|
|
194
|
+
}
|
|
180
195
|
//# sourceMappingURL=doctor-diagnostic.js.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type VersionCommand } from '../platform/claude-version.js';
|
|
2
|
-
import { type DoctorInstallationDiagnostic, type DoctorUpdateDiagnostic, type PraxisDistTagLoader } from './doctor-diagnostic.js';
|
|
2
|
+
import { type DoctorInstallationDiagnostic, type DoctorPendingUpdateDiagnostic, type DoctorUpdateDiagnostic, type PraxisDistTagLoader } from './doctor-diagnostic.js';
|
|
3
3
|
export interface DoctorCheck {
|
|
4
4
|
id: 'installation' | 'node' | 'provider' | 'config-root' | 'settings' | 'plugins' | 'mcp' | 'permissions' | 'resources' | 'hooks' | 'claude-runtime';
|
|
5
5
|
status: 'pass' | 'warn' | 'fail';
|
|
@@ -19,6 +19,10 @@ export interface DoctorReport {
|
|
|
19
19
|
failed: number;
|
|
20
20
|
};
|
|
21
21
|
}
|
|
22
|
+
export type DoctorProgressReport = Omit<DoctorReport, 'updates'> & {
|
|
23
|
+
updates: DoctorPendingUpdateDiagnostic;
|
|
24
|
+
};
|
|
25
|
+
export type DoctorProgressListener = (report: DoctorProgressReport) => void;
|
|
22
26
|
export interface DoctorOptions {
|
|
23
27
|
version: string;
|
|
24
28
|
executablePath: string;
|
|
@@ -33,6 +37,7 @@ export interface DoctorOptions {
|
|
|
33
37
|
autoUpdateChannel: 'latest' | 'stable';
|
|
34
38
|
invokedBinaryPath?: string;
|
|
35
39
|
loadDistTags?: PraxisDistTagLoader;
|
|
40
|
+
onProgress?: DoctorProgressListener;
|
|
36
41
|
}
|
|
37
42
|
export declare function runDoctor(options: DoctorOptions): Promise<DoctorReport>;
|
|
38
43
|
export declare function formatDoctorReport(report: DoctorReport): string;
|
|
@@ -15,7 +15,7 @@ import { ContextBudget } from '../core/context-budget.js';
|
|
|
15
15
|
import { ModelPricingRegistry } from '../core/usage.js';
|
|
16
16
|
import { detectInstalledClaudeVersion, } from '../platform/claude-version.js';
|
|
17
17
|
import { redactSensitiveText, sensitiveEnvironmentValues, } from '../platform/sensitive-data.js';
|
|
18
|
-
import {
|
|
18
|
+
import { collectDoctorLocalDiagnostics, resolveDoctorUpdates, } from './doctor-diagnostic.js';
|
|
19
19
|
function isRecord(value) {
|
|
20
20
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
21
21
|
}
|
|
@@ -129,7 +129,7 @@ export async function runDoctor(options) {
|
|
|
129
129
|
const configRoot = resolve(options.configRoot);
|
|
130
130
|
const cwd = resolve(options.cwd);
|
|
131
131
|
const sensitiveValues = sensitiveEnvironmentValues(options.environment);
|
|
132
|
-
const
|
|
132
|
+
const diagnosticOptions = {
|
|
133
133
|
version: options.version,
|
|
134
134
|
executablePath: options.executablePath,
|
|
135
135
|
...(options.invokedBinaryPath === undefined
|
|
@@ -141,7 +141,9 @@ export async function runDoctor(options) {
|
|
|
141
141
|
...(options.loadDistTags === undefined
|
|
142
142
|
? {}
|
|
143
143
|
: { loadDistTags: options.loadDistTags }),
|
|
144
|
-
}
|
|
144
|
+
};
|
|
145
|
+
const local = await collectDoctorLocalDiagnostics(diagnosticOptions);
|
|
146
|
+
const updatesPromise = resolveDoctorUpdates(diagnosticOptions, local.updates);
|
|
145
147
|
let settings;
|
|
146
148
|
const checks = [];
|
|
147
149
|
checks.push(await capture('installation', async () => {
|
|
@@ -372,26 +374,28 @@ export async function runDoctor(options) {
|
|
|
372
374
|
check.summary = redactSensitiveText(check.summary, sensitiveValues);
|
|
373
375
|
}
|
|
374
376
|
}
|
|
375
|
-
const reportUpdates = updates.error === undefined
|
|
376
|
-
? updates
|
|
377
|
-
: {
|
|
378
|
-
...updates,
|
|
379
|
-
error: redactSensitiveText(updates.error, sensitiveValues),
|
|
380
|
-
};
|
|
381
377
|
const summary = {
|
|
382
378
|
passed: checks.filter((check) => check.status === 'pass').length,
|
|
383
379
|
warnings: checks.filter((check) => check.status === 'warn').length,
|
|
384
380
|
failed: checks.filter((check) => check.status === 'fail').length,
|
|
385
381
|
};
|
|
386
|
-
|
|
382
|
+
const base = {
|
|
387
383
|
type: 'doctor',
|
|
388
384
|
ok: checks.every((check) => check.status !== 'fail'),
|
|
389
385
|
praxisVersion: options.version,
|
|
390
|
-
diagnostic,
|
|
391
|
-
updates: reportUpdates,
|
|
386
|
+
diagnostic: local.diagnostic,
|
|
392
387
|
checks,
|
|
393
388
|
summary,
|
|
394
389
|
};
|
|
390
|
+
options.onProgress?.({ ...base, updates: local.updates });
|
|
391
|
+
const updates = await updatesPromise;
|
|
392
|
+
const reportUpdates = updates.error === undefined
|
|
393
|
+
? updates
|
|
394
|
+
: {
|
|
395
|
+
...updates,
|
|
396
|
+
error: redactSensitiveText(updates.error, sensitiveValues),
|
|
397
|
+
};
|
|
398
|
+
return { ...base, updates: reportUpdates };
|
|
395
399
|
}
|
|
396
400
|
export function formatDoctorReport(report) {
|
|
397
401
|
const lines = ['Praxis doctor', ''];
|