@staff0rd/assist 0.184.0 → 0.184.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/index.js +87 -82
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { Command } from "commander";
|
|
|
6
6
|
// package.json
|
|
7
7
|
var package_default = {
|
|
8
8
|
name: "@staff0rd/assist",
|
|
9
|
-
version: "0.184.
|
|
9
|
+
version: "0.184.1",
|
|
10
10
|
type: "module",
|
|
11
11
|
main: "dist/index.js",
|
|
12
12
|
bin: {
|
|
@@ -4591,6 +4591,70 @@ function registerBacklog(program2) {
|
|
|
4591
4591
|
registerUpdateCommands(cmd);
|
|
4592
4592
|
}
|
|
4593
4593
|
|
|
4594
|
+
// src/shared/splitCompound.ts
|
|
4595
|
+
import { parse } from "shell-quote";
|
|
4596
|
+
|
|
4597
|
+
// src/shared/hasUnquotedBackticks.ts
|
|
4598
|
+
var QUOTED_OR_BACKTICK_RE = /\\.|'[^']*'|"[^"]*"|(`)/g;
|
|
4599
|
+
function hasUnquotedBackticks(command) {
|
|
4600
|
+
QUOTED_OR_BACKTICK_RE.lastIndex = 0;
|
|
4601
|
+
for (let m = QUOTED_OR_BACKTICK_RE.exec(command); m !== null; m = QUOTED_OR_BACKTICK_RE.exec(command)) {
|
|
4602
|
+
if (m[1] !== void 0) return true;
|
|
4603
|
+
}
|
|
4604
|
+
return false;
|
|
4605
|
+
}
|
|
4606
|
+
|
|
4607
|
+
// src/shared/splitCompound.ts
|
|
4608
|
+
var SEPARATOR_OPS = /* @__PURE__ */ new Set(["|", "&&", "||", ";"]);
|
|
4609
|
+
var UNSAFE_OPS = /* @__PURE__ */ new Set(["(", ")", ">", ">>", "<", "<&", "|&", ">&"]);
|
|
4610
|
+
var FD_REDIRECT_RE = /\d+>&\d+/g;
|
|
4611
|
+
var FD_DEVNULL_RE = /\d*>\/dev\/null/g;
|
|
4612
|
+
function splitCompound(command) {
|
|
4613
|
+
const tokens = tokenizeCommand(command);
|
|
4614
|
+
if (!tokens) return void 0;
|
|
4615
|
+
const groups = groupByOperator(tokens);
|
|
4616
|
+
if (!groups) return void 0;
|
|
4617
|
+
const result = groups.map((parts) => stripEnvPrefix(parts).join(" ")).filter((cmd) => cmd !== "");
|
|
4618
|
+
return result.length > 0 ? result : void 0;
|
|
4619
|
+
}
|
|
4620
|
+
function tokenizeCommand(command) {
|
|
4621
|
+
const trimmed = command.trim().replace(FD_DEVNULL_RE, "").replace(FD_REDIRECT_RE, "");
|
|
4622
|
+
if (!trimmed) return void 0;
|
|
4623
|
+
if (hasUnquotedBackticks(trimmed)) return void 0;
|
|
4624
|
+
try {
|
|
4625
|
+
return parse(trimmed);
|
|
4626
|
+
} catch {
|
|
4627
|
+
return void 0;
|
|
4628
|
+
}
|
|
4629
|
+
}
|
|
4630
|
+
function getOp(token) {
|
|
4631
|
+
return typeof token === "object" && token !== null && "op" in token ? token.op : void 0;
|
|
4632
|
+
}
|
|
4633
|
+
function groupByOperator(tokens) {
|
|
4634
|
+
const groups = [[]];
|
|
4635
|
+
for (const token of tokens) {
|
|
4636
|
+
const op = getOp(token);
|
|
4637
|
+
if (op === void 0) {
|
|
4638
|
+
if (typeof token !== "string") return void 0;
|
|
4639
|
+
groups[groups.length - 1].push(token);
|
|
4640
|
+
} else if (op === "glob") {
|
|
4641
|
+
groups[groups.length - 1].push(token.pattern);
|
|
4642
|
+
} else if (SEPARATOR_OPS.has(op)) {
|
|
4643
|
+
groups.push([]);
|
|
4644
|
+
} else if (UNSAFE_OPS.has(op)) {
|
|
4645
|
+
return void 0;
|
|
4646
|
+
} else {
|
|
4647
|
+
return void 0;
|
|
4648
|
+
}
|
|
4649
|
+
}
|
|
4650
|
+
return groups;
|
|
4651
|
+
}
|
|
4652
|
+
function stripEnvPrefix(parts) {
|
|
4653
|
+
let i = 0;
|
|
4654
|
+
while (i < parts.length && /^[A-Za-z_]\w*=/.test(parts[i])) i++;
|
|
4655
|
+
return i > 0 ? parts.slice(i) : parts;
|
|
4656
|
+
}
|
|
4657
|
+
|
|
4594
4658
|
// src/shared/isApprovedRead.ts
|
|
4595
4659
|
import { resolve as resolve3 } from "path";
|
|
4596
4660
|
|
|
@@ -4761,8 +4825,8 @@ var denyCache;
|
|
|
4761
4825
|
var TOOL_RE = /^(Bash|PowerShell)\((.+?)(:.*)?\)$/;
|
|
4762
4826
|
var SHELL_TOOLS = ["Bash", "PowerShell"];
|
|
4763
4827
|
var DOTSLASH_RE = /^\.[\\/]/;
|
|
4764
|
-
var
|
|
4765
|
-
var
|
|
4828
|
+
var FD_REDIRECT_RE2 = /\d+>&\d+/g;
|
|
4829
|
+
var FD_DEVNULL_RE2 = /\d*>\/dev\/null/g;
|
|
4766
4830
|
function loadPerms(key) {
|
|
4767
4831
|
return parsePerms(readSettingsPerms(key));
|
|
4768
4832
|
}
|
|
@@ -4773,7 +4837,7 @@ function shellEntries(map, toolName) {
|
|
|
4773
4837
|
return map.get(toolName) ?? [];
|
|
4774
4838
|
}
|
|
4775
4839
|
function normCmd(cmd) {
|
|
4776
|
-
return cmd.replace(
|
|
4840
|
+
return cmd.replace(FD_DEVNULL_RE2, "").replace(FD_REDIRECT_RE2, "").trim().replace(DOTSLASH_RE, "");
|
|
4777
4841
|
}
|
|
4778
4842
|
function findMatch2(entries, command) {
|
|
4779
4843
|
const norm = normCmd(command);
|
|
@@ -4838,72 +4902,7 @@ function matchesConfigDeny(command) {
|
|
|
4838
4902
|
);
|
|
4839
4903
|
}
|
|
4840
4904
|
|
|
4841
|
-
// src/
|
|
4842
|
-
import { parse } from "shell-quote";
|
|
4843
|
-
|
|
4844
|
-
// src/shared/hasUnquotedBackticks.ts
|
|
4845
|
-
var QUOTED_OR_BACKTICK_RE = /\\.|'[^']*'|"[^"]*"|(`)/g;
|
|
4846
|
-
function hasUnquotedBackticks(command) {
|
|
4847
|
-
QUOTED_OR_BACKTICK_RE.lastIndex = 0;
|
|
4848
|
-
for (let m = QUOTED_OR_BACKTICK_RE.exec(command); m !== null; m = QUOTED_OR_BACKTICK_RE.exec(command)) {
|
|
4849
|
-
if (m[1] !== void 0) return true;
|
|
4850
|
-
}
|
|
4851
|
-
return false;
|
|
4852
|
-
}
|
|
4853
|
-
|
|
4854
|
-
// src/shared/splitCompound.ts
|
|
4855
|
-
var SEPARATOR_OPS = /* @__PURE__ */ new Set(["|", "&&", "||", ";"]);
|
|
4856
|
-
var UNSAFE_OPS = /* @__PURE__ */ new Set(["(", ")", ">", ">>", "<", "<&", "|&", ">&"]);
|
|
4857
|
-
var FD_REDIRECT_RE2 = /\d+>&\d+/g;
|
|
4858
|
-
var FD_DEVNULL_RE2 = /\d*>\/dev\/null/g;
|
|
4859
|
-
function splitCompound(command) {
|
|
4860
|
-
const tokens = tokenizeCommand(command);
|
|
4861
|
-
if (!tokens) return void 0;
|
|
4862
|
-
const groups = groupByOperator(tokens);
|
|
4863
|
-
if (!groups) return void 0;
|
|
4864
|
-
const result = groups.map((parts) => stripEnvPrefix(parts).join(" ")).filter((cmd) => cmd !== "");
|
|
4865
|
-
return result.length > 0 ? result : void 0;
|
|
4866
|
-
}
|
|
4867
|
-
function tokenizeCommand(command) {
|
|
4868
|
-
const trimmed = command.trim().replace(FD_DEVNULL_RE2, "").replace(FD_REDIRECT_RE2, "");
|
|
4869
|
-
if (!trimmed) return void 0;
|
|
4870
|
-
if (hasUnquotedBackticks(trimmed)) return void 0;
|
|
4871
|
-
try {
|
|
4872
|
-
return parse(trimmed);
|
|
4873
|
-
} catch {
|
|
4874
|
-
return void 0;
|
|
4875
|
-
}
|
|
4876
|
-
}
|
|
4877
|
-
function getOp(token) {
|
|
4878
|
-
return typeof token === "object" && token !== null && "op" in token ? token.op : void 0;
|
|
4879
|
-
}
|
|
4880
|
-
function groupByOperator(tokens) {
|
|
4881
|
-
const groups = [[]];
|
|
4882
|
-
for (const token of tokens) {
|
|
4883
|
-
const op = getOp(token);
|
|
4884
|
-
if (op === void 0) {
|
|
4885
|
-
if (typeof token !== "string") return void 0;
|
|
4886
|
-
groups[groups.length - 1].push(token);
|
|
4887
|
-
} else if (op === "glob") {
|
|
4888
|
-
groups[groups.length - 1].push(token.pattern);
|
|
4889
|
-
} else if (SEPARATOR_OPS.has(op)) {
|
|
4890
|
-
groups.push([]);
|
|
4891
|
-
} else if (UNSAFE_OPS.has(op)) {
|
|
4892
|
-
return void 0;
|
|
4893
|
-
} else {
|
|
4894
|
-
return void 0;
|
|
4895
|
-
}
|
|
4896
|
-
}
|
|
4897
|
-
return groups;
|
|
4898
|
-
}
|
|
4899
|
-
function stripEnvPrefix(parts) {
|
|
4900
|
-
let i = 0;
|
|
4901
|
-
while (i < parts.length && /^[A-Za-z_]\w*=/.test(parts[i])) i++;
|
|
4902
|
-
return i > 0 ? parts.slice(i) : parts;
|
|
4903
|
-
}
|
|
4904
|
-
|
|
4905
|
-
// src/commands/cliHook/index.ts
|
|
4906
|
-
var SUPPORTED_TOOLS = /* @__PURE__ */ new Set(["Bash", "PowerShell"]);
|
|
4905
|
+
// src/commands/cliHook/resolvePermission.ts
|
|
4907
4906
|
function findDeny(toolName, parts) {
|
|
4908
4907
|
for (const part of parts) {
|
|
4909
4908
|
const configDeny = matchesConfigDeny(part);
|
|
@@ -4939,25 +4938,31 @@ function resolvePermission(toolName, parts) {
|
|
|
4939
4938
|
permissionDecisionReason: reasons.join("; ")
|
|
4940
4939
|
};
|
|
4941
4940
|
}
|
|
4942
|
-
|
|
4941
|
+
|
|
4942
|
+
// src/commands/cliHook/index.ts
|
|
4943
|
+
var SUPPORTED_TOOLS = /* @__PURE__ */ new Set(["Bash", "PowerShell"]);
|
|
4944
|
+
function tryParseInput(raw) {
|
|
4943
4945
|
try {
|
|
4944
|
-
|
|
4946
|
+
const data = JSON.parse(raw);
|
|
4947
|
+
if (!SUPPORTED_TOOLS.has(data.tool_name) || !data.tool_input?.command)
|
|
4948
|
+
return void 0;
|
|
4949
|
+
return {
|
|
4950
|
+
toolName: data.tool_name,
|
|
4951
|
+
command: data.tool_input.command.trim()
|
|
4952
|
+
};
|
|
4945
4953
|
} catch {
|
|
4946
4954
|
return void 0;
|
|
4947
4955
|
}
|
|
4948
4956
|
}
|
|
4949
|
-
function
|
|
4950
|
-
|
|
4951
|
-
|
|
4952
|
-
|
|
4953
|
-
return parts ? { toolName: data.tool_name, parts } : void 0;
|
|
4957
|
+
function decide(toolName, rawCommand) {
|
|
4958
|
+
const parts = splitCompound(rawCommand);
|
|
4959
|
+
if (parts) return resolvePermission(toolName, parts);
|
|
4960
|
+
return findDeny(toolName, [rawCommand]);
|
|
4954
4961
|
}
|
|
4955
4962
|
async function cliHook() {
|
|
4956
|
-
const
|
|
4957
|
-
if (!
|
|
4958
|
-
const
|
|
4959
|
-
if (!cmd) return;
|
|
4960
|
-
const decision = resolvePermission(cmd.toolName, cmd.parts);
|
|
4963
|
+
const input = tryParseInput(await readStdin());
|
|
4964
|
+
if (!input) return;
|
|
4965
|
+
const decision = decide(input.toolName, input.command);
|
|
4961
4966
|
if (!decision) return;
|
|
4962
4967
|
console.log(
|
|
4963
4968
|
JSON.stringify({
|