pi-webapp 0.1.19 → 0.1.21

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.
@@ -0,0 +1,299 @@
1
+ # Desktop application
2
+
3
+ The desktop application **pi** is an optional Electron host for the existing Web UI.
4
+ The `npx pi-webapp` and Pi `/web` entry points remain available. There is no
5
+ second implementation of chat, files, terminals, Git or session storage.
6
+
7
+ ## Build and run
8
+
9
+ Build on the target OS and architecture (macOS/Linux/Windows, x64 or arm64):
10
+
11
+ ```bash
12
+ npm ci
13
+ npm run check
14
+ npm test
15
+ npm run desktop:prepare
16
+ npm run desktop:start
17
+ ```
18
+
19
+ `desktop:prepare` builds the UI/extension, downloads **Node 22.23.3** from
20
+ nodejs.org, verifies the archive against the official HTTPS SHA-256 manifest,
21
+ and installs the pinned production dependencies from
22
+ `desktop/runtime-manifest/package-lock.json`. It verifies the bundled Pi version
23
+ and actually starts a PTY before declaring success. Internet is required while
24
+ building, not to install Node/Pi on the end user's machine. Model calls,
25
+ authorization and package installation can still require internet.
26
+
27
+ The staging directory is `.desktop/runtime/`:
28
+
29
+ - `node/`: standalone Node and npm, including their upstream license.
30
+ - `backend/`: pi-webapp assets, extension, launcher and locked dependencies,
31
+ including Pi. It is outside ASAR, so Node and native PTY helpers run normally.
32
+ - `build-info.json`: app/runtime versions, platform, architecture and Node checksum.
33
+
34
+ Electron's renderer has no Node integration or preload bridge. It loads the same
35
+ loopback HTTP page as a browser, with sandboxing, context isolation, normal CSP,
36
+ and the existing bearer-token authentication. External HTTP(S) links require a
37
+ native confirmation and open in the default browser. Other OS protocols, webviews,
38
+ page-created windows, permission requests and downloads are not enabled.
39
+
40
+ ## Create an installer
41
+
42
+ ```bash
43
+ npm run desktop:package # DMG / NSIS installer / AppImage on this host
44
+ npm run desktop:package -- --dir # unpacked application for QA
45
+ ```
46
+
47
+ Output is in `desktop-release/`. The macOS bundle is **pi.app**, the native menu
48
+ and window name are **pi**, and installer names include a desktop build number,
49
+ e.g. `pi-0.1.20-desktop.5-mac-arm64.dmg`. “pi → 关于 pi” shows the build number
50
+ and executable location, so different desktop rebuilds are distinguishable even
51
+ when their shared backend stays at the same npm version. `desktop/release.json`
52
+ is the single source for the desktop name/build; increment its build number for
53
+ each delivered rebuild. The CFBundleVersion / Windows file version also changes.
54
+
55
+ Cross-platform/architecture flags are
56
+ intentionally rejected by the wrapper: using the current machine's Node/native
57
+ modules in another platform's installer would create a broken application. Use
58
+ native runners for each target. `desktop.yml` remains a manual cross-platform
59
+ packaging/artifact workflow. The separate `desktop-release.yml` below handles
60
+ verified macOS arm64 prereleases, not every main push.
61
+
62
+ The application embeds Node and Pi. Git, SSH, project compilers and other system
63
+ tools are **not** bundled. Missing tools must be installed by the user. Model
64
+ accounts/API credentials must still be configured in the existing settings UI.
65
+
66
+ ### Signing and updates / “签名更新”
67
+
68
+ These are two separate release responsibilities:
69
+
70
+ - **Code signing** identifies the publisher and protects the application from
71
+ undetected modification. macOS public distribution normally also needs Apple
72
+ notarization. Windows signing reduces unknown-publisher warnings. These require
73
+ the publisher's own credentials/certificates and, potentially, paid accounts.
74
+ - **Safe updates** verify an update's publisher/integrity and replace a compatible
75
+ application/runtime without destroying user data.
76
+
77
+ The installers remain **unsigned/unnotarized test builds**, with no certificate
78
+ discovery or automatic desktop updater. A GitHub prerelease is a download channel,
79
+ not a claim of formal signed-distribution readiness.
80
+ macOS Gatekeeper / Windows SmartScreen may warn or block an unsigned download.
81
+ Do not disable OS security globally to use it. Public distribution needs a
82
+ separately configured, authorized signing/notarization workflow; local successful
83
+ packaging is not proof of public-distribution readiness.
84
+
85
+ For now, install a newer desktop package to upgrade; if replacing a running
86
+ desktop-owned runtime, first finish tasks and stop that owned service. A desktop
87
+ attached to an external Web service can simply close without stopping the service.
88
+ Desktop-managed backends reject the Web/npm update and restart paths,
89
+ so the UI cannot overwrite the bundled runtime. A desktop window attached to an
90
+ existing npm-managed backend preserves that backend's original update behavior.
91
+
92
+ ### Upgrading from the former “Pi Webapp” app
93
+
94
+ 1. Quit the old desktop process first. A running old instance cannot be replaced
95
+ in memory by dragging a new app into Applications. Keep an external Web
96
+ backend running; an attached desktop's exit never stops it.
97
+ 2. Open the **new build-numbered** DMG and drag **pi.app** into Applications.
98
+ If pi.app already exists, confirm Replace. The formerly named Pi Webapp.app
99
+ is a separate Finder item and is not silently deleted or overwritten.
100
+ 3. Explicitly open `/Applications/pi.app`, not the old Dock shortcut, an older
101
+ mounted disk image, or Pi Webapp.app. Verify the expected build in **pi → 关于 pi**.
102
+ 4. Remove the old pinned Dock shortcut and pin the new pi.app. Once verified,
103
+ the old Pi Webapp.app may be removed manually; do not delete `~/.pi`.
104
+
105
+ The bundle ID remains `dev.pi.webapp`. The old Electron profile/instance-lock
106
+ location (`appData/Pi Webapp`) is retained so the rename does not reset UI
107
+ preferences or allow a second independent desktop instance. Explicit
108
+ `--user-data-dir` overrides are respected for testing. Pi configuration and
109
+ sessions still live in their existing directory. The shared Web document/CLI
110
+ keeps its existing name; this rename is for the native desktop application.
111
+
112
+ ## GitHub desktop prereleases
113
+
114
+ Download builds from **[GitHub Releases](https://github.com/chengzhiyi/pi-webapp/releases)**,
115
+ not the npm package, source ZIP or an expired Actions artifact. The current
116
+ release channel only offers tested macOS Apple Silicon DMGs; Windows/Linux and
117
+ Intel macOS need their own acceptance before becoming release targets.
118
+
119
+ `.github/workflows/desktop-release.yml` supports:
120
+
121
+ - **Tag push**: `desktop-v<backend-version>-b<desktop-build>`, such as
122
+ `desktop-v0.1.20-b5`. The tag must match package.json and desktop/release.json
123
+ at that exact source commit; mismatches fail before installation/build.
124
+ - **Manual build only** (default): `gh workflow run desktop-release.yml --ref main`.
125
+ This produces checksummed Actions artifacts without a public release.
126
+ - **Explicit manual publication**: add `-f publish=true`. The workflow pins the
127
+ dispatch commit, derives the tag from it, and only creates a missing tag at
128
+ that same commit. Existing tags pointing elsewhere are never moved.
129
+
130
+ For repeatable publication, commit the intended version/build and push a tag
131
+ pointing to that verified source SHA; do not silently follow a moving main while
132
+ its independent npm pipeline may write another version. Increment the desktop
133
+ build number for each delivered rebuild. Tag creation/release is an intentional
134
+ publication action, not part of an ordinary main commit.
135
+
136
+ The build job uses standard `macos-15` arm64, pinned npm lockfiles, standalone
137
+ Node/Pi preparation, icon/config tests and the **packaged** desktop/browser/PTY
138
+ smoke. Sentry reporting and signing discovery are disabled. It produces:
139
+
140
+ - `pi-<version>-desktop.<build>-mac-arm64.dmg`
141
+ - `SHA256SUMS` (DMG SHA-256)
142
+ - `desktop-release.json` (source SHA, backend/build/runtime versions, unsigned
143
+ status, platform/architecture, file size/checksum and smoke checks)
144
+ - `release-notes.md` (used as the Release body, not a separate download asset)
145
+
146
+ A separate Ubuntu job has scoped `contents: write` and no npm installation/app
147
+ execution. It revalidates the source-bound files, creates a **draft prerelease**,
148
+ uploads only the three intended assets, downloads them to verify their bytes,
149
+ and only then publishes the prerelease with `latest=false`. Signing is not
150
+ claimed. An interrupted upload leaves a draft; retrying the same source/tag may
151
+ repair a draft. A published release is never clobbered: a retry only succeeds
152
+ when downloaded assets are byte-identical. A conflicting source/tag or different
153
+ published bytes fails rather than replacing a public download.
154
+
155
+ The packing wrapper deliberately retains `--publish never`: explicit CI Release
156
+ upload owns publication. The manual cross-platform package workflow remains
157
+ artifact-only. npm/Web publishing is unchanged and independent.
158
+
159
+ ## Application icon
160
+
161
+ The desktop uses an original deep-teal rounded tile with an ivory **π** monogram
162
+ and a mint **>_** terminal prompt. Editable artwork lives in
163
+ `desktop/icons/icon.svg`; the checked-in `icon.png` (1024px, transparent),
164
+ `icon.icns` (standard/Retina macOS sizes), and `icon.ico` (16–256px Windows sizes)
165
+ are generated from it. Packaging explicitly selects an icon for each platform;
166
+ the window and macOS development Dock also use this artwork instead of Electron's.
167
+
168
+ To regenerate after editing the SVG:
169
+
170
+ ```bash
171
+ npx playwright install chromium # only needed to regenerate artwork
172
+ npm run desktop:icons
173
+ # Or use installed Google Chrome: PI_WEB_TEST_CHROME=true npm run desktop:icons
174
+ npm run test:desktop
175
+ npm run desktop:package
176
+ ```
177
+
178
+ Normal packaging uses the committed images and does not need a browser or an
179
+ image-conversion dependency. Installing a rebuilt app replaces its icon; quit
180
+ the old app first and replace it in Applications. A stale pinned Dock shortcut
181
+ may need to be removed and re-added. Do not modify an installed application's
182
+ bundle to change its icon, and do not delete Pi user data to refresh an icon.
183
+
184
+ ## Service ownership and shared state
185
+
186
+ The existing launcher state directory and exclusive lock are reused under
187
+ `~/.pi/agent/pi-web/` (or `PI_CODING_AGENT_DIR`). Model credentials and Pi sessions
188
+ stay in Pi's existing data directory, not inside the application bundle.
189
+
190
+ - The desktop checks a live launcher's bridge version, exact app version, token
191
+ and authenticated version endpoint before attaching. The released **0.1.19**
192
+ Web launcher predates these metadata fields: when they are absent, the desktop
193
+ also checks the authenticated session schema (v1) and the initial NDJSON
194
+ snapshot event before attaching. This is a narrow, tested legacy allowlist,
195
+ not cross-version compatibility or unconditional acceptance of missing fields.
196
+ - Legacy detection uses only GET requests, cancels its temporary event stream,
197
+ bounds response size/time, and never rewrites launcher state or claims service
198
+ ownership. A service replaced during a handshake is rechecked.
199
+ - Explicit incompatible protocols/versions, bad authentication, and failed health
200
+ checks remain errors with distinct messages. A native dialog offers retry,
201
+ opening the authenticated existing service in a browser when safe, or exiting.
202
+ It never stops, upgrades, or migrates an external service automatically. A truly
203
+ incompatible backend must be switched from its original entry point after
204
+ finishing tasks; a compatible old Web backend does **not** need to be stopped.
205
+ - If there is no running service, the desktop starts the shared launcher with its
206
+ bundled Node/Pi. A racing launcher still has to acquire the same exclusive lock.
207
+ - A desktop application is single-instance. Launching it again focuses its window.
208
+ - Closing the window or choosing Quit asks whether to stop the owned service or
209
+ leave it running. Stopping ends **all** sessions and terminals on that service,
210
+ including those used by a browser. Cancel leaves the application open.
211
+ - An attached service is never stopped by closing the desktop window.
212
+ - “Window → Open in browser” opens the same backend, not another Pi process.
213
+ - After choosing to leave the service running, reopening the desktop attaches to
214
+ it. To stop it later, use the Web launcher's `pi-webapp stop` command (or
215
+ `npm run stop` from this checkout); a new attached desktop does not claim ownership.
216
+
217
+ The initial workspace is the user's home directory; add/select project workspaces
218
+ using the existing UI. No shell login scripts are executed merely to construct a
219
+ PATH. The bundled Node directory is prepended to the GUI process's environment;
220
+ Git/SSH/toolchain PATH differences on desktop launch should be checked explicitly.
221
+
222
+ ## Tests
223
+
224
+ ```bash
225
+ npm run test:desktop
226
+ npm run desktop:smoke
227
+ npm run desktop:smoke -- --packaged
228
+ # Reproduce the original bug against an installed, pre-desktop 0.1.19 npm release:
229
+ npm run desktop:smoke:legacy -- --packaged --legacy-package /path/to/node_modules/pi-webapp
230
+ ```
231
+
232
+ Smoke testing requires a graphical session (Linux can use Xvfb) and Playwright
233
+ Chromium (`npx playwright install chromium`). Set `PI_WEB_TEST_CHROME=true` to
234
+ use an installed Chrome instead. Build the unpacked application before the
235
+ `--packaged` test. The smoke test uses a temporary HOME/Pi directory and a PATH
236
+ without global Node/Pi. It tests renderer isolation, real PTY interaction,
237
+ authentication, file listing, desktop update protection, a browser connected to
238
+ the same service, and confirmed shutdown/process cleanup. It does **not** submit
239
+ a paid model request, log in to a provider, or use the user's saved credentials.
240
+ Screenshots/results are written to `artifacts/desktop/`.
241
+
242
+ The legacy smoke uses a temporary HOME/agent directory and copies the old package
243
+ without changing its launcher or extension JavaScript. It prepares node-pty's
244
+ macOS helper executable bit **only in its fixture copy** (as normal installation
245
+ would), leaving the original installed release and live service untouched. It
246
+ starts the genuine old Web backend first, opens a working browser PTY, attaches
247
+ the desktop to the same chat, and verifies that the same PTY and backend survive
248
+ both attachment and desktop exit. The complementary regular smoke covers the
249
+ opposite order: desktop first, then browser. No model request is sent.
250
+
251
+ If the local harness wraps Git with a forced author, the existing Git history test
252
+ may observe that author instead of its fixture author. Run tests with the normal
253
+ system Git in PATH in an isolated test environment; do not change global Git
254
+ configuration to make a fixture pass.
255
+
256
+ ## Why the bundled Pi may not be the latest upstream version
257
+
258
+ The desktop bundles **Pi 0.87.1** because that is the host project's explicitly
259
+ pinned and tested SDK/runtime pair, not because npm automatically chose its
260
+ latest release. `package.json` and `desktop/runtime-manifest/package-lock.json`
261
+ pin both `@earendil-works/pi-coding-agent` and `@earendil-works/pi-ai` together.
262
+ The standalone Node runtime and native PTY are verified as part of that unit.
263
+ The app version, desktop build number and bundled Pi version are separate.
264
+
265
+ The public npm `latest` for both Pi packages was **1.3.0 when checked on
266
+ 2026-10-20**. Thus 0.87.1 is **not** the latest Pi; a validated pin should not be
267
+ misrepresented as one or become an excuse never to maintain the dependency.
268
+ Moving from the tested 0.x SDK to 1.x needs API/type compatibility review, paired
269
+ lockfile updates, authentication/plugin/session regressions, native PTY checks,
270
+ and packaged desktop/Web smoke tests before publishing a new installer.
271
+
272
+ Do not replace the signed/packaged runtime in place or install `latest` on every
273
+ startup. Upgrade it deliberately through a new tested desktop build, recording
274
+ the exact Pi version in `desktop-release.json` and release notes. This preserves
275
+ reproducibility and prevents silently changing a user's running tasks.
276
+
277
+ ## Updating runtime dependencies
278
+
279
+ When production dependencies or pinned Pi versions in the root manifest change:
280
+
281
+ ```bash
282
+ npm run desktop:sync-runtime
283
+ # Review and commit desktop/runtime-manifest/package{,-lock}.json.
284
+ npm run desktop:prepare
285
+ ```
286
+
287
+ The sync command seeds resolutions from the main lockfile and generates a separate
288
+ production-only lockfile. Preparation refuses to proceed when these dependencies
289
+ are out of sync. Electron and electron-builder are development dependencies only;
290
+ they do not enter the published npm package's runtime dependencies.
291
+
292
+ ## Verification scope of the initial delivery
293
+
294
+ macOS arm64 is the local implementation/QA target. Windows/Linux installer
295
+ configuration is provided but must be tested on their own runners before promising
296
+ support. Custom icons are configured for all platforms; the icon replacement
297
+ has only been verified in a packaged macOS arm64 app.
298
+ Formal signing, automatic desktop updates, tray integration, completion
299
+ notifications and cross-platform end-to-end QA are not included in this delivery.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-webapp",
3
- "version": "0.1.19",
3
+ "version": "0.1.21",
4
4
  "type": "module",
5
5
  "description": "A browser interface for Pi with live chat, workspaces, models, and attachments",
6
6
  "repository": {
@@ -15,7 +15,7 @@
15
15
  "pi-webapp": "./bin/pi-webapp.mjs"
16
16
  },
17
17
  "pi": {
18
- "image": "https://cdn.jsdelivr.net/npm/pi-webapp@0.1.19/assets/cover-webapp.png",
18
+ "image": "https://cdn.jsdelivr.net/npm/pi-webapp@0.1.21/assets/cover-webapp.png",
19
19
  "extensions": [
20
20
  "./dist/extension.js"
21
21
  ]
@@ -31,6 +31,7 @@
31
31
  "web/src/ui/shared/LICENSE.txt",
32
32
  "docs/sentry.md",
33
33
  "docs/sentry-triage.md",
34
+ "docs/desktop.md",
34
35
  "scripts/prepare-terminal.mjs"
35
36
  ],
36
37
  "scripts": {
@@ -38,7 +39,15 @@
38
39
  "status": "node bin/pi-webapp.mjs status",
39
40
  "stop": "node bin/pi-webapp.mjs stop",
40
41
  "check": "tsc --noEmit && tsc -p web/tsconfig.json",
41
- "test": "node --import ./test/setup-env.mjs --experimental-strip-types --test test/*.test.ts",
42
+ "test": "node --import ./test/setup-env.mjs --experimental-strip-types --test test/*.test.ts && npm run test:desktop",
43
+ "test:desktop": "node --test desktop/test/*.test.mjs",
44
+ "desktop:icons": "node scripts/generate-desktop-icons.mjs",
45
+ "desktop:sync-runtime": "node scripts/sync-desktop-runtime.mjs",
46
+ "desktop:prepare": "npm run build && node scripts/prepare-desktop.mjs",
47
+ "desktop:start": "electron desktop",
48
+ "desktop:smoke": "node scripts/smoke-desktop.mjs",
49
+ "desktop:smoke:legacy": "node scripts/smoke-desktop-legacy.mjs",
50
+ "desktop:package": "node scripts/package-desktop.mjs",
42
51
  "build": "node scripts/build.mjs",
43
52
  "build:web": "node scripts/build.mjs browser",
44
53
  "build:extension": "node scripts/build.mjs node",
@@ -70,6 +79,8 @@
70
79
  "@types/node": "22.19.19",
71
80
  "@types/react": "^18.3.1",
72
81
  "@types/react-dom": "^18.3.0",
82
+ "electron": "44.9.0",
83
+ "electron-builder": "26.15.3",
73
84
  "esbuild": "^0.28.2",
74
85
  "micromark-util-types": "^2.0.2",
75
86
  "typescript": "7.0.2",
@@ -1,8 +1,8 @@
1
- var O=Object.defineProperty;var x=(e,t,i)=>t in e?O(e,t,{enumerable:!0,configurable:!0,writable:!0,value:i}):e[t]=i;var d=(e,t,i)=>x(e,typeof t!="symbol"?t+"":t,i);(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},t=new e.Error().stack;t&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[t]="35a0f8a5-781e-43ae-8b22-2ee7cf462cd3",e._sentryDebugIdIdentifier="sentry-dbid-35a0f8a5-781e-43ae-8b22-2ee7cf462cd3")}catch{}})();(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const s of document.querySelectorAll('link[rel="modulepreload"]'))r(s);new MutationObserver(s=>{for(const n of s)if(n.type==="childList")for(const a of n.addedNodes)a.tagName==="LINK"&&a.rel==="modulepreload"&&r(a)}).observe(document,{childList:!0,subtree:!0});function i(s){const n={};return s.integrity&&(n.integrity=s.integrity),s.referrerPolicy&&(n.referrerPolicy=s.referrerPolicy),s.crossOrigin==="use-credentials"?n.credentials="include":s.crossOrigin==="anonymous"?n.credentials="omit":n.credentials="same-origin",n}function r(s){if(s.ep)return;s.ep=!0;const n=i(s);fetch(s.href,n)}})();const B="modulepreload",D=function(e){return"/"+e},I={},A=function(t,i,r){let s=Promise.resolve();if(i&&i.length>0){let a=function(o){return Promise.all(o.map(l=>Promise.resolve(l).then(g=>({status:"fulfilled",value:g}),g=>({status:"rejected",reason:g}))))};document.getElementsByTagName("link");const c=document.querySelector("meta[property=csp-nonce]"),m=(c==null?void 0:c.nonce)||(c==null?void 0:c.getAttribute("nonce"));s=a(i.map(o=>{if(o=D(o),o in I)return;I[o]=!0;const l=o.endsWith(".css"),g=l?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${o}"]${g}`))return;const u=document.createElement("link");if(u.rel=l?"stylesheet":B,l||(u.as="script"),u.crossOrigin="",u.href=o,m&&u.setAttribute("nonce",m),document.head.appendChild(u),l)return new Promise((T,N)=>{u.addEventListener("load",T),u.addEventListener("error",()=>N(new Error(`Unable to preload CSS for ${o}`)))})}))}function n(a){const c=new Event("vite:preloadError",{cancelable:!0});if(c.payload=a,window.dispatchEvent(c),!c.defaultPrevented)throw a}return s.then(a=>{for(const c of a||[])c.status==="rejected"&&n(c.reason);return t().catch(n)})},j=new Set(["bash","powershell","read","write","edit","grep","find","ls"]),R=new Set(["cancelled","blocked","validation","not_found","permission","timeout","process_exit","unknown"]),ee={userInfo:!1,cookies:!1,httpHeaders:!1,httpBodies:[],urlQueryParams:!1,genAI:{inputs:!1,outputs:!1},graphQL:{document:!1,variables:!1},databaseQueryData:!1,queues:!1,stackFrameVariables:!1,frameContextLines:0},U=new Set(["stage","route","method","status","durationMs","connection","idle","model","thinkingLevel","messageCount","attachmentCount","session","requestId","operationId","errorId","repeats","dropped","componentStack","eventType","sequence","nodeVersion","piVersion","platform","browser","buildId","code","toolName","toolId","toolCallId","failureKind","errorCode","exitCode","timeoutMs","diagnosticSource","originalStackAvailable","errorSummary","summaryOmitted","summaryOmittedReason","level"]),q=new Set(["/api/workspace/git/control","/api/workspace/git/write","/api/workspace/git/status","/api/workspace/git/diff","/api/workspace/git/history","/api/workspace/git/commit-detail","/api/workspace/git/commit-diff","/api/workspace/files/list","/api/workspace/files/preview","/api/plugins","/api/plugin-action","/api/plugin-interaction","/api/resume","/api/update","/api/update/version","/api/provider/models","/api/provider/logout","/api/provider/login/active","/api/telemetry/config","/api/image","/api/attachment","/api/attachment/remove","/api/session","/api/providers","/api/models","/api/config","/api/workspaces","/api/commands","/api/events","/api/message","/api/abort","/api/compact","/api/new-session","/api/model","/api/thinking-level","/api/provider/login","/api/provider/login/respond","/api/provider/login/cancel","/api/provider/custom","/api/workspace/add","/api/workspace/select","/api/workspace/new-session","/api/workspace/remove","/api/session/select","/api/directory/capability","/api/directory/list","/api/directory/create","/api/directory/pick"]);function te(e){return e==="/api/message"||e.startsWith("/api/provider/")||e.startsWith("/api/workspace/files/")||e.startsWith("/api/workspace/git/")||["/api/plugin-action","/api/plugin-interaction","/api/resume","/api/compact"].includes(e)}function p(e){return e.slice(0,8192).replace(/-----BEGIN [^-\n]+-----[\s\S]*?(?:-----END [^-\n]+-----|$)/g,"[redacted]").replace(/(["'`])[\s\S]*?\1/g,"[quoted]").replace(/(?:Bearer\s+\S+|(?:api[_-]?key|token|password|secret|authorization)\s*[=:]\s*\S+)/gi,"[redacted]").replace(/\b(?:sk-|sntrys_|eyJ)[A-Za-z0-9_.-]+/g,"[redacted]").replace(/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g,"[email]").replace(/https?:\/\/[^\s)]+/gi,"[url]").replace(/(?:file:\/\/)?(?:\/[\w.~-]+){2,}(?::\d+(?::\d+)?)?/g,"[path]").replace(/[A-Za-z]:\\[^\s)]+/g,"[path]").replace(/(?:^|\s)(?:\.\.?[\\/]|~[\\/])[^\s)]+/g," [path]").replace(/\b(?:[\w.-]+[\\/])+[\w.-]+/g,"[path]").replace(/\{[^\n]*\}/g,"[object]").replace(/\b[A-Za-z0-9_-]{24,}\b/g,"[redacted]").slice(0,1024)}function h(e){const t={};for(const i of U){const r=e[i];i==="toolName"?typeof r=="string"&&(j.has(r)||r==="custom")&&(t[i]=r):i==="failureKind"?R.has(r)&&(t[i]=r):i==="level"?(r==="warning"||r==="error")&&(t[i]=r):i==="diagnosticSource"?(r==="tool_execution_end"||r==="message_end")&&(t[i]=r):i==="errorCode"?typeof r=="string"&&/^(?:E[A-Z0-9]{1,20}|nonzero_exit|timeout|cancelled|blocked|invalid_arguments|tool_not_found|unknown)$/.test(r)&&(t[i]=r):i==="toolId"?typeof r=="string"&&/^[a-f0-9]{16}$/.test(r)&&(t[i]=r):i==="route"&&typeof r=="string"?t[i]=q.has(r.split("?")[0])?r.split("?")[0]:"[route]":i==="model"&&typeof r=="string"&&/^[\w.-]+\/[\w.-]+$/.test(r)?t[i]=r.split("/").map(p).join("/"):typeof r=="string"?t[i]=["requestId","operationId","errorId","session","buildId","toolId","toolCallId"].includes(i)&&/^[\w-]{1,80}$/.test(r)?r:p(r).slice(0,i==="errorSummary"?512:1024):(typeof r=="boolean"||typeof r=="number"&&Number.isFinite(r)||r===null)&&(t[i]=r)}return t}function v(e){var r;const t=e.replace(/\\/g,"/").split(/[?#]/)[0];return t.startsWith("node:")?t.slice(0,150):`app:///${(((r=t.match(/(?:^|\/)((?:web\/src|extension|shared|dist|assets)\/[^\s:)]+)$/))==null?void 0:r[1])??t.split("/").pop()??"unknown").replace(/[^\w./-]/g,"_").slice(-200)}`}function S(e,t=0){const i=e instanceof Error?e:new Error(typeof e=="string"?e:"Non-Error rejection"),r=new Error(p(i.message));if(r.name=p(i.name).slice(0,100),i.stack){const s=i.stack.split(`
1
+ var O=Object.defineProperty;var x=(e,t,i)=>t in e?O(e,t,{enumerable:!0,configurable:!0,writable:!0,value:i}):e[t]=i;var d=(e,t,i)=>x(e,typeof t!="symbol"?t+"":t,i);(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof globalThis<"u"?globalThis:typeof self<"u"?self:{},t=new e.Error().stack;t&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[t]="b4ccb35d-2c25-4c71-a83d-ff79175b2fb7",e._sentryDebugIdIdentifier="sentry-dbid-b4ccb35d-2c25-4c71-a83d-ff79175b2fb7")}catch{}})();(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const s of document.querySelectorAll('link[rel="modulepreload"]'))r(s);new MutationObserver(s=>{for(const n of s)if(n.type==="childList")for(const a of n.addedNodes)a.tagName==="LINK"&&a.rel==="modulepreload"&&r(a)}).observe(document,{childList:!0,subtree:!0});function i(s){const n={};return s.integrity&&(n.integrity=s.integrity),s.referrerPolicy&&(n.referrerPolicy=s.referrerPolicy),s.crossOrigin==="use-credentials"?n.credentials="include":s.crossOrigin==="anonymous"?n.credentials="omit":n.credentials="same-origin",n}function r(s){if(s.ep)return;s.ep=!0;const n=i(s);fetch(s.href,n)}})();const B="modulepreload",D=function(e){return"/"+e},I={},A=function(t,i,r){let s=Promise.resolve();if(i&&i.length>0){let a=function(o){return Promise.all(o.map(l=>Promise.resolve(l).then(g=>({status:"fulfilled",value:g}),g=>({status:"rejected",reason:g}))))};document.getElementsByTagName("link");const c=document.querySelector("meta[property=csp-nonce]"),m=(c==null?void 0:c.nonce)||(c==null?void 0:c.getAttribute("nonce"));s=a(i.map(o=>{if(o=D(o),o in I)return;I[o]=!0;const l=o.endsWith(".css"),g=l?'[rel="stylesheet"]':"";if(document.querySelector(`link[href="${o}"]${g}`))return;const u=document.createElement("link");if(u.rel=l?"stylesheet":B,l||(u.as="script"),u.crossOrigin="",u.href=o,m&&u.setAttribute("nonce",m),document.head.appendChild(u),l)return new Promise((T,N)=>{u.addEventListener("load",T),u.addEventListener("error",()=>N(new Error(`Unable to preload CSS for ${o}`)))})}))}function n(a){const c=new Event("vite:preloadError",{cancelable:!0});if(c.payload=a,window.dispatchEvent(c),!c.defaultPrevented)throw a}return s.then(a=>{for(const c of a||[])c.status==="rejected"&&n(c.reason);return t().catch(n)})},j=new Set(["bash","powershell","read","write","edit","grep","find","ls"]),R=new Set(["cancelled","blocked","validation","not_found","permission","timeout","process_exit","unknown"]),ee={userInfo:!1,cookies:!1,httpHeaders:!1,httpBodies:[],urlQueryParams:!1,genAI:{inputs:!1,outputs:!1},graphQL:{document:!1,variables:!1},databaseQueryData:!1,queues:!1,stackFrameVariables:!1,frameContextLines:0},U=new Set(["stage","route","method","status","durationMs","connection","idle","model","thinkingLevel","messageCount","attachmentCount","session","requestId","operationId","errorId","repeats","dropped","componentStack","eventType","sequence","nodeVersion","piVersion","platform","browser","buildId","code","toolName","toolId","toolCallId","failureKind","errorCode","exitCode","timeoutMs","diagnosticSource","originalStackAvailable","errorSummary","summaryOmitted","summaryOmittedReason","level"]),q=new Set(["/api/workspace/git/control","/api/workspace/git/write","/api/workspace/git/status","/api/workspace/git/diff","/api/workspace/git/history","/api/workspace/git/commit-detail","/api/workspace/git/commit-diff","/api/workspace/files/list","/api/workspace/files/preview","/api/plugins","/api/plugin-action","/api/plugin-interaction","/api/resume","/api/update","/api/update/version","/api/provider/models","/api/provider/logout","/api/provider/login/active","/api/telemetry/config","/api/image","/api/attachment","/api/attachment/remove","/api/session","/api/providers","/api/models","/api/config","/api/workspaces","/api/commands","/api/events","/api/message","/api/abort","/api/compact","/api/new-session","/api/model","/api/thinking-level","/api/provider/login","/api/provider/login/respond","/api/provider/login/cancel","/api/provider/custom","/api/workspace/add","/api/workspace/select","/api/workspace/new-session","/api/workspace/remove","/api/session/select","/api/directory/capability","/api/directory/list","/api/directory/create","/api/directory/pick"]);function te(e){return e==="/api/message"||e.startsWith("/api/provider/")||e.startsWith("/api/workspace/files/")||e.startsWith("/api/workspace/git/")||["/api/plugin-action","/api/plugin-interaction","/api/resume","/api/compact"].includes(e)}function p(e){return e.slice(0,8192).replace(/-----BEGIN [^-\n]+-----[\s\S]*?(?:-----END [^-\n]+-----|$)/g,"[redacted]").replace(/(["'`])[\s\S]*?\1/g,"[quoted]").replace(/(?:Bearer\s+\S+|(?:api[_-]?key|token|password|secret|authorization)\s*[=:]\s*\S+)/gi,"[redacted]").replace(/\b(?:sk-|sntrys_|eyJ)[A-Za-z0-9_.-]+/g,"[redacted]").replace(/[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g,"[email]").replace(/https?:\/\/[^\s)]+/gi,"[url]").replace(/(?:file:\/\/)?(?:\/[\w.~-]+){2,}(?::\d+(?::\d+)?)?/g,"[path]").replace(/[A-Za-z]:\\[^\s)]+/g,"[path]").replace(/(?:^|\s)(?:\.\.?[\\/]|~[\\/])[^\s)]+/g," [path]").replace(/\b(?:[\w.-]+[\\/])+[\w.-]+/g,"[path]").replace(/\{[^\n]*\}/g,"[object]").replace(/\b[A-Za-z0-9_-]{24,}\b/g,"[redacted]").slice(0,1024)}function h(e){const t={};for(const i of U){const r=e[i];i==="toolName"?typeof r=="string"&&(j.has(r)||r==="custom")&&(t[i]=r):i==="failureKind"?R.has(r)&&(t[i]=r):i==="level"?(r==="warning"||r==="error")&&(t[i]=r):i==="diagnosticSource"?(r==="tool_execution_end"||r==="message_end")&&(t[i]=r):i==="errorCode"?typeof r=="string"&&/^(?:E[A-Z0-9]{1,20}|nonzero_exit|timeout|cancelled|blocked|invalid_arguments|tool_not_found|unknown)$/.test(r)&&(t[i]=r):i==="toolId"?typeof r=="string"&&/^[a-f0-9]{16}$/.test(r)&&(t[i]=r):i==="route"&&typeof r=="string"?t[i]=q.has(r.split("?")[0])?r.split("?")[0]:"[route]":i==="model"&&typeof r=="string"&&/^[\w.-]+\/[\w.-]+$/.test(r)?t[i]=r.split("/").map(p).join("/"):typeof r=="string"?t[i]=["requestId","operationId","errorId","session","buildId","toolId","toolCallId"].includes(i)&&/^[\w-]{1,80}$/.test(r)?r:p(r).slice(0,i==="errorSummary"?512:1024):(typeof r=="boolean"||typeof r=="number"&&Number.isFinite(r)||r===null)&&(t[i]=r)}return t}function v(e){var r;const t=e.replace(/\\/g,"/").split(/[?#]/)[0];return t.startsWith("node:")?t.slice(0,150):`app:///${(((r=t.match(/(?:^|\/)((?:web\/src|extension|shared|dist|assets)\/[^\s:)]+)$/))==null?void 0:r[1])??t.split("/").pop()??"unknown").replace(/[^\w./-]/g,"_").slice(-200)}`}function S(e,t=0){const i=e instanceof Error?e:new Error(typeof e=="string"?e:"Non-Error rejection"),r=new Error(p(i.message));if(r.name=p(i.name).slice(0,100),i.stack){const s=i.stack.split(`
2
2
  `).slice(1,31).map(n=>{const a=n.match(/((?:file:\/\/|https?:\/\/|\/|[A-Za-z]:\\)[^\s()]+):(\d+):(\d+)(\)?)$/);return a?`${p(n.slice(0,a.index))}${a[1]}:${a[2]}:${a[3]}${a[4]}`:p(n)});r.stack=`${r.name}: ${r.message}
3
3
  ${s.join(`
4
4
  `)}`}else r.stack=void 0;return t<3&&i.cause!==void 0&&(r.cause=S(i.cause,t+1)),r}function re(e,t){const i=new Error(t);return e instanceof Error&&(i.name=e.name,e.stack&&(i.stack=`${i.name}: ${t}
5
5
  ${e.stack.split(`
6
6
  `).slice(1).join(`
7
7
  `)}`)),i}function F(e){return{...e.filename?{filename:v(e.filename)}:{},...e.abs_path?{abs_path:v(e.abs_path)}:{},...e.function?{function:p(e.function)}:{},lineno:e.lineno,colno:e.colno,in_app:e.in_app}}function K(e){var r,s,n,a,c,m;const t=h(((r=e.contexts)==null?void 0:r.diagnostic)??{}),i=C(t);return{event_id:e.event_id,timestamp:e.timestamp,platform:e.platform,level:e.level,release:e.release,dist:e.dist,environment:p(e.environment??"production"),...e.message?{message:p(e.message)}:{},exception:e.exception?{values:(s=e.exception.values)==null?void 0:s.slice(0,4).map(o=>{var l;return{type:p(o.type??"Error"),value:p(o.value??""),...o.stacktrace?{stacktrace:{frames:(l=o.stacktrace.frames)==null?void 0:l.slice(-30).map(F)}}:{},...o.mechanism?{mechanism:{type:o.mechanism.type,handled:o.mechanism.handled}}:{}}})}:void 0,tags:{side:(n=e.tags)==null?void 0:n.side,buildId:(a=e.tags)==null?void 0:a.buildId,...t.toolName?{toolName:t.toolName}:{},...t.failureKind?{failureKind:t.failureKind}:{},...t.errorCode?{errorCode:t.errorCode}:{}},...i?{fingerprint:i}:{},contexts:{diagnostic:t},breadcrumbs:(c=e.breadcrumbs)==null?void 0:c.slice(-100).map(o=>({timestamp:o.timestamp,category:p(o.category??"app"),data:h(o.data??{})})),debug_meta:e.debug_meta?{images:(m=e.debug_meta.images)==null?void 0:m.slice(0,10).map(o=>({type:o.type,debug_id:o.debug_id,...o.code_file?{code_file:v(o.code_file)}:{}}))}:void 0}}function C(e){if(!(e.stage!=="tool"||e.originalStackAvailable!==!1||!e.toolName||!e.failureKind))return["pi-webapp-tool-result",String(e.toolName),String(e.toolId??"builtin"),String(e.failureKind),String(e.errorCode??"unknown")]}function ie(e,t){return t.attachments=[],K(e)}class Z{constructor(){d(this,"items",[]);d(this,"bytes",0);d(this,"encoder",new TextEncoder)}add(t,i={}){const r={timestamp:Date.now()/1e3,category:p(t),data:h(i)},s=this.encoder.encode(JSON.stringify(r)).byteLength+1;for(this.items.push({item:r,size:s}),this.bytes+=s;this.items.length>100||this.bytes>64*1024-2;)this.bytes-=this.items.shift().size}snapshot(){return this.items.map(({item:t})=>t)}}class V{constructor(){d(this,"windowAt",-1);d(this,"total",0);d(this,"seen",new Map)}take(t,i=Date.now()){(this.windowAt<0||i-this.windowAt>=6e4)&&(this.windowAt=i,this.total=0);const r=this.seen.get(t);if(r&&i-r.at<6e4){r.repeats++;return}if(!(this.total>=20))return this.total++,this.seen.size>=64&&!r&&this.seen.delete(this.seen.keys().next().value),this.seen.set(t,{at:i,repeats:0}),{repeats:(r==null?void 0:r.repeats)??0}}}const W=new Set(["目录路径必须是绝对路径","父目录路径必须是绝对路径","文件夹名称无效","工作区目录不可用,请恢复目录或从列表移除后重新添加","会话已切换","Pi 正在运行,请等待当前回复结束","请等待当前回复结束","请等待当前回复结束再切换工作区","请等待当前回复结束再切换会话","请先切换到其他工作区","新会话已取消","已有登录正在进行","模型不可用","模型提供方未配置认证","当前模型不支持此推理强度","其他提供方的登录正在进行,请先完成或取消当前登录","当前会话没有暂停的任务","请先完成当前交互或审批","请先选择模型","请先连接当前模型","插件未启用","会话运行实例已切换","提供方已存在","文件超过 20 MB","请求内容过大","会话不属于该工作区","推理强度无效"]);function L(e){return e instanceof Error&&(e.name==="AbortError"||W.has(e.message))}class se{constructor(t,i,r,s,n=new Z){d(this,"budget",new V);d(this,"breadcrumbs");d(this,"scopeClass");d(this,"seen",new WeakSet);d(this,"state",{});d(this,"client");d(this,"side");d(this,"buildId");this.client=t,this.side=i,this.buildId=r,this.scopeClass=s.Scope,this.breadcrumbs=n,t.addIntegration(s.linkedErrorsIntegration({limit:4}))}setState(t){this.state=h(t)}capture(t,i={},r){var s;try{if(L(t))return;if(typeof t=="object"&&t!==null){if(this.seen.has(t))return;this.seen.add(t)}const n=S(t),a=h({...this.state,...i}),c=C(a),m=c?JSON.stringify(c):`${n.name}:${n.message}:${((s=n.stack)==null?void 0:s.split(`
8
- `)[1])??""}:${i.stage??""}`,o=this.budget.take(m);if(!o)return;const l=new this.scopeClass;l.setClient(this.client),l.setTags({side:this.side,buildId:this.buildId}),a.level==="warning"&&l.setLevel("warning"),c&&l.setFingerprint(c),l.setContext("diagnostic",{...a,repeats:o.repeats});for(const g of this.breadcrumbs.snapshot())l.addBreadcrumb(g,100);return l.captureException(n,r?{event_id:r}:void 0)}catch{return}}ignore(t){this.seen.add(t)}}function ne(e,t){return e({...t,bufferSize:20},async({body:i})=>{const r=await fetch(t.url,{method:"POST",body:i,signal:AbortSignal.timeout(3e3),credentials:"omit",referrerPolicy:"no-referrer",redirect:"error",headers:{"Content-Type":"application/x-sentry-envelope"}});return{statusCode:r.status,headers:{"x-sentry-rate-limits":r.headers.get("x-sentry-rate-limits"),"retry-after":r.headers.get("retry-after")}}})}let w;function M(){if(w!==void 0)return w;const e=location.hash.slice(1);try{w=e||sessionStorage.getItem("pi-web-token"),e&&sessionStorage.setItem("pi-web-token",e)}catch{w=e||null}return e&&history.replaceState(null,"",location.pathname),w}const H="pi-webapp@0.1.19+e370826d8f2658b06bbc",J="e370826d8f2658b06bbc";function Q(){if(typeof crypto.randomUUID=="function")return crypto.randomUUID();const e=crypto.getRandomValues(new Uint8Array(16));e[6]=e[6]&15|64,e[8]=e[8]&63|128;const t=Array.from(e,i=>i.toString(16).padStart(2,"0")).join("");return`${t.slice(0,8)}-${t.slice(8,12)}-${t.slice(12,16)}-${t.slice(16,20)}-${t.slice(20)}`}let f,z=!0,$=!1,P=!1,_=[];const E=new WeakSet,b=new Map;let y={};function k(e,t={}){try{if(L(e))return;if(typeof e=="object"&&e!==null){if(E.has(e))return;E.add(e)}if(f)return f.capture(e,t);z&&_.length<20&&_.push({error:S(e),context:h(t)})}catch{}}function oe(e){E.add(e)}function ae(e,t={}){f==null||f.breadcrumbs.add(e,t)}function ce(e){e.sessionId&&(b.has(e.sessionId)||(b.size>=32&&b.delete(b.keys().next().value),b.set(e.sessionId,Q())),e={...e,session:b.get(e.sessionId)}),y=h({...y,...e}),f==null||f.setState(y)}function G(){$||($=!0,P=new URL(location.href).searchParams.get("sentry_release_probe")==="1",window.addEventListener("error",e=>{e instanceof ErrorEvent?k(e.error??new Error(e.message),{stage:"global"}):(e.target instanceof HTMLScriptElement||e.target instanceof HTMLLinkElement)&&k(new Error("Application resource failed to load"),{stage:"resource"})},!0),window.addEventListener("unhandledrejection",e=>k(e.reason,{stage:"unhandled_rejection"})),X())}async function X(){var e;try{const t=M();if(!t)return;const i=await fetch("/api/telemetry/config",{headers:{Authorization:`Bearer ${t}`},signal:AbortSignal.timeout(1e3)});if(!i.ok)return;const r=await i.json();if(!r.enabled||!r.dsn)return;const{createBrowserReporter:s}=await A(async()=>{const{createBrowserReporter:a}=await import("./telemetry-client-CBQBug9X.js");return{createBrowserReporter:a}},[]);f=s({...r,buildId:J,release:H});const n=((e=navigator.userAgent.match(/(?:Firefox|Edg|Chrome|Version)\/[\d.]+/))==null?void 0:e[0])??"unknown";f.setState({...y,browser:n,platform:navigator.platform}),y={...y,browser:n,platform:navigator.platform};for(const a of _)f.capture(a.error,a.context);r.environment==="sentry-verification"&&P&&f.capture(new Error("Sentry browser release verification"),{stage:"release_verification",code:"sentry_release_probe"})}catch{}finally{_=[],z=!1}}G();A(()=>import("./app-4px1DWHV.js").then(e=>e.d),[]).catch(e=>k(e,{stage:"startup"}));export{se as E,A as _,Q as a,te as b,ae as c,M as d,ie as e,ne as f,oe as i,re as o,ee as p,k as r,ce as s};
8
+ `)[1])??""}:${i.stage??""}`,o=this.budget.take(m);if(!o)return;const l=new this.scopeClass;l.setClient(this.client),l.setTags({side:this.side,buildId:this.buildId}),a.level==="warning"&&l.setLevel("warning"),c&&l.setFingerprint(c),l.setContext("diagnostic",{...a,repeats:o.repeats});for(const g of this.breadcrumbs.snapshot())l.addBreadcrumb(g,100);return l.captureException(n,r?{event_id:r}:void 0)}catch{return}}ignore(t){this.seen.add(t)}}function ne(e,t){return e({...t,bufferSize:20},async({body:i})=>{const r=await fetch(t.url,{method:"POST",body:i,signal:AbortSignal.timeout(3e3),credentials:"omit",referrerPolicy:"no-referrer",redirect:"error",headers:{"Content-Type":"application/x-sentry-envelope"}});return{statusCode:r.status,headers:{"x-sentry-rate-limits":r.headers.get("x-sentry-rate-limits"),"retry-after":r.headers.get("retry-after")}}})}let w;function M(){if(w!==void 0)return w;const e=location.hash.slice(1);try{w=e||sessionStorage.getItem("pi-web-token"),e&&sessionStorage.setItem("pi-web-token",e)}catch{w=e||null}return e&&history.replaceState(null,"",location.pathname),w}const H="pi-webapp@0.1.21+c6b0921cd1db2811f3fc",J="c6b0921cd1db2811f3fc";function Q(){if(typeof crypto.randomUUID=="function")return crypto.randomUUID();const e=crypto.getRandomValues(new Uint8Array(16));e[6]=e[6]&15|64,e[8]=e[8]&63|128;const t=Array.from(e,i=>i.toString(16).padStart(2,"0")).join("");return`${t.slice(0,8)}-${t.slice(8,12)}-${t.slice(12,16)}-${t.slice(16,20)}-${t.slice(20)}`}let f,z=!0,$=!1,P=!1,_=[];const E=new WeakSet,b=new Map;let y={};function k(e,t={}){try{if(L(e))return;if(typeof e=="object"&&e!==null){if(E.has(e))return;E.add(e)}if(f)return f.capture(e,t);z&&_.length<20&&_.push({error:S(e),context:h(t)})}catch{}}function oe(e){E.add(e)}function ae(e,t={}){f==null||f.breadcrumbs.add(e,t)}function ce(e){e.sessionId&&(b.has(e.sessionId)||(b.size>=32&&b.delete(b.keys().next().value),b.set(e.sessionId,Q())),e={...e,session:b.get(e.sessionId)}),y=h({...y,...e}),f==null||f.setState(y)}function G(){$||($=!0,P=new URL(location.href).searchParams.get("sentry_release_probe")==="1",window.addEventListener("error",e=>{e instanceof ErrorEvent?k(e.error??new Error(e.message),{stage:"global"}):(e.target instanceof HTMLScriptElement||e.target instanceof HTMLLinkElement)&&k(new Error("Application resource failed to load"),{stage:"resource"})},!0),window.addEventListener("unhandledrejection",e=>k(e.reason,{stage:"unhandled_rejection"})),X())}async function X(){var e;try{const t=M();if(!t)return;const i=await fetch("/api/telemetry/config",{headers:{Authorization:`Bearer ${t}`},signal:AbortSignal.timeout(1e3)});if(!i.ok)return;const r=await i.json();if(!r.enabled||!r.dsn)return;const{createBrowserReporter:s}=await A(async()=>{const{createBrowserReporter:a}=await import("./telemetry-client-CBQBug9X.js");return{createBrowserReporter:a}},[]);f=s({...r,buildId:J,release:H});const n=((e=navigator.userAgent.match(/(?:Firefox|Edg|Chrome|Version)\/[\d.]+/))==null?void 0:e[0])??"unknown";f.setState({...y,browser:n,platform:navigator.platform}),y={...y,browser:n,platform:navigator.platform};for(const a of _)f.capture(a.error,a.context);r.environment==="sentry-verification"&&P&&f.capture(new Error("Sentry browser release verification"),{stage:"release_verification",code:"sentry_release_probe"})}catch{}finally{_=[],z=!1}}G();A(()=>import("./app-4px1DWHV.js").then(e=>e.d),[]).catch(e=>k(e,{stage:"startup"}));export{se as E,A as _,Q as a,te as b,ae as c,M as d,ie as e,ne as f,oe as i,re as o,ee as p,k as r,ce as s};