reslop 0.2.0 → 0.2.3
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/CHANGELOG.md +27 -1
- package/README.md +13 -2
- package/lib/ansi.js +263 -6
- package/lib/api.js +2 -0
- package/lib/capabilities.js +6 -0
- package/lib/cli.js +13 -2
- package/lib/deps.js +43 -3
- package/lib/git-branches.js +228 -17
- package/lib/git-reword-todo.js +20 -0
- package/lib/git.js +20 -3
- package/lib/keys.js +10 -4
- package/lib/npm-commands.js +513 -0
- package/lib/render/branches.js +23 -58
- package/lib/render/chrome.js +156 -99
- package/lib/render/commits.js +643 -31
- package/lib/render/diff.js +4 -4
- package/lib/render/frame.js +51 -5
- package/lib/render/notes.js +22 -5
- package/lib/render/npm.js +228 -0
- package/lib/render/primitives.js +48 -34
- package/lib/render/render.js +3 -3
- package/lib/report-model.js +127 -0
- package/lib/report-parse.js +94 -0
- package/lib/report-render.js +87 -0
- package/lib/report-run.js +164 -0
- package/lib/report-test.js +506 -0
- package/lib/report-tools.js +311 -0
- package/lib/review-merge.js +270 -0
- package/lib/review.js +38 -6
- package/lib/session/actions.js +81 -5
- package/lib/session/commit.js +187 -19
- package/lib/session/compose.js +96 -32
- package/lib/session/dispatch.js +36 -2
- package/lib/session/files-pane.js +36 -6
- package/lib/session/lifecycle.js +116 -16
- package/lib/session/navigation.js +1 -0
- package/lib/session/npm.js +335 -0
- package/lib/session/pointer.js +12 -1
- package/lib/session/todos.js +29 -1
- package/lib/session/view.js +14 -3
- package/lib/session/watch.js +120 -8
- package/lib/session.js +11 -2
- package/package.json +7 -7
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { stripAnsi } = require('./ansi.js');
|
|
4
|
+
const commands = require('./npm-commands.js');
|
|
5
|
+
|
|
6
|
+
const { withoutNodeFrame, indentStack, relativize } = commands;
|
|
7
|
+
|
|
8
|
+
const summary = () => ({
|
|
9
|
+
tests: null,
|
|
10
|
+
passed: null,
|
|
11
|
+
failed: null,
|
|
12
|
+
skipped: null,
|
|
13
|
+
errors: null,
|
|
14
|
+
warnings: null,
|
|
15
|
+
duration: '',
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const problem = (fields = {}) => {
|
|
19
|
+
const trace = fields.trace || '';
|
|
20
|
+
const traces = fields.traces || (trace ? [trace] : []);
|
|
21
|
+
return {
|
|
22
|
+
severity: fields.severity || 'error',
|
|
23
|
+
name: fields.name || '',
|
|
24
|
+
message: fields.message || '',
|
|
25
|
+
trace,
|
|
26
|
+
traces,
|
|
27
|
+
duration: fields.duration || '',
|
|
28
|
+
code: fields.code || '',
|
|
29
|
+
operator: fields.operator || '',
|
|
30
|
+
expected: fields.expected || '',
|
|
31
|
+
actual: fields.actual || '',
|
|
32
|
+
extra: fields.extra || [],
|
|
33
|
+
count: fields.count === undefined ? 1 : fields.count,
|
|
34
|
+
omitted: fields.omitted || 0,
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const report = (tool, fields = {}) => ({
|
|
39
|
+
tool,
|
|
40
|
+
ok: fields.ok !== false,
|
|
41
|
+
summary: fields.summary || summary(),
|
|
42
|
+
problems: fields.problems || [],
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const userTrace = (text, root) => {
|
|
46
|
+
const lines = stripAnsi(`${text ?? ''}`).split(/\r?\n/);
|
|
47
|
+
const kept = [];
|
|
48
|
+
for (const line of lines) {
|
|
49
|
+
const next = withoutNodeFrame(line);
|
|
50
|
+
if (next === null) continue;
|
|
51
|
+
kept.push(relativize(indentStack(next), root).trimEnd());
|
|
52
|
+
}
|
|
53
|
+
while (kept.length && kept[kept.length - 1] === '') kept.pop();
|
|
54
|
+
return kept.join('\n').trim();
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const normalizeMessage = (message) => {
|
|
58
|
+
const text = `${message ?? ''}`.trim().replace(/\s+/g, ' ');
|
|
59
|
+
return text.replace(/\s+\S+:\d+:\d+$/, '');
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const groupKey = (item) =>
|
|
63
|
+
[
|
|
64
|
+
item.severity,
|
|
65
|
+
item.code,
|
|
66
|
+
item.operator,
|
|
67
|
+
item.expected,
|
|
68
|
+
item.actual,
|
|
69
|
+
normalizeMessage(item.message),
|
|
70
|
+
].join('\0');
|
|
71
|
+
|
|
72
|
+
const groupProblems = (problems) => {
|
|
73
|
+
const groups = new Map();
|
|
74
|
+
const order = [];
|
|
75
|
+
for (const item of problems) {
|
|
76
|
+
const key = groupKey(item);
|
|
77
|
+
let group = groups.get(key);
|
|
78
|
+
if (!group) {
|
|
79
|
+
group = problem({ ...item, count: 0, traces: [], omitted: 0 });
|
|
80
|
+
groups.set(key, group);
|
|
81
|
+
order.push(group);
|
|
82
|
+
}
|
|
83
|
+
group.count += 1;
|
|
84
|
+
if (item.trace && group.traces.length < 3) group.traces.push(item.trace);
|
|
85
|
+
}
|
|
86
|
+
for (const group of order) {
|
|
87
|
+
group.trace = group.traces[0] || '';
|
|
88
|
+
group.omitted = Math.max(0, group.count - group.traces.length);
|
|
89
|
+
}
|
|
90
|
+
return order;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const groupReport = (item) =>
|
|
94
|
+
report(item.tool, {
|
|
95
|
+
ok: item.ok,
|
|
96
|
+
summary: item.summary,
|
|
97
|
+
problems: groupProblems(item.problems),
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const reduceStderr = (text, root) => userTrace(text, root);
|
|
101
|
+
|
|
102
|
+
const shortTail = (text) => {
|
|
103
|
+
const lines = `${text ?? ''}`.trim().split(/\r?\n/);
|
|
104
|
+
if (lines.length <= 20) return lines.join('\n');
|
|
105
|
+
return lines.slice(-20).join('\n');
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const envelope = (reports, exit, stderr) => {
|
|
109
|
+
const status = exit === null || exit === undefined ? 1 : exit;
|
|
110
|
+
const ok = status === 0;
|
|
111
|
+
const items = [];
|
|
112
|
+
for (const item of reports) {
|
|
113
|
+
items.push(report(item.tool, { ...item, ok }));
|
|
114
|
+
}
|
|
115
|
+
return { ok, exit: status, reports: items, stderr: stderr || '' };
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
module.exports = {
|
|
119
|
+
summary,
|
|
120
|
+
problem,
|
|
121
|
+
report,
|
|
122
|
+
userTrace,
|
|
123
|
+
groupReport,
|
|
124
|
+
reduceStderr,
|
|
125
|
+
shortTail,
|
|
126
|
+
envelope,
|
|
127
|
+
};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { stripAnsi } = require('./ansi.js');
|
|
4
|
+
const model = require('./report-model.js');
|
|
5
|
+
const testParse = require('./report-test.js');
|
|
6
|
+
const toolParse = require('./report-tools.js');
|
|
7
|
+
|
|
8
|
+
const { problem, report, groupReport } = model;
|
|
9
|
+
const { reduceStderr, shortTail, envelope } = model;
|
|
10
|
+
const { parseTap, parseNodeJsonl, parseTestJson, parseSpec } = testParse;
|
|
11
|
+
const { parseToolJson, parseToolText } = toolParse;
|
|
12
|
+
|
|
13
|
+
const KNOWN = new Set([
|
|
14
|
+
'test',
|
|
15
|
+
'tsc',
|
|
16
|
+
'eslint',
|
|
17
|
+
'prettier',
|
|
18
|
+
'audit',
|
|
19
|
+
'outdated',
|
|
20
|
+
'ls',
|
|
21
|
+
]);
|
|
22
|
+
|
|
23
|
+
const toolHint = (program, args) => {
|
|
24
|
+
const name = `${program ?? ''}`.split(/[/\\]/).pop();
|
|
25
|
+
const list = args || [];
|
|
26
|
+
const joined = [name, ...list].join(' ');
|
|
27
|
+
if (name === 'eslint') return 'eslint';
|
|
28
|
+
if (name === 'tsc') return 'tsc';
|
|
29
|
+
if (name === 'prettier') return 'prettier';
|
|
30
|
+
if (/\baudit\b/.test(joined)) return 'audit';
|
|
31
|
+
if (/\boutdated\b/.test(joined)) return 'outdated';
|
|
32
|
+
if (name === 'npm' || name === 'pnpm' || name === 'npm.cmd') {
|
|
33
|
+
if (/\b(ls|list)\b/.test(joined)) return 'ls';
|
|
34
|
+
}
|
|
35
|
+
if (name === 'node' && (args || []).includes('--test')) return 'test';
|
|
36
|
+
return '';
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const parseJson = (text) => {
|
|
40
|
+
const trimmed = `${text ?? ''}`.trim();
|
|
41
|
+
if (!trimmed || (trimmed[0] !== '{' && trimmed[0] !== '[')) return null;
|
|
42
|
+
try {
|
|
43
|
+
return JSON.parse(trimmed);
|
|
44
|
+
} catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const parseJsonReports = (text, root) => {
|
|
50
|
+
const node = parseNodeJsonl(text, root);
|
|
51
|
+
if (node) return [node];
|
|
52
|
+
const data = parseJson(text);
|
|
53
|
+
if (!data) return null;
|
|
54
|
+
const test = parseTestJson(data, root);
|
|
55
|
+
if (test) return [test];
|
|
56
|
+
const tools = parseToolJson(data, root);
|
|
57
|
+
if (tools) return tools;
|
|
58
|
+
return [];
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const parseReports = (text, root) => {
|
|
62
|
+
const json = parseJsonReports(text, root);
|
|
63
|
+
if (json) return json;
|
|
64
|
+
const reports = [];
|
|
65
|
+
const tap = parseTap(text, root);
|
|
66
|
+
if (tap) reports.push(tap);
|
|
67
|
+
const tools = parseToolText(text, root);
|
|
68
|
+
for (const item of tools) reports.push(item);
|
|
69
|
+
if (!tap) {
|
|
70
|
+
const spec = parseSpec(text, root);
|
|
71
|
+
if (spec) reports.push(spec);
|
|
72
|
+
}
|
|
73
|
+
return reports;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const withHint = (reports, text, exit, hint) => {
|
|
77
|
+
if (reports.length || !`${text ?? ''}`.trim() || exit === 0) return reports;
|
|
78
|
+
const tool = KNOWN.has(hint) ? hint : 'test';
|
|
79
|
+
return [report(tool, { problems: [problem({ message: shortTail(text) })] })];
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const buildDocument = (stdout, stderr, root, exit, hint) => {
|
|
83
|
+
const text = stripAnsi(stdout);
|
|
84
|
+
const reports = withHint(parseReports(text, root), text, exit, hint);
|
|
85
|
+
const grouped = [];
|
|
86
|
+
for (const item of reports) grouped.push(groupReport(item));
|
|
87
|
+
return envelope(grouped, exit, reduceStderr(stderr, root));
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
module.exports = {
|
|
91
|
+
toolHint,
|
|
92
|
+
parseReports,
|
|
93
|
+
buildDocument,
|
|
94
|
+
};
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const NOTICE_HEAD =
|
|
4
|
+
'reslop: reduced output; passing results are omitted ' +
|
|
5
|
+
'and similar problems are grouped';
|
|
6
|
+
|
|
7
|
+
const NOTICE = [
|
|
8
|
+
NOTICE_HEAD,
|
|
9
|
+
'If reduced output hides information needed for debugging,',
|
|
10
|
+
'rerun the same command with RESLOP_OUTPUT=raw.',
|
|
11
|
+
].join('\n');
|
|
12
|
+
|
|
13
|
+
const addRow = (rows, key, value) => {
|
|
14
|
+
if (value === null || value === undefined || value === '') return;
|
|
15
|
+
rows.push([key, `${value}`]);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const summaryRows = (stats) => {
|
|
19
|
+
const rows = [];
|
|
20
|
+
addRow(rows, 'passed', stats.passed);
|
|
21
|
+
addRow(rows, 'failed', stats.failed);
|
|
22
|
+
addRow(rows, 'skipped', stats.skipped);
|
|
23
|
+
addRow(rows, 'errors', stats.errors);
|
|
24
|
+
addRow(rows, 'warnings', stats.warnings);
|
|
25
|
+
addRow(rows, 'duration', stats.duration);
|
|
26
|
+
return rows;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const problemRows = (item) => {
|
|
30
|
+
const rows = [];
|
|
31
|
+
addRow(rows, 'severity', item.severity);
|
|
32
|
+
addRow(rows, 'duration', item.duration);
|
|
33
|
+
addRow(rows, 'code', item.code);
|
|
34
|
+
addRow(rows, 'operator', item.operator);
|
|
35
|
+
addRow(rows, 'expected', item.expected);
|
|
36
|
+
addRow(rows, 'actual', item.actual);
|
|
37
|
+
addRow(rows, 'message', item.message);
|
|
38
|
+
for (const extra of item.extra) addRow(rows, extra[0], extra[1]);
|
|
39
|
+
if (item.count > 1) addRow(rows, 'count', item.count);
|
|
40
|
+
if (item.omitted > 0) addRow(rows, 'omitted', item.omitted);
|
|
41
|
+
return rows;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const markdownValue = (value) => {
|
|
45
|
+
const text = `${value}`;
|
|
46
|
+
if (!text.includes('\n')) return text;
|
|
47
|
+
return `\n${text}`;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const markdownProblem = (item) => {
|
|
51
|
+
const title = item.name || item.message || item.code || 'problem';
|
|
52
|
+
const lines = ['', `## ${title}`, ''];
|
|
53
|
+
for (const row of problemRows(item)) {
|
|
54
|
+
lines.push(`- ${row[0]}: ${markdownValue(row[1])}`);
|
|
55
|
+
}
|
|
56
|
+
for (const trace of item.traces) {
|
|
57
|
+
if (!trace) continue;
|
|
58
|
+
lines.push(`- trace:\n${trace}`);
|
|
59
|
+
}
|
|
60
|
+
return lines;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const markdownReport = (item) => {
|
|
64
|
+
const lines = ['', `# ${item.tool}`, '', `ok: ${item.ok}`];
|
|
65
|
+
for (const row of summaryRows(item.summary)) {
|
|
66
|
+
lines.push(`${row[0]}: ${row[1]}`);
|
|
67
|
+
}
|
|
68
|
+
for (const problem of item.problems) {
|
|
69
|
+
lines.push(...markdownProblem(problem));
|
|
70
|
+
}
|
|
71
|
+
return lines;
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const renderMarkdown = (doc) => {
|
|
75
|
+
const lines = [NOTICE, '', `exit: ${doc.exit}`];
|
|
76
|
+
for (const item of doc.reports) lines.push(...markdownReport(item));
|
|
77
|
+
if (doc.stderr) lines.push('', '# stderr', '', doc.stderr);
|
|
78
|
+
return `${lines.join('\n').replace(/\n+$/, '')}\n`;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const renderDocument = (doc) => renderMarkdown(doc);
|
|
82
|
+
|
|
83
|
+
module.exports = {
|
|
84
|
+
NOTICE,
|
|
85
|
+
renderMarkdown,
|
|
86
|
+
renderDocument,
|
|
87
|
+
};
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const { spawn } = require('node:child_process');
|
|
5
|
+
|
|
6
|
+
const { spawnBase } = require('./utilities.js');
|
|
7
|
+
const { writeLog } = require('./npm-commands.js');
|
|
8
|
+
const { toolHint, buildDocument } = require('./report-parse.js');
|
|
9
|
+
const { renderDocument } = require('./report-render.js');
|
|
10
|
+
|
|
11
|
+
const OUTPUTS = new Set(['md', 'raw']);
|
|
12
|
+
|
|
13
|
+
const outputMode = (env) => {
|
|
14
|
+
const value = env.RESLOP_OUTPUT;
|
|
15
|
+
if (value) return OUTPUTS.has(value) ? value : '';
|
|
16
|
+
return 'md';
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const CMD_SAFE = /^[\w./:=@+-]+$/;
|
|
20
|
+
|
|
21
|
+
const quoteCmdArg = (arg) => {
|
|
22
|
+
const text = `${arg}`;
|
|
23
|
+
if (text && CMD_SAFE.test(text)) return text;
|
|
24
|
+
const escaped = text.replaceAll('"', '""').replaceAll('%', '"%"');
|
|
25
|
+
return `"${escaped}"`;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const winCommand = (program, args) => {
|
|
29
|
+
const parts = [program, ...args].map(quoteCmdArg);
|
|
30
|
+
return `"${parts.join(' ')}"`;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const spawnCommand = (program, args, options) => {
|
|
34
|
+
const base = {
|
|
35
|
+
cwd: options.cwd,
|
|
36
|
+
env: options.env,
|
|
37
|
+
stdio: options.stdio,
|
|
38
|
+
};
|
|
39
|
+
if (process.platform !== 'win32') {
|
|
40
|
+
return spawn(program, args, spawnBase(base));
|
|
41
|
+
}
|
|
42
|
+
const command = winCommand(program, args);
|
|
43
|
+
const shell = process.env.comspec || 'cmd.exe';
|
|
44
|
+
return spawn(
|
|
45
|
+
shell,
|
|
46
|
+
['/d', '/s', '/c', command],
|
|
47
|
+
spawnBase({ ...base, windowsVerbatimArguments: true }),
|
|
48
|
+
);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const waitStatus = (child) =>
|
|
52
|
+
new Promise((resolve) => {
|
|
53
|
+
let settled = false;
|
|
54
|
+
const finish = (status) => {
|
|
55
|
+
if (settled) return;
|
|
56
|
+
settled = true;
|
|
57
|
+
resolve(status);
|
|
58
|
+
};
|
|
59
|
+
child.on('error', () => finish(1));
|
|
60
|
+
child.on('close', (status) => finish(status === null ? 1 : status));
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
const collect = (child) =>
|
|
64
|
+
new Promise((resolve) => {
|
|
65
|
+
let out = '';
|
|
66
|
+
let err = '';
|
|
67
|
+
let settled = false;
|
|
68
|
+
const finish = (status) => {
|
|
69
|
+
if (settled) return;
|
|
70
|
+
settled = true;
|
|
71
|
+
resolve({ status, stdout: out, stderr: err });
|
|
72
|
+
};
|
|
73
|
+
if (child.stdout) {
|
|
74
|
+
child.stdout.setEncoding('utf8');
|
|
75
|
+
child.stdout.on('data', (chunk) => {
|
|
76
|
+
out += chunk;
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
if (child.stderr) {
|
|
80
|
+
child.stderr.setEncoding('utf8');
|
|
81
|
+
child.stderr.on('data', (chunk) => {
|
|
82
|
+
err += chunk;
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
child.on('error', (error) => {
|
|
86
|
+
err += `${error.message}\n`;
|
|
87
|
+
finish(1);
|
|
88
|
+
});
|
|
89
|
+
child.on('close', (status) => finish(status === null ? 1 : status));
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const commandArgs = (argv) => {
|
|
93
|
+
if (argv[0] !== 't' || argv[1] !== '--' || !argv[2]) return null;
|
|
94
|
+
return { program: argv[2], args: argv.slice(3) };
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const usage = (stderr) => {
|
|
98
|
+
stderr.write('reslop: missing command\n');
|
|
99
|
+
stderr.write('Usage: reslop t -- <program> [args]\n');
|
|
100
|
+
return 1;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const runInherit = async (spawnFn, program, args, options) => {
|
|
104
|
+
let child;
|
|
105
|
+
try {
|
|
106
|
+
child = spawnFn(program, args, { ...options, stdio: 'inherit' });
|
|
107
|
+
} catch {
|
|
108
|
+
return 1;
|
|
109
|
+
}
|
|
110
|
+
return waitStatus(child);
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const runCapture = async (proc, deps = {}) => {
|
|
114
|
+
const env = proc.env || {};
|
|
115
|
+
const argv = proc.argv.slice(2);
|
|
116
|
+
const command = commandArgs(argv);
|
|
117
|
+
if (!command) return usage(proc.stderr);
|
|
118
|
+
const mode = outputMode(env);
|
|
119
|
+
if (!mode) {
|
|
120
|
+
proc.stderr.write(`reslop: unknown RESLOP_OUTPUT ${env.RESLOP_OUTPUT}\n`);
|
|
121
|
+
return 1;
|
|
122
|
+
}
|
|
123
|
+
const cwd = deps.cwd ? deps.cwd : proc.cwd();
|
|
124
|
+
const spawnFn = deps.spawn || spawnCommand;
|
|
125
|
+
const capture = env.RESLOP_CAPTURE === '1';
|
|
126
|
+
if (mode === 'raw' || capture) {
|
|
127
|
+
return runInherit(spawnFn, command.program, command.args, { cwd, env });
|
|
128
|
+
}
|
|
129
|
+
const childEnv = { ...env, RESLOP_CAPTURE: '1' };
|
|
130
|
+
let child;
|
|
131
|
+
try {
|
|
132
|
+
child = spawnFn(command.program, command.args, {
|
|
133
|
+
cwd,
|
|
134
|
+
env: childEnv,
|
|
135
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
136
|
+
});
|
|
137
|
+
} catch (error) {
|
|
138
|
+
proc.stderr.write(`reslop: ${error.message}\n`);
|
|
139
|
+
return 1;
|
|
140
|
+
}
|
|
141
|
+
const result = await collect(child);
|
|
142
|
+
const hint = toolHint(command.program, command.args);
|
|
143
|
+
const doc = buildDocument(
|
|
144
|
+
result.stdout,
|
|
145
|
+
result.stderr,
|
|
146
|
+
cwd,
|
|
147
|
+
result.status,
|
|
148
|
+
hint,
|
|
149
|
+
);
|
|
150
|
+
const text = renderDocument(doc);
|
|
151
|
+
proc.stdout.write(text);
|
|
152
|
+
try {
|
|
153
|
+
writeLog(cwd, path.basename(command.program), text);
|
|
154
|
+
} catch (error) {
|
|
155
|
+
proc.stderr.write(`reslop: ${error.message}\n`);
|
|
156
|
+
}
|
|
157
|
+
return result.status;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
module.exports = {
|
|
161
|
+
outputMode,
|
|
162
|
+
winCommand,
|
|
163
|
+
runCapture,
|
|
164
|
+
};
|