@wrongstack/tools 0.276.4 → 0.277.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audit.js +21 -8
- package/dist/audit.js.map +1 -1
- package/dist/bash.js.map +1 -1
- package/dist/builtin.js +661 -57
- package/dist/builtin.js.map +1 -1
- package/dist/exec.js +534 -9
- package/dist/exec.js.map +1 -1
- package/dist/fetch.js +7 -3
- package/dist/fetch.js.map +1 -1
- package/dist/format.js +22 -9
- package/dist/format.js.map +1 -1
- package/dist/index.js +662 -58
- package/dist/index.js.map +1 -1
- package/dist/install.js +21 -8
- package/dist/install.js.map +1 -1
- package/dist/lint.js +21 -8
- package/dist/lint.js.map +1 -1
- package/dist/memory.js +1 -1
- package/dist/memory.js.map +1 -1
- package/dist/outdated.js +20 -7
- package/dist/outdated.js.map +1 -1
- package/dist/pack.js +661 -57
- package/dist/pack.js.map +1 -1
- package/dist/search.js +113 -36
- package/dist/search.js.map +1 -1
- package/dist/test.js +21 -8
- package/dist/test.js.map +1 -1
- package/dist/typecheck.js +21 -8
- package/dist/typecheck.js.map +1 -1
- package/package.json +9 -5
package/dist/pack.js
CHANGED
|
@@ -15,7 +15,7 @@ import * as ts from 'typescript';
|
|
|
15
15
|
import { toErrorMessage as toErrorMessage$1 } from '@wrongstack/core/utils/error';
|
|
16
16
|
import * as dns from 'node:dns/promises';
|
|
17
17
|
import * as net from 'node:net';
|
|
18
|
-
import { Agent } from 'undici';
|
|
18
|
+
import { Agent, fetch } from 'undici';
|
|
19
19
|
import TurndownService from 'turndown';
|
|
20
20
|
import { randomUUID } from 'node:crypto';
|
|
21
21
|
|
|
@@ -714,16 +714,28 @@ function resolvePowerShell(cmd) {
|
|
|
714
714
|
}
|
|
715
715
|
return resolved;
|
|
716
716
|
}
|
|
717
|
-
var WIN32_SHELL_META = /[
|
|
717
|
+
var WIN32_SHELL_META = /[&|<>"\r\n\0]/;
|
|
718
718
|
function assertSafeWin32ShellArgs(args) {
|
|
719
|
-
for (const
|
|
720
|
-
if (typeof
|
|
719
|
+
for (const arg of args) {
|
|
720
|
+
if (typeof arg === "string" && WIN32_SHELL_META.test(arg)) {
|
|
721
721
|
throw new Error(
|
|
722
|
-
|
|
722
|
+
'win32 cmd shim spawn: argument contains a shell metacharacter (one of & | < > ", or a newline) that could enable command injection through the .cmd/.bat wrapper - refusing to run. Offending argument: ' + JSON.stringify(arg)
|
|
723
723
|
);
|
|
724
724
|
}
|
|
725
725
|
}
|
|
726
726
|
}
|
|
727
|
+
function buildWin32CmdShimInvocation(command, args = []) {
|
|
728
|
+
assertSafeWin32ShellArgs([command, ...args]);
|
|
729
|
+
const line = ["call", quoteWin32CmdArg(command), ...args.map(quoteWin32CmdArg)].join(" ");
|
|
730
|
+
return {
|
|
731
|
+
command: process.env["COMSPEC"] ?? "cmd.exe",
|
|
732
|
+
args: ["/d", "/c", line],
|
|
733
|
+
windowsVerbatimArguments: true
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
function quoteWin32CmdArg(arg) {
|
|
737
|
+
return `"${arg}"`;
|
|
738
|
+
}
|
|
727
739
|
|
|
728
740
|
// src/_spawn-stream.ts
|
|
729
741
|
var isWin = process.platform === "win32";
|
|
@@ -738,15 +750,16 @@ async function* spawnStream(opts) {
|
|
|
738
750
|
const spool = createOutputSpool({ tool: opts.cmd, thresholdBytes: max });
|
|
739
751
|
const resolved = resolveWin32Command(opts.cmd);
|
|
740
752
|
const needsShell = isWin && (resolved.endsWith(".cmd") || resolved.endsWith(".bat"));
|
|
741
|
-
const
|
|
742
|
-
|
|
743
|
-
const
|
|
753
|
+
const shim = needsShell ? buildWin32CmdShimInvocation(resolved, opts.args) : null;
|
|
754
|
+
const cmd = shim?.command ?? resolved;
|
|
755
|
+
const args = shim?.args ?? opts.args;
|
|
756
|
+
const child = spawn(cmd, args, {
|
|
744
757
|
cwd: opts.cwd,
|
|
745
758
|
env: buildChildEnv(),
|
|
746
759
|
stdio: ["ignore", "pipe", "pipe"],
|
|
747
760
|
windowsHide: true,
|
|
748
761
|
...isWin ? {} : { signal: opts.signal },
|
|
749
|
-
...
|
|
762
|
+
...shim ? { windowsVerbatimArguments: shim.windowsVerbatimArguments } : {}
|
|
750
763
|
});
|
|
751
764
|
const registry = getProcessRegistry();
|
|
752
765
|
const pid = child.pid;
|
|
@@ -5408,9 +5421,9 @@ var designTool = {
|
|
|
5408
5421
|
category: "Design",
|
|
5409
5422
|
description: 'Browse, load, customize, and enforce curated frontend/mobile UI design kits. Use BEFORE writing UI code to commit to one coherent, modern, responsive, dark/light, accessible design. Actions: "list" (menu), "use" (load+pin a kit for a stack), "foundations" (baseline), "set" (override kit colors/tokens), "materialize" (write the tokens to a real theme file \u2014 CSS @theme/OKLCH or native), "verify" (scan UI files for off-palette colors).',
|
|
5410
5423
|
usageHint: 'Flow: `design {action:"use", kit:"minimal-clarity", stack:"web"}` \u2192 optionally `design {action:"set", set:{primary:"oklch(62% 0.2 25)"}}` \u2192 `design {action:"materialize"}` to write tokens to disk \u2192 implement against them \u2192 `design {action:"verify"}`.',
|
|
5411
|
-
permission: "
|
|
5412
|
-
mutating:
|
|
5413
|
-
capabilities: [],
|
|
5424
|
+
permission: "confirm",
|
|
5425
|
+
mutating: true,
|
|
5426
|
+
capabilities: ["fs.write"],
|
|
5414
5427
|
timeoutMs: 15e3,
|
|
5415
5428
|
inputSchema: {
|
|
5416
5429
|
type: "object",
|
|
@@ -6146,10 +6159,20 @@ var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
6146
6159
|
// C / C++ / native build
|
|
6147
6160
|
"make",
|
|
6148
6161
|
"cmake",
|
|
6162
|
+
"ninja",
|
|
6163
|
+
"clang",
|
|
6164
|
+
"clang-cl",
|
|
6165
|
+
"gcc",
|
|
6166
|
+
"g++",
|
|
6167
|
+
"link",
|
|
6168
|
+
"msbuild",
|
|
6149
6169
|
// containers / orchestration
|
|
6150
6170
|
"docker",
|
|
6151
6171
|
"podman",
|
|
6152
6172
|
"kubectl",
|
|
6173
|
+
// network (read-only intent; destructive ops still blocked by BLOCKED_ARG_PATTERNS)
|
|
6174
|
+
"curl",
|
|
6175
|
+
"wget",
|
|
6153
6176
|
// common POSIX file/text utilities
|
|
6154
6177
|
"pwd",
|
|
6155
6178
|
"ls",
|
|
@@ -6169,7 +6192,509 @@ var DEFAULT_ALLOWED_COMMANDS = /* @__PURE__ */ new Set([
|
|
|
6169
6192
|
"cp",
|
|
6170
6193
|
"mv",
|
|
6171
6194
|
"rm",
|
|
6172
|
-
"touch"
|
|
6195
|
+
"touch",
|
|
6196
|
+
"tar",
|
|
6197
|
+
// Windows-native tooling (win32). All non-destructive binaries; per-arg
|
|
6198
|
+
// safety is still enforced by BLOCKED_ARG_PATTERNS + the destructive-ops
|
|
6199
|
+
// gate in bash-kill-guard.ts. `gh` is included even though it lives at
|
|
6200
|
+
// "C:\Program Files\GitHub CLI\gh.exe" — resolveWin32Command handles the
|
|
6201
|
+
// space in the path.
|
|
6202
|
+
"gh",
|
|
6203
|
+
"where",
|
|
6204
|
+
"tasklist",
|
|
6205
|
+
"systeminfo",
|
|
6206
|
+
"wmic",
|
|
6207
|
+
"sc",
|
|
6208
|
+
"netstat",
|
|
6209
|
+
"ipconfig",
|
|
6210
|
+
"nslookup",
|
|
6211
|
+
"tracert",
|
|
6212
|
+
"pathping",
|
|
6213
|
+
// Windows shell interpreters. Without these, `exec` cannot run cmd builtins
|
|
6214
|
+
// (`dir`, `type`, `copy`, …) or any PowerShell cmdlet on Windows — a major
|
|
6215
|
+
// gap since those are the platform's primary shells. Arbitrary execution
|
|
6216
|
+
// through `cmd /c …` / `powershell -c …` is NOT a new hole: the permission
|
|
6217
|
+
// policy reconstructs the full command line (shellCommandLineFromInput) and
|
|
6218
|
+
// still runs it through the YOLO destructive classifier, so a genuinely
|
|
6219
|
+
// destructive `cmd /c del /s /q C:\…` continues to require confirmation.
|
|
6220
|
+
"cmd",
|
|
6221
|
+
"cmd.exe",
|
|
6222
|
+
"powershell",
|
|
6223
|
+
"powershell.exe",
|
|
6224
|
+
"pwsh",
|
|
6225
|
+
"pwsh.exe",
|
|
6226
|
+
// [core] Extended default allowlist (added 4b3d18d1 + this commit). All
|
|
6227
|
+
// non-destructive, broadly-used dev binaries. Per-arg safety is still
|
|
6228
|
+
// enforced by BLOCKED_ARG_PATTERNS + bash-kill-guard.ts.
|
|
6229
|
+
// --- Archives & compression ---
|
|
6230
|
+
"7z",
|
|
6231
|
+
"7za",
|
|
6232
|
+
"bzip2",
|
|
6233
|
+
"gzip",
|
|
6234
|
+
"xz",
|
|
6235
|
+
"unzip",
|
|
6236
|
+
"zip",
|
|
6237
|
+
"gtar",
|
|
6238
|
+
"bsdtar",
|
|
6239
|
+
"star",
|
|
6240
|
+
"pax",
|
|
6241
|
+
"cpio",
|
|
6242
|
+
// --- Android / mobile dev ---
|
|
6243
|
+
"adb",
|
|
6244
|
+
"fastboot",
|
|
6245
|
+
"sdkmanager",
|
|
6246
|
+
// --- DevOps / config mgmt ---
|
|
6247
|
+
"ansible",
|
|
6248
|
+
"ansible-playbook",
|
|
6249
|
+
"ansible-vault",
|
|
6250
|
+
"ansible-lint",
|
|
6251
|
+
"ansible-galaxy",
|
|
6252
|
+
"molecule",
|
|
6253
|
+
// --- Cloud CLIs ---
|
|
6254
|
+
"aws",
|
|
6255
|
+
"aws-vault",
|
|
6256
|
+
"awslocal",
|
|
6257
|
+
"az",
|
|
6258
|
+
"azcopy",
|
|
6259
|
+
"gcloud",
|
|
6260
|
+
"gsutil",
|
|
6261
|
+
"doctl",
|
|
6262
|
+
"linode-cli",
|
|
6263
|
+
// --- Native / C / C++ / linker tools ---
|
|
6264
|
+
"clang++",
|
|
6265
|
+
"clang-format",
|
|
6266
|
+
"clang-tidy",
|
|
6267
|
+
"clangd",
|
|
6268
|
+
"lld",
|
|
6269
|
+
"lldb",
|
|
6270
|
+
"ctest",
|
|
6271
|
+
"gmake",
|
|
6272
|
+
"meson",
|
|
6273
|
+
"conan",
|
|
6274
|
+
"vcpkg",
|
|
6275
|
+
"cl",
|
|
6276
|
+
"rc",
|
|
6277
|
+
"mt",
|
|
6278
|
+
"dumpbin",
|
|
6279
|
+
"dotnet-format",
|
|
6280
|
+
// --- Image / media / binary tools ---
|
|
6281
|
+
"convert",
|
|
6282
|
+
"ffmpeg",
|
|
6283
|
+
"ffprobe",
|
|
6284
|
+
"magick",
|
|
6285
|
+
"gs",
|
|
6286
|
+
"exiftool",
|
|
6287
|
+
// --- HTTP / fetch ---
|
|
6288
|
+
"wget2",
|
|
6289
|
+
"aria2c",
|
|
6290
|
+
"axel",
|
|
6291
|
+
"httpie",
|
|
6292
|
+
"hey",
|
|
6293
|
+
"ab",
|
|
6294
|
+
"wrk",
|
|
6295
|
+
"http",
|
|
6296
|
+
// --- Diff / patch / merge ---
|
|
6297
|
+
"diff",
|
|
6298
|
+
"diff3",
|
|
6299
|
+
"patch",
|
|
6300
|
+
"meld",
|
|
6301
|
+
"kdiff3",
|
|
6302
|
+
"kompare",
|
|
6303
|
+
// --- Encoding / file inspection ---
|
|
6304
|
+
"dos2unix",
|
|
6305
|
+
"unix2dos",
|
|
6306
|
+
"iconv",
|
|
6307
|
+
"file",
|
|
6308
|
+
"stat",
|
|
6309
|
+
"xxd",
|
|
6310
|
+
"hexdump",
|
|
6311
|
+
"od",
|
|
6312
|
+
"base64",
|
|
6313
|
+
// --- SSH / crypto / signing ---
|
|
6314
|
+
"ssh",
|
|
6315
|
+
"ssh-add",
|
|
6316
|
+
"ssh-keygen",
|
|
6317
|
+
"ssh-keyscan",
|
|
6318
|
+
"scp",
|
|
6319
|
+
"sftp",
|
|
6320
|
+
"rsync",
|
|
6321
|
+
"gpg",
|
|
6322
|
+
"gpg2",
|
|
6323
|
+
"gpg-agent",
|
|
6324
|
+
"openssl",
|
|
6325
|
+
"step",
|
|
6326
|
+
"keytool",
|
|
6327
|
+
// --- Search ---
|
|
6328
|
+
"egrep",
|
|
6329
|
+
"fgrep",
|
|
6330
|
+
"ag",
|
|
6331
|
+
"ack",
|
|
6332
|
+
"sift",
|
|
6333
|
+
"ugrep",
|
|
6334
|
+
"fd",
|
|
6335
|
+
"fdfind",
|
|
6336
|
+
"jq",
|
|
6337
|
+
"yq",
|
|
6338
|
+
"xq",
|
|
6339
|
+
"fx",
|
|
6340
|
+
"gron",
|
|
6341
|
+
// --- K8s / container ecosystem ---
|
|
6342
|
+
"kubectl.exe",
|
|
6343
|
+
"kubeadm",
|
|
6344
|
+
"kubelet",
|
|
6345
|
+
"helm",
|
|
6346
|
+
"k9s",
|
|
6347
|
+
"kustomize",
|
|
6348
|
+
"skaffold",
|
|
6349
|
+
"tilt",
|
|
6350
|
+
"minikube",
|
|
6351
|
+
"kind",
|
|
6352
|
+
"k3d",
|
|
6353
|
+
"k3s",
|
|
6354
|
+
"docker-compose",
|
|
6355
|
+
"buildah",
|
|
6356
|
+
"skopeo",
|
|
6357
|
+
"nerdctl",
|
|
6358
|
+
"ctr",
|
|
6359
|
+
"ctr.exe",
|
|
6360
|
+
// --- Databases ---
|
|
6361
|
+
"sqlite3",
|
|
6362
|
+
"sqlite",
|
|
6363
|
+
"psql",
|
|
6364
|
+
"pg_dump",
|
|
6365
|
+
"pg_restore",
|
|
6366
|
+
"mysql",
|
|
6367
|
+
"mysqladmin",
|
|
6368
|
+
"mysqldump",
|
|
6369
|
+
"mariadb",
|
|
6370
|
+
"mariadb-dump",
|
|
6371
|
+
"redis-cli",
|
|
6372
|
+
"redis-server",
|
|
6373
|
+
"memcached",
|
|
6374
|
+
"etcdctl",
|
|
6375
|
+
"consul",
|
|
6376
|
+
"vault",
|
|
6377
|
+
"nomad",
|
|
6378
|
+
"mongosh",
|
|
6379
|
+
"mongo",
|
|
6380
|
+
"mongoexport",
|
|
6381
|
+
"mongoimport",
|
|
6382
|
+
"mongodump",
|
|
6383
|
+
"mongorestore",
|
|
6384
|
+
// --- Windows extended (read-mostly ops) ---
|
|
6385
|
+
"taskkill",
|
|
6386
|
+
"gpupdate",
|
|
6387
|
+
"gpresult",
|
|
6388
|
+
"hostname",
|
|
6389
|
+
"whoami",
|
|
6390
|
+
"who",
|
|
6391
|
+
"net",
|
|
6392
|
+
"net1",
|
|
6393
|
+
// --- VCS ecosystem ---
|
|
6394
|
+
"glab",
|
|
6395
|
+
"hub",
|
|
6396
|
+
"tea",
|
|
6397
|
+
"git-lfs",
|
|
6398
|
+
"tig",
|
|
6399
|
+
"lazygit",
|
|
6400
|
+
// --- POSIX text utilities (extended; duplicates of pwd/ls/cat/head/tail/wc/
|
|
6401
|
+
// grep/find/echo/awk/mkdir/cp/mv/rm/touch from the base list above are
|
|
6402
|
+
// omitted — the Set is de-duplicated at runtime but a clean literal is
|
|
6403
|
+
// easier to maintain) ---
|
|
6404
|
+
"gawk",
|
|
6405
|
+
"tr",
|
|
6406
|
+
"cut",
|
|
6407
|
+
"paste",
|
|
6408
|
+
"join",
|
|
6409
|
+
"comm",
|
|
6410
|
+
"expand",
|
|
6411
|
+
"unexpand",
|
|
6412
|
+
"fold",
|
|
6413
|
+
"fmt",
|
|
6414
|
+
"nl",
|
|
6415
|
+
"pr",
|
|
6416
|
+
"column",
|
|
6417
|
+
"tsort",
|
|
6418
|
+
"tty",
|
|
6419
|
+
"ul",
|
|
6420
|
+
"units",
|
|
6421
|
+
"factor",
|
|
6422
|
+
"seq",
|
|
6423
|
+
"shuf",
|
|
6424
|
+
"look",
|
|
6425
|
+
"yes",
|
|
6426
|
+
"true",
|
|
6427
|
+
"false",
|
|
6428
|
+
"test",
|
|
6429
|
+
"[",
|
|
6430
|
+
"printf",
|
|
6431
|
+
"env",
|
|
6432
|
+
"tree",
|
|
6433
|
+
"locate",
|
|
6434
|
+
"which",
|
|
6435
|
+
"whereis",
|
|
6436
|
+
"type",
|
|
6437
|
+
"hash",
|
|
6438
|
+
"pushd",
|
|
6439
|
+
"popd",
|
|
6440
|
+
"dirs",
|
|
6441
|
+
"history",
|
|
6442
|
+
"fc",
|
|
6443
|
+
"jobs",
|
|
6444
|
+
"bg",
|
|
6445
|
+
"fg",
|
|
6446
|
+
"wait",
|
|
6447
|
+
"ulimit",
|
|
6448
|
+
"umask",
|
|
6449
|
+
"nice",
|
|
6450
|
+
"nohup",
|
|
6451
|
+
"timeout",
|
|
6452
|
+
"time",
|
|
6453
|
+
"trap",
|
|
6454
|
+
"exit",
|
|
6455
|
+
"return",
|
|
6456
|
+
"source",
|
|
6457
|
+
".",
|
|
6458
|
+
"alias",
|
|
6459
|
+
"unalias",
|
|
6460
|
+
"set",
|
|
6461
|
+
"unset",
|
|
6462
|
+
"export",
|
|
6463
|
+
"readonly",
|
|
6464
|
+
"typeset",
|
|
6465
|
+
"declare",
|
|
6466
|
+
"local",
|
|
6467
|
+
"eval",
|
|
6468
|
+
"exec",
|
|
6469
|
+
// --- Process / system inspection ---
|
|
6470
|
+
"htop",
|
|
6471
|
+
"top",
|
|
6472
|
+
"atop",
|
|
6473
|
+
"glances",
|
|
6474
|
+
"iotop",
|
|
6475
|
+
"nethogs",
|
|
6476
|
+
"iftop",
|
|
6477
|
+
"lsof",
|
|
6478
|
+
"strace",
|
|
6479
|
+
"ltrace",
|
|
6480
|
+
"sysstat",
|
|
6481
|
+
"vmstat",
|
|
6482
|
+
"iostat",
|
|
6483
|
+
"mpstat",
|
|
6484
|
+
"sar",
|
|
6485
|
+
"free",
|
|
6486
|
+
"df",
|
|
6487
|
+
"du",
|
|
6488
|
+
"mount",
|
|
6489
|
+
"umount",
|
|
6490
|
+
"lsblk",
|
|
6491
|
+
"blkid",
|
|
6492
|
+
"kill",
|
|
6493
|
+
"killall",
|
|
6494
|
+
"pkill",
|
|
6495
|
+
"pgrep",
|
|
6496
|
+
"pidof",
|
|
6497
|
+
"ps",
|
|
6498
|
+
"ps.exe",
|
|
6499
|
+
// --- Network inspection ---
|
|
6500
|
+
"ip",
|
|
6501
|
+
"ss",
|
|
6502
|
+
"route",
|
|
6503
|
+
"arp",
|
|
6504
|
+
"arping",
|
|
6505
|
+
"ping",
|
|
6506
|
+
"ping6",
|
|
6507
|
+
"hping3",
|
|
6508
|
+
"mtr",
|
|
6509
|
+
"tracepath",
|
|
6510
|
+
"tcpdump",
|
|
6511
|
+
"nmap",
|
|
6512
|
+
"netcat",
|
|
6513
|
+
"nc",
|
|
6514
|
+
"ncat",
|
|
6515
|
+
"socat",
|
|
6516
|
+
// --- Sync / backup ---
|
|
6517
|
+
"rclone",
|
|
6518
|
+
"restic",
|
|
6519
|
+
"borg",
|
|
6520
|
+
"duplicati",
|
|
6521
|
+
"duplicacy",
|
|
6522
|
+
"syncthing",
|
|
6523
|
+
"syncthing-cli",
|
|
6524
|
+
// --- Permissions / users / ACLs (POSIX) ---
|
|
6525
|
+
"useradd",
|
|
6526
|
+
"userdel",
|
|
6527
|
+
"usermod",
|
|
6528
|
+
"groupadd",
|
|
6529
|
+
"groupdel",
|
|
6530
|
+
"groupmod",
|
|
6531
|
+
"chown",
|
|
6532
|
+
"chmod",
|
|
6533
|
+
"chgrp",
|
|
6534
|
+
"getfacl",
|
|
6535
|
+
"setfacl",
|
|
6536
|
+
"setcap",
|
|
6537
|
+
"getcap",
|
|
6538
|
+
// --- Crypto / cert mgmt (extended) ---
|
|
6539
|
+
"certbot",
|
|
6540
|
+
"mkcert",
|
|
6541
|
+
"jarsigner",
|
|
6542
|
+
// --- Editors ---
|
|
6543
|
+
"subl",
|
|
6544
|
+
"code",
|
|
6545
|
+
"code-insiders",
|
|
6546
|
+
"cursor",
|
|
6547
|
+
"atom",
|
|
6548
|
+
"nano",
|
|
6549
|
+
"vim",
|
|
6550
|
+
"nvim",
|
|
6551
|
+
"vi",
|
|
6552
|
+
"emacs",
|
|
6553
|
+
"helix",
|
|
6554
|
+
"hx",
|
|
6555
|
+
"micro",
|
|
6556
|
+
"jed",
|
|
6557
|
+
"ed",
|
|
6558
|
+
"ex",
|
|
6559
|
+
"mg",
|
|
6560
|
+
// --- Terminal multiplexers ---
|
|
6561
|
+
"asciinema",
|
|
6562
|
+
"script",
|
|
6563
|
+
"scriptreplay",
|
|
6564
|
+
"expect",
|
|
6565
|
+
"screen",
|
|
6566
|
+
"tmux",
|
|
6567
|
+
"byobu",
|
|
6568
|
+
"dtach",
|
|
6569
|
+
"abduco",
|
|
6570
|
+
// --- Calculators / REPLs / scientific ---
|
|
6571
|
+
"bc",
|
|
6572
|
+
"dc",
|
|
6573
|
+
"calc",
|
|
6574
|
+
"qalc",
|
|
6575
|
+
"genius",
|
|
6576
|
+
"octave",
|
|
6577
|
+
"R",
|
|
6578
|
+
"Rscript",
|
|
6579
|
+
"julia",
|
|
6580
|
+
"irb",
|
|
6581
|
+
"pry",
|
|
6582
|
+
"ghci",
|
|
6583
|
+
"stack",
|
|
6584
|
+
"cabal",
|
|
6585
|
+
"ghc",
|
|
6586
|
+
// --- PHP / Lua / Perl / Ruby ecosystem (extended) ---
|
|
6587
|
+
"php8",
|
|
6588
|
+
"php7",
|
|
6589
|
+
"phpcs",
|
|
6590
|
+
"phpcbf",
|
|
6591
|
+
"phpmd",
|
|
6592
|
+
"phpstan",
|
|
6593
|
+
"psalm",
|
|
6594
|
+
"lua",
|
|
6595
|
+
"lua5.1",
|
|
6596
|
+
"lua5.2",
|
|
6597
|
+
"lua5.3",
|
|
6598
|
+
"lua5.4",
|
|
6599
|
+
"luarocks",
|
|
6600
|
+
"perl",
|
|
6601
|
+
"cpan",
|
|
6602
|
+
"prove",
|
|
6603
|
+
"plackup",
|
|
6604
|
+
"rake",
|
|
6605
|
+
"rspec",
|
|
6606
|
+
"jekyll",
|
|
6607
|
+
"node-gyp",
|
|
6608
|
+
"node-pre-gyp",
|
|
6609
|
+
// --- JS / TS toolchain (extended) ---
|
|
6610
|
+
"electron",
|
|
6611
|
+
"electron-builder",
|
|
6612
|
+
"electron-forge",
|
|
6613
|
+
"vite-preview",
|
|
6614
|
+
"swc",
|
|
6615
|
+
"swc-cli",
|
|
6616
|
+
"swcpack",
|
|
6617
|
+
"mocha",
|
|
6618
|
+
"chai",
|
|
6619
|
+
"jasmine",
|
|
6620
|
+
"puppeteer",
|
|
6621
|
+
"lighthouse",
|
|
6622
|
+
// --- Linters / formatters (extended) ---
|
|
6623
|
+
"tslint",
|
|
6624
|
+
"stylelint",
|
|
6625
|
+
"htmlhint",
|
|
6626
|
+
"jshint",
|
|
6627
|
+
"jslint",
|
|
6628
|
+
"jscs",
|
|
6629
|
+
// --- Document conversion ---
|
|
6630
|
+
"pandoc",
|
|
6631
|
+
"weasyprint",
|
|
6632
|
+
"wkhtmltopdf",
|
|
6633
|
+
"wkhtmltoimage",
|
|
6634
|
+
"prince",
|
|
6635
|
+
"mdp",
|
|
6636
|
+
"markdown",
|
|
6637
|
+
"multimarkdown",
|
|
6638
|
+
"cmark",
|
|
6639
|
+
"cmark-gfm",
|
|
6640
|
+
// --- Office / spreadsheet ---
|
|
6641
|
+
"soffice",
|
|
6642
|
+
"libreoffice",
|
|
6643
|
+
"unoconv",
|
|
6644
|
+
"abiword",
|
|
6645
|
+
"gnumeric",
|
|
6646
|
+
// --- Spell / grammar ---
|
|
6647
|
+
"aspell",
|
|
6648
|
+
"hunspell",
|
|
6649
|
+
"enchant",
|
|
6650
|
+
"languagetool",
|
|
6651
|
+
// --- Source-highlight / diff tools ---
|
|
6652
|
+
"delta",
|
|
6653
|
+
"bat",
|
|
6654
|
+
"ccat",
|
|
6655
|
+
"hl",
|
|
6656
|
+
"highlight",
|
|
6657
|
+
"source-highlight",
|
|
6658
|
+
"ansifilter",
|
|
6659
|
+
// --- Job schedulers ---
|
|
6660
|
+
"pueue",
|
|
6661
|
+
"task-spooler",
|
|
6662
|
+
"ts",
|
|
6663
|
+
"at",
|
|
6664
|
+
"atd",
|
|
6665
|
+
"anacron",
|
|
6666
|
+
"fcron",
|
|
6667
|
+
"cronie",
|
|
6668
|
+
"systemd-run",
|
|
6669
|
+
"systemd-cat",
|
|
6670
|
+
// --- Plotting / visualization ---
|
|
6671
|
+
"gnuplot",
|
|
6672
|
+
"gnuplot-nox",
|
|
6673
|
+
"veusz",
|
|
6674
|
+
"scidavis",
|
|
6675
|
+
"grace",
|
|
6676
|
+
"xmgrace",
|
|
6677
|
+
"labplot",
|
|
6678
|
+
// --- Security / recon (network + web) ---
|
|
6679
|
+
"masscan",
|
|
6680
|
+
"zmap",
|
|
6681
|
+
"rustscan",
|
|
6682
|
+
"amass",
|
|
6683
|
+
"subfinder",
|
|
6684
|
+
"httpx",
|
|
6685
|
+
"nuclei",
|
|
6686
|
+
"naabu",
|
|
6687
|
+
"katana",
|
|
6688
|
+
"dnsx",
|
|
6689
|
+
"assetfinder",
|
|
6690
|
+
"findomain",
|
|
6691
|
+
"gau",
|
|
6692
|
+
"waybackurls",
|
|
6693
|
+
"httprobe",
|
|
6694
|
+
"meg",
|
|
6695
|
+
"subjack",
|
|
6696
|
+
"sublert",
|
|
6697
|
+
"chaos"
|
|
6173
6698
|
]);
|
|
6174
6699
|
var allowedCommands = new Set(DEFAULT_ALLOWED_COMMANDS);
|
|
6175
6700
|
var normalizeCmd = (c) => c.trim();
|
|
@@ -6377,17 +6902,18 @@ function runCommand(cmd, args, cwd, timeout, signal, sessionId) {
|
|
|
6377
6902
|
const spool = createOutputSpool({ tool: `exec-${cmd}`, thresholdBytes: MAX_OUTPUT2 });
|
|
6378
6903
|
const resolved = resolveWin32Command(cmd);
|
|
6379
6904
|
const needsShell = isWin3 && (resolved.endsWith(".cmd") || resolved.endsWith(".bat"));
|
|
6380
|
-
const
|
|
6381
|
-
|
|
6905
|
+
const shim = needsShell ? buildWin32CmdShimInvocation(resolved, args) : null;
|
|
6906
|
+
const spawnCmd = shim?.command ?? resolved;
|
|
6907
|
+
const spawnArgs = shim?.args ?? args;
|
|
6382
6908
|
let child;
|
|
6383
6909
|
try {
|
|
6384
|
-
child = spawn(spawnCmd,
|
|
6910
|
+
child = spawn(spawnCmd, spawnArgs, {
|
|
6385
6911
|
cwd,
|
|
6386
6912
|
env: buildChildEnv(sessionId),
|
|
6387
6913
|
stdio: ["ignore", "pipe", "pipe"],
|
|
6388
6914
|
windowsHide: true,
|
|
6389
6915
|
...isWin3 ? {} : { signal },
|
|
6390
|
-
...
|
|
6916
|
+
...shim ? { windowsVerbatimArguments: shim.windowsVerbatimArguments } : {}
|
|
6391
6917
|
});
|
|
6392
6918
|
} catch (err) {
|
|
6393
6919
|
spool.finalize();
|
|
@@ -6482,6 +7008,7 @@ TD.addRule("stripDangerousElements", {
|
|
|
6482
7008
|
});
|
|
6483
7009
|
var MAX_BYTES = 131072;
|
|
6484
7010
|
var TIMEOUT_MS = 2e4;
|
|
7011
|
+
var nativeGlobalFetch = globalThis.fetch;
|
|
6485
7012
|
var ALLOW_PRIVATE = process.env["WRONGSTACK_FETCH_ALLOW_PRIVATE"] === "1";
|
|
6486
7013
|
if (ALLOW_PRIVATE && !process.env["CI"]) {
|
|
6487
7014
|
console.warn(
|
|
@@ -6531,6 +7058,9 @@ function getPinnedDispatcher() {
|
|
|
6531
7058
|
}
|
|
6532
7059
|
return pinnedAgent;
|
|
6533
7060
|
}
|
|
7061
|
+
function dispatcherFetch() {
|
|
7062
|
+
return globalThis.fetch === nativeGlobalFetch ? fetch : globalThis.fetch;
|
|
7063
|
+
}
|
|
6534
7064
|
var _beforeExitRegistered = false;
|
|
6535
7065
|
if (!_beforeExitRegistered) {
|
|
6536
7066
|
_beforeExitRegistered = true;
|
|
@@ -6566,7 +7096,7 @@ async function guardedFetch(url, maxRedirects, signal, headers = {
|
|
|
6566
7096
|
headers,
|
|
6567
7097
|
dispatcher: getPinnedDispatcher()
|
|
6568
7098
|
};
|
|
6569
|
-
const res = await
|
|
7099
|
+
const res = await dispatcherFetch()(currentUrl, init);
|
|
6570
7100
|
if (res.status < 300 || res.status > 399) {
|
|
6571
7101
|
return res;
|
|
6572
7102
|
}
|
|
@@ -6594,7 +7124,7 @@ var fetchTool = {
|
|
|
6594
7124
|
category: "Network",
|
|
6595
7125
|
description: "Fetch a URL and return its content. HTML pages are automatically converted to clean markdown. This tool has strong SSRF protections (private IPs, localhost, and cloud metadata endpoints are blocked by default).",
|
|
6596
7126
|
usageHint: "Use this when you need external information (documentation, API responses, web pages, etc.).\n\nSecurity notes:\n- Only HTTPS is allowed by default.\n- Internal/private networks are blocked unless explicitly enabled via environment variable.\n- Redirects are followed but re-validated at each hop.\n- Output is capped (128KB by default) to avoid flooding context.\nPrefer this over raw `bash curl` or `bash wget`.",
|
|
6597
|
-
permission: "
|
|
7127
|
+
permission: "auto",
|
|
6598
7128
|
mutating: false,
|
|
6599
7129
|
capabilities: ["net.outbound"],
|
|
6600
7130
|
icon: "web",
|
|
@@ -6834,7 +7364,7 @@ var formatTool = {
|
|
|
6834
7364
|
usageHint: "RUN REGULARLY:\n\n- Use on changed files before committing.\n- `check: true` verifies formatting without making changes (useful in CI-like flows).\nThis project has very consistent formatting expectations. Always ensure your changes are formatted.",
|
|
6835
7365
|
permission: "confirm",
|
|
6836
7366
|
mutating: true,
|
|
6837
|
-
capabilities: ["fs.write", "shell.
|
|
7367
|
+
capabilities: ["fs.write", "shell.restricted"],
|
|
6838
7368
|
icon: "code",
|
|
6839
7369
|
timeoutMs: 6e4,
|
|
6840
7370
|
inputSchema: {
|
|
@@ -8739,9 +9269,10 @@ function runOutdated(manager, args, cwd, signal) {
|
|
|
8739
9269
|
const MAX = 1e5;
|
|
8740
9270
|
const resolved = resolveWin32Command(manager);
|
|
8741
9271
|
const needsShell = process.platform === "win32" && (resolved.endsWith(".cmd") || resolved.endsWith(".bat"));
|
|
8742
|
-
const
|
|
8743
|
-
|
|
8744
|
-
const
|
|
9272
|
+
const shim = needsShell ? buildWin32CmdShimInvocation(resolved, args) : null;
|
|
9273
|
+
const spawnCmd = shim?.command ?? resolved;
|
|
9274
|
+
const spawnArgs = shim?.args ?? args;
|
|
9275
|
+
const child = spawn(spawnCmd, spawnArgs, { cwd, signal, env: buildChildEnv(), stdio: ["ignore", "pipe", "pipe"], windowsHide: true, ...shim ? { windowsVerbatimArguments: shim.windowsVerbatimArguments } : {} });
|
|
8745
9276
|
child.stdout?.on("data", (c) => {
|
|
8746
9277
|
if (stdout.length < MAX) stdout += c.toString();
|
|
8747
9278
|
});
|
|
@@ -9782,7 +10313,7 @@ var searchTool = {
|
|
|
9782
10313
|
category: "Search",
|
|
9783
10314
|
description: "Perform a web search and return results with title, URL, and snippet. Use this when you need up-to-date external information that is not in the local codebase. Results are cached (5 min TTL) and deduplicated by URL.",
|
|
9784
10315
|
usageHint: "Good for: API documentation, error messages, library usage examples, current best practices.\n\n- Prefer specific queries over very broad ones.\n- Results go through the guarded fetch system (same protections as the `fetch` tool).\n- Supports duckduckgo (default), google, and bing sources.\n- Set `skip_cache: true` to force a fresh search.\n- This is often better than the model trying to recall outdated knowledge.",
|
|
9785
|
-
permission: "
|
|
10316
|
+
permission: "auto",
|
|
9786
10317
|
mutating: false,
|
|
9787
10318
|
capabilities: ["net.outbound"],
|
|
9788
10319
|
icon: "search",
|
|
@@ -9845,15 +10376,15 @@ var searchTool = {
|
|
|
9845
10376
|
};
|
|
9846
10377
|
yield {
|
|
9847
10378
|
type: "partial_output",
|
|
9848
|
-
text: `${results.length} cached results from ${source}`,
|
|
9849
|
-
data: { count: results.length, cached: true }
|
|
10379
|
+
text: `${results.length} cached results from ${entry.source}`,
|
|
10380
|
+
data: { count: results.length, cached: true, source: entry.source }
|
|
9850
10381
|
};
|
|
9851
10382
|
yield {
|
|
9852
10383
|
type: "final",
|
|
9853
10384
|
output: {
|
|
9854
10385
|
query: input.query,
|
|
9855
10386
|
results: results.slice(0, num),
|
|
9856
|
-
source,
|
|
10387
|
+
source: entry.source,
|
|
9857
10388
|
truncated: results.length >= num,
|
|
9858
10389
|
cached: true
|
|
9859
10390
|
}
|
|
@@ -9867,6 +10398,7 @@ var searchTool = {
|
|
|
9867
10398
|
data: { source, query: input.query, cached: false }
|
|
9868
10399
|
};
|
|
9869
10400
|
let rawResults;
|
|
10401
|
+
let effectiveSource = source;
|
|
9870
10402
|
switch (source) {
|
|
9871
10403
|
case "duckduckgo":
|
|
9872
10404
|
rawResults = await duckduckgoSearch(input.query, num, opts.signal);
|
|
@@ -9883,24 +10415,24 @@ var searchTool = {
|
|
|
9883
10415
|
field: "source"
|
|
9884
10416
|
});
|
|
9885
10417
|
}
|
|
9886
|
-
|
|
9887
|
-
|
|
9888
|
-
|
|
9889
|
-
|
|
9890
|
-
|
|
9891
|
-
|
|
9892
|
-
|
|
9893
|
-
|
|
9894
|
-
|
|
10418
|
+
let ranked = rankSearchResults(rawResults, input.query);
|
|
10419
|
+
if (source !== "duckduckgo" && shouldFallbackToDuckDuckGo(ranked, input.query)) {
|
|
10420
|
+
yield {
|
|
10421
|
+
type: "log",
|
|
10422
|
+
text: `${source} returned no relevant static results; falling back to duckduckgo`,
|
|
10423
|
+
data: { source, fallback: "duckduckgo", query: input.query }
|
|
10424
|
+
};
|
|
10425
|
+
rawResults = await duckduckgoSearch(input.query, num, opts.signal);
|
|
10426
|
+
ranked = rankSearchResults(rawResults, input.query);
|
|
10427
|
+
effectiveSource = "duckduckgo";
|
|
9895
10428
|
}
|
|
9896
|
-
const ranked = scoreResults(deduped, input.query);
|
|
9897
10429
|
const finalResults = ranked.slice(0, num);
|
|
9898
|
-
cache.set(cacheKey, { results: ranked, timestamp: Date.now() });
|
|
10430
|
+
cache.set(cacheKey, { results: ranked, source: effectiveSource, timestamp: Date.now() });
|
|
9899
10431
|
pruneStaleCacheEntries();
|
|
9900
10432
|
yield {
|
|
9901
10433
|
type: "partial_output",
|
|
9902
|
-
text: `${finalResults.length} results from ${
|
|
9903
|
-
data: { count: finalResults.length, cached: false }
|
|
10434
|
+
text: `${finalResults.length} results from ${effectiveSource}`,
|
|
10435
|
+
data: { count: finalResults.length, cached: false, source: effectiveSource }
|
|
9904
10436
|
};
|
|
9905
10437
|
yield {
|
|
9906
10438
|
type: "final",
|
|
@@ -9911,7 +10443,7 @@ var searchTool = {
|
|
|
9911
10443
|
url: r.url,
|
|
9912
10444
|
snippet: r.snippet
|
|
9913
10445
|
})),
|
|
9914
|
-
source,
|
|
10446
|
+
source: effectiveSource,
|
|
9915
10447
|
truncated: finalResults.length >= num,
|
|
9916
10448
|
cached: false
|
|
9917
10449
|
}
|
|
@@ -9924,6 +10456,19 @@ function pruneStaleCacheEntries() {
|
|
|
9924
10456
|
if (entry.timestamp < cutoff) cache.delete(key);
|
|
9925
10457
|
}
|
|
9926
10458
|
}
|
|
10459
|
+
function rankSearchResults(results, query) {
|
|
10460
|
+
const seenUrls = /* @__PURE__ */ new Set();
|
|
10461
|
+
const deduped = [];
|
|
10462
|
+
for (const r of results) {
|
|
10463
|
+
const noQuery = r.url.split("?")[0] ?? r.url;
|
|
10464
|
+
const normalized = noQuery.split("#")[0] ?? r.url;
|
|
10465
|
+
if (!seenUrls.has(normalized) && r.url.startsWith("http")) {
|
|
10466
|
+
seenUrls.add(normalized);
|
|
10467
|
+
deduped.push(r);
|
|
10468
|
+
}
|
|
10469
|
+
}
|
|
10470
|
+
return scoreResults(deduped, query);
|
|
10471
|
+
}
|
|
9927
10472
|
function scoreResults(results, query) {
|
|
9928
10473
|
const terms = query.toLowerCase().split(/\s+/).filter((t) => t.length > 0);
|
|
9929
10474
|
return results.map((r) => {
|
|
@@ -9937,6 +10482,15 @@ function scoreResults(results, query) {
|
|
|
9937
10482
|
return { ...r, score };
|
|
9938
10483
|
}).sort((a, b) => b.score - a.score);
|
|
9939
10484
|
}
|
|
10485
|
+
function shouldFallbackToDuckDuckGo(results, query) {
|
|
10486
|
+
if (results.length === 0) return true;
|
|
10487
|
+
const terms = query.toLowerCase().split(/\s+/).filter((t) => t.length >= 3);
|
|
10488
|
+
if (terms.length === 0) return false;
|
|
10489
|
+
return !results.some((r) => {
|
|
10490
|
+
const haystack = `${r.title} ${r.url} ${r.snippet}`.toLowerCase();
|
|
10491
|
+
return terms.some((term) => haystack.includes(term));
|
|
10492
|
+
});
|
|
10493
|
+
}
|
|
9940
10494
|
async function duckduckgoSearch(query, num, signal) {
|
|
9941
10495
|
const encoded = encodeURIComponent(query);
|
|
9942
10496
|
const url = `https://lite.duckduckgo.com/lite/?q=${encoded}&kd=-1&kl=wt-wt`;
|
|
@@ -9961,14 +10515,19 @@ function takeFrom(iter, max) {
|
|
|
9961
10515
|
}
|
|
9962
10516
|
function parseDuckDuckGo(html, num) {
|
|
9963
10517
|
const results = [];
|
|
9964
|
-
const
|
|
9965
|
-
const
|
|
10518
|
+
const linkRegex = /<a\b([^>]*\bclass=(["'])[^"']*\bresult-link\b[^"']*\2[^>]*)>([\s\S]*?)<\/a>/gi;
|
|
10519
|
+
const snippetRegex = /<([a-z0-9]+)\b([^>]*\bclass=(["'])[^"']*\bresult-snippet\b[^"']*\3[^>]*)>([\s\S]*?)<\/\1>/gi;
|
|
9966
10520
|
const linkMatches = takeFrom(
|
|
9967
|
-
[...html.matchAll(
|
|
10521
|
+
[...html.matchAll(linkRegex)].map((m) => {
|
|
10522
|
+
const attrs = expectDefined(m[1]);
|
|
10523
|
+
const href = getHtmlAttr(attrs, "href");
|
|
10524
|
+
const title = stripTags(expectDefined(m[3]));
|
|
10525
|
+
return href && title ? { url: normalizeDuckDuckGoUrl(href), title } : void 0;
|
|
10526
|
+
}).filter((m) => m !== void 0),
|
|
9968
10527
|
num
|
|
9969
10528
|
);
|
|
9970
10529
|
const snippetMatches = takeFrom(
|
|
9971
|
-
[...html.matchAll(
|
|
10530
|
+
[...html.matchAll(snippetRegex)].filter((m) => m[4]).map((m) => stripTags(expectDefined(m[4]))),
|
|
9972
10531
|
num
|
|
9973
10532
|
);
|
|
9974
10533
|
for (let i = 0; i < linkMatches.length && i < num; i++) {
|
|
@@ -9984,6 +10543,24 @@ function parseDuckDuckGo(html, num) {
|
|
|
9984
10543
|
}
|
|
9985
10544
|
return results;
|
|
9986
10545
|
}
|
|
10546
|
+
function getHtmlAttr(attrs, name) {
|
|
10547
|
+
const quoted = new RegExp(`\\b${name}\\s*=\\s*(["'])(.*?)\\1`, "i").exec(attrs);
|
|
10548
|
+
if (quoted?.[2]) return decodeHtmlEntities(quoted[2]);
|
|
10549
|
+
const unquoted = new RegExp(`\\b${name}\\s*=\\s*([^\\s>]+)`, "i").exec(attrs);
|
|
10550
|
+
return unquoted?.[1] ? decodeHtmlEntities(unquoted[1]) : void 0;
|
|
10551
|
+
}
|
|
10552
|
+
function normalizeDuckDuckGoUrl(raw) {
|
|
10553
|
+
if (raw.startsWith("//")) return `https:${raw}`;
|
|
10554
|
+
if (!raw.startsWith("/")) return raw;
|
|
10555
|
+
if (!raw.startsWith("/l/")) return raw;
|
|
10556
|
+
try {
|
|
10557
|
+
const url = new URL(raw, "https://duckduckgo.com");
|
|
10558
|
+
const uddg = url.searchParams.get("uddg");
|
|
10559
|
+
return uddg?.startsWith("http") ? uddg : url.toString();
|
|
10560
|
+
} catch {
|
|
10561
|
+
return raw;
|
|
10562
|
+
}
|
|
10563
|
+
}
|
|
9987
10564
|
async function googleSearch(query, num, signal) {
|
|
9988
10565
|
const encoded = encodeURIComponent(query);
|
|
9989
10566
|
const url = `https://www.google.com/search?q=${encoded}&hl=en`;
|
|
@@ -10025,29 +10602,53 @@ async function bingSearch(query, num, signal) {
|
|
|
10025
10602
|
}
|
|
10026
10603
|
function parseBingResults(html, num) {
|
|
10027
10604
|
const results = [];
|
|
10028
|
-
const
|
|
10029
|
-
const
|
|
10030
|
-
const entries = takeFrom(
|
|
10031
|
-
|
|
10032
|
-
|
|
10033
|
-
|
|
10034
|
-
|
|
10035
|
-
|
|
10036
|
-
|
|
10037
|
-
|
|
10605
|
+
const blocks = [...html.matchAll(/<li\b[^>]*class=(["'])[^"']*\bb_algo\b[^"']*\1[^>]*>([\s\S]*?)(?=<li\b[^>]*class=(["'])[^"']*\bb_algo\b[^"']*\3|<\/ol>)/gi)].map((m) => expectDefined(m[2]));
|
|
10606
|
+
const candidates = blocks.length > 0 ? blocks : [html];
|
|
10607
|
+
const entries = takeFrom(candidates.flatMap((block) => {
|
|
10608
|
+
const titleMatch = /<h2[^>]*>\s*<a\b([^>]*)>([\s\S]*?)<\/a>\s*<\/h2>/i.exec(block);
|
|
10609
|
+
if (!titleMatch) return [];
|
|
10610
|
+
const href = getHtmlAttr(expectDefined(titleMatch[1]), "href");
|
|
10611
|
+
const title = stripTags(expectDefined(titleMatch[2]));
|
|
10612
|
+
if (!href || !title) return [];
|
|
10613
|
+
const snippetMatch = /<p\b[^>]*class=(["'])[^"']*\b(?:b_paractl|b_lineclamp\d*)\b[^"']*\1[^>]*>([\s\S]*?)<\/p>/i.exec(block) ?? /<p\b[^>]*>([\s\S]*?)<\/p>/i.exec(block);
|
|
10614
|
+
const snippet = snippetMatch ? stripTags(expectDefined(snippetMatch.at(-1))) : "";
|
|
10615
|
+
return [{ url: normalizeBingUrl(href), title, snippet, score: 1 }];
|
|
10616
|
+
}), num);
|
|
10038
10617
|
for (let i = 0; i < entries.length; i++) {
|
|
10039
10618
|
const entry = entries[i];
|
|
10040
10619
|
if (entry) {
|
|
10041
10620
|
results.push({
|
|
10042
10621
|
title: entry.title ?? "",
|
|
10043
10622
|
url: entry.url ?? "",
|
|
10044
|
-
snippet:
|
|
10623
|
+
snippet: entry.snippet ?? "",
|
|
10045
10624
|
score: 1
|
|
10046
10625
|
});
|
|
10047
10626
|
}
|
|
10048
10627
|
}
|
|
10049
10628
|
return results;
|
|
10050
10629
|
}
|
|
10630
|
+
function normalizeBingUrl(raw) {
|
|
10631
|
+
try {
|
|
10632
|
+
const url = new URL(raw);
|
|
10633
|
+
if (url.hostname.endsWith("bing.com") && url.pathname.startsWith("/ck/")) {
|
|
10634
|
+
const encoded = url.searchParams.get("u");
|
|
10635
|
+
const decoded = decodeBingTarget(encoded);
|
|
10636
|
+
if (decoded?.startsWith("http")) return decoded;
|
|
10637
|
+
}
|
|
10638
|
+
} catch {
|
|
10639
|
+
}
|
|
10640
|
+
return raw;
|
|
10641
|
+
}
|
|
10642
|
+
function decodeBingTarget(encoded) {
|
|
10643
|
+
if (!encoded) return void 0;
|
|
10644
|
+
const payload = encoded.startsWith("a1") ? encoded.slice(2) : encoded;
|
|
10645
|
+
try {
|
|
10646
|
+
const padded = payload.replace(/-/g, "+").replace(/_/g, "/").padEnd(Math.ceil(payload.length / 4) * 4, "=");
|
|
10647
|
+
return Buffer.from(padded, "base64").toString("utf8");
|
|
10648
|
+
} catch {
|
|
10649
|
+
return void 0;
|
|
10650
|
+
}
|
|
10651
|
+
}
|
|
10051
10652
|
async function fetchWithTimeout(url, signal, timeoutMs) {
|
|
10052
10653
|
const controller = new AbortController();
|
|
10053
10654
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
@@ -10075,7 +10676,10 @@ function anySignal(...signals) {
|
|
|
10075
10676
|
return AbortSignal.any(signals);
|
|
10076
10677
|
}
|
|
10077
10678
|
function stripTags(html) {
|
|
10078
|
-
return html.replace(/<[^>]+>/g, "")
|
|
10679
|
+
return decodeHtmlEntities(html.replace(/<[^>]+>/g, "")).trim();
|
|
10680
|
+
}
|
|
10681
|
+
function decodeHtmlEntities(text) {
|
|
10682
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'");
|
|
10079
10683
|
}
|
|
10080
10684
|
var setWorkingDirTool = {
|
|
10081
10685
|
name: "set_working_dir",
|