@wrongstack/plugins 0.306.4 → 0.307.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/gitignore-guard.js +1 -1
- package/dist/index.js +393 -376
- package/dist/notify-hub.js +13 -0
- package/dist/path-guard/glob.d.ts +32 -0
- package/dist/path-guard/index.d.ts +2 -44
- package/dist/path-guard/shell-targets.d.ts +40 -0
- package/dist/path-guard/tool-targets.d.ts +34 -0
- package/dist/path-guard.js +377 -373
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -9343,7 +9343,7 @@ var DEFAULT_ARTIFACT_PATTERNS = Object.freeze([
|
|
|
9343
9343
|
"*.env.*"
|
|
9344
9344
|
]);
|
|
9345
9345
|
function toForwardSlashes(p) {
|
|
9346
|
-
return
|
|
9346
|
+
return p.split(sep3).join("/").replaceAll("\\", "/");
|
|
9347
9347
|
}
|
|
9348
9348
|
function globToSource(glob) {
|
|
9349
9349
|
return glob.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]");
|
|
@@ -13544,6 +13544,19 @@ var plugin38 = {
|
|
|
13544
13544
|
}
|
|
13545
13545
|
}
|
|
13546
13546
|
state35.eventUnsubscribers = [];
|
|
13547
|
+
if (api.tools?.unregister) {
|
|
13548
|
+
try {
|
|
13549
|
+
api.tools.unregister("notify_send");
|
|
13550
|
+
api.tools.unregister("notify_hub_status");
|
|
13551
|
+
} catch {
|
|
13552
|
+
}
|
|
13553
|
+
}
|
|
13554
|
+
if (api.notifier?.unregisterChannel) {
|
|
13555
|
+
try {
|
|
13556
|
+
api.notifier.unregisterChannel("webhook");
|
|
13557
|
+
} catch {
|
|
13558
|
+
}
|
|
13559
|
+
}
|
|
13547
13560
|
const channelCounters = state35.channel?.counters();
|
|
13548
13561
|
state35.channel = null;
|
|
13549
13562
|
state35.lastDelivery = null;
|
|
@@ -13565,40 +13578,7 @@ var plugin38 = {
|
|
|
13565
13578
|
};
|
|
13566
13579
|
var notify_hub_default = plugin38;
|
|
13567
13580
|
|
|
13568
|
-
// src/path-guard/
|
|
13569
|
-
function createState() {
|
|
13570
|
-
return { invocations: 0, blocks: 0, warns: 0, lastBlock: null, hookUnregister: null };
|
|
13571
|
-
}
|
|
13572
|
-
var states = /* @__PURE__ */ new WeakMap();
|
|
13573
|
-
var latestState = createState();
|
|
13574
|
-
var DEFAULT_PROTECT = [
|
|
13575
|
-
"pnpm-lock.yaml",
|
|
13576
|
-
"package-lock.json",
|
|
13577
|
-
"yarn.lock",
|
|
13578
|
-
"bun.lockb",
|
|
13579
|
-
"Cargo.lock",
|
|
13580
|
-
"poetry.lock",
|
|
13581
|
-
".env",
|
|
13582
|
-
".env.*",
|
|
13583
|
-
".git/**",
|
|
13584
|
-
"**/migrations/**"
|
|
13585
|
-
];
|
|
13586
|
-
var DEFAULTS33 = {
|
|
13587
|
-
enabled: true,
|
|
13588
|
-
mode: "block",
|
|
13589
|
-
protect: DEFAULT_PROTECT,
|
|
13590
|
-
allow: []
|
|
13591
|
-
};
|
|
13592
|
-
function readConfig34(raw) {
|
|
13593
|
-
if (!raw || typeof raw !== "object") return { ...DEFAULTS33, protect: [...DEFAULT_PROTECT] };
|
|
13594
|
-
const r = raw;
|
|
13595
|
-
return {
|
|
13596
|
-
enabled: r["enabled"] !== false,
|
|
13597
|
-
mode: r["mode"] === "warn" ? "warn" : "block",
|
|
13598
|
-
protect: Array.isArray(r["protect"]) ? r["protect"].filter((p) => typeof p === "string" && p.length > 0) : [...DEFAULT_PROTECT],
|
|
13599
|
-
allow: Array.isArray(r["allow"]) ? r["allow"].filter((p) => typeof p === "string" && p.length > 0) : []
|
|
13600
|
-
};
|
|
13601
|
-
}
|
|
13581
|
+
// src/path-guard/glob.ts
|
|
13602
13582
|
function compilePathGlob(pattern) {
|
|
13603
13583
|
const normalized = pattern.replace(/\\/g, "/");
|
|
13604
13584
|
let source = "";
|
|
@@ -13764,337 +13744,101 @@ function targetFullyAllowed(target, allowTexts, allowRes) {
|
|
|
13764
13744
|
return allowNormalized.endsWith("/**") && allowRe?.test(`${normalized}/.path-guard-probe`);
|
|
13765
13745
|
});
|
|
13766
13746
|
}
|
|
13767
|
-
|
|
13768
|
-
|
|
13769
|
-
var
|
|
13770
|
-
|
|
13771
|
-
|
|
13772
|
-
"
|
|
13773
|
-
"
|
|
13774
|
-
"
|
|
13775
|
-
"
|
|
13776
|
-
"
|
|
13777
|
-
"
|
|
13778
|
-
"
|
|
13779
|
-
"install"
|
|
13747
|
+
|
|
13748
|
+
// src/path-guard/shell-targets.ts
|
|
13749
|
+
var VALUE_TAKING_GIT_OPTIONS = /* @__PURE__ */ new Set([
|
|
13750
|
+
"-C",
|
|
13751
|
+
"-c",
|
|
13752
|
+
"--git-dir",
|
|
13753
|
+
"--work-tree",
|
|
13754
|
+
"--namespace",
|
|
13755
|
+
"--super-prefix",
|
|
13756
|
+
"--exec-path",
|
|
13757
|
+
"--config-env",
|
|
13758
|
+
"--attr-source"
|
|
13780
13759
|
]);
|
|
13781
|
-
|
|
13782
|
-
|
|
13783
|
-
|
|
13784
|
-
const
|
|
13785
|
-
|
|
13786
|
-
|
|
13787
|
-
|
|
13788
|
-
|
|
13789
|
-
|
|
13790
|
-
|
|
13791
|
-
if (
|
|
13792
|
-
|
|
13793
|
-
const
|
|
13794
|
-
|
|
13795
|
-
|
|
13796
|
-
|
|
13797
|
-
|
|
13798
|
-
(field) => toolInput[field] !== void 0
|
|
13799
|
-
);
|
|
13800
|
-
if (filesystemWriter && hasKnownPath) return true;
|
|
13760
|
+
var MAX_LAUNCHER_TOKENS = 256;
|
|
13761
|
+
var MAX_LAUNCHER_LENGTH = 64 * 1024;
|
|
13762
|
+
function boundedShellTokens(raw) {
|
|
13763
|
+
const tokens = [];
|
|
13764
|
+
let token = "";
|
|
13765
|
+
let tokenStart = -1;
|
|
13766
|
+
let quote = null;
|
|
13767
|
+
const limit = Math.min(raw.length, MAX_LAUNCHER_LENGTH);
|
|
13768
|
+
for (let index = 0; index < limit && tokens.length < MAX_LAUNCHER_TOKENS; index += 1) {
|
|
13769
|
+
const char = raw[index] ?? "";
|
|
13770
|
+
if (tokenStart < 0 && !/\s/.test(char)) tokenStart = index;
|
|
13771
|
+
if (char === "\\" && quote !== "'" && index + 1 < limit) {
|
|
13772
|
+
const escaped = raw[index + 1] ?? "";
|
|
13773
|
+
const shellEscaped = quote === '"' ? /[$\x60"\\\r\n]/.test(escaped) : /[\s'"\\;&|()`]/.test(escaped);
|
|
13774
|
+
token += shellEscaped ? escaped : `\\${escaped}`;
|
|
13775
|
+
index += 1;
|
|
13776
|
+
continue;
|
|
13801
13777
|
}
|
|
13802
|
-
|
|
13778
|
+
if (char === "'" || char === '"') {
|
|
13779
|
+
if (quote === char) quote = null;
|
|
13780
|
+
else if (quote === null) quote = char;
|
|
13781
|
+
else token += char;
|
|
13782
|
+
continue;
|
|
13783
|
+
}
|
|
13784
|
+
if (quote === null && /\s/.test(char)) {
|
|
13785
|
+
if (tokenStart >= 0) tokens.push({ value: token, start: tokenStart, end: index });
|
|
13786
|
+
token = "";
|
|
13787
|
+
tokenStart = -1;
|
|
13788
|
+
continue;
|
|
13789
|
+
}
|
|
13790
|
+
token += char;
|
|
13803
13791
|
}
|
|
13804
|
-
if (
|
|
13805
|
-
|
|
13806
|
-
}
|
|
13807
|
-
function executesShell(input) {
|
|
13808
|
-
const toolName = input.toolName ?? "";
|
|
13809
|
-
if (LEGACY_SHELL_TOOLS.has(toolName)) return true;
|
|
13810
|
-
if (toolName === "git") return false;
|
|
13811
|
-
const segmentedName = toolName.replace(/([a-z0-9])([A-Z])/g, "$1_$2");
|
|
13812
|
-
const isCommandStringRunner = /(?:^|[_.-])(?:command|exec|execute|shell|terminal)(?:$|[_.-])/i.test(segmentedName);
|
|
13813
|
-
const hasShellCapability = input.toolCapabilities?.some((capability) => SHELL_CAPABILITIES.has(capability)) ?? false;
|
|
13814
|
-
const hasCommandString = typeof input.toolInput?.["command"] === "string";
|
|
13815
|
-
return isCommandStringRunner && hasShellCapability || hasCommandString && input.toolMutating === true;
|
|
13816
|
-
}
|
|
13817
|
-
var PATH_FIELDS = [
|
|
13818
|
-
"path",
|
|
13819
|
-
"file_path",
|
|
13820
|
-
"filePath",
|
|
13821
|
-
"target",
|
|
13822
|
-
"target_path",
|
|
13823
|
-
"targetPath",
|
|
13824
|
-
"destination",
|
|
13825
|
-
"dest",
|
|
13826
|
-
"output_path",
|
|
13827
|
-
"outputPath",
|
|
13828
|
-
"out",
|
|
13829
|
-
"file"
|
|
13830
|
-
];
|
|
13831
|
-
var PATH_LIST_FIELDS = ["files", "paths"];
|
|
13832
|
-
var SOURCE_PATH_FIELDS = [
|
|
13833
|
-
"source",
|
|
13834
|
-
"from",
|
|
13835
|
-
"src",
|
|
13836
|
-
"input_path",
|
|
13837
|
-
"inputPath",
|
|
13838
|
-
"old_path",
|
|
13839
|
-
"oldPath"
|
|
13840
|
-
];
|
|
13841
|
-
var MOVE_TOOL_NAME = /(?:^|[_.-])(move|rename)(?:$|[_.-])/i;
|
|
13842
|
-
var DIRECTORY_DELETE_TOOL_NAME = /(?:^|[_.-])(?:rmdir|(?:delete|remove)[_.-](?:dir|directory))(?:$|[_.-])/i;
|
|
13843
|
-
function segmentedToolName(toolName) {
|
|
13844
|
-
return toolName.replace(/([a-z0-9])([A-Z])/g, "$1_$2");
|
|
13845
|
-
}
|
|
13846
|
-
function isMoveToolName(toolName) {
|
|
13847
|
-
return MOVE_TOOL_NAME.test(segmentedToolName(toolName));
|
|
13848
|
-
}
|
|
13849
|
-
function isDirectoryDeleteToolName(toolName) {
|
|
13850
|
-
return DIRECTORY_DELETE_TOOL_NAME.test(segmentedToolName(toolName));
|
|
13851
|
-
}
|
|
13852
|
-
function cleanPatchPath(raw) {
|
|
13853
|
-
const trimmed = raw.trim();
|
|
13854
|
-
if (!trimmed || trimmed === "/dev/null") return null;
|
|
13855
|
-
const quoted = /^"([^"]+)"(?:\s|$)/.exec(trimmed)?.[1];
|
|
13856
|
-
const withoutTimestamp = quoted ?? trimmed.replace(/(?:\t|\s+)\d{4}-\d{2}-\d{2}(?:\s.*)?$/, "").trim();
|
|
13857
|
-
if (!withoutTimestamp || withoutTimestamp === "/dev/null") return null;
|
|
13858
|
-
return withoutTimestamp.replace(/^[ab]\//, "");
|
|
13859
|
-
}
|
|
13860
|
-
function pathsFromPatch(patch) {
|
|
13861
|
-
const paths = [];
|
|
13862
|
-
const lines = patch.split(/\r?\n/);
|
|
13863
|
-
for (let index = 0; index + 2 < lines.length; index += 1) {
|
|
13864
|
-
const oldHeader = lines[index];
|
|
13865
|
-
const newHeader = lines[index + 1];
|
|
13866
|
-
const hunkHeader = lines[index + 2];
|
|
13867
|
-
if (!oldHeader?.startsWith("--- ") || !newHeader?.startsWith("+++ ")) continue;
|
|
13868
|
-
if (!hunkHeader?.startsWith("@@ ")) continue;
|
|
13869
|
-
const oldPath = cleanPatchPath(oldHeader.slice(4));
|
|
13870
|
-
const newPath = cleanPatchPath(newHeader.slice(4));
|
|
13871
|
-
if (oldPath) paths.push(oldPath);
|
|
13872
|
-
if (newPath) paths.push(newPath);
|
|
13792
|
+
if (tokenStart >= 0 && tokens.length < MAX_LAUNCHER_TOKENS) {
|
|
13793
|
+
tokens.push({ value: token, start: tokenStart, end: limit });
|
|
13873
13794
|
}
|
|
13874
|
-
return
|
|
13795
|
+
return tokens;
|
|
13875
13796
|
}
|
|
13876
|
-
function
|
|
13877
|
-
|
|
13878
|
-
targets.push({
|
|
13879
|
-
path: resolveTargetPath(value, base),
|
|
13880
|
-
kind
|
|
13881
|
-
});
|
|
13797
|
+
function shellTokens(raw) {
|
|
13798
|
+
return boundedShellTokens(raw).map((token) => token.value);
|
|
13882
13799
|
}
|
|
13883
|
-
function
|
|
13884
|
-
const
|
|
13885
|
-
|
|
13886
|
-
|
|
13887
|
-
|
|
13888
|
-
|
|
13889
|
-
|
|
13890
|
-
|
|
13891
|
-
|
|
13892
|
-
|
|
13893
|
-
|
|
13800
|
+
function gitInvocationArguments(command) {
|
|
13801
|
+
const argumentsList = [];
|
|
13802
|
+
const quotedIndexes = new Uint8Array(command.length);
|
|
13803
|
+
let activeQuote = null;
|
|
13804
|
+
for (let index = 0; index < command.length; index += 1) {
|
|
13805
|
+
const char = command[index];
|
|
13806
|
+
if (isQuoteBoundary(command, index, activeQuote)) {
|
|
13807
|
+
quotedIndexes[index] = 1;
|
|
13808
|
+
activeQuote = activeQuote === char ? null : char === "'" ? "'" : '"';
|
|
13809
|
+
} else if (activeQuote !== null) {
|
|
13810
|
+
quotedIndexes[index] = 1;
|
|
13811
|
+
}
|
|
13894
13812
|
}
|
|
13895
|
-
|
|
13896
|
-
|
|
13897
|
-
|
|
13898
|
-
const
|
|
13899
|
-
if (
|
|
13813
|
+
const gitStart = /(?:^|[;&|\r\n]\s*|\(\s*|`\s*)git\b/gi;
|
|
13814
|
+
let match = gitStart.exec(command);
|
|
13815
|
+
while (match !== null) {
|
|
13816
|
+
const gitOffset = match[0].toLowerCase().lastIndexOf("git");
|
|
13817
|
+
if (gitOffset < 0 || quotedIndexes[match.index + gitOffset] === 1) {
|
|
13818
|
+
match = gitStart.exec(command);
|
|
13819
|
+
continue;
|
|
13820
|
+
}
|
|
13821
|
+
const start = gitStart.lastIndex;
|
|
13822
|
+
let quote = null;
|
|
13823
|
+
let end = start;
|
|
13824
|
+
for (; end < command.length; end += 1) {
|
|
13825
|
+
const char = command[end] ?? "";
|
|
13826
|
+
if (char === "\\" && quote !== "'") {
|
|
13827
|
+
end += 1;
|
|
13828
|
+
continue;
|
|
13829
|
+
}
|
|
13830
|
+
if (char === "'" || char === '"') {
|
|
13831
|
+
if (quote === char) quote = null;
|
|
13832
|
+
else if (quote === null) quote = char;
|
|
13833
|
+
continue;
|
|
13834
|
+
}
|
|
13835
|
+
if (quote === null && /[;&|)`\r\n]/.test(char)) break;
|
|
13836
|
+
}
|
|
13837
|
+
argumentsList.push(command.slice(start, end));
|
|
13838
|
+
gitStart.lastIndex = Math.max(end, start);
|
|
13839
|
+
match = gitStart.exec(command);
|
|
13900
13840
|
}
|
|
13901
|
-
|
|
13902
|
-
function isReadOnlyInvocation(toolName, toolInput) {
|
|
13903
|
-
if (toolName === "git") {
|
|
13904
|
-
const command = toolInput["command"];
|
|
13905
|
-
if (command === "status" || command === "log" || command === "diff" || command === "fetch" || command === "commit" || command === "branch" || command === "push") {
|
|
13906
|
-
return true;
|
|
13907
|
-
}
|
|
13908
|
-
return command === "worktree" && toolInput["worktreeAction"] === "list";
|
|
13909
|
-
}
|
|
13910
|
-
if (toolName === "design") {
|
|
13911
|
-
const action = toolInput["action"] ?? "list";
|
|
13912
|
-
return action === "list" || action === "foundations" || action === "verify";
|
|
13913
|
-
}
|
|
13914
|
-
if (toolName === "format") return toolInput["check"] === true;
|
|
13915
|
-
if (toolName === "patch" || toolName === "scaffold") return toolInput["dry_run"] === true;
|
|
13916
|
-
if (toolName === "replace") return toolInput["dry_run"] !== false;
|
|
13917
|
-
return false;
|
|
13918
|
-
}
|
|
13919
|
-
function pathsFromToolInput(toolInput, toolName, invocationCwd) {
|
|
13920
|
-
const targets = [];
|
|
13921
|
-
const effectiveCwd = effectiveToolCwd(toolInput["cwd"], invocationCwd);
|
|
13922
|
-
const directoryDelete = isDirectoryDeleteToolName(toolName);
|
|
13923
|
-
for (const field of PATH_FIELDS) {
|
|
13924
|
-
const value = toolInput[field];
|
|
13925
|
-
appendTarget(
|
|
13926
|
-
targets,
|
|
13927
|
-
value,
|
|
13928
|
-
directoryDelete ? "deletion-scope" : typeof value === "string" && isUnresolvedPathScope(value) ? "scope" : "file",
|
|
13929
|
-
effectiveCwd
|
|
13930
|
-
);
|
|
13931
|
-
}
|
|
13932
|
-
const directoryCapableLists = toolName === "format" || toolName === "replace";
|
|
13933
|
-
for (const field of PATH_LIST_FIELDS) {
|
|
13934
|
-
appendTargetList(
|
|
13935
|
-
targets,
|
|
13936
|
-
toolInput[field],
|
|
13937
|
-
directoryCapableLists && field === "files",
|
|
13938
|
-
effectiveCwd
|
|
13939
|
-
);
|
|
13940
|
-
}
|
|
13941
|
-
if (toolName === "install") {
|
|
13942
|
-
appendTarget(targets, effectiveCwd ?? invocationCwd ?? ".", "scope");
|
|
13943
|
-
}
|
|
13944
|
-
if (toolName === "git") {
|
|
13945
|
-
const command = toolInput["command"];
|
|
13946
|
-
if (command === "worktree" && (toolInput["worktreeAction"] === "add" || toolInput["worktreeAction"] === "remove")) {
|
|
13947
|
-
appendTarget(targets, toolInput["worktreePath"] ?? toolInput["worktree_path"], "file");
|
|
13948
|
-
}
|
|
13949
|
-
}
|
|
13950
|
-
if (toolName === "scaffold") {
|
|
13951
|
-
const cwdValue = toolInput["cwd"];
|
|
13952
|
-
const cwd = typeof cwdValue === "string" && cwdValue.length > 0 ? cwdValue : invocationCwd ?? ".";
|
|
13953
|
-
const base = normalizePath2(cwd).replace(/\/$/, "");
|
|
13954
|
-
const name = typeof toolInput["name"] === "string" ? toolInput["name"] : "";
|
|
13955
|
-
const template = toolInput["template"];
|
|
13956
|
-
const filesByTemplate = {
|
|
13957
|
-
"npm-package": ["package.json", "tsconfig.json", "src/index.ts", "src/index.test.ts"],
|
|
13958
|
-
"cli-tool": ["package.json", "src/index.ts"],
|
|
13959
|
-
"react-component": name ? [`${name}.tsx`, `${name}.test.tsx`] : []
|
|
13960
|
-
};
|
|
13961
|
-
for (const file of typeof template === "string" ? filesByTemplate[template] ?? [] : []) {
|
|
13962
|
-
targets.push({ path: `${base}/${file}`, kind: "file" });
|
|
13963
|
-
}
|
|
13964
|
-
targets.push({ path: base, kind: "scope" });
|
|
13965
|
-
}
|
|
13966
|
-
if (isMoveToolName(toolName)) {
|
|
13967
|
-
for (const field of SOURCE_PATH_FIELDS) {
|
|
13968
|
-
appendTarget(targets, toolInput[field], "deletion-scope", effectiveCwd);
|
|
13969
|
-
}
|
|
13970
|
-
}
|
|
13971
|
-
const patch = toolInput["patch"];
|
|
13972
|
-
if (typeof patch === "string") {
|
|
13973
|
-
const patchTargets = pathsFromPatch(patch);
|
|
13974
|
-
const directory = toolInput["directory"];
|
|
13975
|
-
const baseValue = typeof directory === "string" && directory.length > 0 ? directory : invocationCwd;
|
|
13976
|
-
if (baseValue) {
|
|
13977
|
-
const base = normalizePath2(baseValue).replace(/\/$/, "");
|
|
13978
|
-
targets.push(
|
|
13979
|
-
...patchTargets.map((target) => ({ path: `${base}/${target}`, kind: "file" }))
|
|
13980
|
-
);
|
|
13981
|
-
} else {
|
|
13982
|
-
targets.push(...patchTargets.map((path) => ({ path, kind: "file" })));
|
|
13983
|
-
}
|
|
13984
|
-
}
|
|
13985
|
-
if (targets.length === 0) {
|
|
13986
|
-
const cwd = effectiveCwd ?? ".";
|
|
13987
|
-
targets.push({ path: normalizePath2(cwd).replace(/\/$/, "") || ".", kind: "scope" });
|
|
13988
|
-
}
|
|
13989
|
-
const seen = /* @__PURE__ */ new Set();
|
|
13990
|
-
return targets.map((target) => ({
|
|
13991
|
-
...target,
|
|
13992
|
-
path: relativeToInvocationCwd(target.path, invocationCwd)
|
|
13993
|
-
})).filter((target) => {
|
|
13994
|
-
const key = `${target.kind}:${target.path}`;
|
|
13995
|
-
if (seen.has(key)) return false;
|
|
13996
|
-
seen.add(key);
|
|
13997
|
-
return true;
|
|
13998
|
-
});
|
|
13999
|
-
}
|
|
14000
|
-
function operationLabel(toolName) {
|
|
14001
|
-
if (toolName === "write") return "write";
|
|
14002
|
-
if (toolName === "edit") return "edit";
|
|
14003
|
-
return `write via "${toolName}"`;
|
|
14004
|
-
}
|
|
14005
|
-
var VALUE_TAKING_GIT_OPTIONS = /* @__PURE__ */ new Set([
|
|
14006
|
-
"-C",
|
|
14007
|
-
"-c",
|
|
14008
|
-
"--git-dir",
|
|
14009
|
-
"--work-tree",
|
|
14010
|
-
"--namespace",
|
|
14011
|
-
"--super-prefix",
|
|
14012
|
-
"--exec-path",
|
|
14013
|
-
"--config-env",
|
|
14014
|
-
"--attr-source"
|
|
14015
|
-
]);
|
|
14016
|
-
var MAX_LAUNCHER_TOKENS = 256;
|
|
14017
|
-
var MAX_LAUNCHER_LENGTH = 64 * 1024;
|
|
14018
|
-
function boundedShellTokens(raw) {
|
|
14019
|
-
const tokens = [];
|
|
14020
|
-
let token = "";
|
|
14021
|
-
let tokenStart = -1;
|
|
14022
|
-
let quote = null;
|
|
14023
|
-
const limit = Math.min(raw.length, MAX_LAUNCHER_LENGTH);
|
|
14024
|
-
for (let index = 0; index < limit && tokens.length < MAX_LAUNCHER_TOKENS; index += 1) {
|
|
14025
|
-
const char = raw[index] ?? "";
|
|
14026
|
-
if (tokenStart < 0 && !/\s/.test(char)) tokenStart = index;
|
|
14027
|
-
if (char === "\\" && quote !== "'" && index + 1 < limit) {
|
|
14028
|
-
const escaped = raw[index + 1] ?? "";
|
|
14029
|
-
const shellEscaped = quote === '"' ? /[$\x60"\\\r\n]/.test(escaped) : /[\s'"\\;&|()`]/.test(escaped);
|
|
14030
|
-
token += shellEscaped ? escaped : `\\${escaped}`;
|
|
14031
|
-
index += 1;
|
|
14032
|
-
continue;
|
|
14033
|
-
}
|
|
14034
|
-
if (char === "'" || char === '"') {
|
|
14035
|
-
if (quote === char) quote = null;
|
|
14036
|
-
else if (quote === null) quote = char;
|
|
14037
|
-
else token += char;
|
|
14038
|
-
continue;
|
|
14039
|
-
}
|
|
14040
|
-
if (quote === null && /\s/.test(char)) {
|
|
14041
|
-
if (tokenStart >= 0) tokens.push({ value: token, start: tokenStart, end: index });
|
|
14042
|
-
token = "";
|
|
14043
|
-
tokenStart = -1;
|
|
14044
|
-
continue;
|
|
14045
|
-
}
|
|
14046
|
-
token += char;
|
|
14047
|
-
}
|
|
14048
|
-
if (tokenStart >= 0 && tokens.length < MAX_LAUNCHER_TOKENS) {
|
|
14049
|
-
tokens.push({ value: token, start: tokenStart, end: limit });
|
|
14050
|
-
}
|
|
14051
|
-
return tokens;
|
|
14052
|
-
}
|
|
14053
|
-
function shellTokens(raw) {
|
|
14054
|
-
return boundedShellTokens(raw).map((token) => token.value);
|
|
14055
|
-
}
|
|
14056
|
-
function gitInvocationArguments(command) {
|
|
14057
|
-
const argumentsList = [];
|
|
14058
|
-
const quotedIndexes = new Uint8Array(command.length);
|
|
14059
|
-
let activeQuote = null;
|
|
14060
|
-
for (let index = 0; index < command.length; index += 1) {
|
|
14061
|
-
const char = command[index];
|
|
14062
|
-
if (isQuoteBoundary(command, index, activeQuote)) {
|
|
14063
|
-
quotedIndexes[index] = 1;
|
|
14064
|
-
activeQuote = activeQuote === char ? null : char === "'" ? "'" : '"';
|
|
14065
|
-
} else if (activeQuote !== null) {
|
|
14066
|
-
quotedIndexes[index] = 1;
|
|
14067
|
-
}
|
|
14068
|
-
}
|
|
14069
|
-
const gitStart = /(?:^|[;&|\r\n]\s*|\(\s*|`\s*)git\b/gi;
|
|
14070
|
-
let match = gitStart.exec(command);
|
|
14071
|
-
while (match !== null) {
|
|
14072
|
-
const gitOffset = match[0].toLowerCase().lastIndexOf("git");
|
|
14073
|
-
if (gitOffset < 0 || quotedIndexes[match.index + gitOffset] === 1) {
|
|
14074
|
-
match = gitStart.exec(command);
|
|
14075
|
-
continue;
|
|
14076
|
-
}
|
|
14077
|
-
const start = gitStart.lastIndex;
|
|
14078
|
-
let quote = null;
|
|
14079
|
-
let end = start;
|
|
14080
|
-
for (; end < command.length; end += 1) {
|
|
14081
|
-
const char = command[end] ?? "";
|
|
14082
|
-
if (char === "\\" && quote !== "'") {
|
|
14083
|
-
end += 1;
|
|
14084
|
-
continue;
|
|
14085
|
-
}
|
|
14086
|
-
if (char === "'" || char === '"') {
|
|
14087
|
-
if (quote === char) quote = null;
|
|
14088
|
-
else if (quote === null) quote = char;
|
|
14089
|
-
continue;
|
|
14090
|
-
}
|
|
14091
|
-
if (quote === null && /[;&|)`\r\n]/.test(char)) break;
|
|
14092
|
-
}
|
|
14093
|
-
argumentsList.push(command.slice(start, end));
|
|
14094
|
-
gitStart.lastIndex = Math.max(end, start);
|
|
14095
|
-
match = gitStart.exec(command);
|
|
14096
|
-
}
|
|
14097
|
-
return argumentsList;
|
|
13841
|
+
return argumentsList;
|
|
14098
13842
|
}
|
|
14099
13843
|
function gitSubcommandIndex(tokens) {
|
|
14100
13844
|
for (let index = 0; index < tokens.length; index += 1) {
|
|
@@ -14165,21 +13909,6 @@ function unwrapEnvSplitStringAtBoundary(command) {
|
|
|
14165
13909
|
}
|
|
14166
13910
|
return command;
|
|
14167
13911
|
}
|
|
14168
|
-
function stripTransparentLaunchers(command) {
|
|
14169
|
-
let stripped = command;
|
|
14170
|
-
let previous;
|
|
14171
|
-
do {
|
|
14172
|
-
previous = stripped;
|
|
14173
|
-
let beforeUnwrap;
|
|
14174
|
-
do {
|
|
14175
|
-
beforeUnwrap = stripped;
|
|
14176
|
-
stripped = unwrapEnvSplitStringAtBoundary(stripped);
|
|
14177
|
-
} while (stripped !== beforeUnwrap);
|
|
14178
|
-
stripped = stripLauncherAtBoundary(stripped, "env", ENV_VALUE_TAKING);
|
|
14179
|
-
stripped = stripLauncherAtBoundary(stripped, "sudo", SUDO_VALUE_TAKING);
|
|
14180
|
-
} while (stripped !== previous);
|
|
14181
|
-
return stripped;
|
|
14182
|
-
}
|
|
14183
13912
|
var SUDO_VALUE_TAKING = /* @__PURE__ */ new Set([
|
|
14184
13913
|
"-u",
|
|
14185
13914
|
"-g",
|
|
@@ -14221,6 +13950,21 @@ var ENV_FLAG_OPTIONS = /* @__PURE__ */ new Set([
|
|
|
14221
13950
|
"--help",
|
|
14222
13951
|
"--version"
|
|
14223
13952
|
]);
|
|
13953
|
+
function stripTransparentLaunchers(command) {
|
|
13954
|
+
let stripped = command;
|
|
13955
|
+
let previous;
|
|
13956
|
+
do {
|
|
13957
|
+
previous = stripped;
|
|
13958
|
+
let beforeUnwrap;
|
|
13959
|
+
do {
|
|
13960
|
+
beforeUnwrap = stripped;
|
|
13961
|
+
stripped = unwrapEnvSplitStringAtBoundary(stripped);
|
|
13962
|
+
} while (stripped !== beforeUnwrap);
|
|
13963
|
+
stripped = stripLauncherAtBoundary(stripped, "env", ENV_VALUE_TAKING);
|
|
13964
|
+
stripped = stripLauncherAtBoundary(stripped, "sudo", SUDO_VALUE_TAKING);
|
|
13965
|
+
} while (stripped !== previous);
|
|
13966
|
+
return stripped;
|
|
13967
|
+
}
|
|
14224
13968
|
function firstUnquotedShellSeparator(raw, start, end) {
|
|
14225
13969
|
let quote = null;
|
|
14226
13970
|
for (let index = start; index < end; index += 1) {
|
|
@@ -14357,9 +14101,7 @@ function executableCommandSubstitutions(command) {
|
|
|
14357
14101
|
}
|
|
14358
14102
|
const commandSubstitution = char === "$" && command[index + 1] === "(";
|
|
14359
14103
|
const processSubstitution = (char === ">" || char === "<") && command[index + 1] === "(";
|
|
14360
|
-
if (!commandSubstitution && !processSubstitution ||
|
|
14361
|
-
// contents as a shell command substitution.
|
|
14362
|
-
commandSubstitution && command[index + 2] === "(")
|
|
14104
|
+
if (!commandSubstitution && !processSubstitution || commandSubstitution && command[index + 2] === "(")
|
|
14363
14105
|
continue;
|
|
14364
14106
|
let depth = 1;
|
|
14365
14107
|
let innerQuote = null;
|
|
@@ -14807,6 +14549,281 @@ function destructiveTargetsAtDepth(command, depth) {
|
|
|
14807
14549
|
)
|
|
14808
14550
|
];
|
|
14809
14551
|
}
|
|
14552
|
+
|
|
14553
|
+
// src/path-guard/tool-targets.ts
|
|
14554
|
+
var WRITE_CAPABILITIES = /* @__PURE__ */ new Set(["fs.write", "fs.write.outside-project"]);
|
|
14555
|
+
var DISK_MUTATING_CAPABILITIES = /* @__PURE__ */ new Set(["package.install"]);
|
|
14556
|
+
var SHELL_CAPABILITIES = /* @__PURE__ */ new Set(["shell.arbitrary", "shell.restricted", "shell.exec"]);
|
|
14557
|
+
var LEGACY_SHELL_TOOLS = /* @__PURE__ */ new Set(["bash", "shell", "exec"]);
|
|
14558
|
+
var LEGACY_WRITE_TOOLS = /* @__PURE__ */ new Set([
|
|
14559
|
+
"write",
|
|
14560
|
+
"edit",
|
|
14561
|
+
"patch",
|
|
14562
|
+
"scaffold",
|
|
14563
|
+
"format",
|
|
14564
|
+
"replace",
|
|
14565
|
+
"design",
|
|
14566
|
+
"install"
|
|
14567
|
+
]);
|
|
14568
|
+
var PATH_FIELDS = [
|
|
14569
|
+
"path",
|
|
14570
|
+
"file_path",
|
|
14571
|
+
"filePath",
|
|
14572
|
+
"target",
|
|
14573
|
+
"target_path",
|
|
14574
|
+
"targetPath",
|
|
14575
|
+
"destination",
|
|
14576
|
+
"dest",
|
|
14577
|
+
"output_path",
|
|
14578
|
+
"outputPath",
|
|
14579
|
+
"out",
|
|
14580
|
+
"file"
|
|
14581
|
+
];
|
|
14582
|
+
var PATH_LIST_FIELDS = ["files", "paths"];
|
|
14583
|
+
var SOURCE_PATH_FIELDS = [
|
|
14584
|
+
"source",
|
|
14585
|
+
"from",
|
|
14586
|
+
"src",
|
|
14587
|
+
"input_path",
|
|
14588
|
+
"inputPath",
|
|
14589
|
+
"old_path",
|
|
14590
|
+
"oldPath"
|
|
14591
|
+
];
|
|
14592
|
+
var MOVE_TOOL_NAME = /(?:^|[_.-])(move|rename)(?:$|[_.-])/i;
|
|
14593
|
+
var DIRECTORY_DELETE_TOOL_NAME = /(?:^|[_.-])(?:rmdir|(?:delete|remove)[_.-](?:dir|directory))(?:$|[_.-])/i;
|
|
14594
|
+
function segmentedToolName(toolName) {
|
|
14595
|
+
return toolName.replace(/([a-z0-9])([A-Z])/g, "$1_$2");
|
|
14596
|
+
}
|
|
14597
|
+
function isMoveToolName(toolName) {
|
|
14598
|
+
return MOVE_TOOL_NAME.test(segmentedToolName(toolName));
|
|
14599
|
+
}
|
|
14600
|
+
function isDirectoryDeleteToolName(toolName) {
|
|
14601
|
+
return DIRECTORY_DELETE_TOOL_NAME.test(segmentedToolName(toolName));
|
|
14602
|
+
}
|
|
14603
|
+
function cleanPatchPath(raw) {
|
|
14604
|
+
const trimmed = raw.trim();
|
|
14605
|
+
if (!trimmed || trimmed === "/dev/null") return null;
|
|
14606
|
+
const quoted = /^"([^"]+)"(?:\s|$)/.exec(trimmed)?.[1];
|
|
14607
|
+
const withoutTimestamp = quoted ?? trimmed.replace(/(?:\t|\s+)\d{4}-\d{2}-\d{2}(?:\s.*)?$/, "").trim();
|
|
14608
|
+
if (!withoutTimestamp || withoutTimestamp === "/dev/null") return null;
|
|
14609
|
+
return withoutTimestamp.replace(/^[ab]\//, "");
|
|
14610
|
+
}
|
|
14611
|
+
function pathsFromPatch(patch) {
|
|
14612
|
+
const paths = [];
|
|
14613
|
+
const lines = patch.split(/\r?\n/);
|
|
14614
|
+
for (let index = 0; index + 2 < lines.length; index += 1) {
|
|
14615
|
+
const oldHeader = lines[index];
|
|
14616
|
+
const newHeader = lines[index + 1];
|
|
14617
|
+
const hunkHeader = lines[index + 2];
|
|
14618
|
+
if (!oldHeader?.startsWith("--- ") || !newHeader?.startsWith("+++ ")) continue;
|
|
14619
|
+
if (!hunkHeader?.startsWith("@@ ")) continue;
|
|
14620
|
+
const oldPath = cleanPatchPath(oldHeader.slice(4));
|
|
14621
|
+
const newPath = cleanPatchPath(newHeader.slice(4));
|
|
14622
|
+
if (oldPath) paths.push(oldPath);
|
|
14623
|
+
if (newPath) paths.push(newPath);
|
|
14624
|
+
}
|
|
14625
|
+
return paths;
|
|
14626
|
+
}
|
|
14627
|
+
function appendTarget(targets, value, kind, base) {
|
|
14628
|
+
if (typeof value !== "string" || value.length === 0) return;
|
|
14629
|
+
targets.push({
|
|
14630
|
+
path: resolveTargetPath(value, base),
|
|
14631
|
+
kind
|
|
14632
|
+
});
|
|
14633
|
+
}
|
|
14634
|
+
function appendTargetList(targets, value, directoryCapable, base) {
|
|
14635
|
+
const appendPath = (path) => {
|
|
14636
|
+
targets.push({
|
|
14637
|
+
path: resolveTargetPath(path, base),
|
|
14638
|
+
kind: isUnresolvedPathScope(path) || isRootPathScope(path) || directoryCapable && isDirectoryAmbiguousPath(path) ? "scope" : "file"
|
|
14639
|
+
});
|
|
14640
|
+
};
|
|
14641
|
+
if (typeof value === "string") {
|
|
14642
|
+
const paths = value.split(",").map((item) => item.trim()).filter((path) => path.length > 0);
|
|
14643
|
+
for (const path of paths) appendPath(path);
|
|
14644
|
+
return;
|
|
14645
|
+
}
|
|
14646
|
+
if (!Array.isArray(value)) return;
|
|
14647
|
+
for (const item of value) {
|
|
14648
|
+
if (typeof item !== "string") continue;
|
|
14649
|
+
const path = item.trim();
|
|
14650
|
+
if (path.length > 0) appendPath(path);
|
|
14651
|
+
}
|
|
14652
|
+
}
|
|
14653
|
+
function isReadOnlyInvocation(toolName, toolInput) {
|
|
14654
|
+
if (toolName === "git") {
|
|
14655
|
+
const command = toolInput["command"];
|
|
14656
|
+
if (command === "status" || command === "log" || command === "diff" || command === "fetch" || command === "commit" || command === "branch" || command === "push") {
|
|
14657
|
+
return true;
|
|
14658
|
+
}
|
|
14659
|
+
return command === "worktree" && toolInput["worktreeAction"] === "list";
|
|
14660
|
+
}
|
|
14661
|
+
if (toolName === "design") {
|
|
14662
|
+
const action = toolInput["action"] ?? "list";
|
|
14663
|
+
return action === "list" || action === "foundations" || action === "verify";
|
|
14664
|
+
}
|
|
14665
|
+
if (toolName === "format") return toolInput["check"] === true;
|
|
14666
|
+
if (toolName === "patch" || toolName === "scaffold") return toolInput["dry_run"] === true;
|
|
14667
|
+
if (toolName === "replace") return toolInput["dry_run"] !== false;
|
|
14668
|
+
return false;
|
|
14669
|
+
}
|
|
14670
|
+
function writesToDisk(input) {
|
|
14671
|
+
const capabilities = input.toolCapabilities;
|
|
14672
|
+
const capabilitiesUndeclared = !capabilities || capabilities.length === 0;
|
|
14673
|
+
const hasWriteCap = capabilities?.some((capability) => WRITE_CAPABILITIES.has(capability)) ?? false;
|
|
14674
|
+
const hasDiskMutatingCap = capabilities?.some((capability) => DISK_MUTATING_CAPABILITIES.has(capability)) ?? false;
|
|
14675
|
+
const hasCommandString = typeof input.toolInput?.["command"] === "string";
|
|
14676
|
+
if (hasCommandString && executesShell(input) && !hasWriteCap && !hasDiskMutatingCap && !(capabilitiesUndeclared && LEGACY_WRITE_TOOLS.has(input.toolName ?? "")))
|
|
14677
|
+
return false;
|
|
14678
|
+
if (!capabilitiesUndeclared) {
|
|
14679
|
+
if (hasWriteCap || hasDiskMutatingCap) return true;
|
|
14680
|
+
if (capabilities.includes("mcp.proxy")) {
|
|
14681
|
+
const segmentedName = (input.toolName ?? "").replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^a-z0-9]+/gi, "_").toLowerCase();
|
|
14682
|
+
const filesystemWriter = /(?:^|_)filesystem(?:_|$)/.test(segmentedName) && /(?:^|_)(?:add|append|copy|create|delete|edit|mkdir|move|remove|rename|write)(?:_|$)/.test(
|
|
14683
|
+
segmentedName
|
|
14684
|
+
);
|
|
14685
|
+
const toolInput = input.toolInput ?? {};
|
|
14686
|
+
const hasKnownPath = [...PATH_FIELDS, ...PATH_LIST_FIELDS].some(
|
|
14687
|
+
(field) => toolInput[field] !== void 0
|
|
14688
|
+
);
|
|
14689
|
+
if (filesystemWriter && hasKnownPath) return true;
|
|
14690
|
+
}
|
|
14691
|
+
return false;
|
|
14692
|
+
}
|
|
14693
|
+
if (input.toolMutating !== void 0) return input.toolMutating;
|
|
14694
|
+
return LEGACY_WRITE_TOOLS.has(input.toolName ?? "");
|
|
14695
|
+
}
|
|
14696
|
+
function executesShell(input) {
|
|
14697
|
+
const toolName = input.toolName ?? "";
|
|
14698
|
+
if (LEGACY_SHELL_TOOLS.has(toolName)) return true;
|
|
14699
|
+
if (toolName === "git") return false;
|
|
14700
|
+
const segmentedName = toolName.replace(/([a-z0-9])([A-Z])/g, "$1_$2");
|
|
14701
|
+
const isCommandStringRunner = /(?:^|[_.-])(?:command|exec|execute|shell|terminal)(?:$|[_.-])/i.test(segmentedName);
|
|
14702
|
+
const hasShellCapability = input.toolCapabilities?.some((capability) => SHELL_CAPABILITIES.has(capability)) ?? false;
|
|
14703
|
+
const hasCommandString = typeof input.toolInput?.["command"] === "string";
|
|
14704
|
+
return isCommandStringRunner && hasShellCapability || hasCommandString && input.toolMutating === true;
|
|
14705
|
+
}
|
|
14706
|
+
function pathsFromToolInput(toolInput, toolName, invocationCwd) {
|
|
14707
|
+
const targets = [];
|
|
14708
|
+
const effectiveCwd = effectiveToolCwd(toolInput["cwd"], invocationCwd);
|
|
14709
|
+
const directoryDelete = isDirectoryDeleteToolName(toolName);
|
|
14710
|
+
for (const field of PATH_FIELDS) {
|
|
14711
|
+
const value = toolInput[field];
|
|
14712
|
+
appendTarget(
|
|
14713
|
+
targets,
|
|
14714
|
+
value,
|
|
14715
|
+
directoryDelete ? "deletion-scope" : typeof value === "string" && isUnresolvedPathScope(value) ? "scope" : "file",
|
|
14716
|
+
effectiveCwd
|
|
14717
|
+
);
|
|
14718
|
+
}
|
|
14719
|
+
const directoryCapableLists = toolName === "format" || toolName === "replace";
|
|
14720
|
+
for (const field of PATH_LIST_FIELDS) {
|
|
14721
|
+
appendTargetList(
|
|
14722
|
+
targets,
|
|
14723
|
+
toolInput[field],
|
|
14724
|
+
directoryCapableLists && field === "files",
|
|
14725
|
+
effectiveCwd
|
|
14726
|
+
);
|
|
14727
|
+
}
|
|
14728
|
+
if (toolName === "install") {
|
|
14729
|
+
appendTarget(targets, effectiveCwd ?? invocationCwd ?? ".", "scope");
|
|
14730
|
+
}
|
|
14731
|
+
if (toolName === "git") {
|
|
14732
|
+
const command = toolInput["command"];
|
|
14733
|
+
if (command === "worktree" && (toolInput["worktreeAction"] === "add" || toolInput["worktreeAction"] === "remove")) {
|
|
14734
|
+
appendTarget(targets, toolInput["worktreePath"] ?? toolInput["worktree_path"], "file");
|
|
14735
|
+
}
|
|
14736
|
+
}
|
|
14737
|
+
if (toolName === "scaffold") {
|
|
14738
|
+
const cwdValue = toolInput["cwd"];
|
|
14739
|
+
const cwd = typeof cwdValue === "string" && cwdValue.length > 0 ? cwdValue : invocationCwd ?? ".";
|
|
14740
|
+
const base = normalizePath2(cwd).replace(/\/$/, "");
|
|
14741
|
+
const name = typeof toolInput["name"] === "string" ? toolInput["name"] : "";
|
|
14742
|
+
const template = toolInput["template"];
|
|
14743
|
+
const filesByTemplate = {
|
|
14744
|
+
"npm-package": ["package.json", "tsconfig.json", "src/index.ts", "src/index.test.ts"],
|
|
14745
|
+
"cli-tool": ["package.json", "src/index.ts"],
|
|
14746
|
+
"react-component": name ? [`${name}.tsx`, `${name}.test.tsx`] : []
|
|
14747
|
+
};
|
|
14748
|
+
for (const file of typeof template === "string" ? filesByTemplate[template] ?? [] : []) {
|
|
14749
|
+
targets.push({ path: `${base}/${file}`, kind: "file" });
|
|
14750
|
+
}
|
|
14751
|
+
targets.push({ path: base, kind: "scope" });
|
|
14752
|
+
}
|
|
14753
|
+
if (isMoveToolName(toolName)) {
|
|
14754
|
+
for (const field of SOURCE_PATH_FIELDS) {
|
|
14755
|
+
appendTarget(targets, toolInput[field], "deletion-scope", effectiveCwd);
|
|
14756
|
+
}
|
|
14757
|
+
}
|
|
14758
|
+
const patch = toolInput["patch"];
|
|
14759
|
+
if (typeof patch === "string") {
|
|
14760
|
+
const patchTargets = pathsFromPatch(patch);
|
|
14761
|
+
const directory = toolInput["directory"];
|
|
14762
|
+
const baseValue = typeof directory === "string" && directory.length > 0 ? directory : invocationCwd;
|
|
14763
|
+
if (baseValue) {
|
|
14764
|
+
const base = normalizePath2(baseValue).replace(/\/$/, "");
|
|
14765
|
+
targets.push(
|
|
14766
|
+
...patchTargets.map((target) => ({ path: `${base}/${target}`, kind: "file" }))
|
|
14767
|
+
);
|
|
14768
|
+
} else {
|
|
14769
|
+
targets.push(...patchTargets.map((path) => ({ path, kind: "file" })));
|
|
14770
|
+
}
|
|
14771
|
+
}
|
|
14772
|
+
if (targets.length === 0) {
|
|
14773
|
+
const cwd = effectiveCwd ?? ".";
|
|
14774
|
+
targets.push({ path: normalizePath2(cwd).replace(/\/$/, "") || ".", kind: "scope" });
|
|
14775
|
+
}
|
|
14776
|
+
const seen = /* @__PURE__ */ new Set();
|
|
14777
|
+
return targets.map((target) => ({
|
|
14778
|
+
...target,
|
|
14779
|
+
path: relativeToInvocationCwd(target.path, invocationCwd)
|
|
14780
|
+
})).filter((target) => {
|
|
14781
|
+
const key = `${target.kind}:${target.path}`;
|
|
14782
|
+
if (seen.has(key)) return false;
|
|
14783
|
+
seen.add(key);
|
|
14784
|
+
return true;
|
|
14785
|
+
});
|
|
14786
|
+
}
|
|
14787
|
+
function operationLabel(toolName) {
|
|
14788
|
+
if (toolName === "write") return "write";
|
|
14789
|
+
if (toolName === "edit") return "edit";
|
|
14790
|
+
return `write via "${toolName}"`;
|
|
14791
|
+
}
|
|
14792
|
+
|
|
14793
|
+
// src/path-guard/index.ts
|
|
14794
|
+
function createState() {
|
|
14795
|
+
return { invocations: 0, blocks: 0, warns: 0, lastBlock: null, hookUnregister: null };
|
|
14796
|
+
}
|
|
14797
|
+
var states = /* @__PURE__ */ new WeakMap();
|
|
14798
|
+
var latestState = createState();
|
|
14799
|
+
var DEFAULT_PROTECT = [
|
|
14800
|
+
"pnpm-lock.yaml",
|
|
14801
|
+
"package-lock.json",
|
|
14802
|
+
"yarn.lock",
|
|
14803
|
+
"bun.lockb",
|
|
14804
|
+
"Cargo.lock",
|
|
14805
|
+
"poetry.lock",
|
|
14806
|
+
".env",
|
|
14807
|
+
".env.*",
|
|
14808
|
+
".git/**",
|
|
14809
|
+
"**/migrations/**"
|
|
14810
|
+
];
|
|
14811
|
+
var DEFAULTS33 = {
|
|
14812
|
+
enabled: true,
|
|
14813
|
+
mode: "block",
|
|
14814
|
+
protect: DEFAULT_PROTECT,
|
|
14815
|
+
allow: []
|
|
14816
|
+
};
|
|
14817
|
+
function readConfig34(raw) {
|
|
14818
|
+
if (!raw || typeof raw !== "object") return { ...DEFAULTS33, protect: [...DEFAULT_PROTECT] };
|
|
14819
|
+
const r = raw;
|
|
14820
|
+
return {
|
|
14821
|
+
enabled: r["enabled"] !== false,
|
|
14822
|
+
mode: r["mode"] === "warn" ? "warn" : "block",
|
|
14823
|
+
protect: Array.isArray(r["protect"]) ? r["protect"].filter((p) => typeof p === "string" && p.length > 0) : [...DEFAULT_PROTECT],
|
|
14824
|
+
allow: Array.isArray(r["allow"]) ? r["allow"].filter((p) => typeof p === "string" && p.length > 0) : []
|
|
14825
|
+
};
|
|
14826
|
+
}
|
|
14810
14827
|
var plugin39 = {
|
|
14811
14828
|
name: "path-guard",
|
|
14812
14829
|
version: "0.1.0",
|