From 8ea81f059ed7e418a25aeaedde651aaca8c24130 Mon Sep 17 00:00:00 2001 From: JohnMcPMS Date: Wed, 15 Apr 2026 11:48:57 -0700 Subject: [PATCH 1/4] log viewer tool, level added to log lines, debug logging command --- .../Commands/DebugCommand.cpp | 129 ++++ .../Commands/DebugCommand.h | 14 + src/AppInstallerCommonCore/FileLogger.cpp | 8 +- .../OutputDebugStringLogger.cpp | 4 +- src/AppInstallerCommonCore/StdErrLogger.cpp | 2 +- src/AppInstallerCommonCore/TraceLogger.cpp | 4 +- .../AppInstallerLogging.cpp | 13 + .../Public/AppInstallerLogging.h | 3 + tools/WinGetLogViewer/.vscodeignore | 4 + tools/WinGetLogViewer/README.md | 91 +++ .../language-configuration.json | 6 + tools/WinGetLogViewer/media/viewer.css | 387 ++++++++++ tools/WinGetLogViewer/media/viewer.html | 100 +++ tools/WinGetLogViewer/media/viewer.js | 675 ++++++++++++++++++ tools/WinGetLogViewer/out/extension.js | 66 ++ tools/WinGetLogViewer/out/extension.js.map | 1 + tools/WinGetLogViewer/out/logParser.js | 101 +++ tools/WinGetLogViewer/out/logParser.js.map | 1 + .../WinGetLogViewer/out/logViewerProvider.js | 201 ++++++ .../out/logViewerProvider.js.map | 1 + tools/WinGetLogViewer/package-lock.json | 58 ++ tools/WinGetLogViewer/package.json | 87 +++ tools/WinGetLogViewer/src/extension.ts | 41 ++ tools/WinGetLogViewer/src/logParser.ts | 144 ++++ .../WinGetLogViewer/src/logViewerProvider.ts | 197 +++++ .../syntaxes/winget-log.tmLanguage.json | 41 ++ tools/WinGetLogViewer/tsconfig.json | 15 + 27 files changed, 2385 insertions(+), 9 deletions(-) create mode 100644 tools/WinGetLogViewer/.vscodeignore create mode 100644 tools/WinGetLogViewer/README.md create mode 100644 tools/WinGetLogViewer/language-configuration.json create mode 100644 tools/WinGetLogViewer/media/viewer.css create mode 100644 tools/WinGetLogViewer/media/viewer.html create mode 100644 tools/WinGetLogViewer/media/viewer.js create mode 100644 tools/WinGetLogViewer/out/extension.js create mode 100644 tools/WinGetLogViewer/out/extension.js.map create mode 100644 tools/WinGetLogViewer/out/logParser.js create mode 100644 tools/WinGetLogViewer/out/logParser.js.map create mode 100644 tools/WinGetLogViewer/out/logViewerProvider.js create mode 100644 tools/WinGetLogViewer/out/logViewerProvider.js.map create mode 100644 tools/WinGetLogViewer/package-lock.json create mode 100644 tools/WinGetLogViewer/package.json create mode 100644 tools/WinGetLogViewer/src/extension.ts create mode 100644 tools/WinGetLogViewer/src/logParser.ts create mode 100644 tools/WinGetLogViewer/src/logViewerProvider.ts create mode 100644 tools/WinGetLogViewer/syntaxes/winget-log.tmLanguage.json create mode 100644 tools/WinGetLogViewer/tsconfig.json diff --git a/src/AppInstallerCLICore/Commands/DebugCommand.cpp b/src/AppInstallerCLICore/Commands/DebugCommand.cpp index 0df85d0f2a..bf14837822 100644 --- a/src/AppInstallerCLICore/Commands/DebugCommand.cpp +++ b/src/AppInstallerCLICore/Commands/DebugCommand.cpp @@ -62,6 +62,7 @@ namespace AppInstaller::CLI std::make_unique(FullName()), std::make_unique(FullName()), std::make_unique(FullName()), + std::make_unique(FullName()), }); } @@ -365,6 +366,134 @@ namespace AppInstaller::CLI context.Reporter.Info() << context.Args.GetArg(WINGET_DEBUG_PROGRESS_POST) << std::endl; } } + +// ── LogViewerTestCommand ───────────────────────────────────────────────────── + +#define WINGET_DEBUG_LOG_VIEWER_FOLLOW Args::Type::Force + + std::vector LogViewerTestCommand::GetArguments() const + { + return { + Argument{ "follow", 'f', WINGET_DEBUG_LOG_VIEWER_FOLLOW, Resource::String::SourceListUpdatedNever, ArgumentType::Flag }, + }; + } + + Resource::LocString LogViewerTestCommand::ShortDescription() const + { + return Utility::LocIndString("Emit test logs for the log viewer extension"sv); + } + + Resource::LocString LogViewerTestCommand::LongDescription() const + { + return Utility::LocIndString( + "Emits log entries exercising every channel, level, subchannel, continuation line, " + "and long-line feature of the WinGet Log Viewer VS Code extension. " + "Use --follow to stream additional log lines every 3 seconds (up to 100 iterations)."sv); + } + + void LogViewerTestCommand::ExecuteInternal(Execution::Context& context) const + { + // Ensure all channels and the most verbose level are active so every test entry lands in the file. + auto& logger = AppInstaller::Logging::Log(); + logger.EnableChannel(AppInstaller::Logging::Channel::All); + logger.SetLevel(AppInstaller::Logging::Level::Verbose); + + // ── All five levels on CLI ──────────────────────────────────────────── + AICLI_LOG(CLI, Verbose, << "Log viewer test: Verbose level message"); + AICLI_LOG(CLI, Info, << "Log viewer test: Info level message"); + AICLI_LOG(CLI, Warning, << "Log viewer test: Warning level message"); + AICLI_LOG(CLI, Error, << "Log viewer test: Error level message"); + AICLI_LOG(CLI, Crit, << "Log viewer test: Critical level message"); + + // ── One Info entry on every channel ────────────────────────────────── + AICLI_LOG(Fail, Info, << "Log viewer test: Failure channel"); + AICLI_LOG(SQL, Info, << "Log viewer test: SQL channel"); + AICLI_LOG(Repo, Info, << "Log viewer test: Repository channel"); + AICLI_LOG(YAML, Info, << "Log viewer test: YAML channel"); + AICLI_LOG(Core, Info, << "Log viewer test: Core channel"); + AICLI_LOG(Test, Info, << "Log viewer test: Test channel"); + AICLI_LOG(Config, Info, << "Log viewer test: Configuration channel"); + AICLI_LOG(Workflow, Info, << "Log viewer test: Workflow channel"); + + // ── Subchannel simulation (sub-component logs routed through CLI) ───── + AICLI_LOG(CLI, Info, << "[SQL ] Subchannel test: database query initiated for package lookup"); + AICLI_LOG(CLI, Info, << "[REPO] Subchannel test: fetching package metadata from remote source"); + + // ── Continuation lines (newlines in the message become continuation rows) ── + AICLI_LOG(Core, Warning, << "Package installation encountered multiple issues:\n" + " - Dependency 'vcredist' version 14.0.30704 not found in any configured source\n" + " - Insufficient disk space on C:\\ (requires 512 MB, available 203 MB)\n" + " - Installation directory is read-only: C:\\Program Files\\TestPackage\\1.0.0"); + + // ── Long line (should require horizontal scroll or wrap in the viewer) ─ + AICLI_LOG(Workflow, Info, << "Resolving full package dependency graph: The following packages are required " + "as dependencies and will be installed in sequence if not already present on the system: " + "Microsoft.VCRedist.2015+.x64 (>= 14.0.30704), Microsoft.DotNet.Runtime.7 (>= 7.0.14), " + "Microsoft.WebView2.Runtime (>= 113.0.1774.35), Microsoft.WindowsAppRuntime.1.4 (>= 1.4.231219000). " + "Total estimated download size: 847 MB across 4 installers."); + + context.Reporter.Info() << "Log viewer test burst complete. Open the WinGet log file to review all viewer features." << std::endl; + + if (!context.Args.Contains(WINGET_DEBUG_LOG_VIEWER_FOLLOW)) + { + return; + } + + // ── Follow mode: stream log lines every 3 seconds ──────────────────── + context.Reporter.Info() << "Follow mode active (up to 100 iterations). Press Ctrl-C to stop." << std::endl; + + struct FollowEntry { AppInstaller::Logging::Channel Channel; AppInstaller::Logging::Level Level; std::string_view Message; }; + static constexpr FollowEntry s_entries[] = + { + { AppInstaller::Logging::Channel::CLI, AppInstaller::Logging::Level::Info, "Follow: searching for available package updates" }, + { AppInstaller::Logging::Channel::Repo, AppInstaller::Logging::Level::Info, "Follow: refreshing source index from remote endpoint" }, + { AppInstaller::Logging::Channel::SQL, AppInstaller::Logging::Level::Verbose, "Follow: executing SELECT query on packages table" }, + { AppInstaller::Logging::Channel::Core, AppInstaller::Logging::Level::Info, "Follow: applying version comparison for upgrade eligibility" }, + { AppInstaller::Logging::Channel::YAML, AppInstaller::Logging::Level::Verbose, "Follow: parsing manifest for Microsoft.TestPackage 2.1.0" }, + { AppInstaller::Logging::Channel::Workflow, AppInstaller::Logging::Level::Info, "Follow: evaluating installer selection policy for current architecture" }, + { AppInstaller::Logging::Channel::Config, AppInstaller::Logging::Level::Info, "Follow: reading configuration resource state from DSC provider" }, + { AppInstaller::Logging::Channel::CLI, AppInstaller::Logging::Level::Warning, "Follow: package is pinned to a specific version, skipping upgrade" }, + { AppInstaller::Logging::Channel::Core, AppInstaller::Logging::Level::Info, "Follow: SHA-256 hash verification passed for downloaded installer" }, + { AppInstaller::Logging::Channel::CLI, AppInstaller::Logging::Level::Info, "[SQL ] Follow: subchannel activity routed through CLI during follow" }, + }; + + auto progress = context.Reporter.BeginAsyncProgress(true); + + for (int i = 1; i <= 100; ++i) + { + // Wait 3 seconds, checking for cancellation every 100 ms. + for (int t = 0; t < 30; ++t) + { + if (progress->Callback().IsCancelledBy(CancelReason::Any)) { return; } + std::this_thread::sleep_for(100ms); + } + + // Emit the cycling entry for this iteration. + const auto& e = s_entries[static_cast(i) % ARRAYSIZE(s_entries)]; + const std::string msg = std::string(e.Message) + " [" + std::to_string(i) + "/100]"; + logger.Write(e.Channel, e.Level, msg); + + // Every 5 iterations: multi-line status summary (continuation lines). + if (i % 5 == 0) + { + AICLI_LOG(Core, Info, << "Follow iteration " << i << " status summary:\n" + " Packages checked: " << (i * 7) << "\n" + " Updates available: " << (i % 3) << "\n" + " Sources refreshed: 2"); + } + + // Every 20 iterations: simulated error with a stack trace (continuation lines + HRESULT). + if (i % 20 == 0) + { + AICLI_LOG(Fail, Error, << "Simulated transient error at follow iteration " << i << " [HRESULT 0x80070005]:\n" + " at AppInstaller::Repository::SourceList::OpenSource(std::string_view)\n" + " at AppInstaller::CLI::Workflow::OpenSourcesForSearch(Context&)\n" + " at AppInstaller::CLI::LogViewerTestCommand::ExecuteInternal(Context&)"); + } + } + + context.Reporter.Info() << "Follow mode complete (100 iterations)." << std::endl; + } } #endif diff --git a/src/AppInstallerCLICore/Commands/DebugCommand.h b/src/AppInstallerCLICore/Commands/DebugCommand.h index 5e37520b2d..93193a91d7 100644 --- a/src/AppInstallerCLICore/Commands/DebugCommand.h +++ b/src/AppInstallerCLICore/Commands/DebugCommand.h @@ -85,6 +85,20 @@ namespace AppInstaller::CLI protected: void ExecuteInternal(Execution::Context& context) const override; }; + // Tests the log viewer extension by emitting logs that exercise all channels, levels, subchannels, + // continuation lines, long lines, and optionally a streaming follow mode. + struct LogViewerTestCommand final : public Command + { + LogViewerTestCommand(std::string_view parent) : Command("log-viewer", {}, parent) {} + + std::vector GetArguments() const override; + + Resource::LocString ShortDescription() const override; + Resource::LocString LongDescription() const override; + + protected: + void ExecuteInternal(Execution::Context& context) const override; + }; } #endif diff --git a/src/AppInstallerCommonCore/FileLogger.cpp b/src/AppInstallerCommonCore/FileLogger.cpp index f4b3c6e936..a430694ef6 100644 --- a/src/AppInstallerCommonCore/FileLogger.cpp +++ b/src/AppInstallerCommonCore/FileLogger.cpp @@ -22,10 +22,10 @@ namespace AppInstaller::Logging static constexpr std::string_view s_fileLoggerDefaultFileExt = ".log"sv; // Send to a string first to create a single block to write to a file. - std::string ToLogLine(Channel channel, std::string_view message) + std::string ToLogLine(Channel channel, Level level, std::string_view message) { std::stringstream strstr; - strstr << std::chrono::system_clock::now() << " [" << std::setw(GetMaxChannelNameLength()) << std::left << std::setfill(' ') << GetChannelName(channel) << "] " << message; + strstr << std::chrono::system_clock::now() << " <" << GetLevelChar(level) << "> [" << std::setw(GetMaxChannelNameLength()) << std::left << std::setfill(' ') << GetChannelName(channel) << "] " << message; return std::move(strstr).str(); } @@ -94,7 +94,7 @@ namespace AppInstaller::Logging void FileLogger::Write(Channel channel, Level level, std::string_view message) noexcept try { - std::string log = ToLogLine(channel, message); + std::string log = ToLogLine(channel, level, message); WriteDirect(channel, level, log); } catch (...) {} @@ -229,6 +229,6 @@ namespace AppInstaller::Logging { m_stream.seekp(m_headersEnd); // Yes, we may go over the size limit slightly due to this and the unaccounted for newlines - m_stream << ToLogLine(Channel::Core, "--- log file has wrapped ---") << std::endl; + m_stream << ToLogLine(Channel::Core, Level::Info, "--- log file has wrapped ---") << std::endl; } } diff --git a/src/AppInstallerCommonCore/OutputDebugStringLogger.cpp b/src/AppInstallerCommonCore/OutputDebugStringLogger.cpp index 08103bbfd8..54300ce00a 100644 --- a/src/AppInstallerCommonCore/OutputDebugStringLogger.cpp +++ b/src/AppInstallerCommonCore/OutputDebugStringLogger.cpp @@ -15,10 +15,10 @@ namespace AppInstaller::Logging return std::string{ s_OutputDebugStringLoggerName }; } - void OutputDebugStringLogger::Write(Channel channel, Level, std::string_view message) noexcept try + void OutputDebugStringLogger::Write(Channel channel, Level level, std::string_view message) noexcept try { std::stringstream strstr; - strstr << "[" << std::setw(GetMaxChannelNameLength()) << std::left << std::setfill(' ') << GetChannelName(channel) << "] " << message << std::endl; + strstr << "<" << GetLevelChar(level) << "> [" << std::setw(GetMaxChannelNameLength()) << std::left << std::setfill(' ') << GetChannelName(channel) << "] " << message << std::endl; std::string formattedMessage = std::move(strstr).str(); OutputDebugStringA(formattedMessage.c_str()); diff --git a/src/AppInstallerCommonCore/StdErrLogger.cpp b/src/AppInstallerCommonCore/StdErrLogger.cpp index 9a65ef6d3e..d1341d8531 100644 --- a/src/AppInstallerCommonCore/StdErrLogger.cpp +++ b/src/AppInstallerCommonCore/StdErrLogger.cpp @@ -19,7 +19,7 @@ namespace AppInstaller::Logging { if (level >= m_level) { - std::cerr << "[" << std::setw(GetMaxChannelNameLength()) << std::left << std::setfill(' ') << GetChannelName(channel) << "] " << message << std::endl; + std::cerr << "<" << GetLevelChar(level) << "> [" << std::setw(GetMaxChannelNameLength()) << std::left << std::setfill(' ') << GetChannelName(channel) << "] " << message << std::endl; } } catch (...) diff --git a/src/AppInstallerCommonCore/TraceLogger.cpp b/src/AppInstallerCommonCore/TraceLogger.cpp index 4f0fe9ba9e..bb95e42ee9 100644 --- a/src/AppInstallerCommonCore/TraceLogger.cpp +++ b/src/AppInstallerCommonCore/TraceLogger.cpp @@ -7,11 +7,11 @@ namespace AppInstaller::Logging { - void TraceLogger::Write(Channel channel, Level, std::string_view message) noexcept try + void TraceLogger::Write(Channel channel, Level level, std::string_view message) noexcept try { // Send to a string first to create a single block to log to a trace. std::stringstream strstr; - strstr << std::chrono::system_clock::now() << " [" << std::setw(GetMaxChannelNameLength()) << std::left << std::setfill(' ') << GetChannelName(channel) << "] " << message << std::endl; + strstr << std::chrono::system_clock::now() << " <" << GetLevelChar(level) << "> [" << std::setw(GetMaxChannelNameLength()) << std::left << std::setfill(' ') << GetChannelName(channel) << "] " << message << std::endl; TraceLoggingWriteActivity(g_hTraceProvider, "Diagnostics", diff --git a/src/AppInstallerSharedLib/AppInstallerLogging.cpp b/src/AppInstallerSharedLib/AppInstallerLogging.cpp index 7ea18be478..5b78994516 100644 --- a/src/AppInstallerSharedLib/AppInstallerLogging.cpp +++ b/src/AppInstallerSharedLib/AppInstallerLogging.cpp @@ -79,6 +79,19 @@ namespace AppInstaller::Logging size_t GetMaxChannelNameLength() { return 4; } + char GetLevelChar(Level level) + { + switch (level) + { + case Level::Verbose: return 'V'; + case Level::Info: return 'I'; + case Level::Warning: return 'W'; + case Level::Error: return 'E'; + case Level::Crit: return 'C'; + default: return '?'; + } + } + void DiagnosticLogger::AddLogger(std::unique_ptr&& logger) { m_loggers.emplace_back(std::move(logger)); diff --git a/src/AppInstallerSharedLib/Public/AppInstallerLogging.h b/src/AppInstallerSharedLib/Public/AppInstallerLogging.h index 90e8511990..ae99cba596 100644 --- a/src/AppInstallerSharedLib/Public/AppInstallerLogging.h +++ b/src/AppInstallerSharedLib/Public/AppInstallerLogging.h @@ -83,6 +83,9 @@ namespace AppInstaller::Logging Crit, }; + // Gets the single-character level marker written to log files: V/I/W/E/C. + char GetLevelChar(Level level); + // Indicates a location of significance in the logging stream. enum class Tag { diff --git a/tools/WinGetLogViewer/.vscodeignore b/tools/WinGetLogViewer/.vscodeignore new file mode 100644 index 0000000000..4e0713d748 --- /dev/null +++ b/tools/WinGetLogViewer/.vscodeignore @@ -0,0 +1,4 @@ +out +node_modules +.vscode-test +*.vsix diff --git a/tools/WinGetLogViewer/README.md b/tools/WinGetLogViewer/README.md new file mode 100644 index 0000000000..958248ffec --- /dev/null +++ b/tools/WinGetLogViewer/README.md @@ -0,0 +1,91 @@ +# WinGet Log Viewer + +A VS Code extension that makes reading WinGet diagnostic log files fast and pleasant. + +## Features + +### Rich log viewer (WebView editor) +Opens automatically for `WinGet-*.log` and `WinGetCOM-*.log` files. Use the **"Open in WinGet Log Viewer"** command (or right-click any `.log` file in the Explorer) to open any log file in the viewer. + +**Channel color badges** — each of the nine WinGet channels gets a distinct color: + +| Badge | Channel | Description | +|-------|---------|-------------| +| ![FAIL](#) | `FAIL` | Failures / exceptions | +| ![CLI](#) | `CLI` | CLI command handling | +| ![SQL](#) | `SQL` | SQLite / index operations | +| ![REPO](#) | `REPO` | Repository / source operations | +| ![YAML](#) | `YAML` | YAML manifest parsing | +| ![CORE](#) | `CORE` | Core runtime | +| ![TEST](#) | `TEST` | Test infrastructure | +| ![CONF](#) | `CONF` | Configuration / DSC | +| ![WORK](#) | `WORK` | Workflow execution | + +**Subchannel detection** — when a sub-component routes its log lines through a parent channel, the original `[CHAN]` tag appears at the start of the message. The viewer detects this and renders it as a secondary subchannel badge. + +**Dynamic filters** — toggle individual channels and subchannels on/off with checkboxes. Use "All" / "None" quick links per section. + +**Quick text search** — type in the Search box to live-filter visible lines. + +**Severity highlighting** — rows that contain error/warning keywords get a colored left border and message highlighting. + +**Time delta** — enable "Show time delta" to see the elapsed time between consecutive visible lines (`+Xms` / `+Xs`). Great for spotting slow operations. + +**Jump to error** — use the ↑ Error / ↓ Error buttons to navigate between error and critical log lines. + +**Follow mode** — enable "Follow (live tail)" to auto-scroll as the log file grows on disk. New line count is shown briefly in the status bar. + +**Export filtered** — "Copy visible lines" sends all currently visible (filtered) raw log lines to the clipboard. + +**Wrap long lines** — enable "Wrap long lines" to prevent horizontal scrolling on very long messages. + +### Syntax highlighting (standard editor) +When a WinGet log file is opened in VS Code's standard text editor, the TextMate grammar provides coloring for timestamps, channel badges, subchannels, and error/warning keywords — no additional setup required. + +## Log format + +``` +YY-MM-DD HH:MM:SS.mmm [CHAN] message +YY-MM-DD HH:MM:SS.mmm [CHAN] [SUBCHAN] message ← subchannel variant +``` + +## Development + +### Prerequisites +- Node.js 18+ +- VS Code 1.85+ + +### Build + +```bash +cd tools/WinGetLogViewer +npm install +npm run compile +``` + +### Run / Debug + +1. Open `tools/WinGetLogViewer/` as a workspace in VS Code. +2. Press **F5** — this launches the Extension Development Host. +3. Open any `WinGet-*.log` or `WinGetCOM-*.log` file; the viewer opens automatically. + +### Package + +```bash +npm install -g @vscode/vsce +vsce package +``` + +This produces a `.vsix` file you can install via **Extensions: Install from VSIX…** + +## Keyboard shortcuts + +| Key | Action | +|-----|--------| +| **Ctrl+F** (in viewer) | Focus the search box | + +## Roadmap / ideas + +- Per-session filter presets (save/restore named filter combinations) +- Fold/collapse groups of lines by channel +- Correlation ID linking (when GUIDs appear in messages) diff --git a/tools/WinGetLogViewer/language-configuration.json b/tools/WinGetLogViewer/language-configuration.json new file mode 100644 index 0000000000..4d20c18e2a --- /dev/null +++ b/tools/WinGetLogViewer/language-configuration.json @@ -0,0 +1,6 @@ +{ + "comments": {}, + "brackets": [], + "autoClosingPairs": [], + "surroundingPairs": [] +} diff --git a/tools/WinGetLogViewer/media/viewer.css b/tools/WinGetLogViewer/media/viewer.css new file mode 100644 index 0000000000..42b954f0e1 --- /dev/null +++ b/tools/WinGetLogViewer/media/viewer.css @@ -0,0 +1,387 @@ +/* ── Reset & base ──────────────────────────────────────── */ +*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } + +:root { + --font-mono: 'Cascadia Code', 'Consolas', 'Courier New', monospace; + --font-ui: var(--vscode-font-family, system-ui, sans-serif); + --font-size: var(--vscode-editor-font-size, 13px); + + --bg: var(--vscode-editor-background, #1e1e1e); + --fg: var(--vscode-editor-foreground, #d4d4d4); + --sidebar-bg: var(--vscode-sideBar-background, #252526); + --sidebar-fg: var(--vscode-sideBar-foreground, #cccccc); + --border: var(--vscode-panel-border, #444); + --input-bg: var(--vscode-input-background, #3c3c3c); + --input-fg: var(--vscode-input-foreground, #cccccc); + --input-border:var(--vscode-input-border, #555); + --btn-bg: var(--vscode-button-background, #0e639c); + --btn-fg: var(--vscode-button-foreground, #ffffff); + --hover-bg: var(--vscode-list-hoverBackground, #2a2d2e); + --select-bg: var(--vscode-list-activeSelectionBackground, #094771); + --stats-bg: var(--vscode-statusBar-background, #007acc); + --stats-fg: var(--vscode-statusBar-foreground, #ffffff); + + /* Channel colors */ + --ch-fail: #f14c4c; + --ch-cli: #4fc1ff; + --ch-sql: #c792ea; + --ch-repo: #89ddff; + --ch-yaml: #ffcb6b; + --ch-core: #858585; + --ch-test: #c3e88d; + --ch-conf: #7fdbca; + --ch-work: #f78c6c; + --ch-unknown: #aaaaaa; + + --row-height: 20px; + --sidebar-width: 210px; +} + +html, body { + height: 100%; + overflow: hidden; + background: var(--bg); + color: var(--fg); + font-family: var(--font-ui); + font-size: var(--font-size); +} + +/* ── Layout ────────────────────────────────────────────── */ +body { display: flex; height: 100vh; } + +#sidebar { + width: var(--sidebar-width); + min-width: var(--sidebar-width); + background: var(--sidebar-bg); + color: var(--sidebar-fg); + border-right: 1px solid var(--border); + overflow-y: auto; + display: flex; + flex-direction: column; + gap: 0; +} + +#main { + flex: 1; + display: flex; + flex-direction: column; + overflow: hidden; +} + +/* ── Stats bar ─────────────────────────────────────────── */ +#stats-bar { + display: flex; + align-items: center; + justify-content: space-between; + padding: 2px 10px; + background: var(--stats-bg); + color: var(--stats-fg); + font-size: 11px; + flex-shrink: 0; + user-select: none; +} +#status-indicator { + font-size: 10px; + opacity: 0.8; +} + +/* ── Log container ─────────────────────────────────────── */ +#log-container { + flex: 1; + overflow: auto; + overflow-anchor: none; /* prevent scroll anchoring from cascading when top spacer grows */ + position: relative; + font-family: var(--font-mono); + font-size: var(--font-size); +} + +#log-rows { + position: relative; +} + +/* ── Log row ───────────────────────────────────────────── */ +.log-row { + display: flex; + align-items: baseline; + min-height: var(--row-height); + padding: 1px 8px; + border-left: 3px solid transparent; + white-space: nowrap; + cursor: default; + transition: background 0.05s; +} +.log-row:hover { background: var(--hover-bg); } +.log-row.selected { background: var(--select-bg); } +.log-row.wrap-lines { white-space: pre-wrap; word-break: break-all; } + +/* Severity left-border */ +.log-row.sev-error { border-left-color: var(--ch-fail); } +.log-row.sev-warning { border-left-color: var(--ch-yaml); } + +.log-row.sev-error .log-message { color: #f88; } +.log-row.sev-warning .log-message { color: var(--ch-yaml); } +.log-row.sev-verbose .log-message { opacity: 0.55; } + +/* ── Row parts ─────────────────────────────────────────── */ +.log-timestamp { + color: #6a9955; + margin-right: 6px; + flex-shrink: 0; + font-size: 0.9em; + user-select: none; +} + +.log-delta { + font-size: 0.82em; + margin-right: 6px; + flex-shrink: 0; + min-width: 60px; + text-align: right; + user-select: none; + color: #888; /* default: under 1 second */ +} +/* 1 s – 1 min */ +.log-delta.delta-slow { color: var(--ch-yaml); font-weight: 600; } +/* over 1 min */ +.log-delta.delta-very-slow { color: var(--ch-fail); font-weight: 700; } + +.log-channel { + display: inline-block; + min-width: 52px; + padding: 0 4px; + margin-right: 6px; + border-radius: 3px; + font-size: 0.82em; + font-weight: 700; + text-align: center; + flex-shrink: 0; + user-select: none; +} + +.log-subchannel { + display: inline-block; + padding: 0 3px; + margin-right: 6px; + border-radius: 3px; + font-size: 0.78em; + font-weight: 600; + text-align: center; + flex-shrink: 0; + opacity: 0.85; + user-select: none; + border: 1px solid currentColor; +} + +.log-message { + overflow: hidden; + text-overflow: ellipsis; + flex: 1; +} +.wrap-lines .log-message { + overflow: visible; + text-overflow: unset; + white-space: pre-wrap; + word-break: break-all; +} + +/* ── Continuation rows (timestamp-less lines promoted to full rows) ── */ +.log-row.is-continuation { + border-left-color: var(--border); + padding-left: 20px; +} +.log-row.is-continuation .log-message { + opacity: 0.75; + white-space: pre; + overflow: hidden; + text-overflow: ellipsis; +} +.log-row.wrap-lines.is-continuation .log-message { + white-space: pre-wrap; + word-break: break-all; + overflow: visible; + text-overflow: unset; +} +/* ── Level badge(shown when explicit marker is present) ── */ +.log-level { + display: inline-block; + min-width: 22px; + padding: 0 3px; + margin-right: 6px; + border-radius: 3px; + font-size: 0.8em; + font-weight: 700; + text-align: center; + flex-shrink: 0; + user-select: none; +} +.lv-V { background: #4a4a4a; color: #aaa; } +.lv-I { background: #1a5276; color: #aed6f1; } +.lv-W { background: #7d6608; color: var(--ch-yaml); } +.lv-E { background: #7b241c; color: #f1948a; } +.lv-C { background: var(--ch-fail); color: #000; font-weight: 900; } + +/* ── Channel color assignments ─────────────────────────── */ +.ch-FAIL { background: var(--ch-fail); color: #000; } +.ch-CLI { background: var(--ch-cli); color: #000; } +.ch-SQL { background: var(--ch-sql); color: #000; } +.ch-REPO { background: var(--ch-repo); color: #000; } +.ch-YAML { background: var(--ch-yaml); color: #000; } +.ch-CORE { background: var(--ch-core); color: #fff; } +.ch-TEST { background: var(--ch-test); color: #000; } +.ch-CONF { background: var(--ch-conf); color: #000; } +.ch-WORK { background: var(--ch-work); color: #000; } + +/* Subchannel uses text color (no background fill) */ +.sub-FAIL { color: var(--ch-fail); } +.sub-CLI { color: var(--ch-cli); } +.sub-SQL { color: var(--ch-sql); } +.sub-REPO { color: var(--ch-repo); } +.sub-YAML { color: var(--ch-yaml); } +.sub-CORE { color: var(--ch-core); } +.sub-TEST { color: var(--ch-test); } +.sub-CONF { color: var(--ch-conf); } +.sub-WORK { color: var(--ch-work); } + +/* ── Sidebar sections ──────────────────────────────────── */ +.sidebar-section { + padding: 8px 10px; + border-bottom: 1px solid var(--border); +} + +.section-header { + display: flex; + align-items: center; + justify-content: space-between; + font-size: 0.78em; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.06em; + opacity: 0.7; + margin-bottom: 6px; + user-select: none; +} + +.header-actions { display: flex; gap: 6px; } + +.link-btn { + background: none; + border: none; + color: var(--vscode-textLink-foreground, #4fc1ff); + cursor: pointer; + font-size: 0.9em; + padding: 0; + text-decoration: underline; +} +.link-btn:hover { opacity: 0.8; } + +.full-btn { + width: 100%; + background: var(--btn-bg); + color: var(--btn-fg); + border: none; + border-radius: 3px; + padding: 5px 8px; + cursor: pointer; + font-size: 0.88em; +} +.full-btn:hover { opacity: 0.9; } + +/* ── Search input ──────────────────────────────────────── */ +#search-input { + width: 100%; + background: var(--input-bg); + color: var(--input-fg); + border: 1px solid var(--input-border); + border-radius: 3px; + padding: 4px 6px; + font-size: 0.9em; + outline: none; +} +#search-input:focus { border-color: var(--vscode-focusBorder, #007acc); } + +/* ── Filter lists ──────────────────────────────────────── */ +.filter-list { + list-style: none; + display: flex; + flex-direction: column; + gap: 2px; +} + +.filter-item { + display: flex; + align-items: center; + gap: 6px; + font-size: 0.88em; + cursor: pointer; + padding: 2px 2px; + border-radius: 3px; +} +.filter-item:hover { background: var(--hover-bg); } + +.filter-item input[type="checkbox"] { + cursor: pointer; + flex-shrink: 0; + accent-color: var(--vscode-checkbox-background, #007acc); +} + +.filter-badge { + display: inline-block; + min-width: 44px; + padding: 1px 4px; + border-radius: 3px; + font-size: 0.8em; + font-weight: 700; + text-align: center; +} + +.filter-item .filter-count { + margin-left: auto; + font-size: 0.78em; + opacity: 0.55; +} + +/* ── Options ───────────────────────────────────────────── */ +.option-label { + display: flex; + align-items: center; + gap: 6px; + font-size: 0.88em; + cursor: pointer; + padding: 2px 0; +} + +/* ── Navigation buttons ────────────────────────────────── */ +.nav-buttons { + display: flex; + gap: 6px; +} +.nav-buttons button { + flex: 1; + background: var(--hover-bg); + color: var(--sidebar-fg); + border: 1px solid var(--border); + border-radius: 3px; + padding: 4px 4px; + cursor: pointer; + font-size: 0.82em; +} +.nav-buttons button:hover { background: var(--select-bg); color: #fff; } + +/* ── Keyword highlights inside message ─────────────────── */ +.kw-error { color: #f88; font-weight: 600; } +.kw-warning { color: var(--ch-yaml); } +.kw-hex { color: var(--ch-conf); font-family: var(--font-mono); } + +/* ── Search match highlight ────────────────────────────── */ +mark.search-match { + background: var(--vscode-editor-findMatchHighlightBackground, rgba(255, 200, 0, 0.55)); + color: inherit; + border-radius: 2px; + padding: 0 1px; + outline: 1px solid var(--vscode-editor-findMatchHighlightBorder, rgba(255, 200, 0, 0.9)); +} + +/* ── Scrollbar ─────────────────────────────────────────── */ +#log-container::-webkit-scrollbar { width: 8px; height: 8px; } +#log-container::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; } +#log-container::-webkit-scrollbar-track { background: transparent; } diff --git a/tools/WinGetLogViewer/media/viewer.html b/tools/WinGetLogViewer/media/viewer.html new file mode 100644 index 0000000000..c871579376 --- /dev/null +++ b/tools/WinGetLogViewer/media/viewer.html @@ -0,0 +1,100 @@ + + + + + + + + WinGet Log Viewer + + + + + + +
+
+ Loading… + +
+
+ +
+
+
+
+
+ + + + diff --git a/tools/WinGetLogViewer/media/viewer.js b/tools/WinGetLogViewer/media/viewer.js new file mode 100644 index 0000000000..09e443dcb2 --- /dev/null +++ b/tools/WinGetLogViewer/media/viewer.js @@ -0,0 +1,675 @@ +// @ts-check +// WinGet Log Viewer — WebView client script +// Communicates with the extension host via postMessage. + +(function () { + 'use strict'; + + const vscode = acquireVsCodeApi(); + + // ── State ──────────────────────────────────────────────────────── + /** @type {import('../src/logParser').LogEntry[]} */ + let allEntries = []; + /** @type {import('../src/logParser').LogEntry[]} */ + let visibleEntries = []; + + /** + * Flat list of rows to render — primary entries plus continuation lines + * each promoted to their own row with parent metadata replicated. + * @type {Array<{timestamp:string, levelChar:string|null, channel:string, subchannel:string|null, message:string, severity:string, isContinuation:boolean, deltaMs:number}>} + */ + let displayRows = []; + + /** @type {Set} */ + let enabledChannels = new Set(); + /** @type {Set} */ + let enabledSubchannels = new Set(); + /** @type {Set} — active level chars; null means file has no level markers (filter hidden) */ + let enabledLevels = new Set(['V','I','W','E','C']); + /** Whether the loaded file contains explicit level markers. */ + let fileHasLevels = false; + + let searchText = ''; + let showDelta = false; + let followMode = false; + let wrapLines = false; + + // Virtual scroll + const ROW_HEIGHT = 20; // px — matches CSS var(--row-height) + let scrollTop = 0; + let containerH = 0; + let renderBuffer = 40; // extra rows above/below viewport + + // Error navigation + let lastErrorJumpIndex = -1; + + // ── DOM refs ───────────────────────────────────────────────────── + const levelList = /** @type {HTMLUListElement} */ (document.getElementById('level-list')); + const levelSec = /** @type {HTMLElement} */ (document.getElementById('level-section')); + const channelList = /** @type {HTMLUListElement} */ (document.getElementById('channel-list')); + const subchannelList = /** @type {HTMLUListElement} */ (document.getElementById('subchannel-list')); + const subchannelSec = /** @type {HTMLElement} */ (document.getElementById('subchannel-section')); + const searchInput = /** @type {HTMLInputElement} */ (document.getElementById('search-input')); + const statsText = /** @type {HTMLSpanElement} */ (document.getElementById('stats-text')); + const statusIndicator= /** @type {HTMLSpanElement} */ (document.getElementById('status-indicator')); + const logContainer = /** @type {HTMLDivElement} */ (document.getElementById('log-container')); + const logRows = /** @type {HTMLDivElement} */ (document.getElementById('log-rows')); + const logSpacerTop = /** @type {HTMLDivElement} */ (document.getElementById('log-spacer-top')); + const logSpacerBot = /** @type {HTMLDivElement} */ (document.getElementById('log-spacer-bottom')); + const optDelta = /** @type {HTMLInputElement} */ (document.getElementById('opt-delta')); + const optFollow = /** @type {HTMLInputElement} */ (document.getElementById('opt-follow')); + const optWrap = /** @type {HTMLInputElement} */ (document.getElementById('opt-wrap')); + const btnPrevError = /** @type {HTMLButtonElement} */ (document.getElementById('btn-prev-error')); + const btnNextError = /** @type {HTMLButtonElement} */ (document.getElementById('btn-next-error')); + const btnExport = /** @type {HTMLButtonElement} */ (document.getElementById('btn-export')); + + // ── Helpers ────────────────────────────────────────────────────── + /** @param {string} ch */ + function channelClass(ch) { + const known = ['FAIL','CLI','SQL','REPO','YAML','CORE','TEST','CONF','WORK']; + return known.includes(ch) ? 'ch-' + ch : ''; + } + /** @param {string} ch */ + function subchannelClass(ch) { + const known = ['FAIL','CLI','SQL','REPO','YAML','CORE','TEST','CONF','WORK']; + return known.includes(ch) ? 'sub-' + ch : ''; + } + /** @param {string} lv - level char V/I/W/E/C */ + function levelClass(lv) { return 'lv-' + lv; } + + const LEVEL_LABELS = { V: 'Verbose', I: 'Info', W: 'Warning', E: 'Error', C: 'Crit' }; + + /** + * Format a millisecond delta into a compact string. + * @param {number} ms + */ + function formatDelta(ms) { + if (ms < 0) { return ''; } + if (ms < 1000) { return '+' + ms + 'ms'; } + if (ms < 60000) { return '+' + (ms / 1000).toFixed(2) + 's'; } + return '+' + (ms / 60000).toFixed(1) + 'm'; + } + + /** + * Parse the timestamp string "YYYY-MM-DD HH:MM:SS.mmm" into a Date ms value. + * Also handles legacy 2-digit year "YY-MM-DD ...". + * Returns NaN on failure. + * @param {string} ts + */ + function parseTimestampMs(ts) { + // "2026-04-14 22:39:42.041" (4-digit year) or "26-04-14 ..." (2-digit year) + const m = ts.match(/^(\d{2,4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})\.(\d{3})$/); + if (!m) { return NaN; } + const [, yr, mo, dd, hh, mm, ss, ms] = m.map(Number); + const fullYear = yr < 100 ? 2000 + yr : yr; + return Date.UTC(fullYear, mo - 1, dd, hh, mm, ss, ms); + } + + /** Escape HTML special characters. @param {string} s */ + function esc(s) { + return s.replace(/&/g,'&').replace(//g,'>'); + } + + const KW_RE = /(Error|Fail(?:ed|ure)?|Exception|HRESULT|Crit(?:ical)?)|(Warn(?:ing)?|Deprecated)|(0x[0-9a-fA-F]{1,8})/gi; + + /** Annotate error/warning/hex keywords in message HTML. @param {string} s */ + function annotateMessage(s) { + return esc(s).replace(KW_RE, (_, err, warn, hex) => { + if (err) { return '' + esc(err) + ''; } + if (warn) { return '' + esc(warn) + ''; } + if (hex) { return '' + esc(hex) + ''; } + return _; + }); + } + + /** + * Build innerHTML for a message, applying keyword annotation and search highlighting. + * Search matches are wrapped in . + * @param {string} raw - raw (unescaped) message text + * @param {boolean} [keywords] - whether to apply keyword annotation (default true) + */ + function buildMessageHtml(raw, keywords = true) { + if (!searchText) { + return keywords ? annotateMessage(raw) : esc(raw); + } + const lower = raw.toLowerCase(); + const needle = searchText.toLowerCase(); + const needleLen = needle.length; + let result = ''; + let pos = 0; + let idx; + while ((idx = lower.indexOf(needle, pos)) !== -1) { + const before = raw.slice(pos, idx); + const match = raw.slice(idx, idx + needleLen); + result += keywords ? annotateMessage(before) : esc(before); + result += '' + esc(match) + ''; + pos = idx + needleLen; + } + const after = raw.slice(pos); + result += keywords ? annotateMessage(after) : esc(after); + return result; + } + + // ── Filter logic ───────────────────────────────────────────────── + /** Flatten visibleEntries (including continuation lines) into uniform display rows. */ + function buildDisplayRows() { + displayRows = []; + let prevTimestampMs = NaN; + for (const entry of visibleEntries) { + const curMs = parseTimestampMs(entry.timestamp); + const delta = (!isNaN(curMs) && !isNaN(prevTimestampMs)) ? curMs - prevTimestampMs : -1; + if (!isNaN(curMs)) { prevTimestampMs = curMs; } + + displayRows.push({ + timestamp: entry.timestamp, + levelChar: entry.levelChar ?? null, + channel: entry.channel, + subchannel: entry.subchannel ?? null, + message: entry.message, + severity: entry.severity, + isContinuation: false, + deltaMs: delta + }); + + for (const cl of (entry.continuationLines || [])) { + displayRows.push({ + timestamp: entry.timestamp, + levelChar: entry.levelChar ?? null, + channel: entry.channel, + subchannel: entry.subchannel ?? null, + message: cl, + severity: entry.severity, + isContinuation: true, + deltaMs: -1 + }); + } + } + } + + function applyFilters() { + const lowerSearch = searchText.toLowerCase(); + + visibleEntries = allEntries.filter(e => { + if (!enabledChannels.has(e.channel)) { return false; } + if (e.subchannel && !enabledSubchannels.has(e.subchannel)) { return false; } + // Level filter only applies when the file has explicit markers and the entry has one. + if (fileHasLevels && e.levelChar && !enabledLevels.has(e.levelChar)) { return false; } + if (lowerSearch && !e.message.toLowerCase().includes(lowerSearch) && + !e.channel.toLowerCase().includes(lowerSearch)) { + return false; + } + return true; + }); + + updateStats(); + buildDisplayRows(); + renderVirtual(true); + } + + function updateStats() { + statsText.textContent = visibleEntries.length + ' visible / ' + allEntries.length + ' total lines'; + } + + // ── Sidebar builder ────────────────────────────────────────────── + /** + * Wire a filter-item
  • so clicking anywhere on it (except the checkbox itself) toggles the checkbox. + * @param {HTMLLIElement} li + * @param {HTMLInputElement} cb + */ + function wireFilterItem(li, cb) { + li.addEventListener('click', e => { + if (e.target === cb) { return; } + cb.checked = !cb.checked; + cb.dispatchEvent(new Event('change')); + }); + } + + /** + * @param {string[]} channels + * @param {Map} counts + */ + function buildChannelList(channels, counts) { + channelList.innerHTML = ''; + for (const ch of channels) { + const count = counts.get(ch) ?? 0; + const li = document.createElement('li'); + li.className = 'filter-item'; + + const cb = document.createElement('input'); + cb.type = 'checkbox'; + cb.checked = enabledChannels.has(ch); + cb.addEventListener('change', () => { + if (cb.checked) { enabledChannels.add(ch); } + else { enabledChannels.delete(ch); } + applyFilters(); + }); + + const badge = document.createElement('span'); + badge.className = 'filter-badge ' + channelClass(ch); + badge.textContent = ch; + + const cnt = document.createElement('span'); + cnt.className = 'filter-count'; + cnt.textContent = String(count); + + li.appendChild(cb); + li.appendChild(badge); + li.appendChild(cnt); + wireFilterItem(li, cb); + channelList.appendChild(li); + } + } + + /** + * @param {string[]} subchannels + * @param {Map} counts + */ + function buildSubchannelList(subchannels, counts) { + if (subchannels.length === 0) { + subchannelSec.style.display = 'none'; + return; + } + subchannelSec.style.display = ''; + subchannelList.innerHTML = ''; + for (const sc of subchannels) { + const count = counts.get(sc) ?? 0; + const li = document.createElement('li'); + li.className = 'filter-item'; + + const cb = document.createElement('input'); + cb.type = 'checkbox'; + cb.checked = enabledSubchannels.has(sc); + cb.addEventListener('change', () => { + if (cb.checked) { enabledSubchannels.add(sc); } + else { enabledSubchannels.delete(sc); } + applyFilters(); + }); + + const badge = document.createElement('span'); + badge.className = 'filter-badge ' + subchannelClass(sc); + badge.textContent = sc; + badge.style.border = '1px solid currentColor'; + + const cnt = document.createElement('span'); + cnt.className = 'filter-count'; + cnt.textContent = String(count); + + li.appendChild(cb); + li.appendChild(badge); + li.appendChild(cnt); + wireFilterItem(li, cb); + subchannelList.appendChild(li); + } + } + + /** + * Build the Levels filter section. Hidden when the file has no explicit level markers. + * @param {Map} counts - map of levelChar → count + */ + function buildLevelList(counts) { + if (!fileHasLevels) { + levelSec.style.display = 'none'; + return; + } + levelSec.style.display = ''; + levelList.innerHTML = ''; + const order = ['V','I','W','E','C']; + for (const lv of order) { + const count = counts.get(lv) ?? 0; + if (count === 0) { continue; } + + const li = document.createElement('li'); + li.className = 'filter-item'; + + const cb = document.createElement('input'); + cb.type = 'checkbox'; + cb.checked = enabledLevels.has(lv); + cb.addEventListener('change', () => { + if (cb.checked) { enabledLevels.add(lv); } + else { enabledLevels.delete(lv); } + applyFilters(); + }); + + const badge = document.createElement('span'); + badge.className = 'filter-badge log-level ' + levelClass(lv); + badge.textContent = lv; + + const label = document.createElement('span'); + label.textContent = LEVEL_LABELS[lv] ?? lv; + + const cnt = document.createElement('span'); + cnt.className = 'filter-count'; + cnt.textContent = String(count); + + li.appendChild(cb); + li.appendChild(badge); + li.appendChild(label); + li.appendChild(cnt); + wireFilterItem(li, cb); + levelList.appendChild(li); + } + } + + // ── Virtual scroll renderer ─────────────────────────────────────── + let scheduledRender = false; + + /** + * Render only the rows currently visible in the viewport. + * @param {boolean} [reset] Reset scroll position to top (or bottom if follow mode). + */ + function renderVirtual(reset = false) { + const total = displayRows.length; + + if (reset) { + logContainer.scrollTop = followMode ? total * ROW_HEIGHT : 0; + } + scrollTop = logContainer.scrollTop; + containerH = logContainer.clientHeight; + + const firstVisible = Math.max(0, Math.floor(scrollTop / ROW_HEIGHT) - renderBuffer); + const lastVisible = Math.min(total - 1, Math.ceil((scrollTop + containerH) / ROW_HEIGHT) + renderBuffer); + + logSpacerTop.style.height = (firstVisible * ROW_HEIGHT) + 'px'; + logSpacerBot.style.height = (Math.max(0, total - 1 - lastVisible) * ROW_HEIGHT) + 'px'; + + const fragment = document.createDocumentFragment(); + for (let i = firstVisible; i <= lastVisible; i++) { + fragment.appendChild(buildRow(i)); + } + logRows.innerHTML = ''; + logRows.appendChild(fragment); + } + + /** + * Build a single log row element. + * @param {number} idx Index into displayRows. + */ + function buildRow(idx) { + const entry = displayRows[idx]; + const row = document.createElement('div'); + const contClass = entry.isContinuation ? ' is-continuation' : ''; + row.className = 'log-row sev-' + entry.severity + contClass + (wrapLines ? ' wrap-lines' : ''); + row.dataset.idx = String(idx); + + // Continuation rows show only the raw message text; no prefix columns. + if (entry.isContinuation) { + const msg = document.createElement('span'); + msg.className = 'log-message'; + msg.innerHTML = buildMessageHtml(entry.message, false); + row.appendChild(msg); + return row; + } + + // Timestamp + const ts = document.createElement('span'); + ts.className = 'log-timestamp'; + ts.textContent = entry.timestamp; + row.appendChild(ts); + + // Time delta (primary rows only) + if (showDelta && !entry.isContinuation) { + const delta = document.createElement('span'); + delta.className = 'log-delta'; + if (entry.deltaMs >= 0) { + delta.textContent = formatDelta(entry.deltaMs); + if (entry.deltaMs >= 60000) { delta.classList.add('delta-very-slow'); } + else if (entry.deltaMs >= 1000) { delta.classList.add('delta-slow'); } + } + row.appendChild(delta); + } + + // Level badge (only when explicit marker present) + if (entry.levelChar) { + const lv = document.createElement('span'); + lv.className = 'log-level ' + levelClass(entry.levelChar); + lv.textContent = entry.levelChar; + row.appendChild(lv); + } + + // Channel badge + const ch = document.createElement('span'); + ch.className = 'log-channel ' + channelClass(entry.channel); + ch.textContent = entry.channel; + row.appendChild(ch); + + // Optional subchannel badge + if (entry.subchannel) { + const sc = document.createElement('span'); + sc.className = 'log-subchannel ' + subchannelClass(entry.subchannel); + sc.textContent = entry.subchannel; + row.appendChild(sc); + } + + // Message + const msg = document.createElement('span'); + msg.className = 'log-message'; + msg.innerHTML = buildMessageHtml(entry.message); + row.appendChild(msg); + + return row; + } + + // ── Scroll handler (virtual scroll repaint) ─────────────────────── + let scrollRaf = 0; + logContainer.addEventListener('scroll', () => { + if (scrollRaf) { return; } + scrollRaf = requestAnimationFrame(() => { + scrollRaf = 0; + renderVirtual(false); + }); + }); + + // Resize + const resizeObs = new ResizeObserver(() => { + if (!scheduledRender) { + scheduledRender = true; + requestAnimationFrame(() => { + scheduledRender = false; + renderVirtual(false); + }); + } + }); + resizeObs.observe(logContainer); + + // ── Error navigation ───────────────────────────────────────────── + /** @param {'next'|'prev'} dir */ + function jumpToError(dir) { + const errors = displayRows + .map((e, i) => ({ i, sev: e.severity, isCont: e.isContinuation })) + .filter(x => !x.isCont && (x.sev === 'error' || x.sev === 'crit')); + if (errors.length === 0) { return; } + + let target; + if (dir === 'next') { + target = errors.find(x => x.i > lastErrorJumpIndex) ?? errors[0]; + } else { + const rev = [...errors].reverse(); + target = rev.find(x => x.i < lastErrorJumpIndex) ?? errors[errors.length - 1]; + } + lastErrorJumpIndex = target.i; + logContainer.scrollTop = target.i * ROW_HEIGHT - containerH / 2; + renderVirtual(false); + } + + btnNextError.addEventListener('click', () => jumpToError('next')); + btnPrevError.addEventListener('click', () => jumpToError('prev')); + + // ── Option toggles ──────────────────────────────────────────────── + optDelta.addEventListener('change', () => { + showDelta = optDelta.checked; + renderVirtual(false); + }); + optFollow.addEventListener('change', () => { + followMode = optFollow.checked; + if (followMode) { + logContainer.scrollTop = displayRows.length * ROW_HEIGHT; + } + }); + optWrap.addEventListener('change', () => { + wrapLines = optWrap.checked; + renderVirtual(false); + }); + + // ── Search ──────────────────────────────────────────────────────── + let searchTimer = 0; + searchInput.addEventListener('input', () => { + clearTimeout(searchTimer); + searchTimer = setTimeout(() => { + searchText = searchInput.value; + applyFilters(); + }, 150); + }); + + // ── Level / Channel / Subchannel "All / None" buttons ──────────── + document.getElementById('levels-all')?.addEventListener('click', () => { + for (const cb of /** @type {NodeListOf} */ (levelList.querySelectorAll('input[type=checkbox]'))) { + cb.checked = true; + } + enabledLevels = new Set(['V','I','W','E','C']); + applyFilters(); + }); + document.getElementById('levels-none')?.addEventListener('click', () => { + for (const cb of /** @type {NodeListOf} */ (levelList.querySelectorAll('input[type=checkbox]'))) { + cb.checked = false; + } + enabledLevels = new Set(); + applyFilters(); + }); + document.getElementById('channels-all')?.addEventListener('click', () => { + for (const cb of /** @type {NodeListOf} */ (channelList.querySelectorAll('input[type=checkbox]'))) { + cb.checked = true; + } + enabledChannels = new Set(allEntries.map(e => e.channel)); + applyFilters(); + }); + document.getElementById('channels-none')?.addEventListener('click', () => { + for (const cb of /** @type {NodeListOf} */ (channelList.querySelectorAll('input[type=checkbox]'))) { + cb.checked = false; + } + enabledChannels = new Set(); + applyFilters(); + }); + document.getElementById('subchannels-all')?.addEventListener('click', () => { + for (const cb of /** @type {NodeListOf} */ (subchannelList.querySelectorAll('input[type=checkbox]'))) { + cb.checked = true; + } + enabledSubchannels = new Set(allEntries.filter(e => e.subchannel).map(e => /** @type {string} */ (e.subchannel))); + applyFilters(); + }); + document.getElementById('subchannels-none')?.addEventListener('click', () => { + for (const cb of /** @type {NodeListOf} */ (subchannelList.querySelectorAll('input[type=checkbox]'))) { + cb.checked = false; + } + enabledSubchannels = new Set(); + applyFilters(); + }); + + // ── Export ──────────────────────────────────────────────────────── + btnExport.addEventListener('click', () => { + const lines = []; + for (const e of visibleEntries) { + lines.push(e.raw); + if (e.continuationLines) { lines.push(...e.continuationLines); } + } + vscode.postMessage({ type: 'export', text: lines.join('\n') }); + }); + + // ── Message handler (from extension host) ───────────────────────── + window.addEventListener('message', event => { + const msg = event.data; + switch (msg.type) { + case 'load': { + handleLoad(msg); + break; + } + case 'update': { + handleUpdate(msg); + break; + } + } + }); + + /** + * Full initial load (or reload after file change in non-follow mode). + * @param {{ entries: any[], channels: string[], subchannels: string[], hasLevels: boolean }} msg + */ + function handleLoad(msg) { + allEntries = msg.entries; + fileHasLevels = msg.hasLevels; + + /** @type {Map} */ + const chCounts = new Map(); + /** @type {Map} */ + const subCounts = new Map(); + /** @type {Map} */ + const lvCounts = new Map(); + for (const e of allEntries) { + chCounts.set(e.channel, (chCounts.get(e.channel) ?? 0) + 1); + if (e.subchannel) { subCounts.set(e.subchannel, (subCounts.get(e.subchannel) ?? 0) + 1); } + if (e.levelChar) { lvCounts.set(e.levelChar, (lvCounts.get(e.levelChar) ?? 0) + 1); } + } + + // First load: enable everything + enabledChannels = new Set(msg.channels); + enabledSubchannels = new Set(msg.subchannels); + enabledLevels = new Set(['V','I','W','E','C']); + + buildLevelList(lvCounts); + buildChannelList(msg.channels, chCounts); + buildSubchannelList(msg.subchannels, subCounts); + applyFilters(); + statusIndicator.textContent = ''; + } + + + /** + * Incremental update (follow mode — new lines appended). + * @param {{ entries: any[] }} msg + */ + function handleUpdate(msg) { + const prevLen = allEntries.length; + allEntries = msg.entries; + + const newChannels = new Set(allEntries.map(e => e.channel)); + const newSubchannels = new Set(allEntries.filter(e => e.subchannel).map(e => /** @type {string} */(e.subchannel))); + const newLevels = new Set(allEntries.filter(e => e.levelChar).map(e => /** @type {string} */(e.levelChar))); + + let needsRebuild = false; + for (const ch of newChannels) { if (!enabledChannels.has(ch)) { enabledChannels.add(ch); needsRebuild = true; } } + for (const sc of newSubchannels) { if (!enabledSubchannels.has(sc)) { enabledSubchannels.add(sc); needsRebuild = true; } } + for (const lv of newLevels) { if (!enabledLevels.has(lv)) { enabledLevels.add(lv); needsRebuild = true; } } + + if (needsRebuild) { + /** @type {Map} */ + const chCounts = new Map(); + /** @type {Map} */ + const subCounts = new Map(); + /** @type {Map} */ + const lvCounts = new Map(); + for (const e of allEntries) { + chCounts.set(e.channel, (chCounts.get(e.channel) ?? 0) + 1); + if (e.subchannel) { subCounts.set(e.subchannel, (subCounts.get(e.subchannel) ?? 0) + 1); } + if (e.levelChar) { lvCounts.set(e.levelChar, (lvCounts.get(e.levelChar) ?? 0) + 1); } + } + buildLevelList(lvCounts); + buildChannelList([...newChannels], chCounts); + buildSubchannelList([...newSubchannels], subCounts); + } + + applyFilters(); + + if (followMode) { + logContainer.scrollTop = displayRows.length * ROW_HEIGHT; + renderVirtual(false); + } + + const added = allEntries.length - prevLen; + if (added > 0) { + statusIndicator.textContent = '+' + added + ' new'; + setTimeout(() => { statusIndicator.textContent = ''; }, 3000); + } + } + + // Signal to the extension host that the webview is ready to receive data. + vscode.postMessage({ type: 'ready' }); +}()); \ No newline at end of file diff --git a/tools/WinGetLogViewer/out/extension.js b/tools/WinGetLogViewer/out/extension.js new file mode 100644 index 0000000000..5d1a36d354 --- /dev/null +++ b/tools/WinGetLogViewer/out/extension.js @@ -0,0 +1,66 @@ +"use strict"; +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +exports.activate = activate; +exports.deactivate = deactivate; +const vscode = __importStar(require("vscode")); +const logViewerProvider_1 = require("./logViewerProvider"); +function activate(context) { + const provider = new logViewerProvider_1.LogViewerProvider(context); + // Register the custom editor for WinGet-*.log and WinGetCOM-*.log + context.subscriptions.push(vscode.window.registerCustomEditorProvider(logViewerProvider_1.LogViewerProvider.viewType, provider, { + webviewOptions: { + retainContextWhenHidden: true, + }, + supportsMultipleEditorsPerDocument: false, + })); + // "Open in WinGet Log Viewer" command — works on any .log file + context.subscriptions.push(vscode.commands.registerCommand('wingetLogViewer.open', (uri) => { + // When invoked from the editor title or context menu, uri is provided. + // When invoked from the command palette, use the active editor's document. + const target = uri ?? vscode.window.activeTextEditor?.document.uri; + if (!target) { + vscode.window.showErrorMessage('WinGet Log Viewer: no file to open. Open a log file first.'); + return; + } + provider.openFile(target); + })); +} +function deactivate() { + // Nothing to clean up; subscriptions are disposed automatically. +} +//# sourceMappingURL=extension.js.map \ No newline at end of file diff --git a/tools/WinGetLogViewer/out/extension.js.map b/tools/WinGetLogViewer/out/extension.js.map new file mode 100644 index 0000000000..5b0cbfa2b6 --- /dev/null +++ b/tools/WinGetLogViewer/out/extension.js.map @@ -0,0 +1 @@ +{"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":";AAAA,uCAAuC;AACvC,kCAAkC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAKlC,4BA8BC;AAED,gCAEC;AArCD,+CAAiC;AACjC,2DAAwD;AAExD,SAAgB,QAAQ,CAAC,OAAgC;IACrD,MAAM,QAAQ,GAAG,IAAI,qCAAiB,CAAC,OAAO,CAAC,CAAC;IAEhD,kEAAkE;IAClE,OAAO,CAAC,aAAa,CAAC,IAAI,CACtB,MAAM,CAAC,MAAM,CAAC,4BAA4B,CACtC,qCAAiB,CAAC,QAAQ,EAC1B,QAAQ,EACR;QACI,cAAc,EAAE;YACZ,uBAAuB,EAAE,IAAI;SAChC;QACD,kCAAkC,EAAE,KAAK;KAC5C,CACJ,CACJ,CAAC;IAEF,+DAA+D;IAC/D,OAAO,CAAC,aAAa,CAAC,IAAI,CACtB,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,sBAAsB,EAAE,CAAC,GAAgB,EAAE,EAAE;QACzE,uEAAuE;QACvE,2EAA2E;QAC3E,MAAM,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,gBAAgB,EAAE,QAAQ,CAAC,GAAG,CAAC;QACnE,IAAI,CAAC,MAAM,EAAE,CAAC;YACV,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,4DAA4D,CAAC,CAAC;YAC7F,OAAO;QACX,CAAC;QACD,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9B,CAAC,CAAC,CACL,CAAC;AACN,CAAC;AAED,SAAgB,UAAU;IACtB,iEAAiE;AACrE,CAAC"} \ No newline at end of file diff --git a/tools/WinGetLogViewer/out/logParser.js b/tools/WinGetLogViewer/out/logParser.js new file mode 100644 index 0000000000..518c7c5fc7 --- /dev/null +++ b/tools/WinGetLogViewer/out/logParser.js @@ -0,0 +1,101 @@ +"use strict"; +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +Object.defineProperty(exports, "__esModule", { value: true }); +exports.LEVEL_CHARS = exports.KNOWN_CHANNELS = void 0; +exports.parseLog = parseLog; +exports.collectChannels = collectChannels; +exports.collectSubchannels = collectSubchannels; +exports.hasExplicitLevels = hasExplicitLevels; +const LEVEL_CHAR_TO_SEVERITY = { + V: 'verbose', + I: 'info', + W: 'warning', + E: 'error', + C: 'crit', +}; +/** All known WinGet primary channels in display order. */ +exports.KNOWN_CHANNELS = [ + 'FAIL', 'CLI', 'SQL', 'REPO', 'YAML', 'CORE', 'TEST', 'CONF', 'WORK', +]; +/** All level chars in severity order. */ +exports.LEVEL_CHARS = ['V', 'I', 'W', 'E', 'C']; +// YYYY-MM-DD HH:MM:SS.mmm [optional: ] [CHAN(+spaces)] rest-of-line +// Year may be 2 or 4 digits for forward/backward compat. +const LOG_LINE_RE = /^(\d{2,4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3})\s+(?:<([VIWEC])>\s+)?\[([A-Z]{2,8})\s*\]\s?(.*)$/; +// Optional subchannel at the very start of the message: [CHAN] or [CHAN ] … +const SUBCHANNEL_RE = /^\[([A-Z]{2,8})\s*\]\s?(.*)$/; +/** + * Parse a raw log text (full file content) into an array of LogEntry objects. + * Lines that do not match the expected format are skipped. + */ +function parseLog(text) { + const lines = text.split(/\r?\n/); + // Drop trailing empty lines (standard file ending or blank lines at EOF). + while (lines.length > 0 && lines[lines.length - 1] === '') { + lines.pop(); + } + const entries = []; + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + const m = LOG_LINE_RE.exec(line); + if (!m) { + // Continuation line — attach to the most recent entry. + if (entries.length > 0) { + const last = entries[entries.length - 1]; + (last.continuationLines ?? (last.continuationLines = [])).push(line); + } + continue; + } + const [, timestamp, rawLevel, channel, rest] = m; + const levelChar = rawLevel; + let subchannel; + let message = rest; + const sub = SUBCHANNEL_RE.exec(rest); + if (sub) { + subchannel = sub[1]; + message = sub[2]; + } + const severity = levelChar + ? LEVEL_CHAR_TO_SEVERITY[levelChar] + : 'info'; + entries.push({ + lineIndex: i, + raw: line, + timestamp, + levelChar, + channel, + subchannel, + message, + severity, + }); + } + return entries; +} +/** Collect the unique set of channels present in the given entries, preserving known order. */ +function collectChannels(entries) { + const found = new Set(entries.map(e => e.channel)); + const ordered = exports.KNOWN_CHANNELS.filter(c => found.has(c)); + // Append any unexpected channel names after the known ones. + for (const c of found) { + if (!exports.KNOWN_CHANNELS.includes(c)) { + ordered.push(c); + } + } + return ordered; +} +/** Collect the unique set of subchannels present in the given entries, sorted. */ +function collectSubchannels(entries) { + const found = new Set(); + for (const e of entries) { + if (e.subchannel) { + found.add(e.subchannel); + } + } + return [...found].sort(); +} +/** Returns true if the log file contains any entries with an explicit level marker. */ +function hasExplicitLevels(entries) { + return entries.some(e => e.levelChar !== undefined); +} +//# sourceMappingURL=logParser.js.map \ No newline at end of file diff --git a/tools/WinGetLogViewer/out/logParser.js.map b/tools/WinGetLogViewer/out/logParser.js.map new file mode 100644 index 0000000000..ba307eb1e1 --- /dev/null +++ b/tools/WinGetLogViewer/out/logParser.js.map @@ -0,0 +1 @@ +{"version":3,"file":"logParser.js","sourceRoot":"","sources":["../src/logParser.ts"],"names":[],"mappings":";AAAA,uCAAuC;AACvC,kCAAkC;;;AAsElC,4BA+CC;AAGD,0CAQC;AAGD,gDAMC;AAGD,8CAEC;AAnGD,MAAM,sBAAsB,GAAgC;IACxD,CAAC,EAAE,SAAS;IACZ,CAAC,EAAE,MAAM;IACT,CAAC,EAAE,SAAS;IACZ,CAAC,EAAE,OAAO;IACV,CAAC,EAAE,MAAM;CACZ,CAAC;AAEF,0DAA0D;AAC7C,QAAA,cAAc,GAAsB;IAC7C,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CACvE,CAAC;AAEF,yCAAyC;AAC5B,QAAA,WAAW,GAAyB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AAE3E,wEAAwE;AACxE,yDAAyD;AACzD,MAAM,WAAW,GAAG,kGAAkG,CAAC;AAEvH,4EAA4E;AAC5E,MAAM,aAAa,GAAG,8BAA8B,CAAC;AAErD;;;GAGG;AACH,SAAgB,QAAQ,CAAC,IAAY;IACjC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAClC,0EAA0E;IAC1E,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC;QAAC,KAAK,CAAC,GAAG,EAAE,CAAC;IAAC,CAAC;IAC3E,MAAM,OAAO,GAAe,EAAE,CAAC;IAE/B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,MAAM,CAAC,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,CAAC,CAAC,EAAE,CAAC;YACL,uDAAuD;YACvD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACrB,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;gBACzC,CAAC,IAAI,CAAC,iBAAiB,KAAtB,IAAI,CAAC,iBAAiB,GAAK,EAAE,EAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/C,CAAC;YACD,SAAS;QACb,CAAC;QAED,MAAM,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;QACjD,MAAM,SAAS,GAAG,QAAiC,CAAC;QAEpD,IAAI,UAA8B,CAAC;QACnC,IAAI,OAAO,GAAG,IAAI,CAAC;QAEnB,MAAM,GAAG,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,GAAG,EAAE,CAAC;YACN,UAAU,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;YACpB,OAAO,GAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QACxB,CAAC;QAED,MAAM,QAAQ,GAAa,SAAS;YAChC,CAAC,CAAC,sBAAsB,CAAC,SAAS,CAAC;YACnC,CAAC,CAAC,MAAM,CAAC;QAEb,OAAO,CAAC,IAAI,CAAC;YACT,SAAS,EAAE,CAAC;YACZ,GAAG,EAAE,IAAI;YACT,SAAS;YACT,SAAS;YACT,OAAO;YACP,UAAU;YACV,OAAO;YACP,QAAQ;SACX,CAAC,CAAC;IACP,CAAC;IAED,OAAO,OAAO,CAAC;AACnB,CAAC;AAED,+FAA+F;AAC/F,SAAgB,eAAe,CAAC,OAAmB;IAC/C,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IACnD,MAAM,OAAO,GAAG,sBAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACzD,4DAA4D;IAC5D,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACpB,IAAI,CAAC,sBAAc,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;YAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAAC,CAAC;IACzD,CAAC;IACD,OAAO,OAAO,CAAC;AACnB,CAAC;AAED,kFAAkF;AAClF,SAAgB,kBAAkB,CAAC,OAAmB;IAClD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACtB,IAAI,CAAC,CAAC,UAAU,EAAE,CAAC;YAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;QAAC,CAAC;IAClD,CAAC;IACD,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;AAC7B,CAAC;AAED,uFAAuF;AACvF,SAAgB,iBAAiB,CAAC,OAAmB;IACjD,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC;AACxD,CAAC"} \ No newline at end of file diff --git a/tools/WinGetLogViewer/out/logViewerProvider.js b/tools/WinGetLogViewer/out/logViewerProvider.js new file mode 100644 index 0000000000..e2f69d3932 --- /dev/null +++ b/tools/WinGetLogViewer/out/logViewerProvider.js @@ -0,0 +1,201 @@ +"use strict"; +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + var desc = Object.getOwnPropertyDescriptor(m, k); + if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { + desc = { enumerable: true, get: function() { return m[k]; } }; + } + Object.defineProperty(o, k2, desc); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || (function () { + var ownKeys = function(o) { + ownKeys = Object.getOwnPropertyNames || function (o) { + var ar = []; + for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; + return ar; + }; + return ownKeys(o); + }; + return function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); + __setModuleDefault(result, mod); + return result; + }; +})(); +Object.defineProperty(exports, "__esModule", { value: true }); +exports.LogViewerProvider = void 0; +const vscode = __importStar(require("vscode")); +const path = __importStar(require("path")); +const fs = __importStar(require("fs")); +const logParser_1 = require("./logParser"); +/** + * CustomReadonlyEditorProvider that renders WinGet log files in a rich WebView. + */ +class LogViewerProvider { + constructor(_context) { + this._context = _context; + /** Track open panels so they can be updated by the follow-mode watcher. */ + this._panels = new Map(); + } + // ── CustomReadonlyEditorProvider ──────────────────────────────── + async openCustomDocument(uri) { + return { uri, dispose: () => { } }; + } + async resolveCustomEditor(document, webviewPanel) { + const filePath = document.uri.fsPath; + webviewPanel.webview.options = { + enableScripts: true, + localResourceRoots: [ + vscode.Uri.file(path.join(this._context.extensionPath, 'media')), + ], + }; + webviewPanel.webview.html = this._buildHtml(webviewPanel.webview); + // Send initial data once the webview is ready. + const sendLog = () => { + try { + const raw = fs.readFileSync(filePath, 'utf8'); + const entries = (0, logParser_1.parseLog)(raw); + webviewPanel.webview.postMessage({ + type: 'load', + entries, + channels: (0, logParser_1.collectChannels)(entries), + subchannels: (0, logParser_1.collectSubchannels)(entries), + hasLevels: (0, logParser_1.hasExplicitLevels)(entries), + }); + } + catch (err) { + vscode.window.showErrorMessage(`WinGet Log Viewer: failed to read ${filePath}: ${err}`); + } + }; + webviewPanel.webview.onDidReceiveMessage(msg => { + if (msg.type === 'ready') { + sendLog(); + } + else if (msg.type === 'export') { + vscode.env.clipboard.writeText(msg.text).then(() => { + const lineCount = msg.text.split('\n').length; + vscode.window.showInformationMessage(`WinGet Log Viewer: ${lineCount} line(s) copied to clipboard.`); + }); + } + }); + // Follow mode: poll for file changes using fs.watchFile (polling is reliable even when + // another process holds the file open, unlike ReadDirectoryChangesW-based watchers). + let lastMtime = 0; + const sendUpdate = () => { + try { + const raw = fs.readFileSync(filePath, 'utf8'); + const entries = (0, logParser_1.parseLog)(raw); + webviewPanel.webview.postMessage({ type: 'update', entries }); + } + catch { /* ignore read errors during live tail */ } + }; + fs.watchFile(filePath, { interval: 500, persistent: false }, (curr, prev) => { + if (curr.mtimeMs !== prev.mtimeMs) { + sendUpdate(); + } + }); + const key = filePath; + this._panels.set(key, { panel: webviewPanel }); + webviewPanel.onDidDispose(() => { + fs.unwatchFile(filePath); + this._panels.delete(key); + }); + } + // ── Public: open any log file in a new panel ───────────────────── + /** + * Open a specific file URI in the viewer (used by the "Open in WinGet Log Viewer" command). + */ + openFile(uri) { + const filePath = uri.fsPath; + const fileName = path.basename(filePath); + const panel = vscode.window.createWebviewPanel(LogViewerProvider.viewType, fileName, vscode.ViewColumn.Active, { + enableScripts: true, + localResourceRoots: [ + vscode.Uri.file(path.join(this._context.extensionPath, 'media')), + ], + retainContextWhenHidden: true, + }); + panel.webview.html = this._buildHtml(panel.webview); + const sendLoad = () => { + try { + const raw = fs.readFileSync(filePath, 'utf8'); + const entries = (0, logParser_1.parseLog)(raw); + panel.webview.postMessage({ + type: 'load', + entries, + channels: (0, logParser_1.collectChannels)(entries), + subchannels: (0, logParser_1.collectSubchannels)(entries), + hasLevels: (0, logParser_1.hasExplicitLevels)(entries), + }); + } + catch (err) { + vscode.window.showErrorMessage(`WinGet Log Viewer: failed to read ${filePath}: ${err}`); + } + }; + panel.webview.onDidReceiveMessage(msg => { + if (msg.type === 'ready') { + sendLoad(); + } + else if (msg.type === 'export') { + vscode.env.clipboard.writeText(msg.text).then(() => { + const lineCount = msg.text.split('\n').length; + vscode.window.showInformationMessage(`WinGet Log Viewer: ${lineCount} line(s) copied to clipboard.`); + }); + } + }); + fs.watchFile(filePath, { interval: 500, persistent: false }, (curr, prev) => { + if (curr.mtimeMs !== prev.mtimeMs) { + try { + const raw = fs.readFileSync(filePath, 'utf8'); + const entries = (0, logParser_1.parseLog)(raw); + panel.webview.postMessage({ type: 'update', entries }); + } + catch { /* ignore */ } + } + }); + const key = filePath + '#manual'; + this._panels.set(key, { panel }); + panel.onDidDispose(() => { + fs.unwatchFile(filePath); + this._panels.delete(key); + }); + } + // ── HTML builder ───────────────────────────────────────────────── + _buildHtml(webview) { + const nonce = this._getNonce(); + const cspSource = webview.cspSource; + const cssUri = webview.asWebviewUri(vscode.Uri.file(path.join(this._context.extensionPath, 'media', 'viewer.css'))); + const jsUri = webview.asWebviewUri(vscode.Uri.file(path.join(this._context.extensionPath, 'media', 'viewer.js'))); + const templatePath = path.join(this._context.extensionPath, 'media', 'viewer.html'); + let html = fs.readFileSync(templatePath, 'utf8'); + html = html + .replace(/\{\{nonce\}\}/g, nonce) + .replace(/\{\{cspSource\}\}/g, cspSource) + .replace(/\{\{viewerCssUri\}\}/g, cssUri.toString()) + .replace(/\{\{viewerJsUri\}\}/g, jsUri.toString()); + return html; + } + _getNonce() { + let text = ''; + const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + for (let i = 0; i < 32; i++) { + text += possible.charAt(Math.floor(Math.random() * possible.length)); + } + return text; + } +} +exports.LogViewerProvider = LogViewerProvider; +LogViewerProvider.viewType = 'wingetLogViewer.logViewer'; +//# sourceMappingURL=logViewerProvider.js.map \ No newline at end of file diff --git a/tools/WinGetLogViewer/out/logViewerProvider.js.map b/tools/WinGetLogViewer/out/logViewerProvider.js.map new file mode 100644 index 0000000000..dba1d6e5ce --- /dev/null +++ b/tools/WinGetLogViewer/out/logViewerProvider.js.map @@ -0,0 +1 @@ +{"version":3,"file":"logViewerProvider.js","sourceRoot":"","sources":["../src/logViewerProvider.ts"],"names":[],"mappings":";AAAA,uCAAuC;AACvC,kCAAkC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAElC,+CAAiC;AACjC,2CAA+B;AAC/B,uCAA6B;AAC7B,2CAA+F;AAE/F;;GAEG;AACH,MAAa,iBAAiB;IAO1B,YAA6B,QAAiC;QAAjC,aAAQ,GAAR,QAAQ,CAAyB;QAH9D,2EAA2E;QAC1D,YAAO,GAAG,IAAI,GAAG,EAA0C,CAAC;IAEZ,CAAC;IAElE,mEAAmE;IAEnE,KAAK,CAAC,kBAAkB,CACpB,GAAe;QAEf,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE,CAAC;IACtC,CAAC;IAED,KAAK,CAAC,mBAAmB,CACrB,QAA+B,EAC/B,YAAiC;QAEjC,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC;QAErC,YAAY,CAAC,OAAO,CAAC,OAAO,GAAG;YAC3B,aAAa,EAAE,IAAI;YACnB,kBAAkB,EAAE;gBAChB,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;aACnE;SACJ,CAAC;QAEF,YAAY,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;QAElE,+CAA+C;QAC/C,MAAM,OAAO,GAAG,GAAG,EAAE;YACjB,IAAI,CAAC;gBACD,MAAM,GAAG,GAAO,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;gBAClD,MAAM,OAAO,GAAG,IAAA,oBAAQ,EAAC,GAAG,CAAC,CAAC;gBAC9B,YAAY,CAAC,OAAO,CAAC,WAAW,CAAC;oBAC7B,IAAI,EAAS,MAAM;oBACnB,OAAO;oBACP,QAAQ,EAAK,IAAA,2BAAe,EAAC,OAAO,CAAC;oBACrC,WAAW,EAAE,IAAA,8BAAkB,EAAC,OAAO,CAAC;oBACxC,SAAS,EAAI,IAAA,6BAAiB,EAAC,OAAO,CAAC;iBAC1C,CAAC,CAAC;YACP,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACX,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,qCAAqC,QAAQ,KAAK,GAAG,EAAE,CAAC,CAAC;YAC5F,CAAC;QACL,CAAC,CAAC;QAEF,YAAY,CAAC,OAAO,CAAC,mBAAmB,CAAC,GAAG,CAAC,EAAE;YAC3C,IAAI,GAAG,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBACvB,OAAO,EAAE,CAAC;YACd,CAAC;iBAAM,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC/B,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;oBAC/C,MAAM,SAAS,GAAI,GAAG,CAAC,IAAe,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;oBAC1D,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAAC,sBAAsB,SAAS,+BAA+B,CAAC,CAAC;gBACzG,CAAC,CAAC,CAAC;YACP,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,uFAAuF;QACvF,qFAAqF;QACrF,IAAI,SAAS,GAAG,CAAC,CAAC;QAClB,MAAM,UAAU,GAAG,GAAG,EAAE;YACpB,IAAI,CAAC;gBACD,MAAM,GAAG,GAAO,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;gBAClD,MAAM,OAAO,GAAG,IAAA,oBAAQ,EAAC,GAAG,CAAC,CAAC;gBAC9B,YAAY,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;YAClE,CAAC;YAAC,MAAM,CAAC,CAAC,yCAAyC,CAAC,CAAC;QACzD,CAAC,CAAC;QAEF,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE;YACxE,IAAI,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC;gBAChC,UAAU,EAAE,CAAC;YACjB,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,MAAM,GAAG,GAAG,QAAQ,CAAC;QACrB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC,CAAC;QAC/C,YAAY,CAAC,YAAY,CAAC,GAAG,EAAE;YAC3B,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;YACzB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;IACP,CAAC;IAED,oEAAoE;IAEpE;;OAEG;IACI,QAAQ,CAAC,GAAe;QAC3B,MAAM,QAAQ,GAAG,GAAG,CAAC,MAAM,CAAC;QAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QAEzC,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,kBAAkB,CAC1C,iBAAiB,CAAC,QAAQ,EAC1B,QAAQ,EACR,MAAM,CAAC,UAAU,CAAC,MAAM,EACxB;YACI,aAAa,EAAE,IAAI;YACnB,kBAAkB,EAAE;gBAChB,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;aACnE;YACD,uBAAuB,EAAE,IAAI;SAChC,CACJ,CAAC;QAEF,KAAK,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAEpD,MAAM,QAAQ,GAAG,GAAG,EAAE;YAClB,IAAI,CAAC;gBACD,MAAM,GAAG,GAAO,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;gBAClD,MAAM,OAAO,GAAG,IAAA,oBAAQ,EAAC,GAAG,CAAC,CAAC;gBAC9B,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC;oBACtB,IAAI,EAAS,MAAM;oBACnB,OAAO;oBACP,QAAQ,EAAK,IAAA,2BAAe,EAAC,OAAO,CAAC;oBACrC,WAAW,EAAE,IAAA,8BAAkB,EAAC,OAAO,CAAC;oBACxC,SAAS,EAAI,IAAA,6BAAiB,EAAC,OAAO,CAAC;iBAC1C,CAAC,CAAC;YACP,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACX,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,qCAAqC,QAAQ,KAAK,GAAG,EAAE,CAAC,CAAC;YAC5F,CAAC;QACL,CAAC,CAAC;QAEF,KAAK,CAAC,OAAO,CAAC,mBAAmB,CAAC,GAAG,CAAC,EAAE;YACpC,IAAI,GAAG,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBACvB,QAAQ,EAAE,CAAC;YACf,CAAC;iBAAM,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC/B,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;oBAC/C,MAAM,SAAS,GAAI,GAAG,CAAC,IAAe,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;oBAC1D,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAAC,sBAAsB,SAAS,+BAA+B,CAAC,CAAC;gBACzG,CAAC,CAAC,CAAC;YACP,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,SAAS,CAAC,QAAQ,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE;YACxE,IAAI,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC;gBAChC,IAAI,CAAC;oBACD,MAAM,GAAG,GAAO,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;oBAClD,MAAM,OAAO,GAAG,IAAA,oBAAQ,EAAC,GAAG,CAAC,CAAC;oBAC9B,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;gBAC3D,CAAC;gBAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC;YAC5B,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,MAAM,GAAG,GAAG,QAAQ,GAAG,SAAS,CAAC;QACjC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QACjC,KAAK,CAAC,YAAY,CAAC,GAAG,EAAE;YACpB,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;YACzB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;IACP,CAAC;IAED,oEAAoE;IAE5D,UAAU,CAAC,OAAuB;QACtC,MAAM,KAAK,GAAU,IAAI,CAAC,SAAS,EAAE,CAAC;QACtC,MAAM,SAAS,GAAM,OAAO,CAAC,SAAS,CAAC;QAEvC,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,CAC/B,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC,CACjF,CAAC;QACF,MAAM,KAAK,GAAG,OAAO,CAAC,YAAY,CAC9B,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC,CAChF,CAAC;QAEF,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,EAAE,OAAO,EAAE,aAAa,CAAC,CAAC;QACpF,IAAI,IAAI,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;QACjD,IAAI,GAAG,IAAI;aACN,OAAO,CAAC,gBAAgB,EAAS,KAAK,CAAC;aACvC,OAAO,CAAC,oBAAoB,EAAM,SAAS,CAAC;aAC5C,OAAO,CAAC,uBAAuB,EAAG,MAAM,CAAC,QAAQ,EAAE,CAAC;aACpD,OAAO,CAAC,sBAAsB,EAAI,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;QACzD,OAAO,IAAI,CAAC;IAChB,CAAC;IAEO,SAAS;QACb,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,MAAM,QAAQ,GAAG,gEAAgE,CAAC;QAClF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;YAC1B,IAAI,IAAI,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;QACzE,CAAC;QACD,OAAO,IAAI,CAAC;IAChB,CAAC;;AAxLL,8CAyLC;AAvL0B,0BAAQ,GAAG,2BAA2B,AAA9B,CAA+B"} \ No newline at end of file diff --git a/tools/WinGetLogViewer/package-lock.json b/tools/WinGetLogViewer/package-lock.json new file mode 100644 index 0000000000..0a486374ea --- /dev/null +++ b/tools/WinGetLogViewer/package-lock.json @@ -0,0 +1,58 @@ +{ + "name": "winget-log-viewer", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "winget-log-viewer", + "version": "0.1.0", + "devDependencies": { + "@types/node": "20.x", + "@types/vscode": "^1.85.0", + "typescript": "^5.3.0" + }, + "engines": { + "vscode": "^1.85.0" + } + }, + "node_modules/@types/node": { + "version": "20.19.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.39.tgz", + "integrity": "sha512-orrrD74MBUyK8jOAD/r0+lfa1I2MO6I+vAkmAWzMYbCcgrN4lCrmK52gRFQq/JRxfYPfonkr4b0jcY7Olqdqbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/vscode": { + "version": "1.115.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.115.0.tgz", + "integrity": "sha512-/M8cdznOlqtMqduHKKlIF00v4eum4ZWKgn8YoPRKcN6PDdvoWeeqDaQSnw63ipDbq1Uzz78Wndk/d0uSPwORfA==", + "dev": true, + "license": "MIT" + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + } + } +} diff --git a/tools/WinGetLogViewer/package.json b/tools/WinGetLogViewer/package.json new file mode 100644 index 0000000000..42c38b1c48 --- /dev/null +++ b/tools/WinGetLogViewer/package.json @@ -0,0 +1,87 @@ +{ + "name": "winget-log-viewer", + "displayName": "WinGet Log Viewer", + "description": "Rich viewer for WinGet diagnostic log files with channel filtering, highlighting, and live follow mode.", + "version": "0.1.0", + "publisher": "microsoft", + "engines": { + "vscode": "^1.85.0" + }, + "categories": [ + "Other" + ], + "activationEvents": [], + "main": "./out/extension.js", + "contributes": { + "customEditors": [ + { + "viewType": "wingetLogViewer.logViewer", + "displayName": "WinGet Log Viewer", + "selector": [ + { + "filenamePattern": "WinGet-*.log" + }, + { + "filenamePattern": "WinGetCOM-*.log" + } + ], + "priority": "default" + } + ], + "commands": [ + { + "command": "wingetLogViewer.open", + "title": "Open in WinGet Log Viewer", + "category": "WinGet Log Viewer" + } + ], + "languages": [ + { + "id": "winget-log", + "aliases": [ + "WinGet Log" + ], + "filenamePatterns": [ + "WinGet-*.log", + "WinGetCOM-*.log" + ], + "configuration": "./language-configuration.json" + } + ], + "grammars": [ + { + "language": "winget-log", + "scopeName": "text.winget-log", + "path": "./syntaxes/winget-log.tmLanguage.json" + } + ], + "menus": { + "explorer/context": [ + { + "command": "wingetLogViewer.open", + "when": "resourceExtname == .log", + "group": "navigation" + } + ], + "editor/title": [ + { + "command": "wingetLogViewer.open", + "when": "resourceExtname == .log && activeCustomEditorId != 'wingetLogViewer.logViewer'", + "group": "navigation" + } + ] + } + }, + "scripts": { + "vscode:prepublish": "npm run compile", + "compile": "tsc -p ./ && cp src/viewer.html media/viewer.html 2>/dev/null || true", + "watch": "tsc -watch -p ./", + "pretest": "npm run compile", + "lint": "eslint src --ext ts" + }, + "devDependencies": { + "@types/vscode": "^1.85.0", + "@types/node": "20.x", + "typescript": "^5.3.0" + } +} diff --git a/tools/WinGetLogViewer/src/extension.ts b/tools/WinGetLogViewer/src/extension.ts new file mode 100644 index 0000000000..a57d751782 --- /dev/null +++ b/tools/WinGetLogViewer/src/extension.ts @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import * as vscode from 'vscode'; +import { LogViewerProvider } from './logViewerProvider'; + +export function activate(context: vscode.ExtensionContext): void { + const provider = new LogViewerProvider(context); + + // Register the custom editor for WinGet-*.log and WinGetCOM-*.log + context.subscriptions.push( + vscode.window.registerCustomEditorProvider( + LogViewerProvider.viewType, + provider, + { + webviewOptions: { + retainContextWhenHidden: true, + }, + supportsMultipleEditorsPerDocument: false, + }, + ), + ); + + // "Open in WinGet Log Viewer" command — works on any .log file + context.subscriptions.push( + vscode.commands.registerCommand('wingetLogViewer.open', (uri?: vscode.Uri) => { + // When invoked from the editor title or context menu, uri is provided. + // When invoked from the command palette, use the active editor's document. + const target = uri ?? vscode.window.activeTextEditor?.document.uri; + if (!target) { + vscode.window.showErrorMessage('WinGet Log Viewer: no file to open. Open a log file first.'); + return; + } + provider.openFile(target); + }), + ); +} + +export function deactivate(): void { + // Nothing to clean up; subscriptions are disposed automatically. +} diff --git a/tools/WinGetLogViewer/src/logParser.ts b/tools/WinGetLogViewer/src/logParser.ts new file mode 100644 index 0000000000..9604ce1295 --- /dev/null +++ b/tools/WinGetLogViewer/src/logParser.ts @@ -0,0 +1,144 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +/** + * A parsed WinGet log entry. + * + * Log line format (new): + * YYYY-MM-DD HH:MM:SS.mmm [CHAN] [SUBCHAN] message + * + * Log line format (old, without level marker): + * YYYY-MM-DD HH:MM:SS.mmm [CHAN] [SUBCHAN] message + * + * The subchannel is optional and appears when a sub-component routes its logs + * through a parent channel. In that case the original channel tag is embedded + * as the first token of the message text. + */ +export interface LogEntry { + /** 0-based index in the original file. */ + lineIndex: number; + /** Raw, unmodified primary log line. */ + raw: string; + /** Timestamp string as it appears in the file, e.g. "2026-04-14 22:39:42.041". */ + timestamp: string; + /** Explicit level char from marker (V/I/W/E/C), or undefined for old-format logs. */ + levelChar?: LevelChar; + /** Primary channel name, e.g. "CLI", "CORE", "FAIL". */ + channel: string; + /** Optional subchannel detected from the message prefix, e.g. "REPO". */ + subchannel?: string; + /** Message text after channel (and optional subchannel) have been stripped. */ + message: string; + /** Severity derived from the explicit level marker when present. */ + severity: Severity; + /** + * Raw text of any lines that followed this entry without a timestamp of their own. + * These are continuation lines (e.g. multi-line output, stack traces) that belong + * to this log entry. + */ + continuationLines?: string[]; +} + +export type LevelChar = 'V' | 'I' | 'W' | 'E' | 'C'; +export type Severity = 'verbose' | 'info' | 'warning' | 'error' | 'crit'; + +const LEVEL_CHAR_TO_SEVERITY: Record = { + V: 'verbose', + I: 'info', + W: 'warning', + E: 'error', + C: 'crit', +}; + +/** All known WinGet primary channels in display order. */ +export const KNOWN_CHANNELS: readonly string[] = [ + 'FAIL', 'CLI', 'SQL', 'REPO', 'YAML', 'CORE', 'TEST', 'CONF', 'WORK', +]; + +/** All level chars in severity order. */ +export const LEVEL_CHARS: readonly LevelChar[] = ['V', 'I', 'W', 'E', 'C']; + +// YYYY-MM-DD HH:MM:SS.mmm [optional: ] [CHAN(+spaces)] rest-of-line +// Year may be 2 or 4 digits for forward/backward compat. +const LOG_LINE_RE = /^(\d{2,4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3})\s+(?:<([VIWEC])>\s+)?\[([A-Z]{2,8})\s*\]\s?(.*)$/; + +// Optional subchannel at the very start of the message: [CHAN] or [CHAN ] … +const SUBCHANNEL_RE = /^\[([A-Z]{2,8})\s*\]\s?(.*)$/; + +/** + * Parse a raw log text (full file content) into an array of LogEntry objects. + * Lines that do not match the expected format are skipped. + */ +export function parseLog(text: string): LogEntry[] { + const lines = text.split(/\r?\n/); + // Drop trailing empty lines (standard file ending or blank lines at EOF). + while (lines.length > 0 && lines[lines.length - 1] === '') { lines.pop(); } + const entries: LogEntry[] = []; + + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + const m = LOG_LINE_RE.exec(line); + if (!m) { + // Continuation line — attach to the most recent entry. + if (entries.length > 0) { + const last = entries[entries.length - 1]; + (last.continuationLines ??= []).push(line); + } + continue; + } + + const [, timestamp, rawLevel, channel, rest] = m; + const levelChar = rawLevel as LevelChar | undefined; + + let subchannel: string | undefined; + let message = rest; + + const sub = SUBCHANNEL_RE.exec(rest); + if (sub) { + subchannel = sub[1]; + message = sub[2]; + } + + const severity: Severity = levelChar + ? LEVEL_CHAR_TO_SEVERITY[levelChar] + : 'info'; + + entries.push({ + lineIndex: i, + raw: line, + timestamp, + levelChar, + channel, + subchannel, + message, + severity, + }); + } + + return entries; +} + +/** Collect the unique set of channels present in the given entries, preserving known order. */ +export function collectChannels(entries: LogEntry[]): string[] { + const found = new Set(entries.map(e => e.channel)); + const ordered = KNOWN_CHANNELS.filter(c => found.has(c)); + // Append any unexpected channel names after the known ones. + for (const c of found) { + if (!KNOWN_CHANNELS.includes(c)) { ordered.push(c); } + } + return ordered; +} + +/** Collect the unique set of subchannels present in the given entries, sorted. */ +export function collectSubchannels(entries: LogEntry[]): string[] { + const found = new Set(); + for (const e of entries) { + if (e.subchannel) { found.add(e.subchannel); } + } + return [...found].sort(); +} + +/** Returns true if the log file contains any entries with an explicit level marker. */ +export function hasExplicitLevels(entries: LogEntry[]): boolean { + return entries.some(e => e.levelChar !== undefined); +} diff --git a/tools/WinGetLogViewer/src/logViewerProvider.ts b/tools/WinGetLogViewer/src/logViewerProvider.ts new file mode 100644 index 0000000000..ecf820b86c --- /dev/null +++ b/tools/WinGetLogViewer/src/logViewerProvider.ts @@ -0,0 +1,197 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import * as vscode from 'vscode'; +import * as path from 'path'; +import * as fs from 'fs'; +import { parseLog, collectChannels, collectSubchannels, hasExplicitLevels } from './logParser'; + +/** + * CustomReadonlyEditorProvider that renders WinGet log files in a rich WebView. + */ +export class LogViewerProvider implements vscode.CustomReadonlyEditorProvider { + + public static readonly viewType = 'wingetLogViewer.logViewer'; + + /** Track open panels so they can be updated by the follow-mode watcher. */ + private readonly _panels = new Map(); + + constructor(private readonly _context: vscode.ExtensionContext) {} + + // ── CustomReadonlyEditorProvider ──────────────────────────────── + + async openCustomDocument( + uri: vscode.Uri, + ): Promise { + return { uri, dispose: () => {} }; + } + + async resolveCustomEditor( + document: vscode.CustomDocument, + webviewPanel: vscode.WebviewPanel, + ): Promise { + const filePath = document.uri.fsPath; + + webviewPanel.webview.options = { + enableScripts: true, + localResourceRoots: [ + vscode.Uri.file(path.join(this._context.extensionPath, 'media')), + ], + }; + + webviewPanel.webview.html = this._buildHtml(webviewPanel.webview); + + // Send initial data once the webview is ready. + const sendLog = () => { + try { + const raw = fs.readFileSync(filePath, 'utf8'); + const entries = parseLog(raw); + webviewPanel.webview.postMessage({ + type: 'load', + entries, + channels: collectChannels(entries), + subchannels: collectSubchannels(entries), + hasLevels: hasExplicitLevels(entries), + }); + } catch (err) { + vscode.window.showErrorMessage(`WinGet Log Viewer: failed to read ${filePath}: ${err}`); + } + }; + + webviewPanel.webview.onDidReceiveMessage(msg => { + if (msg.type === 'ready') { + sendLog(); + } else if (msg.type === 'export') { + vscode.env.clipboard.writeText(msg.text).then(() => { + const lineCount = (msg.text as string).split('\n').length; + vscode.window.showInformationMessage(`WinGet Log Viewer: ${lineCount} line(s) copied to clipboard.`); + }); + } + }); + + // Follow mode: poll for file changes using fs.watchFile (polling is reliable even when + // another process holds the file open, unlike ReadDirectoryChangesW-based watchers). + let lastMtime = 0; + const sendUpdate = () => { + try { + const raw = fs.readFileSync(filePath, 'utf8'); + const entries = parseLog(raw); + webviewPanel.webview.postMessage({ type: 'update', entries }); + } catch { /* ignore read errors during live tail */ } + }; + + fs.watchFile(filePath, { interval: 500, persistent: false }, (curr, prev) => { + if (curr.mtimeMs !== prev.mtimeMs) { + sendUpdate(); + } + }); + + const key = filePath; + this._panels.set(key, { panel: webviewPanel }); + webviewPanel.onDidDispose(() => { + fs.unwatchFile(filePath); + this._panels.delete(key); + }); + } + + // ── Public: open any log file in a new panel ───────────────────── + + /** + * Open a specific file URI in the viewer (used by the "Open in WinGet Log Viewer" command). + */ + public openFile(uri: vscode.Uri): void { + const filePath = uri.fsPath; + const fileName = path.basename(filePath); + + const panel = vscode.window.createWebviewPanel( + LogViewerProvider.viewType, + fileName, + vscode.ViewColumn.Active, + { + enableScripts: true, + localResourceRoots: [ + vscode.Uri.file(path.join(this._context.extensionPath, 'media')), + ], + retainContextWhenHidden: true, + }, + ); + + panel.webview.html = this._buildHtml(panel.webview); + + const sendLoad = () => { + try { + const raw = fs.readFileSync(filePath, 'utf8'); + const entries = parseLog(raw); + panel.webview.postMessage({ + type: 'load', + entries, + channels: collectChannels(entries), + subchannels: collectSubchannels(entries), + hasLevels: hasExplicitLevels(entries), + }); + } catch (err) { + vscode.window.showErrorMessage(`WinGet Log Viewer: failed to read ${filePath}: ${err}`); + } + }; + + panel.webview.onDidReceiveMessage(msg => { + if (msg.type === 'ready') { + sendLoad(); + } else if (msg.type === 'export') { + vscode.env.clipboard.writeText(msg.text).then(() => { + const lineCount = (msg.text as string).split('\n').length; + vscode.window.showInformationMessage(`WinGet Log Viewer: ${lineCount} line(s) copied to clipboard.`); + }); + } + }); + + fs.watchFile(filePath, { interval: 500, persistent: false }, (curr, prev) => { + if (curr.mtimeMs !== prev.mtimeMs) { + try { + const raw = fs.readFileSync(filePath, 'utf8'); + const entries = parseLog(raw); + panel.webview.postMessage({ type: 'update', entries }); + } catch { /* ignore */ } + } + }); + + const key = filePath + '#manual'; + this._panels.set(key, { panel }); + panel.onDidDispose(() => { + fs.unwatchFile(filePath); + this._panels.delete(key); + }); + } + + // ── HTML builder ───────────────────────────────────────────────── + + private _buildHtml(webview: vscode.Webview): string { + const nonce = this._getNonce(); + const cspSource = webview.cspSource; + + const cssUri = webview.asWebviewUri( + vscode.Uri.file(path.join(this._context.extensionPath, 'media', 'viewer.css')), + ); + const jsUri = webview.asWebviewUri( + vscode.Uri.file(path.join(this._context.extensionPath, 'media', 'viewer.js')), + ); + + const templatePath = path.join(this._context.extensionPath, 'media', 'viewer.html'); + let html = fs.readFileSync(templatePath, 'utf8'); + html = html + .replace(/\{\{nonce\}\}/g, nonce) + .replace(/\{\{cspSource\}\}/g, cspSource) + .replace(/\{\{viewerCssUri\}\}/g, cssUri.toString()) + .replace(/\{\{viewerJsUri\}\}/g, jsUri.toString()); + return html; + } + + private _getNonce(): string { + let text = ''; + const possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + for (let i = 0; i < 32; i++) { + text += possible.charAt(Math.floor(Math.random() * possible.length)); + } + return text; + } +} diff --git a/tools/WinGetLogViewer/syntaxes/winget-log.tmLanguage.json b/tools/WinGetLogViewer/syntaxes/winget-log.tmLanguage.json new file mode 100644 index 0000000000..606b052602 --- /dev/null +++ b/tools/WinGetLogViewer/syntaxes/winget-log.tmLanguage.json @@ -0,0 +1,41 @@ +{ + "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", + "name": "WinGet Log", + "scopeName": "text.winget-log", + "patterns": [ + { "include": "#logLine" } + ], + "repository": { + "logLine": { + "comment": "Full log line: TIMESTAMP [] [CHAN] [SUBCHAN] message", + "match": "^(\\d{2,4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d{3})\\s+(?:(<[VIWEC]>)\\s+)?(\\[(FAIL|CLI |SQL |REPO|YAML|CORE|TEST|CONF|WORK)\\s*\\])(\\s+\\[([A-Z]{2,8})\\s*\\])?(.*)$", + "captures": { + "1": { "name": "constant.numeric.timestamp.winget-log" }, + "2": { "name": "keyword.operator.level-marker.winget-log" }, + "3": { "patterns": [{ "include": "#channelBadge" }] }, + "6": { "name": "entity.name.type.subchannel.winget-log" }, + "7": { "patterns": [{ "include": "#messageText" }] } + } + }, + "channelBadge": { + "patterns": [ + { "match": "\\[FAIL\\s*\\]", "name": "invalid.illegal.channel.fail.winget-log" }, + { "match": "\\[CLI\\s*\\]", "name": "support.function.channel.cli.winget-log" }, + { "match": "\\[SQL\\s*\\]", "name": "entity.name.function.channel.sql.winget-log" }, + { "match": "\\[REPO\\s*\\]", "name": "support.class.channel.repo.winget-log" }, + { "match": "\\[YAML\\s*\\]", "name": "constant.language.channel.yaml.winget-log" }, + { "match": "\\[CORE\\s*\\]", "name": "comment.channel.core.winget-log" }, + { "match": "\\[TEST\\s*\\]", "name": "markup.inserted.channel.test.winget-log" }, + { "match": "\\[CONF\\s*\\]", "name": "keyword.control.channel.conf.winget-log" }, + { "match": "\\[WORK\\s*\\]", "name": "variable.parameter.channel.work.winget-log" } + ] + }, + "messageText": { + "patterns": [ + { "match": "\\b(Error|Fail(ed|ure)?|Exception|HRESULT|0x[0-9a-fA-F]+)\\b", "name": "invalid.illegal.error-keyword.winget-log" }, + { "match": "\\b(Warn(ing)?|Deprecated)\\b", "name": "support.type.warning-keyword.winget-log" }, + { "match": "\\b(Verbose|Trace|Debug)\\b", "name": "comment.verbose-keyword.winget-log" } + ] + } + } +} diff --git a/tools/WinGetLogViewer/tsconfig.json b/tools/WinGetLogViewer/tsconfig.json new file mode 100644 index 0000000000..61d02af9c9 --- /dev/null +++ b/tools/WinGetLogViewer/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "ES2020", + "lib": ["ES2020"], + "outDir": "./out", + "rootDir": "./src", + "sourceMap": true, + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true + }, + "include": ["src/**/*.ts"], + "exclude": ["node_modules", ".vscode-test"] +} From 6d2630dc529e062513a1747210113616e0997e9c Mon Sep 17 00:00:00 2001 From: JohnMcPMS Date: Thu, 16 Apr 2026 10:03:11 -0700 Subject: [PATCH 2/4] Add packaging and fixes --- .gitignore | 3 + tools/WinGetLogViewer/.vscodeignore | 5 +- tools/WinGetLogViewer/LICENSE | 21 + tools/WinGetLogViewer/README.md | 37 +- tools/WinGetLogViewer/package-lock.json | 3963 ++++++++++++++++++++++- tools/WinGetLogViewer/package.json | 11 +- 6 files changed, 4016 insertions(+), 24 deletions(-) create mode 100644 tools/WinGetLogViewer/LICENSE diff --git a/.gitignore b/.gitignore index 51dad2a822..28817289a2 100644 --- a/.gitignore +++ b/.gitignore @@ -351,3 +351,6 @@ src/PowerShell/scripts/Module # Interop nuget src/WinGetUtilInterop/scripts/Nuget* + +# VS Code extension packages +*.vsix diff --git a/tools/WinGetLogViewer/.vscodeignore b/tools/WinGetLogViewer/.vscodeignore index 4e0713d748..f223f9943d 100644 --- a/tools/WinGetLogViewer/.vscodeignore +++ b/tools/WinGetLogViewer/.vscodeignore @@ -1,4 +1,7 @@ -out node_modules .vscode-test *.vsix +src +tsconfig.json +.eslintrc.json +out/**/*.map diff --git a/tools/WinGetLogViewer/LICENSE b/tools/WinGetLogViewer/LICENSE new file mode 100644 index 0000000000..4b1ad51b2f --- /dev/null +++ b/tools/WinGetLogViewer/LICENSE @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. All rights reserved. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE diff --git a/tools/WinGetLogViewer/README.md b/tools/WinGetLogViewer/README.md index 958248ffec..18ba5d4cf8 100644 --- a/tools/WinGetLogViewer/README.md +++ b/tools/WinGetLogViewer/README.md @@ -9,17 +9,17 @@ Opens automatically for `WinGet-*.log` and `WinGetCOM-*.log` files. Use the **"O **Channel color badges** — each of the nine WinGet channels gets a distinct color: -| Badge | Channel | Description | -|-------|---------|-------------| -| ![FAIL](#) | `FAIL` | Failures / exceptions | -| ![CLI](#) | `CLI` | CLI command handling | -| ![SQL](#) | `SQL` | SQLite / index operations | -| ![REPO](#) | `REPO` | Repository / source operations | -| ![YAML](#) | `YAML` | YAML manifest parsing | -| ![CORE](#) | `CORE` | Core runtime | -| ![TEST](#) | `TEST` | Test infrastructure | -| ![CONF](#) | `CONF` | Configuration / DSC | -| ![WORK](#) | `WORK` | Workflow execution | +| Channel | Description | +|---------|-------------| +| 🔴 `FAIL` | Failures / exceptions | +| 🔵 `CLI` | CLI command handling | +| 🟣 `SQL` | SQLite / index operations | +| 🩵 `REPO` | Repository / source operations | +| 🟡 `YAML` | YAML manifest parsing | +| ⬜ `CORE` | Core runtime | +| 🟢 `TEST` | Test infrastructure | +| 🩶 `CONF` | Configuration / DSC | +| 🟠 `WORK` | Workflow execution | **Subchannel detection** — when a sub-component routes its log lines through a parent channel, the original `[CHAN]` tag appears at the start of the message. The viewer detects this and renders it as a secondary subchannel badge. @@ -45,10 +45,12 @@ When a WinGet log file is opened in VS Code's standard text editor, the TextMate ## Log format ``` -YY-MM-DD HH:MM:SS.mmm [CHAN] message -YY-MM-DD HH:MM:SS.mmm [CHAN] [SUBCHAN] message ← subchannel variant +YYYY-MM-DD HH:MM:SS.mmm [CHAN] message +YYYY-MM-DD HH:MM:SS.mmm [CHAN] [SUBCHAN] message ← subchannel variant ``` +Where `` is an optional single-letter severity marker: `V`=Verbose, `I`=Info, `W`=Warning, `E`=Error, `C`=Critical. Older log files without the marker are also supported. + ## Development ### Prerequisites @@ -72,11 +74,14 @@ npm run compile ### Package ```bash -npm install -g @vscode/vsce -vsce package +npm run package ``` -This produces a `.vsix` file you can install via **Extensions: Install from VSIX…** +This produces `winget-log-viewer-.vsix`. Install it via **Extensions: Install from VSIX…** or: + +```bash +code --install-extension winget-log-viewer-0.1.0.vsix +``` ## Keyboard shortcuts diff --git a/tools/WinGetLogViewer/package-lock.json b/tools/WinGetLogViewer/package-lock.json index 0a486374ea..562d73523c 100644 --- a/tools/WinGetLogViewer/package-lock.json +++ b/tools/WinGetLogViewer/package-lock.json @@ -10,12 +10,543 @@ "devDependencies": { "@types/node": "20.x", "@types/vscode": "^1.85.0", + "@vscode/vsce": "^3.0.0", "typescript": "^5.3.0" }, "engines": { "vscode": "^1.85.0" } }, + "node_modules/@azu/format-text": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@azu/format-text/-/format-text-1.0.2.tgz", + "integrity": "sha512-Swi4N7Edy1Eqq82GxgEECXSSLyn6GOb5htRFPzBDdUkECGXtlf12ynO5oJSpWKPwCaUssOu7NfhDcCWpIC6Ywg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@azu/style-format": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@azu/style-format/-/style-format-1.0.1.tgz", + "integrity": "sha512-AHcTojlNBdD/3/KxIKlg8sxIWHfOtQszLvOpagLTO+bjC3u7SAszu1lf//u7JJC50aUSH+BVWDD/KvaA6Gfn5g==", + "dev": true, + "license": "WTFPL", + "dependencies": { + "@azu/format-text": "^1.0.1" + } + }, + "node_modules/@azure/abort-controller": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.1.2.tgz", + "integrity": "sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@azure/core-auth": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.10.1.tgz", + "integrity": "sha512-ykRMW8PjVAn+RS6ww5cmK9U2CyH9p4Q88YJwvUslfuMmN98w/2rdGRLPqJYObapBCdzBVeDgYWdJnFPFb7qzpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-util": "^1.13.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/core-client": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.10.1.tgz", + "integrity": "sha512-Nh5PhEOeY6PrnxNPsEHRr9eimxLwgLlpmguQaHKBinFYA/RU9+kOYVOQqOrTsCL+KSxrLLl1gD8Dk5BFW/7l/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.10.0", + "@azure/core-rest-pipeline": "^1.22.0", + "@azure/core-tracing": "^1.3.0", + "@azure/core-util": "^1.13.0", + "@azure/logger": "^1.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/core-rest-pipeline": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.23.0.tgz", + "integrity": "sha512-Evs1INHo+jUjwHi1T6SG6Ua/LHOQBCLuKEEE6efIpt4ZOoNonaT1kP32GoOcdNDbfqsD2445CPri3MubBy5DEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.10.0", + "@azure/core-tracing": "^1.3.0", + "@azure/core-util": "^1.13.0", + "@azure/logger": "^1.3.0", + "@typespec/ts-http-runtime": "^0.3.4", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/core-tracing": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.3.1.tgz", + "integrity": "sha512-9MWKevR7Hz8kNzzPLfX4EAtGM2b8mr50HPDBvio96bURP/9C+HjdH3sBlLSNNrvRAr5/k/svoH457gB5IKpmwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/core-util": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.13.1.tgz", + "integrity": "sha512-XPArKLzsvl0Hf0CaGyKHUyVgF7oDnhKoP85Xv6M4StF/1AhfORhZudHtOyf2s+FcbuQ9dPRAjB8J2KvRRMUK2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@typespec/ts-http-runtime": "^0.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/identity": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.13.1.tgz", + "integrity": "sha512-5C/2WD5Vb1lHnZS16dNQRPMjN6oV/Upba+C9nBIs15PmOi6A3ZGs4Lr2u60zw4S04gi+u3cEXiqTVP7M4Pz3kw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.9.0", + "@azure/core-client": "^1.9.2", + "@azure/core-rest-pipeline": "^1.17.0", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.11.0", + "@azure/logger": "^1.0.0", + "@azure/msal-browser": "^5.5.0", + "@azure/msal-node": "^5.1.0", + "open": "^10.1.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/logger": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.3.0.tgz", + "integrity": "sha512-fCqPIfOcLE+CGqGPd66c8bZpwAji98tZ4JI9i/mlTNTlsIWslCfpg48s/ypyLxZTump5sypjrKn2/kY7q8oAbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typespec/ts-http-runtime": "^0.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@azure/msal-browser": { + "version": "5.6.3", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-5.6.3.tgz", + "integrity": "sha512-sTjMtUm+bJpENU/1WlRzHEsgEHppZDZ1EtNyaOODg/sQBtMxxJzGB+MOCM+T2Q5Qe1fKBrdxUmjyRxm0r7Ez9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/msal-common": "16.4.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-common": { + "version": "16.4.1", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-16.4.1.tgz", + "integrity": "sha512-Bl8f+w37xkXsYh7QRkAKCFGYtWMYuOVO7Lv+BxILrvGz3HbIEF22Pt0ugyj0QPOl6NLrHcnNUQ9yeew98P/5iw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-node": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-5.1.2.tgz", + "integrity": "sha512-DoeSJ9U5KPAIZoHsPywvfEj2MhBniQe0+FSpjLUTdWoIkI999GB5USkW6nNEHnIaLVxROHXvprWA1KzdS1VQ4A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/msal-common": "16.4.1", + "jsonwebtoken": "^9.0.0", + "uuid": "^8.3.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@isaacs/cliui": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-9.0.0.tgz", + "integrity": "sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@secretlint/config-creator": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/config-creator/-/config-creator-10.2.2.tgz", + "integrity": "sha512-BynOBe7Hn3LJjb3CqCHZjeNB09s/vgf0baBaHVw67w7gHF0d25c3ZsZ5+vv8TgwSchRdUCRrbbcq5i2B1fJ2QQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/types": "^10.2.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/config-loader": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/config-loader/-/config-loader-10.2.2.tgz", + "integrity": "sha512-ndjjQNgLg4DIcMJp4iaRD6xb9ijWQZVbd9694Ol2IszBIbGPPkwZHzJYKICbTBmh6AH/pLr0CiCaWdGJU7RbpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/profiler": "^10.2.2", + "@secretlint/resolver": "^10.2.2", + "@secretlint/types": "^10.2.2", + "ajv": "^8.17.1", + "debug": "^4.4.1", + "rc-config-loader": "^4.1.3" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/core": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/core/-/core-10.2.2.tgz", + "integrity": "sha512-6rdwBwLP9+TO3rRjMVW1tX+lQeo5gBbxl1I5F8nh8bgGtKwdlCMhMKsBWzWg1ostxx/tIG7OjZI0/BxsP8bUgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/profiler": "^10.2.2", + "@secretlint/types": "^10.2.2", + "debug": "^4.4.1", + "structured-source": "^4.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/formatter": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/formatter/-/formatter-10.2.2.tgz", + "integrity": "sha512-10f/eKV+8YdGKNQmoDUD1QnYL7TzhI2kzyx95vsJKbEa8akzLAR5ZrWIZ3LbcMmBLzxlSQMMccRmi05yDQ5YDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/resolver": "^10.2.2", + "@secretlint/types": "^10.2.2", + "@textlint/linter-formatter": "^15.2.0", + "@textlint/module-interop": "^15.2.0", + "@textlint/types": "^15.2.0", + "chalk": "^5.4.1", + "debug": "^4.4.1", + "pluralize": "^8.0.0", + "strip-ansi": "^7.1.0", + "table": "^6.9.0", + "terminal-link": "^4.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/formatter/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@secretlint/node": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/node/-/node-10.2.2.tgz", + "integrity": "sha512-eZGJQgcg/3WRBwX1bRnss7RmHHK/YlP/l7zOQsrjexYt6l+JJa5YhUmHbuGXS94yW0++3YkEJp0kQGYhiw1DMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/config-loader": "^10.2.2", + "@secretlint/core": "^10.2.2", + "@secretlint/formatter": "^10.2.2", + "@secretlint/profiler": "^10.2.2", + "@secretlint/source-creator": "^10.2.2", + "@secretlint/types": "^10.2.2", + "debug": "^4.4.1", + "p-map": "^7.0.3" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/profiler": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/profiler/-/profiler-10.2.2.tgz", + "integrity": "sha512-qm9rWfkh/o8OvzMIfY8a5bCmgIniSpltbVlUVl983zDG1bUuQNd1/5lUEeWx5o/WJ99bXxS7yNI4/KIXfHexig==", + "dev": true, + "license": "MIT" + }, + "node_modules/@secretlint/resolver": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/resolver/-/resolver-10.2.2.tgz", + "integrity": "sha512-3md0cp12e+Ae5V+crPQYGd6aaO7ahw95s28OlULGyclyyUtf861UoRGS2prnUrKh7MZb23kdDOyGCYb9br5e4w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@secretlint/secretlint-formatter-sarif": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/secretlint-formatter-sarif/-/secretlint-formatter-sarif-10.2.2.tgz", + "integrity": "sha512-ojiF9TGRKJJw308DnYBucHxkpNovDNu1XvPh7IfUp0A12gzTtxuWDqdpuVezL7/IP8Ua7mp5/VkDMN9OLp1doQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "node-sarif-builder": "^3.2.0" + } + }, + "node_modules/@secretlint/secretlint-rule-no-dotenv": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/secretlint-rule-no-dotenv/-/secretlint-rule-no-dotenv-10.2.2.tgz", + "integrity": "sha512-KJRbIShA9DVc5Va3yArtJ6QDzGjg3PRa1uYp9As4RsyKtKSSZjI64jVca57FZ8gbuk4em0/0Jq+uy6485wxIdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/types": "^10.2.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/secretlint-rule-preset-recommend": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/secretlint-rule-preset-recommend/-/secretlint-rule-preset-recommend-10.2.2.tgz", + "integrity": "sha512-K3jPqjva8bQndDKJqctnGfwuAxU2n9XNCPtbXVI5JvC7FnQiNg/yWlQPbMUlBXtBoBGFYp08A94m6fvtc9v+zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/source-creator": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/source-creator/-/source-creator-10.2.2.tgz", + "integrity": "sha512-h6I87xJfwfUTgQ7irWq7UTdq/Bm1RuQ/fYhA3dtTIAop5BwSFmZyrchph4WcoEvbN460BWKmk4RYSvPElIIvxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/types": "^10.2.2", + "istextorbinary": "^9.5.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/types": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/types/-/types-10.2.2.tgz", + "integrity": "sha512-Nqc90v4lWCXyakD6xNyNACBJNJ0tNCwj2WNk/7ivyacYHxiITVgmLUFXTBOeCdy79iz6HtN9Y31uw/jbLrdOAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@textlint/ast-node-types": { + "version": "15.5.4", + "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-15.5.4.tgz", + "integrity": "sha512-bVtB6VEy9U9DpW8cTt25k5T+lz86zV5w6ImePZqY1AXzSuPhqQNT77lkMPxonXzUducEIlSvUu3o7sKw3y9+Sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@textlint/linter-formatter": { + "version": "15.5.4", + "resolved": "https://registry.npmjs.org/@textlint/linter-formatter/-/linter-formatter-15.5.4.tgz", + "integrity": "sha512-D9qJedKBLmAo+kiudop4UKgSxXMi4O8U86KrCidVXZ9RsK0NSVIw6+r2rlMUOExq79iEY81FRENyzmNVRxDBsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azu/format-text": "^1.0.2", + "@azu/style-format": "^1.0.1", + "@textlint/module-interop": "15.5.4", + "@textlint/resolver": "15.5.4", + "@textlint/types": "15.5.4", + "chalk": "^4.1.2", + "debug": "^4.4.3", + "js-yaml": "^4.1.1", + "lodash": "^4.18.1", + "pluralize": "^2.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "table": "^6.9.0", + "text-table": "^0.2.0" + } + }, + "node_modules/@textlint/linter-formatter/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@textlint/linter-formatter/node_modules/pluralize": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-2.0.0.tgz", + "integrity": "sha512-TqNZzQCD4S42De9IfnnBvILN7HAW7riLqsCyp8lgjXeysyPlX5HhqKAcJHHHb9XskE4/a+7VGC9zzx8Ls0jOAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@textlint/linter-formatter/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@textlint/module-interop": { + "version": "15.5.4", + "resolved": "https://registry.npmjs.org/@textlint/module-interop/-/module-interop-15.5.4.tgz", + "integrity": "sha512-JyAUd26ll3IFF87LP0uGoa8Tzw5ZKiYvGs6v8jLlzyND1lUYCI4+2oIAslrODLkf0qwoCaJrBQWM3wsw+asVGQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@textlint/resolver": { + "version": "15.5.4", + "resolved": "https://registry.npmjs.org/@textlint/resolver/-/resolver-15.5.4.tgz", + "integrity": "sha512-5GUagtpQuYcmhlOzBGdmVBvDu5lKgVTjwbxtdfoidN4OIqblIxThJHHjazU+ic+/bCIIzI2JcOjHGSaRmE8Gcg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@textlint/types": { + "version": "15.5.4", + "resolved": "https://registry.npmjs.org/@textlint/types/-/types-15.5.4.tgz", + "integrity": "sha512-mY28j2U7nrWmZbxyKnRvB8vJxJab4AxqOobLfb6iozrLelJbqxcOTvBQednadWPfAk9XWaZVMqUr9Nird3mutg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@textlint/ast-node-types": "15.5.4" + } + }, "node_modules/@types/node": { "version": "20.19.39", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.39.tgz", @@ -23,16 +554,3223 @@ "dev": true, "license": "MIT", "dependencies": { - "undici-types": "~6.21.0" + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/sarif": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@types/sarif/-/sarif-2.1.7.tgz", + "integrity": "sha512-kRz0VEkJqWLf1LLVN4pT1cg1Z9wAuvI6L97V3m2f5B76Tg8d413ddvLBPTEHAZJlnn4XSvu0FkZtViCQGVyrXQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/vscode": { + "version": "1.115.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.115.0.tgz", + "integrity": "sha512-/M8cdznOlqtMqduHKKlIF00v4eum4ZWKgn8YoPRKcN6PDdvoWeeqDaQSnw63ipDbq1Uzz78Wndk/d0uSPwORfA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typespec/ts-http-runtime": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.5.tgz", + "integrity": "sha512-yURCknZhvywvQItHMMmFSo+fq5arCUIyz/CVk7jD89MSai7dkaX8ufjCWp3NttLojoTVbcE72ri+be/TnEbMHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@vscode/vsce": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-3.9.0.tgz", + "integrity": "sha512-Dfql2kgPHpTKS+G4wTqYBKzK1KqX2gMxTC9dpnYge+aIZL+thh1Z6GXs4zOtNwo7DCPmS7BCfaHUAmNLxKiXkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/identity": "^4.1.0", + "@secretlint/node": "^10.1.2", + "@secretlint/secretlint-formatter-sarif": "^10.1.2", + "@secretlint/secretlint-rule-no-dotenv": "^10.1.2", + "@secretlint/secretlint-rule-preset-recommend": "^10.1.2", + "@vscode/vsce-sign": "^2.0.0", + "azure-devops-node-api": "^12.5.0", + "chalk": "^4.1.2", + "cheerio": "^1.0.0-rc.9", + "cockatiel": "^3.1.2", + "commander": "^12.1.0", + "form-data": "^4.0.0", + "glob": "^11.0.0", + "hosted-git-info": "^4.0.2", + "jsonc-parser": "^3.2.0", + "leven": "^3.1.0", + "markdown-it": "^14.1.0", + "mime": "^1.3.4", + "minimatch": "^3.0.3", + "parse-semver": "^1.1.1", + "read": "^1.0.7", + "secretlint": "^10.1.2", + "semver": "^7.5.2", + "tmp": "^0.2.3", + "typed-rest-client": "^1.8.4", + "url-join": "^4.0.1", + "xml2js": "^0.5.0", + "yauzl": "^3.2.1", + "yazl": "^2.2.2" + }, + "bin": { + "vsce": "vsce" + }, + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "keytar": "^7.7.0" + } + }, + "node_modules/@vscode/vsce-sign": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign/-/vsce-sign-2.0.9.tgz", + "integrity": "sha512-8IvaRvtFyzUnGGl3f5+1Cnor3LqaUWvhaUjAYO8Y39OUYlOf3cRd+dowuQYLpZcP3uwSG+mURwjEBOSq4SOJ0g==", + "dev": true, + "hasInstallScript": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optionalDependencies": { + "@vscode/vsce-sign-alpine-arm64": "2.0.6", + "@vscode/vsce-sign-alpine-x64": "2.0.6", + "@vscode/vsce-sign-darwin-arm64": "2.0.6", + "@vscode/vsce-sign-darwin-x64": "2.0.6", + "@vscode/vsce-sign-linux-arm": "2.0.6", + "@vscode/vsce-sign-linux-arm64": "2.0.6", + "@vscode/vsce-sign-linux-x64": "2.0.6", + "@vscode/vsce-sign-win32-arm64": "2.0.6", + "@vscode/vsce-sign-win32-x64": "2.0.6" + } + }, + "node_modules/@vscode/vsce-sign-alpine-arm64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-alpine-arm64/-/vsce-sign-alpine-arm64-2.0.6.tgz", + "integrity": "sha512-wKkJBsvKF+f0GfsUuGT0tSW0kZL87QggEiqNqK6/8hvqsXvpx8OsTEc3mnE1kejkh5r+qUyQ7PtF8jZYN0mo8Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "alpine" + ] + }, + "node_modules/@vscode/vsce-sign-alpine-x64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-alpine-x64/-/vsce-sign-alpine-x64-2.0.6.tgz", + "integrity": "sha512-YoAGlmdK39vKi9jA18i4ufBbd95OqGJxRvF3n6ZbCyziwy3O+JgOpIUPxv5tjeO6gQfx29qBivQ8ZZTUF2Ba0w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "alpine" + ] + }, + "node_modules/@vscode/vsce-sign-darwin-arm64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-arm64/-/vsce-sign-darwin-arm64-2.0.6.tgz", + "integrity": "sha512-5HMHaJRIQuozm/XQIiJiA0W9uhdblwwl2ZNDSSAeXGO9YhB9MH5C4KIHOmvyjUnKy4UCuiP43VKpIxW1VWP4tQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@vscode/vsce-sign-darwin-x64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-x64/-/vsce-sign-darwin-x64-2.0.6.tgz", + "integrity": "sha512-25GsUbTAiNfHSuRItoQafXOIpxlYj+IXb4/qarrXu7kmbH94jlm5sdWSCKrrREs8+GsXF1b+l3OB7VJy5jsykw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@vscode/vsce-sign-linux-arm": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-arm/-/vsce-sign-linux-arm-2.0.6.tgz", + "integrity": "sha512-UndEc2Xlq4HsuMPnwu7420uqceXjs4yb5W8E2/UkaHBB9OWCwMd3/bRe/1eLe3D8kPpxzcaeTyXiK3RdzS/1CA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/vsce-sign-linux-arm64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-arm64/-/vsce-sign-linux-arm64-2.0.6.tgz", + "integrity": "sha512-cfb1qK7lygtMa4NUl2582nP7aliLYuDEVpAbXJMkDq1qE+olIw/es+C8j1LJwvcRq1I2yWGtSn3EkDp9Dq5FdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/vsce-sign-linux-x64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-x64/-/vsce-sign-linux-x64-2.0.6.tgz", + "integrity": "sha512-/olerl1A4sOqdP+hjvJ1sbQjKN07Y3DVnxO4gnbn/ahtQvFrdhUi0G1VsZXDNjfqmXw57DmPi5ASnj/8PGZhAA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/vsce-sign-win32-arm64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-win32-arm64/-/vsce-sign-win32-arm64-2.0.6.tgz", + "integrity": "sha512-ivM/MiGIY0PJNZBoGtlRBM/xDpwbdlCWomUWuLmIxbi1Cxe/1nooYrEQoaHD8ojVRgzdQEUzMsRbyF5cJJgYOg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@vscode/vsce-sign-win32-x64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-win32-x64/-/vsce-sign-win32-x64-2.0.6.tgz", + "integrity": "sha512-mgth9Kvze+u8CruYMmhHw6Zgy3GRX2S+Ed5oSokDEK5vPEwGGKnmuXua9tmFhomeAnhgJnL4DCna3TiNuGrBTQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", + "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/azure-devops-node-api": { + "version": "12.5.0", + "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-12.5.0.tgz", + "integrity": "sha512-R5eFskGvOm3U/GzeAuxRkUsAl0hrAwGgWn6zAd2KrZmrEhWZVqLew4OOupbQlXUuojUzpGtq62SmdhJ06N88og==", + "dev": true, + "license": "MIT", + "dependencies": { + "tunnel": "0.0.6", + "typed-rest-client": "^1.8.4" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true + }, + "node_modules/binaryextensions": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-6.11.0.tgz", + "integrity": "sha512-sXnYK/Ij80TO3lcqZVV2YgfKN5QjUWIRk/XSm2J/4bd/lPko3lvk0O4ZppH6m+6hB2/GTu+ptNwVFe1xh+QLQw==", + "dev": true, + "license": "Artistic-2.0", + "dependencies": { + "editions": "^6.21.0" + }, + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, + "license": "ISC" + }, + "node_modules/boundary": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/boundary/-/boundary-2.0.0.tgz", + "integrity": "sha512-rJKn5ooC9u8q13IMCrW0RSp31pxBCHE3y9V/tp3TdWSLf8Em3p6Di4NBpfzbJge9YjjFEsD0RtFEjtvHL5VyEA==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/brace-expansion": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", + "integrity": "sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true, + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cheerio": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.2.0.tgz", + "integrity": "sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "encoding-sniffer": "^0.2.1", + "htmlparser2": "^10.1.0", + "parse5": "^7.3.0", + "parse5-htmlparser2-tree-adapter": "^7.1.0", + "parse5-parser-stream": "^7.1.2", + "undici": "^7.19.0", + "whatwg-mimetype": "^4.0.0" + }, + "engines": { + "node": ">=20.18.1" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/cockatiel": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/cockatiel/-/cockatiel-3.2.1.tgz", + "integrity": "sha512-gfrHV6ZPkquExvMh9IOkKsBzNDk6sDuZ6DdBGUBkvFnTCqCxzpuq48RySgP0AnaqQkw2zynOFj9yly6T1Q2G5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/default-browser": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.0.tgz", + "integrity": "sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/editions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/editions/-/editions-6.22.0.tgz", + "integrity": "sha512-UgGlf8IW75je7HZjNDpJdCv4cGJWIi6yumFdZ0R7A8/CIhQiWUjyGLCxdHpd8bmyD1gnkfUNK0oeOXqUS2cpfQ==", + "dev": true, + "license": "Artistic-2.0", + "dependencies": { + "version-range": "^4.15.0" + }, + "engines": { + "ecmascript": ">= es5", + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/encoding-sniffer": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz", + "integrity": "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "^0.6.3", + "whatwg-encoding": "^3.1.1" + }, + "funding": { + "url": "https://github.com/fb55/encoding-sniffer?sponsor=1" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "dev": true, + "license": "(MIT OR WTFPL)", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", + "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastq": { + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", + "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "dev": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/fs-extra": { + "version": "11.3.4", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.4.tgz", + "integrity": "sha512-CTXd6rk/M3/ULNQj8FBqBWHYBVYybQ3VPBw0xGKFe3tuH7ytT6ACnvzpIQ3UZtB8yvUKC2cXn1a+x+5EVQLovA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/glob": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.1.0.tgz", + "integrity": "sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "foreground-child": "^3.3.1", + "jackspeak": "^4.1.1", + "minimatch": "^10.1.1", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", + "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globby": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.1.0.tgz", + "integrity": "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.3", + "path-type": "^6.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/htmlparser2": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz", + "integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "entities": "^7.0.1" + } + }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/index-to-position": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.2.0.tgz", + "integrity": "sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/istextorbinary": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-9.5.0.tgz", + "integrity": "sha512-5mbUj3SiZXCuRf9fT3ibzbSSEWiy63gFfksmGfdOzujPjW3k+z8WvIBxcJHBoQNlaZaiyB25deviif2+osLmLw==", + "dev": true, + "license": "Artistic-2.0", + "dependencies": { + "binaryextensions": "^6.11.0", + "editions": "^6.21.0", + "textextensions": "^6.11.0" + }, + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/jackspeak": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.2.3.tgz", + "integrity": "sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^9.0.0" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", + "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonfile": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", + "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonwebtoken": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", + "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", + "dev": true, + "license": "MIT", + "dependencies": { + "jws": "^4.0.1", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/keytar": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz", + "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-addon-api": "^4.3.0", + "prebuild-install": "^7.0.1" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/linkify-it": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/markdown-it": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz", + "integrity": "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "optional": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true, + "license": "ISC" + }, + "node_modules/napi-build-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", + "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/node-abi": { + "version": "3.89.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.89.0.tgz", + "integrity": "sha512-6u9UwL0HlAl21+agMN3YAMXcKByMqwGx+pq+P76vii5f7hTPtKDp08/H9py6DY+cfDw7kQNTGEj/rly3IgbNQA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/node-sarif-builder": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/node-sarif-builder/-/node-sarif-builder-3.4.0.tgz", + "integrity": "sha512-tGnJW6OKRii9u/b2WiUViTJS+h7Apxx17qsMUjsUeNDiMMX5ZFf8F8Fcz7PAQ6omvOxHZtvDTmOYKJQwmfpjeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/sarif": "^2.1.7", + "fs-extra": "^11.1.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/normalize-package-data": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", + "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/normalize-package-data/node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/normalize-package-data/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/open": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.2.0.tgz", + "integrity": "sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "wsl-utils": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", + "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, + "node_modules/parse-json": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", + "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "index-to-position": "^1.1.0", + "type-fest": "^4.39.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-semver": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", + "integrity": "sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^5.1.0" + } + }, + "node_modules/parse-semver/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz", + "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "domhandler": "^5.0.3", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-parser-stream": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz", + "integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5/node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.3.5.tgz", + "integrity": "sha512-NxVFwLAnrd9i7KUBxC4DrUhmgjzOs+1Qm50D3oF1/oL+r1NpZ4gA7xvG0/zJ8evR7zIKn4vLf7qTNduWFtCrRw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/path-type": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", + "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/prebuild-install": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", + "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", + "deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^2.0.0", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.15.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.1.tgz", + "integrity": "sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "optional": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc-config-loader": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/rc-config-loader/-/rc-config-loader-4.1.4.tgz", + "integrity": "sha512-3GiwEzklkbXTDp52UR5nT8iXgYAx1V9ZG/kDZT7p60u2GCv2XTwQq4NzinMoMpNtXhmt3WkhYXcj6HH8HdwCEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "js-yaml": "^4.1.1", + "json5": "^2.2.3", + "require-from-string": "^2.0.2" + } + }, + "node_modules/read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "mute-stream": "~0.0.4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/read-pkg": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz", + "integrity": "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/normalize-package-data": "^2.4.3", + "normalize-package-data": "^6.0.0", + "parse-json": "^8.0.0", + "type-fest": "^4.6.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg/node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/sax": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/secretlint": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/secretlint/-/secretlint-10.2.2.tgz", + "integrity": "sha512-xVpkeHV/aoWe4vP4TansF622nBEImzCY73y/0042DuJ29iKIaqgoJ8fGxre3rVSHHbxar4FdJobmTnLp9AU0eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/config-creator": "^10.2.2", + "@secretlint/formatter": "^10.2.2", + "@secretlint/node": "^10.2.2", + "@secretlint/profiler": "^10.2.2", + "debug": "^4.4.1", + "globby": "^14.1.0", + "read-pkg": "^9.0.1" + }, + "bin": { + "secretlint": "bin/secretlint.js" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true, + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, - "node_modules/@types/vscode": { - "version": "1.115.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.115.0.tgz", - "integrity": "sha512-/M8cdznOlqtMqduHKKlIF00v4eum4ZWKgn8YoPRKcN6PDdvoWeeqDaQSnw63ipDbq1Uzz78Wndk/d0uSPwORfA==", + "node_modules/spdx-license-ids": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", + "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/structured-source": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/structured-source/-/structured-source-4.0.0.tgz", + "integrity": "sha512-qGzRFNJDjFieQkl/sVOI2dUjHKRyL9dAJi2gCPGJLbJHBIkyOHxjuocpIEfbLioX+qSJpvbYdT49/YCdMznKxA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boundary": "^2.0.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.2.0.tgz", + "integrity": "sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1" + } + }, + "node_modules/table": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", + "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/table/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar-fs": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", + "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/terminal-link": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-4.0.0.tgz", + "integrity": "sha512-lk+vH+MccxNqgVqSnkMVKx4VLJfnLjDBGzH16JVZjKE2DoxP57s6/vt6JmXV5I3jBcfGrxNrYtC+mPtU7WJztA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "supports-hyperlinks": "^3.2.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true, "license": "MIT" }, + "node_modules/textextensions": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-6.11.0.tgz", + "integrity": "sha512-tXJwSr9355kFJI3lbCkPpUH5cP8/M0GGy2xLO34aZCjMXBaK3SoPnZwr/oWmo1FdCnELcs4npdCIOFtq9W3ruQ==", + "dev": true, + "license": "Artistic-2.0", + "dependencies": { + "editions": "^6.21.0" + }, + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/tmp": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", + "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-rest-client": { + "version": "1.8.11", + "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.11.tgz", + "integrity": "sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "qs": "^6.9.1", + "tunnel": "0.0.6", + "underscore": "^1.12.1" + } + }, "node_modules/typescript": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", @@ -47,12 +3785,227 @@ "node": ">=14.17" } }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true, + "license": "MIT" + }, + "node_modules/underscore": { + "version": "1.13.8", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.8.tgz", + "integrity": "sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.25.0.tgz", + "integrity": "sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, "node_modules/undici-types": { "version": "6.21.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "dev": true, "license": "MIT" + }, + "node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", + "dev": true, + "license": "MIT" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/version-range": { + "version": "4.15.0", + "resolved": "https://registry.npmjs.org/version-range/-/version-range-4.15.0.tgz", + "integrity": "sha512-Ck0EJbAGxHwprkzFO966t4/5QkRuzh+/I1RxhLgUKKwEn+Cd8NwM60mE3AqBZg5gYODoXW0EFsQvbZjRlvdqbg==", + "dev": true, + "license": "Artistic-2.0", + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/wsl-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.1.0.tgz", + "integrity": "sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/yauzl": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.3.0.tgz", + "integrity": "sha512-PtGEvEP30p7sbIBJKUBjUnqgTVOyMURc4dLo9iNyAJnNIEz9pm88cCXF21w94Kg3k6RXkeZh5DHOGS0qEONvNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "pend": "~1.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yazl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", + "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3" + } } } } diff --git a/tools/WinGetLogViewer/package.json b/tools/WinGetLogViewer/package.json index 42c38b1c48..34a6dc6e15 100644 --- a/tools/WinGetLogViewer/package.json +++ b/tools/WinGetLogViewer/package.json @@ -4,6 +4,11 @@ "description": "Rich viewer for WinGet diagnostic log files with channel filtering, highlighting, and live follow mode.", "version": "0.1.0", "publisher": "microsoft", + "repository": { + "type": "git", + "url": "https://github.com/microsoft/winget-cli" + }, + "license": "MIT", "engines": { "vscode": "^1.85.0" }, @@ -74,14 +79,16 @@ }, "scripts": { "vscode:prepublish": "npm run compile", - "compile": "tsc -p ./ && cp src/viewer.html media/viewer.html 2>/dev/null || true", + "compile": "tsc -p ./", "watch": "tsc -watch -p ./", "pretest": "npm run compile", - "lint": "eslint src --ext ts" + "lint": "eslint src --ext ts", + "package": "vsce package" }, "devDependencies": { "@types/vscode": "^1.85.0", "@types/node": "20.x", + "@vscode/vsce": "^3.0.0", "typescript": "^5.3.0" } } From 52b3dae5f067bc311176d75b907acf7fed0a52cd Mon Sep 17 00:00:00 2001 From: JohnMcPMS Date: Thu, 16 Apr 2026 11:06:20 -0700 Subject: [PATCH 3/4] spelling and instructions dump from session memory --- .github/actions/spelling/expect.txt | 9 ++ .../winget-log-viewer.instructions.md | 109 ++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 .github/instructions/winget-log-viewer.instructions.md diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 72aba15720..63ebf98779 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -98,6 +98,7 @@ COMGLB commandline compressapi concurrencysal +Consolas constexpr contactsupport contentfiles @@ -236,6 +237,7 @@ hybridcrt Hyperlink IARP IAttachment +ical ICONDIR ICONDIRENTRY ICONIMAGE @@ -340,6 +342,7 @@ minidump MINORVERSION missingdependency mkgmtime +mmm MMmmbbbb MODULEENTRY mof @@ -519,6 +522,7 @@ servercertificate setmetadatabymanifestid SETTINGCHANGE SETTINGMAPPING +sev sfs sfsclient SHCONTF @@ -553,6 +557,7 @@ storeapps storeorigin STRRET stylecop +SUBCHAN subdir subkey Sudarshan @@ -617,8 +622,10 @@ uswgp uwp VALUENAMECASE vclib +vcredist versioned VERSIONINFO +VIWEC vns vsconfig vstest @@ -670,6 +677,7 @@ xcopy Xes XFile XManifest +Xms XMUGIWARAMODULE XName XPLATSTR @@ -677,6 +685,7 @@ XRESOURCEZORO xsi yamato yao +Zabcdefghijklmnopqrstuvwxyz Zanollo ZIPHASH zoro diff --git a/.github/instructions/winget-log-viewer.instructions.md b/.github/instructions/winget-log-viewer.instructions.md new file mode 100644 index 0000000000..8ec1836cb8 --- /dev/null +++ b/.github/instructions/winget-log-viewer.instructions.md @@ -0,0 +1,109 @@ +--- +applyTo: "tools/WinGetLogViewer/**" +--- +# WinGet Log Viewer — Copilot Instructions + +This is a VS Code extension that renders WinGet diagnostic log files in a rich WebView custom editor. + +## Log Format + +``` +YYYY-MM-DD HH:MM:SS.mmm [CHAN ] message +YYYY-MM-DD HH:MM:SS.mmm [CHAN ] [SUBCHAN] message ← subchannel variant +``` + +- `` is optional; values: `V`=Verbose, `I`=Info, `W`=Warning, `E`=Error, `C`=Critical +- Channel is padded to 8 chars with spaces inside the brackets +- Subchannel: when a sub-component routes logs through a parent, its original `[CHAN]` tag appears at the start of `message` and is treated as a subchannel +- Older files without `` are also supported +- Main parse regex (used in both `src/logParser.ts` and `media/viewer.js`): + ``` + /^(\d{2,4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3})\s+(?:<([VIWEC])>\s+)?\[([A-Z]{2,8})\s*\]\s?(.*)$/ + ``` + +## Architecture + +``` +src/ + extension.ts — activate/deactivate; registers provider and openFile command + logParser.ts — parses raw text → LogEntry[]; compiled to out/logParser.js + logViewerProvider.ts — CustomTextEditorProvider; manages WebView lifecycle, follow mode +media/ + viewer.html — WebView HTML template (nonces injected at runtime for CSP) + viewer.css — All styles; --row-height CSS var must match ROW_HEIGHT in viewer.js + viewer.js — All client-side logic (not compiled — served directly) +syntaxes/ + winget-log.tmLanguage.json — TextMate grammar for standard editor syntax highlighting +``` + +## Virtual Scroll Architecture + +- All rows are **uniform height** (`ROW_HEIGHT = 20` px in `viewer.js`, `--row-height: 20px` in `viewer.css`) — these **must stay in sync** +- `displayRows[]` is a flat array built from filtered log entries; continuation lines are promoted to full rows with parent metadata replicated +- `logSpacerTop` and `logSpacerBot` are `
    ` elements whose `.style.height` creates the illusion of the full list +- `overflow-anchor: none` on `#log-container` is **critical** — without it, when `logSpacerTop` first grows from 0, CSS scroll anchoring cascades and jumps the view to the end +- `scheduledRender` must be declared on its **own line** (not embedded in a comment) or it will be silently undefined + +## WebView CSP Rules + +- No inline `style="..."` attributes in HTML — **always use CSS classes or `element.style.property = value`** via CSSOM +- Script/style nonces are replaced at runtime in `logViewerProvider.ts` +- After any edit to `media/viewer.js`, validate syntax: `node --check media/viewer.js` + +## Follow Mode + +- Uses **Node.js `fs.watchFile({ interval: 500, persistent: false })`**, not VS Code's `createFileSystemWatcher` +- Reason: `ReadDirectoryChangesW` (used by VS Code's watcher) misses events when another process holds the file open — WinGet keeps log files open while writing +- `fs.unwatchFile()` is called in `panel.onDidDispose()` to clean up +- Both `resolveCustomEditor` and `openFile` code paths set up the watcher + +## Ready Handshake + +The WebView sends `{ type: 'ready' }` when its JS has loaded. `logViewerProvider.ts` waits for this message before calling `sendLog()`. This prevents `postMessage` being dropped before the listener is registered. + +## Channel Colors + +| Channel | Color (CSS class) | Emoji proxy in README | +|---------|-------------------|-----------------------| +| `FAIL` | red | 🔴 | +| `CLI` | blue | 🔵 | +| `SQL` | purple | 🟣 | +| `REPO` | light-blue/cyan | 🩵 | +| `YAML` | yellow | 🟡 | +| `CORE` | white/light-gray | ⬜ | +| `TEST` | green | 🟢 | +| `CONF` | gray | 🩶 | +| `WORK` | orange | 🟠 | + +## Build & Package + +```bash +# Compile TypeScript (required after any .ts change) +npx tsc + +# Build + package VSIX +npm run package # → winget-log-viewer-.vsix + +# Install locally +code --install-extension winget-log-viewer-0.1.0.vsix +``` + +## .vscodeignore Notes + +- `out/` must **NOT** be in `.vscodeignore` — the compiled JS lives there and is the extension entrypoint +- `src/`, `tsconfig.json`, `out/**/*.map` are excluded (source only, not needed at runtime) + +## Related C++ Files + +The C++ logging infrastructure (in the parent repo) writes the `` level marker: +- `src/AppInstallerCommonCore/FileLogger.cpp` — `ToLogLine()` writes ` ` between timestamp and `[CHAN]` +- `src/AppInstallerSharedLib/AppInstallerLogging.h/.cpp` — `GetLevelChar(Level)` returns V/I/W/E/C +- `src/AppInstallerCLICore/Commands/DebugCommand.h/.cpp` — `LogViewerTestCommand` exercises all viewer features (`winget debug log-viewer [--follow]`) + +## Known Gotchas + +- **Scroll jump at 8–9 wheel clicks**: caused by `overflow-anchor` — fixed with `overflow-anchor: none` on `#log-container` +- **Follow mode not updating**: VS Code's file watcher uses `ReadDirectoryChangesW` and misses events when WinGet holds the file open — use `fs.watchFile()` polling instead +- **`postMessage` dropped on open**: webview JS may not be listening yet — always use the ready-handshake +- **Orphaned JS fragments**: regex replacements can leave stale code that causes silent runtime errors — always validate with `node --check media/viewer.js` +- **CRLF logs**: the parser handles both `\r\n` and `\n` line endings; trailing empty lines are discarded From 726118980b45a18b13ea2bd38e7dccc4e577d85d Mon Sep 17 00:00:00 2001 From: JohnMcPMS Date: Thu, 16 Apr 2026 11:10:35 -0700 Subject: [PATCH 4/4] instructions spelling --- .github/actions/spelling/expect.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 63ebf98779..d25fd51356 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -205,6 +205,7 @@ GHS github gitlab gity +Gotchas goku GRPICONDIR GRPICONDIRENTRY @@ -627,6 +628,7 @@ versioned VERSIONINFO VIWEC vns +vscodeignore vsconfig vstest waitable