aria-code 4.1.3__py3-none-any.whl
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.
- agents/__init__.py +32 -0
- agents/base.py +190 -0
- agents/deep/__init__.py +37 -0
- agents/deep/calibration_loop.py +144 -0
- agents/deep/critic.py +125 -0
- agents/deep/deepen.py +193 -0
- agents/deep/models.py +149 -0
- agents/deep/pipeline.py +164 -0
- agents/deep/quant_fusion.py +192 -0
- agents/deep/themes.py +95 -0
- agents/deep/tiers.py +106 -0
- agents/financial/__init__.py +10 -0
- agents/financial/catalyst.py +279 -0
- agents/financial/debate.py +145 -0
- agents/financial/earnings.py +303 -0
- agents/financial/fundamental.py +159 -0
- agents/financial/macro.py +99 -0
- agents/financial/news.py +207 -0
- agents/financial/risk.py +132 -0
- agents/financial/sector.py +279 -0
- agents/financial/synthesis.py +274 -0
- agents/financial/technical.py +258 -0
- agents/portfolio_agent.py +333 -0
- agents/realty/__init__.py +62 -0
- agents/realty/asset_diagnosis.py +150 -0
- agents/realty/business_match.py +165 -0
- agents/realty/cashflow_verify.py +208 -0
- agents/realty/contract_rules.py +209 -0
- agents/realty/energy_anomaly.py +188 -0
- agents/realty/exit_settlement.py +207 -0
- agents/realty/fulfillment_risk.py +205 -0
- agents/realty/ops_optimize.py +159 -0
- agents/realty/revenue_share.py +214 -0
- agents/registry.py +144 -0
- agents/sports/__init__.py +0 -0
- agents/sports/football_agent.py +169 -0
- agents/team.py +289 -0
- aliyun_data_client.py +660 -0
- apps/README.md +12 -0
- apps/__init__.py +2 -0
- apps/channels/README.md +15 -0
- apps/cli/README.md +13 -0
- apps/cli/__init__.py +2 -0
- apps/cli/bootstrap.py +99 -0
- apps/cli/codegen_paths.py +29 -0
- apps/cli/commands/__init__.py +16 -0
- apps/cli/commands/analysis_cmds.py +288 -0
- apps/cli/commands/backtest_cmds.py +1887 -0
- apps/cli/commands/broker_cmds.py +1154 -0
- apps/cli/commands/business_workflow_cmds.py +289 -0
- apps/cli/commands/catalog.py +84 -0
- apps/cli/commands/data_cmds.py +405 -0
- apps/cli/commands/diagnostic_cmds.py +179 -0
- apps/cli/commands/diagnostic_ops_cmds.py +696 -0
- apps/cli/commands/finance_render.py +12 -0
- apps/cli/commands/market.py +399 -0
- apps/cli/commands/market_cmds.py +1276 -0
- apps/cli/commands/market_context.py +425 -0
- apps/cli/commands/market_render.py +7 -0
- apps/cli/commands/model_cmds.py +1579 -0
- apps/cli/commands/ops_cmds.py +668 -0
- apps/cli/commands/portfolio_cmds.py +962 -0
- apps/cli/commands/report.py +377 -0
- apps/cli/commands/scaffold_templates.py +617 -0
- apps/cli/commands/session_cmds.py +179 -0
- apps/cli/commands/session_ux_cmds.py +280 -0
- apps/cli/commands/team.py +588 -0
- apps/cli/commands/team_render.py +8 -0
- apps/cli/commands/ui_cmds.py +358 -0
- apps/cli/commands/workflow_cmds.py +279 -0
- apps/cli/commands/workspace_cmds.py +1414 -0
- apps/cli/config_paths.py +70 -0
- apps/cli/config_store.py +61 -0
- apps/cli/deterministic.py +122 -0
- apps/cli/direct.py +48 -0
- apps/cli/github_app_auth.py +135 -0
- apps/cli/handlers/__init__.py +11 -0
- apps/cli/handlers/broker_handlers.py +122 -0
- apps/cli/handlers/chart_handlers.py +1309 -0
- apps/cli/handlers/market_handlers.py +2509 -0
- apps/cli/handlers/realty_handlers.py +114 -0
- apps/cli/handlers/strategy_advice.py +82 -0
- apps/cli/hooks.py +180 -0
- apps/cli/i18n.py +284 -0
- apps/cli/intent.py +136 -0
- apps/cli/intent_router.py +217 -0
- apps/cli/lifecycle_hooks.py +48 -0
- apps/cli/main.py +29 -0
- apps/cli/market_metadata.py +135 -0
- apps/cli/market_universe.py +265 -0
- apps/cli/message_processing.py +257 -0
- apps/cli/plan_mode.py +139 -0
- apps/cli/plotly_html.py +15 -0
- apps/cli/prediction_feedback.py +202 -0
- apps/cli/preflight.py +497 -0
- apps/cli/project_aria.py +60 -0
- apps/cli/prompts/__init__.py +0 -0
- apps/cli/prompts/coding.py +658 -0
- apps/cli/prompts/system_prompts.py +531 -0
- apps/cli/prompts/ui.py +434 -0
- apps/cli/providers/__init__.py +1 -0
- apps/cli/providers/base.py +271 -0
- apps/cli/providers/chat_routing.py +80 -0
- apps/cli/providers/llm/__init__.py +1 -0
- apps/cli/providers/llm/ollama_stream.py +1170 -0
- apps/cli/providers/llm/sse_stream.py +216 -0
- apps/cli/providers/runtime_bridge.py +185 -0
- apps/cli/runtime_consumer.py +489 -0
- apps/cli/session_export.py +87 -0
- apps/cli/session_jsonl.py +207 -0
- apps/cli/session_store.py +112 -0
- apps/cli/todo_tracker.py +190 -0
- apps/cli/tools/__init__.py +40 -0
- apps/cli/tools/context.py +46 -0
- apps/cli/tools/file_tools.py +112 -0
- apps/cli/tools/market_tools.py +549 -0
- apps/cli/tools/notebook_tools.py +111 -0
- apps/cli/tools/system_tools.py +669 -0
- apps/cli/tools/write_tools.py +715 -0
- apps/cli/tradingview_bridge.py +434 -0
- apps/cli/update_check.py +152 -0
- apps/cli/utils/__init__.py +0 -0
- apps/cli/utils/market_detect.py +1578 -0
- apps/daemon/README.md +14 -0
- apps/vscode/README.md +115 -0
- apps/vscode/package.json +70 -0
- aria_cli.py +11636 -0
- aria_code-4.1.3.dist-info/METADATA +952 -0
- aria_code-4.1.3.dist-info/RECORD +284 -0
- aria_code-4.1.3.dist-info/WHEEL +5 -0
- aria_code-4.1.3.dist-info/entry_points.txt +2 -0
- aria_code-4.1.3.dist-info/licenses/LICENSE +121 -0
- aria_code-4.1.3.dist-info/top_level.txt +50 -0
- aria_daemon.py +1295 -0
- aria_feishu_bot.py +1359 -0
- aria_relay_client.py +182 -0
- aria_relay_server.py +405 -0
- aria_telegram_bot.py +202 -0
- ariarc.py +328 -0
- artifacts.py +491 -0
- backtest_report.py +472 -0
- brokers/__init__.py +72 -0
- brokers/base.py +207 -0
- brokers/capabilities.py +264 -0
- brokers/cn/__init__.py +10 -0
- brokers/cn/easytrader_broker.py +193 -0
- brokers/cn/futu_broker.py +194 -0
- brokers/cn/longbridge_broker.py +190 -0
- brokers/cn/tiger_broker.py +196 -0
- brokers/cn/xtquant_broker.py +175 -0
- brokers/config.py +364 -0
- brokers/intl/__init__.py +5 -0
- brokers/intl/alpaca_broker.py +183 -0
- brokers/intl/ibkr_broker.py +215 -0
- brokers/intl/webull_broker.py +156 -0
- brokers/paper_broker.py +259 -0
- brokers/planning.py +296 -0
- brokers/registry.py +181 -0
- brokers/trading.py +237 -0
- change_store.py +127 -0
- command_safety.py +19 -0
- computer_use_tools.py +504 -0
- dashboard_generator.py +578 -0
- data_analysis_tools.py +808 -0
- data_cleaner.py +483 -0
- data_service.py +481 -0
- datasources/__init__.py +23 -0
- datasources/base.py +166 -0
- datasources/router.py +221 -0
- datasources/sources/__init__.py +15 -0
- datasources/sources/akshare_source.py +269 -0
- datasources/sources/alpha_vantage_source.py +202 -0
- datasources/sources/edgar_source.py +218 -0
- datasources/sources/finnhub_source.py +197 -0
- datasources/sources/fred_source.py +219 -0
- datasources/sources/tushare_source.py +141 -0
- datasources/sources/web_scraper_source.py +278 -0
- datasources/sources/world_bank_source.py +205 -0
- datasources/sources/yfinance_source.py +152 -0
- demo_player.py +204 -0
- doctor.py +508 -0
- file_analysis_tools.py +734 -0
- finance_formulas.py +389 -0
- football_data_client.py +1670 -0
- intent_classifier.py +358 -0
- local_finance_tools.py +3221 -0
- local_llm_provider.py +552 -0
- macro_tools.py +368 -0
- market_data_client.py +1899 -0
- mcp_client.py +506 -0
- memory_manager.py +245 -0
- model_capability.py +416 -0
- notification_tools.py +248 -0
- packages/__init__.py +23 -0
- packages/aria_agents/__init__.py +5 -0
- packages/aria_agents/manifest.py +69 -0
- packages/aria_core/__init__.py +34 -0
- packages/aria_core/architecture.py +192 -0
- packages/aria_core/export.py +124 -0
- packages/aria_core/manifest.py +65 -0
- packages/aria_infra/__init__.py +15 -0
- packages/aria_infra/arthera.py +52 -0
- packages/aria_infra/doctor.py +246 -0
- packages/aria_infra/product.py +37 -0
- packages/aria_mcp/__init__.py +25 -0
- packages/aria_mcp/bridge.py +38 -0
- packages/aria_mcp/config.py +97 -0
- packages/aria_mcp/tools.py +61 -0
- packages/aria_sdk/__init__.py +19 -0
- packages/aria_sdk/client.py +396 -0
- packages/aria_sdk/providers.py +70 -0
- packages/aria_sdk/streaming.py +73 -0
- packages/aria_sdk/types.py +86 -0
- packages/aria_services/__init__.py +55 -0
- packages/aria_services/context.py +258 -0
- packages/aria_services/data.py +11 -0
- packages/aria_services/provider_health.py +189 -0
- packages/aria_services/registry.py +213 -0
- packages/aria_services/usage.py +138 -0
- packages/aria_skills/__init__.py +5 -0
- packages/aria_skills/registry.py +59 -0
- packages/aria_tools/__init__.py +5 -0
- packages/aria_tools/registry.py +128 -0
- packages/quant_engine/__init__.py +6 -0
- packages/quant_engine/sports/__init__.py +72 -0
- packages/quant_engine/sports/calibrator.py +353 -0
- packages/quant_engine/sports/dixon_coles.py +234 -0
- packages/quant_engine/sports/elo.py +299 -0
- packages/quant_engine/sports/form.py +188 -0
- packages/quant_engine/sports/h2h.py +195 -0
- packages/quant_engine/sports/ml_model.py +354 -0
- packages/quant_engine/sports/predictor.py +311 -0
- packages/quant_engine/sports/tracker.py +664 -0
- packages/quant_engine/stochastic/__init__.py +27 -0
- packages/quant_engine/stochastic/gbm_enhanced.py +195 -0
- packages/quant_engine/stochastic/ito_calculus.py +477 -0
- packages/quant_engine/stochastic/kelly_criterion.py +181 -0
- packages/quant_engine/stochastic/monte_carlo_advanced.py +95 -0
- packages/quant_engine/stochastic/options_pricing.py +573 -0
- packages/quant_engine/stochastic/stochastic_processes.py +90 -0
- plan_utils.py +194 -0
- plugin_loader.py +328 -0
- portfolio_ledger.py +262 -0
- privacy/__init__.py +5 -0
- privacy/feedback.py +123 -0
- project_tools.py +525 -0
- providers/__init__.py +30 -0
- providers/llm/__init__.py +19 -0
- providers/llm/anthropic.py +184 -0
- providers/llm/base.py +139 -0
- providers/llm/ollama.py +128 -0
- providers/llm/openai_compat.py +282 -0
- providers/llm/registry.py +358 -0
- realty_data_tools.py +659 -0
- report_generator.py +1314 -0
- runtime/__init__.py +103 -0
- runtime/agent_loop.py +1183 -0
- runtime/approval.py +51 -0
- runtime/events.py +102 -0
- runtime/gateway.py +128 -0
- runtime/lsp.py +346 -0
- runtime/subagent.py +258 -0
- runtime/tool_executor.py +104 -0
- runtime/tool_policy.py +106 -0
- safety/__init__.py +21 -0
- safety/permissions.py +275 -0
- setup_wizard.py +653 -0
- strategy_vault.py +420 -0
- ui/__init__.py +100 -0
- ui/banner.py +310 -0
- ui/completer.py +391 -0
- ui/console.py +271 -0
- ui/image_render.py +243 -0
- ui/input_box.py +376 -0
- ui/picker.py +195 -0
- ui/render/__init__.py +11 -0
- ui/render/finance.py +1480 -0
- ui/render/market.py +225 -0
- ui/render/output.py +681 -0
- ui/render/team.py +346 -0
- ui/robot.py +235 -0
- workspace/__init__.py +6 -0
- workspace/files.py +170 -0
- workspace/verify.py +113 -0
safety/permissions.py
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
"""Unified permission and command-risk policy for Aria Code."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import shlex
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from enum import Enum
|
|
8
|
+
from typing import Any, Dict
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
SAFE_POLICIES = {"safe", "balanced", "full"}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class PermissionMode(str, Enum):
|
|
15
|
+
READ_ONLY = "read-only"
|
|
16
|
+
WORKSPACE_WRITE = "workspace-write"
|
|
17
|
+
FULL_ACCESS = "full-access"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@dataclass(frozen=True)
|
|
21
|
+
class PolicyDecision:
|
|
22
|
+
allowed: bool
|
|
23
|
+
normalized_command: str
|
|
24
|
+
policy: str
|
|
25
|
+
risk: str
|
|
26
|
+
reason: str = ""
|
|
27
|
+
requires_approval: bool = False
|
|
28
|
+
network: bool = False
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass(frozen=True)
|
|
32
|
+
class PermissionDecision:
|
|
33
|
+
allowed: bool
|
|
34
|
+
requires_approval: bool
|
|
35
|
+
risk: str
|
|
36
|
+
reason: str
|
|
37
|
+
normalized_command: str = ""
|
|
38
|
+
network: bool = False
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def normalize_command(command) -> str:
|
|
42
|
+
"""Normalize common macOS command aliases used by models/users."""
|
|
43
|
+
if isinstance(command, list):
|
|
44
|
+
import shlex as _shlex
|
|
45
|
+
command = _shlex.join(str(c) for c in command)
|
|
46
|
+
raw = (command or "").strip()
|
|
47
|
+
if not raw:
|
|
48
|
+
return ""
|
|
49
|
+
try:
|
|
50
|
+
parts = shlex.split(raw)
|
|
51
|
+
except ValueError:
|
|
52
|
+
parts = []
|
|
53
|
+
if parts:
|
|
54
|
+
if parts[0] == "python":
|
|
55
|
+
parts[0] = "python3"
|
|
56
|
+
elif parts[0] == "pip":
|
|
57
|
+
parts[0] = "pip3"
|
|
58
|
+
return shlex.join(parts)
|
|
59
|
+
if raw.startswith("python ") and not raw.startswith("python3"):
|
|
60
|
+
return "python3" + raw[6:]
|
|
61
|
+
if raw == "python":
|
|
62
|
+
return "python3"
|
|
63
|
+
if raw.startswith("pip ") and not raw.startswith("pip3"):
|
|
64
|
+
return "pip3" + raw[3:]
|
|
65
|
+
if raw == "pip":
|
|
66
|
+
return "pip3"
|
|
67
|
+
return raw
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def command_uses_network(command: str) -> bool:
|
|
71
|
+
stripped = command.lower().strip()
|
|
72
|
+
network_prefixes = (
|
|
73
|
+
"curl ", "wget ", "http ", "https ", "gh ", "git fetch", "git pull",
|
|
74
|
+
"git push", "pip3 install", "pip install", "npm install", "npm i ",
|
|
75
|
+
"pnpm install", "yarn install", "brew install",
|
|
76
|
+
)
|
|
77
|
+
return any(stripped.startswith(prefix) for prefix in network_prefixes)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def is_verification_command(command: str) -> bool:
|
|
81
|
+
stripped = command.lower().strip()
|
|
82
|
+
prefixes = (
|
|
83
|
+
"python3 -m py_compile",
|
|
84
|
+
"python -m py_compile",
|
|
85
|
+
"python3 -m pytest",
|
|
86
|
+
"python -m pytest",
|
|
87
|
+
"pytest",
|
|
88
|
+
"npm test",
|
|
89
|
+
"npm run test",
|
|
90
|
+
"npm run build",
|
|
91
|
+
"npx tsc --noemit",
|
|
92
|
+
"npx tsc --noEmit".lower(),
|
|
93
|
+
"tsc --noemit",
|
|
94
|
+
"go test",
|
|
95
|
+
"cargo test",
|
|
96
|
+
"mypy",
|
|
97
|
+
"ruff check",
|
|
98
|
+
)
|
|
99
|
+
return any(stripped.startswith(prefix) for prefix in prefixes)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def classify_command_risk(command) -> str:
|
|
103
|
+
"""Classify command risk into low/medium/high."""
|
|
104
|
+
if isinstance(command, list):
|
|
105
|
+
import shlex as _shlex
|
|
106
|
+
command = _shlex.join(str(c) for c in command)
|
|
107
|
+
normalized = f" {str(command).lower().strip()} "
|
|
108
|
+
stripped = normalized.strip()
|
|
109
|
+
|
|
110
|
+
high_risk_patterns = (
|
|
111
|
+
" rm ", " rm -", "chmod ", "chown ", "mkfs", "dd if=", "docker ", "kubectl ",
|
|
112
|
+
"shutdown", "reboot", "systemctl ", "launchctl ", "passwd", "sudo ",
|
|
113
|
+
"git push", "git reset --hard", "git checkout --", "mv ",
|
|
114
|
+
"> /dev/", ":(){ :", "fork bomb",
|
|
115
|
+
)
|
|
116
|
+
low_risk_prefixes = (
|
|
117
|
+
"ls", "pwd", "echo", "cat ", "head ", "tail ", "rg ", "find ", "git status",
|
|
118
|
+
"git diff", "git log", "which ", "whoami", "date", "uname ", "env",
|
|
119
|
+
"python3 --version", "node --version", "npm --version",
|
|
120
|
+
)
|
|
121
|
+
medium_risk_prefixes = (
|
|
122
|
+
"pip ", "pip3 ", "npm install", "npm i ", "npm run ", "python ", "python3 ",
|
|
123
|
+
"pytest", "make ", "go test", "cargo test", "git commit", "git pull", "git merge",
|
|
124
|
+
"gh ", "curl ", "wget ",
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
if any(pattern in normalized for pattern in high_risk_patterns):
|
|
128
|
+
return "high"
|
|
129
|
+
if stripped.startswith(low_risk_prefixes):
|
|
130
|
+
return "low"
|
|
131
|
+
if stripped.startswith(medium_risk_prefixes) or is_verification_command(stripped):
|
|
132
|
+
return "medium"
|
|
133
|
+
return "medium"
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
class PermissionService:
|
|
137
|
+
"""Central policy for tools and shell-command execution."""
|
|
138
|
+
|
|
139
|
+
READ_TOOLS = {"read_file", "list_files", "search_code", "project_context", "git_status", "git_diff"}
|
|
140
|
+
WRITE_TOOLS = {"write_file", "edit_file", "apply_change", "apply_patch", "reject_change"}
|
|
141
|
+
|
|
142
|
+
def __init__(
|
|
143
|
+
self,
|
|
144
|
+
mode: PermissionMode | str = PermissionMode.WORKSPACE_WRITE,
|
|
145
|
+
command_policy: str = "safe",
|
|
146
|
+
network_enabled: bool = True,
|
|
147
|
+
) -> None:
|
|
148
|
+
try:
|
|
149
|
+
self.mode = PermissionMode(mode)
|
|
150
|
+
except ValueError:
|
|
151
|
+
self.mode = PermissionMode.WORKSPACE_WRITE
|
|
152
|
+
self.command_policy = command_policy if command_policy in SAFE_POLICIES else "safe"
|
|
153
|
+
self.network_enabled = network_enabled
|
|
154
|
+
|
|
155
|
+
def evaluate_tool(self, tool_name: str, params: Dict[str, Any] | None = None) -> PermissionDecision:
|
|
156
|
+
name = (tool_name or "").strip()
|
|
157
|
+
if name in self.READ_TOOLS:
|
|
158
|
+
return PermissionDecision(True, False, "low", "Read-only tool allowed.")
|
|
159
|
+
if name in self.WRITE_TOOLS:
|
|
160
|
+
if self.mode == PermissionMode.READ_ONLY:
|
|
161
|
+
return PermissionDecision(False, False, "medium", "Writes are blocked in read-only mode.")
|
|
162
|
+
return PermissionDecision(
|
|
163
|
+
True,
|
|
164
|
+
self.mode != PermissionMode.FULL_ACCESS,
|
|
165
|
+
"medium",
|
|
166
|
+
"Write requires review or explicit approval before disk mutation.",
|
|
167
|
+
)
|
|
168
|
+
if name == "run_command":
|
|
169
|
+
return self.evaluate_command(str((params or {}).get("command", "")))
|
|
170
|
+
return PermissionDecision(False, False, "unknown", f"Unknown tool '{name}' is blocked.")
|
|
171
|
+
|
|
172
|
+
def evaluate_command(self, command: str, policy: str | None = None) -> PermissionDecision:
|
|
173
|
+
decision = evaluate_command_policy(
|
|
174
|
+
command,
|
|
175
|
+
policy or self.command_policy,
|
|
176
|
+
mode=self.mode.value,
|
|
177
|
+
network_enabled=self.network_enabled,
|
|
178
|
+
)
|
|
179
|
+
return PermissionDecision(
|
|
180
|
+
allowed=decision.allowed,
|
|
181
|
+
requires_approval=decision.requires_approval,
|
|
182
|
+
risk=decision.risk,
|
|
183
|
+
reason=decision.reason or "Command allowed.",
|
|
184
|
+
normalized_command=decision.normalized_command,
|
|
185
|
+
network=decision.network,
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def evaluate_command_policy(
|
|
190
|
+
command: str,
|
|
191
|
+
policy: str = "safe",
|
|
192
|
+
*,
|
|
193
|
+
mode: str = PermissionMode.WORKSPACE_WRITE.value,
|
|
194
|
+
network_enabled: bool = True,
|
|
195
|
+
) -> PolicyDecision:
|
|
196
|
+
"""Return policy decision for command execution."""
|
|
197
|
+
normalized = normalize_command(command)
|
|
198
|
+
selected_policy = (policy or "safe").strip().lower()
|
|
199
|
+
if selected_policy not in SAFE_POLICIES:
|
|
200
|
+
selected_policy = "safe"
|
|
201
|
+
try:
|
|
202
|
+
selected_mode = PermissionMode(mode)
|
|
203
|
+
except ValueError:
|
|
204
|
+
selected_mode = PermissionMode.WORKSPACE_WRITE
|
|
205
|
+
|
|
206
|
+
risk = classify_command_risk(normalized)
|
|
207
|
+
network = command_uses_network(normalized)
|
|
208
|
+
if network and not network_enabled:
|
|
209
|
+
return PolicyDecision(
|
|
210
|
+
allowed=False,
|
|
211
|
+
normalized_command=normalized,
|
|
212
|
+
policy=selected_policy,
|
|
213
|
+
risk=risk,
|
|
214
|
+
reason=f"Network command blocked by policy: {normalized}",
|
|
215
|
+
requires_approval=False,
|
|
216
|
+
network=True,
|
|
217
|
+
)
|
|
218
|
+
if selected_mode == PermissionMode.READ_ONLY and risk != "low":
|
|
219
|
+
return PolicyDecision(
|
|
220
|
+
allowed=False,
|
|
221
|
+
normalized_command=normalized,
|
|
222
|
+
policy=selected_policy,
|
|
223
|
+
risk=risk,
|
|
224
|
+
reason=f"Command blocked by read-only mode (risk={risk}): {normalized}",
|
|
225
|
+
requires_approval=False,
|
|
226
|
+
network=network,
|
|
227
|
+
)
|
|
228
|
+
if risk == "high" and selected_policy != "full":
|
|
229
|
+
return PolicyDecision(
|
|
230
|
+
allowed=False,
|
|
231
|
+
normalized_command=normalized,
|
|
232
|
+
policy=selected_policy,
|
|
233
|
+
risk=risk,
|
|
234
|
+
reason=(
|
|
235
|
+
f"Command blocked by policy '{selected_policy}' (risk={risk}): {normalized}. "
|
|
236
|
+
"Use /config set command_policy=full only if you understand the risk."
|
|
237
|
+
),
|
|
238
|
+
requires_approval=selected_policy == "balanced",
|
|
239
|
+
network=network,
|
|
240
|
+
)
|
|
241
|
+
if selected_policy == "safe" and risk != "low":
|
|
242
|
+
extra = ""
|
|
243
|
+
norm_low = normalized.lower()
|
|
244
|
+
if "pip3" in norm_low or "pip " in norm_low or norm_low.startswith("pip"):
|
|
245
|
+
extra = (
|
|
246
|
+
"\n\n💡 依赖安装提示:运行 `/config set command_policy=balanced` 后重试,"
|
|
247
|
+
"或手动在终端执行该命令。不要重试相同命令!"
|
|
248
|
+
)
|
|
249
|
+
elif "python" in norm_low and ("~/" in normalized or "/Desktop/" in normalized):
|
|
250
|
+
extra = (
|
|
251
|
+
"\n\n💡 脚本执行提示:运行 `/config set command_policy=balanced` 后重试。"
|
|
252
|
+
"不要重试相同命令!"
|
|
253
|
+
)
|
|
254
|
+
return PolicyDecision(
|
|
255
|
+
allowed=False,
|
|
256
|
+
normalized_command=normalized,
|
|
257
|
+
policy=selected_policy,
|
|
258
|
+
risk=risk,
|
|
259
|
+
reason=(
|
|
260
|
+
f"Command blocked by policy '{selected_policy}' (risk={risk}): {normalized}. "
|
|
261
|
+
"Use /config set command_policy=balanced or /run --dry-run <cmd> first."
|
|
262
|
+
+ extra
|
|
263
|
+
),
|
|
264
|
+
requires_approval=True,
|
|
265
|
+
network=network,
|
|
266
|
+
)
|
|
267
|
+
return PolicyDecision(
|
|
268
|
+
allowed=True,
|
|
269
|
+
normalized_command=normalized,
|
|
270
|
+
policy=selected_policy,
|
|
271
|
+
risk=risk,
|
|
272
|
+
reason="",
|
|
273
|
+
requires_approval=False,
|
|
274
|
+
network=network,
|
|
275
|
+
)
|