@yibie/pi-jev-browser 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.
package/LICENSE ADDED
@@ -0,0 +1,201 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright 2026 Cline Bot Inc.
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,137 @@
1
+ # pi-jev-browser
2
+
3
+ An isolated Playwright Chromium browser for pi, driven by [Jev](https://typesafe.ai/blog/introducing-system-one-models-and-jev) — TypeSafe AI's System One model — called directly through the TypeSafe API, or by the model pi already has configured.
4
+
5
+ > **Ported from Cline.** This package is a port of [`cline/plugins` → `plugins/jev-browser`](https://github.com/cline/plugins/tree/main/plugins/jev-browser) (v0.2.2, by Bee / Cline Bot Inc., Apache-2.0) to the pi extension API. The observation layer, decision loop, action executor, configuration, live stream, recording overlay, and browser setup are upstream code, largely unchanged. The host adapter, the direct TypeSafe transport in place of Vercel AI Gateway, and the `pi` decision policy are new. See [Porting notes](#porting-notes) for the full list.
6
+
7
+ Jev does not see screenshots. The plugin hands it a structured DOM observation and one multiple-choice question per step, and Jev answers with a concrete operation plus a probability distribution over the offered options. That removes the screenshot round trip and the reasoning round trip from every browser step.
8
+
9
+ **This is not a replacement for `agent_browser`.** It is the other trade: no login state, no extensions, no host environment, every step recorded with its probability, and a much cheaper fast loop. Use it for narrowly scoped goals on public pages. Use a profile-based browser tool when you need the user's session.
10
+
11
+ ## Decision policies
12
+
13
+ Each step offers the same enumerated choices — every concrete action compared directly against scrolling, waiting, and stopping — and a policy answers which one to take. Only the answerer differs.
14
+
15
+ | `policy` | Who decides | Needs | Trade-off |
16
+ | --- | --- | --- | --- |
17
+ | `pi` (default) | The model pi has configured | Nothing extra | `probability` is whatever the model claims, and completion discipline follows that model |
18
+ | `typesafe` | [Jev](https://typesafe.ai/blog/introducing-system-one-models-and-jev) via the TypeSafe API | `TYPESAFE_API_KEY` or `typesafe.apiKey` | Better at checking that a requirement is really visible before declaring done; every step is one TypeSafe request |
19
+
20
+ `pi` is the default because it works with no second credential and no extra API quota. Its weakness is the mirror image: measured on one goal (open a category, then a detail page, stop when the UPC and availability are visible), both `deepseek-flash` and `deepseek-v4-pro` declared `DONE` after two clicks without ever scrolling to the Product Information table, where Jev scrolled twice and then stopped. Clarifying the `DONE` criterion did not change that. What kept the outcome honest was the evidence: `done_unverified` plus a viewport-scoped page text let the calling agent see that the UPC had never been read, and it said so instead of reporting success.
21
+
22
+ On the same goal, policy `typesafe` completed it in four executed steps (7.1 s) with both required values in the returned page text, and five consecutive direct API calls showed no throttling at all — the Gateway free tier in the same position stopped after five or six requests.
23
+
24
+ ## Related work
25
+
26
+ [`pi-jev-browser`](https://github.com/laihenyi/pi-Jev-browser) (npm `pi-jev-browser`) is a sibling port of the same upstream plugin, and it is the more capable of the two: eight tools, including a deterministic extractor and a macOS accessibility-tree driver behind a surface-agnostic loop, plus stuck detection and a 22-scenario benchmark across local, model, live, and desktop tiers. It requires a TypeSafe API key to run at all.
27
+
28
+ This package differs in two ways worth choosing it for: policy `pi` runs with no external credential, and the measurement above compares the decision layers instead of assuming one. If you want the broader tool surface, use the sibling.
29
+
30
+ ## Install
31
+
32
+ ```bash
33
+ pi install /absolute/path/to/pi-jev-browser # local checkout
34
+ pi install git:github.com/yibie/pi-jev-browser # from git
35
+ pi install npm:@yibie/pi-jev-browser # from npm
36
+ ```
37
+
38
+ Installing pulls in `playwright`, whose own install step downloads Chromium — roughly 150 MB, so the first install takes a moment. `ensureChromium()` covers the case where that step was skipped: the first `jev_run` runs `playwright install chromium` if no matching build is cached, bounded to two minutes. Nothing is downloaded at pi startup. On Linux the system browser libraries remain an administrator-managed prerequisite; this package never runs sudo.
39
+
40
+ ## Configuration
41
+
42
+ Optional. Without a config file the plugin allows all HTTP and HTTPS origins, runs headless at 1280×720, records WebM video, and writes artifacts to `~/.pi/agent/data/jev-browser/`.
43
+
44
+ ```bash
45
+ cp pi-jev-browser.config.example.json ~/.pi/agent/pi-jev-browser.config.json
46
+ ```
47
+
48
+ | Key | Default | Notes |
49
+ | --- | --- | --- |
50
+ | `policy` | `"pi"` | `pi` uses the model pi has configured; `typesafe` calls the TypeSafe API directly. See [Decision policies](#decision-policies). |
51
+ | `allowedOrigins` | `["http://*", "https://*"]` | `*` wildcards, matched against the origin. Narrow this for sensitive work. |
52
+ | `headless` | `true` | On macOS a rejected headless launch falls back to a visible window. |
53
+ | `recordVideo` | `true` | Finalized by `jev_stop`. |
54
+ | `showCursor`, `showClickIndicators` | `true` | Overlay for screenshots, stream, and recordings. |
55
+ | `viewport` | `1280×720` | Clamped to 640–2560 × 480–1600. |
56
+ | `outputDir` | `~/.pi/agent/data/jev-browser` | One directory per browser session. |
57
+ | `stream` | `{enabled:false, intervalMs:1000}` | `jev_stream` can start it on demand. |
58
+ | `typesafe.apiKey` | — | Used when `TYPESAFE_API_KEY` is not set. |
59
+ | `typesafe.model` | `jev-latest` | TypeSafe model alias for the decision step. |
60
+
61
+ Credentials resolve in this order: `TYPESAFE_API_KEY`, then `typesafe.apiKey`; `TYPESAFE_MODEL`, then `typesafe.model`. `PI_JEV_BROWSER_CONFIG` overrides the config path. Credentials are read on every run, never written into the browser's environment, and never returned in tool results. Both settings apply to policy `typesafe` only; policy `pi` resolves its model through pi's own provider configuration. Field values are always filled by pi's configured model, because Jev generates no text.
62
+
63
+ With policy `typesafe`, **every step costs one request**, so a 20-step run makes up to 20 of them. TypeSafe documents `429 Too Many Requests` and `529 Overloaded` as back-off-and-retry. The loop does not retry: retrying inside the loop would spend the step budget on requests that keep failing. Those responses end the run as `interrupted` with failure category `rate_limited` or `overloaded`, take no action for the step being decided, and tell the caller to wait.
64
+
65
+ ## Tools
66
+
67
+ | Tool | Purpose |
68
+ | --- | --- |
69
+ | `jev_run` | Start or reuse the browser, capture before/after screenshots, and run the Jev loop toward one goal. |
70
+ | `jev_actions` | Manual click/type/scroll/drag batch. **Does not call Jev.** Escape hatch only. |
71
+ | `jev_state` | URLs, titles, tabs, viewport, start time. |
72
+ | `jev_logs` | Console messages, page errors, failed requests, navigations, blocked downloads, security blocks. |
73
+ | `jev_stream` | Tokenized live screenshot + log viewer bound to `127.0.0.1`. |
74
+ | `jev_stop` | Cancel any in-flight run, close the browser, finalize video. |
75
+
76
+ A run is bounded to 20 steps by default (60 max) and 100 seconds. `jev_run` returns a status, the executed step count, `elapsedMs`, a JSONL trace path, screenshots on disk, and text evidence of the page the run stopped on: URL, title, an excerpt of the visible text, and the number of actionable targets observed.
77
+
78
+ **Verification is text-first.** The final screenshot is attached as an image content block only when the active model declares image input. pi also strips images when `images.blockImages` is set, and extensions cannot read that setting — so the result always carries text evidence, and the verification line states which path applies, names the `Image reading is disabled` symptom, and forbids reporting success from the status alone.
79
+
80
+ Statuses are `done_unverified`, `blocked`, `needs_review`, `uncertain`, `step_limit`, `evaluation_limit`, and `interrupted`. There is deliberately no `done`: `done_unverified` means Jev believes the goal is complete and the calling agent must verify independently before reporting success.
81
+
82
+ ## Safety
83
+
84
+ Three layers exist, and only the first one is enforcement:
85
+
86
+ 1. **Mechanical.** Navigation allowlist enforced in the request router; downloads refused and logged; service workers blocked; extensions and file-system access disabled; the browser process gets an empty environment; password, file, and hidden inputs are never observed; the model can only select from server-generated target IDs, so its output can never become a selector, URL, or code.
87
+ 2. **Model guidance.** Jev is instructed to return `REVIEW` before messages, posts, orders, payments, bookings, deletions, permission changes, sensitive-data entry, CAPTCHAs, or security warnings. This is guidance, not a deterministic boundary.
88
+ 3. **Agent instructions.** The tool guidelines tell pi to treat page content as untrusted, to ask before consequential actions, to never type secrets, and to verify `done_unverified` independently. These are instructions to another model, not guarantees.
89
+
90
+ Page text, visible field values, and the goal are sent to the decision model — the TypeSafe API under policy `typesafe`, your configured provider under policy `pi` — and field values are sent to pi's model to be filled. Password and file fields are excluded, but other sensitive content is **not** automatically redacted. Delegate only narrowly scoped tasks.
91
+
92
+ ## Scope and limits
93
+
94
+ - **Not a vision agent.** No screenshots are sent to Jev. Screenshots exist for the calling agent's verification and for the user.
95
+ - **DOM coverage.** Frames, shadow DOM, canvas controls, nested scrolling, uploads, and arbitrary keyboard widgets are outside the observation loop. Use `jev_actions` there.
96
+ - **Observation caps.** 200 action targets, 6,000 visible characters, 50 selected options, and up to 50 offscreen control labels per direction. Dense pages can lose controls.
97
+ - **No persistent state.** Every browser start creates a fresh context: no cookies, no logins, no profiles.
98
+ - **Not desktop control.** This is a browser harness. Full desktop control would need a VM/container backend and an OS input adapter.
99
+ - **Unbenchmarked.** End-to-end speed and live-model reliability have not been measured.
100
+ - **Memory is narrow.** The last ten actions are retained in memory per goal within one browser session, and are dropped when the goal changes. Nothing is persisted.
101
+
102
+ The loop retries only reads invalidated by a document replacement, up to five times. A browser mutation is **never** retried: a failed run may still have applied an action, so inspect the page before continuing. Three non-wait actions without observable progress end the run as `blocked`.
103
+
104
+ ## Porting notes
105
+
106
+ Ported from [`cline/plugins` → `plugins/jev-browser`](https://github.com/cline/plugins/tree/main/plugins/jev-browser) (v0.2.2). The observation layer, decision loop, action executor, config, stream, overlay, and browser setup are the upstream code, unchanged apart from names. What the host boundary required:
107
+
108
+ - **Cancellation.** Cline passes tool context over JSON IPC, so the upstream plugin could not receive a live `AbortSignal` and managed cancellation itself — Escape did not stop a run. Pi passes a real `signal` into `execute()`, so host cancellation now works and `jev_stop` is cleanup rather than the only stop button.
109
+ - **Screenshots.** Upstream returned a host-specific result array; here the final image becomes a Pi `{type:"image"}` content block, so verification no longer depends on the client rendering an artifact path.
110
+ - **One browser, not a map.** Upstream keyed sessions by Cline session id. A pi extension instance is one session, so the manager holds one browser and `session_shutdown` closes it.
111
+ - **Rules → guidelines.** The upstream global safety rule became per-tool `promptGuidelines`, each naming its tool, plus `executionMode: "sequential"` on the tools that drive the shared page.
112
+ - **No dashboard events.** Upstream emitted seven `jev_browser_update` events for the Cline UI. Pi has no equivalent surface; artifacts, the trace, and tool results carry the same information.
113
+ - **Dependencies.** `zod` was unused and was dropped. Upstream reached Jev through Vercel AI Gateway with `ai` and `@ai-sdk/gateway`; both are gone, because TypeSafe's own API takes the same `state` + `questions` body the loop already builds. The validation those packages provided moved into `parseChoiceAnswer`, narrowed to what the loop actually needs: only an answer that names no offered option is fatal, because a doubtful probability distribution must never kill a run that has already clicked things. Its own value is reported when it is a usable number and marked unknown otherwise.
114
+ - **Throttling is named, and failures explain themselves.** Upstream reported any evaluation failure as an unexplained interruption. HTTP 429 and 529 now carry their own failure categories, `rate_limited` and `overloaded`, and every failure records a bounded single-line `detail`. That last part is not cosmetic: an unexplained four-step failure is what prompted this change, and the detail line is what makes the next one diagnosable.
115
+ - **Input validation.** `jev_actions` now validates every action in the batch before executing any of it, so a malformed action can no longer leave earlier actions half-applied.
116
+ - **Pluggable decision policy.** The decision step became the `JevPolicy` seam the upstream interface hinted at: `policy: "pi"` answers it with the model pi already has configured, so the loop needs no second credential, while `policy: "typesafe"` calls the TypeSafe API directly. Vercel AI Gateway is no longer a dependency of any kind.
117
+ - **Verification without vision.** Upstream handed back screenshots, so a text-only model could not check a `done_unverified` claim at all. Runs now also return the stopped page's URL, title, and visible-text excerpt, produced by the same observation layer, and the image is attached only when the model declares image input. Measured on one goal: the payload dropped from 1.38 MB to 164 KB with a text-only model, while the agent's verification went from "claim is unverified" to naming the book title and price.
118
+
119
+ ## Development
120
+
121
+ ```bash
122
+ bun install
123
+ bun run check # tsc --noEmit
124
+ bun run test # node --test; browser tests need Chromium and a display
125
+ ```
126
+
127
+ Tests use local HTML and mocked model responses, including the TypeSafe transport against a fake HTTP response. They make no paid model calls.
128
+
129
+ To exercise the loop for real, run it: the default `pi` policy needs no key at all, and `policy: "typesafe"` with `TYPESAFE_API_KEY` set uses Jev.
130
+
131
+ ```bash
132
+ pi -e ./extensions/jev-browser.ts -p "Use jev_run with url https://books.toscrape.com and goal: open the Travel category and stop when the first book's title is visible."
133
+ ```
134
+
135
+ ## License
136
+
137
+ Apache-2.0. Upstream `cline/plugins` is Apache-2.0 (its plugin `package.json` says MIT, but the repository ships no separate plugin license, so the repository license is followed here). Upstream author: Bee, Cline Bot Inc.