typeclaw 0.31.1 → 0.32.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/package.json +1 -1
- package/scripts/verify-procbind-sandbox.sh +61 -0
- package/src/agent/multimodal/look-at.ts +7 -5
- package/src/agent/plugin-tools.ts +47 -12
- package/src/agent/session-origin.ts +56 -5
- package/src/agent/system-prompt.ts +6 -0
- package/src/agent/tools/channel-fetch-attachment.ts +8 -7
- package/src/agent/tools/channel-history.ts +2 -0
- package/src/bundled-plugins/github-cli-auth/gh-command.ts +267 -13
- package/src/bundled-plugins/reviewer/skills/code-review.ts +11 -9
- package/src/channels/adapters/slack-bot-reference.ts +9 -10
- package/src/channels/adapters/slack-bot.ts +29 -7
- package/src/channels/router.ts +89 -21
- package/src/cli/index.ts +42 -2
- package/src/cli/inspect.ts +5 -2
- package/src/config/config.ts +23 -11
- package/src/container/start.ts +12 -7
- package/src/init/find-agent-dir.ts +44 -0
- package/src/init/index.ts +3 -34
- package/src/inspect/transcript-view.ts +33 -7
- package/src/sandbox/availability.ts +354 -2
- package/src/sandbox/build.ts +17 -7
- package/src/sandbox/index.ts +10 -1
- package/src/sandbox/policy.ts +27 -9
- package/src/skills/typeclaw-markdown-pdf/SKILL.md +81 -8
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: typeclaw-markdown-pdf
|
|
3
|
-
description: "
|
|
3
|
+
description: "The ONLY supported way to turn Markdown into a polished, professional PDF (and optionally attach it to a channel). Load this whenever you need to deliver a document as a PDF rather than raw markdown — reports, summaries, briefs, meeting notes, docs, render report, export document, anything a human would want to download, print, or forward, including a researcher's report file shipped as a Slack/Discord attachment. Triggers: 'make a PDF', 'export to PDF', 'markdown to PDF', 'PDF report', 'render report', 'export document', 'the report', 'attach the report', 'send me a PDF', 'as a PDF', 'turn this into a document', a researcher/subagent result you want to ship as a file, 'PDF로', 'PDF로 만들어', 'PDF로 변환', 'PDF 첨부', '리포트', '보고서'. Handles CJK/Korean/Japanese/Chinese: CJK fonts are opt-in, so before rendering it checks whether a CJK font is present and, if not, asks the user to enable `docker.file.cjkFonts` and regenerate rather than shipping a tofu PDF — it never auto-downloads a font. Also load before saying you cannot produce PDFs — you can: this skill installs a tiny Typst toolchain into workspace/ on first use, then renders. NEVER build a PDF with jsPDF, pdfkit, a canvas text dump, or a headless-browser raw-text print — those produce unrendered markdown and broken CJK; this skill is the only correct path. Covers the one-time setup, the styled wrapper, the render command, and how to attach the PDF to Slack/Discord/Telegram/KakaoTalk. For operating on EXISTING PDFs (merge, split, extract text, fill forms), this is not the skill — use pypdf/qpdf instead."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# typeclaw-markdown-pdf
|
|
@@ -22,6 +22,15 @@ You do **not** need to learn Typst markup. `cmarker` renders your CommonMark
|
|
|
22
22
|
wrapper only sets _styling_ — fonts, margins, headings, page numbers — so the
|
|
23
23
|
output looks deliberate, not like a default-template export.
|
|
24
24
|
|
|
25
|
+
> **This is the only supported way to make a PDF from Markdown in TypeClaw.**
|
|
26
|
+
> Do **not** reach for `jsPDF`, `pdfkit`, a `<canvas>` text dump, or a
|
|
27
|
+
> headless-browser "print raw text" path. Those skip Markdown rendering (you get
|
|
28
|
+
> literal `##` and `**` in the output) and ship no CJK font, so Korean/Japanese/
|
|
29
|
+
> Chinese come out as mojibake. The Typst path below renders the Markdown properly;
|
|
30
|
+
> for CJK it relies on the opt-in `cjkFonts` font and gates on its presence (see
|
|
31
|
+
> "## Handling CJK content") rather than shipping tofu. If you catch yourself about
|
|
32
|
+
> to `bun add` a PDF library, stop and use this skill instead.
|
|
33
|
+
|
|
25
34
|
## When to use this
|
|
26
35
|
|
|
27
36
|
- A research report, brief, or summary the user wants as a downloadable file.
|
|
@@ -108,7 +117,7 @@ fonts/margins only if the user asks.
|
|
|
108
117
|
#counter(page).display("1 / 1", both: true)
|
|
109
118
|
]),
|
|
110
119
|
)
|
|
111
|
-
#set text(font: ("Libertinus Serif", "New Computer Modern"), size: 11pt, lang: "en")
|
|
120
|
+
#set text(font: ("Libertinus Serif", "New Computer Modern", "Noto Serif CJK KR"), size: 11pt, lang: "en")
|
|
112
121
|
#set par(justify: true, leading: 0.68em, spacing: 1.1em)
|
|
113
122
|
|
|
114
123
|
#show heading: set text(weight: "semibold")
|
|
@@ -136,9 +145,65 @@ Notes:
|
|
|
136
145
|
- `read("report.md")` is **relative to the workspace** (the compiler's `workspace`
|
|
137
146
|
is set to `workspace/` — see Step 3). Keep the `.typ` and `.md` in `workspace/`.
|
|
138
147
|
- Fonts `Libertinus Serif` / `New Computer Modern` are bundled with Typst (no font
|
|
139
|
-
install)
|
|
140
|
-
|
|
141
|
-
|
|
148
|
+
install) and carry the Latin text. `"Noto Serif CJK KR"` is appended as the
|
|
149
|
+
fallback so Korean/CJK glyphs resolve per-glyph — Typst falls through to it
|
|
150
|
+
wherever the Latin fonts have no glyph, leaving Latin runs untouched. It comes
|
|
151
|
+
from `fonts-noto-cjk`, which Step 3's renderer loads from `/usr/share/fonts` via
|
|
152
|
+
`fontPaths`. **The package is only present when the container's `cjkFonts` toggle
|
|
153
|
+
resolves to `true`** (default `"auto"` installs it only on a CJK host locale), so
|
|
154
|
+
on a non-CJK host CJK text renders as tofu — see "## Handling CJK content" below
|
|
155
|
+
for the pre-render check that catches this and asks the user before shipping a
|
|
156
|
+
broken PDF. If your CJK font lives elsewhere, add its dir to the `fontPaths` list.
|
|
157
|
+
|
|
158
|
+
## Handling CJK content
|
|
159
|
+
|
|
160
|
+
CJK fonts are **opt-in** (the `docker.file.cjkFonts` toggle). When they are off,
|
|
161
|
+
Typst still renders — it just substitutes `.notdef` tofu boxes for every
|
|
162
|
+
Korean/Japanese/Chinese glyph, so the render "succeeds" and you can ship a broken
|
|
163
|
+
PDF without noticing. **Do not** download, vendor, or `curl` a font into the
|
|
164
|
+
workspace to work around this, and **do not** silently deliver a tofu PDF. Instead,
|
|
165
|
+
run this gate **before** Step 3 whenever the markdown might contain CJK:
|
|
166
|
+
|
|
167
|
+
```sh
|
|
168
|
+
# Run from workspace/. MD is the markdown you are about to render.
|
|
169
|
+
MD="report.md"
|
|
170
|
+
|
|
171
|
+
# Hangul, Kana, CJK ideographs + the common extensions. grep -P on Debian; perl
|
|
172
|
+
# slurp as the fallback (BusyBox/macOS grep lack -P).
|
|
173
|
+
CJK_RE='[\x{1100}-\x{11FF}\x{3130}-\x{318F}\x{AC00}-\x{D7A3}\x{3040}-\x{30FF}\x{31F0}-\x{31FF}\x{3400}-\x{4DBF}\x{4E00}-\x{9FFF}\x{F900}-\x{FAFF}\x{20000}-\x{2A6DF}\x{2A700}-\x{2B73F}\x{2B740}-\x{2B81F}\x{2B820}-\x{2CEAF}\x{2CEB0}-\x{2EBEF}\x{30000}-\x{3134F}]'
|
|
174
|
+
if command -v grep >/dev/null && echo | grep -qP '' 2>/dev/null; then
|
|
175
|
+
LC_ALL=C.UTF-8 grep -qP "$CJK_RE" -- "$MD" && HAS_CJK=1 || HAS_CJK=0
|
|
176
|
+
else
|
|
177
|
+
perl -CSDA -0777 -ne "exit(/$CJK_RE/ ? 0 : 1)" "$MD" && HAS_CJK=1 || HAS_CJK=0
|
|
178
|
+
fi
|
|
179
|
+
|
|
180
|
+
# A CJK font Typst can load. dpkg is the authoritative signal for the opt-in
|
|
181
|
+
# fonts-noto-cjk package; the file scan covers a preinstalled or mounted font.
|
|
182
|
+
# fontconfig/fc-list is NOT consulted — Typst reads fontPaths directly, not fc.
|
|
183
|
+
has_cjk_font() {
|
|
184
|
+
dpkg-query -W -f='${Status}' fonts-noto-cjk 2>/dev/null | grep -q 'install ok installed' && return 0
|
|
185
|
+
find /usr/share/fonts /usr/local/share/fonts -type f \( -iname '*.otf' -o -iname '*.ttf' -o -iname '*.ttc' \) 2>/dev/null |
|
|
186
|
+
grep -Eiq '(Noto(Sans|Serif)CJK|Noto (Sans|Serif) CJK|SourceHan|Source Han|WenQuanYi|Nanum|Unifont|DroidSansFallback|AR PL)'
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if [ "$HAS_CJK" = 1 ] && ! has_cjk_font; then
|
|
190
|
+
echo "CJK_FONT_MISSING"
|
|
191
|
+
fi
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
If the gate prints `CJK_FONT_MISSING`, **stop — do not render or attach a PDF.**
|
|
195
|
+
Tell the user, honestly, that this is a restart-required boot setting, e.g.:
|
|
196
|
+
|
|
197
|
+
> This report has Korean/Japanese/Chinese text, but the container has no CJK font
|
|
198
|
+
> — they're opt-in, so the PDF would come out as tofu boxes. Want me to set
|
|
199
|
+
> `docker.file.cjkFonts: true` in `typeclaw.json`? It's a boot setting, so after I
|
|
200
|
+
> edit it you'll need to run `typeclaw restart` from the host project directory,
|
|
201
|
+
> and then I'll regenerate the PDF.
|
|
202
|
+
|
|
203
|
+
Only after the user agrees: edit `typeclaw.json` to set `docker.file.cjkFonts:
|
|
204
|
+
true` (use the `typeclaw-config` skill), ask them to `typeclaw restart`, and
|
|
205
|
+
regenerate the PDF **after** the restarted container reports `has_cjk_font` true.
|
|
206
|
+
If the markdown has no CJK, or a CJK font is present, skip straight to Step 3.
|
|
142
207
|
|
|
143
208
|
## Step 3 — render
|
|
144
209
|
|
|
@@ -149,15 +214,23 @@ writes the PDF. Pass the wrapper and output paths as arguments.
|
|
|
149
214
|
```ts
|
|
150
215
|
// workspace/.tools/render.ts
|
|
151
216
|
import { NodeCompiler } from '@myriaddreamin/typst-ts-node-compiler'
|
|
152
|
-
import { writeFileSync } from 'node:fs'
|
|
217
|
+
import { existsSync, writeFileSync } from 'node:fs'
|
|
153
218
|
|
|
154
219
|
const [, , mainFile, outFile] = process.argv
|
|
155
220
|
if (!mainFile || !outFile) throw new Error('usage: render.ts <main.typ> <out.pdf>')
|
|
156
221
|
|
|
222
|
+
// Load system fonts so CJK glyphs resolve. The compiler does NOT auto-discover
|
|
223
|
+
// system font dirs the way the Typst CLI does — without explicit fontPaths,
|
|
224
|
+
// "Noto Serif CJK KR" (from fonts-noto-cjk under /usr/share/fonts) is invisible
|
|
225
|
+
// and Korean/Japanese/Chinese text renders as .notdef tofu boxes. Filtered with
|
|
226
|
+
// existsSync so a missing dir (e.g. on a dev/host run) is skipped, not fatal.
|
|
227
|
+
const fontPaths = ['/usr/share/fonts', '/usr/local/share/fonts', '/Library/Fonts', '/System/Library/Fonts'].filter(
|
|
228
|
+
existsSync,
|
|
229
|
+
)
|
|
230
|
+
|
|
157
231
|
const compiler = NodeCompiler.create({
|
|
158
232
|
workspace: '.', // run from workspace/, so read("report.md") resolves
|
|
159
|
-
|
|
160
|
-
// fontArgs: [{ fontPaths: ["/usr/share/fonts"] }],
|
|
233
|
+
...(fontPaths.length > 0 ? { fontArgs: [{ fontPaths }] } : {}),
|
|
161
234
|
})
|
|
162
235
|
const pdf = compiler.pdf({ mainFilePath: mainFile })
|
|
163
236
|
writeFileSync(outFile, Buffer.from(pdf))
|