@mars-sea/dsh-commandcode-provider 0.11.12 → 0.11.13
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/CHANGELOG.md +12 -0
- package/README.md +19 -19
- package/README.zh-CN.md +19 -19
- package/lib/client.js +2028 -1731
- package/lib/client.js.map +1 -1
- package/lib/index.d.ts +16 -11
- package/lib/index.js +154 -68
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
package/lib/index.d.ts
CHANGED
|
@@ -738,6 +738,16 @@ declare class CommandCodeAccountPool {
|
|
|
738
738
|
private pick;
|
|
739
739
|
}
|
|
740
740
|
//#endregion
|
|
741
|
+
//#region src/command-guard.d.ts
|
|
742
|
+
/**
|
|
743
|
+
* The auto-approve strictness a user picks (`Config.commandGuardLevel`). Each
|
|
744
|
+
* level is the probability every verdict must reach before the guard grants
|
|
745
|
+
* `allowed-once`; a higher level approves less, on stronger evidence. Three
|
|
746
|
+
* presets replace a free-form probability because the useful range is narrow
|
|
747
|
+
* and a hand-typed 0.6 silently turns the guard into a rubber stamp.
|
|
748
|
+
*/
|
|
749
|
+
type CommandGuardLevel = 'high' | 'medium' | 'low';
|
|
750
|
+
//#endregion
|
|
741
751
|
//#region src/capabilities.d.ts
|
|
742
752
|
/**
|
|
743
753
|
* Static capability snapshot for the Command Code provider: model →
|
|
@@ -1915,23 +1925,18 @@ interface Config {
|
|
|
1915
1925
|
* opt-in, and the command text (plus the agent's own description of it) is
|
|
1916
1926
|
* sent to Command Code to judge. Only commands a policy already wanted a
|
|
1917
1927
|
* human to look at are ever judged, and only a confident "safe" verdict
|
|
1918
|
-
* (`
|
|
1928
|
+
* (`commandGuardLevel`) skips the prompt — every other outcome, including
|
|
1919
1929
|
* any failure of the decision call itself, delegates to the normal approval
|
|
1920
1930
|
* flow. See `./command-guard.ts`.
|
|
1921
1931
|
*/
|
|
1922
1932
|
commandGuard?: boolean;
|
|
1923
1933
|
/**
|
|
1924
|
-
*
|
|
1925
|
-
*
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
/**
|
|
1929
|
-
* Milliseconds the guard waits for a decision before falling back to the
|
|
1930
|
-
* human prompt; defaults to 1500. This is a latency budget for an interactive
|
|
1931
|
-
* approval, not a request timeout — a decision that arrives late is useless,
|
|
1932
|
-
* because the user is staring at a prompt.
|
|
1934
|
+
* How confident every verdict must be before the guard skips the approval
|
|
1935
|
+
* prompt: `high` (0.95), `medium` (0.9, the default) or `low` (0.8). A lower
|
|
1936
|
+
* level approves more, on less evidence. The decision budget is fixed
|
|
1937
|
+
* (`COMMAND_GUARD_TIMEOUT_MS`), so this is the guard's only tuning knob.
|
|
1933
1938
|
*/
|
|
1934
|
-
|
|
1939
|
+
commandGuardLevel?: CommandGuardLevel;
|
|
1935
1940
|
/**
|
|
1936
1941
|
* Whether requests enforce zero data retention: the provider then routes
|
|
1937
1942
|
* them only through upstreams that keep no prompts/completions and never
|
package/lib/index.js
CHANGED
|
@@ -6950,8 +6950,8 @@ function buildCommandCodeTuiSection(deps) {
|
|
|
6950
6950
|
kind: "boolean",
|
|
6951
6951
|
label: "AI command guard",
|
|
6952
6952
|
descriptions: { zh: "AI 命令安全预判" },
|
|
6953
|
-
hint: "typesafe/jev judges whether a shell command is safe and
|
|
6954
|
-
hintDescriptions: { zh: "由 typesafe/jev 判断 shell
|
|
6953
|
+
hint: "typesafe/jev judges whether a shell command is safe; sandbox escalations also need separate scope and necessity verdicts. All must be confident enough; everything else asks as usual. Off by default.",
|
|
6954
|
+
hintDescriptions: { zh: "由 typesafe/jev 判断 shell 命令是否安全;沙箱提权还要分别判断范围与必要性,三项都足够确定才自动放行,其余照常弹窗。默认关闭。" },
|
|
6955
6955
|
format: (value) => value === true ? "true" : "false",
|
|
6956
6956
|
parse: (text) => ({
|
|
6957
6957
|
kind: "set",
|
|
@@ -6959,38 +6959,36 @@ function buildCommandCodeTuiSection(deps) {
|
|
|
6959
6959
|
})
|
|
6960
6960
|
},
|
|
6961
6961
|
{
|
|
6962
|
-
path: ["
|
|
6962
|
+
path: ["commandGuardLevel"],
|
|
6963
6963
|
group: "advanced",
|
|
6964
|
-
kind: "
|
|
6965
|
-
label: "Auto-approve threshold
|
|
6966
|
-
descriptions: { zh: "
|
|
6967
|
-
hint: "
|
|
6968
|
-
hintDescriptions: { zh: "typesafe/jev
|
|
6969
|
-
|
|
6970
|
-
|
|
6971
|
-
|
|
6972
|
-
|
|
6973
|
-
|
|
6974
|
-
|
|
6975
|
-
|
|
6976
|
-
|
|
6977
|
-
|
|
6978
|
-
|
|
6979
|
-
|
|
6980
|
-
|
|
6981
|
-
|
|
6982
|
-
|
|
6983
|
-
|
|
6984
|
-
|
|
6985
|
-
|
|
6986
|
-
|
|
6964
|
+
kind: "select",
|
|
6965
|
+
label: "Auto-approve threshold",
|
|
6966
|
+
descriptions: { zh: "自动放行阈值" },
|
|
6967
|
+
hint: "How confident typesafe/jev must be before a command runs without asking. Default: medium.",
|
|
6968
|
+
hintDescriptions: { zh: "typesafe/jev 需要多确定才免弹窗放行;默认「中」。" },
|
|
6969
|
+
options: [
|
|
6970
|
+
{
|
|
6971
|
+
value: "high",
|
|
6972
|
+
label: "High (0.95, approves least)",
|
|
6973
|
+
descriptions: { zh: "高(0.95,放行最少)" }
|
|
6974
|
+
},
|
|
6975
|
+
{
|
|
6976
|
+
value: "medium",
|
|
6977
|
+
label: "Medium (0.9)",
|
|
6978
|
+
descriptions: { zh: "中(0.9)" }
|
|
6979
|
+
},
|
|
6980
|
+
{
|
|
6981
|
+
value: "low",
|
|
6982
|
+
label: "Low (0.8, approves most)",
|
|
6983
|
+
descriptions: { zh: "低(0.8,放行最多)" }
|
|
6984
|
+
}
|
|
6985
|
+
],
|
|
6986
|
+
format: (value) => value === "high" || value === "low" ? value : "medium",
|
|
6987
6987
|
parse: (text) => {
|
|
6988
6988
|
const trimmed = text.trim();
|
|
6989
|
-
|
|
6990
|
-
const parsed = Number(trimmed);
|
|
6991
|
-
return Number.isFinite(parsed) && parsed >= 200 && parsed <= 1e4 ? {
|
|
6989
|
+
return trimmed === "high" || trimmed === "medium" || trimmed === "low" ? {
|
|
6992
6990
|
kind: "set",
|
|
6993
|
-
value:
|
|
6991
|
+
value: trimmed
|
|
6994
6992
|
} : void 0;
|
|
6995
6993
|
}
|
|
6996
6994
|
},
|
|
@@ -7311,8 +7309,6 @@ function transportBudgetMessage(failureMessage, maxRetries) {
|
|
|
7311
7309
|
*/
|
|
7312
7310
|
/** Path of the decision endpoint, relative to `apiBase`. */
|
|
7313
7311
|
const SYSTEMONE_ROUTE = "/provider/v1/systemone";
|
|
7314
|
-
/** Milliseconds a decision may take before the caller gives up on it. */
|
|
7315
|
-
const SYSTEMONE_DEFAULT_TIMEOUT_MS = 1500;
|
|
7316
7312
|
/** The one error type this client throws. Callers fail closed on it. */
|
|
7317
7313
|
var SystemOneError = class extends Error {
|
|
7318
7314
|
kind;
|
|
@@ -7570,13 +7566,40 @@ async function runSystemOne(deps, request, options = {}) {
|
|
|
7570
7566
|
//#region src/command-guard.ts
|
|
7571
7567
|
/** Tool names whose `arguments.command` this guard judges. */
|
|
7572
7568
|
const COMMAND_GUARD_SHELL_TOOLS = ["bash", "pwsh"];
|
|
7573
|
-
/** Question id the safety verdict is keyed by. */
|
|
7569
|
+
/** Question id the primary safety verdict is keyed by. */
|
|
7574
7570
|
const COMMAND_GUARD_QUESTION_ID = "safe";
|
|
7575
|
-
/**
|
|
7576
|
-
const
|
|
7577
|
-
/**
|
|
7578
|
-
const
|
|
7579
|
-
|
|
7571
|
+
/** Question id for the narrow-purpose part of a sandbox escalation. */
|
|
7572
|
+
const COMMAND_GUARD_ESCALATION_SCOPE_QUESTION_ID = "escalation_scope";
|
|
7573
|
+
/** Question id for the necessity/proportionality part of a sandbox escalation. */
|
|
7574
|
+
const COMMAND_GUARD_ESCALATION_NECESSITY_QUESTION_ID = "escalation_necessity";
|
|
7575
|
+
/** The selectable levels, strictest first (the order the settings surfaces list them in). */
|
|
7576
|
+
const COMMAND_GUARD_LEVELS = [
|
|
7577
|
+
"high",
|
|
7578
|
+
"medium",
|
|
7579
|
+
"low"
|
|
7580
|
+
];
|
|
7581
|
+
/** Each level's probability threshold. */
|
|
7582
|
+
const COMMAND_GUARD_LEVEL_THRESHOLDS = {
|
|
7583
|
+
high: .95,
|
|
7584
|
+
medium: .9,
|
|
7585
|
+
low: .8
|
|
7586
|
+
};
|
|
7587
|
+
/** The level an unset config reads as. */
|
|
7588
|
+
const COMMAND_GUARD_DEFAULT_LEVEL = "medium";
|
|
7589
|
+
/** Probability of "safe" at or above which the guard grants `allowed-once` by default. */
|
|
7590
|
+
const COMMAND_GUARD_DEFAULT_THRESHOLD = COMMAND_GUARD_LEVEL_THRESHOLDS[COMMAND_GUARD_DEFAULT_LEVEL];
|
|
7591
|
+
/** The threshold for a stored level; anything unrecognized reads as the default level. */
|
|
7592
|
+
function commandGuardThreshold(level) {
|
|
7593
|
+
return typeof level === "string" && Object.hasOwn(COMMAND_GUARD_LEVEL_THRESHOLDS, level) ? COMMAND_GUARD_LEVEL_THRESHOLDS[level] : COMMAND_GUARD_DEFAULT_THRESHOLD;
|
|
7594
|
+
}
|
|
7595
|
+
/**
|
|
7596
|
+
* Decision budget; the approval prompt must not wait longer than this. Fixed
|
|
7597
|
+
* rather than configurable: it only bounds how long a late verdict can delay
|
|
7598
|
+
* the prompt, and every failure (a timeout included) already falls back to
|
|
7599
|
+
* asking the user, so there is nothing for a user to tune. 3 s leaves room for
|
|
7600
|
+
* credential resolution plus one decision round trip on a slow link.
|
|
7601
|
+
*/
|
|
7602
|
+
const COMMAND_GUARD_TIMEOUT_MS = 3e3;
|
|
7580
7603
|
/**
|
|
7581
7604
|
* Longest command the guard will send for judgement. A longer one is delegated
|
|
7582
7605
|
* instead of truncated: a verdict on the first N characters of a command is a
|
|
@@ -7755,17 +7778,21 @@ function shellCommandOf(name, args) {
|
|
|
7755
7778
|
/**
|
|
7756
7779
|
* Build the decision request for one command.
|
|
7757
7780
|
*
|
|
7758
|
-
*
|
|
7759
|
-
*
|
|
7760
|
-
*
|
|
7761
|
-
*
|
|
7762
|
-
*
|
|
7781
|
+
* A normal approval asks one question. A call that explicitly requests a wider
|
|
7782
|
+
* sandbox gets the same safety question plus two veto questions. This keeps the
|
|
7783
|
+
* common case cheap while making the broader permission change an explicit
|
|
7784
|
+
* decision: JEV must agree that the extra access has a narrow purpose and is
|
|
7785
|
+
* necessary, not merely that the command text looks familiar.
|
|
7786
|
+
*
|
|
7787
|
+
* The agent's own `description` and the harness's `reason` are included as
|
|
7788
|
+
* context, but the criteria say the command text itself decides — a
|
|
7763
7789
|
* model-written description is a claim, not evidence.
|
|
7764
7790
|
*
|
|
7765
7791
|
* @param fact - the command and its context.
|
|
7766
7792
|
* @returns the request to send.
|
|
7767
7793
|
*/
|
|
7768
7794
|
function buildSafetyRequest(fact) {
|
|
7795
|
+
const escalated = fact.sandboxPermissions !== void 0;
|
|
7769
7796
|
const lines = [
|
|
7770
7797
|
`Tool: ${fact.tool}`,
|
|
7771
7798
|
"Command:",
|
|
@@ -7777,24 +7804,43 @@ function buildSafetyRequest(fact) {
|
|
|
7777
7804
|
];
|
|
7778
7805
|
const question = {
|
|
7779
7806
|
type: "noul",
|
|
7780
|
-
instructions: "Is it safe to run this command right now WITHOUT asking the user first? Judge the command text itself; a description is only a claim about it.",
|
|
7807
|
+
instructions: escalated ? "Is it safe to run this command right now WITHOUT asking the user first, including the requested sandbox escalation? Judge the command text itself; a description or stated reason is only a claim about it." : "Is it safe to run this command right now WITHOUT asking the user first? Judge the command text itself; a description is only a claim about it.",
|
|
7781
7808
|
criteria: {
|
|
7782
|
-
true: "Read-only, or its effects stay inside the current project and are trivially reversible: no data leaves the machine, nothing outside the project is modified, and no credentials, git history or remote state are touched.",
|
|
7783
|
-
false: "Anything else.
|
|
7809
|
+
true: escalated ? "A normal, non-obfuscated read, build, or test operation whose outside-workspace effects are limited to conventional build/dependency caches or temporary files and are easily reversible: no unrelated user or system data is accessed, no data leaves the machine, and no credentials, git history or remote state are touched." : "Read-only, or its effects stay inside the current project and are trivially reversible: no data leaves the machine, nothing outside the project is modified, and no credentials, git history or remote state are touched.",
|
|
7810
|
+
false: "Anything else. Broad or unrelated outside-workspace access, deleting or overwriting files outside the project, rewriting or publishing git history, uploading data anywhere, installing system or global packages, changing permissions, ownership or credentials, killing processes, running as another user or as root, piping a download into a shell, or a command obfuscated enough that its effect cannot be read."
|
|
7784
7811
|
}
|
|
7785
7812
|
};
|
|
7813
|
+
const questions = { [COMMAND_GUARD_QUESTION_ID]: question };
|
|
7814
|
+
if (escalated) {
|
|
7815
|
+
questions[COMMAND_GUARD_ESCALATION_SCOPE_QUESTION_ID] = {
|
|
7816
|
+
type: "noul",
|
|
7817
|
+
instructions: "Is the requested wider sandbox access limited to a narrow, conventional purpose supported by this command, such as a build cache, dependency cache, or temporary directory, rather than unrelated user files, credentials, other projects, or the network?",
|
|
7818
|
+
criteria: {
|
|
7819
|
+
true: "The wider access is plausibly limited to conventional local build/dependency caches or temporary files required by the command, with no unrelated host data or remote transfer in scope.",
|
|
7820
|
+
false: "The command needs broad or unrelated host access, cannot establish a narrow purpose, or would use the wider permission to reach credentials, other projects, user files, or the network."
|
|
7821
|
+
}
|
|
7822
|
+
};
|
|
7823
|
+
questions[COMMAND_GUARD_ESCALATION_NECESSITY_QUESTION_ID] = {
|
|
7824
|
+
type: "noul",
|
|
7825
|
+
instructions: "Is the requested sandbox escalation necessary and proportionate for this one command, rather than broader than the command needs? Treat the stated reason as a claim to check against the command, not as proof.",
|
|
7826
|
+
criteria: {
|
|
7827
|
+
true: "The command and its stated purpose support a one-shot escalation that is needed for the task and is no broader than the requested effect requires.",
|
|
7828
|
+
false: "The wider mode is unnecessary, broader than needed, unsupported by the command, or the command is too ambiguous to justify the extra authority."
|
|
7829
|
+
}
|
|
7830
|
+
};
|
|
7831
|
+
}
|
|
7786
7832
|
return {
|
|
7787
7833
|
state: lines.join("\n"),
|
|
7788
|
-
questions
|
|
7834
|
+
questions
|
|
7789
7835
|
};
|
|
7790
7836
|
}
|
|
7791
7837
|
/**
|
|
7792
|
-
* Read
|
|
7838
|
+
* Read a probability out of a decision response.
|
|
7793
7839
|
*
|
|
7794
7840
|
* @param response - the parsed response.
|
|
7795
7841
|
* @param questionId - the question id to read (defaults to the guard's own).
|
|
7796
|
-
* @returns the probability
|
|
7797
|
-
*
|
|
7842
|
+
* @returns the probability, or undefined when the answer is missing or is not
|
|
7843
|
+
* a `noul` verdict.
|
|
7798
7844
|
*/
|
|
7799
7845
|
function safeProbabilityOf(response, questionId = COMMAND_GUARD_QUESTION_ID) {
|
|
7800
7846
|
const answer = response.answers[questionId];
|
|
@@ -7901,7 +7947,7 @@ var CommandGuard = class {
|
|
|
7901
7947
|
const agentDecisions = request.agent === void 0 ? void 0 : this.decisions.get(request.agent);
|
|
7902
7948
|
const memo = agentDecisions?.get(memoKey);
|
|
7903
7949
|
if (memo !== void 0) {
|
|
7904
|
-
if (now - memo.at < 6e5) return this.verdict(memo
|
|
7950
|
+
if (now - memo.at < 6e5) return this.verdict(memo, settings.threshold, "memo", excerpt, full.sandboxPermissions !== void 0);
|
|
7905
7951
|
agentDecisions?.delete(memoKey);
|
|
7906
7952
|
}
|
|
7907
7953
|
let response;
|
|
@@ -7923,12 +7969,28 @@ var CommandGuard = class {
|
|
|
7923
7969
|
reason: "the decision carried no safe verdict",
|
|
7924
7970
|
command: excerpt
|
|
7925
7971
|
};
|
|
7972
|
+
let escalation;
|
|
7973
|
+
if (full.sandboxPermissions !== void 0) {
|
|
7974
|
+
const scope = safeProbabilityOf(response, COMMAND_GUARD_ESCALATION_SCOPE_QUESTION_ID);
|
|
7975
|
+
const necessity = safeProbabilityOf(response, COMMAND_GUARD_ESCALATION_NECESSITY_QUESTION_ID);
|
|
7976
|
+
if (scope === void 0 || necessity === void 0) return {
|
|
7977
|
+
kind: "delegate",
|
|
7978
|
+
reason: "the decision carried no complete sandbox-escalation verdict",
|
|
7979
|
+
command: excerpt
|
|
7980
|
+
};
|
|
7981
|
+
escalation = {
|
|
7982
|
+
scope,
|
|
7983
|
+
necessity
|
|
7984
|
+
};
|
|
7985
|
+
}
|
|
7986
|
+
const memoEntry = {
|
|
7987
|
+
probability,
|
|
7988
|
+
...escalation === void 0 ? {} : { escalation },
|
|
7989
|
+
at: now
|
|
7990
|
+
};
|
|
7926
7991
|
if (request.agent !== void 0) {
|
|
7927
7992
|
const decisions = agentDecisions ?? /* @__PURE__ */ new Map();
|
|
7928
|
-
decisions.set(memoKey,
|
|
7929
|
-
probability,
|
|
7930
|
-
at: now
|
|
7931
|
-
});
|
|
7993
|
+
decisions.set(memoKey, memoEntry);
|
|
7932
7994
|
while (decisions.size > 64) {
|
|
7933
7995
|
const oldest = decisions.keys().next();
|
|
7934
7996
|
if (oldest.done === true) break;
|
|
@@ -7936,19 +7998,44 @@ var CommandGuard = class {
|
|
|
7936
7998
|
}
|
|
7937
7999
|
this.decisions.set(request.agent, decisions);
|
|
7938
8000
|
}
|
|
7939
|
-
return this.verdict(
|
|
8001
|
+
return this.verdict(memoEntry, settings.threshold, "model", excerpt, full.sandboxPermissions !== void 0);
|
|
7940
8002
|
}
|
|
7941
|
-
/** Apply the threshold to
|
|
7942
|
-
verdict(
|
|
7943
|
-
|
|
8003
|
+
/** Apply the threshold to the primary verdict and any escalation vetoes. */
|
|
8004
|
+
verdict(entry, threshold, source, command, escalated) {
|
|
8005
|
+
if (entry.probability < threshold) return {
|
|
8006
|
+
kind: "delegate",
|
|
8007
|
+
reason: `safe probability ${entry.probability.toFixed(3)} below ${threshold}`,
|
|
8008
|
+
probability: entry.probability,
|
|
8009
|
+
command
|
|
8010
|
+
};
|
|
8011
|
+
if (!escalated) return {
|
|
7944
8012
|
kind: "approve",
|
|
7945
|
-
probability,
|
|
8013
|
+
probability: entry.probability,
|
|
7946
8014
|
source,
|
|
7947
8015
|
command
|
|
7948
|
-
}
|
|
8016
|
+
};
|
|
8017
|
+
if (entry.escalation === void 0) return {
|
|
7949
8018
|
kind: "delegate",
|
|
7950
|
-
reason:
|
|
7951
|
-
|
|
8019
|
+
reason: "the cached sandbox-escalation verdict was incomplete",
|
|
8020
|
+
command
|
|
8021
|
+
};
|
|
8022
|
+
if (entry.escalation.scope < threshold) return {
|
|
8023
|
+
kind: "delegate",
|
|
8024
|
+
reason: `sandbox scope probability ${entry.escalation.scope.toFixed(3)} below ${threshold}`,
|
|
8025
|
+
probability: entry.probability,
|
|
8026
|
+
command
|
|
8027
|
+
};
|
|
8028
|
+
if (entry.escalation.necessity < threshold) return {
|
|
8029
|
+
kind: "delegate",
|
|
8030
|
+
reason: `sandbox necessity probability ${entry.escalation.necessity.toFixed(3)} below ${threshold}`,
|
|
8031
|
+
probability: entry.probability,
|
|
8032
|
+
command
|
|
8033
|
+
};
|
|
8034
|
+
return {
|
|
8035
|
+
kind: "approve",
|
|
8036
|
+
probability: entry.probability,
|
|
8037
|
+
source,
|
|
8038
|
+
...entry.escalation === void 0 ? {} : { escalation: entry.escalation },
|
|
7952
8039
|
command
|
|
7953
8040
|
};
|
|
7954
8041
|
}
|
|
@@ -7986,7 +8073,7 @@ function applyCommandGuard(ctx, deps) {
|
|
|
7986
8073
|
return next();
|
|
7987
8074
|
}
|
|
7988
8075
|
if (verdict.kind === "approve") {
|
|
7989
|
-
deps.log?.(`command guard auto-approved a ${request.toolName} call (safe probability ${verdict.probability.toFixed(3)}, ${verdict.source}): ${verdict.command ?? "(command unknown)"}`);
|
|
8076
|
+
deps.log?.(`command guard auto-approved a ${request.toolName} call (safe probability ${verdict.probability.toFixed(3)}${verdict.escalation === void 0 ? "" : `, sandbox scope ${verdict.escalation.scope.toFixed(3)}, necessity ${verdict.escalation.necessity.toFixed(3)}`}, ${verdict.source}): ${verdict.command ?? "(command unknown)"}`);
|
|
7990
8077
|
return "allowed-once";
|
|
7991
8078
|
}
|
|
7992
8079
|
deps.log?.(`command guard delegated a ${request.toolName} call: ${verdict.reason}${verdict.command === void 0 ? "" : ` — ${verdict.command}`}`);
|
|
@@ -8170,8 +8257,7 @@ const Config = z.object(markVolatileFields({
|
|
|
8170
8257
|
account: z.string()
|
|
8171
8258
|
})),
|
|
8172
8259
|
commandGuard: z.boolean().default(false),
|
|
8173
|
-
|
|
8174
|
-
commandGuardTimeoutMs: z.number().min(200).max(COMMAND_GUARD_MAX_TIMEOUT_MS),
|
|
8260
|
+
commandGuardLevel: z.union([...COMMAND_GUARD_LEVELS]).default(COMMAND_GUARD_DEFAULT_LEVEL),
|
|
8175
8261
|
zdr: z.boolean().default(false),
|
|
8176
8262
|
lang: z.string().pattern(/^(zh|en)$/).default("zh")
|
|
8177
8263
|
}, ["apiKey"]));
|
|
@@ -8402,8 +8488,8 @@ function apply(ctx, config) {
|
|
|
8402
8488
|
const raw = current();
|
|
8403
8489
|
return {
|
|
8404
8490
|
enabled: raw.commandGuard === true,
|
|
8405
|
-
threshold: raw.
|
|
8406
|
-
timeoutMs:
|
|
8491
|
+
threshold: commandGuardThreshold(raw.commandGuardLevel),
|
|
8492
|
+
timeoutMs: COMMAND_GUARD_TIMEOUT_MS
|
|
8407
8493
|
};
|
|
8408
8494
|
};
|
|
8409
8495
|
ctx.inject(["approval"], (approvalCtx) => {
|