@getmarrow/mcp 3.9.108 → 3.9.109

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.
Files changed (93) hide show
  1. package/README.md +16 -1
  2. package/dist/cli.js +26 -1
  3. package/dist/cli.js.map +1 -1
  4. package/dist/control-notice.d.ts +13 -0
  5. package/dist/control-notice.d.ts.map +1 -0
  6. package/dist/control-notice.js +76 -0
  7. package/dist/control-notice.js.map +1 -0
  8. package/dist/control-routes.d.ts +10 -0
  9. package/dist/control-routes.d.ts.map +1 -0
  10. package/dist/control-routes.js +81 -0
  11. package/dist/control-routes.js.map +1 -0
  12. package/dist/hook-context.d.ts.map +1 -1
  13. package/dist/hook-context.js +34 -11
  14. package/dist/hook-context.js.map +1 -1
  15. package/dist/hook-contract.d.ts +2 -2
  16. package/dist/hook-contract.js +1 -1
  17. package/dist/hook-pre-action.d.ts +2 -0
  18. package/dist/hook-pre-action.d.ts.map +1 -1
  19. package/dist/hook-pre-action.js +86 -20
  20. package/dist/hook-pre-action.js.map +1 -1
  21. package/dist/hook-session.d.ts.map +1 -1
  22. package/dist/hook-session.js +12 -7
  23. package/dist/hook-session.js.map +1 -1
  24. package/dist/hook-tool-policy.d.ts +1 -1
  25. package/dist/hook-tool-policy.d.ts.map +1 -1
  26. package/dist/hook.d.ts.map +1 -1
  27. package/dist/hook.js +19 -14
  28. package/dist/hook.js.map +1 -1
  29. package/dist/ipv4-first.d.ts +7 -0
  30. package/dist/ipv4-first.d.ts.map +1 -0
  31. package/dist/ipv4-first.js +60 -0
  32. package/dist/ipv4-first.js.map +1 -0
  33. package/dist/key-class.d.ts +16 -0
  34. package/dist/key-class.d.ts.map +1 -0
  35. package/dist/key-class.js +37 -0
  36. package/dist/key-class.js.map +1 -0
  37. package/dist/keyless-notice.d.ts +10 -0
  38. package/dist/keyless-notice.d.ts.map +1 -0
  39. package/dist/keyless-notice.js +47 -0
  40. package/dist/keyless-notice.js.map +1 -0
  41. package/dist/normalized-action.d.ts +4 -0
  42. package/dist/normalized-action.d.ts.map +1 -1
  43. package/dist/normalized-action.js +60 -27
  44. package/dist/normalized-action.js.map +1 -1
  45. package/dist/owner-bypass.d.ts +9 -0
  46. package/dist/owner-bypass.d.ts.map +1 -0
  47. package/dist/owner-bypass.js +79 -0
  48. package/dist/owner-bypass.js.map +1 -0
  49. package/dist/redact.d.ts +5 -0
  50. package/dist/redact.d.ts.map +1 -1
  51. package/dist/redact.js +61 -9
  52. package/dist/redact.js.map +1 -1
  53. package/dist/seatbelt/hook.d.ts +3 -1
  54. package/dist/seatbelt/hook.d.ts.map +1 -1
  55. package/dist/seatbelt/hook.js +7 -3
  56. package/dist/seatbelt/hook.js.map +1 -1
  57. package/dist/seatbelt/mapper.d.ts.map +1 -1
  58. package/dist/seatbelt/mapper.js +849 -12
  59. package/dist/seatbelt/mapper.js.map +1 -1
  60. package/dist/seatbelt/patch-text.d.ts +49 -0
  61. package/dist/seatbelt/patch-text.d.ts.map +1 -0
  62. package/dist/seatbelt/patch-text.js +376 -0
  63. package/dist/seatbelt/patch-text.js.map +1 -0
  64. package/dist/seatbelt/tables.d.ts +66 -0
  65. package/dist/seatbelt/tables.d.ts.map +1 -1
  66. package/dist/seatbelt/tables.js +467 -3
  67. package/dist/seatbelt/tables.js.map +1 -1
  68. package/dist/seatbelt/win-protected.d.ts +52 -0
  69. package/dist/seatbelt/win-protected.d.ts.map +1 -0
  70. package/dist/seatbelt/win-protected.js +1279 -0
  71. package/dist/seatbelt/win-protected.js.map +1 -0
  72. package/dist/self-protect.d.ts +18 -0
  73. package/dist/self-protect.d.ts.map +1 -0
  74. package/dist/self-protect.js +185 -0
  75. package/dist/self-protect.js.map +1 -0
  76. package/dist/session-id.d.ts +2 -0
  77. package/dist/session-id.d.ts.map +1 -0
  78. package/dist/session-id.js +32 -0
  79. package/dist/session-id.js.map +1 -0
  80. package/dist/session-loop-guard.d.ts +7 -0
  81. package/dist/session-loop-guard.d.ts.map +1 -1
  82. package/dist/session-loop-guard.js +168 -1
  83. package/dist/session-loop-guard.js.map +1 -1
  84. package/dist/session-marker.d.ts +7 -0
  85. package/dist/session-marker.d.ts.map +1 -0
  86. package/dist/session-marker.js +42 -0
  87. package/dist/session-marker.js.map +1 -0
  88. package/dist/win-private-state.d.ts +117 -0
  89. package/dist/win-private-state.d.ts.map +1 -0
  90. package/dist/win-private-state.js +544 -0
  91. package/dist/win-private-state.js.map +1 -0
  92. package/package.json +1 -1
  93. package/server.json +2 -2
@@ -3,12 +3,24 @@
3
3
  // Compiled into the package on purpose: no local file can extend or relax them (spec §2.1.7).
4
4
  Object.defineProperty(exports, "__esModule", { value: true });
5
5
  exports.CWD_KEYS = exports.ENV_KEYS = exports.TERMINAL_TEXT_KEYS = exports.GH_HEAD_SAFE = exports.HEAD_CHANGERS = exports.HEAD_RUNNERS = exports.BUILD_TOOLS = exports.TERMINAL_SEGMENTS = exports.STDIN_KEYS = exports.CODE_KEYS = exports.ARGV_STRICT = exports.ARGV_SEGMENTS = exports.ARGV_KEYS = exports.COMMAND_KEYS = exports.FILE_TOOL_NAMES = exports.SHELL_TOOL_NAMES = exports.GIT_CONFIG_ENV_FILES = exports.GIT_CONFIG_INCLUDE = exports.GIT_EXEC_CONFIG = exports.NPM_BOOL_FLAGS = exports.NPM_VALUE_FLAGS = exports.NPM_ALIASES = exports.NPM_COMMANDS = exports.EVAL_PRODUCERS = exports.NON_SCRIPT_NAMES = exports.SCRIPT_SUFFIX = exports.INERT_PROGRAMS = exports.KNOWN_COMMANDS = exports.NAME_TRIPWIRE = exports.TRIPWIRE = exports.GIT_PUSH_RISKY_LONG = exports.GIT_PUSH_LONG = exports.GIT_BUILTINS = exports.PACKAGE_BINS = exports.MARROW_OWNER_SUBS = exports.INTERPRETER_EXEC = exports.INTERPRETERS = exports.SHELLS = exports.GIT_S4_EXEMPT_SUBS = exports.S4_EXEMPT_PROGRAMS = exports.PROD_ENV = exports.SECRET_VAR = exports.SSH_PUBLIC = exports.ENV_TEMPLATE_SUFFIX = exports.KEY_FIXTURE_SEGMENTS = exports.KEY_EXTENSIONS = exports.SECRET_PATTERNS = exports.PRESENT_SECRET_PATTERNS = exports.LIMITS = exports.SEATBELT_RULES_VERSION = void 0;
6
- exports.LANGUAGE_KEYS = exports.OPTION_OBJECT_KEYS = void 0;
6
+ exports.PS_BLOCK_WORDS = exports.PS_OUTPUT_CMDLETS = exports.PS_KEYWORDS = exports.PS_EXECUTION_POLICIES = exports.PS_SNIFF = exports.PS_BLOCK_CALL = exports.PS_DYNAMIC_AMP = exports.PS_DYNAMIC_CALL = exports.PS_EVAL_WORDS = exports.WIN_CMDLET_WORD = exports.WIN_DELETE_WORDS = exports.WIN_SHELL_DELETE_VERBS = exports.WIN_DELETE_VERBS = exports.A3_REASONS = exports.LANGUAGE_KEYS = exports.OPTION_OBJECT_KEYS = void 0;
7
7
  exports.secretSamples = secretSamples;
8
8
  exports.interpreterTreeDelete = interpreterTreeDelete;
9
9
  exports.interpreterDecodeToken = interpreterDecodeToken;
10
10
  exports.commandLikeKey = commandLikeKey;
11
11
  exports.codeLikeKey = codeLikeKey;
12
+ exports.windowsProgramName = windowsProgramName;
13
+ exports.windowsDeleteStops = windowsDeleteStops;
14
+ exports.windowsDeleteStopsFrom = windowsDeleteStopsFrom;
15
+ exports.dotNetTreeDelete = dotNetTreeDelete;
16
+ exports.psOption = psOption;
17
+ exports.decodeEncodedCommand = decodeEncodedCommand;
18
+ exports.psNormalize = psNormalize;
19
+ exports.psClean = psClean;
20
+ exports.psFlatten = psFlatten;
21
+ exports.psDynamicCode = psDynamicCode;
22
+ exports.psDefaultParameters = psDefaultParameters;
23
+ exports.psStatements = psStatements;
12
24
  exports.SEATBELT_RULES_VERSION = 'marrow.seatbelt.rules.v1';
13
25
  // Budgets. A command that exceeds ANY budget stops (never passes): padding, deep nesting, wide
14
26
  // fan-out and slow repositories must not turn into "pass" (audit F3, F10).
@@ -18,6 +30,8 @@ exports.LIMITS = Object.freeze({
18
30
  maxSegments: 256,
19
31
  maxDepth: 6,
20
32
  maxScriptBytes: 64 * 1024,
33
+ // WK-5: the largest patch file the mapper reads for `patch`, `git apply` and `git am`; a bigger one is an unknown write.
34
+ maxPatchBytes: 1024 * 1024,
21
35
  maxPackageJsonBytes: 256 * 1024,
22
36
  maxConfigBytes: 1024 * 1024,
23
37
  maxAliasExpansions: 5,
@@ -40,6 +54,11 @@ exports.LIMITS = Object.freeze({
40
54
  maxWords: 1024,
41
55
  maxBraceChars: 1024,
42
56
  maxParseCost: 24_000_000,
57
+ // A3 (Windows hotfix): nested PowerShell / cmd texts (pwsh -c, cmd /c, iex, Start-Process, decoded
58
+ // -EncodedCommand) stop beyond this many levels, and a base64 -EncodedCommand value longer than this many
59
+ // characters is not decoded: it stops as unreadable. 32767 is the longest command line Windows can start.
60
+ maxPsDepth: 4,
61
+ maxEncodedChars: 32_767,
43
62
  });
44
63
  // S4 secret paths: one table with the keyed policy (src/secret-paths.ts).
45
64
  var secret_paths_1 = require("../secret-paths");
@@ -183,7 +202,7 @@ exports.KNOWN_COMMANDS = new Set([
183
202
  'builtin', 'exec', 'stdbuf', 'ionice', 'chrt', 'taskset', 'setsid', 'unbuffer', 'caffeinate', 'retry', 'flock', 'xargs', 'parallel',
184
203
  'watch', 'ssh', 'git', 'gh', 'npm', 'pnpm', 'yarn', 'bun', 'npx', 'bunx', 'corepack', 'make', 'gmake', 'rm', 'rimraf', 'rmdir', 'find',
185
204
  'rsync', 'shred', 'dd', 'docker', 'podman', 'kubectl', 'helm', 'marrow', 'marrow-install', 'claude', 'apply_patch', 'applypatch',
186
- 'trap', 'script', 'cpio', 'pax', 'read', 'mapfile', 'readarray', 'getopts', 'busybox', 'toybox', 'concurrently', 'npm-run-all', 'npm-run-all2', 'run-s', 'run-p', 'railway',
205
+ 'patch', 'trap', 'script', 'cpio', 'pax', 'read', 'mapfile', 'readarray', 'getopts', 'busybox', 'toybox', 'concurrently', 'npm-run-all', 'npm-run-all2', 'run-s', 'run-p', 'railway',
187
206
  // deploy tools
188
207
  'wrangler', 'vercel', 'netlify', 'ntl', 'fly', 'flyctl', 'firebase', 'heroku', 'gcloud', 'sst', 'serverless', 'sls', 'cdk', 'terraform',
189
208
  'tofu', 'terragrunt', 'pulumi', 'eb', 'aws', 'az',
@@ -197,6 +216,8 @@ exports.KNOWN_COMMANDS = new Set([
197
216
  'sh', 'bash', 'zsh', 'dash', 'ksh', 'fish', 'ash', 'mksh', 'yash', 'rbash', 'csh', 'tcsh',
198
217
  'python', 'python2', 'python3', 'node', 'nodejs', 'ruby', 'perl', 'php', 'deno', 'lua', 'pwsh', 'powershell', 'osascript', 'tclsh',
199
218
  'irb', 'ipython', 'awk', 'gawk', 'mawk', 'nawk', 'sed', 'gsed', 'tar', 'gtar', 'bsdtar', 'ps',
219
+ // A3: the Windows command interpreter (its /c text is read as PowerShell / cmd text)
220
+ 'cmd',
200
221
  ]);
201
222
  // Programs whose arguments are text, patterns or paths and are never run. Their argv is not scanned
202
223
  // for a command. A program with an exec-capable flag (find -exec, xargs, tar --to-command) is not
@@ -212,7 +233,7 @@ exports.INERT_PROGRAMS = new Set([
212
233
  'exit', 'break', 'continue', 'shift', 'read', 'getopts', 'hash', 'rev', 'tac', 'sed', 'gsed', 'zip', 'unzip', 'gzip',
213
234
  'gunzip', 'bzip2', 'xz', 'zstd', 'tar', 'truncate', 'unlink', 'mktemp', 'install', 'ssh-add', 'ssh-keygen',
214
235
  'ssh-keyscan', 'openssl', 'gpg', 'gpg2', 'tree', 'bat', 'fd', 'exa', 'eza', 'lsof', 'netstat', 'ss', 'ip', 'ifconfig', 'top', 'htop',
215
- 'nproc', 'getconf', 'locale', 'cal', 'bc', 'dc', 'zcat', 'bzcat', 'xzcat', 'diff3', 'patch', 'colordiff',
236
+ 'nproc', 'getconf', 'locale', 'cal', 'bc', 'dc', 'zcat', 'bzcat', 'xzcat', 'diff3', 'colordiff',
216
237
  'git-lfs', 'tsc', 'eslint', 'prettier', 'jest', 'vitest', 'mocha',
217
238
  ]);
218
239
  // Executable-looking argument paths worth reading as a script when an unknown program is given one.
@@ -352,4 +373,447 @@ exports.CWD_KEYS = new Set(['cwd', 'workdir', 'working_dir', 'working_directory'
352
373
  exports.OPTION_OBJECT_KEYS = new Set(['options', 'opts', 'context', 'session', 'execution', 'spawn_options', 'exec_options', 'config', 'settings', 'env_options', 'process', 'run_options']);
353
374
  // A sibling that names the language of a code field.
354
375
  exports.LANGUAGE_KEYS = new Set(['runtime', 'language', 'lang', 'interpreter', 'engine', 'kind', 'type', 'shell', 'mode']);
376
+ // ---------------------------------------------------------------------------------------------
377
+ // A3: Windows shell deletes (PowerShell and cmd). Everything below only ADDS stops.
378
+ // The reasons A3 adds. When one of them is the first hit of the decision's category, the decision's rule is
379
+ // `<category>.<reason>` (S5.windows_shell_delete_unparsed, Sx.encoded_powershell_unreadable,
380
+ // Sx.powershell_script_unreadable, Sx.dynamic_powershell_code); every one matches the hook's CODE pattern.
381
+ exports.A3_REASONS = new Set(['windows_shell_delete_unparsed', 'encoded_powershell_unreadable',
382
+ 'powershell_script_unreadable', 'dynamic_powershell_code']);
383
+ // Delete verbs in every text. rm and rmdir keep their POSIX handlers: they count only in PowerShell / cmd text
384
+ // and on native Windows.
385
+ exports.WIN_DELETE_VERBS = new Set(['remove-item', 'ri', 'del', 'erase', 'rd']);
386
+ exports.WIN_SHELL_DELETE_VERBS = new Set(['rm', 'rmdir']);
387
+ /** A program word as Windows names it: both separators split the path, a .exe/.cmd/.bat/.com suffix goes, case folds. */
388
+ function windowsProgramName(text) {
389
+ const base = text.replace(/[\\/]+$/, '').split(/[\\/]/).pop() || '';
390
+ return base.replace(/\.(?:exe|cmd|bat|com)$/i, '').toLowerCase();
391
+ }
392
+ // Remove-Item parameters that cannot recurse. A prefix counts only when it names exactly one of them (`-f` is
393
+ // Filter or Force, so it is unknown). `ea` is the ErrorAction alias.
394
+ const PS_DELETE_OPTIONS = ['path', 'literalpath', 'filter', 'include', 'exclude', 'force', 'whatif', 'confirm', 'erroraction', 'verbose', 'debug'];
395
+ function deleteOptionStops(word) {
396
+ if (word[0] === '/') {
397
+ // cmd switches, alone or run together (/s/q): /q /f /p /a[:attrs] are fine; /s (recursion) and everything else stops.
398
+ for (const part of word.slice(1).split('/'))
399
+ if (!/^(?:[qfp]|a(?::[a-z-]{0,12})?)$/i.test(part))
400
+ return true;
401
+ return false;
402
+ }
403
+ if (word.startsWith('--'))
404
+ return true; // GNU long options (--recursive and every other one)
405
+ const colon = word.indexOf(':');
406
+ const name = (colon > 0 ? word.slice(1, colon) : word.slice(1)).toLowerCase();
407
+ const value = colon > 0 ? word.slice(colon + 1) : null;
408
+ if (name === '' || name.startsWith('r'))
409
+ return true; // -r, -rec, -Recurse, -Recurse:$true and a typo of them
410
+ if (name !== 'ea' && PS_DELETE_OPTIONS.filter((k) => k.startsWith(name)).length !== 1)
411
+ return true;
412
+ if (value !== null && value.includes('$') && !/^\$(?:true|false)$/i.test(value))
413
+ return true;
414
+ return false;
415
+ }
416
+ /**
417
+ * A3 rules (i) to (iv) for one command whose program is a delete verb. `words` are its arguments (null = not a literal:
418
+ * a variable, a substitution, several values). True = stop: pipeline input, a recursion marker, an option outside the
419
+ * known non-recursive set, or an argument that is not a plain literal (a `$` expression, a splat, a backtick, `%VAR%`,
420
+ * `!VAR!`, a script block).
421
+ */
422
+ function windowsDeleteStops(words, piped) {
423
+ if (piped)
424
+ return true;
425
+ let targets = 0;
426
+ for (const raw of words) {
427
+ const k = deleteWordClass(raw);
428
+ if (k === DELETE_WORD_STOPS)
429
+ return true;
430
+ if (k === DELETE_WORD_TARGET)
431
+ targets += 1;
432
+ }
433
+ // A delete with no target at all gets its target from somewhere the text does not show (a splat, a default parameter value).
434
+ return targets === 0;
435
+ }
436
+ // How one argument of a delete verb counts: nothing (a blank piece, a safe option), a target, or a stop on its own.
437
+ const DELETE_WORD_SKIP = 0;
438
+ const DELETE_WORD_TARGET = 1;
439
+ const DELETE_WORD_STOPS = 2;
440
+ function deleteWordClass(raw) {
441
+ if (raw === null)
442
+ return DELETE_WORD_STOPS;
443
+ const t = psNormalize(raw);
444
+ if (t === '' || t === '}')
445
+ return DELETE_WORD_SKIP; // a lone `}` is the end of a script block that bash read as a word
446
+ if (/[`%!{}]/.test(t) || t[0] === '@')
447
+ return DELETE_WORD_STOPS;
448
+ if (t[0] === '-' || t[0] === '/')
449
+ return deleteOptionStops(t) ? DELETE_WORD_STOPS : DELETE_WORD_SKIP;
450
+ if (t.includes('$'))
451
+ return DELETE_WORD_STOPS;
452
+ return DELETE_WORD_TARGET;
453
+ }
454
+ /**
455
+ * `windowsDeleteStops(words.slice(p + 1), piped && p === 0)` for every p, from one pass over `words`. A suffix stops when
456
+ * it holds a word that stops on its own or no target at all, so the last word of each kind answers every p. The result is
457
+ * a function of p; each call is constant time.
458
+ */
459
+ function windowsDeleteStopsFrom(words, pipedFirst) {
460
+ let lastStop = -1;
461
+ let lastTarget = -1;
462
+ for (let i = 0; i < words.length; i += 1) {
463
+ const k = deleteWordClass(words[i]);
464
+ if (k === DELETE_WORD_STOPS)
465
+ lastStop = i;
466
+ else if (k === DELETE_WORD_TARGET)
467
+ lastTarget = i;
468
+ }
469
+ return (p) => (pipedFirst && p === 0) || lastStop > p || lastTarget <= p;
470
+ }
471
+ // A delete verb anywhere in text bash could not read (rule vi). A verb is a whole word that does not continue a name,
472
+ // a variable or a path component (the text had its backticks and carets removed first).
473
+ exports.WIN_DELETE_WORDS = /(?<![\w.$-])(?:remove-item|ri|rm|rmdir|rd|del|erase)(?![\w-])/i;
474
+ // Outside PowerShell / cmd text only the unambiguous cmdlet name counts, and only as the start of a statement, when bash
475
+ // cannot read the text (a commit message that quotes it is not a command).
476
+ exports.WIN_CMDLET_WORD = /(?:^|[\n;|&(]|&&|\|\|)[ \t]*(?:remove-item)(?![\w-])/i;
477
+ exports.PS_EVAL_WORDS = /(?:^|[\n;|(]|&&|\|\|)[ \t]*(?:iex|invoke-expression)(?![\w-])/i;
478
+ // `& $cmd`, `& (expr)`, `& @args` at the start of a statement (and `. $x` in PowerShell text): code that is not a literal.
479
+ exports.PS_DYNAMIC_CALL = /(?:^|[\n;|(]|&&|\|\|)[ \t]*(?:&[ \t]*(?:[$(@]|"[^"\n]{0,300}\$)|\.[ \t]+(?:[$(@]|"[^"\n]{0,300}\$))/;
480
+ exports.PS_DYNAMIC_AMP = /(?:^|[\n;|(]|&&|\|\|)[ \t]*&[ \t]*(?:[$(@]|"[^"\n]{0,300}\$)/;
481
+ // A script block called with `&` or `.` at the start of a statement: PowerShell, never bash.
482
+ exports.PS_BLOCK_CALL = /(?:^|[\n;|(]|&&|\|\|)[ \t]*[&.][ \t]*\{/;
483
+ // Plain shell text that looks like PowerShell with script blocks: its blocks are read as statements too (a probe).
484
+ exports.PS_SNIFF = /remove-item|foreach-object|where-object|invoke-command|-scriptblock|get-childitem|%[ \t]*\{|(?:^|[\n;&|(])[ \t]*(?:rd|rmdir|del|erase|cmd)[/,;=]|(?:^|[\n;|(]|&&|\|\|)[ \t]*[&.][ \t]*\{/i;
485
+ /**
486
+ * .NET and COM deletes of a whole tree (rule v). The text is lower-cased with all white space removed, so padding and
487
+ * spacing change nothing. `strict` (PowerShell / cmd text) also stops `.Delete(<anything but $false/0/false>)`; outside
488
+ * it only the PowerShell-only forms count, so a C# search for `.Delete(true)` keeps its answer.
489
+ */
490
+ function dotNetTreeDelete(text, strict) {
491
+ const t = text.toLowerCase().replace(/\s+/g, '');
492
+ if (t.includes('directory]::delete') || t.includes('::deletedirectory') || t.includes('deletefolder('))
493
+ return true;
494
+ // A member name that is built at run time (`[IO.Directory]::('De'+'lete')`, `[IO.Directory]::$m`).
495
+ if (t.includes('directory]::(') || t.includes('directory]::$'))
496
+ return true;
497
+ if (/\.delete\(\$(?!false)/.test(t))
498
+ return true;
499
+ if (!strict)
500
+ return false;
501
+ // Any delete call next to a walk of the tree in the same text (the analog of `find -delete`), and FileSystemObject.DeleteFile.
502
+ if (t.includes('.deletefile(') || t.includes('.deletefile"') || t.includes(".deletefile'") || t.includes('.deletefolder"') || t.includes(".deletefolder'"))
503
+ return true; // VBScript may leave out the parentheses
504
+ if ((t.includes('.delete(') || t.includes('::delete(')) && ['get-childitem', 'gci', '-recurse', 'foreach', '|%', '%{', 'while(', 'for('].some((w) => t.includes(w)))
505
+ return true;
506
+ if (t.includes('::delete') && t.includes('directory'))
507
+ return true;
508
+ if (t.includes('directory') && t.includes('getmethod') && t.includes('delete'))
509
+ return true;
510
+ for (const m of t.matchAll(/\.delete\(([^)]{0,16})/g))
511
+ if (m[1] !== '' && !/^(?:\$false|0|false)$/.test(m[1]))
512
+ return true;
513
+ return false;
514
+ }
515
+ const PS_VALUE_OPTIONS = ['windowstyle', 'executionpolicy', 'inputformat', 'outputformat', 'version', 'workingdirectory', 'wd',
516
+ 'configurationname', 'settingsfile', 'custompipename'];
517
+ function psOption(raw) {
518
+ const word = psNormalize(raw);
519
+ if (word.length < 2 || (word[0] !== '-' && word[0] !== '/'))
520
+ return null;
521
+ const colon = word.indexOf(':');
522
+ const name = (colon > 0 ? word.slice(1, colon) : word.slice(1)).toLowerCase();
523
+ const attached = colon > 0 ? word.slice(colon + 1) : null;
524
+ if (!/^[a-z?]+$/.test(name))
525
+ return null;
526
+ let kind = 'flag';
527
+ // Every -c* parameter carries code (-Command, -CommandWithArgs, -cwa, any prefix); -conf* and -cu* (pipe name) take a value.
528
+ if (name[0] === 'c' && !name.startsWith('conf') && !name.startsWith('cu'))
529
+ kind = 'command';
530
+ else if (name === 'ep')
531
+ kind = 'value';
532
+ else if (name[0] === 'e' && !name.startsWith('ex'))
533
+ kind = 'encoded';
534
+ else if ('file'.startsWith(name))
535
+ kind = 'file';
536
+ else if (PS_VALUE_OPTIONS.some((v) => v.startsWith(name)))
537
+ kind = 'value';
538
+ return { kind, name, attached };
539
+ }
540
+ exports.PS_EXECUTION_POLICIES = /^(?:bypass|unrestricted|remotesigned|allsigned|restricted|undefined|default)$/i;
541
+ /** The text of a base64 UTF-16LE -EncodedCommand value, or null when it cannot be read (the caller then stops). */
542
+ function decodeEncodedCommand(value) {
543
+ const compact = value.replace(/\s+/g, '');
544
+ if (compact.length === 0 || compact.length > exports.LIMITS.maxEncodedChars)
545
+ return null;
546
+ if (!/^[A-Za-z0-9+/]+={0,2}$/.test(compact) || compact.length % 4 !== 0)
547
+ return null;
548
+ let bytes;
549
+ try {
550
+ bytes = Buffer.from(compact, 'base64');
551
+ }
552
+ catch {
553
+ return null;
554
+ }
555
+ if (bytes.length === 0 || bytes.length % 2 !== 0)
556
+ return null;
557
+ const text = bytes.toString('utf16le');
558
+ // NUL and other control characters (tab, CR and LF are fine), and the replacement character an invalid pair leaves.
559
+ if (/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f�￾￿]/.test(text))
560
+ return null;
561
+ return text;
562
+ }
563
+ /** PowerShell reads U+2013, U+2014 and U+2015 as the parameter dash and the smart quotes as quotes: the same text with plain ones. */
564
+ function psNormalize(text) {
565
+ // PowerShell also reads a vertical tab, a form feed, U+00A0, U+0085 and the Unicode space separators as blanks (bash does not), and
566
+ // U+2028 / U+2029 as line ends: every one of them becomes a plain blank or line break first.
567
+ return text.replace(/[\u2028\u2029]/g, '\n').replace(/[\u000b\u000c\u00a0\u0085\u1680\u2000-\u200a\u202f\u205f\u3000]/g, ' ').replace(/[\u2013\u2014\u2015]/g, '-').replace(/[\u2018\u2019\u201a\u201b]/g, '\'').replace(/[\u201c\u201d\u201e]/g, '"');
568
+ }
569
+ /** PowerShell / cmd text with its escapes taken out: a backtick (PowerShell) or caret (cmd) before a line break joins the lines, any other one goes; dashes and quotes plain. */
570
+ function psClean(text) {
571
+ return psNormalize(text.replace(/[`^]\r?\n/g, ' ').replace(/[`^]/g, ''));
572
+ }
573
+ /**
574
+ * The same PowerShell / cmd text with its block braces turned into line breaks and its call operators dropped, so
575
+ * `& { ri -r x }`, `Invoke-Command -ScriptBlock { rd /s x }` and `% { rm $_ }` show their bodies as commands. Quotes and
576
+ * `${name}` are left alone. A reading for the delete checks only; it never replaces the text's own reading.
577
+ */
578
+ function psFlatten(text) {
579
+ let out = '';
580
+ let quote = null;
581
+ let braced = false;
582
+ for (let i = 0; i < text.length; i += 1) {
583
+ const ch = text[i];
584
+ if (quote !== null) {
585
+ out += ch;
586
+ if (ch === quote)
587
+ quote = null;
588
+ continue;
589
+ }
590
+ if (braced) {
591
+ out += ch;
592
+ if (ch === '}')
593
+ braced = false;
594
+ continue;
595
+ }
596
+ if (ch === '\'' || ch === '"') {
597
+ quote = ch;
598
+ out += ch;
599
+ continue;
600
+ }
601
+ if (ch === '$' && text[i + 1] === '{') {
602
+ braced = true;
603
+ out += '${';
604
+ i += 1;
605
+ continue;
606
+ }
607
+ out += ch === '{' || ch === '}' ? '\n' : ch;
608
+ }
609
+ return out.replace(/(^|[\n;|(]|&&|\|\|)([ \t]*)(?:&[ \t]*|\.[ \t]+)(?=[^\s&])/g, '$1$2').replace(/(^|[\n;|(]|&&|\|\|)([ \t]*)[&.][ \t]*(?=\n|$)/g, '$1$2');
610
+ }
611
+ // PowerShell text that builds or runs code from pieces, and the settings that change what a plain command does. Only the
612
+ // PowerShell / cmd context looks at it: `$PSDefaultParameterValues['Remove-Item:Recurse']=$true` makes `Remove-Item C:\x`
613
+ // recursive, and `[scriptblock]::Create($s).Invoke()` is code nobody can read.
614
+ function psDynamicCode(text) {
615
+ const t = text.toLowerCase();
616
+ const c = t.replace(/\s+/g, '');
617
+ if (c.includes('[scriptblock]::create') || c.includes('.invoke(') || c.includes('executioncontext.invokecommand') || c.includes('add-type'))
618
+ return true;
619
+ // COM objects that start programs (`WScript.Shell`.Run, `Shell.Application`.ShellExecute).
620
+ if (c.includes('wscript.shell') || c.includes('shell.application') || c.includes('.shellexecute('))
621
+ return true;
622
+ if (/(?:^|[\n;|(]|&&|\|\|)[ \t]*(?:invoke-command|icm)(?![\w-])[^\n;|]{0,1024}[ \t]-f[a-z]*(?![\w-])/.test(t))
623
+ return true;
624
+ if (/(?:foreach-object|foreach|%)[ \t]+-m[a-z]*(?![\w-])/.test(t) || /\|[ \t]*(?:%|foreach-object|foreach)[ \t]+[a-z]/.test(t))
625
+ return true;
626
+ return false;
627
+ }
628
+ function psDefaultParameters(text) { return text.toLowerCase().includes('psdefaultparametervalues'); }
629
+ const CMD_INTERNAL = new Set(['rd', 'rmdir', 'del', 'erase', 'rm', 'cmd', 'call', 'start']);
630
+ exports.PS_KEYWORDS = new Set(['if', 'for', 'foreach', 'while', 'else', 'elseif', 'do', 'then', 'call', 'start', 'switch', 'try', 'catch', 'finally', '%', 'foreach-object']);
631
+ function splitInternal(words) {
632
+ const first = words[0];
633
+ const at = first.indexOf('/');
634
+ if (at <= 0)
635
+ return words;
636
+ const head = first.slice(0, at);
637
+ if (!CMD_INTERNAL.has(head.toLowerCase().replace(/\.(?:exe|cmd|bat|com)$/, '')))
638
+ return words;
639
+ return [head, ...first.slice(at).split(/(?=\/)/), ...words.slice(1)];
640
+ }
641
+ function psStatements(text, cmd) {
642
+ const out = [];
643
+ let ok = true;
644
+ const scan = (start, closer, depth) => {
645
+ let words = [];
646
+ let cur = '';
647
+ let has = false;
648
+ let piped = false;
649
+ let i = start;
650
+ const endWord = () => { if (has)
651
+ words.push(cur); cur = ''; has = false; };
652
+ const endStmt = (pipe) => {
653
+ endWord();
654
+ // cmd: a leading `@` (echo off for this command) is no part of the command name.
655
+ if (cmd && words.length && /^@+/.test(words[0])) {
656
+ words[0] = words[0].replace(/^@+/, '');
657
+ if (words[0] === '')
658
+ words.shift();
659
+ }
660
+ if (words.length)
661
+ out.push({ words: cmd ? splitInternal(words) : words, piped });
662
+ words = [];
663
+ piped = pipe;
664
+ };
665
+ while (i < text.length) {
666
+ const ch = text[i];
667
+ if (ch === '"' || (ch === '\'' && !cmd)) {
668
+ has = true;
669
+ i += 1;
670
+ let closed = false;
671
+ while (i < text.length) {
672
+ const c = text[i];
673
+ if (c === ch) {
674
+ if (text[i + 1] === ch) {
675
+ cur += ch;
676
+ i += 2;
677
+ continue;
678
+ }
679
+ closed = true;
680
+ break;
681
+ }
682
+ if (c === '`' && ch === '"' && !cmd && i + 1 < text.length) {
683
+ cur += text[i + 1];
684
+ i += 2;
685
+ continue;
686
+ } // `" is a quote character inside the string
687
+ if (ch === '"' && c === '$' && text[i + 1] === '(') {
688
+ cur += '$';
689
+ if (depth >= 20) {
690
+ ok = false;
691
+ return text.length;
692
+ }
693
+ i = scan(i + 2, true, depth + 1);
694
+ continue;
695
+ }
696
+ cur += c;
697
+ i += 1;
698
+ }
699
+ if (!closed)
700
+ ok = false;
701
+ i += 1;
702
+ continue;
703
+ }
704
+ if ((ch === '`' && !cmd) || (ch === '^' && cmd)) {
705
+ // The escape character: a line break after it joins the lines; any other character after it is plain text (a quote or `&` too).
706
+ const nx = text[i + 1];
707
+ if (nx === undefined) {
708
+ i += 1;
709
+ continue;
710
+ }
711
+ if (nx === '\n' || nx === '\r') {
712
+ endWord();
713
+ i += nx === '\r' && text[i + 2] === '\n' ? 3 : 2;
714
+ continue;
715
+ }
716
+ cur += nx;
717
+ has = true;
718
+ i += 2;
719
+ continue;
720
+ }
721
+ if (ch === ' ' || ch === '\t' || ch === ',' || ch === '=') {
722
+ endWord();
723
+ i += 1;
724
+ continue;
725
+ }
726
+ if (ch === '\n' || ch === '\r' || ch === '{' || ch === '}') {
727
+ endStmt(false);
728
+ i += 1;
729
+ continue;
730
+ }
731
+ if (ch === ';') {
732
+ if (cmd)
733
+ endWord();
734
+ else
735
+ endStmt(false);
736
+ i += 1;
737
+ continue;
738
+ }
739
+ if (ch === '|') {
740
+ if (text[i + 1] === '|') {
741
+ endStmt(false);
742
+ i += 2;
743
+ }
744
+ else {
745
+ endStmt(true);
746
+ i += 1;
747
+ }
748
+ continue;
749
+ }
750
+ if (ch === '&') {
751
+ if (text[i + 1] === '&') {
752
+ endStmt(false);
753
+ i += 2;
754
+ continue;
755
+ }
756
+ if (words.length === 0 && !has) {
757
+ i += 1;
758
+ continue;
759
+ } // the call operator
760
+ endStmt(false);
761
+ i += 1;
762
+ continue;
763
+ }
764
+ if (ch === '(') {
765
+ if (depth >= 20) {
766
+ ok = false;
767
+ return text.length;
768
+ }
769
+ // The group is part of the current word (an expression, not a literal): a `$` in the word says so.
770
+ if (!cur.endsWith('$'))
771
+ cur += '$';
772
+ has = true;
773
+ i = scan(i + 1, true, depth + 1);
774
+ continue;
775
+ }
776
+ if (ch === ')') {
777
+ if (closer) {
778
+ endStmt(false);
779
+ return i + 1;
780
+ }
781
+ endStmt(false);
782
+ i += 1;
783
+ continue;
784
+ }
785
+ if (ch === '#' && !has && !cmd) {
786
+ while (i < text.length && text[i] !== '\n')
787
+ i += 1;
788
+ continue;
789
+ }
790
+ if (ch === '<' && text[i + 1] === '#') {
791
+ ok = false;
792
+ i += 2;
793
+ continue;
794
+ }
795
+ if (ch === '@' && (text[i + 1] === '\'' || text[i + 1] === '"') && !has) {
796
+ ok = false;
797
+ }
798
+ cur += ch;
799
+ has = true;
800
+ i += 1;
801
+ }
802
+ if (closer)
803
+ ok = false;
804
+ endStmt(false);
805
+ return i;
806
+ };
807
+ scan(0, false, 0);
808
+ return { statements: out, ok };
809
+ }
810
+ // PowerShell cmdlets that print or read text and run none of it. A string argument of one is still read as a command line by
811
+ // the usual unknown-program scan (so `Write-Host "npm publish"` keeps its stop), but a delete verb inside it is no A3 stop.
812
+ exports.PS_OUTPUT_CMDLETS = new Set(['write-host', 'write-output', 'write-verbose', 'write-warning', 'write-error', 'write-debug',
813
+ 'write-information', 'select-string', 'get-content', 'out-string', 'out-host', 'out-null', 'get-help', 'measure-object']);
814
+ // PowerShell statement keywords and block cmdlets: bash reads their script blocks as their arguments. In PowerShell text those
815
+ // arguments are scanned as before, but a delete verb found in them is no A3 stop (the blocks are read as statements by the
816
+ // lexical check and the flattened reading, where each command has its real owner).
817
+ exports.PS_BLOCK_WORDS = new Set(['try', 'catch', 'finally', 'if', 'elseif', 'else', 'foreach', 'for', 'while', 'do', 'switch',
818
+ 'foreach-object', 'where-object', '%', '?']);
355
819
  //# sourceMappingURL=tables.js.map