wherdr 2.3.0 → 2.5.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/.output/nitro.json +1 -1
- package/.output/public/_nuxt/1gzTzt3j.js +9 -0
- package/.output/public/_nuxt/1gzTzt3j.js.br +0 -0
- package/.output/public/_nuxt/1gzTzt3j.js.gz +0 -0
- package/.output/public/_nuxt/AgentView.B6zltno1.css +1 -0
- package/.output/public/_nuxt/AgentView.B6zltno1.css.br +0 -0
- package/.output/public/_nuxt/AgentView.B6zltno1.css.gz +0 -0
- package/.output/public/_nuxt/{DN2uhp8-.js → Bd0Z2zzq.js} +1 -1
- package/.output/public/_nuxt/BdJIc1Xf.js +1 -0
- package/.output/public/_nuxt/BdJIc1Xf.js.br +0 -0
- package/.output/public/_nuxt/BdJIc1Xf.js.gz +0 -0
- package/.output/public/_nuxt/BrxmYJEM.js +1 -0
- package/.output/public/_nuxt/BrxmYJEM.js.br +0 -0
- package/.output/public/_nuxt/BrxmYJEM.js.gz +0 -0
- package/.output/public/_nuxt/C6fXOTRV.js +3 -0
- package/.output/public/_nuxt/C6fXOTRV.js.br +0 -0
- package/.output/public/_nuxt/C6fXOTRV.js.gz +0 -0
- package/.output/public/_nuxt/{BqaV2jLN.js → CXbAL3Yu.js} +43 -42
- package/.output/public/_nuxt/CXbAL3Yu.js.br +0 -0
- package/.output/public/_nuxt/CXbAL3Yu.js.gz +0 -0
- package/.output/public/_nuxt/Cf1C5Vkb.js +27 -0
- package/.output/public/_nuxt/Cf1C5Vkb.js.br +0 -0
- package/.output/public/_nuxt/Cf1C5Vkb.js.gz +0 -0
- package/.output/public/_nuxt/CgUSTIM1.js +1 -0
- package/.output/public/_nuxt/CgUSTIM1.js.br +0 -0
- package/.output/public/_nuxt/CgUSTIM1.js.gz +0 -0
- package/.output/public/_nuxt/CmTpxyM2.js +62 -0
- package/.output/public/_nuxt/CmTpxyM2.js.br +0 -0
- package/.output/public/_nuxt/CmTpxyM2.js.gz +0 -0
- package/.output/public/_nuxt/DMzjoyW_.js +1 -0
- package/.output/public/_nuxt/DMzjoyW_.js.br +0 -0
- package/.output/public/_nuxt/DMzjoyW_.js.gz +0 -0
- package/.output/public/_nuxt/{B2KlcBQ-.js → DOVT2Tt8.js} +1 -1
- package/.output/public/_nuxt/DOVT2Tt8.js.br +0 -0
- package/.output/public/_nuxt/{B2KlcBQ-.js.gz → DOVT2Tt8.js.gz} +0 -0
- package/.output/public/_nuxt/PjGJWal8.js +23 -0
- package/.output/public/_nuxt/PjGJWal8.js.br +0 -0
- package/.output/public/_nuxt/PjGJWal8.js.gz +0 -0
- package/.output/public/_nuxt/WPcHpWhL.js +31 -0
- package/.output/public/_nuxt/WPcHpWhL.js.br +0 -0
- package/.output/public/_nuxt/WPcHpWhL.js.gz +0 -0
- package/.output/public/_nuxt/{board.CeTYM1XN.css → board.CpFnG_Ho.css} +1 -1
- package/.output/public/_nuxt/board.CpFnG_Ho.css.br +0 -0
- package/.output/public/_nuxt/{board.CeTYM1XN.css.gz → board.CpFnG_Ho.css.gz} +0 -0
- package/.output/public/_nuxt/builds/latest.json +1 -1
- package/.output/public/_nuxt/builds/meta/d4aab09d-c1c4-4743-b8aa-35541006e853.json +1 -0
- package/.output/public/_nuxt/entry.DosS87kQ.css +2 -0
- package/.output/public/_nuxt/entry.DosS87kQ.css.br +0 -0
- package/.output/public/_nuxt/entry.DosS87kQ.css.gz +0 -0
- package/.output/public/_nuxt/nfsDZG4P.js +123 -0
- package/.output/public/_nuxt/nfsDZG4P.js.br +0 -0
- package/.output/public/_nuxt/nfsDZG4P.js.gz +0 -0
- package/.output/public/_nuxt/qODuBH5E.js +1 -0
- package/.output/public/_nuxt/{settings.Cdb21nNw.css → settings.ycbeituV.css} +1 -1
- package/.output/public/_nuxt/settings.ycbeituV.css.br +0 -0
- package/.output/public/_nuxt/settings.ycbeituV.css.gz +0 -0
- package/.output/public/_nuxt/tYQOxjM1.js +1 -0
- package/.output/public/_nuxt/tYQOxjM1.js.br +0 -0
- package/.output/public/_nuxt/tYQOxjM1.js.gz +0 -0
- package/.output/public/sw.js +1 -1
- package/.output/server/chunks/_/branding.mjs +1 -1
- package/.output/server/chunks/_/fileDownload.mjs +1 -1
- package/.output/server/chunks/_/machineOrder.mjs +1 -1
- package/.output/server/chunks/_/onboarding.mjs +1 -1
- package/.output/server/chunks/_/package.mjs +1 -1
- package/.output/server/chunks/_/plugins.mjs +1 -1
- package/.output/server/chunks/_/restart.mjs +1 -1
- package/.output/server/chunks/_/selfupdate.mjs +1 -1
- package/.output/server/chunks/_/splitShell.mjs +42 -0
- package/.output/server/chunks/_/updates.mjs +18 -5
- package/.output/server/chunks/_/worktrees.mjs +1 -1
- package/.output/server/chunks/_/ws.mjs +1 -1
- package/.output/server/chunks/nitro/nitro.mjs +6946 -6412
- package/.output/server/chunks/raw/check-leaks.mjs +1 -1
- package/.output/server/chunks/raw/ci-browser-plan.mjs +5 -0
- package/.output/server/chunks/raw/engine-changes.mjs +5 -0
- package/.output/server/chunks/raw/engine-result.mjs +7 -0
- package/.output/server/chunks/raw/install-claude-statusline.mjs +1 -1
- package/.output/server/chunks/raw/prerelease.mjs +1 -1
- package/.output/server/chunks/raw/test-affected.mjs +1 -1
- package/.output/server/chunks/routes/api/_..._.mjs +3 -3
- package/.output/server/chunks/routes/api/agents.post.mjs +3 -3
- package/.output/server/chunks/routes/api/ask-tab.post.mjs +3 -3
- package/.output/server/chunks/routes/api/attach.post.mjs +3 -3
- package/.output/server/chunks/routes/api/auth/disable.post.mjs +3 -3
- package/.output/server/chunks/routes/api/auth/lock-all.post.mjs +3 -3
- package/.output/server/chunks/routes/api/auth/lock.post.mjs +3 -3
- package/.output/server/chunks/routes/api/auth/login/options.post.mjs +3 -3
- package/.output/server/chunks/routes/api/auth/login/verify.post.mjs +3 -3
- package/.output/server/chunks/routes/api/auth/max-session.post.mjs +3 -3
- package/.output/server/chunks/routes/api/auth/register/options.post.mjs +3 -3
- package/.output/server/chunks/routes/api/auth/register/verify.post.mjs +3 -3
- package/.output/server/chunks/routes/api/auth/status.get.mjs +3 -3
- package/.output/server/chunks/routes/api/changes.get.mjs +3 -3
- package/.output/server/chunks/routes/api/chat/image.get.mjs +3 -3
- package/.output/server/chunks/routes/api/chat.get.mjs +3 -3
- package/.output/server/chunks/routes/api/choose.post.mjs +3 -3
- package/.output/server/chunks/routes/api/claude-setup.post.mjs +3 -3
- package/.output/server/chunks/routes/api/claude-statusline.post.mjs +3 -3
- package/.output/server/chunks/routes/api/clear-queued-input.post.mjs +3 -3
- package/.output/server/chunks/routes/api/close/status.get.mjs +3 -3
- package/.output/server/chunks/routes/api/close-preview.get.mjs +62 -0
- package/.output/server/chunks/routes/api/close.post.mjs +3 -3
- package/.output/server/chunks/routes/api/codex-update.post.mjs +4 -4
- package/.output/server/chunks/routes/api/commands.get.mjs +4 -4
- package/.output/server/chunks/routes/api/config.get.mjs +4 -4
- package/.output/server/chunks/routes/api/dirs.get.mjs +4 -4
- package/.output/server/chunks/routes/api/dismiss-stopped.post.mjs +4 -4
- package/.output/server/chunks/routes/api/dismiss.post.mjs +4 -4
- package/.output/server/chunks/routes/api/effort.post.mjs +4 -4
- package/.output/server/chunks/routes/api/efforts.get.mjs +4 -4
- package/.output/server/chunks/routes/api/file.post.mjs +4 -4
- package/.output/server/chunks/routes/api/files/download.get.mjs +3 -3
- package/.output/server/chunks/routes/api/files/download.head.mjs +3 -3
- package/.output/server/chunks/routes/api/files/read.get.mjs +3 -3
- package/.output/server/chunks/routes/api/files.get.mjs +3 -3
- package/.output/server/chunks/routes/api/health.get.mjs +3 -3
- package/.output/server/chunks/routes/api/input.post.mjs +4 -4
- package/.output/server/chunks/routes/api/interrupt.post.mjs +4 -4
- package/.output/server/chunks/routes/api/isgit.get.mjs +4 -4
- package/.output/server/chunks/routes/api/machine/awake.get.mjs +3 -3
- package/.output/server/chunks/routes/api/machine/awake.post.mjs +3 -3
- package/.output/server/chunks/routes/api/machine/order.get.mjs +3 -3
- package/.output/server/chunks/routes/api/machine/order.post.mjs +3 -3
- package/.output/server/chunks/routes/api/machine/reconnect.post.mjs +4 -4
- package/.output/server/chunks/routes/api/machine/rename.post.mjs +4 -4
- package/.output/server/chunks/routes/api/machine/status.post.mjs +4 -4
- package/.output/server/chunks/routes/api/menu-left.post.mjs +4 -4
- package/.output/server/chunks/routes/api/menu.post.mjs +4 -4
- package/.output/server/chunks/routes/api/model.post.mjs +4 -4
- package/.output/server/chunks/routes/api/models.get.mjs +4 -4
- package/.output/server/chunks/routes/api/nav.post.mjs +4 -4
- package/.output/server/chunks/routes/api/onboarding.get.mjs +3 -3
- package/.output/server/chunks/routes/api/onboarding.post.mjs +3 -3
- package/.output/server/chunks/routes/api/phone.get.mjs +4 -4
- package/.output/server/chunks/routes/api/phone.post.mjs +4 -4
- package/.output/server/chunks/routes/api/plugins/actions.get.mjs +3 -3
- package/.output/server/chunks/routes/api/plugins/invoke.post.mjs +3 -3
- package/.output/server/chunks/routes/api/plugins/projects.get.mjs +4 -4
- package/.output/server/chunks/routes/api/plugins/projects.post.mjs +4 -4
- package/.output/server/chunks/routes/api/prompt.post.mjs +4 -4
- package/.output/server/chunks/routes/api/push/devices.post.mjs +49 -0
- package/.output/server/chunks/routes/api/push/quiet.post.mjs +4 -4
- package/.output/server/chunks/routes/api/push/subscribe.post.mjs +4 -4
- package/.output/server/chunks/routes/api/push/test.post.mjs +4 -4
- package/.output/server/chunks/routes/api/push/unsubscribe.post.mjs +4 -4
- package/.output/server/chunks/routes/api/quotas.get.mjs +4 -4
- package/.output/server/chunks/routes/api/rename.post.mjs +3 -3
- package/.output/server/chunks/routes/api/requeue.post.mjs +4 -4
- package/.output/server/chunks/routes/api/restart.get.mjs +3 -3
- package/.output/server/chunks/routes/api/restart.post.mjs +3 -3
- package/.output/server/chunks/routes/api/reveal.post.mjs +4 -4
- package/.output/server/chunks/routes/api/screen-key.post.mjs +4 -4
- package/.output/server/chunks/routes/api/screen.get.mjs +4 -4
- package/.output/server/chunks/routes/api/search.get.mjs +58 -5
- package/.output/server/chunks/routes/api/seen.post.mjs +4 -4
- package/.output/server/chunks/routes/api/send-now.post.mjs +53 -0
- package/.output/server/chunks/routes/api/sessions.get.mjs +4 -4
- package/.output/server/chunks/routes/api/sessions.post.mjs +4 -4
- package/.output/server/chunks/routes/api/settings-tab.post.mjs +4 -4
- package/.output/server/chunks/routes/api/settings.get.mjs +4 -4
- package/.output/server/chunks/routes/api/settings.post.mjs +4 -4
- package/.output/server/chunks/routes/api/space.post.mjs +4 -4
- package/.output/server/chunks/routes/api/split-command.post.mjs +122 -0
- package/.output/server/chunks/routes/api/state.get.mjs +4 -4
- package/.output/server/chunks/routes/api/tasks/action.post.mjs +4 -4
- package/.output/server/chunks/routes/api/tasks/add.post.mjs +4 -4
- package/.output/server/chunks/routes/api/tasks/after.post.mjs +4 -4
- package/.output/server/chunks/routes/api/tasks/approve.post.mjs +4 -4
- package/.output/server/chunks/routes/api/tasks/archive-done.post.mjs +4 -4
- package/.output/server/chunks/routes/api/tasks/archived.get.mjs +4 -4
- package/.output/server/chunks/routes/api/tasks/autopilot.get.mjs +4 -4
- package/.output/server/chunks/routes/api/tasks/autopilot.post.mjs +4 -4
- package/.output/server/chunks/routes/api/tasks/board-settings.get.mjs +4 -4
- package/.output/server/chunks/routes/api/tasks/board-settings.post.mjs +4 -4
- package/.output/server/chunks/routes/api/tasks/coordinator.get.mjs +4 -4
- package/.output/server/chunks/routes/api/tasks/coordinator.post.mjs +4 -4
- package/.output/server/chunks/routes/api/tasks/describe.post.mjs +4 -4
- package/.output/server/chunks/routes/api/tasks/details.get.mjs +4 -4
- package/.output/server/chunks/routes/api/tasks/limit.post.mjs +4 -4
- package/.output/server/chunks/routes/api/tasks/links.get.mjs +4 -4
- package/.output/server/chunks/routes/api/tasks/models.get.mjs +4 -4
- package/.output/server/chunks/routes/api/tasks/pick.post.mjs +4 -4
- package/.output/server/chunks/routes/api/tasks/project.get.mjs +4 -4
- package/.output/server/chunks/routes/api/tasks/project.post.mjs +4 -4
- package/.output/server/chunks/routes/api/tasks/question.post.mjs +4 -4
- package/.output/server/chunks/routes/api/tasks/scheduled.get.mjs +4 -4
- package/.output/server/chunks/routes/api/tasks/settings.get.mjs +4 -4
- package/.output/server/chunks/routes/api/tasks/start.get.mjs +4 -4
- package/.output/server/chunks/routes/api/tasks/tell.post.mjs +4 -4
- package/.output/server/chunks/routes/api/tasks.get.mjs +4 -4
- package/.output/server/chunks/routes/api/unqueue.post.mjs +4 -4
- package/.output/server/chunks/routes/api/update/status.get.mjs +3 -3
- package/.output/server/chunks/routes/api/update.get.mjs +3 -3
- package/.output/server/chunks/routes/api/update.post.mjs +3 -3
- package/.output/server/chunks/routes/api/upload.post.mjs +4 -4
- package/.output/server/chunks/routes/api/worktrees/remove.post.mjs +3 -3
- package/.output/server/chunks/routes/api/worktrees.get.mjs +3 -3
- package/.output/server/chunks/routes/favicon.ico.get.mjs +3 -3
- package/.output/server/chunks/routes/icons/_name_.get.mjs +4 -4
- package/.output/server/chunks/routes/renderer.mjs +5 -5
- package/.output/server/chunks/routes/uploads/_...name_.get.mjs +4 -4
- package/.output/server/chunks/routes/ws/_..._.mjs +4 -4
- package/.output/server/chunks/routes/ws/events.mjs +8 -4
- package/.output/server/chunks/routes/ws/term.mjs +4 -4
- package/.output/server/chunks/virtual/precomputed.mjs +1 -1
- package/.output/server/index.mjs +4 -4
- package/.output/server/package.json +1 -1
- package/docs/README.md +5 -0
- package/docs/RELEASING.md +27 -5
- package/docs/board.md +8 -1
- package/docs/configuration.md +3 -4
- package/docs/conversation.md +2 -3
- package/docs/design.md +112 -0
- package/docs/devices.md +33 -0
- package/docs/herdr-projects-1x.md +28 -0
- package/docs/home.md +9 -0
- package/docs/installation.md +12 -0
- package/docs/notifications.md +7 -0
- package/docs/quotas.md +13 -1
- package/docs/release-notes-2.4.0.md +37 -0
- package/docs/release-notes-2.5.0.md +25 -0
- package/docs/security.md +7 -0
- package/package.json +1 -1
- package/skills/wherdr/SKILL.md +21 -0
- package/.output/public/_nuxt/30nuHmZs.js +0 -1
- package/.output/public/_nuxt/30nuHmZs.js.br +0 -0
- package/.output/public/_nuxt/30nuHmZs.js.gz +0 -0
- package/.output/public/_nuxt/AgentView.CfD2RWZY.css +0 -1
- package/.output/public/_nuxt/AgentView.CfD2RWZY.css.br +0 -0
- package/.output/public/_nuxt/AgentView.CfD2RWZY.css.gz +0 -0
- package/.output/public/_nuxt/B2KlcBQ-.js.br +0 -0
- package/.output/public/_nuxt/BF2qZ0lx.js +0 -31
- package/.output/public/_nuxt/BF2qZ0lx.js.br +0 -0
- package/.output/public/_nuxt/BF2qZ0lx.js.gz +0 -0
- package/.output/public/_nuxt/BU6Ihnb9.js +0 -62
- package/.output/public/_nuxt/BU6Ihnb9.js.br +0 -0
- package/.output/public/_nuxt/BU6Ihnb9.js.gz +0 -0
- package/.output/public/_nuxt/BmF5BXwf.js +0 -23
- package/.output/public/_nuxt/BmF5BXwf.js.br +0 -0
- package/.output/public/_nuxt/BmF5BXwf.js.gz +0 -0
- package/.output/public/_nuxt/BqaV2jLN.js.br +0 -0
- package/.output/public/_nuxt/BqaV2jLN.js.gz +0 -0
- package/.output/public/_nuxt/C_pXkozx.js +0 -1
- package/.output/public/_nuxt/C_pXkozx.js.br +0 -0
- package/.output/public/_nuxt/C_pXkozx.js.gz +0 -0
- package/.output/public/_nuxt/Cq1IlvFx.js +0 -3
- package/.output/public/_nuxt/Cq1IlvFx.js.br +0 -0
- package/.output/public/_nuxt/Cq1IlvFx.js.gz +0 -0
- package/.output/public/_nuxt/DNk1pHah.js +0 -1
- package/.output/public/_nuxt/DNk1pHah.js.br +0 -0
- package/.output/public/_nuxt/DNk1pHah.js.gz +0 -0
- package/.output/public/_nuxt/DcQrp3bD.js +0 -25
- package/.output/public/_nuxt/DcQrp3bD.js.br +0 -0
- package/.output/public/_nuxt/DcQrp3bD.js.gz +0 -0
- package/.output/public/_nuxt/I_R_EgeO.js +0 -1
- package/.output/public/_nuxt/L_vgVKcG.js +0 -105
- package/.output/public/_nuxt/L_vgVKcG.js.br +0 -0
- package/.output/public/_nuxt/L_vgVKcG.js.gz +0 -0
- package/.output/public/_nuxt/RI4B_b2M.js +0 -9
- package/.output/public/_nuxt/RI4B_b2M.js.br +0 -0
- package/.output/public/_nuxt/RI4B_b2M.js.gz +0 -0
- package/.output/public/_nuxt/Y-4S7Nuf.js +0 -1
- package/.output/public/_nuxt/Y-4S7Nuf.js.br +0 -0
- package/.output/public/_nuxt/Y-4S7Nuf.js.gz +0 -0
- package/.output/public/_nuxt/board.CeTYM1XN.css.br +0 -0
- package/.output/public/_nuxt/builds/meta/9240e8b5-8099-4108-9ff2-34b7f376d31a.json +0 -1
- package/.output/public/_nuxt/entry._gNxiS8l.css +0 -2
- package/.output/public/_nuxt/entry._gNxiS8l.css.br +0 -0
- package/.output/public/_nuxt/entry._gNxiS8l.css.gz +0 -0
- package/.output/public/_nuxt/settings.Cdb21nNw.css.br +0 -0
- package/.output/public/_nuxt/settings.Cdb21nNw.css.gz +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// ROLLUP_NO_REPLACE
|
|
2
|
-
const checkLeaks = "#!/usr/bin/env node\n// Leak check: gitleaks + forbidden patterns read from a local, untracked file (.leak-patterns).\n// (default) scans the content of the git index (tracked or staged files)\n// --staged only scans staged files (pre-commit hook)\n// --range <revs> scans every commit of a revision range (`origin/main..HEAD`): the lines\n// each commit adds and its message, so a leak added then removed is caught\n// --no-gitleaks skips gitleaks (patterns only)\n// gitleaks runs from the `gitleaks` binary when installed, otherwise it is skipped.\n// In a linked worktree (`git worktree add`), .leak-patterns (ignored by git) often only\n// exists in the main checkout: we then fall back to that one.\n//\n// .leak-patterns format (see .leak-patterns.example):\n// # comment\n// <regex> forbidden pattern (case-insensitive)\n// <regex> !! LICENSE, docs/*.md pattern allowed in these files\n// ! <glob> file never scanned by the patterns\nimport { execFileSync, spawnSync } from 'node:child_process'\nimport { existsSync, mkdtempSync, readFileSync, rmSync } from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nexport const PATTERNS_FILE = '.leak-patterns'\nconst ALWAYS_SKIPPED = ['.leak-patterns', '.leak-patterns.example', 'package-lock.json']\n\n/** Simple glob: `*` = anything but `/`, `**` = anything, `?` = one character. */\nexport function globToRegExp(glob) {\n let re = ''\n for (let i = 0; i < glob.length; i++) {\n const c = glob[i]\n if (c === '*' && glob[i + 1] === '*') { re += '.*'; i++; if (glob[i + 1] === '/') i++ }\n else if (c === '*') re += '[^/]*'\n else if (c === '?') re += '[^/]'\n else re += c.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&')\n }\n return new RegExp(`^${re}$`)\n}\n\nconst matchesAny = (file, globs) => globs.some((g) => g.test(file))\n\n/** Parses the pattern file text. Throws a readable error on an invalid regex. */\nexport function parsePatterns(text) {\n const rules = []\n const skip = []\n text.split(/\\r?\\n/).forEach((raw, i) => {\n const line = raw.trim()\n if (!line || line.startsWith('#')) return\n if (line.startsWith('!') && !line.startsWith('!!')) {\n skip.push(globToRegExp(line.slice(1).trim()))\n return\n }\n const [source, allowed = ''] = line.split(/\\s+!!\\s+/)\n let regex\n try { regex = new RegExp(source.trim(), 'gi') }\n catch (e) { throw new Error(`${PATTERNS_FILE}:${i + 1}: invalid regex (${e.message})`) }\n const allow = allowed.split(',').map((s) => s.trim()).filter(Boolean).map(globToRegExp)\n rules.push({ source: source.trim(), regex, allow })\n })\n return { rules, skip }\n}\n\n/** Reads the pattern file; `null` if it does not exist. */\nexport function loadPatterns(file) {\n if (!existsSync(file)) return null\n return parsePatterns(readFileSync(file, 'utf8'))\n}\n\nconst git = (args, cwd) => execFileSync('git', args, { cwd, encoding: 'utf8', maxBuffer: 64 << 20 })\n\n/** Root of the main checkout when `root` is a linked worktree; `null` otherwise. */\nexport function mainCheckoutRoot(root) {\n let common\n try { common = git(['rev-parse', '--git-common-dir'], root).trim() }\n catch { return null }\n common = path.resolve(root, common)\n // Bare repository or submodule: no main checkout next to the common .git folder.\n if (path.basename(common) !== '.git') return null\n const main = path.dirname(common)\n return path.resolve(main) === path.resolve(root) ? null : main\n}\n\n/**\n * Pattern file to use: the current checkout's, otherwise the main checkout's.\n * Returns `{ file, from: 'checkout' | 'main' }`, or `{ file: null, tried }` if none exists.\n */\nexport function findPatternsFile(root) {\n const own = path.join(root, PATTERNS_FILE)\n if (existsSync(own)) return { file: own, from: 'checkout' }\n const tried = [own]\n const main = mainCheckoutRoot(root)\n if (main) {\n const shared = path.join(main, PATTERNS_FILE)\n if (existsSync(shared)) return { file: shared, from: 'main' }\n tried.push(shared)\n }\n return { file: null, tried }\n}\n\n/** Shows enough to find the value without displaying it in full. */\nexport function redact(value) {\n if (value.length <= 4) return `${value[0] ?? ''}…`\n return `${value.slice(0, Math.min(4, Math.floor(value.length / 3)))}…(${value.length} chars)`\n}\n\n/** Hits of the rules in numbered lines (`[{ n, text }]`), without the file filters. */\nfunction matchLines(lines, rules) {\n const hits = []\n for (const rule of rules) {\n for (const { n, text } of lines) {\n for (const m of text.matchAll(rule.regex)) {\n if (!m[0]) continue\n hits.push({ line: n, pattern: rule.source, excerpt: redact(m[0]) })\n }\n }\n }\n return hits\n}\n\n/** Looks for the patterns in some lines of a file, honouring ignored files and exceptions. */\nfunction scanLines(file, lines, patterns) {\n if (ALWAYS_SKIPPED.includes(path.basename(file)) || matchesAny(file, patterns.skip)) return []\n const rules = patterns.rules.filter((rule) => !matchesAny(file, rule.allow))\n return matchLines(lines, rules).map((h) => ({ file, ...h }))\n}\n\n/** Looks for the patterns in a file's content. */\nexport function scanText(file, text, patterns) {\n return scanLines(file, text.split('\\n').map((t, i) => ({ n: i + 1, text: t })), patterns)\n}\n\n/** Unquotes a path as git prints it in a diff header (`\"a\\303\\251.txt\"` when quoted). */\nfunction diffPath(raw) {\n if (!raw.startsWith('\"')) return raw\n const bytes = []\n const s = raw.slice(1, -1)\n for (let i = 0; i < s.length; i++) {\n if (s[i] !== '\\\\') { bytes.push(...Buffer.from(s[i])); continue }\n const c = s[++i]\n if (/[0-7]/.test(c)) { bytes.push(parseInt(s.slice(i, i + 3), 8)); i += 2 }\n else bytes.push(({ n: 10, t: 9, '\"': 34, '\\\\': 92 })[c] ?? c.charCodeAt(0))\n }\n return Buffer.from(bytes).toString('utf8')\n}\n\n/**\n * Lines a commit adds, per file, from `git diff-tree -p` output. Merges use the combined\n * format (`--cc`: one marker column per parent), which only keeps conflict resolutions:\n * the lines of the merged commits are scanned with those commits.\n */\nexport function addedLines(patch) {\n const files = new Map()\n let lines = null\n let parents = 1\n let next = 0\n for (const row of patch.split('\\n')) {\n if (row.startsWith('diff ')) { lines = null; continue }\n if (row.startsWith('+++ ')) {\n const target = row.slice(4)\n if (target === '/dev/null') { lines = null; continue }\n const file = diffPath(target).replace(/^b\\//, '')\n lines = files.get(file) ?? []\n files.set(file, lines)\n continue\n }\n const hunk = /^(@@+) .*?\\+(\\d+)/.exec(row)\n if (hunk) { parents = hunk[1].length - 1; next = Number(hunk[2]); continue }\n if (!lines || !next) continue\n const marks = row.slice(0, parents)\n if (marks.includes('-')) continue\n if (marks.includes('+')) lines.push({ n: next, text: row.slice(parents) })\n next++\n }\n return files\n}\n\n/**\n * Scans each commit of `range` (as `git rev-list` reads it): the lines it adds, with the file\n * rules, and its message, with every rule. Hits carry the short commit and `file: null` for\n * the message.\n */\nexport function scanRange(root, range, patterns) {\n const commits = git(['rev-list', '--reverse', range], root).split('\\n').filter(Boolean)\n const hits = []\n for (const sha of commits) {\n const commit = sha.slice(0, 9)\n const message = git(['log', '-1', '--format=%B', sha], root)\n const msgLines = message.split('\\n').map((t, i) => ({ n: i + 1, text: t }))\n hits.push(...matchLines(msgLines, patterns.rules).map((h) => ({ commit, file: null, ...h })))\n const patch = git(['diff-tree', '-p', '--cc', '--root', '-r', '--no-color', '--no-ext-diff', '--no-textconv', '-U0', sha], root)\n for (const [file, lines] of addedLines(patch)) {\n hits.push(...scanLines(file, lines, patterns).map((h) => ({ commit, ...h })))\n }\n }\n return { commits: commits.length, hits }\n}\n\n/** Copies the index content (all files or only staged ones) into a temporary folder. */\nfunction exportIndex(root, staged) {\n const list = staged\n ? git(['diff', '--cached', '--name-only', '--diff-filter=ACMR', '-z'], root)\n : git(['ls-files', '-z'], root)\n const files = list.split('\\0').filter(Boolean)\n const dir = mkdtempSync(path.join(tmpdir(), 'leaks-'))\n if (files.length) {\n execFileSync('git', ['checkout-index', '-z', '--stdin', `--prefix=${dir}/`], { cwd: root, input: files.join('\\0') })\n }\n return { dir, files }\n}\n\n/** Whether the `gitleaks` binary is installed. */\nconst hasGitleaks = () => !spawnSync('gitleaks', ['version'], { encoding: 'utf8' }).error\n\n/** Runs gitleaks on a folder (`dir` mode) or on a commit range (`git` mode). */\nfunction runGitleaks({ dir, root, range }) {\n // --verbose lists each finding (commit, file, line, rule); --redact hides the secret itself.\n const opts = ['--redact', '--verbose', '--no-banner', '--exit-code', '1']\n const args = range ? ['git', root, `--log-opts=${range}`, ...opts] : ['dir', dir, ...opts]\n if (!hasGitleaks()) {\n console.log('gitleaks: not installed, skipped (https://github.com/gitleaks/gitleaks). Forbidden patterns still run.')\n return true\n }\n const r = spawnSync('gitleaks', args, { stdio: 'inherit' })\n if (r.status === 0) console.log('gitleaks: no secret found.')\n else if (r.status !== 1) console.error(`gitleaks: failed to run (exit ${r.status ?? r.signal}).`)\n return r.status === 0\n}\n\n/** Loads the pattern file and says which one is used; `null` (with a warning) if none. */\nfunction patternsFor(root) {\n const found = findPatternsFile(root)\n const patterns = found.file && loadPatterns(found.file)\n if (!patterns) {\n console.warn([\n `WARNING: no ${PATTERNS_FILE} file found, forbidden patterns were NOT checked.`,\n ...found.tried.map((f) => ` looked for: ${f}`),\n ` Copy ${PATTERNS_FILE}.example to ${PATTERNS_FILE} in the main checkout and fill it.`,\n ].join('\\n'))\n return null\n }\n console.log(`patterns: using ${found.file}${found.from === 'main' ? ' (main checkout)' : ''}`)\n if (!patterns.rules.length) console.warn(`WARNING: ${found.file} has no active pattern, nothing is forbidden.`)\n return patterns\n}\n\nfunction mainRange(root, range, gitleaks) {\n let ok = gitleaks ? runGitleaks({ root, range }) : true\n const patterns = patternsFor(root)\n if (!patterns) return ok ? 0 : 1\n const { commits, hits } = scanRange(root, range, patterns)\n for (const h of hits) {\n console.log(h.file === null\n ? `${h.commit} message:${h.line} ${h.excerpt} [${h.pattern}]`\n : `${h.commit} ${h.file}:${h.line} ${h.excerpt} [${h.pattern}]`)\n }\n console.log(hits.length\n ? `patterns: ${hits.length} forbidden match(es) in ${commits} commit(s) of ${range}.`\n : `patterns: ${patterns.rules.length} pattern(s), ${commits} commit(s) of ${range}, no match.`)\n if (hits.length) ok = false\n return ok ? 0 : 1\n}\n\nfunction main(argv) {\n const staged = argv.includes('--staged')\n const gitleaks = !argv.includes('--no-gitleaks')\n const root = git(['rev-parse', '--show-toplevel']).trim()\n const r = argv.indexOf('--range')\n if (r !== -1) {\n const range = argv[r + 1]\n if (!range || range.startsWith('--')) throw new Error('--range needs a revision range, e.g. origin/main..HEAD')\n return mainRange(root, range, gitleaks)\n }\n const { dir, files } = exportIndex(root, staged)\n try {\n if (!files.length) { console.log('check:leaks: nothing to scan.'); return 0 }\n let ok = gitleaks ? runGitleaks({ dir }) : true\n const patterns = patternsFor(root)\n if (patterns) {\n const hits = []\n for (const file of files) {\n const buf = readFileSync(path.join(dir, file))\n if (buf.includes(0)) continue // binaire\n hits.push(...scanText(file, buf.toString('utf8'), patterns))\n }\n for (const h of hits) console.log(`${h.file}:${h.line} ${h.excerpt} [${h.pattern}]`)\n console.log(hits.length\n ? `patterns: ${hits.length} forbidden match(es) in ${files.length} file(s).`\n : `patterns: ${patterns.rules.length} pattern(s), ${files.length} file(s), no match.`)\n if (hits.length) ok = false\n }\n return ok ? 0 : 1\n }\n finally {\n rmSync(dir, { recursive: true, force: true })\n }\n}\n\nif (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {\n try { process.exit(main(process.argv.slice(2))) }\n catch (e) { console.error(`check:leaks: ${e.message}`); process.exit(2) }\n}\n";
|
|
2
|
+
const checkLeaks = "#!/usr/bin/env node\n// Leak check: gitleaks + forbidden patterns read from a local, untracked file (.leak-patterns).\n// (default) scans the content of the git index (tracked or staged files)\n// --staged only scans staged files (pre-commit hook)\n// --range <revs> scans every commit of a revision range (`origin/main..HEAD`): the lines\n// each commit adds and its message, so a leak added then removed is caught\n// --no-gitleaks skips gitleaks (patterns only)\n// gitleaks runs from the `gitleaks` binary when installed, otherwise it is skipped.\n// In a linked worktree (`git worktree add`), .leak-patterns (ignored by git) often only\n// exists in the main checkout: we then fall back to that one.\n//\n// .leak-patterns format (see .leak-patterns.example):\n// # comment\n// <regex> forbidden pattern (case-insensitive)\n// <regex> !! LICENSE, docs/*.md pattern allowed in these files\n// ! <glob> file never scanned by the patterns\nimport { execFileSync, spawnSync } from 'node:child_process'\nimport { existsSync, mkdtempSync, readFileSync, rmSync } from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nexport const PATTERNS_FILE = '.leak-patterns'\nconst ALWAYS_SKIPPED = ['.leak-patterns', '.leak-patterns.example', 'package-lock.json']\n\n/** Simple glob: `*` = anything but `/`, `**` = anything, `?` = one character. */\nexport function globToRegExp(glob) {\n let re = ''\n for (let i = 0; i < glob.length; i++) {\n const c = glob[i]\n if (c === '*' && glob[i + 1] === '*') { re += '.*'; i++; if (glob[i + 1] === '/') i++ }\n else if (c === '*') re += '[^/]*'\n else if (c === '?') re += '[^/]'\n else re += c.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&')\n }\n return new RegExp(`^${re}$`)\n}\n\nconst matchesAny = (file, globs) => globs.some((g) => g.test(file))\n\n/** Parses the pattern file text. Throws a readable error on an invalid regex. */\nexport function parsePatterns(text) {\n const rules = []\n const skip = []\n text.split(/\\r?\\n/).forEach((raw, i) => {\n const line = raw.trim()\n if (!line || line.startsWith('#')) return\n if (line.startsWith('!') && !line.startsWith('!!')) {\n skip.push(globToRegExp(line.slice(1).trim()))\n return\n }\n const [source, allowed = ''] = line.split(/\\s+!!\\s+/)\n let regex\n try { regex = new RegExp(source.trim(), 'gi') }\n catch (e) { throw new Error(`${PATTERNS_FILE}:${i + 1}: invalid regex (${e.message})`) }\n const allow = allowed.split(',').map((s) => s.trim()).filter(Boolean).map(globToRegExp)\n rules.push({ source: source.trim(), regex, allow })\n })\n return { rules, skip }\n}\n\n/** Reads the pattern file; `null` if it does not exist. */\nexport function loadPatterns(file) {\n if (!existsSync(file)) return null\n return parsePatterns(readFileSync(file, 'utf8'))\n}\n\nconst git = (args, cwd) => execFileSync('git', args, { cwd, encoding: 'utf8', maxBuffer: 64 << 20 })\n\n/** Root of the main checkout when `root` is a linked worktree; `null` otherwise. */\nexport function mainCheckoutRoot(root) {\n let common\n try { common = git(['rev-parse', '--git-common-dir'], root).trim() }\n catch { return null }\n common = path.resolve(root, common)\n // Bare repository or submodule: no main checkout next to the common .git folder.\n if (path.basename(common) !== '.git') return null\n const main = path.dirname(common)\n return path.resolve(main) === path.resolve(root) ? null : main\n}\n\n/**\n * Pattern file to use: the current checkout's, otherwise the main checkout's.\n * Returns `{ file, from: 'checkout' | 'main' }`, or `{ file: null, tried }` if none exists.\n */\nexport function findPatternsFile(root) {\n const own = path.join(root, PATTERNS_FILE)\n if (existsSync(own)) return { file: own, from: 'checkout' }\n const tried = [own]\n const main = mainCheckoutRoot(root)\n if (main) {\n const shared = path.join(main, PATTERNS_FILE)\n if (existsSync(shared)) return { file: shared, from: 'main' }\n tried.push(shared)\n }\n return { file: null, tried }\n}\n\n/** Shows enough to find the value without displaying it in full. */\nexport function redact(value) {\n if (value.length <= 4) return `${value[0] ?? ''}…`\n return `${value.slice(0, Math.min(4, Math.floor(value.length / 3)))}…(${value.length} chars)`\n}\n\n/** Hits of the rules in numbered lines (`[{ n, text }]`), without the file filters. */\nfunction matchLines(lines, rules) {\n const hits = []\n for (const rule of rules) {\n for (const { n, text } of lines) {\n for (const m of text.matchAll(rule.regex)) {\n if (!m[0]) continue\n hits.push({ line: n, pattern: rule.source, excerpt: redact(m[0]) })\n }\n }\n }\n return hits\n}\n\n/** Looks for the patterns in some lines of a file, honouring ignored files and exceptions. */\nfunction scanLines(file, lines, patterns) {\n if (ALWAYS_SKIPPED.includes(path.basename(file)) || matchesAny(file, patterns.skip)) return []\n const rules = patterns.rules.filter((rule) => !matchesAny(file, rule.allow))\n return matchLines(lines, rules).map((h) => ({ file, ...h }))\n}\n\n/** Looks for the patterns in a file's content. */\nexport function scanText(file, text, patterns) {\n return scanLines(file, text.split('\\n').map((t, i) => ({ n: i + 1, text: t })), patterns)\n}\n\n/** Unquotes a path as git prints it in a diff header (`\"a\\303\\251.txt\"` when quoted). */\nfunction diffPath(raw) {\n if (!raw.startsWith('\"')) return raw\n const bytes = []\n const s = raw.slice(1, -1)\n for (let i = 0; i < s.length; i++) {\n if (s[i] !== '\\\\') { bytes.push(...Buffer.from(s[i])); continue }\n const c = s[++i]\n if (/[0-7]/.test(c)) { bytes.push(parseInt(s.slice(i, i + 3), 8)); i += 2 }\n else bytes.push(({ n: 10, t: 9, '\"': 34, '\\\\': 92 })[c] ?? c.charCodeAt(0))\n }\n return Buffer.from(bytes).toString('utf8')\n}\n\n/**\n * Lines a commit adds, per file, from `git diff-tree -p` output. Merges use the combined\n * format (`--cc`: one marker column per parent), which only keeps conflict resolutions:\n * the lines of the merged commits are scanned with those commits.\n */\nexport function addedLines(patch) {\n const files = new Map()\n let lines = null\n let parents = 1\n let next = 0\n for (const row of patch.split('\\n')) {\n if (row.startsWith('diff ')) { lines = null; continue }\n if (row.startsWith('+++ ')) {\n const target = row.slice(4)\n if (target === '/dev/null') { lines = null; continue }\n const file = diffPath(target).replace(/^b\\//, '')\n lines = files.get(file) ?? []\n files.set(file, lines)\n continue\n }\n const hunk = /^(@@+) .*?\\+(\\d+)/.exec(row)\n if (hunk) { parents = hunk[1].length - 1; next = Number(hunk[2]); continue }\n if (!lines || !next) continue\n const marks = row.slice(0, parents)\n if (marks.includes('-')) continue\n if (marks.includes('+')) lines.push({ n: next, text: row.slice(parents) })\n next++\n }\n return files\n}\n\n/**\n * Scans each commit of `range` (as `git rev-list` reads it): the lines it adds, with the file\n * rules, and its message, with every rule. Hits carry the short commit and `file: null` for\n * the message.\n */\nexport function scanRange(root, range, patterns) {\n const commits = git(['rev-list', '--reverse', range], root).split('\\n').filter(Boolean)\n const hits = []\n for (const sha of commits) {\n const commit = sha.slice(0, 9)\n const message = git(['log', '-1', '--format=%B', sha], root)\n const msgLines = message.split('\\n').map((t, i) => ({ n: i + 1, text: t }))\n hits.push(...matchLines(msgLines, patterns.rules).map((h) => ({ commit, file: null, ...h })))\n const patch = git(['diff-tree', '-p', '--cc', '--root', '-r', '--no-color', '--no-ext-diff', '--no-textconv', '-U0', sha], root)\n for (const [file, lines] of addedLines(patch)) {\n hits.push(...scanLines(file, lines, patterns).map((h) => ({ commit, ...h })))\n }\n }\n return { commits: commits.length, hits }\n}\n\n/** Copies the index content (all files or only staged ones) into a temporary folder. */\nfunction exportIndex(root, staged) {\n const list = staged\n ? git(['diff', '--cached', '--name-only', '--diff-filter=ACMR', '-z'], root)\n : git(['ls-files', '-z'], root)\n const files = list.split('\\0').filter(Boolean)\n const dir = mkdtempSync(path.join(tmpdir(), 'leaks-'))\n if (files.length) {\n execFileSync('git', ['checkout-index', '-z', '--stdin', `--prefix=${dir}/`], { cwd: root, input: files.join('\\0') })\n }\n return { dir, files }\n}\n\n/** Whether the `gitleaks` binary is installed. */\nconst hasGitleaks = () => !spawnSync('gitleaks', ['version'], { encoding: 'utf8' }).error\n\n/** Runs gitleaks on a folder (`dir` mode) or on a commit range (`git` mode). */\nfunction runGitleaks({ dir, root, range }) {\n // --verbose lists each finding (commit, file, line, rule); --redact hides the secret itself.\n const opts = ['--redact', '--verbose', '--no-banner', '--exit-code', '1']\n // Index scans run on a temporary export, outside the repository config discovery.\n const config = path.join(root ?? git(['rev-parse', '--show-toplevel']).trim(), '.gitleaks.toml')\n if (existsSync(config)) opts.push('--config', config)\n const args = range ? ['git', root, `--log-opts=${range}`, ...opts] : ['dir', dir, ...opts]\n if (!hasGitleaks()) {\n console.log('gitleaks: not installed, skipped (https://github.com/gitleaks/gitleaks). Forbidden patterns still run.')\n return true\n }\n const r = spawnSync('gitleaks', args, { stdio: 'inherit' })\n if (r.status === 0) console.log('gitleaks: no secret found.')\n else if (r.status !== 1) console.error(`gitleaks: failed to run (exit ${r.status ?? r.signal}).`)\n return r.status === 0\n}\n\n/** Loads the pattern file and says which one is used; `null` (with a warning) if none. */\nfunction patternsFor(root) {\n const found = findPatternsFile(root)\n const patterns = found.file && loadPatterns(found.file)\n if (!patterns) {\n console.warn([\n `WARNING: no ${PATTERNS_FILE} file found, forbidden patterns were NOT checked.`,\n ...found.tried.map((f) => ` looked for: ${f}`),\n ` Copy ${PATTERNS_FILE}.example to ${PATTERNS_FILE} in the main checkout and fill it.`,\n ].join('\\n'))\n return null\n }\n console.log(`patterns: using ${found.file}${found.from === 'main' ? ' (main checkout)' : ''}`)\n if (!patterns.rules.length) console.warn(`WARNING: ${found.file} has no active pattern, nothing is forbidden.`)\n return patterns\n}\n\nfunction mainRange(root, range, gitleaks) {\n let ok = gitleaks ? runGitleaks({ root, range }) : true\n const patterns = patternsFor(root)\n if (!patterns) return ok ? 0 : 1\n const { commits, hits } = scanRange(root, range, patterns)\n for (const h of hits) {\n console.log(h.file === null\n ? `${h.commit} message:${h.line} ${h.excerpt} [${h.pattern}]`\n : `${h.commit} ${h.file}:${h.line} ${h.excerpt} [${h.pattern}]`)\n }\n console.log(hits.length\n ? `patterns: ${hits.length} forbidden match(es) in ${commits} commit(s) of ${range}.`\n : `patterns: ${patterns.rules.length} pattern(s), ${commits} commit(s) of ${range}, no match.`)\n if (hits.length) ok = false\n return ok ? 0 : 1\n}\n\nfunction main(argv) {\n const staged = argv.includes('--staged')\n const gitleaks = !argv.includes('--no-gitleaks')\n const root = git(['rev-parse', '--show-toplevel']).trim()\n const r = argv.indexOf('--range')\n if (r !== -1) {\n const range = argv[r + 1]\n if (!range || range.startsWith('--')) throw new Error('--range needs a revision range, e.g. origin/main..HEAD')\n return mainRange(root, range, gitleaks)\n }\n const { dir, files } = exportIndex(root, staged)\n try {\n if (!files.length) { console.log('check:leaks: nothing to scan.'); return 0 }\n let ok = gitleaks ? runGitleaks({ dir }) : true\n const patterns = patternsFor(root)\n if (patterns) {\n const hits = []\n for (const file of files) {\n const buf = readFileSync(path.join(dir, file))\n if (buf.includes(0)) continue // binaire\n hits.push(...scanText(file, buf.toString('utf8'), patterns))\n }\n for (const h of hits) console.log(`${h.file}:${h.line} ${h.excerpt} [${h.pattern}]`)\n console.log(hits.length\n ? `patterns: ${hits.length} forbidden match(es) in ${files.length} file(s).`\n : `patterns: ${patterns.rules.length} pattern(s), ${files.length} file(s), no match.`)\n if (hits.length) ok = false\n }\n return ok ? 0 : 1\n }\n finally {\n rmSync(dir, { recursive: true, force: true })\n }\n}\n\nif (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {\n try { process.exit(main(process.argv.slice(2))) }\n catch (e) { console.error(`check:leaks: ${e.message}`); process.exit(2) }\n}\n";
|
|
3
3
|
|
|
4
4
|
export { checkLeaks as default };
|
|
5
5
|
//# sourceMappingURL=check-leaks.mjs.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// ROLLUP_NO_REPLACE
|
|
2
|
+
const ciBrowserPlan = "#!/usr/bin/env node\nimport { pathToFileURL } from 'node:url'\n\nexport function browserPlan(event, ref) {\n const scope = event === 'schedule' || event === 'workflow_dispatch' || ref.startsWith('refs/tags/') ? 'full' : 'light'\n const include = []\n // Recent light PR runs: Chromium phone 211–284 s/shard with four shards,\n // WebKit phone 199–239 s unsharded, before npm/build/browser preparation.\n for (const [project, count] of [['chromium-phone', 6], ['webkit-phone', 2]]) {\n for (let n = 1; n <= count; n++) include.push({ project, shard: `${n}/${count}` })\n }\n include.push({ project: 'chromium-desktop' }, { project: 'webkit-desktop' })\n return { scope, matrix: { include } }\n}\n\nif (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {\n const plan = browserPlan(process.env.EVENT, process.env.REF)\n for (const [key, value] of Object.entries(plan)) console.log(`${key}=${typeof value === 'string' ? value : JSON.stringify(value)}`)\n}\n";
|
|
3
|
+
|
|
4
|
+
export { ciBrowserPlan as default };
|
|
5
|
+
//# sourceMappingURL=ci-browser-plan.mjs.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// ROLLUP_NO_REPLACE
|
|
2
|
+
const engineChanges = "#!/usr/bin/env node\nimport { spawnSync } from 'node:child_process'\nimport { appendFileSync } from 'node:fs'\nimport { pathToFileURL } from 'node:url'\n\n// Keep engine inputs here, alongside the filter regression tests. Release assembly\n// is added by later distribution work; these paths already require engine checks.\nexport function needsEngine(paths) {\n return paths.some(p => /^(engine|packages|skills\\/wherdr-board|tests\\/recordings\\/wherdr-board)\\//.test(p)\n || /^(package(?:-lock)?\\.json|herdr-plugin\\.toml)$/.test(p)\n || /^(bin|scripts)\\/.*(?:board|runtime|userpath|pack|updat|version|release|engine)/.test(p)\n || /^shared\\/projectsPlugin\\.ts$|^server\\/utils\\/(?:projects(?:Tasks|Plugin)|boardLinks)\\.ts$/.test(p)\n || /^tests\\/.*(?:[Bb]oard|[Pp]rojects|[Pp]lugin|[Mm]igration|[Cc]ohabitation|[Dd]istribution|engine)/.test(p)\n || /^\\.github\\/workflows\\/(?:ci|engine-.*|release.*|develop-prerelease|npm)\\.yml$/.test(p))\n}\n\nexport function engineDecision(event, before, cwd = process.cwd()) {\n if (!['pull_request', 'push'].includes(event)) return true\n const base = event === 'pull_request' ? 'HEAD^1' : before\n if (!base || /^0+$/.test(base)) return true\n // No rename detection: a move is a deletion plus addition, including both\n // sides of moves across engine/. NUL separation preserves unusual filenames.\n const diff = spawnSync('git', ['diff', '--no-renames', '--name-only', '-z', base, 'HEAD', '--'], { cwd, encoding: 'utf8' })\n if (diff.status !== 0) return true\n return needsEngine(diff.stdout.split('\\0').filter(Boolean))\n}\n\nif (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {\n const needed = engineDecision(process.env.EVENT, process.env.BEFORE)\n console.log(`Engine checks needed: ${needed}`)\n appendFileSync(process.env.GITHUB_OUTPUT, `engine=${needed}\\n`)\n}\n";
|
|
3
|
+
|
|
4
|
+
export { engineChanges as default };
|
|
5
|
+
//# sourceMappingURL=engine-changes.mjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { b as base64ToUint8Array } from '../virtual/_raw-helpers.mjs';
|
|
2
|
+
|
|
3
|
+
// ROLLUP_NO_REPLACE
|
|
4
|
+
const engineResult = base64ToUint8Array("IyEvYmluL3NoCnNldCAtZXUKWyAiJENIQU5HRVMiID0gc3VjY2VzcyBdIHx8IGV4aXQgMQpjYXNlICIkTkVFREVEOiRFTkdJTkUiIGluCiAgZmFsc2U6c2tpcHBlZCkgZWNobyAiTm8gZW5naW5lIGlucHV0IGNoYW5nZWQuIiA7OwogIHRydWU6c3VjY2VzcykgZWNobyAiRXZlcnkgZW5naW5lIGNoZWNrIHBhc3NlZC4iIDs7CiAgKikgZWNobyAiRW5naW5lIGNoZWNrcyBkaWQgbm90IHBhc3M6IG5lZWRlZD0kTkVFREVELCByZXN1bHQ9JEVOR0lORSI7IGV4aXQgMSA7Owplc2FjCg==");
|
|
5
|
+
|
|
6
|
+
export { engineResult as default };
|
|
7
|
+
//# sourceMappingURL=engine-result.mjs.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { b as base64ToUint8Array } from '../virtual/_raw-helpers.mjs';
|
|
2
2
|
|
|
3
3
|
// ROLLUP_NO_REPLACE
|
|
4
|
-
const installClaudeStatusline = base64ToUint8Array("IyEvYmluL3NoCiMgd2hlcmRyOiBpbnN0YWxscyBDbGF1ZGUgQ29kZSdzIGludmlzaWJsZSBzdGF0dXMgbGluZSAocXVvdGFzICsgYWNjb3VudAojIGZpbmdlcnByaW50KSBmb3IgdGhlIGN1cnJlbnQgdXNlci4gU2VsZi1jb250YWluZWQgKHRoZSBzdGF0dXMgbGluZSBpcyBpbmNsdWRlZAojIGJlbG93KTogd2hlcmRyIHJ1bnMgaXQgYXMgaXMgb24gYSBtYWNoaW5lICgiSW5zdGFsbCIgYnV0dG9uKSBvcgojIGhhbmRzIGl0IG91dCB0byBwYXN0ZSAoIkNvcHkgY29tbWFuZCIpLiBTYWZlIHRvIHJ1biBhZ2FpbjoKIyAgLSB3cml0ZXMgdGhlIHN0YXR1cyBsaW5lIHRvIH4vLmNsYXVkZS93aGVyZHItc3RhdHVzbGluZS5zaCAodXBkYXRlKTsKIyAgLSBubyBgc3RhdHVzTGluZWAgaW4gfi8uY2xhdWRlL3NldHRpbmdzLmpzb246IGFkZHMgb3VyczsKIyAgLSBhbm90aGVyIGBzdGF0dXNMaW5lYCAoY29tbWFuZCk6IGNoYWlucyBpdCBiZWhpbmQgb3VycywgaXRzCiMgICAgb3V0cHV0IHN0YXlzIHRoZSBzYW1lOyBiYWNrdXAgY29weSBzZXR0aW5ncy5qc29uLmJhay13aGVyZHIuCiMgUXVvdGFzIHNob3cgdXAgYWZ0ZXIgdGhlIG5leHQgZXhjaGFuZ2Ugd2l0aCBhIENsYXVkZS4Kc2V0IC1lCmRpcj0iJHtDTEFVREVfQ09ORklHX0RJUjotJEhPTUUvLmNsYXVkZX0iCm1rZGlyIC1wICIkZGlyIgojIC0tLS0gc3RhdHVzIGxpbmUgKHByaW50cyBub3RoaW5nKSAtLS0tCmNhdCA+
|
|
4
|
+
const installClaudeStatusline = base64ToUint8Array("IyEvYmluL3NoCiMgd2hlcmRyOiBpbnN0YWxscyBDbGF1ZGUgQ29kZSdzIGludmlzaWJsZSBzdGF0dXMgbGluZSAocXVvdGFzICsgYWNjb3VudAojIGZpbmdlcnByaW50KSBmb3IgdGhlIGN1cnJlbnQgdXNlci4gU2VsZi1jb250YWluZWQgKHRoZSBzdGF0dXMgbGluZSBpcyBpbmNsdWRlZAojIGJlbG93KTogd2hlcmRyIHJ1bnMgaXQgYXMgaXMgb24gYSBtYWNoaW5lICgiSW5zdGFsbCIgYnV0dG9uKSBvcgojIGhhbmRzIGl0IG91dCB0byBwYXN0ZSAoIkNvcHkgY29tbWFuZCIpLiBTYWZlIHRvIHJ1biBhZ2FpbjoKIyAgLSB3cml0ZXMgdGhlIHN0YXR1cyBsaW5lIHRvIH4vLmNsYXVkZS93aGVyZHItc3RhdHVzbGluZS5zaCAodXBkYXRlKTsKIyAgLSBubyBgc3RhdHVzTGluZWAgaW4gfi8uY2xhdWRlL3NldHRpbmdzLmpzb246IGFkZHMgb3VyczsKIyAgLSBhbm90aGVyIGBzdGF0dXNMaW5lYCAoY29tbWFuZCk6IGNoYWlucyBpdCBiZWhpbmQgb3VycywgaXRzCiMgICAgb3V0cHV0IHN0YXlzIHRoZSBzYW1lOyBiYWNrdXAgY29weSBzZXR0aW5ncy5qc29uLmJhay13aGVyZHIuCiMgUXVvdGFzIHNob3cgdXAgYWZ0ZXIgdGhlIG5leHQgZXhjaGFuZ2Ugd2l0aCBhIENsYXVkZS4Kc2V0IC1lCmRpcj0iJHtDTEFVREVfQ09ORklHX0RJUjotJEhPTUUvLmNsYXVkZX0iCm1rZGlyIC1wICIkZGlyIgojIC0tLS0gc3RhdHVzIGxpbmUgKHByaW50cyBub3RoaW5nKSAtLS0tCmNhdCA+ICIkZGlyL3doZXJkci1zdGF0dXNsaW5lLnNoLnRtcCIgPDwnV0hFUkRSX1NUQVRVU0xJTkUnCiMhL2Jpbi9zaAojIHdoZXJkcjogQ2xhdWRlIENvZGUncyBpbnZpc2libGUgc3RhdHVzIGxpbmUgKHByaW50cyBub3RoaW5nKS4gSXQgb25seSBrZWVwcwojIHRoZSBhY2NvdW50IHF1b3RhcyAocmF0ZV9saW1pdHMsIHdoaWNoIENsYXVkZSBDb2RlIHBhc3NlcyB0byBpdHMKIyBzdGF0dXMgbGluZSBhZnRlciBlYWNoIGV4Y2hhbmdlKSBmb3IgdGhlIHdoZXJkciBob21lIHNjcmVlbiwgYW5kIGFuIGFjY291bnQKIyBmaW5nZXJwcmludCAodHJ1bmNhdGVkIGhhc2ggb2YgaXRzIElELCBuZXZlciB0aGUgSUQgb3IgdGhlIGVtYWlsKQojIHRvIHRlbGwgYXBhcnQgbWFjaGluZXMgdGhhdCBkbyBub3QgdXNlIHRoZSBzYW1lIGFjY291bnQuIE9uIEFQSSBiaWxsaW5nCiMgKEFQSSBrZXksIENvbnNvbGUgY3JlZGl0cykgQ2xhdWRlIENvZGUgcGFzc2VzIG5vIHJhdGVfbGltaXRzOiBvbmNlIHRoZSBzZXNzaW9uCiMgaGFzIGhhZCBhbiBBUEkgcmVzcG9uc2UgKGNvc3QudG90YWxfYXBpX2R1cmF0aW9uX21zID4gMCksIHRoZSBzbmFwc2hvdCBpcyBrZXB0CiMgd2l0aG91dCB0aGVtLCBhbmQgd2hlcmRyIHJlYWRzICJBUEkgdXNhZ2UsIG5vIHF1b3RhIiBmb3IgdGhlIG1hY2hpbmUuCiMgSW5zdGFsbGVkIGJ5IGluc3RhbGwtY2xhdWRlLXN0YXR1c2xpbmUuc2ggKHdoZXJkciByZXBvc2l0b3J5LCBSRUFETUUsICJRdW90YXMKIyBvbiB0aGUgaG9tZSBzY3JlZW4iKS4gRXhpc3Rpbmcgc3RhdHVzIGxpbmU6IHBhc3NlZCBhcyBhbiBhcmd1bWVudCwgaXQgcmVjZWl2ZXMgdGhlCiMgc2FtZSBkYXRhIGFuZCBpdHMgb3V0cHV0IGlzIGtlcHQgKHNoIHdoZXJkci1zdGF0dXNsaW5lLnNoICdjbWQnKS4KZD0kKGNhdCkKY2FzZSAiJGQiIGluCiAgKicicmF0ZV9saW1pdHMiJyp8KicidG90YWxfYXBpX2R1cmF0aW9uX21zIicqKQogICAgZGlyPSIkSE9NRS8uY2FjaGUvaGVyZHItd2ViIgogICAgbWtkaXIgLXAgIiRkaXIiCiAgICAjIEJpbmQgdGhlIGZpbmdlcnByaW50IGFuZCB0aW1lc3RhbXAgdG8gdGhlIHBheWxvYWQgaW4gb25lIGF0b21pYyByZW5hbWUuCiAgICAjIE5vIGZpbmdlcnByaW50IFRUTDogYSBsb2dpbiBjaGFuZ2UgbXVzdCBhZmZlY3QgdGhlIHZlcnkgbmV4dCByZWFkaW5nLgogICAgcHJpbnRmICclcycgIiRkIiB8IHB5dGhvbjMgLWMgJwppbXBvcnQgaGFzaGxpYiwganNvbiwgb3MsIHN5cywgdGVtcGZpbGUsIHRpbWUKZnJvbSBwYXRobGliIGltcG9ydCBQYXRoCmNhY2hlID0gUGF0aChzeXMuYXJndlsxXSkKY29uZmlnID0gUGF0aChvcy5lbnZpcm9uLmdldCgiQ0xBVURFX0NPTkZJR19ESVIiLCBvcy5lbnZpcm9uWyJIT01FIl0pKSAvICIuY2xhdWRlLmpzb24iCnRyeToKICAgIGFjY291bnRfaWQgPSBqc29uLmxvYWRzKGNvbmZpZy5yZWFkX3RleHQoKSkuZ2V0KCJvYXV0aEFjY291bnQiLCB7fSkuZ2V0KCJhY2NvdW50VXVpZCIpCmV4Y2VwdCAoT1NFcnJvciwgVmFsdWVFcnJvciwgQXR0cmlidXRlRXJyb3IpOgogICAgYWNjb3VudF9pZCA9IE5vbmUKYWNjb3VudCA9IGhhc2hsaWIuc2hhMjU2KCgid2hlcmRyOiIgKyBhY2NvdW50X2lkKS5lbmNvZGUoKSkuaGV4ZGlnZXN0KClbOjE2XSBpZiBpc2luc3RhbmNlKGFjY291bnRfaWQsIHN0cikgYW5kIGFjY291bnRfaWQgZWxzZSBOb25lCnN0YXR1cyA9IGpzb24ubG9hZChzeXMuc3RkaW4pCmlmIG5vdCBpc2luc3RhbmNlKHN0YXR1cywgZGljdCk6CiAgICBzeXMuZXhpdCgwKQppZiAicmF0ZV9saW1pdHMiIG5vdCBpbiBzdGF0dXM6CiAgICAjIFN1YnNjcmliZXJzIGdldCByYXRlX2xpbWl0cyBvbmx5IGFmdGVyIHRoZSBmaXJzdCBBUEkgcmVzcG9uc2Ugb2YgYSBzZXNzaW9uOgogICAgIyB3aXRob3V0IG9uZSB5ZXQsIG5vdGhpbmcgaXMga25vd24uIEEgc2Vzc2lvbiB0aGF0IGFscmVhZHkgZ2F2ZSByYXRlIGxpbWl0cwogICAgIyBzdGF5cyBhIHN1YnNjcmlwdGlvbiAoYSB3aW5kb3cgbWF5IGRyb3Agb3V0IG9uY2UgaXQgcmVzZXRzKS4KICAgIGFwaV9tcyA9IChzdGF0dXMuZ2V0KCJjb3N0Iikgb3Ige30pLmdldCgidG90YWxfYXBpX2R1cmF0aW9uX21zIikKICAgIGlmIG5vdCBpc2luc3RhbmNlKGFwaV9tcywgKGludCwgZmxvYXQpKSBvciBhcGlfbXMgPD0gMDoKICAgICAgICBzeXMuZXhpdCgwKQogICAgdHJ5OgogICAgICAgIHByZXYgPSBqc29uLmxvYWRzKChjYWNoZSAvICJjbGF1ZGUtc3RhdHVzLmpzb24iKS5yZWFkX3RleHQoKSkKICAgICAgICBpZiBwcmV2LmdldCgicmF0ZV9saW1pdHMiKSBpcyBub3QgTm9uZSBhbmQgcHJldi5nZXQoInNlc3Npb25faWQiKSA9PSBzdGF0dXMuZ2V0KCJzZXNzaW9uX2lkIik6CiAgICAgICAgICAgIHN5cy5leGl0KDApCiAgICBleGNlcHQgKE9TRXJyb3IsIFZhbHVlRXJyb3IsIEF0dHJpYnV0ZUVycm9yKToKICAgICAgICBwYXNzCnN0YXR1c1siX3doZXJkciJdID0geyJ2ZXJzaW9uIjogMSwgImFjY291bnQiOiBhY2NvdW50LCAiYXQiOiBpbnQodGltZS50aW1lKCkgKiAxMDAwKX0KZGVmIGF0b21pYyhuYW1lLCB0ZXh0KToKICAgIGZkLCB0ZW1wID0gdGVtcGZpbGUubWtzdGVtcChwcmVmaXg9bmFtZSArICIuIiwgZGlyPWNhY2hlKQogICAgdHJ5OgogICAgICAgIHdpdGggb3MuZmRvcGVuKGZkLCAidyIpIGFzIGY6CiAgICAgICAgICAgIGYud3JpdGUodGV4dCkKICAgICAgICBvcy5yZXBsYWNlKHRlbXAsIGNhY2hlIC8gbmFtZSkKICAgIGZpbmFsbHk6CiAgICAgICAgaWYgb3MucGF0aC5leGlzdHModGVtcCk6CiAgICAgICAgICAgIG9zLnVubGluayh0ZW1wKQojIENvbXBhdGliaWxpdHkgZm9yIG9sZGVyIHJlYWRlcnM7IG5ldyByZWFkZXJzIHVzZSBvbmx5IHRoZSBlbWJlZGRlZCBhY2NvdW50LgppZiBhY2NvdW50OgogICAgYXRvbWljKCJjbGF1ZGUtYWNjb3VudCIsIGFjY291bnQgKyAiXG4iKQplbHNlOgogICAgKGNhY2hlIC8gImNsYXVkZS1hY2NvdW50IikudW5saW5rKG1pc3Npbmdfb2s9VHJ1ZSkKYXRvbWljKCJjbGF1ZGUtc3RhdHVzLmpzb24iLCBqc29uLmR1bXBzKHN0YXR1cykpCicgIiRkaXIiIDs7CmVzYWMKaWYgWyAtbiAiJDEiIF07IHRoZW4gcHJpbnRmICclcycgIiRkIiB8IHNoIC1jICIkMSI7IGV4aXQgJD87IGZpCmV4aXQgMApXSEVSRFJfU1RBVFVTTElORQpjaG1vZCA3NTUgIiRkaXIvd2hlcmRyLXN0YXR1c2xpbmUuc2gudG1wIgptdiAiJGRpci93aGVyZHItc3RhdHVzbGluZS5zaC50bXAiICIkZGlyL3doZXJkci1zdGF0dXNsaW5lLnNoIgplY2hvICJzdGF0dXMgbGluZSB3cml0dGVuOiAkZGlyL3doZXJkci1zdGF0dXNsaW5lLnNoIgojIC0tLS0gc2V0dGluZ3MuanNvbiAtLS0tClsgLWYgIiRkaXIvc2V0dGluZ3MuanNvbiIgXSB8fCBlY2hvICd7fScgPiAiJGRpci9zZXR0aW5ncy5qc29uIgpjcCAiJGRpci9zZXR0aW5ncy5qc29uIiAiJGRpci9zZXR0aW5ncy5qc29uLmJhay13aGVyZHIiCnB5dGhvbjMgLSAiJGRpci9zZXR0aW5ncy5qc29uIiAiJGRpci93aGVyZHItc3RhdHVzbGluZS5zaCIgPDwnV0hFUkRSX1BZJwppbXBvcnQganNvbiwgc2hsZXgsIHN5cwpwYXRoLCBzY3JpcHQgPSBzeXMuYXJndlsxXSwgc3lzLmFyZ3ZbMl0KZCA9IGpzb24ubG9hZChvcGVuKHBhdGgpKQpvdXJzID0gJ3NoICcgKyBzaGxleC5xdW90ZShzY3JpcHQpCmN1ciA9IGQuZ2V0KCdzdGF0dXNMaW5lJykKaWYgaXNpbnN0YW5jZShjdXIsIGRpY3QpIGFuZCAnd2hlcmRyLXN0YXR1c2xpbmUuc2gnIGluIHN0cihjdXIuZ2V0KCdjb21tYW5kJywgJycpKToKICAgIHByaW50KCdhbHJlYWR5IGluc3RhbGxlZDonLCBjdXJbJ2NvbW1hbmQnXSkKICAgIHN5cy5leGl0KDApCmlmIGN1ciBpcyBOb25lOgogICAgZFsnc3RhdHVzTGluZSddID0geyd0eXBlJzogJ2NvbW1hbmQnLCAnY29tbWFuZCc6IG91cnN9CiAgICBwcmludCgnc3RhdHVzIGxpbmUgYWRkZWQ6Jywgb3VycykKZWxpZiBpc2luc3RhbmNlKGN1ciwgZGljdCkgYW5kIGN1ci5nZXQoJ3R5cGUnKSA9PSAnY29tbWFuZCcgYW5kIGN1ci5nZXQoJ2NvbW1hbmQnKToKICAgIGRbJ3N0YXR1c0xpbmUnXSA9IHsqKmN1ciwgJ2NvbW1hbmQnOiBvdXJzICsgJyAnICsgc2hsZXgucXVvdGUoY3VyWydjb21tYW5kJ10pfQogICAgcHJpbnQoJ2V4aXN0aW5nIHN0YXR1cyBsaW5lIGNoYWluZWQ6JywgZFsnc3RhdHVzTGluZSddWydjb21tYW5kJ10pCmVsc2U6CiAgICBwcmludCgndW5rbm93biBzdGF0dXNMaW5lLCBub3RoaW5nIGNoYW5nZWQ6JywganNvbi5kdW1wcyhjdXIpLCBmaWxlPXN5cy5zdGRlcnIpCiAgICBzeXMuZXhpdCgxKQp3aXRoIG9wZW4ocGF0aCwgJ3cnKSBhcyBmOgogICAganNvbi5kdW1wKGQsIGYsIGluZGVudD0yLCBlbnN1cmVfYXNjaWk9RmFsc2UpCiAgICBmLndyaXRlKCdcbicpCldIRVJEUl9QWQo=");
|
|
5
5
|
|
|
6
6
|
export { installClaudeStatusline as default };
|
|
7
7
|
//# sourceMappingURL=install-claude-statusline.mjs.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { b as base64ToUint8Array } from '../virtual/_raw-helpers.mjs';
|
|
2
2
|
|
|
3
3
|
// ROLLUP_NO_REPLACE
|
|
4
|
-
const prerelease = base64ToUint8Array("IyEvdXNyL2Jpbi9lbnYgYmFzaAojIFJvbGxpbmcgcHJlcmVsZWFzZSBvZiB0aGUgZGV2ZWxvcCBicmFuY2ggKC5naXRodWIvd29ya2Zsb3dzL2RldmVsb3AtcHJlcmVsZWFzZS55bWwpLgojIFBSRVJFTEVBU0VfVEFHPWRldmVsb3Agc2VsZWN0cyB0aGUgZml4ZWQgY2hhbm5lbCwgaW5jbHVkaW5nIHN0YWJsZSB2ZXJzaW9ucy4KIyBXaXRob3V0IGl0LCB0aGUgaGlzdG9yaWNhbCBzdWZmaXgtb25seSBjaGFubmVsIHJlbWFpbnMgYXZhaWxhYmxlLgojIENvbW1hbmRzOiB2ZXJzaW9uIHwgcGFja2FnZSA8dGd6PiA8c2hhPiB8IHB1Ymxpc2ggPHRnej4gPHNoYT4KIyBwYWNrYWdlIGNoZWNrcyB0aGUgYXJjaGl2ZSBhbmQgd3JpdGVzIGl0cyBjaGVja3N1bSwgQ09NTUlUIGFuZCBub3Rlcy4KIyBwdWJsaXNoIG5lZWRzIGdoLCBHSF9SRVBPIGFuZCBhIHRva2VuIHRoYXQgY2FuIHdyaXRlIGNvbnRlbnRzLgojIEV4aXN0aW5nIHJlbGVhc2VzIG11c3QgYmUgcHVibGlzaGVkIHByZXJlbGVhc2VzOyBzdGFibGUgdGFncyBhcmUgbmV2ZXIgbW92ZWQuCnNldCAtZXVvIHBpcGVmYWlsCgpkaWUoKSB7IGVjaG8gInByZXJlbGVhc2U6ICQqIiA+JjI7IGV4aXQgMTsgfQoKcGx1Z2luX3ZlcnNpb24oKSB7IHNlZCAtbiAncy9edmVyc2lvbiA9ICJcKC4qXCkiJC9cMS9wJyBoZXJkci1wbHVnaW4udG9tbCB8IGhlYWQgLW4gMTsgfQoKY21kX3ZlcnNpb24oKSB7CiAgbG9jYWwgdmVyc2lvbiBwa2cKICB2ZXJzaW9uPSIkKHBsdWdpbl92ZXJzaW9uKSIKICBwa2c9IiQobm9kZSAtcCAicmVxdWlyZSgnLi9wYWNrYWdlLmpzb24nKS52ZXJzaW9uIikiCiAgWyAiJHZlcnNpb24iID0gIiRwa2ciIF0gfHwgZGllICJoZXJkci1wbHVnaW4udG9tbCAoJHZlcnNpb24pIGFuZCBwYWNrYWdlLmpzb24gKCRwa2cpIGRpc2FncmVlIgogIFsgIiR7UFJFUkVMRUFTRV9UQUc6LWRldmVsb3B9IiA9IGRldmVsb3AgXSB8fCBkaWUgInVuc3VwcG9ydGVkIFBSRVJFTEVBU0VfVEFHIgogIGlmIFsgIiR7UFJFUkVMRUFTRV9UQUc6LX0iID0gZGV2ZWxvcCBdOyB0aGVuCiAgICBbWyAiJHZlcnNpb24iID1+IF5bMC05XStcLlswLTldK1wuWzAtOV0rKC1bMC05QS1aYS16Li1dKyk/JCBdXSB8fCBkaWUgImludmFsaWQgdmVyc2lvbiAkdmVyc2lvbiIKICAgIGVjaG8gIiR2ZXJzaW9uIgogICAgcmV0dXJuCiAgZmkKICBbWyAiJHZlcnNpb24iID1+IF5bMC05XStcLlswLTldK1wuWzAtOV0rLVswLTlBLVphLXouLV0rJCBdXSBcCiAgICB8fCBkaWUgInZlcnNpb24gJHZlcnNpb24gaXMgbm90IGEgcHJlcmVsZWFzZSAoWC5ZLlotc3VmZml4KTogc3RhYmxlIHJlbGVhc2VzIGdvIHRocm91Z2ggcmVsZWFzZS55bWwiCiAgZWNobyAiJHZlcnNpb24iCn0KCmNoZWNrX3NoYSgpIHsgW1sgIiQxIiA9fiBeWzAtOWEtZl17NDB9JCBdXSB8fCBkaWUgIm5vdCBhIGZ1bGwgY29tbWl0IFNIQTogJDEiOyB9CgojIFRoZSBhcmNoaXZlIG11c3QgaG9sZCB3aGF0IGZldGNoX3ByZWJ1aWx0IGluc3RhbGxzLCBhbmQgbm90aGluZyBjb21waWxlZCBmb3IKIyBvbmUgcGxhdGZvcm06IHRoZSBzYW1lIGZpbGUgcnVucyBvbiBsaW51eC1hcm02NCAoUmFzcGJlcnJ5IFBpKSBhbmQgeDY0LgpjaGVja19hcmNoaXZlKCkgewogIGxvY2FsIHRnej0iJDEiIHRtcCBtaXNzaW5nPTAgbmF0aXZlCiAgdG1wPSIkKG1rdGVtcCAtZCkiCiAgdGFyIC14emYgIiR0Z3oiIC1DICIkdG1wIgogIGZvciBlbnRyeSBpbiAub3V0cHV0L3NlcnZlci9pbmRleC5tanMgYmluL3doZXJkci5tanMgYmluL2xpYi9pbnN0YWxsLXNraWxsLnNoIGJpbi9saWIvdmVyaWZ5LXJlbGVhc2UubWpzIFwKICAgIHBhY2thZ2UuanNvbiBza2lsbHMvd2hlcmRyL1NLSUxMLm1kOyBkbwogICAgWyAtZiAiJHRtcC9wYWNrYWdlLyRlbnRyeSIgXSB8fCB7IGVjaG8gInByZXJlbGVhc2U6IG1pc3NpbmcgcGFja2FnZS8kZW50cnkiID4mMjsgbWlzc2luZz0xOyB9CiAgZG9uZQogIG5hdGl2ZT0iJChub2RlIC1lICcKICAgIGNvbnN0IGZzID0gcmVxdWlyZSgibm9kZTpmcyIpLCBwYXRoID0gcmVxdWlyZSgibm9kZTpwYXRoIikKICAgIGNvbnN0IE1BR0lDID0gWyI3ZjQ1NGM0NiIsICJmZWVkZmFjZSIsICJmZWVkZmFjZiIsICJjZWZhZWRmZSIsICJjZmZhZWRmZSJdCiAgICBjb25zdCBoaXRzID0gW10KICAgIGNvbnN0IHdhbGsgPSBkaXIgPT4gewogICAgICBmb3IgKGNvbnN0IGUgb2YgZnMucmVhZGRpclN5bmMoZGlyLCB7IHdpdGhGaWxlVHlwZXM6IHRydWUgfSkpIHsKICAgICAgICBjb25zdCBwID0gcGF0aC5qb2luKGRpciwgZS5uYW1lKQogICAgICAgIGlmIChlLmlzRGlyZWN0b3J5KCkpIHsgaWYgKGUubmFtZSA9PT0gInByZWJ1aWxkcyIpIGhpdHMucHVzaChwKTsgZWxzZSB3YWxrKHApOyBjb250aW51ZSB9CiAgICAgICAgaWYgKCFlLmlzRmlsZSgpKSBjb250aW51ZQogICAgICAgIGlmICgvXC4obm9kZXxzb3xkeWxpYnxkbGx8ZXhlKSQvLnRlc3QoZS5uYW1lKSB8fCBlLm5hbWUgPT09ICJiaW5kaW5nLmd5cCIpIHsgaGl0cy5wdXNoKHApOyBjb250aW51ZSB9CiAgICAgICAgY29uc3QgZmQgPSBmcy5vcGVuU3luYyhwLCAiciIpLCBiID0gQnVmZmVyLmFsbG9jKDQpCiAgICAgICAgY29uc3QgbiA9IGZzLnJlYWRTeW5jKGZkLCBiLCAwLCA0LCAwKTsgZnMuY2xvc2VTeW5jKGZkKQogICAgICAgIGlmIChuID09PSA0ICYmIE1BR0lDLmluY2x1ZGVzKGIudG9TdHJpbmcoImhleCIpKSkgaGl0cy5wdXNoKHApCiAgICAgIH0KICAgIH0KICAgIHdhbGsocHJvY2Vzcy5hcmd2WzFdKQogICAgY29uc29sZS5sb2coaGl0cy5tYXAoaCA9PiBwYXRoLnJlbGF0aXZlKHByb2Nlc3MuYXJndlsxXSwgaCkpLmpvaW4oIlxuIikpCiAgJyAiJHRtcCIpIgogIHJtIC1yZiAiJHRtcCIKICBbICIkbWlzc2luZyIgPSAwIF0gfHwgZGllICJpbmNvbXBsZXRlIHBhY2thZ2UgJHRneiIKICBbIC16ICIkbmF0aXZlIiBdIHx8IGRpZSAibmF0aXZlIGNvZGUgaW4gdGhlIHBhY2thZ2UgKGl0IHdvdWxkIG5vdCBydW4gb24gYW5vdGhlciBwbGF0Zm9ybSk6CiRuYXRpdmUiCn0KCmNtZF9wYWNrYWdlKCkgewogIGxvY2FsIHRnej0iJHsxOj91c2FnZTogcHJlcmVsZWFzZS5zaCBwYWNrYWdlIDx0Z3o+IDxzaGE+fSIgc2hhPSIkezI6P2NvbW1pdCBTSEF9IiB2ZXJzaW9uIGRpciBuYW1lCiAgY2hlY2tfc2hhICIkc2hhIgogIHZlcnNpb249IiQoY21kX3ZlcnNpb24pIgogIG5hbWU9IndoZXJkci0kdmVyc2lvbi50Z3oiCiAgWyAiJChiYXNlbmFtZSAiJHRneiIpIiA9ICIkbmFtZSIgXSB8fCBkaWUgImV4cGVjdGVkICRuYW1lLCBnb3QgJChiYXNlbmFtZSAiJHRneiIpIgogIGNoZWNrX2FyY2hpdmUgIiR0Z3oiCiAgZGlyPSIkKGRpcm5hbWUgIiR0Z3oiKSIKICAjIFRoZSBmb3JtYXQgYmluL2xpYi92ZXJpZnktcmVsZWFzZS5tanMgcmVhZHMsIGFzIHJlbGVhc2UueW1sIHdyaXRlcyBpdC4KICAoY2QgIiRkaXIiICYmIHNoYTI1NnN1bSAiJG5hbWUiID4gIiRuYW1lLnNoYTI1NiIpCiAgcHJpbnRmICclc1xuJyAiJHNoYSIgPiAiJGRpci9DT01NSVQiCiAgaWYgWyAiJHtQUkVSRUxFQVNFX1RBRzotfSIgPSBkZXZlbG9wIF07IHRoZW4KICAgICMgUmVsZWFzZSBwcmVwYXJhdGlvbiBjYW4gbGVhdmUgVW5yZWxlYXNlZCBlbXB0eTsgdGhlIGNoYW5uZWwgc3RpbGwgcHVibGlzaGVzLgogICAgcHJpbnRmICcjIyBVcGRhdGVcblxuVGhpcyBwYWNrYWdlIGZvbGxvd3MgdGhlIGRldmVsb3AgYnJhbmNoIGF0IHRoZSBjb21taXQgYmVsb3cuIFJlYWQgQ0hBTkdFTE9HLm1kIGluIHRoZSBhcmNoaXZlIGZvciB0aGUgY2hhbmdlcyBpbmNsdWRlZCBpbiB0aGlzIGJ1aWxkLlxuJyA+ICIkZGlyL3ByZXJlbGVhc2Utbm90ZXMubWQiCiAgZWxzZQogIG5vZGUgIiQoZGlybmFtZSAiJHtCQVNIX1NPVVJDRVswXX0iKS9wcmVyZWxlYXNlLXN1bW1hcnkubWpzIiAiJHNoYSIgPiAiJGRpci9wcmVyZWxlYXNlLW5vdGVzLm1kIgogIGZpCiAgewogICAgZWNobwogICAgZWNobyAiUm9sbGluZyBwcmVyZWxlYXNlIG9mIHRoZSBcYGRldmVsb3BcYCBicmFuY2gsIHJlYnVpbHQgb24gZXZlcnkgcHVzaC4gTm90IGEgc3RhYmxlIHJlbGVhc2U6IG5ldmVyIG1hcmtlZCBsYXRlc3QsIG5ldmVyIG9mZmVyZWQgYXMgYW4gdXBkYXRlLiIKICAgIGVjaG8KICAgIGVjaG8gIkNvbW1pdDogXGAkc2hhXGAiCiAgICBlY2hvCiAgICBlY2hvICJCdWlsdCAkKGRhdGUgLXUgJyslWS0lbS0lZCAlSDolTSBVVEMnKSR7R0lUSFVCX1JVTl9JRDorIGJ5ICR7R0lUSFVCX1NFUlZFUl9VUkw6LWh0dHBzOi8vZ2l0aHViLmNvbX0vJHtHSVRIVUJfUkVQT1NJVE9SWTotfS9hY3Rpb25zL3J1bnMvJEdJVEhVQl9SVU5fSUR9LiIKICAgIGVjaG8KICAgIGVjaG8gIlxgQ09NTUlUXGAgaG9sZHMgdGhlIGNvbW1pdCBvZiBcYCRuYW1lXGAuIEl0IGlzIHJlbW92ZWQgd2hpbGUgdGhlIGZpbGVzIGFyZSByZXBsYWNlZCBhbmQgYXR0YWNoZWQgbGFzdDogd2hlbiBpdCBpcyBwcmVzZW50LCB0aGUgYXJjaGl2ZSBtYXRjaGVzIGl0LiIKICB9ID4+ICIkZGlyL3ByZXJlbGVhc2Utbm90ZXMubWQiCiAgZWNobyAicHJlcmVsZWFzZTogJG5hbWUgZm9yICRzaGEgY2hlY2tlZCIKfQoKY21kX3B1Ymxpc2goKSB7CiAgbG9jYWwgdGd6PSIkezE6P3VzYWdlOiBwcmVyZWxlYXNlLnNoIHB1Ymxpc2ggPHRnej4gPHNoYT59IiBzaGE9IiR7Mjo/Y29tbWl0IFNIQX0iIHZlcnNpb24gdGFnIGRpciByZXBvIHN0YXRlIGFzc2V0cyBleGlzdHMKICBjaGVja19zaGEgIiRzaGEiCiAgdmVyc2lvbj0iJChjbWRfdmVyc2lvbikiCiAgdGFnPSIke1BSRVJFTEVBU0VfVEFHOi12JHZlcnNpb259IgogIGRpcj0iJChkaXJuYW1lICIkdGd6IikiCiAgcmVwbz0iJHtHSF9SRVBPOj9HSF9SRVBPIGlzIHJlcXVpcmVkfSIKICBmb3IgZiBpbiAiJHRneiIgIiR0Z3ouc2hhMjU2IiAiJGRpci9DT01NSVQiICIkZGlyL3ByZXJlbGVhc2Utbm90ZXMubWQiOyBkbwogICAgWyAtZiAiJGYiIF0gfHwgZGllICJtaXNzaW5nICRmIChydW46IHByZXJlbGVhc2Uuc2ggcGFja2FnZSBmaXJzdCkiCiAgZG9uZQoKICBpZiBzdGF0ZT0iJChnaCByZWxlYXNlIHZpZXcgIiR0YWciIC0tanNvbiBpc1ByZXJlbGVhc2UsaXNEcmFmdCAtLWpxICciXCguaXNQcmVyZWxlYXNlKSBcKC5pc0RyYWZ0KSInIDI+L2Rldi9udWxsKSI7IHRoZW4KICAgIFsgIiRzdGF0ZSIgPSAidHJ1ZSBmYWxzZSIgXSB8fCBkaWUgInJlbGVhc2UgJHRhZyBleGlzdHMgYW5kIGlzIG5vdCBhIHB1Ymxpc2hlZCBwcmVyZWxlYXNlICgkc3RhdGUpOiBsZWZ0IGFsb25lIgogICAgIyBHb25lIHdoaWxlIHRoZSBhcmNoaXZlIGNoYW5nZXM6IGEgcmVhZGVyIHRoYXQgZmluZHMgQ09NTUlUIGZpbmRzIGl0cyBhcmNoaXZlLgogICAgYXNzZXRzPSIkKGdoIHJlbGVhc2UgdmlldyAiJHRhZyIgLS1qc29uIGFzc2V0cyAtLWpxICcuYXNzZXRzW10ubmFtZScpIgogICAgaWYgcHJpbnRmICclc1xuJyAiJGFzc2V0cyIgfCBncmVwIC1xeCBDT01NSVQ7IHRoZW4KICAgICAgZ2ggcmVsZWFzZSBkZWxldGUtYXNzZXQgIiR0YWciIENPTU1JVCAtLXllcwogICAgZmkKICAgIGV4aXN0cz0xCiAgZWxzZQogICAgZXhpc3RzPTAKICBmaQoKICAjIFRoZSB0YWcgZm9sbG93cyB0aGUgcHVzaGVkIGNvbW1pdC4gTWFkZSB3aXRoIHRoZSB3b3JrZmxvdydzIHRva2VuLCBpdCBzdGFydHMKICAjIG5vIG90aGVyIHdvcmtmbG93IChyZWxlYXNlLnltbCBhbmQgbnBtLnltbCBsaXN0ZW4gdG8gdiogdGFncykuCiAgaWYgZ2ggYXBpICJyZXBvcy8kcmVwby9naXQvcmVmcy90YWdzLyR0YWciID4vZGV2L251bGwgMj4mMTsgdGhlbgogICAgZ2ggYXBpIC1YIFBBVENIICJyZXBvcy8kcmVwby9naXQvcmVmcy90YWdzLyR0YWciIC1mIHNoYT0iJHNoYSIgLUYgZm9yY2U9dHJ1ZSA+L2Rldi9udWxsCiAgZWxzZQogICAgZ2ggYXBpIC1YIFBPU1QgInJlcG9zLyRyZXBvL2dpdC9yZWZzIiAtZiByZWY9InJlZnMvdGFncy8kdGFnIiAtZiBzaGE9IiRzaGEiID4vZGV2L251bGwKICBmaQoKICBpZiBbICIkZXhpc3RzIiA9IDEgXTsgdGhlbgogICAgZ2ggcmVsZWFzZSBlZGl0ICIkdGFnIiAtLXByZXJlbGVhc2UgLS1sYXRlc3Q9ZmFsc2UgLS10aXRsZSAid2hlcmRyICR2ZXJzaW9uIiAtLW5vdGVzLWZpbGUgIiRkaXIvcHJlcmVsZWFzZS1ub3Rlcy5tZCIKICBlbHNlCiAgICBnaCByZWxlYXNlIGNyZWF0ZSAiJHRhZyIgLS12ZXJpZnktdGFnIC0tcHJlcmVsZWFzZSAtLWxhdGVzdD1mYWxzZSAtLXRpdGxlICJ3aGVyZHIgJHZlcnNpb24iIC0tbm90ZXMtZmlsZSAiJGRpci9wcmVyZWxlYXNlLW5vdGVzLm1kIgogIGZpCiAgZ2ggcmVsZWFzZSB1cGxvYWQgIiR0YWciICIkdGd6IiAiJHRnei5zaGEyNTYiIC0tY2xvYmJlcgogICMgS2VlcCBleGFjdGx5IG9uZSBhcmNoaXZlIGFuZCBjaGVja3N1bSBvbiB0aGUgZml4ZWQgY2hhbm5lbCBhZnRlciB2ZXJzaW9uIGJ1bXBzLgogIGlmIFsgIiRleGlzdHMiID0gMSBdICYmIFsgIiR0YWciID0gZGV2ZWxvcCBdOyB0aGVuCiAgICB3aGlsZSBJRlM9IHJlYWQgLXIgYXNzZXQ7IGRvCiAgICAgIGNhc2UgIiRhc3NldCIgaW4KICAgICAgICB3aGVyZHItKi50Z3p8d2hlcmRyLSoudGd6LnNoYTI1NikKICAgICAgICAgIFsgIiRhc3NldCIgPSAiJChiYXNlbmFtZSAiJHRneiIpIiBdIHx8IFsgIiRhc3NldCIgPSAiJChiYXNlbmFtZSAiJHRneiIpLnNoYTI1NiIgXSBcCiAgICAgICAgICAgIHx8IGdoIHJlbGVhc2UgZGVsZXRlLWFzc2V0ICIkdGFnIiAiJGFzc2V0IiAtLXllcyA7OwogICAgICBlc2FjCiAgICBkb25lIDw8PCAiJGFzc2V0cyIKICBmaQogIGdoIHJlbGVhc2UgdXBsb2FkICIkdGFnIiAiJGRpci9DT01NSVQiIC0tY2xvYmJlcgogIGVjaG8gInByZXJlbGVhc2U6ICR0YWcgbm93IGF0ICRzaGEiCn0KCmNhc2UgIiR7MTotfSIgaW4KICB2ZXJzaW9uKSBjbWRfdmVyc2lvbiA7OwogIHBhY2thZ2UpIHNoaWZ0OyBjbWRfcGFja2FnZSAiJEAiIDs7CiAgcHVibGlzaCkgc2hpZnQ7IGNtZF9wdWJsaXNoICIkQCIgOzsKICAqKSBkaWUgInVzYWdlOiAkMCB2ZXJzaW9uIHwgcGFja2FnZSA8dGd6PiA8c2hhPiB8IHB1Ymxpc2ggPHRnej4gPHNoYT4iIDs7CmVzYWMK");
|
|
4
|
+
const prerelease = base64ToUint8Array("IyEvdXNyL2Jpbi9lbnYgYmFzaAojIFJvbGxpbmcgcHJlcmVsZWFzZSBvZiB0aGUgZGV2ZWxvcCBicmFuY2ggKC5naXRodWIvd29ya2Zsb3dzL2RldmVsb3AtcHJlcmVsZWFzZS55bWwpLgojIFBSRVJFTEVBU0VfVEFHPWRldmVsb3Agc2VsZWN0cyB0aGUgZml4ZWQgY2hhbm5lbCwgaW5jbHVkaW5nIHN0YWJsZSB2ZXJzaW9ucy4KIyBXaXRob3V0IGl0LCB0aGUgaGlzdG9yaWNhbCBzdWZmaXgtb25seSBjaGFubmVsIHJlbWFpbnMgYXZhaWxhYmxlLgojIENvbW1hbmRzOiB2ZXJzaW9uIHwgZ2F0ZSA8c2hhPiB8IHBhY2thZ2UgPHRnej4gPHNoYT4gfCBwdWJsaXNoIDx0Z3o+IDxzaGE+CiMgZ2F0ZSBkZWNpZGVzIHdoZXRoZXIgPHNoYT4gbWF5IGJlIHB1Ymxpc2hlZCAoc2VlIGNtZF9nYXRlKS4KIyBwYWNrYWdlIGNoZWNrcyB0aGUgYXJjaGl2ZSBhbmQgd3JpdGVzIGl0cyBjaGVja3N1bSwgQ09NTUlUIGFuZCBub3Rlcy4KIyBwdWJsaXNoIG5lZWRzIGdoLCBHSF9SRVBPIGFuZCBhIHRva2VuIHRoYXQgY2FuIHdyaXRlIGNvbnRlbnRzLgojIEV4aXN0aW5nIHJlbGVhc2VzIG11c3QgYmUgcHVibGlzaGVkIHByZXJlbGVhc2VzOyBzdGFibGUgdGFncyBhcmUgbmV2ZXIgbW92ZWQuCnNldCAtZXVvIHBpcGVmYWlsCgpkaWUoKSB7IGVjaG8gInByZXJlbGVhc2U6ICQqIiA+JjI7IGV4aXQgMTsgfQoKcGx1Z2luX3ZlcnNpb24oKSB7IHNlZCAtbiAncy9edmVyc2lvbiA9ICJcKC4qXCkiJC9cMS9wJyBoZXJkci1wbHVnaW4udG9tbCB8IGhlYWQgLW4gMTsgfQoKY21kX3ZlcnNpb24oKSB7CiAgbG9jYWwgdmVyc2lvbiBwa2cKICB2ZXJzaW9uPSIkKHBsdWdpbl92ZXJzaW9uKSIKICBwa2c9IiQobm9kZSAtcCAicmVxdWlyZSgnLi9wYWNrYWdlLmpzb24nKS52ZXJzaW9uIikiCiAgWyAiJHZlcnNpb24iID0gIiRwa2ciIF0gfHwgZGllICJoZXJkci1wbHVnaW4udG9tbCAoJHZlcnNpb24pIGFuZCBwYWNrYWdlLmpzb24gKCRwa2cpIGRpc2FncmVlIgogIFsgIiR7UFJFUkVMRUFTRV9UQUc6LWRldmVsb3B9IiA9IGRldmVsb3AgXSB8fCBkaWUgInVuc3VwcG9ydGVkIFBSRVJFTEVBU0VfVEFHIgogIGlmIFsgIiR7UFJFUkVMRUFTRV9UQUc6LX0iID0gZGV2ZWxvcCBdOyB0aGVuCiAgICBbWyAiJHZlcnNpb24iID1+IF5bMC05XStcLlswLTldK1wuWzAtOV0rKC1bMC05QS1aYS16Li1dKyk/JCBdXSB8fCBkaWUgImludmFsaWQgdmVyc2lvbiAkdmVyc2lvbiIKICAgIGVjaG8gIiR2ZXJzaW9uIgogICAgcmV0dXJuCiAgZmkKICBbWyAiJHZlcnNpb24iID1+IF5bMC05XStcLlswLTldK1wuWzAtOV0rLVswLTlBLVphLXouLV0rJCBdXSBcCiAgICB8fCBkaWUgInZlcnNpb24gJHZlcnNpb24gaXMgbm90IGEgcHJlcmVsZWFzZSAoWC5ZLlotc3VmZml4KTogc3RhYmxlIHJlbGVhc2VzIGdvIHRocm91Z2ggcmVsZWFzZS55bWwiCiAgZWNobyAiJHZlcnNpb24iCn0KCmNoZWNrX3NoYSgpIHsgW1sgIiQxIiA9fiBeWzAtOWEtZl17NDB9JCBdXSB8fCBkaWUgIm5vdCBhIGZ1bGwgY29tbWl0IFNIQTogJDEiOyB9CgojIFRoZSBhcmNoaXZlIG11c3QgaG9sZCB3aGF0IGZldGNoX3ByZWJ1aWx0IGluc3RhbGxzLCBhbmQgbm90aGluZyBjb21waWxlZCBmb3IKIyBvbmUgcGxhdGZvcm06IHRoZSBzYW1lIGZpbGUgcnVucyBvbiBsaW51eC1hcm02NCAoUmFzcGJlcnJ5IFBpKSBhbmQgeDY0LgpjaGVja19hcmNoaXZlKCkgewogIGxvY2FsIHRnej0iJDEiIHRtcCBtaXNzaW5nPTAgbmF0aXZlCiAgdG1wPSIkKG1rdGVtcCAtZCkiCiAgdGFyIC14emYgIiR0Z3oiIC1DICIkdG1wIgogIGZvciBlbnRyeSBpbiAub3V0cHV0L3NlcnZlci9pbmRleC5tanMgYmluL3doZXJkci5tanMgYmluL2xpYi9pbnN0YWxsLXNraWxsLnNoIGJpbi9saWIvdmVyaWZ5LXJlbGVhc2UubWpzIFwKICAgIHBhY2thZ2UuanNvbiBza2lsbHMvd2hlcmRyL1NLSUxMLm1kOyBkbwogICAgWyAtZiAiJHRtcC9wYWNrYWdlLyRlbnRyeSIgXSB8fCB7IGVjaG8gInByZXJlbGVhc2U6IG1pc3NpbmcgcGFja2FnZS8kZW50cnkiID4mMjsgbWlzc2luZz0xOyB9CiAgZG9uZQogIG5hdGl2ZT0iJChub2RlIC1lICcKICAgIGNvbnN0IGZzID0gcmVxdWlyZSgibm9kZTpmcyIpLCBwYXRoID0gcmVxdWlyZSgibm9kZTpwYXRoIikKICAgIGNvbnN0IE1BR0lDID0gWyI3ZjQ1NGM0NiIsICJmZWVkZmFjZSIsICJmZWVkZmFjZiIsICJjZWZhZWRmZSIsICJjZmZhZWRmZSJdCiAgICBjb25zdCBoaXRzID0gW10KICAgIGNvbnN0IHdhbGsgPSBkaXIgPT4gewogICAgICBmb3IgKGNvbnN0IGUgb2YgZnMucmVhZGRpclN5bmMoZGlyLCB7IHdpdGhGaWxlVHlwZXM6IHRydWUgfSkpIHsKICAgICAgICBjb25zdCBwID0gcGF0aC5qb2luKGRpciwgZS5uYW1lKQogICAgICAgIGlmIChlLmlzRGlyZWN0b3J5KCkpIHsgaWYgKGUubmFtZSA9PT0gInByZWJ1aWxkcyIpIGhpdHMucHVzaChwKTsgZWxzZSB3YWxrKHApOyBjb250aW51ZSB9CiAgICAgICAgaWYgKCFlLmlzRmlsZSgpKSBjb250aW51ZQogICAgICAgIGlmICgvXC4obm9kZXxzb3xkeWxpYnxkbGx8ZXhlKSQvLnRlc3QoZS5uYW1lKSB8fCBlLm5hbWUgPT09ICJiaW5kaW5nLmd5cCIpIHsgaGl0cy5wdXNoKHApOyBjb250aW51ZSB9CiAgICAgICAgY29uc3QgZmQgPSBmcy5vcGVuU3luYyhwLCAiciIpLCBiID0gQnVmZmVyLmFsbG9jKDQpCiAgICAgICAgY29uc3QgbiA9IGZzLnJlYWRTeW5jKGZkLCBiLCAwLCA0LCAwKTsgZnMuY2xvc2VTeW5jKGZkKQogICAgICAgIGlmIChuID09PSA0ICYmIE1BR0lDLmluY2x1ZGVzKGIudG9TdHJpbmcoImhleCIpKSkgaGl0cy5wdXNoKHApCiAgICAgIH0KICAgIH0KICAgIHdhbGsocHJvY2Vzcy5hcmd2WzFdKQogICAgY29uc29sZS5sb2coaGl0cy5tYXAoaCA9PiBwYXRoLnJlbGF0aXZlKHByb2Nlc3MuYXJndlsxXSwgaCkpLmpvaW4oIlxuIikpCiAgJyAiJHRtcCIpIgogIHJtIC1yZiAiJHRtcCIKICBbICIkbWlzc2luZyIgPSAwIF0gfHwgZGllICJpbmNvbXBsZXRlIHBhY2thZ2UgJHRneiIKICBbIC16ICIkbmF0aXZlIiBdIHx8IGRpZSAibmF0aXZlIGNvZGUgaW4gdGhlIHBhY2thZ2UgKGl0IHdvdWxkIG5vdCBydW4gb24gYW5vdGhlciBwbGF0Zm9ybSk6CiRuYXRpdmUiCn0KCmNtZF9wYWNrYWdlKCkgewogIGxvY2FsIHRnej0iJHsxOj91c2FnZTogcHJlcmVsZWFzZS5zaCBwYWNrYWdlIDx0Z3o+IDxzaGE+fSIgc2hhPSIkezI6P2NvbW1pdCBTSEF9IiB2ZXJzaW9uIGRpciBuYW1lCiAgY2hlY2tfc2hhICIkc2hhIgogIHZlcnNpb249IiQoY21kX3ZlcnNpb24pIgogIG5hbWU9IndoZXJkci0kdmVyc2lvbi50Z3oiCiAgWyAiJChiYXNlbmFtZSAiJHRneiIpIiA9ICIkbmFtZSIgXSB8fCBkaWUgImV4cGVjdGVkICRuYW1lLCBnb3QgJChiYXNlbmFtZSAiJHRneiIpIgogIGNoZWNrX2FyY2hpdmUgIiR0Z3oiCiAgZGlyPSIkKGRpcm5hbWUgIiR0Z3oiKSIKICAjIFRoZSBmb3JtYXQgYmluL2xpYi92ZXJpZnktcmVsZWFzZS5tanMgcmVhZHMsIGFzIHJlbGVhc2UueW1sIHdyaXRlcyBpdC4KICAoY2QgIiRkaXIiICYmIHNoYTI1NnN1bSAiJG5hbWUiID4gIiRuYW1lLnNoYTI1NiIpCiAgcHJpbnRmICclc1xuJyAiJHNoYSIgPiAiJGRpci9DT01NSVQiCiAgaWYgWyAiJHtQUkVSRUxFQVNFX1RBRzotfSIgPSBkZXZlbG9wIF07IHRoZW4KICAgICMgUmVsZWFzZSBwcmVwYXJhdGlvbiBjYW4gbGVhdmUgVW5yZWxlYXNlZCBlbXB0eTsgdGhlIGNoYW5uZWwgc3RpbGwgcHVibGlzaGVzLgogICAgcHJpbnRmICcjIyBVcGRhdGVcblxuVGhpcyBwYWNrYWdlIGZvbGxvd3MgdGhlIGRldmVsb3AgYnJhbmNoIGF0IHRoZSBjb21taXQgYmVsb3cuIFJlYWQgQ0hBTkdFTE9HLm1kIGluIHRoZSBhcmNoaXZlIGZvciB0aGUgY2hhbmdlcyBpbmNsdWRlZCBpbiB0aGlzIGJ1aWxkLlxuJyA+ICIkZGlyL3ByZXJlbGVhc2Utbm90ZXMubWQiCiAgZWxzZQogIG5vZGUgIiQoZGlybmFtZSAiJHtCQVNIX1NPVVJDRVswXX0iKS9wcmVyZWxlYXNlLXN1bW1hcnkubWpzIiAiJHNoYSIgPiAiJGRpci9wcmVyZWxlYXNlLW5vdGVzLm1kIgogIGZpCiAgewogICAgZWNobwogICAgZWNobyAiUm9sbGluZyBwcmVyZWxlYXNlIG9mIHRoZSBcYGRldmVsb3BcYCBicmFuY2gsIHJlYnVpbHQgZm9yIGVhY2ggZGV2ZWxvcCBjb21taXQgdGhhdCBwYXNzZXMgQ0kuIE5vdCBhIHN0YWJsZSByZWxlYXNlOiBuZXZlciBtYXJrZWQgbGF0ZXN0LCBuZXZlciBvZmZlcmVkIGFzIGFuIHVwZGF0ZS4iCiAgICBlY2hvCiAgICBlY2hvICJDb21taXQ6IFxgJHNoYVxgIgogICAgZWNobwogICAgZWNobyAiQnVpbHQgJChkYXRlIC11ICcrJVktJW0tJWQgJUg6JU0gVVRDJykke0dJVEhVQl9SVU5fSUQ6KyBieSAke0dJVEhVQl9TRVJWRVJfVVJMOi1odHRwczovL2dpdGh1Yi5jb219LyR7R0lUSFVCX1JFUE9TSVRPUlk6LX0vYWN0aW9ucy9ydW5zLyRHSVRIVUJfUlVOX0lEfS4iCiAgICBlY2hvCiAgICBlY2hvICJcYENPTU1JVFxgIGhvbGRzIHRoZSBjb21taXQgb2YgXGAkbmFtZVxgLiBJdCBpcyByZW1vdmVkIHdoaWxlIHRoZSBmaWxlcyBhcmUgcmVwbGFjZWQgYW5kIGF0dGFjaGVkIGxhc3Q6IHdoZW4gaXQgaXMgcHJlc2VudCwgdGhlIGFyY2hpdmUgbWF0Y2hlcyBpdC4iCiAgfSA+PiAiJGRpci9wcmVyZWxlYXNlLW5vdGVzLm1kIgogIGVjaG8gInByZXJlbGVhc2U6ICRuYW1lIGZvciAkc2hhIGNoZWNrZWQiCn0KCiMgQSBkZXZlbG9wIGNvbW1pdCBpcyBwdWJsaXNoZWQgb25seSB3aGVuOgojIC0gYSBwdXNoIHJ1biBvZiBjaS55bWwgb24gZGV2ZWxvcCBmb3IgZXhhY3RseSB0aGlzIGNvbW1pdCBzdWNjZWVkZWQsIHdpdGggaXRzCiMgICBgY2hlY2tzYCBhbmQgYGUyZWAgam9icyBncmVlbiAodGhlIGNoZWNrcyB0aGUgYnJhbmNoIHByb3RlY3Rpb24gcmVxdWlyZXMpOwojIC0gaXQgaXMgb24gZGV2ZWxvcCAoZGV2ZWxvcCdzIGhlYWQgb3Igb25lIG9mIGl0cyBhbmNlc3RvcnMpOwojIC0gaXQgaXMgbm90IG9sZGVyIHRoYW4gdGhlIGNvbW1pdCB0aGUgZGV2ZWxvcCB0YWcgYWxyZWFkeSBuYW1lczogcnVucyBjYW4KIyAgIGZpbmlzaCBvdXQgb2Ygb3JkZXIsIGFuZCBhIG5ld2VyIGJ1aWxkIGlzIG5ldmVyIHJlcGxhY2VkIGJ5IGFuIG9sZGVyIG9uZS4KIyBXcml0ZXMgcHVibGlzaD10cnVlfGZhbHNlIHRvICRHSVRIVUJfT1VUUFVULiBGYWlscyB3aGVuIENJIGlzIG5vdCBncmVlbiBvciB0aGUKIyBjb21taXQgaXMgbm90IG9uIGRldmVsb3A7IGFuIG9sZGVyIGNvbW1pdCBpcyBza2lwcGVkIHdpdGhvdXQgZmFpbGluZy4KY21kX2dhdGUoKSB7CiAgbG9jYWwgc2hhPSIkezE6P3VzYWdlOiBwcmVyZWxlYXNlLnNoIGdhdGUgPHNoYT59IiByZXBvIHJ1bnMgcnVuIHJ1bl9vaz0iIiBqb2JzIGhlYWQgcHVibGlzaGVkIHN0YXR1cwogIGNoZWNrX3NoYSAiJHNoYSIKICByZXBvPSIke0dIX1JFUE86P0dIX1JFUE8gaXMgcmVxdWlyZWR9IgogICMgRXZlcnkgQVBJIGNhbGwgZmFpbHMgY2xvc2VkOiBhbiBlcnJvciBzdG9wcyB0aGUgZ2F0ZSwgbmV2ZXIgbGV0cyBhIGNvbW1pdCB0aHJvdWdoLgogIHJ1bnM9IiQoZ2ggYXBpICJyZXBvcy8kcmVwby9hY3Rpb25zL3dvcmtmbG93cy9jaS55bWwvcnVucz9oZWFkX3NoYT0kc2hhJmV2ZW50PXB1c2gmYnJhbmNoPWRldmVsb3Amc3RhdHVzPXN1Y2Nlc3MmcGVyX3BhZ2U9MjAiIFwKICAgIC0tanEgJy53b3JrZmxvd19ydW5zW10gfCBzZWxlY3QoLmhlYWRfc2hhID09ICInIiRzaGEiJyIgYW5kIC5jb25jbHVzaW9uID09ICJzdWNjZXNzIikgfCAuaWQnKSIgXAogICAgfHwgZGllICJjb3VsZCBub3QgbGlzdCB0aGUgY2kgcnVucyBvZiAkc2hhIgogIGZvciBydW4gaW4gJHJ1bnM7IGRvCiAgICBqb2JzPSIkKGdoIGFwaSAicmVwb3MvJHJlcG8vYWN0aW9ucy9ydW5zLyRydW4vam9icz9wZXJfcGFnZT0xMDAiIC0tanEgJy5qb2JzW10gfCBzZWxlY3QoLmNvbmNsdXNpb24gPT0gInN1Y2Nlc3MiKSB8IC5uYW1lJykiIFwKICAgICAgfHwgZGllICJjb3VsZCBub3QgcmVhZCB0aGUgam9icyBvZiBjaSBydW4gJHJ1biIKICAgIGlmIHByaW50ZiAnJXNcbicgIiRqb2JzIiB8IGdyZXAgLXF4IGNoZWNrcyAmJiBwcmludGYgJyVzXG4nICIkam9icyIgfCBncmVwIC1xeCBlMmU7IHRoZW4KICAgICAgcnVuX29rPSIkcnVuIjsgYnJlYWsKICAgIGZpCiAgZG9uZQogIFsgLW4gIiRydW5fb2siIF0gfHwgZGllICJubyBzdWNjZXNzZnVsIGNpIHJ1biAoY2hlY2tzIGFuZCBlMmUpIG9uIGRldmVsb3AgZm9yICRzaGEiCiAgaGVhZD0iJChnaCBhcGkgInJlcG9zLyRyZXBvL2JyYW5jaGVzL2RldmVsb3AiIC0tanEgLmNvbW1pdC5zaGEpIiB8fCBkaWUgImNvdWxkIG5vdCByZWFkIHRoZSBoZWFkIG9mIGRldmVsb3AiCiAgY2hlY2tfc2hhICIkaGVhZCIKICBpZiBbICIkaGVhZCIgIT0gIiRzaGEiIF07IHRoZW4KICAgIHN0YXR1cz0iJChnaCBhcGkgInJlcG9zLyRyZXBvL2NvbXBhcmUvJGhlYWQuLi4kc2hhIiAtLWpxIC5zdGF0dXMpIiB8fCBkaWUgImNvdWxkIG5vdCBjb21wYXJlICRzaGEgd2l0aCBkZXZlbG9wIgogICAgWyAiJHN0YXR1cyIgPSBiZWhpbmQgXSB8fCBkaWUgIiRzaGEgaXMgbm90IG9uIGRldmVsb3AgKCRzdGF0dXMgcmVsYXRpdmUgdG8gJGhlYWQpIgogIGZpCiAgIyBtYXRjaGluZy1yZWZzIGFuc3dlcnMgYW4gZW1wdHkgbGlzdCB3aGVuIHRoZSB0YWcgZG9lcyBub3QgZXhpc3QgeWV0LCBzbyBhCiAgIyBmYWlsZWQgY2FsbCBpcyBuZXZlciBtaXN0YWtlbiBmb3IgYSBtaXNzaW5nIHRhZy4KICBwdWJsaXNoZWQ9IiQoZ2ggYXBpICJyZXBvcy8kcmVwby9naXQvbWF0Y2hpbmctcmVmcy90YWdzL2RldmVsb3AiIC0tanEgJy5bXSB8IHNlbGVjdCgucmVmID09ICJyZWZzL3RhZ3MvZGV2ZWxvcCIpIHwgLm9iamVjdC5zaGEnKSIgXAogICAgfHwgZGllICJjb3VsZCBub3QgcmVhZCB0aGUgZGV2ZWxvcCB0YWciCiAgaWYgWyAtbiAiJHB1Ymxpc2hlZCIgXSAmJiBbICIkcHVibGlzaGVkIiAhPSAiJHNoYSIgXTsgdGhlbgogICAgY2hlY2tfc2hhICIkcHVibGlzaGVkIgogICAgc3RhdHVzPSIkKGdoIGFwaSAicmVwb3MvJHJlcG8vY29tcGFyZS8kcHVibGlzaGVkLi4uJHNoYSIgLS1qcSAuc3RhdHVzKSIgfHwgZGllICJjb3VsZCBub3QgY29tcGFyZSAkc2hhIHdpdGggdGhlIHB1Ymxpc2hlZCAkcHVibGlzaGVkIgogICAgY2FzZSAiJHN0YXR1cyIgaW4KICAgICAgYmVoaW5kKQogICAgICAgIGVjaG8gInByZXJlbGVhc2U6IGRldmVsb3AgYWxyZWFkeSBuYW1lcyAkcHVibGlzaGVkLCBuZXdlciB0aGFuICRzaGE6IHNraXBwZWQiCiAgICAgICAgWyAteiAiJHtHSVRIVUJfT1VUUFVUOi19IiBdIHx8IGVjaG8gInB1Ymxpc2g9ZmFsc2UiID4+ICIkR0lUSFVCX09VVFBVVCIKICAgICAgICByZXR1cm4gOzsKICAgICAgYWhlYWR8ZGl2ZXJnZWQpIDs7CiAgICAgICopIGRpZSAidW5leHBlY3RlZCBjb21wYXJpc29uIG9mICRzaGEgd2l0aCB0aGUgcHVibGlzaGVkICRwdWJsaXNoZWQ6ICRzdGF0dXMiIDs7CiAgICBlc2FjCiAgZmkKICBlY2hvICJwcmVyZWxlYXNlOiAkc2hhIHBhc3NlZCBjaSBydW4gJHJ1bl9vayBhbmQgbWF5IGJlIHB1Ymxpc2hlZCIKICBbIC16ICIke0dJVEhVQl9PVVRQVVQ6LX0iIF0gfHwgZWNobyAicHVibGlzaD10cnVlIiA+PiAiJEdJVEhVQl9PVVRQVVQiCn0KCmNtZF9wdWJsaXNoKCkgewogIGxvY2FsIHRnej0iJHsxOj91c2FnZTogcHJlcmVsZWFzZS5zaCBwdWJsaXNoIDx0Z3o+IDxzaGE+fSIgc2hhPSIkezI6P2NvbW1pdCBTSEF9IiB2ZXJzaW9uIHRhZyBkaXIgcmVwbyBzdGF0ZSBhc3NldHMgZXhpc3RzCiAgY2hlY2tfc2hhICIkc2hhIgogIHZlcnNpb249IiQoY21kX3ZlcnNpb24pIgogIHRhZz0iJHtQUkVSRUxFQVNFX1RBRzotdiR2ZXJzaW9ufSIKICBkaXI9IiQoZGlybmFtZSAiJHRneiIpIgogIHJlcG89IiR7R0hfUkVQTzo/R0hfUkVQTyBpcyByZXF1aXJlZH0iCiAgZm9yIGYgaW4gIiR0Z3oiICIkdGd6LnNoYTI1NiIgIiRkaXIvQ09NTUlUIiAiJGRpci9wcmVyZWxlYXNlLW5vdGVzLm1kIjsgZG8KICAgIFsgLWYgIiRmIiBdIHx8IGRpZSAibWlzc2luZyAkZiAocnVuOiBwcmVyZWxlYXNlLnNoIHBhY2thZ2UgZmlyc3QpIgogIGRvbmUKCiAgaWYgc3RhdGU9IiQoZ2ggcmVsZWFzZSB2aWV3ICIkdGFnIiAtLWpzb24gaXNQcmVyZWxlYXNlLGlzRHJhZnQgLS1qcSAnIlwoLmlzUHJlcmVsZWFzZSkgXCguaXNEcmFmdCkiJyAyPi9kZXYvbnVsbCkiOyB0aGVuCiAgICBbICIkc3RhdGUiID0gInRydWUgZmFsc2UiIF0gfHwgZGllICJyZWxlYXNlICR0YWcgZXhpc3RzIGFuZCBpcyBub3QgYSBwdWJsaXNoZWQgcHJlcmVsZWFzZSAoJHN0YXRlKTogbGVmdCBhbG9uZSIKICAgICMgR29uZSB3aGlsZSB0aGUgYXJjaGl2ZSBjaGFuZ2VzOiBhIHJlYWRlciB0aGF0IGZpbmRzIENPTU1JVCBmaW5kcyBpdHMgYXJjaGl2ZS4KICAgIGFzc2V0cz0iJChnaCByZWxlYXNlIHZpZXcgIiR0YWciIC0tanNvbiBhc3NldHMgLS1qcSAnLmFzc2V0c1tdLm5hbWUnKSIKICAgIGlmIHByaW50ZiAnJXNcbicgIiRhc3NldHMiIHwgZ3JlcCAtcXggQ09NTUlUOyB0aGVuCiAgICAgIGdoIHJlbGVhc2UgZGVsZXRlLWFzc2V0ICIkdGFnIiBDT01NSVQgLS15ZXMKICAgIGZpCiAgICBleGlzdHM9MQogIGVsc2UKICAgIGV4aXN0cz0wCiAgZmkKCiAgIyBUaGUgdGFnIGZvbGxvd3MgdGhlIHB1c2hlZCBjb21taXQuIE1hZGUgd2l0aCB0aGUgd29ya2Zsb3cncyB0b2tlbiwgaXQgc3RhcnRzCiAgIyBubyBvdGhlciB3b3JrZmxvdyAocmVsZWFzZS55bWwgYW5kIG5wbS55bWwgbGlzdGVuIHRvIHYqIHRhZ3MpLgogIGlmIGdoIGFwaSAicmVwb3MvJHJlcG8vZ2l0L3JlZnMvdGFncy8kdGFnIiA+L2Rldi9udWxsIDI+JjE7IHRoZW4KICAgIGdoIGFwaSAtWCBQQVRDSCAicmVwb3MvJHJlcG8vZ2l0L3JlZnMvdGFncy8kdGFnIiAtZiBzaGE9IiRzaGEiIC1GIGZvcmNlPXRydWUgPi9kZXYvbnVsbAogIGVsc2UKICAgIGdoIGFwaSAtWCBQT1NUICJyZXBvcy8kcmVwby9naXQvcmVmcyIgLWYgcmVmPSJyZWZzL3RhZ3MvJHRhZyIgLWYgc2hhPSIkc2hhIiA+L2Rldi9udWxsCiAgZmkKCiAgaWYgWyAiJGV4aXN0cyIgPSAxIF07IHRoZW4KICAgIGdoIHJlbGVhc2UgZWRpdCAiJHRhZyIgLS1wcmVyZWxlYXNlIC0tbGF0ZXN0PWZhbHNlIC0tdGl0bGUgIndoZXJkciAkdmVyc2lvbiIgLS1ub3Rlcy1maWxlICIkZGlyL3ByZXJlbGVhc2Utbm90ZXMubWQiCiAgZWxzZQogICAgZ2ggcmVsZWFzZSBjcmVhdGUgIiR0YWciIC0tdmVyaWZ5LXRhZyAtLXByZXJlbGVhc2UgLS1sYXRlc3Q9ZmFsc2UgLS10aXRsZSAid2hlcmRyICR2ZXJzaW9uIiAtLW5vdGVzLWZpbGUgIiRkaXIvcHJlcmVsZWFzZS1ub3Rlcy5tZCIKICBmaQogIGdoIHJlbGVhc2UgdXBsb2FkICIkdGFnIiAiJHRneiIgIiR0Z3ouc2hhMjU2IiAtLWNsb2JiZXIKICAjIEtlZXAgZXhhY3RseSBvbmUgYXJjaGl2ZSBhbmQgY2hlY2tzdW0gb24gdGhlIGZpeGVkIGNoYW5uZWwgYWZ0ZXIgdmVyc2lvbiBidW1wcy4KICBpZiBbICIkZXhpc3RzIiA9IDEgXSAmJiBbICIkdGFnIiA9IGRldmVsb3AgXTsgdGhlbgogICAgd2hpbGUgSUZTPSByZWFkIC1yIGFzc2V0OyBkbwogICAgICBjYXNlICIkYXNzZXQiIGluCiAgICAgICAgd2hlcmRyLSoudGd6fHdoZXJkci0qLnRnei5zaGEyNTYpCiAgICAgICAgICBbICIkYXNzZXQiID0gIiQoYmFzZW5hbWUgIiR0Z3oiKSIgXSB8fCBbICIkYXNzZXQiID0gIiQoYmFzZW5hbWUgIiR0Z3oiKS5zaGEyNTYiIF0gXAogICAgICAgICAgICB8fCBnaCByZWxlYXNlIGRlbGV0ZS1hc3NldCAiJHRhZyIgIiRhc3NldCIgLS15ZXMgOzsKICAgICAgZXNhYwogICAgZG9uZSA8PDwgIiRhc3NldHMiCiAgZmkKICBnaCByZWxlYXNlIHVwbG9hZCAiJHRhZyIgIiRkaXIvQ09NTUlUIiAtLWNsb2JiZXIKICBlY2hvICJwcmVyZWxlYXNlOiAkdGFnIG5vdyBhdCAkc2hhIgp9CgpjYXNlICIkezE6LX0iIGluCiAgdmVyc2lvbikgY21kX3ZlcnNpb24gOzsKICBnYXRlKSBzaGlmdDsgY21kX2dhdGUgIiRAIiA7OwogIHBhY2thZ2UpIHNoaWZ0OyBjbWRfcGFja2FnZSAiJEAiIDs7CiAgcHVibGlzaCkgc2hpZnQ7IGNtZF9wdWJsaXNoICIkQCIgOzsKICAqKSBkaWUgInVzYWdlOiAkMCB2ZXJzaW9uIHwgZ2F0ZSA8c2hhPiB8IHBhY2thZ2UgPHRnej4gPHNoYT4gfCBwdWJsaXNoIDx0Z3o+IDxzaGE+IiA7Owplc2FjCg==");
|
|
5
5
|
|
|
6
6
|
export { prerelease as default };
|
|
7
7
|
//# sourceMappingURL=prerelease.mjs.map
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// ROLLUP_NO_REPLACE
|
|
2
|
-
const testAffected = "#!/usr/bin/env node\nimport { spawnSync } from 'node:child_process'\nimport { existsSync, readdirSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { pathToFileURL, fileURLToPath } from 'node:url'\nimport net from 'node:net'\n\n// Reviewed supplements to Vitest's import graph: Nuxt auto-imports, templates,\n// CSS and transport boundaries are not ordinary static imports.\nexport const domains = [\n { name: 'references', source: /(?:reference|Composer|ChatMarkdown|QuotedText|UserText)/i, tests: /(?:reference|Composer|ChatMarkdown|QuotedText|UserText|quote)/i, e2e: ['reference', 'send-message'], reason: 'References cross templates, composer state and the send boundary.' },\n { name: 'guards', source: /(?:server\\/api\\/(?:prompt|input|choose|menu|nav)|Identity|guardedSend)/i, tests: /(?:guard|Identity|stoppedAgent|agentPrompt|menuRoute)/i, e2e: ['pane-replaced', 'question-reply'], reason: 'Identity and stale actions must be checked through transport.' },\n { name: 'terminal', source: /terminal|server\\/routes\\/.*ws/i, tests: /terminal/i, e2e: ['interactive-terminal', 'terminal-size'], reason: 'Terminal rendering and websocket lifecycle cross the built app.' },\n { name: 'board', source: /board|machine|TaskPanel|TaskSheet|ProjectGroup/i, tests: /board|machine|TaskPanel|TaskSheet|ProjectGroup/i, e2e: ['machine-groups', 'projects-1x'], reason: 'Board auto-imports and cross-machine navigation need explicit coverage.' },\n { name: 'startup', source: /router|app\\.vue|onboarding|app\\/plugins/i, tests: /onboarding|directRoute|stateReady/i, e2e: ['startup-hash', 'onboarding'], reason: 'Startup and routing depend on Nuxt registration.' },\n { name: 'appearance', source: /app\\/assets\\/|themes?\\.|font/i, tests: /layout|sheet|CompactDefault|ChatViewRendering|SettingsTyping|Composer|BoardPanel/i, e2e: ['theme', 'sheet-close'], reason: 'CSS and themes affect layout and overlays without import edges.' },\n { name: 'chat-rendering', source: /ChatView|OmpTool|Settings/i, tests: /ChatViewRendering|CompactDefault|SettingsTyping|OmpTool|settings/i, e2e: ['settings-tabs', 'tool-images'], reason: 'Rendering assertions moved from e2e to components; retain integration boundaries.' },\n]\nconst doc = p => /\\.(md|rst)$/.test(p) || /^docs\\//.test(p)\nconst test = p => /\\.test\\.[cm]?[jt]s$/.test(p)\nconst e2e = p => /^tests\\/e2e\\/.*\\.spec\\.ts$/.test(p)\nexport const literalPattern = p => p.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n\nexport function parseChanges(output) {\n const fields = output.split('\\0'); const paths = []\n for (let i = 0; i < fields.length && fields[i];) {\n const status = fields[i++]\n paths.push(fields[i++])\n if (/^[RC]/.test(status)) paths.push(fields[i++])\n }\n return paths.filter(Boolean)\n}\nfunction git(args, cwd) {\n const result = spawnSync('git', args, { cwd, encoding: 'utf8' })\n if (result.status !== 0) throw new Error(result.stderr.trim() || 'Git command failed')\n return result.stdout\n}\nexport function changedFiles(base, cwd = process.cwd()) {\n let warning\n let committed = []\n try {\n const ancestor = git(['merge-base', 'HEAD', base], cwd).trim()\n committed = parseChanges(git(['diff', '--name-status', '-z', '--find-renames', ancestor, 'HEAD', '--'], cwd))\n } catch {\n warning = `Cannot resolve merge-base with ${base}; fetch the target branch. Selecting broad coverage.`\n }\n return {\n warning,\n files: [...new Set([...committed,\n ...parseChanges(git(['diff', '--name-status', '-z', '--find-renames', 'HEAD', '--'], cwd)),\n ...parseChanges(git(['diff', '--cached', '--name-status', '-z', '--find-renames', '--'], cwd)),\n ...git(['ls-files', '--others', '--exclude-standard', '-z'], cwd).split('\\0').filter(Boolean),\n ])].sort(),\n }\n}\nexport function inventory(dir = 'tests') {\n return readdirSync(dir, { withFileTypes: true }).flatMap(entry => {\n const p = `${dir}/${entry.name}`\n return entry.isDirectory() ? inventory(p) : [p]\n })\n}\nexport function select(files, available, warning) {\n const unit = new Map(); const browser = new Map(); const selectedDomains = new Map(); const related = []\n let broad = Boolean(warning)\n const add = (map, p, reason) => map.set(p, [...new Set([...(map.get(p) || []), reason])])\n for (const file of files) {\n if (doc(file)) continue\n if ((test(file) || e2e(file)) && available.includes(file)) {\n add(e2e(file) ? browser : unit, file, 'Changed test: run explicitly.'); continue\n }\n const matches = domains.filter(d => d.source.test(file))\n if (!matches.length || /(?:package(?:-lock)?\\.json|(?:nuxt|vitest|playwright)\\.config|tests\\/e2e\\/|app\\/plugins\\/|transport)/.test(file)) broad = true\n if (available.includes(file) && !test(file) && !e2e(file)) related.push(file)\n for (const d of matches) {\n selectedDomains.set(d.name, d.reason)\n for (const p of available) {\n if (test(p) && d.tests.test(p)) add(unit, p, d.reason)\n if (d.e2e.some(name => p === `tests/e2e/${name}.spec.ts`)) add(browser, p, d.reason)\n }\n }\n }\n if (broad) {\n const reason = warning || 'Unknown, deleted test or shared infrastructure: conservative fallback.'\n selectedDomains.set('fallback', reason)\n for (const p of available) if (test(p)) add(unit, p, reason)\n const smoke = 'tests/e2e/startup-hash.spec.ts'\n if (available.includes(smoke)) add(browser, smoke, reason)\n }\n if (files.some(p => !doc(p)) && !unit.size && !browser.size) throw new Error('Unexpected empty selection; update the domain table.')\n return { files, domains: Object.fromEntries(selectedDomains), related: broad ? [] : related, tests: Object.fromEntries(unit), e2e: Object.fromEntries(browser), broad, warning }\n}\nfunction assertFocusedE2E(specs) {\n const all = inventory().filter(e2e)\n if (all.length > 1 && all.every(p => specs.includes(p))) {\n throw new Error('Refusing the full Playwright suite locally; leave it to CI and review a smaller selection.')\n }\n}\nfunction run(command, args, env = process.env) {\n const result = spawnSync('flock', ['/tmp/wherdr-heavy.lock', command, ...args], { stdio: 'inherit', env })\n if (result.error) throw result.error\n if (result.status !== 0) throw new Error(`${command} failed (${result.status ?? result.signal})`)\n}\nasync function freePort() {\n for (let port = 7690; port <= 7699; port++) {\n const free = await new Promise(resolve => {\n const server = net.createServer()\n server.once('error', () => resolve(false))\n server.listen(port, '127.0.0.1', () => server.close(() => resolve(true)))\n })\n if (free) return String(port)\n }\n throw new Error('No free E2E_PORT in 7690–7699')\n}\nexport async function main(args = process.argv.slice(2)) {\n let base; let dry = false; let project = 'chromium-phone'\n for (let i = 0; i < args.length; i++) {\n if (args[i] === '--base') base = args[++i]\n else if (args[i] === '--dry-run') dry = true\n else if (args[i] === '--safari') project = 'webkit-phone'\n else throw new Error(`Unknown option: ${args[i]}`)\n }\n if (!base || base.startsWith('-')) throw new Error('Usage: npm run test:affected -- --base <target-branch> [--dry-run] [--safari]')\n const changes = changedFiles(base)\n const plan = select(changes.files, [...new Set([...inventory(), ...changes.files.filter(p => existsSync(p))])], changes.warning)\n console.log(JSON.stringify({ ...plan, project }, null, 2))\n if (plan.broad) console.log('CI must run the complete reduced suite. Local fallback adds all Vitest tests and a startup e2e smoke; review additional journeys manually.')\n if (!plan.files.length && !plan.warning) console.log('No changed files.')\n else if (!Object.keys(plan.tests).length && !Object.keys(plan.e2e).length) console.log('Documentation only: no tests or browser required.')\n if (dry) return\n assertFocusedE2E(Object.keys(plan.e2e))\n const tests = Object.keys(plan.tests)\n // Explicit domain tests run once below; related supplies only additional tests.\n // An empty related graph is allowed because explicit coverage is already selected.\n if (plan.related.length) run('npx', ['--no-install', 'vitest', 'related', '--run', '--passWithNoTests', ...tests.flatMap(p => ['--exclude', p]), ...plan.related.map(p => `./${p}`)])\n if (tests.length) run('npx', ['--no-install', 'vitest', 'run', ...tests])\n const specs = Object.keys(plan.e2e)\n if (specs.length) {\n const env = { ...process.env, E2E_SCOPE: 'full' }\n // One lock covers build and browser run, including the shared .e2e-tmp directory.\n run(process.execPath, [fileURLToPath(import.meta.url), '--execute-e2e', project, ...specs], env)\n }\n}\nif (process.argv[2] === '--execute-e2e') {\n const [, , , project, ...specs] = process.argv\n if (!['chromium-phone', 'webkit-phone'].includes(project) || !specs.length || specs.some(p => !e2e(p) || !existsSync(p))) {\n console.error('Refusing an empty or invalid e2e selection.'); process.exit(1)\n }\n assertFocusedE2E(specs)\n const build = spawnSync('npm', ['run', 'build'], { stdio: 'inherit' })\n if (build.status !== 0) process.exit(build.status || 1)\n const port = await freePort()\n const result = spawnSync('npx', ['--no-install', 'playwright', 'test', ...specs.map(p => `${literalPattern(p)}$`), '--project', project], { stdio: 'inherit', env: { ...process.env, E2E_PORT: port } })\n process.exit(result.status ?? 1)\n} else if (process.argv[1] && import.meta.url === pathToFileURL(resolve(process.argv[1])).href) {\n main().catch(error => { console.error(error.message); process.exitCode = 1 })\n}\n";
|
|
2
|
+
const testAffected = "#!/usr/bin/env node\nimport { spawnSync } from 'node:child_process'\nimport { existsSync, readdirSync } from 'node:fs'\nimport { resolve } from 'node:path'\nimport { pathToFileURL, fileURLToPath } from 'node:url'\nimport net from 'node:net'\n\n// Reviewed supplements to Vitest's import graph: Nuxt auto-imports, templates,\n// CSS and transport boundaries are not ordinary static imports.\nexport const domains = [\n { name: 'references', source: /(?:reference|Composer|ChatMarkdown|QuotedText|UserText)/i, tests: /(?:reference|Composer|ChatMarkdown|QuotedText|UserText|quote)/i, e2e: ['reference', 'send-message'], reason: 'References cross templates, composer state and the send boundary.' },\n { name: 'guards', source: /(?:server\\/api\\/(?:prompt|input|choose|menu|nav)|Identity|guardedSend)/i, tests: /(?:guard|Identity|stoppedAgent|agentPrompt|menuRoute)/i, e2e: ['pane-replaced', 'question-reply'], reason: 'Identity and stale actions must be checked through transport.' },\n { name: 'terminal', source: /terminal|server\\/routes\\/.*ws/i, tests: /terminal/i, e2e: ['interactive-terminal', 'terminal-size'], reason: 'Terminal rendering and websocket lifecycle cross the built app.' },\n { name: 'board', source: /board|machine|TaskPanel|TaskSheet|ProjectGroup/i, tests: /board|machine|TaskPanel|TaskSheet|ProjectGroup/i, e2e: ['machine-groups', 'projects-1x'], reason: 'Board auto-imports and cross-machine navigation need explicit coverage.' },\n { name: 'startup', source: /router|app\\.vue|onboarding|app\\/plugins/i, tests: /onboarding|directRoute|stateReady/i, e2e: ['startup-hash', 'onboarding'], reason: 'Startup and routing depend on Nuxt registration.' },\n { name: 'appearance', source: /app\\/assets\\/|themes?\\.|font/i, tests: /layout|sheet|CompactDefault|ChatViewRendering|SettingsTyping|Composer|BoardPanel/i, e2e: ['theme', 'sheet-close'], reason: 'CSS and themes affect layout and overlays without import edges.' },\n { name: 'chat-rendering', source: /ChatView|OmpTool|Settings/i, tests: /ChatViewRendering|CompactDefault|SettingsTyping|OmpTool|settings/i, e2e: ['settings-tabs', 'tool-images'], reason: 'Rendering assertions moved from e2e to components; retain integration boundaries.' },\n]\nconst doc = p => /\\.(md|rst)$/.test(p) || /^docs\\//.test(p)\nconst test = p => /\\.test\\.[cm]?[jt]s$/.test(p)\nconst e2e = p => /^tests\\/e2e\\/.*\\.spec\\.ts$/.test(p)\nexport const literalPattern = p => p.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n\nexport function parseChanges(output) {\n const fields = output.split('\\0'); const paths = []\n for (let i = 0; i < fields.length && fields[i];) {\n const status = fields[i++]\n paths.push(fields[i++])\n if (/^[RC]/.test(status)) paths.push(fields[i++])\n }\n return paths.filter(Boolean)\n}\nfunction git(args, cwd) {\n const result = spawnSync('git', args, { cwd, encoding: 'utf8' })\n if (result.status !== 0) throw new Error(result.stderr.trim() || 'Git command failed')\n return result.stdout\n}\nexport function changedFiles(base, cwd = process.cwd()) {\n let warning\n let committed = []\n try {\n const ancestor = git(['merge-base', 'HEAD', base], cwd).trim()\n committed = parseChanges(git(['diff', '--name-status', '-z', '--find-renames', ancestor, 'HEAD', '--'], cwd))\n } catch {\n warning = `Cannot resolve merge-base with ${base}; fetch the target branch. Selecting broad coverage.`\n }\n return {\n warning,\n files: [...new Set([...committed,\n ...parseChanges(git(['diff', '--name-status', '-z', '--find-renames', 'HEAD', '--'], cwd)),\n ...parseChanges(git(['diff', '--cached', '--name-status', '-z', '--find-renames', '--'], cwd)),\n ...git(['ls-files', '--others', '--exclude-standard', '-z'], cwd).split('\\0').filter(Boolean),\n ])].sort(),\n }\n}\nexport function inventory(dir = 'tests') {\n return readdirSync(dir, { withFileTypes: true }).flatMap(entry => {\n const p = `${dir}/${entry.name}`\n return entry.isDirectory() ? inventory(p) : [p]\n })\n}\nexport function select(files, available, warning) {\n const unit = new Map(); const browser = new Map(); const selectedDomains = new Map(); const related = []\n let broad = Boolean(warning)\n const add = (map, p, reason) => map.set(p, [...new Set([...(map.get(p) || []), reason])])\n for (const file of files) {\n // Rust tests are selected by the conditional engine workflow, not Vitest.\n if (file.startsWith('engine/')) continue\n if (doc(file)) continue\n if ((test(file) || e2e(file)) && available.includes(file)) {\n add(e2e(file) ? browser : unit, file, 'Changed test: run explicitly.'); continue\n }\n const matches = domains.filter(d => d.source.test(file))\n if (!matches.length || /(?:package(?:-lock)?\\.json|(?:nuxt|vitest|playwright)\\.config|tests\\/e2e\\/|app\\/plugins\\/|transport)/.test(file)) broad = true\n if (available.includes(file) && !test(file) && !e2e(file)) related.push(file)\n for (const d of matches) {\n selectedDomains.set(d.name, d.reason)\n for (const p of available) {\n if (test(p) && d.tests.test(p)) add(unit, p, d.reason)\n if (d.e2e.some(name => p === `tests/e2e/${name}.spec.ts`)) add(browser, p, d.reason)\n }\n }\n }\n if (broad) {\n const reason = warning || 'Unknown, deleted test or shared infrastructure: conservative fallback.'\n selectedDomains.set('fallback', reason)\n for (const p of available) if (test(p)) add(unit, p, reason)\n const smoke = 'tests/e2e/startup-hash.spec.ts'\n if (available.includes(smoke)) add(browser, smoke, reason)\n }\n if (files.some(p => !doc(p) && !p.startsWith('engine/')) && !unit.size && !browser.size) throw new Error('Unexpected empty selection; update the domain table.')\n return { files, domains: Object.fromEntries(selectedDomains), related: broad ? [] : related, tests: Object.fromEntries(unit), e2e: Object.fromEntries(browser), broad, warning }\n}\nfunction assertFocusedE2E(specs) {\n const all = inventory().filter(e2e)\n if (all.length > 1 && all.every(p => specs.includes(p))) {\n throw new Error('Refusing the full Playwright suite locally; leave it to CI and review a smaller selection.')\n }\n}\nfunction run(command, args, env = process.env) {\n const result = spawnSync('flock', ['/tmp/wherdr-heavy.lock', command, ...args], { stdio: 'inherit', env })\n if (result.error) throw result.error\n if (result.status !== 0) throw new Error(`${command} failed (${result.status ?? result.signal})`)\n}\nasync function freePort() {\n for (let port = 7690; port <= 7699; port++) {\n const free = await new Promise(resolve => {\n const server = net.createServer()\n server.once('error', () => resolve(false))\n server.listen(port, '127.0.0.1', () => server.close(() => resolve(true)))\n })\n if (free) return String(port)\n }\n throw new Error('No free E2E_PORT in 7690–7699')\n}\nexport async function main(args = process.argv.slice(2)) {\n let base; let dry = false; let project = 'chromium-phone'\n for (let i = 0; i < args.length; i++) {\n if (args[i] === '--base') base = args[++i]\n else if (args[i] === '--dry-run') dry = true\n else if (args[i] === '--safari') project = 'webkit-phone'\n else throw new Error(`Unknown option: ${args[i]}`)\n }\n if (!base || base.startsWith('-')) throw new Error('Usage: npm run test:affected -- --base <target-branch> [--dry-run] [--safari]')\n const changes = changedFiles(base)\n const plan = select(changes.files, [...new Set([...inventory(), ...changes.files.filter(p => existsSync(p))])], changes.warning)\n console.log(JSON.stringify({ ...plan, project }, null, 2))\n if (plan.broad) console.log('CI must run the complete reduced suite. Local fallback adds all Vitest tests and a startup e2e smoke; review additional journeys manually.')\n if (!plan.files.length && !plan.warning) console.log('No changed files.')\n else if (!Object.keys(plan.tests).length && !Object.keys(plan.e2e).length) console.log('Documentation or engine only: no JS tests or browser required.')\n if (dry) return\n assertFocusedE2E(Object.keys(plan.e2e))\n const tests = Object.keys(plan.tests)\n // Explicit domain tests run once below; related supplies only additional tests.\n // An empty related graph is allowed because explicit coverage is already selected.\n if (plan.related.length) run('npx', ['--no-install', 'vitest', 'related', '--run', '--passWithNoTests', ...tests.flatMap(p => ['--exclude', p]), ...plan.related.map(p => `./${p}`)])\n if (tests.length) run('npx', ['--no-install', 'vitest', 'run', ...tests])\n const specs = Object.keys(plan.e2e)\n if (specs.length) {\n const env = { ...process.env, E2E_SCOPE: 'full' }\n // One lock covers build and browser run, including the shared .e2e-tmp directory.\n run(process.execPath, [fileURLToPath(import.meta.url), '--execute-e2e', project, ...specs], env)\n }\n}\nif (process.argv[2] === '--execute-e2e') {\n const [, , , project, ...specs] = process.argv\n if (!['chromium-phone', 'webkit-phone'].includes(project) || !specs.length || specs.some(p => !e2e(p) || !existsSync(p))) {\n console.error('Refusing an empty or invalid e2e selection.'); process.exit(1)\n }\n assertFocusedE2E(specs)\n const build = spawnSync('npm', ['run', 'build'], { stdio: 'inherit' })\n if (build.status !== 0) process.exit(build.status || 1)\n const port = await freePort()\n const result = spawnSync('npx', ['--no-install', 'playwright', 'test', ...specs.map(p => `${literalPattern(p)}$`), '--project', project], { stdio: 'inherit', env: { ...process.env, E2E_PORT: port } })\n process.exit(result.status ?? 1)\n} else if (process.argv[1] && import.meta.url === pathToFileURL(resolve(process.argv[1])).href) {\n main().catch(error => { console.error(error.message); process.exitCode = 1 })\n}\n";
|
|
3
3
|
|
|
4
4
|
export { testAffected as default };
|
|
5
5
|
//# sourceMappingURL=test-affected.mjs.map
|
|
@@ -17,16 +17,16 @@ import 'node:buffer';
|
|
|
17
17
|
import 'node:fs';
|
|
18
18
|
import 'node:path';
|
|
19
19
|
import 'node:os';
|
|
20
|
-
import 'node:net';
|
|
21
20
|
import 'node:child_process';
|
|
22
21
|
import 'node:dns';
|
|
23
22
|
import 'node:util';
|
|
23
|
+
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
24
|
+
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
24
25
|
import 'web-push';
|
|
26
|
+
import 'node:net';
|
|
25
27
|
import 'node:string_decoder';
|
|
26
28
|
import 'node:fs/promises';
|
|
27
29
|
import 'node:readline';
|
|
28
|
-
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
29
|
-
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
30
30
|
import 'node:url';
|
|
31
31
|
import 'node:zlib';
|
|
32
32
|
import '@simplewebauthn/server';
|
|
@@ -17,16 +17,16 @@ import 'node:buffer';
|
|
|
17
17
|
import 'node:fs';
|
|
18
18
|
import 'node:path';
|
|
19
19
|
import 'node:os';
|
|
20
|
-
import 'node:net';
|
|
21
20
|
import 'node:child_process';
|
|
22
21
|
import 'node:dns';
|
|
23
22
|
import 'node:util';
|
|
23
|
+
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
24
|
+
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
24
25
|
import 'web-push';
|
|
26
|
+
import 'node:net';
|
|
25
27
|
import 'node:string_decoder';
|
|
26
28
|
import 'node:fs/promises';
|
|
27
29
|
import 'node:readline';
|
|
28
|
-
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
29
|
-
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
30
30
|
import 'node:url';
|
|
31
31
|
import 'node:zlib';
|
|
32
32
|
import '@simplewebauthn/server';
|
|
@@ -17,16 +17,16 @@ import 'node:buffer';
|
|
|
17
17
|
import 'node:fs';
|
|
18
18
|
import 'node:path';
|
|
19
19
|
import 'node:os';
|
|
20
|
-
import 'node:net';
|
|
21
20
|
import 'node:child_process';
|
|
22
21
|
import 'node:dns';
|
|
23
22
|
import 'node:util';
|
|
23
|
+
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
24
|
+
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
24
25
|
import 'web-push';
|
|
26
|
+
import 'node:net';
|
|
25
27
|
import 'node:string_decoder';
|
|
26
28
|
import 'node:fs/promises';
|
|
27
29
|
import 'node:readline';
|
|
28
|
-
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
29
|
-
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
30
30
|
import 'node:url';
|
|
31
31
|
import 'node:zlib';
|
|
32
32
|
import '@simplewebauthn/server';
|
|
@@ -17,16 +17,16 @@ import 'node:buffer';
|
|
|
17
17
|
import 'node:fs';
|
|
18
18
|
import 'node:path';
|
|
19
19
|
import 'node:os';
|
|
20
|
-
import 'node:net';
|
|
21
20
|
import 'node:child_process';
|
|
22
21
|
import 'node:dns';
|
|
23
22
|
import 'node:util';
|
|
23
|
+
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
24
|
+
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
24
25
|
import 'web-push';
|
|
26
|
+
import 'node:net';
|
|
25
27
|
import 'node:string_decoder';
|
|
26
28
|
import 'node:fs/promises';
|
|
27
29
|
import 'node:readline';
|
|
28
|
-
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
29
|
-
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
30
30
|
import 'node:url';
|
|
31
31
|
import 'node:zlib';
|
|
32
32
|
import '@simplewebauthn/server';
|
|
@@ -17,16 +17,16 @@ import 'node:buffer';
|
|
|
17
17
|
import 'node:fs';
|
|
18
18
|
import 'node:path';
|
|
19
19
|
import 'node:os';
|
|
20
|
-
import 'node:net';
|
|
21
20
|
import 'node:child_process';
|
|
22
21
|
import 'node:dns';
|
|
23
22
|
import 'node:util';
|
|
23
|
+
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
24
|
+
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
24
25
|
import 'web-push';
|
|
26
|
+
import 'node:net';
|
|
25
27
|
import 'node:string_decoder';
|
|
26
28
|
import 'node:fs/promises';
|
|
27
29
|
import 'node:readline';
|
|
28
|
-
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
29
|
-
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
30
30
|
import 'node:url';
|
|
31
31
|
import 'node:zlib';
|
|
32
32
|
import '@simplewebauthn/server';
|
|
@@ -17,16 +17,16 @@ import 'node:buffer';
|
|
|
17
17
|
import 'node:fs';
|
|
18
18
|
import 'node:path';
|
|
19
19
|
import 'node:os';
|
|
20
|
-
import 'node:net';
|
|
21
20
|
import 'node:child_process';
|
|
22
21
|
import 'node:dns';
|
|
23
22
|
import 'node:util';
|
|
23
|
+
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
24
|
+
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
24
25
|
import 'web-push';
|
|
26
|
+
import 'node:net';
|
|
25
27
|
import 'node:string_decoder';
|
|
26
28
|
import 'node:fs/promises';
|
|
27
29
|
import 'node:readline';
|
|
28
|
-
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
29
|
-
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
30
30
|
import 'node:url';
|
|
31
31
|
import 'node:zlib';
|
|
32
32
|
import '@simplewebauthn/server';
|
|
@@ -17,16 +17,16 @@ import 'node:buffer';
|
|
|
17
17
|
import 'node:fs';
|
|
18
18
|
import 'node:path';
|
|
19
19
|
import 'node:os';
|
|
20
|
-
import 'node:net';
|
|
21
20
|
import 'node:child_process';
|
|
22
21
|
import 'node:dns';
|
|
23
22
|
import 'node:util';
|
|
23
|
+
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
24
|
+
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
24
25
|
import 'web-push';
|
|
26
|
+
import 'node:net';
|
|
25
27
|
import 'node:string_decoder';
|
|
26
28
|
import 'node:fs/promises';
|
|
27
29
|
import 'node:readline';
|
|
28
|
-
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
29
|
-
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
30
30
|
import 'node:url';
|
|
31
31
|
import 'node:zlib';
|
|
32
32
|
import '@simplewebauthn/server';
|
|
@@ -17,16 +17,16 @@ import 'node:buffer';
|
|
|
17
17
|
import 'node:fs';
|
|
18
18
|
import 'node:path';
|
|
19
19
|
import 'node:os';
|
|
20
|
-
import 'node:net';
|
|
21
20
|
import 'node:child_process';
|
|
22
21
|
import 'node:dns';
|
|
23
22
|
import 'node:util';
|
|
23
|
+
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
24
|
+
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
24
25
|
import 'web-push';
|
|
26
|
+
import 'node:net';
|
|
25
27
|
import 'node:string_decoder';
|
|
26
28
|
import 'node:fs/promises';
|
|
27
29
|
import 'node:readline';
|
|
28
|
-
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
29
|
-
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
30
30
|
import 'node:url';
|
|
31
31
|
import 'node:zlib';
|
|
32
32
|
import '@simplewebauthn/server';
|
|
@@ -17,16 +17,16 @@ import 'node:buffer';
|
|
|
17
17
|
import 'node:fs';
|
|
18
18
|
import 'node:path';
|
|
19
19
|
import 'node:os';
|
|
20
|
-
import 'node:net';
|
|
21
20
|
import 'node:child_process';
|
|
22
21
|
import 'node:dns';
|
|
23
22
|
import 'node:util';
|
|
23
|
+
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
24
|
+
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
24
25
|
import 'web-push';
|
|
26
|
+
import 'node:net';
|
|
25
27
|
import 'node:string_decoder';
|
|
26
28
|
import 'node:fs/promises';
|
|
27
29
|
import 'node:readline';
|
|
28
|
-
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
29
|
-
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
30
30
|
import 'node:url';
|
|
31
31
|
import 'node:zlib';
|
|
32
32
|
import '@simplewebauthn/server';
|
|
@@ -17,16 +17,16 @@ import 'node:buffer';
|
|
|
17
17
|
import 'node:fs';
|
|
18
18
|
import 'node:path';
|
|
19
19
|
import 'node:os';
|
|
20
|
-
import 'node:net';
|
|
21
20
|
import 'node:child_process';
|
|
22
21
|
import 'node:dns';
|
|
23
22
|
import 'node:util';
|
|
23
|
+
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
24
|
+
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
24
25
|
import 'web-push';
|
|
26
|
+
import 'node:net';
|
|
25
27
|
import 'node:string_decoder';
|
|
26
28
|
import 'node:fs/promises';
|
|
27
29
|
import 'node:readline';
|
|
28
|
-
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
29
|
-
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
30
30
|
import 'node:url';
|
|
31
31
|
import 'node:zlib';
|
|
32
32
|
import '@simplewebauthn/server';
|
|
@@ -17,16 +17,16 @@ import 'node:buffer';
|
|
|
17
17
|
import 'node:fs';
|
|
18
18
|
import 'node:path';
|
|
19
19
|
import 'node:os';
|
|
20
|
-
import 'node:net';
|
|
21
20
|
import 'node:child_process';
|
|
22
21
|
import 'node:dns';
|
|
23
22
|
import 'node:util';
|
|
23
|
+
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
24
|
+
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
24
25
|
import 'web-push';
|
|
26
|
+
import 'node:net';
|
|
25
27
|
import 'node:string_decoder';
|
|
26
28
|
import 'node:fs/promises';
|
|
27
29
|
import 'node:readline';
|
|
28
|
-
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
29
|
-
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
30
30
|
import 'node:url';
|
|
31
31
|
import 'node:zlib';
|
|
32
32
|
import '@simplewebauthn/server';
|
|
@@ -17,16 +17,16 @@ import 'node:buffer';
|
|
|
17
17
|
import 'node:fs';
|
|
18
18
|
import 'node:path';
|
|
19
19
|
import 'node:os';
|
|
20
|
-
import 'node:net';
|
|
21
20
|
import 'node:child_process';
|
|
22
21
|
import 'node:dns';
|
|
23
22
|
import 'node:util';
|
|
23
|
+
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
24
|
+
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
24
25
|
import 'web-push';
|
|
26
|
+
import 'node:net';
|
|
25
27
|
import 'node:string_decoder';
|
|
26
28
|
import 'node:fs/promises';
|
|
27
29
|
import 'node:readline';
|
|
28
|
-
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
29
|
-
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
30
30
|
import 'node:url';
|
|
31
31
|
import 'node:zlib';
|
|
32
32
|
import '@simplewebauthn/server';
|
|
@@ -17,16 +17,16 @@ import 'node:buffer';
|
|
|
17
17
|
import 'node:fs';
|
|
18
18
|
import 'node:path';
|
|
19
19
|
import 'node:os';
|
|
20
|
-
import 'node:net';
|
|
21
20
|
import 'node:child_process';
|
|
22
21
|
import 'node:dns';
|
|
23
22
|
import 'node:util';
|
|
23
|
+
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
24
|
+
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
24
25
|
import 'web-push';
|
|
26
|
+
import 'node:net';
|
|
25
27
|
import 'node:string_decoder';
|
|
26
28
|
import 'node:fs/promises';
|
|
27
29
|
import 'node:readline';
|
|
28
|
-
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
29
|
-
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
30
30
|
import 'node:url';
|
|
31
31
|
import 'node:zlib';
|
|
32
32
|
import '@simplewebauthn/server';
|
|
@@ -18,16 +18,16 @@ import 'node:buffer';
|
|
|
18
18
|
import 'node:fs';
|
|
19
19
|
import 'node:path';
|
|
20
20
|
import 'node:os';
|
|
21
|
-
import 'node:net';
|
|
22
21
|
import 'node:child_process';
|
|
23
22
|
import 'node:dns';
|
|
24
23
|
import 'node:util';
|
|
24
|
+
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
25
|
+
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
25
26
|
import 'web-push';
|
|
27
|
+
import 'node:net';
|
|
26
28
|
import 'node:string_decoder';
|
|
27
29
|
import 'node:fs/promises';
|
|
28
30
|
import 'node:readline';
|
|
29
|
-
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
30
|
-
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
31
31
|
import 'node:url';
|
|
32
32
|
import 'node:zlib';
|
|
33
33
|
import '@simplewebauthn/server';
|
|
@@ -17,16 +17,16 @@ import 'node:buffer';
|
|
|
17
17
|
import 'node:fs';
|
|
18
18
|
import 'node:path';
|
|
19
19
|
import 'node:os';
|
|
20
|
-
import 'node:net';
|
|
21
20
|
import 'node:child_process';
|
|
22
21
|
import 'node:dns';
|
|
23
22
|
import 'node:util';
|
|
23
|
+
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
24
|
+
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
24
25
|
import 'web-push';
|
|
26
|
+
import 'node:net';
|
|
25
27
|
import 'node:string_decoder';
|
|
26
28
|
import 'node:fs/promises';
|
|
27
29
|
import 'node:readline';
|
|
28
|
-
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
29
|
-
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
30
30
|
import 'node:url';
|
|
31
31
|
import 'node:zlib';
|
|
32
32
|
import '@simplewebauthn/server';
|
|
@@ -18,15 +18,15 @@ import 'node:events';
|
|
|
18
18
|
import 'node:buffer';
|
|
19
19
|
import 'node:fs';
|
|
20
20
|
import 'node:os';
|
|
21
|
-
import 'node:net';
|
|
22
21
|
import 'node:child_process';
|
|
23
22
|
import 'node:dns';
|
|
24
23
|
import 'node:util';
|
|
24
|
+
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
25
|
+
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
25
26
|
import 'web-push';
|
|
27
|
+
import 'node:net';
|
|
26
28
|
import 'node:string_decoder';
|
|
27
29
|
import 'node:readline';
|
|
28
|
-
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
29
|
-
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
30
30
|
import 'node:url';
|
|
31
31
|
import 'node:zlib';
|
|
32
32
|
import '@simplewebauthn/server';
|
|
@@ -17,16 +17,16 @@ import 'node:buffer';
|
|
|
17
17
|
import 'node:fs';
|
|
18
18
|
import 'node:path';
|
|
19
19
|
import 'node:os';
|
|
20
|
-
import 'node:net';
|
|
21
20
|
import 'node:child_process';
|
|
22
21
|
import 'node:dns';
|
|
23
22
|
import 'node:util';
|
|
23
|
+
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
24
|
+
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
24
25
|
import 'web-push';
|
|
26
|
+
import 'node:net';
|
|
25
27
|
import 'node:string_decoder';
|
|
26
28
|
import 'node:fs/promises';
|
|
27
29
|
import 'node:readline';
|
|
28
|
-
import 'qrcode-terminal/vendor/QRCode/index.js';
|
|
29
|
-
import 'qrcode-terminal/vendor/QRCode/QRErrorCorrectLevel.js';
|
|
30
30
|
import 'node:url';
|
|
31
31
|
import 'node:zlib';
|
|
32
32
|
import '@simplewebauthn/server';
|