@steipete/summarize 0.1.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.
Files changed (174) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/LICENSE +21 -0
  3. package/README.md +185 -0
  4. package/dist/cli.cjs +74333 -0
  5. package/dist/cli.cjs.map +7 -0
  6. package/dist/esm/cli-main.js +80 -0
  7. package/dist/esm/cli-main.js.map +1 -0
  8. package/dist/esm/cli.js +18 -0
  9. package/dist/esm/cli.js.map +1 -0
  10. package/dist/esm/config.js +33 -0
  11. package/dist/esm/config.js.map +1 -0
  12. package/dist/esm/content/asset.js +167 -0
  13. package/dist/esm/content/asset.js.map +1 -0
  14. package/dist/esm/content/index.js +4 -0
  15. package/dist/esm/content/index.js.map +1 -0
  16. package/dist/esm/content/link-preview/client.js +20 -0
  17. package/dist/esm/content/link-preview/client.js.map +1 -0
  18. package/dist/esm/content/link-preview/content/article.js +150 -0
  19. package/dist/esm/content/link-preview/content/article.js.map +1 -0
  20. package/dist/esm/content/link-preview/content/cleaner.js +55 -0
  21. package/dist/esm/content/link-preview/content/cleaner.js.map +1 -0
  22. package/dist/esm/content/link-preview/content/fetcher.js +120 -0
  23. package/dist/esm/content/link-preview/content/fetcher.js.map +1 -0
  24. package/dist/esm/content/link-preview/content/index.js +275 -0
  25. package/dist/esm/content/link-preview/content/index.js.map +1 -0
  26. package/dist/esm/content/link-preview/content/parsers.js +77 -0
  27. package/dist/esm/content/link-preview/content/parsers.js.map +1 -0
  28. package/dist/esm/content/link-preview/content/types.js +4 -0
  29. package/dist/esm/content/link-preview/content/types.js.map +1 -0
  30. package/dist/esm/content/link-preview/content/utils.js +127 -0
  31. package/dist/esm/content/link-preview/content/utils.js.map +1 -0
  32. package/dist/esm/content/link-preview/content/youtube.js +82 -0
  33. package/dist/esm/content/link-preview/content/youtube.js.map +1 -0
  34. package/dist/esm/content/link-preview/deps.js +2 -0
  35. package/dist/esm/content/link-preview/deps.js.map +1 -0
  36. package/dist/esm/content/link-preview/fetch-with-timeout.js +35 -0
  37. package/dist/esm/content/link-preview/fetch-with-timeout.js.map +1 -0
  38. package/dist/esm/content/link-preview/transcript/cache.js +73 -0
  39. package/dist/esm/content/link-preview/transcript/cache.js.map +1 -0
  40. package/dist/esm/content/link-preview/transcript/index.js +95 -0
  41. package/dist/esm/content/link-preview/transcript/index.js.map +1 -0
  42. package/dist/esm/content/link-preview/transcript/normalize.js +43 -0
  43. package/dist/esm/content/link-preview/transcript/normalize.js.map +1 -0
  44. package/dist/esm/content/link-preview/transcript/providers/generic.js +11 -0
  45. package/dist/esm/content/link-preview/transcript/providers/generic.js.map +1 -0
  46. package/dist/esm/content/link-preview/transcript/providers/podcast.js +12 -0
  47. package/dist/esm/content/link-preview/transcript/providers/podcast.js.map +1 -0
  48. package/dist/esm/content/link-preview/transcript/providers/twitter.js +12 -0
  49. package/dist/esm/content/link-preview/transcript/providers/twitter.js.map +1 -0
  50. package/dist/esm/content/link-preview/transcript/providers/youtube/api.js +257 -0
  51. package/dist/esm/content/link-preview/transcript/providers/youtube/api.js.map +1 -0
  52. package/dist/esm/content/link-preview/transcript/providers/youtube/apify.js +55 -0
  53. package/dist/esm/content/link-preview/transcript/providers/youtube/apify.js.map +1 -0
  54. package/dist/esm/content/link-preview/transcript/providers/youtube/captions.js +409 -0
  55. package/dist/esm/content/link-preview/transcript/providers/youtube/captions.js.map +1 -0
  56. package/dist/esm/content/link-preview/transcript/providers/youtube/ytdlp.js +114 -0
  57. package/dist/esm/content/link-preview/transcript/providers/youtube/ytdlp.js.map +1 -0
  58. package/dist/esm/content/link-preview/transcript/providers/youtube.js +74 -0
  59. package/dist/esm/content/link-preview/transcript/providers/youtube.js.map +1 -0
  60. package/dist/esm/content/link-preview/transcript/types.js +2 -0
  61. package/dist/esm/content/link-preview/transcript/types.js.map +1 -0
  62. package/dist/esm/content/link-preview/transcript/utils.js +193 -0
  63. package/dist/esm/content/link-preview/transcript/utils.js.map +1 -0
  64. package/dist/esm/content/link-preview/types.js +2 -0
  65. package/dist/esm/content/link-preview/types.js.map +1 -0
  66. package/dist/esm/costs.js +57 -0
  67. package/dist/esm/costs.js.map +1 -0
  68. package/dist/esm/firecrawl.js +54 -0
  69. package/dist/esm/firecrawl.js.map +1 -0
  70. package/dist/esm/flags.js +97 -0
  71. package/dist/esm/flags.js.map +1 -0
  72. package/dist/esm/index.js +4 -0
  73. package/dist/esm/index.js.map +1 -0
  74. package/dist/esm/llm/generate-text.js +296 -0
  75. package/dist/esm/llm/generate-text.js.map +1 -0
  76. package/dist/esm/llm/google-models.js +112 -0
  77. package/dist/esm/llm/google-models.js.map +1 -0
  78. package/dist/esm/llm/html-to-markdown.js +44 -0
  79. package/dist/esm/llm/html-to-markdown.js.map +1 -0
  80. package/dist/esm/llm/model-id.js +45 -0
  81. package/dist/esm/llm/model-id.js.map +1 -0
  82. package/dist/esm/pricing/litellm.js +25 -0
  83. package/dist/esm/pricing/litellm.js.map +1 -0
  84. package/dist/esm/prompts/file.js +14 -0
  85. package/dist/esm/prompts/file.js.map +1 -0
  86. package/dist/esm/prompts/index.js +3 -0
  87. package/dist/esm/prompts/index.js.map +1 -0
  88. package/dist/esm/prompts/link-summary.js +105 -0
  89. package/dist/esm/prompts/link-summary.js.map +1 -0
  90. package/dist/esm/run.js +1674 -0
  91. package/dist/esm/run.js.map +1 -0
  92. package/dist/esm/shared/contracts.js +2 -0
  93. package/dist/esm/shared/contracts.js.map +1 -0
  94. package/dist/esm/summarizeHome.js +20 -0
  95. package/dist/esm/summarizeHome.js.map +1 -0
  96. package/dist/esm/tty/live-markdown.js +52 -0
  97. package/dist/esm/tty/live-markdown.js.map +1 -0
  98. package/dist/esm/tty/osc-progress.js +8 -0
  99. package/dist/esm/tty/osc-progress.js.map +1 -0
  100. package/dist/esm/tty/spinner.js +33 -0
  101. package/dist/esm/tty/spinner.js.map +1 -0
  102. package/dist/esm/version.js +44 -0
  103. package/dist/esm/version.js.map +1 -0
  104. package/dist/types/cli-main.d.ts +11 -0
  105. package/dist/types/cli.d.ts +1 -0
  106. package/dist/types/config.d.ts +15 -0
  107. package/dist/types/content/asset.d.ts +44 -0
  108. package/dist/types/content/index.d.ts +4 -0
  109. package/dist/types/content/link-preview/client.d.ts +14 -0
  110. package/dist/types/content/link-preview/content/article.d.ts +4 -0
  111. package/dist/types/content/link-preview/content/cleaner.d.ts +12 -0
  112. package/dist/types/content/link-preview/content/fetcher.d.ts +16 -0
  113. package/dist/types/content/link-preview/content/index.d.ts +4 -0
  114. package/dist/types/content/link-preview/content/parsers.d.ts +7 -0
  115. package/dist/types/content/link-preview/content/types.d.ts +44 -0
  116. package/dist/types/content/link-preview/content/utils.d.ts +16 -0
  117. package/dist/types/content/link-preview/content/youtube.d.ts +1 -0
  118. package/dist/types/content/link-preview/deps.d.ts +70 -0
  119. package/dist/types/content/link-preview/fetch-with-timeout.d.ts +4 -0
  120. package/dist/types/content/link-preview/transcript/cache.d.ts +29 -0
  121. package/dist/types/content/link-preview/transcript/index.d.ts +9 -0
  122. package/dist/types/content/link-preview/transcript/normalize.d.ts +3 -0
  123. package/dist/types/content/link-preview/transcript/providers/generic.d.ts +3 -0
  124. package/dist/types/content/link-preview/transcript/providers/podcast.d.ts +3 -0
  125. package/dist/types/content/link-preview/transcript/providers/twitter.d.ts +3 -0
  126. package/dist/types/content/link-preview/transcript/providers/youtube/api.d.ts +26 -0
  127. package/dist/types/content/link-preview/transcript/providers/youtube/apify.d.ts +1 -0
  128. package/dist/types/content/link-preview/transcript/providers/youtube/captions.d.ts +7 -0
  129. package/dist/types/content/link-preview/transcript/providers/youtube/ytdlp.d.ts +3 -0
  130. package/dist/types/content/link-preview/transcript/providers/youtube.d.ts +3 -0
  131. package/dist/types/content/link-preview/transcript/types.d.ts +23 -0
  132. package/dist/types/content/link-preview/transcript/utils.d.ts +7 -0
  133. package/dist/types/content/link-preview/types.d.ts +36 -0
  134. package/dist/types/costs.d.ts +31 -0
  135. package/dist/types/firecrawl.d.ts +5 -0
  136. package/dist/types/flags.d.ts +23 -0
  137. package/dist/types/index.d.ts +4 -0
  138. package/dist/types/llm/generate-text.d.ts +43 -0
  139. package/dist/types/llm/google-models.d.ts +10 -0
  140. package/dist/types/llm/html-to-markdown.d.ts +15 -0
  141. package/dist/types/llm/model-id.d.ts +14 -0
  142. package/dist/types/pricing/litellm.d.ts +13 -0
  143. package/dist/types/prompts/file.d.ts +6 -0
  144. package/dist/types/prompts/index.d.ts +3 -0
  145. package/dist/types/prompts/link-summary.d.ts +27 -0
  146. package/dist/types/run.d.ts +8 -0
  147. package/dist/types/shared/contracts.d.ts +2 -0
  148. package/dist/types/summarizeHome.d.ts +6 -0
  149. package/dist/types/tty/live-markdown.d.ts +10 -0
  150. package/dist/types/tty/osc-progress.d.ts +3 -0
  151. package/dist/types/tty/spinner.d.ts +10 -0
  152. package/dist/types/version.d.ts +2 -0
  153. package/docs/README.md +11 -0
  154. package/docs/config.md +28 -0
  155. package/docs/extract-only.md +13 -0
  156. package/docs/firecrawl.md +17 -0
  157. package/docs/llm.md +33 -0
  158. package/docs/openai.md +18 -0
  159. package/docs/site/.nojekyll +1 -0
  160. package/docs/site/404.html +37 -0
  161. package/docs/site/assets/site.css +577 -0
  162. package/docs/site/assets/site.js +69 -0
  163. package/docs/site/docs/config.html +73 -0
  164. package/docs/site/docs/extract-only.html +79 -0
  165. package/docs/site/docs/firecrawl.html +72 -0
  166. package/docs/site/docs/index.html +89 -0
  167. package/docs/site/docs/llm.html +70 -0
  168. package/docs/site/docs/openai.html +66 -0
  169. package/docs/site/docs/website.html +70 -0
  170. package/docs/site/docs/youtube.html +62 -0
  171. package/docs/site/index.html +125 -0
  172. package/docs/website.md +27 -0
  173. package/docs/youtube.md +32 -0
  174. package/package.json +76 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,52 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+
5
+ ## 0.1.0 - 2025-12-19
6
+
7
+ First public release.
8
+
9
+ ### CLI
10
+
11
+ - `summarize` CLI shipped via `@steipete/summarize` (plus optional library exports).
12
+ - Inputs: URL, local file path, or remote file URL (PDFs/images/audio/video/text).
13
+ - Automatic map-reduce for large inputs.
14
+ - Streaming output by default on TTY, with Markdown → ANSI rendering (via `markdansi`).
15
+ - Final “Finished in …” line: timing, token usage, cost estimate (when pricing is available), and service counts.
16
+ - Flags:
17
+ - `--model <provider/model>` (default `google/gemini-3-flash-preview`)
18
+ - `--length short|medium|long|xl|xxl|<chars>` (guideline; no hard truncation)
19
+ - `--max-output-tokens <count>` (optional hard cap)
20
+ - `--timeout <duration>` (default `2m`)
21
+ - `--stream auto|on|off`, `--render auto|md-live|md|plain`
22
+ - `--extract-only` (URLs only; no summary)
23
+ - `--json` (structured output incl. input config, prompt, extracted content, LLM metadata, and metrics)
24
+ - `--metrics off|on|detailed` (default `on`)
25
+ - `--verbose`
26
+
27
+ ### Sources
28
+
29
+ - Websites: fetch + extract “article-ish” content + normalization for prompts.
30
+ - Firecrawl fallback for blocked/thin sites (`--firecrawl off|auto|always`, via `FIRECRAWL_API_KEY`).
31
+ - Markdown extraction for websites in `--extract-only` mode (`--markdown off|auto|llm`).
32
+ - YouTube (`--youtube auto|web|apify`):
33
+ - best-effort transcript endpoints
34
+ - optional Apify fallback (requires `APIFY_API_TOKEN`; single actor `faVsWy9VTSNVIhWpR`)
35
+ - Files (remote or local): MIME sniffing + best-effort forwarding to the model.
36
+ - text-like inputs are inlined for provider compatibility
37
+
38
+ ### LLM providers
39
+
40
+ - Direct-provider API keys (no gateway).
41
+ - OpenAI-compatible base URL support (`OPENAI_BASE_URL`, `OPENROUTER_API_KEY`).
42
+ - Model ids: `openai/...`, `anthropic/...`, `xai/...`, `google/...`.
43
+ - Auto-handling of provider/model limitations (e.g. no streaming support → non-streaming call; unsupported media types → friendly error).
44
+
45
+ ### Pricing + limits
46
+
47
+ - Token/cost estimates and model limits derived from LiteLLM’s model catalog, downloaded + cached under `~/.summarize/cache/`.
48
+
49
+ ### Quality
50
+
51
+ - CI: lint, tests (coverage), and pack.
52
+ - Tooling: Biome (lint/format) + Vitest (tests + coverage gate).
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Peter Steinberger
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,185 @@
1
+ # Summarize 👉 Point at any URL or file. Get the gist.
2
+
3
+ Fast CLI for summarizing *anything you can point at*:
4
+
5
+ - Web pages (article extraction; Firecrawl fallback if sites block agents)
6
+ - YouTube links (best-effort transcripts, optional Apify fallback)
7
+ - Remote files (PDFs/images/audio/video via URL — downloaded and forwarded to the model)
8
+ - Local files (PDFs/images/audio/video/text — forwarded or inlined; support depends on provider/model)
9
+
10
+ It streams output by default on TTY and renders Markdown to ANSI (via `markdansi`). At the end it prints a single “Finished in …” line with timing, token usage, and a best-effort cost estimate (when pricing is available).
11
+
12
+ ## Install
13
+
14
+ - npx (no install):
15
+
16
+ ```bash
17
+ npx -y @steipete/summarize "https://example.com" --model google/gemini-3-flash-preview
18
+ ```
19
+
20
+ - Homebrew (custom tap):
21
+
22
+ ```bash
23
+ brew install steipete/tap/summarize
24
+ ```
25
+
26
+ ## Quickstart
27
+
28
+ ```bash
29
+ summarize "https://example.com" --model google/gemini-3-flash-preview
30
+ ```
31
+
32
+ Input can be a URL or a local file path:
33
+
34
+ ```bash
35
+ npx -y @steipete/summarize "/path/to/file.pdf" --model google/gemini-3-flash-preview
36
+ npx -y @steipete/summarize "/path/to/image.jpeg" --model google/gemini-3-flash-preview
37
+ ```
38
+
39
+ Remote file URLs work the same (best-effort; the file is downloaded and passed to the model):
40
+
41
+ ```bash
42
+ npx -y @steipete/summarize "https://example.com/report.pdf" --model google/gemini-3-flash-preview
43
+ ```
44
+
45
+ YouTube (supports `youtube.com` and `youtu.be`):
46
+
47
+ ```bash
48
+ npx -y @steipete/summarize "https://youtu.be/dQw4w9WgXcQ" --youtube auto
49
+ ```
50
+
51
+ ## What file types work?
52
+
53
+ This is “best effort” and depends on what your selected model/provider accepts. In practice these usually work well:
54
+
55
+ - `text/*` and common structured text (`.txt`, `.md`, `.json`, `.yaml`, `.xml`, …)
56
+ - text-like files are **inlined into the prompt** (instead of attached as a file part) for better provider compatibility
57
+ - PDFs: `application/pdf` (provider support varies; Google is the most reliable in this CLI right now)
58
+ - Images: `image/jpeg`, `image/png`, `image/webp`, `image/gif`
59
+ - Audio/Video: `audio/*`, `video/*` (when supported by the model)
60
+
61
+ Notes:
62
+
63
+ - If a provider rejects a media type, the CLI fails fast with a friendly message (no “mystery stack traces”).
64
+ - xAI models currently don’t support attaching generic files (like PDFs) via the AI SDK; use a Google/OpenAI/Anthropic model for those.
65
+
66
+ ## Model ids
67
+
68
+ Use “gateway-style” ids: `<provider>/<model>`.
69
+
70
+ Examples:
71
+
72
+ - `openai/gpt-5.2`
73
+ - `anthropic/claude-opus-4-5`
74
+ - `xai/grok-4-fast-non-reasoning`
75
+ - `google/gemini-3-flash-preview`
76
+
77
+ Note: some models/providers don’t support streaming or certain file media types. When that happens, the CLI prints a friendly error (or auto-disables streaming for that model when supported by the provider).
78
+
79
+ ## Output length
80
+
81
+ `--length` controls *how much output we ask for* (guideline), not a hard truncation.
82
+
83
+ ```bash
84
+ npx -y @steipete/summarize "https://example.com" --length long
85
+ npx -y @steipete/summarize "https://example.com" --length 20k
86
+ ```
87
+
88
+ - Presets: `short|medium|long|xl|xxl`
89
+ - Character targets: `1500`, `20k`, `20000`
90
+ - Optional hard cap: `--max-output-tokens <count>` (e.g. `2000`, `2k`)
91
+ - Provider/model APIs still enforce their own maximum output limits.
92
+
93
+ ## Common flags
94
+
95
+ ```bash
96
+ npx -y @steipete/summarize <input> [flags]
97
+ ```
98
+
99
+ - `--model <provider/model>`: which model to use (defaults to `google/gemini-3-flash-preview`)
100
+ - `--timeout <duration>`: `30s`, `2m`, `5000ms` (default `2m`)
101
+ - `--length short|medium|long|xl|xxl|<chars>`
102
+ - `--max-output-tokens <count>`: hard cap for LLM output tokens (optional)
103
+ - `--stream auto|on|off`: stream LLM output (`auto` = TTY only; disabled in `--json` mode)
104
+ - `--render auto|md-live|md|plain`: Markdown rendering (`auto` = best default for TTY)
105
+ - `--extract-only`: print extracted content and exit (no summary) — only for URLs
106
+ - `--json`: machine-readable output with diagnostics, prompt, `metrics`, and optional summary
107
+ - `--verbose`: debug/diagnostics on stderr
108
+ - `--metrics off|on|detailed`: metrics output (default `on`; `detailed` prints a breakdown to stderr)
109
+
110
+ ## Website extraction (Firecrawl + Markdown)
111
+
112
+ Non-YouTube URLs go through a “fetch → extract” pipeline. When the direct fetch/extraction is blocked or too thin, `--firecrawl auto` can fall back to Firecrawl (if configured).
113
+
114
+ - `--firecrawl off|auto|always` (default `auto`)
115
+ - `--markdown off|auto|llm` (default `auto`; only affects `--extract-only` for non-YouTube URLs)
116
+ - Plain-text mode: use `--firecrawl off --markdown off`.
117
+
118
+ ## YouTube transcripts (Apify fallback)
119
+
120
+ `--youtube auto` tries best-effort web transcript endpoints first, then falls back to Apify *only if* `APIFY_API_TOKEN` is set.
121
+
122
+ Apify uses a single actor (`faVsWy9VTSNVIhWpR`). It costs money but tends to be more reliable.
123
+
124
+ ## Configuration
125
+
126
+ Single config location:
127
+
128
+ - `~/.summarize/config.json`
129
+
130
+ Supported keys today:
131
+
132
+ ```json
133
+ {
134
+ "model": "openai/gpt-5.2"
135
+ }
136
+ ```
137
+
138
+ Precedence:
139
+
140
+ 1) `--model`
141
+ 2) `SUMMARIZE_MODEL`
142
+ 3) `~/.summarize/config.json`
143
+ 4) default
144
+
145
+ ## Environment variables
146
+
147
+ Set the key matching your chosen `--model`:
148
+
149
+ - `OPENAI_API_KEY` (for `openai/...`)
150
+ - `ANTHROPIC_API_KEY` (for `anthropic/...`)
151
+ - `XAI_API_KEY` (for `xai/...`)
152
+ - `GEMINI_API_KEY` (for `google/...`)
153
+ - also accepts `GOOGLE_GENERATIVE_AI_API_KEY` and `GOOGLE_API_KEY` as aliases
154
+
155
+ OpenRouter (OpenAI-compatible):
156
+
157
+ - Set `OPENAI_BASE_URL=https://openrouter.ai/api/v1`
158
+ - Prefer `OPENROUTER_API_KEY=...` (instead of reusing `OPENAI_API_KEY`)
159
+ - Use OpenRouter models via the `openai/...` prefix, e.g. `--model openai/xiaomi/mimo-v2-flash:free`
160
+
161
+ Optional services:
162
+
163
+ - `FIRECRAWL_API_KEY` (website extraction fallback)
164
+ - `APIFY_API_TOKEN` (YouTube transcript fallback)
165
+
166
+ ## Model limits
167
+
168
+ The CLI uses the LiteLLM model catalog for model limits (like max output tokens):
169
+
170
+ - Downloaded from: `https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json`
171
+ - Cached at: `~/.summarize/cache/`
172
+
173
+ ## Library usage (optional)
174
+
175
+ This package also exports a small library:
176
+
177
+ - `@steipete/summarize/content`
178
+ - `@steipete/summarize/prompts`
179
+
180
+ ## Development
181
+
182
+ ```bash
183
+ pnpm install
184
+ pnpm check
185
+ ```