Compare commits

..
Author SHA1 Message Date
陈大猫 bb81b72ff0 fix(ai): avoid empty CodeBuddy tools whitelist that hides MCP tools (#4214)
Omit tools in MCP mode and explicitly disallow CodeBuddy built-ins, preserving injected MCP visibility and the skills-mode Bash whitelist.

Fixes #4214
2026-11-12 14:13:14 +08:00
陈大猫 ad05867026 fix(linux): use Secret Service keyring on non-GNOME/KDE desktops (#4190)
Chromium only enables gnome-libsecret or kwallet when it recognizes a
GNOME/KDE desktop name, so niri/sway/Hyprland fall through to BASIC_TEXT
even when org.freedesktop.secrets is available. Set --password-store
before app ready when Secret Service is present, without overriding an
explicit switch or KDE's kwallet default.
2026-11-09 09:29:59 +08:00
github-actions[bot]andgithub-actions[bot] e72d6fc7c6 chore: update star history charts [skip ci] (#4193)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2026-11-09 00:07:23 +00:00
陈大猫 907f60616b fix(nix): work around bwrap ssh config owner check for home-manager (#4192)
* fix(nix): work around bwrap ssh config owner check for home-manager

Unprivileged wrapType2/bwrap maps only the caller uid, so a home-manager
~/.ssh/config symlink into the nix store appears as overflowuid 65534.
OpenSSH then rejects the default user config and the Mosh handshake
never sees MOSH CONNECT. Inject an ssh wrapper via extraPkgs that
snapshots a badly owned config and execs nixpkgs OpenSSH with -F.

* fix(nix): always refresh ssh config snapshot for home-manager

Nix store files have normalized old mtimes, so a -nt check never
notices a newer home-manager generation after the first snapshot.

* fix(nix): publish ssh config snapshot atomically

cp truncates the destination before copying, so a concurrent ssh -F
reader can see an empty or partial config and ignore HostName,
identity, or proxy settings. Copy to a unique staging file and
rename it over the snapshot.
2026-11-09 01:46:36 +08:00
陈大猫 d536b22dee fix(host-details): show inherited group proxy and jump hosts (#4188)
* fix(host-details): show inherited group proxy and jump hosts

Host editor summaries for HTTP/SOCKS5/command proxy and ProxyJump
chains now display the same values applyGroupDefaults uses at
connect time, without writing inherited settings onto the host
until the user edits them.

Fixes #4187

* fix(host-details): keep custom proxy and empty jump-host overrides

Selecting Custom while a group saved proxy is inherited now keeps a host-owned draft instead of snapping back to that profile. Removing the last hop of a multi-hop inherited chain keeps an empty override so applyGroupDefaults cannot restore the group hops.

* fix(host-details): keep empty override when clearing inherited chain

Clear Chain on an inherited-only jump-host list now stores { hostIds: [] }
instead of deleting the field so group hops cannot snap back.
2026-11-08 21:30:36 +08:00
8 changed files with 440 additions and 53 deletions

No files matched your search

+24 -22
View File
@@ -15,33 +15,35 @@
<text x="50%" y="30" fill="#e6edf3" font-size="20" font-family="Handlee, cursive" font-weight="bold" text-anchor="middle">Star History</text>
<rect width="178" height="32" x="105" y="90" fill="#161b22" fill-opacity="0.9" stroke="#30363d" stroke-width="1.5" rx="4" ry="4" filter="url(#xkcdify)"/><rect width="8" height="8" x="115" y="102" rx="2" ry="2" fill="#dd4528" filter="url(#xkcdify)"/><text x="131" y="110" fill="#e6edf3" font-size="15" font-family="Handlee, cursive" font-weight="bold">binaricat/Netcatty</text>
<text x="85" y="468.0" fill="#e6edf3" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">0</text>
<line x1="90" y1="408.3" x2="765" y2="408.3" stroke="#21262d" stroke-width="1" filter="url(#xkcdify)"/>
<text x="85" y="413.2857142857143" fill="#e6edf3" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">1K</text>
<line x1="90" y1="353.6" x2="765" y2="353.6" stroke="#21262d" stroke-width="1" filter="url(#xkcdify)"/>
<text x="85" y="358.57142857142856" fill="#e6edf3" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">2K</text>
<line x1="90" y1="298.9" x2="765" y2="298.9" stroke="#21262d" stroke-width="1" filter="url(#xkcdify)"/>
<text x="85" y="303.8571428571429" fill="#e6edf3" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">3K</text>
<line x1="90" y1="244.1" x2="765" y2="244.1" stroke="#21262d" stroke-width="1" filter="url(#xkcdify)"/>
<text x="85" y="249.14285714285717" fill="#e6edf3" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">4K</text>
<line x1="90" y1="189.4" x2="765" y2="189.4" stroke="#21262d" stroke-width="1" filter="url(#xkcdify)"/>
<text x="85" y="194.42857142857144" fill="#e6edf3" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">5K</text>
<line x1="90" y1="134.7" x2="765" y2="134.7" stroke="#21262d" stroke-width="1" filter="url(#xkcdify)"/>
<text x="85" y="139.71428571428572" fill="#e6edf3" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">6K</text>
<line x1="90" y1="415.1" x2="765" y2="415.1" stroke="#21262d" stroke-width="1" filter="url(#xkcdify)"/>
<text x="85" y="420.125" fill="#e6edf3" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">1K</text>
<line x1="90" y1="367.2" x2="765" y2="367.2" stroke="#21262d" stroke-width="1" filter="url(#xkcdify)"/>
<text x="85" y="372.25" fill="#e6edf3" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">2K</text>
<line x1="90" y1="319.4" x2="765" y2="319.4" stroke="#21262d" stroke-width="1" filter="url(#xkcdify)"/>
<text x="85" y="324.375" fill="#e6edf3" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">3K</text>
<line x1="90" y1="271.5" x2="765" y2="271.5" stroke="#21262d" stroke-width="1" filter="url(#xkcdify)"/>
<text x="85" y="276.5" fill="#e6edf3" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">4K</text>
<line x1="90" y1="223.6" x2="765" y2="223.6" stroke="#21262d" stroke-width="1" filter="url(#xkcdify)"/>
<text x="85" y="228.625" fill="#e6edf3" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">5K</text>
<line x1="90" y1="175.8" x2="765" y2="175.8" stroke="#21262d" stroke-width="1" filter="url(#xkcdify)"/>
<text x="85" y="180.75" fill="#e6edf3" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">6K</text>
<line x1="90" y1="127.9" x2="765" y2="127.9" stroke="#21262d" stroke-width="1" filter="url(#xkcdify)"/>
<text x="85" y="132.875" fill="#e6edf3" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">7K</text>
<line x1="90" y1="80.0" x2="765" y2="80.0" stroke="#21262d" stroke-width="1" filter="url(#xkcdify)"/>
<text x="85" y="85.0" fill="#e6edf3" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">7K</text>
<text x="85" y="85.0" fill="#e6edf3" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">8K</text>
<text x="43" y="271.5" fill="#e6edf3" font-size="17" font-family="Handlee, cursive" font-weight="bold" transform="rotate(-90, 43, 271.5)">GitHub Stars</text>
<text x="90.0" y="488" fill="#e6edf3" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="middle">Jan 2026</text>
<text x="217.4" y="488" fill="#e6edf3" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="middle">Mar 2026</text>
<text x="353.7" y="488" fill="#e6edf3" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="middle">May 2026</text>
<text x="490.1" y="488" fill="#e6edf3" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="middle">Jul 2026</text>
<text x="628.7" y="488" fill="#e6edf3" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="middle">Sep 2026</text>
<text x="765.0" y="488" fill="#e6edf3" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="middle">Nov 2026</text>
<text x="214.5" y="488" fill="#e6edf3" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="middle">Mar 2026</text>
<text x="347.8" y="488" fill="#e6edf3" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="middle">May 2026</text>
<text x="481.0" y="488" fill="#e6edf3" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="middle">Jul 2026</text>
<text x="616.5" y="488" fill="#e6edf3" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="middle">Sep 2026</text>
<text x="749.7" y="488" fill="#e6edf3" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="middle">Nov 2026</text>
<text x="50%" y="525" fill="#e6edf3" font-size="17" font-family="Handlee, cursive" font-weight="bold" text-anchor="middle">Date</text>
<line x1="90" y1="80" x2="90" y2="463" stroke="#30363d" stroke-width="2.5" filter="url(#xkcdify)"/>
<line x1="90" y1="463" x2="765" y2="463" stroke="#30363d" stroke-width="2.5" filter="url(#xkcdify)"/>
<path d="M 90.0,462.2 C 90.4,462.2 91.9,461.9 92.2,461.8 C 93.0,461.6 93.7,461.5 94.5,461.3 C 95.2,461.1 96.0,460.9 96.7,460.8 C 97.5,460.7 98.2,460.8 98.9,460.8 C 99.7,460.7 100.4,460.7 101.2,460.6 C 101.9,460.6 102.7,460.5 103.4,460.5 C 104.2,460.4 104.5,460.4 105.6,460.3 C 106.8,460.3 109.0,460.2 110.1,460.2 C 111.2,460.1 111.6,460.1 112.4,460.0 C 113.1,460.0 113.8,460.0 114.6,460.0 C 115.3,460.0 116.1,460.0 116.8,459.9 C 117.6,459.9 118.3,459.9 119.1,459.9 C 119.8,459.8 120.5,459.8 121.3,459.7 C 122.0,459.7 122.8,459.7 123.5,459.5 C 124.3,459.3 125.0,459.1 125.8,458.7 C 126.5,458.4 127.3,457.6 128.0,457.4 C 128.7,457.1 129.5,457.2 130.2,457.2 C 131.0,457.2 131.7,457.1 132.5,457.1 C 133.2,457.1 133.6,457.0 134.7,457.0 C 135.8,457.0 137.7,457.0 139.2,456.9 C 140.7,456.9 142.5,456.9 143.6,456.8 C 144.8,456.8 145.1,456.7 145.9,456.7 C 146.6,456.7 147.4,456.6 148.1,456.6 C 148.9,456.6 149.6,456.5 150.3,456.5 C 151.1,456.5 151.8,456.5 152.6,456.4 C 153.3,456.4 153.7,456.4 154.8,456.4 C 155.9,456.4 157.4,456.3 159.3,456.3 C 161.2,456.2 164.1,456.2 166.0,456.2 C 167.9,456.2 168.2,456.2 170.5,456.2 C 172.7,456.1 177.5,456.0 179.4,455.9 C 181.3,455.9 180.5,455.9 181.6,455.9 C 182.8,455.9 184.2,455.9 186.1,455.8 C 188.0,455.8 189.1,455.8 192.8,455.7 C 196.5,455.7 205.5,455.6 208.5,455.6 C 211.4,455.5 210.0,455.5 210.7,455.5 C 211.4,455.5 211.8,456.1 212.9,455.4 C 214.0,454.8 216.3,454.2 217.4,451.4 C 218.5,448.6 218.9,440.8 219.6,438.4 C 220.4,436.0 221.1,437.4 221.9,437.0 C 222.6,436.6 223.4,436.4 224.1,436.1 C 224.9,435.9 225.6,435.7 226.3,435.5 C 227.1,435.4 227.8,435.4 228.6,435.3 C 229.3,435.2 230.1,435.0 230.8,434.9 C 231.6,434.9 232.3,434.9 233.0,434.9 C 233.8,434.8 234.5,434.6 235.3,434.5 C 236.0,434.4 236.8,434.5 237.5,434.3 C 238.3,434.2 239.0,433.9 239.8,433.7 C 240.5,433.6 241.2,433.7 242.0,433.6 C 242.7,433.5 243.1,433.3 244.2,433.2 C 245.3,433.1 247.6,433.1 248.7,433.0 C 249.8,433.0 250.2,432.9 250.9,432.9 C 251.7,432.8 252.4,432.8 253.2,432.7 C 253.9,432.6 254.7,432.3 255.4,432.2 C 256.1,432.0 256.9,432.7 257.6,431.8 C 258.4,430.9 259.1,427.7 259.9,426.7 C 260.6,425.6 261.4,425.8 262.1,425.6 C 262.8,425.4 263.6,425.7 264.3,425.5 C 265.1,425.4 265.8,425.0 266.6,424.8 C 267.3,424.5 268.1,424.3 268.8,423.8 C 269.6,423.3 270.3,422.3 271.0,421.7 C 271.8,421.1 272.5,420.6 273.3,420.2 C 274.0,419.7 274.8,419.4 275.5,419.1 C 276.3,418.9 277.0,418.7 277.7,418.6 C 278.5,418.5 279.2,418.5 280.0,418.4 C 280.7,418.3 281.5,418.1 282.2,418.0 C 283.0,417.9 283.7,417.9 284.5,417.9 C 285.2,417.8 285.9,417.8 286.7,417.6 C 287.4,417.5 288.2,417.6 288.9,417.1 C 289.7,416.7 290.4,415.7 291.2,415.2 C 291.9,414.7 292.6,414.5 293.4,414.1 C 294.1,413.8 294.9,414.5 295.6,412.9 C 296.4,411.4 297.1,406.6 297.9,404.7 C 298.6,402.9 299.4,402.6 300.1,401.8 C 300.8,401.0 301.6,400.5 302.3,400.0 C 303.1,399.4 303.8,398.9 304.6,398.5 C 305.3,398.1 306.1,397.7 306.8,397.5 C 307.5,397.2 308.3,397.1 309.0,396.9 C 309.8,396.7 310.5,396.4 311.3,396.1 C 312.0,395.8 312.8,395.4 313.5,395.1 C 314.3,394.8 315.0,394.9 315.7,394.6 C 316.5,394.4 317.2,393.9 318.0,393.6 C 318.7,393.3 319.5,393.0 320.2,392.7 C 321.0,392.5 321.7,392.3 322.5,392.1 C 323.2,392.0 323.9,392.0 324.7,391.8 C 325.4,391.7 326.2,391.5 326.9,391.3 C 327.7,391.2 328.4,391.0 329.2,390.8 C 329.9,390.6 330.6,390.4 331.4,390.1 C 332.1,389.7 332.9,389.2 333.6,388.9 C 334.4,388.6 335.1,388.5 335.9,388.3 C 336.6,388.2 337.4,388.1 338.1,387.9 C 338.8,387.8 339.6,387.7 340.3,387.6 C 341.1,387.5 341.8,387.4 342.6,387.3 C 343.3,387.2 344.1,387.2 344.8,387.1 C 345.5,387.0 346.3,386.8 347.0,386.5 C 347.8,386.2 348.5,385.8 349.3,385.4 C 350.0,385.1 350.8,384.7 351.5,384.5 C 352.3,384.3 353.0,384.2 353.7,384.1 C 354.5,384.0 355.2,383.9 356.0,383.7 C 356.7,383.4 357.5,382.9 358.2,382.7 C 359.0,382.5 359.7,382.5 360.4,382.4 C 361.2,382.3 361.9,382.0 362.7,381.9 C 363.4,381.7 364.2,381.5 364.9,381.3 C 365.7,381.1 366.4,380.9 367.2,380.7 C 367.9,380.5 368.6,380.4 369.4,380.2 C 370.1,380.0 370.9,379.6 371.6,379.4 C 372.4,379.2 373.1,379.0 373.9,378.8 C 374.6,378.6 375.3,378.2 376.1,378.0 C 376.8,377.7 377.6,377.4 378.3,377.2 C 379.1,376.9 379.8,376.8 380.6,376.4 C 381.3,376.0 382.1,375.1 382.8,374.7 C 383.5,374.4 384.3,374.3 385.0,374.2 C 385.8,374.1 386.5,374.1 387.3,374.0 C 388.0,373.9 388.8,373.7 389.5,373.6 C 390.2,373.5 391.0,373.7 391.7,373.3 C 392.5,373.0 393.2,371.9 394.0,371.5 C 394.7,371.1 395.5,371.1 396.2,370.9 C 397.0,370.6 397.7,370.1 398.4,369.9 C 399.2,369.7 399.9,369.9 400.7,369.7 C 401.4,369.5 402.2,368.9 402.9,368.7 C 403.7,368.5 404.4,368.6 405.1,368.5 C 405.9,368.4 406.6,368.3 407.4,368.1 C 408.1,367.9 408.9,367.7 409.6,367.1 C 410.4,366.6 411.1,365.6 411.9,365.1 C 412.6,364.5 413.3,364.3 414.1,363.9 C 414.8,363.5 415.6,363.4 416.3,362.7 C 417.1,362.0 417.8,360.3 418.6,359.5 C 419.3,358.7 420.0,358.3 420.8,357.8 C 421.5,357.4 422.3,357.3 423.0,356.6 C 423.8,355.9 424.5,354.2 425.3,353.5 C 426.0,352.8 426.8,352.7 427.5,352.3 C 428.2,351.9 429.0,351.6 429.7,351.1 C 430.5,35Line truncated
<path d="M 90.0,462.2 C 90.4,462.2 91.9,461.9 92.2,461.8 C 93.0,461.6 93.7,461.5 94.5,461.3 C 95.2,461.1 96.0,460.9 96.7,460.8 C 97.5,460.7 98.2,460.8 98.9,460.8 C 99.7,460.7 100.4,460.7 101.2,460.6 C 101.9,460.6 102.7,460.5 103.4,460.5 C 104.2,460.4 104.5,460.4 105.6,460.3 C 106.8,460.3 109.0,460.2 110.1,460.2 C 111.2,460.1 111.6,460.1 112.4,460.0 C 113.1,460.0 113.8,460.0 114.6,460.0 C 115.3,460.0 116.1,460.0 116.8,459.9 C 117.6,459.9 118.3,459.9 119.1,459.9 C 119.8,459.8 120.5,459.8 121.3,459.7 C 122.0,459.7 122.8,459.7 123.5,459.5 C 124.3,459.3 125.0,459.1 125.8,458.7 C 126.5,458.4 127.3,457.6 128.0,457.4 C 128.7,457.1 129.5,457.2 130.2,457.2 C 131.0,457.2 131.7,457.1 132.5,457.1 C 133.2,457.1 133.6,457.0 134.7,457.0 C 135.8,457.0 137.7,457.0 139.2,456.9 C 140.7,456.9 142.5,456.9 143.6,456.8 C 144.8,456.8 145.1,456.7 145.9,456.7 C 146.6,456.7 147.4,456.6 148.1,456.6 C 148.9,456.6 149.6,456.5 150.3,456.5 C 151.1,456.5 151.8,456.5 152.6,456.4 C 153.3,456.4 153.7,456.4 154.8,456.4 C 155.9,456.4 157.4,456.3 159.3,456.3 C 161.2,456.2 164.1,456.2 166.0,456.2 C 167.9,456.2 168.2,456.2 170.5,456.2 C 172.7,456.1 177.5,456.0 179.4,455.9 C 181.3,455.9 180.5,455.9 181.6,455.9 C 182.8,455.9 184.2,455.9 186.1,455.8 C 188.0,455.8 189.1,455.8 192.8,455.7 C 196.5,455.7 205.5,455.6 208.5,455.6 C 211.4,455.5 210.0,455.5 210.7,455.5 C 211.4,455.5 211.8,456.1 212.9,455.4 C 214.0,454.8 216.3,454.2 217.4,451.4 C 218.5,448.6 218.9,440.8 219.6,438.4 C 220.4,436.0 221.1,437.4 221.9,437.0 C 222.6,436.6 223.4,436.4 224.1,436.1 C 224.9,435.9 225.6,435.7 226.3,435.5 C 227.1,435.4 227.8,435.4 228.6,435.3 C 229.3,435.2 230.1,435.0 230.8,434.9 C 231.6,434.9 232.3,434.9 233.0,434.9 C 233.8,434.8 234.5,434.6 235.3,434.5 C 236.0,434.4 236.8,434.5 237.5,434.3 C 238.3,434.2 239.0,433.9 239.8,433.7 C 240.5,433.6 241.2,433.7 242.0,433.6 C 242.7,433.5 243.1,433.3 244.2,433.2 C 245.3,433.1 247.6,433.1 248.7,433.0 C 249.8,433.0 250.2,432.9 250.9,432.9 C 251.7,432.8 252.4,432.8 253.2,432.7 C 253.9,432.6 254.7,432.3 255.4,432.2 C 256.1,432.0 256.9,432.7 257.6,431.8 C 258.4,430.9 259.1,427.7 259.9,426.7 C 260.6,425.6 261.4,425.8 262.1,425.6 C 262.8,425.4 263.6,425.7 264.3,425.5 C 265.1,425.4 265.8,425.0 266.6,424.8 C 267.3,424.5 268.1,424.3 268.8,423.8 C 269.6,423.3 270.3,422.3 271.0,421.7 C 271.8,421.1 272.5,420.6 273.3,420.2 C 274.0,419.7 274.8,419.4 275.5,419.1 C 276.3,418.9 277.0,418.7 277.7,418.6 C 278.5,418.5 279.2,418.5 280.0,418.4 C 280.7,418.3 281.5,418.1 282.2,418.0 C 283.0,417.9 283.7,417.9 284.5,417.9 C 285.2,417.8 285.9,417.8 286.7,417.6 C 287.4,417.5 288.2,417.6 288.9,417.1 C 289.7,416.7 290.4,415.7 291.2,415.2 C 291.9,414.7 292.6,414.5 293.4,414.1 C 294.1,413.8 294.9,414.5 295.6,412.9 C 296.4,411.4 297.1,406.6 297.9,404.7 C 298.6,402.9 299.4,402.6 300.1,401.8 C 300.8,401.0 301.6,400.5 302.3,400.0 C 303.1,399.4 303.8,398.9 304.6,398.5 C 305.3,398.1 306.1,397.7 306.8,397.5 C 307.5,397.2 308.3,397.1 309.0,396.9 C 309.8,396.7 310.5,396.4 311.3,396.1 C 312.0,395.8 312.8,395.4 313.5,395.1 C 314.3,394.8 315.0,394.9 315.7,394.6 C 316.5,394.4 317.2,393.9 318.0,393.6 C 318.7,393.3 319.5,393.0 320.2,392.7 C 321.0,392.5 321.7,392.3 322.5,392.1 C 323.2,392.0 323.9,392.0 324.7,391.8 C 325.4,391.7 326.2,391.5 326.9,391.3 C 327.7,391.2 328.4,391.0 329.2,390.8 C 329.9,390.6 330.6,390.4 331.4,390.1 C 332.1,389.7 332.9,389.2 333.6,388.9 C 334.4,388.6 335.1,388.5 335.9,388.3 C 336.6,388.2 337.4,388.1 338.1,387.9 C 338.8,387.8 339.6,387.7 340.3,387.6 C 341.1,387.5 341.8,387.4 342.6,387.3 C 343.3,387.2 344.1,387.2 344.8,387.1 C 345.5,387.0 346.3,386.8 347.0,386.5 C 347.8,386.2 348.5,385.8 349.3,385.4 C 350.0,385.1 350.8,384.7 351.5,384.5 C 352.3,384.3 353.0,384.2 353.7,384.1 C 354.5,384.0 355.2,383.9 356.0,383.7 C 356.7,383.4 357.5,382.9 358.2,382.7 C 359.0,382.5 359.7,382.5 360.4,382.4 C 361.2,382.3 361.9,382.0 362.7,381.9 C 363.4,381.7 364.2,381.5 364.9,381.3 C 365.7,381.1 366.4,380.9 367.2,380.7 C 367.9,380.5 368.6,380.4 369.4,380.2 C 370.1,380.0 370.9,379.6 371.6,379.4 C 372.4,379.2 373.1,379.0 373.9,378.8 C 374.6,378.6 375.3,378.2 376.1,378.0 C 376.8,377.7 377.6,377.4 378.3,377.2 C 379.1,376.9 379.8,376.8 380.6,376.4 C 381.3,376.0 382.1,375.1 382.8,374.7 C 383.5,374.4 384.3,374.3 385.0,374.2 C 385.8,374.1 386.5,374.1 387.3,374.0 C 388.0,373.9 388.8,373.7 389.5,373.6 C 390.2,373.5 391.0,373.7 391.7,373.3 C 392.5,373.0 393.2,371.9 394.0,371.5 C 394.7,371.1 395.5,371.1 396.2,370.9 C 397.0,370.6 397.7,370.1 398.4,369.9 C 399.2,369.7 399.9,369.9 400.7,369.7 C 401.4,369.5 402.2,368.9 402.9,368.7 C 403.7,368.5 404.4,368.6 405.1,368.5 C 405.9,368.4 406.6,368.3 407.4,368.1 C 408.1,367.9 408.9,367.7 409.6,367.1 C 410.4,366.6 411.1,365.6 411.9,365.1 C 412.6,364.5 413.3,364.3 414.1,363.9 C 414.8,363.5 415.6,363.4 416.3,362.7 C 417.1,362.0 417.8,360.3 418.6,359.5 C 419.3,358.7 420.0,358.3 420.8,357.8 C 421.5,357.4 422.3,357.3 423.0,356.6 C 423.8,355.9 424.5,354.2 425.3,353.5 C 426.0,352.8 426.8,352.7 427.5,352.3 C 428.2,351.9 429.0,351.6 429.7,351.1 C 430.5,35Line truncated
<circle cx="765.0" cy="80.1" r="5" fill="#dd4528" stroke="#0d1117" stroke-width="2" filter="url(#xkcdify)"/>
<text x="753.0" y="77.0" fill="#dd4528" font-size="18" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">6999</text>
<path d="M 90.0,462.3 C 90.4,462.3 91.8,462.0 92.2,461.9 C 92.9,461.8 93.6,461.7 94.4,461.5 C 95.1,461.4 95.8,461.2 96.6,461.1 C 97.3,461.0 98.0,461.1 98.7,461.0 C 99.5,461.0 100.2,461.0 100.9,460.9 C 101.7,460.9 102.4,460.8 103.1,460.8 C 103.8,460.7 104.2,460.7 105.3,460.7 C 106.4,460.6 108.6,460.6 109.7,460.5 C 110.8,460.5 111.1,460.4 111.8,460.4 C 112.6,460.4 113.3,460.4 114.0,460.4 C 114.8,460.4 115.5,460.3 116.2,460.3 C 116.9,460.3 117.7,460.3 118.4,460.3 C 119.1,460.2 119.9,460.2 120.6,460.1 C 121.3,460.1 122.0,460.1 122.8,459.9 C 123.5,459.8 124.2,459.6 125.0,459.3 C 125.7,459.0 126.4,458.3 127.1,458.1 C 127.9,457.8 128.6,458.0 129.3,457.9 C 130.0,457.9 130.8,457.9 131.5,457.8 C 132.2,457.8 132.6,457.8 133.7,457.7 C 134.8,457.7 136.6,457.7 138.1,457.7 C 139.5,457.7 141.3,457.6 142.4,457.6 C 143.5,457.6 143.9,457.5 144.6,457.5 C 145.3,457.5 146.1,457.4 146.8,457.4 C 147.5,457.4 148.3,457.3 149.0,457.3 C 149.7,457.3 150.4,457.3 151.2,457.3 C 151.9,457.2 152.3,457.2 153.3,457.2 C 154.4,457.2 155.9,457.1 157.7,457.1 C 159.5,457.1 162.5,457.1 164.3,457.1 C 166.1,457.0 166.5,457.1 168.6,457.0 C 170.8,457.0 175.6,456.9 177.4,456.8 C 179.2,456.8 178.5,456.8 179.6,456.8 C 180.7,456.8 182.1,456.8 183.9,456.7 C 185.8,456.7 186.8,456.7 190.5,456.6 C 194.1,456.6 202.9,456.5 205.8,456.5 C 208.7,456.5 207.2,456.5 208.0,456.4 C 208.7,456.4 209.1,457.0 210.1,456.4 C 211.2,455.8 213.4,455.3 214.5,452.9 C 215.6,450.4 216.0,443.6 216.7,441.5 C 217.4,439.4 218.2,440.6 218.9,440.3 C 219.6,439.9 220.3,439.7 221.1,439.5 C 221.8,439.3 222.5,439.1 223.3,439.0 C 224.0,438.8 224.7,438.8 225.4,438.7 C 226.2,438.6 226.9,438.5 227.6,438.4 C 228.3,438.4 229.1,438.5 229.8,438.4 C 230.5,438.3 231.3,438.1 232.0,438.1 C 232.7,438.0 233.4,438.0 234.2,437.9 C 234.9,437.8 235.6,437.5 236.4,437.4 C 237.1,437.3 237.8,437.3 238.5,437.2 C 239.3,437.2 239.6,437.0 240.7,436.9 C 241.8,436.8 244.0,436.8 245.1,436.8 C 246.2,436.7 246.6,436.7 247.3,436.6 C 248.0,436.6 248.7,436.6 249.5,436.5 C 250.2,436.4 250.9,436.2 251.7,436.0 C 252.4,435.9 253.1,436.5 253.8,435.7 C 254.6,434.9 255.3,432.1 256.0,431.2 C 256.7,430.3 257.5,430.4 258.2,430.3 C 258.9,430.1 259.7,430.3 260.4,430.2 C 261.1,430.1 261.8,429.8 262.6,429.5 C 263.3,429.3 264.0,429.1 264.8,428.7 C 265.5,428.2 266.2,427.4 266.9,426.9 C 267.7,426.4 268.4,425.9 269.1,425.5 C 269.9,425.1 270.6,424.8 271.3,424.6 C 272.0,424.4 272.8,424.3 273.5,424.2 C 274.2,424.1 275.0,424.1 275.7,424.0 C 276.4,423.9 277.1,423.7 277.9,423.6 C 278.6,423.5 279.3,423.6 280.0,423.5 C 280.8,423.5 281.5,423.4 282.2,423.3 C 283.0,423.2 283.7,423.2 284.4,422.9 C 285.1,422.5 285.9,421.6 286.6,421.2 C 287.3,420.7 288.1,420.6 288.8,420.2 C 289.5,419.9 290.2,420.6 291.0,419.2 C 291.7,417.8 292.4,413.6 293.2,412.0 C 293.9,410.4 294.6,410.1 295.3,409.4 C 296.1,408.7 296.8,408.3 297.5,407.8 C 298.3,407.4 299.0,406.9 299.7,406.6 C 300.4,406.2 301.2,405.9 301.9,405.6 C 302.6,405.4 303.3,405.4 304.1,405.2 C 304.8,405.0 305.5,404.8 306.3,404.5 C 307.0,404.2 307.7,403.8 308.4,403.6 C 309.2,403.4 309.9,403.4 310.6,403.2 C 311.4,402.9 312.1,402.5 312.8,402.2 C 313.5,402.0 314.3,401.7 315.0,401.5 C 315.7,401.3 316.5,401.1 317.2,401.0 C 317.9,400.9 318.6,400.8 319.4,400.7 C 320.1,400.6 320.8,400.4 321.6,400.3 C 322.3,400.1 323.0,400.0 323.7,399.8 C 324.5,399.6 325.2,399.5 325.9,399.2 C 326.7,398.9 327.4,398.4 328.1,398.1 C 328.8,397.9 329.6,397.8 330.3,397.7 C 331.0,397.5 331.7,397.4 332.5,397.3 C 333.2,397.2 333.9,397.1 334.7,397.0 C 335.4,396.9 336.1,396.8 336.8,396.7 C 337.6,396.7 338.3,396.7 339.0,396.6 C 339.8,396.5 340.5,396.3 341.2,396.1 C 341.9,395.8 342.7,395.4 343.4,395.1 C 344.1,394.8 344.9,394.5 345.6,394.3 C 346.3,394.1 347.0,394.1 347.8,394.0 C 348.5,393.8 349.2,393.8 350.0,393.6 C 350.7,393.4 351.4,392.9 352.1,392.7 C 352.9,392.5 353.6,392.6 354.3,392.5 C 355.0,392.4 355.8,392.2 356.5,392.0 C 357.2,391.8 358.0,391.7 358.7,391.5 C 359.4,391.4 360.1,391.2 360.9,391.0 C 361.6,390.8 362.3,390.8 363.1,390.6 C 363.8,390.4 364.5,390.1 365.2,389.8 C 366.0,389.6 366.7,389.5 367.4,389.3 C 368.2,389.1 368.9,388.8 369.6,388.6 C 370.3,388.4 371.1,388.1 371.8,387.9 C 372.5,387.7 373.3,387.6 374.0,387.3 C 374.7,386.9 375.4,386.1 376.2,385.8 C 376.9,385.5 377.6,385.4 378.3,385.3 C 379.1,385.2 379.8,385.2 380.5,385.1 C 381.3,385.0 382.0,384.9 382.7,384.8 C 383.4,384.7 384.2,384.8 384.9,384.5 C 385.6,384.2 386.4,383.3 387.1,382.9 C 387.8,382.5 388.5,382.6 389.3,382.4 C 390.0,382.2 390.7,381.7 391.5,381.6 C 392.2,381.4 392.9,381.5 393.6,381.3 C 394.4,381.1 395.1,380.7 395.8,380.5 C 396.6,380.3 397.3,380.4 398.0,380.3 C 398.7,380.2 399.5,380.2 400.2,380.0 C 400.9,379.8 401.7,379.6 402.4,379.1 C 403.1,378.7 403.8,377.8 404.6,377.3 C 405.3,376.8 406.0,376.6 406.7,376.3 C 407.5,376.0 408.2,375.9 408.9,375.2 C 409.7,374.6 410.4,373.2 411.1,372.5 C 411.8,371.8 412.6,371.5 413.3,371.0 C 414.0,370.6 414.8,370.6 415.5,369.9 C 416.2,369.3 416.9,367.9 417.7,367.2 C 418.4,366.6 419.1,366.5 419.9,366.2 C 420.6,365.8 421.3,365.6 422.0,365.1 C 422.8,36Line truncated
<path d="M 90.0,462.3 C 90.4,462.3 91.8,462.0 92.2,461.9 C 92.9,461.8 93.6,461.7 94.4,461.5 C 95.1,461.4 95.8,461.2 96.6,461.1 C 97.3,461.0 98.0,461.1 98.7,461.0 C 99.5,461.0 100.2,461.0 100.9,460.9 C 101.7,460.9 102.4,460.8 103.1,460.8 C 103.8,460.7 104.2,460.7 105.3,460.7 C 106.4,460.6 108.6,460.6 109.7,460.5 C 110.8,460.5 111.1,460.4 111.8,460.4 C 112.6,460.4 113.3,460.4 114.0,460.4 C 114.8,460.4 115.5,460.3 116.2,460.3 C 116.9,460.3 117.7,460.3 118.4,460.3 C 119.1,460.2 119.9,460.2 120.6,460.1 C 121.3,460.1 122.0,460.1 122.8,459.9 C 123.5,459.8 124.2,459.6 125.0,459.3 C 125.7,459.0 126.4,458.3 127.1,458.1 C 127.9,457.8 128.6,458.0 129.3,457.9 C 130.0,457.9 130.8,457.9 131.5,457.8 C 132.2,457.8 132.6,457.8 133.7,457.7 C 134.8,457.7 136.6,457.7 138.1,457.7 C 139.5,457.7 141.3,457.6 142.4,457.6 C 143.5,457.6 143.9,457.5 144.6,457.5 C 145.3,457.5 146.1,457.4 146.8,457.4 C 147.5,457.4 148.3,457.3 149.0,457.3 C 149.7,457.3 150.4,457.3 151.2,457.3 C 151.9,457.2 152.3,457.2 153.3,457.2 C 154.4,457.2 155.9,457.1 157.7,457.1 C 159.5,457.1 162.5,457.1 164.3,457.1 C 166.1,457.0 166.5,457.1 168.6,457.0 C 170.8,457.0 175.6,456.9 177.4,456.8 C 179.2,456.8 178.5,456.8 179.6,456.8 C 180.7,456.8 182.1,456.8 183.9,456.7 C 185.8,456.7 186.8,456.7 190.5,456.6 C 194.1,456.6 202.9,456.5 205.8,456.5 C 208.7,456.5 207.2,456.5 208.0,456.4 C 208.7,456.4 209.1,457.0 210.1,456.4 C 211.2,455.8 213.4,455.3 214.5,452.9 C 215.6,450.4 216.0,443.6 216.7,441.5 C 217.4,439.4 218.2,440.6 218.9,440.3 C 219.6,439.9 220.3,439.7 221.1,439.5 C 221.8,439.3 222.5,439.1 223.3,439.0 C 224.0,438.8 224.7,438.8 225.4,438.7 C 226.2,438.6 226.9,438.5 227.6,438.4 C 228.3,438.4 229.1,438.5 229.8,438.4 C 230.5,438.3 231.3,438.1 232.0,438.1 C 232.7,438.0 233.4,438.0 234.2,437.9 C 234.9,437.8 235.6,437.5 236.4,437.4 C 237.1,437.3 237.8,437.3 238.5,437.2 C 239.3,437.2 239.6,437.0 240.7,436.9 C 241.8,436.8 244.0,436.8 245.1,436.8 C 246.2,436.7 246.6,436.7 247.3,436.6 C 248.0,436.6 248.7,436.6 249.5,436.5 C 250.2,436.4 250.9,436.2 251.7,436.0 C 252.4,435.9 253.1,436.5 253.8,435.7 C 254.6,434.9 255.3,432.1 256.0,431.2 C 256.7,430.3 257.5,430.4 258.2,430.3 C 258.9,430.1 259.7,430.3 260.4,430.2 C 261.1,430.1 261.8,429.8 262.6,429.5 C 263.3,429.3 264.0,429.1 264.8,428.7 C 265.5,428.2 266.2,427.4 266.9,426.9 C 267.7,426.4 268.4,425.9 269.1,425.5 C 269.9,425.1 270.6,424.8 271.3,424.6 C 272.0,424.4 272.8,424.3 273.5,424.2 C 274.2,424.1 275.0,424.1 275.7,424.0 C 276.4,423.9 277.1,423.7 277.9,423.6 C 278.6,423.5 279.3,423.6 280.0,423.5 C 280.8,423.5 281.5,423.4 282.2,423.3 C 283.0,423.2 283.7,423.2 284.4,422.9 C 285.1,422.5 285.9,421.6 286.6,421.2 C 287.3,420.7 288.1,420.6 288.8,420.2 C 289.5,419.9 290.2,420.6 291.0,419.2 C 291.7,417.8 292.4,413.6 293.2,412.0 C 293.9,410.4 294.6,410.1 295.3,409.4 C 296.1,408.7 296.8,408.3 297.5,407.8 C 298.3,407.4 299.0,406.9 299.7,406.6 C 300.4,406.2 301.2,405.9 301.9,405.6 C 302.6,405.4 303.3,405.4 304.1,405.2 C 304.8,405.0 305.5,404.8 306.3,404.5 C 307.0,404.2 307.7,403.8 308.4,403.6 C 309.2,403.4 309.9,403.4 310.6,403.2 C 311.4,402.9 312.1,402.5 312.8,402.2 C 313.5,402.0 314.3,401.7 315.0,401.5 C 315.7,401.3 316.5,401.1 317.2,401.0 C 317.9,400.9 318.6,400.8 319.4,400.7 C 320.1,400.6 320.8,400.4 321.6,400.3 C 322.3,400.1 323.0,400.0 323.7,399.8 C 324.5,399.6 325.2,399.5 325.9,399.2 C 326.7,398.9 327.4,398.4 328.1,398.1 C 328.8,397.9 329.6,397.8 330.3,397.7 C 331.0,397.5 331.7,397.4 332.5,397.3 C 333.2,397.2 333.9,397.1 334.7,397.0 C 335.4,396.9 336.1,396.8 336.8,396.7 C 337.6,396.7 338.3,396.7 339.0,396.6 C 339.8,396.5 340.5,396.3 341.2,396.1 C 341.9,395.8 342.7,395.4 343.4,395.1 C 344.1,394.8 344.9,394.5 345.6,394.3 C 346.3,394.1 347.0,394.1 347.8,394.0 C 348.5,393.8 349.2,393.8 350.0,393.6 C 350.7,393.4 351.4,392.9 352.1,392.7 C 352.9,392.5 353.6,392.6 354.3,392.5 C 355.0,392.4 355.8,392.2 356.5,392.0 C 357.2,391.8 358.0,391.7 358.7,391.5 C 359.4,391.4 360.1,391.2 360.9,391.0 C 361.6,390.8 362.3,390.8 363.1,390.6 C 363.8,390.4 364.5,390.1 365.2,389.8 C 366.0,389.6 366.7,389.5 367.4,389.3 C 368.2,389.1 368.9,388.8 369.6,388.6 C 370.3,388.4 371.1,388.1 371.8,387.9 C 372.5,387.7 373.3,387.6 374.0,387.3 C 374.7,386.9 375.4,386.1 376.2,385.8 C 376.9,385.5 377.6,385.4 378.3,385.3 C 379.1,385.2 379.8,385.2 380.5,385.1 C 381.3,385.0 382.0,384.9 382.7,384.8 C 383.4,384.7 384.2,384.8 384.9,384.5 C 385.6,384.2 386.4,383.3 387.1,382.9 C 387.8,382.5 388.5,382.6 389.3,382.4 C 390.0,382.2 390.7,381.7 391.5,381.6 C 392.2,381.4 392.9,381.5 393.6,381.3 C 394.4,381.1 395.1,380.7 395.8,380.5 C 396.6,380.3 397.3,380.4 398.0,380.3 C 398.7,380.2 399.5,380.2 400.2,380.0 C 400.9,379.8 401.7,379.6 402.4,379.1 C 403.1,378.7 403.8,377.8 404.6,377.3 C 405.3,376.8 406.0,376.6 406.7,376.3 C 407.5,376.0 408.2,375.9 408.9,375.2 C 409.7,374.6 410.4,373.2 411.1,372.5 C 411.8,371.8 412.6,371.5 413.3,371.0 C 414.0,370.6 414.8,370.6 415.5,369.9 C 416.2,369.3 416.9,367.9 417.7,367.2 C 418.4,366.6 419.1,366.5 419.9,366.2 C 420.6,365.8 421.3,365.6 422.0,365.1 C 422.8,36Line truncated
<circle cx="765.0" cy="119.4" r="5" fill="#dd4528" stroke="#0d1117" stroke-width="2" filter="url(#xkcdify)"/>
<text x="753.0" y="77.0" fill="#dd4528" font-size="18" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">7176</text>
<a href="https://github.com/carsteneu/mystarhistory" target="_blank" rel="noopener"><text x="763" y="527" font-size="13" font-family="Handlee, cursive" fill="#fff" text-anchor="end">Made with carsteneu/mystarhistory</text></a>
</svg>

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 37 KiB

+24 -22
View File
@@ -15,33 +15,35 @@
<text x="50%" y="30" fill="#000" font-size="20" font-family="Handlee, cursive" font-weight="bold" text-anchor="middle">Star History</text>
<rect width="178" height="32" x="105" y="90" fill="#fff" fill-opacity="0.9" stroke="#000" stroke-width="1.5" rx="4" ry="4" filter="url(#xkcdify)"/><rect width="8" height="8" x="115" y="102" rx="2" ry="2" fill="#dd4528" filter="url(#xkcdify)"/><text x="131" y="110" fill="#000" font-size="15" font-family="Handlee, cursive" font-weight="bold">binaricat/Netcatty</text>
<text x="85" y="468.0" fill="#000" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">0</text>
<line x1="90" y1="408.3" x2="765" y2="408.3" stroke="#eee" stroke-width="1" filter="url(#xkcdify)"/>
<text x="85" y="413.2857142857143" fill="#000" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">1K</text>
<line x1="90" y1="353.6" x2="765" y2="353.6" stroke="#eee" stroke-width="1" filter="url(#xkcdify)"/>
<text x="85" y="358.57142857142856" fill="#000" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">2K</text>
<line x1="90" y1="298.9" x2="765" y2="298.9" stroke="#eee" stroke-width="1" filter="url(#xkcdify)"/>
<text x="85" y="303.8571428571429" fill="#000" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">3K</text>
<line x1="90" y1="244.1" x2="765" y2="244.1" stroke="#eee" stroke-width="1" filter="url(#xkcdify)"/>
<text x="85" y="249.14285714285717" fill="#000" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">4K</text>
<line x1="90" y1="189.4" x2="765" y2="189.4" stroke="#eee" stroke-width="1" filter="url(#xkcdify)"/>
<text x="85" y="194.42857142857144" fill="#000" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">5K</text>
<line x1="90" y1="134.7" x2="765" y2="134.7" stroke="#eee" stroke-width="1" filter="url(#xkcdify)"/>
<text x="85" y="139.71428571428572" fill="#000" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">6K</text>
<line x1="90" y1="415.1" x2="765" y2="415.1" stroke="#eee" stroke-width="1" filter="url(#xkcdify)"/>
<text x="85" y="420.125" fill="#000" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">1K</text>
<line x1="90" y1="367.2" x2="765" y2="367.2" stroke="#eee" stroke-width="1" filter="url(#xkcdify)"/>
<text x="85" y="372.25" fill="#000" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">2K</text>
<line x1="90" y1="319.4" x2="765" y2="319.4" stroke="#eee" stroke-width="1" filter="url(#xkcdify)"/>
<text x="85" y="324.375" fill="#000" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">3K</text>
<line x1="90" y1="271.5" x2="765" y2="271.5" stroke="#eee" stroke-width="1" filter="url(#xkcdify)"/>
<text x="85" y="276.5" fill="#000" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">4K</text>
<line x1="90" y1="223.6" x2="765" y2="223.6" stroke="#eee" stroke-width="1" filter="url(#xkcdify)"/>
<text x="85" y="228.625" fill="#000" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">5K</text>
<line x1="90" y1="175.8" x2="765" y2="175.8" stroke="#eee" stroke-width="1" filter="url(#xkcdify)"/>
<text x="85" y="180.75" fill="#000" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">6K</text>
<line x1="90" y1="127.9" x2="765" y2="127.9" stroke="#eee" stroke-width="1" filter="url(#xkcdify)"/>
<text x="85" y="132.875" fill="#000" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">7K</text>
<line x1="90" y1="80.0" x2="765" y2="80.0" stroke="#eee" stroke-width="1" filter="url(#xkcdify)"/>
<text x="85" y="85.0" fill="#000" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">7K</text>
<text x="85" y="85.0" fill="#000" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">8K</text>
<text x="43" y="271.5" fill="#000" font-size="17" font-family="Handlee, cursive" font-weight="bold" transform="rotate(-90, 43, 271.5)">GitHub Stars</text>
<text x="90.0" y="488" fill="#000" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="middle">Jan 2026</text>
<text x="217.4" y="488" fill="#000" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="middle">Mar 2026</text>
<text x="353.7" y="488" fill="#000" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="middle">May 2026</text>
<text x="490.1" y="488" fill="#000" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="middle">Jul 2026</text>
<text x="628.7" y="488" fill="#000" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="middle">Sep 2026</text>
<text x="765.0" y="488" fill="#000" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="middle">Nov 2026</text>
<text x="214.5" y="488" fill="#000" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="middle">Mar 2026</text>
<text x="347.8" y="488" fill="#000" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="middle">May 2026</text>
<text x="481.0" y="488" fill="#000" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="middle">Jul 2026</text>
<text x="616.5" y="488" fill="#000" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="middle">Sep 2026</text>
<text x="749.7" y="488" fill="#000" font-size="16" font-family="Handlee, cursive" font-weight="bold" text-anchor="middle">Nov 2026</text>
<text x="50%" y="525" fill="#000" font-size="17" font-family="Handlee, cursive" font-weight="bold" text-anchor="middle">Date</text>
<line x1="90" y1="80" x2="90" y2="463" stroke="#222" stroke-width="2.5" filter="url(#xkcdify)"/>
<line x1="90" y1="463" x2="765" y2="463" stroke="#222" stroke-width="2.5" filter="url(#xkcdify)"/>
<path d="M 90.0,462.2 C 90.4,462.2 91.9,461.9 92.2,461.8 C 93.0,461.6 93.7,461.5 94.5,461.3 C 95.2,461.1 96.0,460.9 96.7,460.8 C 97.5,460.7 98.2,460.8 98.9,460.8 C 99.7,460.7 100.4,460.7 101.2,460.6 C 101.9,460.6 102.7,460.5 103.4,460.5 C 104.2,460.4 104.5,460.4 105.6,460.3 C 106.8,460.3 109.0,460.2 110.1,460.2 C 111.2,460.1 111.6,460.1 112.4,460.0 C 113.1,460.0 113.8,460.0 114.6,460.0 C 115.3,460.0 116.1,460.0 116.8,459.9 C 117.6,459.9 118.3,459.9 119.1,459.9 C 119.8,459.8 120.5,459.8 121.3,459.7 C 122.0,459.7 122.8,459.7 123.5,459.5 C 124.3,459.3 125.0,459.1 125.8,458.7 C 126.5,458.4 127.3,457.6 128.0,457.4 C 128.7,457.1 129.5,457.2 130.2,457.2 C 131.0,457.2 131.7,457.1 132.5,457.1 C 133.2,457.1 133.6,457.0 134.7,457.0 C 135.8,457.0 137.7,457.0 139.2,456.9 C 140.7,456.9 142.5,456.9 143.6,456.8 C 144.8,456.8 145.1,456.7 145.9,456.7 C 146.6,456.7 147.4,456.6 148.1,456.6 C 148.9,456.6 149.6,456.5 150.3,456.5 C 151.1,456.5 151.8,456.5 152.6,456.4 C 153.3,456.4 153.7,456.4 154.8,456.4 C 155.9,456.4 157.4,456.3 159.3,456.3 C 161.2,456.2 164.1,456.2 166.0,456.2 C 167.9,456.2 168.2,456.2 170.5,456.2 C 172.7,456.1 177.5,456.0 179.4,455.9 C 181.3,455.9 180.5,455.9 181.6,455.9 C 182.8,455.9 184.2,455.9 186.1,455.8 C 188.0,455.8 189.1,455.8 192.8,455.7 C 196.5,455.7 205.5,455.6 208.5,455.6 C 211.4,455.5 210.0,455.5 210.7,455.5 C 211.4,455.5 211.8,456.1 212.9,455.4 C 214.0,454.8 216.3,454.2 217.4,451.4 C 218.5,448.6 218.9,440.8 219.6,438.4 C 220.4,436.0 221.1,437.4 221.9,437.0 C 222.6,436.6 223.4,436.4 224.1,436.1 C 224.9,435.9 225.6,435.7 226.3,435.5 C 227.1,435.4 227.8,435.4 228.6,435.3 C 229.3,435.2 230.1,435.0 230.8,434.9 C 231.6,434.9 232.3,434.9 233.0,434.9 C 233.8,434.8 234.5,434.6 235.3,434.5 C 236.0,434.4 236.8,434.5 237.5,434.3 C 238.3,434.2 239.0,433.9 239.8,433.7 C 240.5,433.6 241.2,433.7 242.0,433.6 C 242.7,433.5 243.1,433.3 244.2,433.2 C 245.3,433.1 247.6,433.1 248.7,433.0 C 249.8,433.0 250.2,432.9 250.9,432.9 C 251.7,432.8 252.4,432.8 253.2,432.7 C 253.9,432.6 254.7,432.3 255.4,432.2 C 256.1,432.0 256.9,432.7 257.6,431.8 C 258.4,430.9 259.1,427.7 259.9,426.7 C 260.6,425.6 261.4,425.8 262.1,425.6 C 262.8,425.4 263.6,425.7 264.3,425.5 C 265.1,425.4 265.8,425.0 266.6,424.8 C 267.3,424.5 268.1,424.3 268.8,423.8 C 269.6,423.3 270.3,422.3 271.0,421.7 C 271.8,421.1 272.5,420.6 273.3,420.2 C 274.0,419.7 274.8,419.4 275.5,419.1 C 276.3,418.9 277.0,418.7 277.7,418.6 C 278.5,418.5 279.2,418.5 280.0,418.4 C 280.7,418.3 281.5,418.1 282.2,418.0 C 283.0,417.9 283.7,417.9 284.5,417.9 C 285.2,417.8 285.9,417.8 286.7,417.6 C 287.4,417.5 288.2,417.6 288.9,417.1 C 289.7,416.7 290.4,415.7 291.2,415.2 C 291.9,414.7 292.6,414.5 293.4,414.1 C 294.1,413.8 294.9,414.5 295.6,412.9 C 296.4,411.4 297.1,406.6 297.9,404.7 C 298.6,402.9 299.4,402.6 300.1,401.8 C 300.8,401.0 301.6,400.5 302.3,400.0 C 303.1,399.4 303.8,398.9 304.6,398.5 C 305.3,398.1 306.1,397.7 306.8,397.5 C 307.5,397.2 308.3,397.1 309.0,396.9 C 309.8,396.7 310.5,396.4 311.3,396.1 C 312.0,395.8 312.8,395.4 313.5,395.1 C 314.3,394.8 315.0,394.9 315.7,394.6 C 316.5,394.4 317.2,393.9 318.0,393.6 C 318.7,393.3 319.5,393.0 320.2,392.7 C 321.0,392.5 321.7,392.3 322.5,392.1 C 323.2,392.0 323.9,392.0 324.7,391.8 C 325.4,391.7 326.2,391.5 326.9,391.3 C 327.7,391.2 328.4,391.0 329.2,390.8 C 329.9,390.6 330.6,390.4 331.4,390.1 C 332.1,389.7 332.9,389.2 333.6,388.9 C 334.4,388.6 335.1,388.5 335.9,388.3 C 336.6,388.2 337.4,388.1 338.1,387.9 C 338.8,387.8 339.6,387.7 340.3,387.6 C 341.1,387.5 341.8,387.4 342.6,387.3 C 343.3,387.2 344.1,387.2 344.8,387.1 C 345.5,387.0 346.3,386.8 347.0,386.5 C 347.8,386.2 348.5,385.8 349.3,385.4 C 350.0,385.1 350.8,384.7 351.5,384.5 C 352.3,384.3 353.0,384.2 353.7,384.1 C 354.5,384.0 355.2,383.9 356.0,383.7 C 356.7,383.4 357.5,382.9 358.2,382.7 C 359.0,382.5 359.7,382.5 360.4,382.4 C 361.2,382.3 361.9,382.0 362.7,381.9 C 363.4,381.7 364.2,381.5 364.9,381.3 C 365.7,381.1 366.4,380.9 367.2,380.7 C 367.9,380.5 368.6,380.4 369.4,380.2 C 370.1,380.0 370.9,379.6 371.6,379.4 C 372.4,379.2 373.1,379.0 373.9,378.8 C 374.6,378.6 375.3,378.2 376.1,378.0 C 376.8,377.7 377.6,377.4 378.3,377.2 C 379.1,376.9 379.8,376.8 380.6,376.4 C 381.3,376.0 382.1,375.1 382.8,374.7 C 383.5,374.4 384.3,374.3 385.0,374.2 C 385.8,374.1 386.5,374.1 387.3,374.0 C 388.0,373.9 388.8,373.7 389.5,373.6 C 390.2,373.5 391.0,373.7 391.7,373.3 C 392.5,373.0 393.2,371.9 394.0,371.5 C 394.7,371.1 395.5,371.1 396.2,370.9 C 397.0,370.6 397.7,370.1 398.4,369.9 C 399.2,369.7 399.9,369.9 400.7,369.7 C 401.4,369.5 402.2,368.9 402.9,368.7 C 403.7,368.5 404.4,368.6 405.1,368.5 C 405.9,368.4 406.6,368.3 407.4,368.1 C 408.1,367.9 408.9,367.7 409.6,367.1 C 410.4,366.6 411.1,365.6 411.9,365.1 C 412.6,364.5 413.3,364.3 414.1,363.9 C 414.8,363.5 415.6,363.4 416.3,362.7 C 417.1,362.0 417.8,360.3 418.6,359.5 C 419.3,358.7 420.0,358.3 420.8,357.8 C 421.5,357.4 422.3,357.3 423.0,356.6 C 423.8,355.9 424.5,354.2 425.3,353.5 C 426.0,352.8 426.8,352.7 427.5,352.3 C 428.2,351.9 429.0,351.6 429.7,351.1 C 430.5,35Line truncated
<path d="M 90.0,462.2 C 90.4,462.2 91.9,461.9 92.2,461.8 C 93.0,461.6 93.7,461.5 94.5,461.3 C 95.2,461.1 96.0,460.9 96.7,460.8 C 97.5,460.7 98.2,460.8 98.9,460.8 C 99.7,460.7 100.4,460.7 101.2,460.6 C 101.9,460.6 102.7,460.5 103.4,460.5 C 104.2,460.4 104.5,460.4 105.6,460.3 C 106.8,460.3 109.0,460.2 110.1,460.2 C 111.2,460.1 111.6,460.1 112.4,460.0 C 113.1,460.0 113.8,460.0 114.6,460.0 C 115.3,460.0 116.1,460.0 116.8,459.9 C 117.6,459.9 118.3,459.9 119.1,459.9 C 119.8,459.8 120.5,459.8 121.3,459.7 C 122.0,459.7 122.8,459.7 123.5,459.5 C 124.3,459.3 125.0,459.1 125.8,458.7 C 126.5,458.4 127.3,457.6 128.0,457.4 C 128.7,457.1 129.5,457.2 130.2,457.2 C 131.0,457.2 131.7,457.1 132.5,457.1 C 133.2,457.1 133.6,457.0 134.7,457.0 C 135.8,457.0 137.7,457.0 139.2,456.9 C 140.7,456.9 142.5,456.9 143.6,456.8 C 144.8,456.8 145.1,456.7 145.9,456.7 C 146.6,456.7 147.4,456.6 148.1,456.6 C 148.9,456.6 149.6,456.5 150.3,456.5 C 151.1,456.5 151.8,456.5 152.6,456.4 C 153.3,456.4 153.7,456.4 154.8,456.4 C 155.9,456.4 157.4,456.3 159.3,456.3 C 161.2,456.2 164.1,456.2 166.0,456.2 C 167.9,456.2 168.2,456.2 170.5,456.2 C 172.7,456.1 177.5,456.0 179.4,455.9 C 181.3,455.9 180.5,455.9 181.6,455.9 C 182.8,455.9 184.2,455.9 186.1,455.8 C 188.0,455.8 189.1,455.8 192.8,455.7 C 196.5,455.7 205.5,455.6 208.5,455.6 C 211.4,455.5 210.0,455.5 210.7,455.5 C 211.4,455.5 211.8,456.1 212.9,455.4 C 214.0,454.8 216.3,454.2 217.4,451.4 C 218.5,448.6 218.9,440.8 219.6,438.4 C 220.4,436.0 221.1,437.4 221.9,437.0 C 222.6,436.6 223.4,436.4 224.1,436.1 C 224.9,435.9 225.6,435.7 226.3,435.5 C 227.1,435.4 227.8,435.4 228.6,435.3 C 229.3,435.2 230.1,435.0 230.8,434.9 C 231.6,434.9 232.3,434.9 233.0,434.9 C 233.8,434.8 234.5,434.6 235.3,434.5 C 236.0,434.4 236.8,434.5 237.5,434.3 C 238.3,434.2 239.0,433.9 239.8,433.7 C 240.5,433.6 241.2,433.7 242.0,433.6 C 242.7,433.5 243.1,433.3 244.2,433.2 C 245.3,433.1 247.6,433.1 248.7,433.0 C 249.8,433.0 250.2,432.9 250.9,432.9 C 251.7,432.8 252.4,432.8 253.2,432.7 C 253.9,432.6 254.7,432.3 255.4,432.2 C 256.1,432.0 256.9,432.7 257.6,431.8 C 258.4,430.9 259.1,427.7 259.9,426.7 C 260.6,425.6 261.4,425.8 262.1,425.6 C 262.8,425.4 263.6,425.7 264.3,425.5 C 265.1,425.4 265.8,425.0 266.6,424.8 C 267.3,424.5 268.1,424.3 268.8,423.8 C 269.6,423.3 270.3,422.3 271.0,421.7 C 271.8,421.1 272.5,420.6 273.3,420.2 C 274.0,419.7 274.8,419.4 275.5,419.1 C 276.3,418.9 277.0,418.7 277.7,418.6 C 278.5,418.5 279.2,418.5 280.0,418.4 C 280.7,418.3 281.5,418.1 282.2,418.0 C 283.0,417.9 283.7,417.9 284.5,417.9 C 285.2,417.8 285.9,417.8 286.7,417.6 C 287.4,417.5 288.2,417.6 288.9,417.1 C 289.7,416.7 290.4,415.7 291.2,415.2 C 291.9,414.7 292.6,414.5 293.4,414.1 C 294.1,413.8 294.9,414.5 295.6,412.9 C 296.4,411.4 297.1,406.6 297.9,404.7 C 298.6,402.9 299.4,402.6 300.1,401.8 C 300.8,401.0 301.6,400.5 302.3,400.0 C 303.1,399.4 303.8,398.9 304.6,398.5 C 305.3,398.1 306.1,397.7 306.8,397.5 C 307.5,397.2 308.3,397.1 309.0,396.9 C 309.8,396.7 310.5,396.4 311.3,396.1 C 312.0,395.8 312.8,395.4 313.5,395.1 C 314.3,394.8 315.0,394.9 315.7,394.6 C 316.5,394.4 317.2,393.9 318.0,393.6 C 318.7,393.3 319.5,393.0 320.2,392.7 C 321.0,392.5 321.7,392.3 322.5,392.1 C 323.2,392.0 323.9,392.0 324.7,391.8 C 325.4,391.7 326.2,391.5 326.9,391.3 C 327.7,391.2 328.4,391.0 329.2,390.8 C 329.9,390.6 330.6,390.4 331.4,390.1 C 332.1,389.7 332.9,389.2 333.6,388.9 C 334.4,388.6 335.1,388.5 335.9,388.3 C 336.6,388.2 337.4,388.1 338.1,387.9 C 338.8,387.8 339.6,387.7 340.3,387.6 C 341.1,387.5 341.8,387.4 342.6,387.3 C 343.3,387.2 344.1,387.2 344.8,387.1 C 345.5,387.0 346.3,386.8 347.0,386.5 C 347.8,386.2 348.5,385.8 349.3,385.4 C 350.0,385.1 350.8,384.7 351.5,384.5 C 352.3,384.3 353.0,384.2 353.7,384.1 C 354.5,384.0 355.2,383.9 356.0,383.7 C 356.7,383.4 357.5,382.9 358.2,382.7 C 359.0,382.5 359.7,382.5 360.4,382.4 C 361.2,382.3 361.9,382.0 362.7,381.9 C 363.4,381.7 364.2,381.5 364.9,381.3 C 365.7,381.1 366.4,380.9 367.2,380.7 C 367.9,380.5 368.6,380.4 369.4,380.2 C 370.1,380.0 370.9,379.6 371.6,379.4 C 372.4,379.2 373.1,379.0 373.9,378.8 C 374.6,378.6 375.3,378.2 376.1,378.0 C 376.8,377.7 377.6,377.4 378.3,377.2 C 379.1,376.9 379.8,376.8 380.6,376.4 C 381.3,376.0 382.1,375.1 382.8,374.7 C 383.5,374.4 384.3,374.3 385.0,374.2 C 385.8,374.1 386.5,374.1 387.3,374.0 C 388.0,373.9 388.8,373.7 389.5,373.6 C 390.2,373.5 391.0,373.7 391.7,373.3 C 392.5,373.0 393.2,371.9 394.0,371.5 C 394.7,371.1 395.5,371.1 396.2,370.9 C 397.0,370.6 397.7,370.1 398.4,369.9 C 399.2,369.7 399.9,369.9 400.7,369.7 C 401.4,369.5 402.2,368.9 402.9,368.7 C 403.7,368.5 404.4,368.6 405.1,368.5 C 405.9,368.4 406.6,368.3 407.4,368.1 C 408.1,367.9 408.9,367.7 409.6,367.1 C 410.4,366.6 411.1,365.6 411.9,365.1 C 412.6,364.5 413.3,364.3 414.1,363.9 C 414.8,363.5 415.6,363.4 416.3,362.7 C 417.1,362.0 417.8,360.3 418.6,359.5 C 419.3,358.7 420.0,358.3 420.8,357.8 C 421.5,357.4 422.3,357.3 423.0,356.6 C 423.8,355.9 424.5,354.2 425.3,353.5 C 426.0,352.8 426.8,352.7 427.5,352.3 C 428.2,351.9 429.0,351.6 429.7,351.1 C 430.5,35Line truncated
<circle cx="765.0" cy="80.1" r="5" fill="#dd4528" stroke="#fff" stroke-width="2" filter="url(#xkcdify)"/>
<text x="753.0" y="77.0" fill="#dd4528" font-size="18" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">6999</text>
<path d="M 90.0,462.3 C 90.4,462.3 91.8,462.0 92.2,461.9 C 92.9,461.8 93.6,461.7 94.4,461.5 C 95.1,461.4 95.8,461.2 96.6,461.1 C 97.3,461.0 98.0,461.1 98.7,461.0 C 99.5,461.0 100.2,461.0 100.9,460.9 C 101.7,460.9 102.4,460.8 103.1,460.8 C 103.8,460.7 104.2,460.7 105.3,460.7 C 106.4,460.6 108.6,460.6 109.7,460.5 C 110.8,460.5 111.1,460.4 111.8,460.4 C 112.6,460.4 113.3,460.4 114.0,460.4 C 114.8,460.4 115.5,460.3 116.2,460.3 C 116.9,460.3 117.7,460.3 118.4,460.3 C 119.1,460.2 119.9,460.2 120.6,460.1 C 121.3,460.1 122.0,460.1 122.8,459.9 C 123.5,459.8 124.2,459.6 125.0,459.3 C 125.7,459.0 126.4,458.3 127.1,458.1 C 127.9,457.8 128.6,458.0 129.3,457.9 C 130.0,457.9 130.8,457.9 131.5,457.8 C 132.2,457.8 132.6,457.8 133.7,457.7 C 134.8,457.7 136.6,457.7 138.1,457.7 C 139.5,457.7 141.3,457.6 142.4,457.6 C 143.5,457.6 143.9,457.5 144.6,457.5 C 145.3,457.5 146.1,457.4 146.8,457.4 C 147.5,457.4 148.3,457.3 149.0,457.3 C 149.7,457.3 150.4,457.3 151.2,457.3 C 151.9,457.2 152.3,457.2 153.3,457.2 C 154.4,457.2 155.9,457.1 157.7,457.1 C 159.5,457.1 162.5,457.1 164.3,457.1 C 166.1,457.0 166.5,457.1 168.6,457.0 C 170.8,457.0 175.6,456.9 177.4,456.8 C 179.2,456.8 178.5,456.8 179.6,456.8 C 180.7,456.8 182.1,456.8 183.9,456.7 C 185.8,456.7 186.8,456.7 190.5,456.6 C 194.1,456.6 202.9,456.5 205.8,456.5 C 208.7,456.5 207.2,456.5 208.0,456.4 C 208.7,456.4 209.1,457.0 210.1,456.4 C 211.2,455.8 213.4,455.3 214.5,452.9 C 215.6,450.4 216.0,443.6 216.7,441.5 C 217.4,439.4 218.2,440.6 218.9,440.3 C 219.6,439.9 220.3,439.7 221.1,439.5 C 221.8,439.3 222.5,439.1 223.3,439.0 C 224.0,438.8 224.7,438.8 225.4,438.7 C 226.2,438.6 226.9,438.5 227.6,438.4 C 228.3,438.4 229.1,438.5 229.8,438.4 C 230.5,438.3 231.3,438.1 232.0,438.1 C 232.7,438.0 233.4,438.0 234.2,437.9 C 234.9,437.8 235.6,437.5 236.4,437.4 C 237.1,437.3 237.8,437.3 238.5,437.2 C 239.3,437.2 239.6,437.0 240.7,436.9 C 241.8,436.8 244.0,436.8 245.1,436.8 C 246.2,436.7 246.6,436.7 247.3,436.6 C 248.0,436.6 248.7,436.6 249.5,436.5 C 250.2,436.4 250.9,436.2 251.7,436.0 C 252.4,435.9 253.1,436.5 253.8,435.7 C 254.6,434.9 255.3,432.1 256.0,431.2 C 256.7,430.3 257.5,430.4 258.2,430.3 C 258.9,430.1 259.7,430.3 260.4,430.2 C 261.1,430.1 261.8,429.8 262.6,429.5 C 263.3,429.3 264.0,429.1 264.8,428.7 C 265.5,428.2 266.2,427.4 266.9,426.9 C 267.7,426.4 268.4,425.9 269.1,425.5 C 269.9,425.1 270.6,424.8 271.3,424.6 C 272.0,424.4 272.8,424.3 273.5,424.2 C 274.2,424.1 275.0,424.1 275.7,424.0 C 276.4,423.9 277.1,423.7 277.9,423.6 C 278.6,423.5 279.3,423.6 280.0,423.5 C 280.8,423.5 281.5,423.4 282.2,423.3 C 283.0,423.2 283.7,423.2 284.4,422.9 C 285.1,422.5 285.9,421.6 286.6,421.2 C 287.3,420.7 288.1,420.6 288.8,420.2 C 289.5,419.9 290.2,420.6 291.0,419.2 C 291.7,417.8 292.4,413.6 293.2,412.0 C 293.9,410.4 294.6,410.1 295.3,409.4 C 296.1,408.7 296.8,408.3 297.5,407.8 C 298.3,407.4 299.0,406.9 299.7,406.6 C 300.4,406.2 301.2,405.9 301.9,405.6 C 302.6,405.4 303.3,405.4 304.1,405.2 C 304.8,405.0 305.5,404.8 306.3,404.5 C 307.0,404.2 307.7,403.8 308.4,403.6 C 309.2,403.4 309.9,403.4 310.6,403.2 C 311.4,402.9 312.1,402.5 312.8,402.2 C 313.5,402.0 314.3,401.7 315.0,401.5 C 315.7,401.3 316.5,401.1 317.2,401.0 C 317.9,400.9 318.6,400.8 319.4,400.7 C 320.1,400.6 320.8,400.4 321.6,400.3 C 322.3,400.1 323.0,400.0 323.7,399.8 C 324.5,399.6 325.2,399.5 325.9,399.2 C 326.7,398.9 327.4,398.4 328.1,398.1 C 328.8,397.9 329.6,397.8 330.3,397.7 C 331.0,397.5 331.7,397.4 332.5,397.3 C 333.2,397.2 333.9,397.1 334.7,397.0 C 335.4,396.9 336.1,396.8 336.8,396.7 C 337.6,396.7 338.3,396.7 339.0,396.6 C 339.8,396.5 340.5,396.3 341.2,396.1 C 341.9,395.8 342.7,395.4 343.4,395.1 C 344.1,394.8 344.9,394.5 345.6,394.3 C 346.3,394.1 347.0,394.1 347.8,394.0 C 348.5,393.8 349.2,393.8 350.0,393.6 C 350.7,393.4 351.4,392.9 352.1,392.7 C 352.9,392.5 353.6,392.6 354.3,392.5 C 355.0,392.4 355.8,392.2 356.5,392.0 C 357.2,391.8 358.0,391.7 358.7,391.5 C 359.4,391.4 360.1,391.2 360.9,391.0 C 361.6,390.8 362.3,390.8 363.1,390.6 C 363.8,390.4 364.5,390.1 365.2,389.8 C 366.0,389.6 366.7,389.5 367.4,389.3 C 368.2,389.1 368.9,388.8 369.6,388.6 C 370.3,388.4 371.1,388.1 371.8,387.9 C 372.5,387.7 373.3,387.6 374.0,387.3 C 374.7,386.9 375.4,386.1 376.2,385.8 C 376.9,385.5 377.6,385.4 378.3,385.3 C 379.1,385.2 379.8,385.2 380.5,385.1 C 381.3,385.0 382.0,384.9 382.7,384.8 C 383.4,384.7 384.2,384.8 384.9,384.5 C 385.6,384.2 386.4,383.3 387.1,382.9 C 387.8,382.5 388.5,382.6 389.3,382.4 C 390.0,382.2 390.7,381.7 391.5,381.6 C 392.2,381.4 392.9,381.5 393.6,381.3 C 394.4,381.1 395.1,380.7 395.8,380.5 C 396.6,380.3 397.3,380.4 398.0,380.3 C 398.7,380.2 399.5,380.2 400.2,380.0 C 400.9,379.8 401.7,379.6 402.4,379.1 C 403.1,378.7 403.8,377.8 404.6,377.3 C 405.3,376.8 406.0,376.6 406.7,376.3 C 407.5,376.0 408.2,375.9 408.9,375.2 C 409.7,374.6 410.4,373.2 411.1,372.5 C 411.8,371.8 412.6,371.5 413.3,371.0 C 414.0,370.6 414.8,370.6 415.5,369.9 C 416.2,369.3 416.9,367.9 417.7,367.2 C 418.4,366.6 419.1,366.5 419.9,366.2 C 420.6,365.8 421.3,365.6 422.0,365.1 C 422.8,36Line truncated
<path d="M 90.0,462.3 C 90.4,462.3 91.8,462.0 92.2,461.9 C 92.9,461.8 93.6,461.7 94.4,461.5 C 95.1,461.4 95.8,461.2 96.6,461.1 C 97.3,461.0 98.0,461.1 98.7,461.0 C 99.5,461.0 100.2,461.0 100.9,460.9 C 101.7,460.9 102.4,460.8 103.1,460.8 C 103.8,460.7 104.2,460.7 105.3,460.7 C 106.4,460.6 108.6,460.6 109.7,460.5 C 110.8,460.5 111.1,460.4 111.8,460.4 C 112.6,460.4 113.3,460.4 114.0,460.4 C 114.8,460.4 115.5,460.3 116.2,460.3 C 116.9,460.3 117.7,460.3 118.4,460.3 C 119.1,460.2 119.9,460.2 120.6,460.1 C 121.3,460.1 122.0,460.1 122.8,459.9 C 123.5,459.8 124.2,459.6 125.0,459.3 C 125.7,459.0 126.4,458.3 127.1,458.1 C 127.9,457.8 128.6,458.0 129.3,457.9 C 130.0,457.9 130.8,457.9 131.5,457.8 C 132.2,457.8 132.6,457.8 133.7,457.7 C 134.8,457.7 136.6,457.7 138.1,457.7 C 139.5,457.7 141.3,457.6 142.4,457.6 C 143.5,457.6 143.9,457.5 144.6,457.5 C 145.3,457.5 146.1,457.4 146.8,457.4 C 147.5,457.4 148.3,457.3 149.0,457.3 C 149.7,457.3 150.4,457.3 151.2,457.3 C 151.9,457.2 152.3,457.2 153.3,457.2 C 154.4,457.2 155.9,457.1 157.7,457.1 C 159.5,457.1 162.5,457.1 164.3,457.1 C 166.1,457.0 166.5,457.1 168.6,457.0 C 170.8,457.0 175.6,456.9 177.4,456.8 C 179.2,456.8 178.5,456.8 179.6,456.8 C 180.7,456.8 182.1,456.8 183.9,456.7 C 185.8,456.7 186.8,456.7 190.5,456.6 C 194.1,456.6 202.9,456.5 205.8,456.5 C 208.7,456.5 207.2,456.5 208.0,456.4 C 208.7,456.4 209.1,457.0 210.1,456.4 C 211.2,455.8 213.4,455.3 214.5,452.9 C 215.6,450.4 216.0,443.6 216.7,441.5 C 217.4,439.4 218.2,440.6 218.9,440.3 C 219.6,439.9 220.3,439.7 221.1,439.5 C 221.8,439.3 222.5,439.1 223.3,439.0 C 224.0,438.8 224.7,438.8 225.4,438.7 C 226.2,438.6 226.9,438.5 227.6,438.4 C 228.3,438.4 229.1,438.5 229.8,438.4 C 230.5,438.3 231.3,438.1 232.0,438.1 C 232.7,438.0 233.4,438.0 234.2,437.9 C 234.9,437.8 235.6,437.5 236.4,437.4 C 237.1,437.3 237.8,437.3 238.5,437.2 C 239.3,437.2 239.6,437.0 240.7,436.9 C 241.8,436.8 244.0,436.8 245.1,436.8 C 246.2,436.7 246.6,436.7 247.3,436.6 C 248.0,436.6 248.7,436.6 249.5,436.5 C 250.2,436.4 250.9,436.2 251.7,436.0 C 252.4,435.9 253.1,436.5 253.8,435.7 C 254.6,434.9 255.3,432.1 256.0,431.2 C 256.7,430.3 257.5,430.4 258.2,430.3 C 258.9,430.1 259.7,430.3 260.4,430.2 C 261.1,430.1 261.8,429.8 262.6,429.5 C 263.3,429.3 264.0,429.1 264.8,428.7 C 265.5,428.2 266.2,427.4 266.9,426.9 C 267.7,426.4 268.4,425.9 269.1,425.5 C 269.9,425.1 270.6,424.8 271.3,424.6 C 272.0,424.4 272.8,424.3 273.5,424.2 C 274.2,424.1 275.0,424.1 275.7,424.0 C 276.4,423.9 277.1,423.7 277.9,423.6 C 278.6,423.5 279.3,423.6 280.0,423.5 C 280.8,423.5 281.5,423.4 282.2,423.3 C 283.0,423.2 283.7,423.2 284.4,422.9 C 285.1,422.5 285.9,421.6 286.6,421.2 C 287.3,420.7 288.1,420.6 288.8,420.2 C 289.5,419.9 290.2,420.6 291.0,419.2 C 291.7,417.8 292.4,413.6 293.2,412.0 C 293.9,410.4 294.6,410.1 295.3,409.4 C 296.1,408.7 296.8,408.3 297.5,407.8 C 298.3,407.4 299.0,406.9 299.7,406.6 C 300.4,406.2 301.2,405.9 301.9,405.6 C 302.6,405.4 303.3,405.4 304.1,405.2 C 304.8,405.0 305.5,404.8 306.3,404.5 C 307.0,404.2 307.7,403.8 308.4,403.6 C 309.2,403.4 309.9,403.4 310.6,403.2 C 311.4,402.9 312.1,402.5 312.8,402.2 C 313.5,402.0 314.3,401.7 315.0,401.5 C 315.7,401.3 316.5,401.1 317.2,401.0 C 317.9,400.9 318.6,400.8 319.4,400.7 C 320.1,400.6 320.8,400.4 321.6,400.3 C 322.3,400.1 323.0,400.0 323.7,399.8 C 324.5,399.6 325.2,399.5 325.9,399.2 C 326.7,398.9 327.4,398.4 328.1,398.1 C 328.8,397.9 329.6,397.8 330.3,397.7 C 331.0,397.5 331.7,397.4 332.5,397.3 C 333.2,397.2 333.9,397.1 334.7,397.0 C 335.4,396.9 336.1,396.8 336.8,396.7 C 337.6,396.7 338.3,396.7 339.0,396.6 C 339.8,396.5 340.5,396.3 341.2,396.1 C 341.9,395.8 342.7,395.4 343.4,395.1 C 344.1,394.8 344.9,394.5 345.6,394.3 C 346.3,394.1 347.0,394.1 347.8,394.0 C 348.5,393.8 349.2,393.8 350.0,393.6 C 350.7,393.4 351.4,392.9 352.1,392.7 C 352.9,392.5 353.6,392.6 354.3,392.5 C 355.0,392.4 355.8,392.2 356.5,392.0 C 357.2,391.8 358.0,391.7 358.7,391.5 C 359.4,391.4 360.1,391.2 360.9,391.0 C 361.6,390.8 362.3,390.8 363.1,390.6 C 363.8,390.4 364.5,390.1 365.2,389.8 C 366.0,389.6 366.7,389.5 367.4,389.3 C 368.2,389.1 368.9,388.8 369.6,388.6 C 370.3,388.4 371.1,388.1 371.8,387.9 C 372.5,387.7 373.3,387.6 374.0,387.3 C 374.7,386.9 375.4,386.1 376.2,385.8 C 376.9,385.5 377.6,385.4 378.3,385.3 C 379.1,385.2 379.8,385.2 380.5,385.1 C 381.3,385.0 382.0,384.9 382.7,384.8 C 383.4,384.7 384.2,384.8 384.9,384.5 C 385.6,384.2 386.4,383.3 387.1,382.9 C 387.8,382.5 388.5,382.6 389.3,382.4 C 390.0,382.2 390.7,381.7 391.5,381.6 C 392.2,381.4 392.9,381.5 393.6,381.3 C 394.4,381.1 395.1,380.7 395.8,380.5 C 396.6,380.3 397.3,380.4 398.0,380.3 C 398.7,380.2 399.5,380.2 400.2,380.0 C 400.9,379.8 401.7,379.6 402.4,379.1 C 403.1,378.7 403.8,377.8 404.6,377.3 C 405.3,376.8 406.0,376.6 406.7,376.3 C 407.5,376.0 408.2,375.9 408.9,375.2 C 409.7,374.6 410.4,373.2 411.1,372.5 C 411.8,371.8 412.6,371.5 413.3,371.0 C 414.0,370.6 414.8,370.6 415.5,369.9 C 416.2,369.3 416.9,367.9 417.7,367.2 C 418.4,366.6 419.1,366.5 419.9,366.2 C 420.6,365.8 421.3,365.6 422.0,365.1 C 422.8,36Line truncated
<circle cx="765.0" cy="119.4" r="5" fill="#dd4528" stroke="#fff" stroke-width="2" filter="url(#xkcdify)"/>
<text x="753.0" y="77.0" fill="#dd4528" font-size="18" font-family="Handlee, cursive" font-weight="bold" text-anchor="end">7176</text>
<a href="https://github.com/carsteneu/mystarhistory" target="_blank" rel="noopener"><text x="763" y="527" font-size="13" font-family="Handlee, cursive" fill="#000" text-anchor="end">Made with carsteneu/mystarhistory</text></a>
</svg>

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 37 KiB

@@ -24,6 +24,21 @@ const UI_DISALLOWED_TOOLS = ["AskUserQuestion"];
const MCP_MODE_TOOLS = [];
const SKILLS_MODE_TOOLS = ["Bash"];
// Deduped built-in catalog from @tencent-ai/agent-sdk 0.3.258 cli/product.json.
const CODEBUDDY_BUILTIN_TOOLS = [
"Agent", "Bash", "PowerShell", "Glob", "Grep", "Read", "Edit", "Write",
"NotebookEdit", "WebFetch", "ListMcpResources", "ReadMcpResource", "WaitForMcpServers",
"TaskCreate", "TaskGet", "TaskUpdate", "TaskList", "WebSearch", "EnterPlanMode",
"ExitPlanMode", "KillShell", "TaskStop", "TaskOutput", "SlashCommand", "Skill",
"SkillManage", "AskUserQuestion", "AskUserForStructuredInput", "LSP", "StructuredOutput",
"ToolSearch", "DeferExecuteTool", "ImageGen", "ImageEdit", "VideoGen", "Artifact",
"ArtifactControl", "ComputerUse", "TeamCreate", "TeamDelete", "SendMessage",
"SendUserMessage", "EnterWorktree", "LeaveWorktree", "CronCreate", "CronDelete",
"CronList", "DelegateTool", "WeChatReply", "WeComReply", "PushNotification",
"ReportFindings", "Workflow", "Monitor", "REPL", "A2AGetAgentCard", "A2ASendMessage",
"A2AGetTask", "A2ACancelTask",
];
const CODEBUDDY_IMAGE_MEDIA_TYPES = new Set(["image/jpeg", "image/png", "image/gif", "image/webp"]);
function isCodebuddyImageAttachment(attachment) {
@@ -261,18 +276,19 @@ function buildCodebuddyQueryOptions({
allowDangerouslySkipPermissions: true,
extraArgs: { "dangerously-skip-permissions": null },
mcpServers: toSdkMcpServers(injectedMcpServers),
tools: builtinTools,
// `tools` is the built-in tool whitelist. In mcp mode it is [], so CodeBuddy
// built-ins stay disabled while injected Netcatty MCP tools remain visible.
// Do not mirror that empty list into allowedTools: the SDK treats
// allowedTools as an auto-approval list, and allowedTools: [] prevents MCP
// tool calls from running under bypassPermissions.
disallowedTools: [...UI_DISALLOWED_TOOLS],
// Block built-ins explicitly in mcp mode: tools: [] becomes --tools "",
// which also hides injected MCP tools in CodeBuddy CLI v2.183.0.
// Leave allowedTools unset: an empty auto-approval list prevents MCP tool
// calls from running under bypassPermissions.
disallowedTools: builtinTools.length > 0
? [...UI_DISALLOWED_TOOLS]
: [...new Set([...UI_DISALLOWED_TOOLS, ...CODEBUDDY_BUILTIN_TOOLS])],
// Keep the SDK isolated from user/project settings so local hooks, plugins,
// or extra MCP servers cannot expand Netcatty's controlled tool boundary.
settingSources: [],
env,
};
if (builtinTools.length > 0) options.tools = builtinTools;
const selection = splitCodebuddyModelSelection(model);
if (selection.model) options.model = selection.model;
if (abortController) options.abortController = abortController;
@@ -59,15 +59,51 @@ test("buildCodebuddyQueryOptions wires SDK options in isolated mode", () => {
assert.equal(opts.pathToCodebuddyCode, "/opt/codebuddy/bin/codebuddy");
assert.equal(opts.abortController, ac);
assert.equal(opts.resume, "sess-1");
assert.deepEqual(opts.tools, []);
// allowedTools must stay unset in mcp mode: tools:[] disables built-ins, while
assert.ok(!("tools" in opts));
// allowedTools:[] would prevent injected Netcatty MCP tools from running.
assert.ok(!("allowedTools" in opts));
assert.ok(opts.disallowedTools.includes("Bash"));
assert.ok(opts.disallowedTools.includes("AskUserQuestion"));
assert.equal(opts.mcpServers["netcatty-remote-hosts"].type, "stdio");
assert.deepEqual(opts.mcpServers["netcatty-remote-hosts"].env, { NETCATTY_MCP_PORT: "1" });
});
test("mcp and default mode block built-ins while preserving injected MCP servers", () => {
for (const toolIntegrationMode of ["mcp", undefined]) {
const opts = buildCodebuddyQueryOptions({
toolIntegrationMode,
injectedMcpServers: [{ name: "netcatty", command: "/abs/electron" }],
});
assert.ok(!("tools" in opts));
assert.ok(!("allowedTools" in opts));
assert.equal(opts.permissionMode, "bypassPermissions");
for (const name of ["Bash", "PowerShell", "Read", "Edit", "Write", "Agent", "Skill", "AskUserQuestion"]) {
assert.ok(opts.disallowedTools.includes(name), `${name} must stay disabled`);
}
assert.equal(opts.mcpServers.netcatty.command, "/abs/electron");
}
});
test("mcp mode omits --tools under the SDK serialization rule", () => {
for (const toolIntegrationMode of ["mcp", undefined]) {
const opts = buildCodebuddyQueryOptions({ toolIntegrationMode });
const args = [];
// @tencent-ai/agent-sdk lib/transport/process-transport.js
if (opts.tools !== undefined) {
args.push("--tools", opts.tools.join(","));
}
assert.deepEqual(args, []);
}
});
test("skills mode keeps the Bash whitelist and UI exclusions", () => {
const opts = buildCodebuddyQueryOptions({ toolIntegrationMode: "skills" });
assert.deepEqual(opts.tools, ["Bash"]);
assert.deepEqual(opts.disallowedTools, ["AskUserQuestion"]);
assert.ok(!opts.disallowedTools.includes("Bash"));
assert.ok(!("allowedTools" in opts));
});
test("built-in tools are mode-aware", () => {
assert.deepEqual(codebuddyBuiltinTools("mcp"), []);
assert.deepEqual(codebuddyBuiltinTools(undefined), []);
+139
View File
@@ -0,0 +1,139 @@
/**
* Pick Chromium's Linux password store before app.whenReady().
*
* Chromium sniffs XDG_CURRENT_DESKTOP and only enables gnome-libsecret /
* kwallet for GNOME-family and KDE/Plasma names. Other compositors
* (niri, sway, Hyprland, …) fall through to BASIC_TEXT even when
* Secret Service is running, so safeStorage.isEncryptionAvailable()
* is false (#4189).
*
* Must run before app.whenReady(); Electron ignores --password-store
* afterwards.
*/
const { execFileSync } = require("node:child_process");
const SECRET_SERVICE_NAME = "org.freedesktop.secrets";
const PASSWORD_STORE_SWITCH = "password-store";
const GNOME_LIBSECRET = "gnome-libsecret";
const DEFAULT_PROBE_TIMEOUT_MS = 1000;
const SECRET_SERVICE_PROBE_COMMANDS = [
{
file: "busctl",
args: [
"--user",
"call",
"org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"NameHasOwner",
"s",
SECRET_SERVICE_NAME,
],
},
{
file: "gdbus",
args: [
"call",
"--session",
"--dest",
"org.freedesktop.DBus",
"--object-path",
"/org/freedesktop/DBus",
"--method",
"org.freedesktop.DBus.NameHasOwner",
SECRET_SERVICE_NAME,
],
},
{
file: "dbus-send",
args: [
"--session",
"--print-reply=literal",
"--dest=org.freedesktop.DBus",
"/org/freedesktop/DBus",
"org.freedesktop.DBus.NameHasOwner",
`string:${SECRET_SERVICE_NAME}`,
],
},
];
function desktopTokens(env = process.env) {
const raw = [env?.XDG_CURRENT_DESKTOP, env?.XDG_SESSION_DESKTOP]
.filter((value) => typeof value === "string" && value.length > 0)
.join(":");
return raw
.split(":")
.map((token) => token.trim().toLowerCase())
.filter(Boolean);
}
function isKdePlasmaDesktop(env = process.env) {
return desktopTokens(env).some((token) => token === "kde" || token === "plasma");
}
function parseNameHasOwnerOutput(stdout) {
const text = String(stdout ?? "");
if (/\bfalse\b/i.test(text)) return false;
if (/\btrue\b/i.test(text)) return true;
return false;
}
function defaultProbeSecretService(options = {}) {
const run = options.execFileSync ?? execFileSync;
const timeout = options.timeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS;
for (const command of SECRET_SERVICE_PROBE_COMMANDS) {
try {
const stdout = run(command.file, command.args, {
encoding: "utf8",
timeout,
stdio: ["ignore", "pipe", "ignore"],
});
return parseNameHasOwnerOutput(stdout);
} catch {
// Missing binary, timeout, or D-Bus error: try the next helper.
}
}
return false;
}
function applyLinuxPasswordStore(app, options = {}) {
const platform = options.platform ?? process.platform;
if (platform !== "linux") return false;
if (!app?.commandLine) return false;
const env = options.env ?? process.env;
const hasSwitch = options.hasSwitch
?? ((name) => Boolean(app.commandLine.hasSwitch?.(name)));
const appendSwitch = options.appendSwitch
?? ((name, value) => app.commandLine.appendSwitch(name, value));
if (hasSwitch(PASSWORD_STORE_SWITCH)) return false;
if (isKdePlasmaDesktop(env)) return false;
let available = false;
try {
const probe = options.probeSecretService ?? defaultProbeSecretService;
available = Boolean(probe({
execFileSync: options.execFileSync,
timeoutMs: options.timeoutMs,
}));
} catch {
return false;
}
if (!available) return false;
appendSwitch(PASSWORD_STORE_SWITCH, GNOME_LIBSECRET);
return true;
}
module.exports = {
SECRET_SERVICE_NAME,
PASSWORD_STORE_SWITCH,
GNOME_LIBSECRET,
applyLinuxPasswordStore,
isKdePlasmaDesktop,
parseNameHasOwnerOutput,
defaultProbeSecretService,
};
+152
View File
@@ -0,0 +1,152 @@
const test = require("node:test");
const assert = require("node:assert/strict");
const fs = require("node:fs");
const path = require("node:path");
const {
GNOME_LIBSECRET,
PASSWORD_STORE_SWITCH,
applyLinuxPasswordStore,
defaultProbeSecretService,
isKdePlasmaDesktop,
parseNameHasOwnerOutput,
} = require("./linuxPasswordStore.cjs");
function createApp({ existingSwitch = false } = {}) {
const appended = [];
return {
appended,
app: {
commandLine: {
hasSwitch(name) {
return existingSwitch && name === PASSWORD_STORE_SWITCH;
},
appendSwitch(name, value) {
appended.push([name, value]);
},
},
},
};
}
function apply(overrides = {}, appOptions = {}) {
const { app, appended } = createApp(appOptions);
const applied = applyLinuxPasswordStore(app, {
platform: "linux",
env: { XDG_CURRENT_DESKTOP: "niri" },
probeSecretService: () => true,
...overrides,
});
return { applied, appended };
}
test("niri with Secret Service appends gnome-libsecret", () => {
const { applied, appended } = apply({
env: { XDG_CURRENT_DESKTOP: "niri" },
});
assert.equal(applied, true);
assert.deepEqual(appended, [[PASSWORD_STORE_SWITCH, GNOME_LIBSECRET]]);
});
test("sway and Hyprland with Secret Service append gnome-libsecret", () => {
for (const desktop of ["sway", "Hyprland"]) {
const { applied, appended } = apply({
env: { XDG_CURRENT_DESKTOP: desktop },
});
assert.equal(applied, true, desktop);
assert.deepEqual(appended, [[PASSWORD_STORE_SWITCH, GNOME_LIBSECRET]], desktop);
}
});
test("KDE and Plasma desktops do not append even when Secret Service is present", () => {
for (const env of [
{ XDG_CURRENT_DESKTOP: "KDE" },
{ XDG_CURRENT_DESKTOP: "plasma" },
{ XDG_CURRENT_DESKTOP: "ubuntu:KDE" },
{ XDG_SESSION_DESKTOP: "plasma" },
]) {
const { applied, appended } = apply({ env });
assert.equal(applied, false, JSON.stringify(env));
assert.deepEqual(appended, [], JSON.stringify(env));
}
});
test("existing --password-store switch is left alone", () => {
const { applied, appended } = apply({}, { existingSwitch: true });
assert.equal(applied, false);
assert.deepEqual(appended, []);
});
test("absent, throwing, or empty Secret Service probe does not append", () => {
for (const probeSecretService of [
() => false,
() => {
throw new Error("probe failed");
},
]) {
const { applied, appended } = apply({ probeSecretService });
assert.equal(applied, false);
assert.deepEqual(appended, []);
}
});
test("non-Linux platforms do not append", () => {
for (const platform of ["darwin", "win32"]) {
const { applied, appended } = apply({ platform });
assert.equal(applied, false, platform);
assert.deepEqual(appended, [], platform);
}
});
test("isKdePlasmaDesktop splits colon-separated desktop names", () => {
assert.equal(isKdePlasmaDesktop({ XDG_CURRENT_DESKTOP: "niri" }), false);
assert.equal(isKdePlasmaDesktop({ XDG_CURRENT_DESKTOP: "ubuntu:GNOME" }), false);
assert.equal(isKdePlasmaDesktop({ XDG_CURRENT_DESKTOP: "ubuntu:KDE" }), true);
assert.equal(isKdePlasmaDesktop({ XDG_SESSION_DESKTOP: "Plasma" }), true);
});
test("parseNameHasOwnerOutput understands busctl, gdbus, and dbus-send", () => {
assert.equal(parseNameHasOwnerOutput("b true\n"), true);
assert.equal(parseNameHasOwnerOutput("b false\n"), false);
assert.equal(parseNameHasOwnerOutput("(true,)"), true);
assert.equal(parseNameHasOwnerOutput("(false,)"), false);
assert.equal(parseNameHasOwnerOutput("boolean true"), true);
assert.equal(parseNameHasOwnerOutput(" boolean false"), false);
assert.equal(parseNameHasOwnerOutput(""), false);
});
test("defaultProbeSecretService falls through missing binaries and reads the first reply", () => {
const calls = [];
const execFileSync = (file, args) => {
calls.push(file);
if (file === "busctl") {
const err = new Error("not found");
err.code = "ENOENT";
throw err;
}
if (file === "gdbus") return "(true,)\n";
throw new Error(`unexpected ${file}`);
};
assert.equal(defaultProbeSecretService({ execFileSync }), true);
assert.deepEqual(calls, ["busctl", "gdbus"]);
});
test("defaultProbeSecretService is false when every helper fails", () => {
assert.equal(defaultProbeSecretService({
execFileSync() {
throw new Error("missing");
},
}), false);
});
test("main.cjs applies the helper before app.whenReady()", () => {
const source = fs.readFileSync(path.join(__dirname, "main.cjs"), "utf8");
const helperIdx = source.indexOf('require("./linuxPasswordStore.cjs")');
const callIdx = source.indexOf("applyLinuxPasswordStore(app)");
const readyIdx = source.indexOf("app.whenReady()");
assert.ok(helperIdx >= 0, "requires linuxPasswordStore.cjs");
assert.ok(callIdx >= 0, "calls applyLinuxPasswordStore(app)");
assert.ok(readyIdx >= 0, "has app.whenReady()");
assert.ok(helperIdx < readyIdx, "require is before whenReady");
assert.ok(callIdx < readyIdx, "call is before whenReady");
});
+6
View File
@@ -255,6 +255,12 @@ if (process.env.NETCATTY_COMPAT_GPU !== "1") {
app.commandLine.appendSwitch("enable-zero-copy");
}
// Linux: Chromium only auto-selects gnome-libsecret / kwallet from
// GNOME/KDE desktop names. Other compositors (niri/sway/Hyprland) fall
// through to BASIC_TEXT even when Secret Service is running (#4189).
const { applyLinuxPasswordStore } = require("./linuxPasswordStore.cjs");
applyLinuxPasswordStore(app);
// Silence noisy DevTools Autofill CDP errors (Electron's backend doesn't expose this domain)
app.on("web-contents-created", (_event, contents) => {
if (contents.getType() !== "devtools") return;
+34
View File
@@ -2,8 +2,10 @@
appimageTools,
fetchurl,
lib,
openssh,
release ? import ./release.nix,
stdenv,
writeShellScriptBin,
}:
let
@@ -22,10 +24,42 @@ let
appimageContents = appimageTools.extractType2 {
inherit pname version src;
};
# home-manager's ~/.ssh/config is a root-owned symlink into the nix store.
# Unprivileged bwrap (wrapType2 / buildFHSEnv) maps only the caller uid, so
# that file appears as overflowuid 65534 and OpenSSH refuses the default
# user config with "Bad owner or permissions". A -F path skips that check.
# The wrapper is injected via extraPkgs so it lands on the FHS /usr/bin,
# which buildFHSEnv prepends ahead of any bind-mounted host profile PATH.
sshWrapped = writeShellScriptBin "ssh" ''
real_ssh="${openssh}/bin/ssh"
config="''${HOME}/.ssh/config"
if [ -e "$config" ]; then
owner="$(stat -c %u -L "$config" 2>/dev/null || true)"
me="$(id -u)"
if [ -n "$owner" ] && [ "$owner" != "$me" ] && [ "$owner" != 0 ]; then
cache="''${XDG_CACHE_HOME:-$HOME/.cache}/netcatty"
snap="$cache/ssh_config"
mkdir -p "$cache"
# Always refresh: nix store files have frozen old mtimes, so -nt
# never sees a newer home-manager generation after the first copy.
# Publish via a unique staging file + mv so a concurrent ssh -F
# reader never sees a truncated snapshot (cp truncates first).
snap_tmp="$snap.tmp.$$"
cp -L "$config" "$snap_tmp"
chmod 600 "$snap_tmp"
mv -f "$snap_tmp" "$snap"
exec "$real_ssh" -F "$snap" "$@"
fi
fi
exec "$real_ssh" "$@"
'';
in
appimageTools.wrapType2 {
inherit pname version src;
extraPkgs = pkgs: [ sshWrapped ];
extraInstallCommands = ''
desktopSource="$(find ${appimageContents} -maxdepth 3 -name '*.desktop' -print -quit)"
if [ -n "$desktopSource" ]; then