agent-reader 1.1.0 → 1.1.2
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 +1 -0
- package/bin/agent-reader.js +7 -1
- package/package.json +1 -1
- package/src/cli/commands.js +7 -1
- package/src/core/exporter.js +87 -27
- package/src/mcp/server.js +1 -1
package/README.md
CHANGED
package/bin/agent-reader.js
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
cleanCommand,
|
|
5
5
|
doctorCommand,
|
|
6
6
|
exportCommand,
|
|
7
|
+
mcpStubCommand,
|
|
7
8
|
openCommand,
|
|
8
9
|
renderCommand,
|
|
9
10
|
runCommandSafely,
|
|
@@ -16,7 +17,7 @@ const program = new Command();
|
|
|
16
17
|
program
|
|
17
18
|
.name('agent-reader')
|
|
18
19
|
.description('AI Agent output beautifier and slideshow generator')
|
|
19
|
-
.version('1.1.
|
|
20
|
+
.version('1.1.2');
|
|
20
21
|
|
|
21
22
|
setupCommonCommandOptions(
|
|
22
23
|
program
|
|
@@ -80,4 +81,9 @@ program
|
|
|
80
81
|
.option('--days <days>', 'max age in days', '7')
|
|
81
82
|
.action((options) => runCommandSafely(() => cleanCommand(options)));
|
|
82
83
|
|
|
84
|
+
program
|
|
85
|
+
.command('mcp')
|
|
86
|
+
.description('Start MCP server on stdio')
|
|
87
|
+
.action(() => runCommandSafely(() => mcpStubCommand()));
|
|
88
|
+
|
|
83
89
|
await program.parseAsync(process.argv);
|
package/package.json
CHANGED
package/src/cli/commands.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { promises as fs } from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
3
4
|
import open from 'open';
|
|
4
5
|
import { execa } from 'execa';
|
|
5
6
|
import { renderMarkdown } from '../core/renderer.js';
|
|
@@ -49,6 +50,9 @@ function normalizeMode(options) {
|
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
async function readAllFromStdin() {
|
|
53
|
+
if (process.stdin.isTTY) {
|
|
54
|
+
throw new Error('stdin is a terminal — pipe content or use a file path instead (e.g. echo "# hi" | agent-reader render --stdin)');
|
|
55
|
+
}
|
|
52
56
|
const chunks = [];
|
|
53
57
|
for await (const chunk of process.stdin) {
|
|
54
58
|
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
@@ -591,7 +595,9 @@ export async function cleanCommand(options) {
|
|
|
591
595
|
}
|
|
592
596
|
|
|
593
597
|
export async function mcpStubCommand() {
|
|
594
|
-
const
|
|
598
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
599
|
+
const serverPath = path.resolve(__dirname, '..', 'mcp', 'server.js');
|
|
600
|
+
const result = await execa('node', [serverPath], { stdio: 'inherit' });
|
|
595
601
|
return result;
|
|
596
602
|
}
|
|
597
603
|
|
package/src/core/exporter.js
CHANGED
|
@@ -690,30 +690,15 @@ export function createPandocFallbackWarnings(platform = process.platform) {
|
|
|
690
690
|
];
|
|
691
691
|
}
|
|
692
692
|
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
let puppeteer;
|
|
704
|
-
try {
|
|
705
|
-
const mod = await import('puppeteer');
|
|
706
|
-
puppeteer = mod.default || mod;
|
|
707
|
-
} catch {
|
|
708
|
-
throw new Error('Puppeteer is not installed. Install optional dependency: npm install puppeteer');
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
const warnings = [];
|
|
712
|
-
const pdfPath = path.join(path.resolve(outDir), fileName);
|
|
713
|
-
const resolvedSandboxMode = resolveSandboxMode(sandbox);
|
|
714
|
-
const launchArgs = landscape ? ['--allow-file-access-from-files'] : [];
|
|
715
|
-
launchArgs.push(...getSandboxArgs(resolvedSandboxMode));
|
|
716
|
-
|
|
693
|
+
async function renderPdfWithPuppeteer({
|
|
694
|
+
puppeteer,
|
|
695
|
+
launchArgs,
|
|
696
|
+
html,
|
|
697
|
+
htmlPath,
|
|
698
|
+
pageSize,
|
|
699
|
+
landscape,
|
|
700
|
+
pdfPath,
|
|
701
|
+
}) {
|
|
717
702
|
const browser = await puppeteer.launch({
|
|
718
703
|
headless: true,
|
|
719
704
|
args: launchArgs,
|
|
@@ -723,14 +708,24 @@ export async function exportPDF(html, options = {}) {
|
|
|
723
708
|
|
|
724
709
|
if (htmlPath) {
|
|
725
710
|
await page.goto(pathToFileURL(path.resolve(htmlPath)).toString(), {
|
|
726
|
-
waitUntil: '
|
|
711
|
+
waitUntil: 'domcontentloaded',
|
|
727
712
|
});
|
|
728
713
|
} else {
|
|
729
714
|
await page.setContent(html, {
|
|
730
|
-
waitUntil: '
|
|
715
|
+
waitUntil: 'domcontentloaded',
|
|
731
716
|
});
|
|
732
717
|
}
|
|
733
718
|
|
|
719
|
+
// Wait for images and fonts to finish loading before generating PDF.
|
|
720
|
+
await page.evaluate(() =>
|
|
721
|
+
Promise.all([
|
|
722
|
+
document.fonts?.ready,
|
|
723
|
+
...Array.from(document.images).map((img) =>
|
|
724
|
+
img.complete ? Promise.resolve() : new Promise((r) => { img.onload = r; img.onerror = r; }),
|
|
725
|
+
),
|
|
726
|
+
]),
|
|
727
|
+
);
|
|
728
|
+
|
|
734
729
|
await page.addStyleTag({
|
|
735
730
|
content: `
|
|
736
731
|
@page {
|
|
@@ -798,7 +793,72 @@ blockquote { break-inside: avoid; }`,
|
|
|
798
793
|
tagged: true,
|
|
799
794
|
});
|
|
800
795
|
} finally {
|
|
801
|
-
await browser.close();
|
|
796
|
+
await browser.close().catch(() => {});
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
export async function exportPDF(html, options = {}) {
|
|
801
|
+
const {
|
|
802
|
+
pageSize = 'A4',
|
|
803
|
+
landscape = false,
|
|
804
|
+
outDir = os.tmpdir(),
|
|
805
|
+
fileName = 'output.pdf',
|
|
806
|
+
htmlPath,
|
|
807
|
+
sandbox,
|
|
808
|
+
puppeteerInstance,
|
|
809
|
+
sandboxRuntime,
|
|
810
|
+
} = options;
|
|
811
|
+
|
|
812
|
+
let puppeteer = puppeteerInstance;
|
|
813
|
+
try {
|
|
814
|
+
if (!puppeteer) {
|
|
815
|
+
const mod = await import('puppeteer');
|
|
816
|
+
puppeteer = mod.default || mod;
|
|
817
|
+
}
|
|
818
|
+
} catch {
|
|
819
|
+
throw new Error('Puppeteer is not installed. Install optional dependency: npm install puppeteer');
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
const warnings = [];
|
|
823
|
+
const pdfPath = path.join(path.resolve(outDir), fileName);
|
|
824
|
+
const resolvedSandboxMode = resolveSandboxMode(sandbox);
|
|
825
|
+
const baseArgs = landscape ? ['--allow-file-access-from-files'] : [];
|
|
826
|
+
const primaryArgs = [...baseArgs, ...getSandboxArgs(resolvedSandboxMode, sandboxRuntime)];
|
|
827
|
+
const canRetryWithNoSandbox = resolvedSandboxMode === 'auto'
|
|
828
|
+
&& !primaryArgs.includes('--no-sandbox');
|
|
829
|
+
|
|
830
|
+
try {
|
|
831
|
+
await renderPdfWithPuppeteer({
|
|
832
|
+
puppeteer,
|
|
833
|
+
launchArgs: primaryArgs,
|
|
834
|
+
html,
|
|
835
|
+
htmlPath,
|
|
836
|
+
pageSize,
|
|
837
|
+
landscape,
|
|
838
|
+
pdfPath,
|
|
839
|
+
});
|
|
840
|
+
} catch (primaryError) {
|
|
841
|
+
if (!canRetryWithNoSandbox) {
|
|
842
|
+
throw primaryError;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
const fallbackArgs = [...baseArgs, ...SANDBOX_DISABLED_ARGS];
|
|
846
|
+
try {
|
|
847
|
+
await renderPdfWithPuppeteer({
|
|
848
|
+
puppeteer,
|
|
849
|
+
launchArgs: fallbackArgs,
|
|
850
|
+
html,
|
|
851
|
+
htmlPath,
|
|
852
|
+
pageSize,
|
|
853
|
+
landscape,
|
|
854
|
+
pdfPath,
|
|
855
|
+
});
|
|
856
|
+
warnings.push('sandbox_auto_retry_off');
|
|
857
|
+
} catch (fallbackError) {
|
|
858
|
+
throw new Error(
|
|
859
|
+
`PDF export failed in auto mode and fallback off mode: ${fallbackError.message} (auto error: ${primaryError.message})`,
|
|
860
|
+
);
|
|
861
|
+
}
|
|
802
862
|
}
|
|
803
863
|
|
|
804
864
|
const stat = await fs.stat(pdfPath);
|