algo-cli-runtime 0.14.0__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.
- algo_cli/__init__.py +3 -0
- algo_cli/__main__.py +7 -0
- algo_cli/_internal/__init__.py +12 -0
- algo_cli/_internal/policy_chain.py +259 -0
- algo_cli/action_registry.py +1047 -0
- algo_cli/agent_blocks.py +550 -0
- algo_cli/agent_pipeline.py +1457 -0
- algo_cli/agent_threads.py +308 -0
- algo_cli/animations.py +316 -0
- algo_cli/cache_admission.py +209 -0
- algo_cli/capability_mask.py +66 -0
- algo_cli/chat_protocol.py +116 -0
- algo_cli/chatgpt_auth.py +510 -0
- algo_cli/chatgpt_client.py +657 -0
- algo_cli/code_rag.py +479 -0
- algo_cli/config.py +651 -0
- algo_cli/context_budget.py +679 -0
- algo_cli/credential_helpers.py +315 -0
- algo_cli/deliberation.py +29 -0
- algo_cli/display.py +1470 -0
- algo_cli/evals/__init__.py +21 -0
- algo_cli/evals/algorithm_effectiveness.py +560 -0
- algo_cli/evals/competitive_harness_rating.py +702 -0
- algo_cli/evals/cot_quality.py +220 -0
- algo_cli/evals/harness_retrieval_benchmark.py +401 -0
- algo_cli/evals/performance_regression.py +136 -0
- algo_cli/evals/scorecard_grading.py +308 -0
- algo_cli/evals/session_distribution.py +84 -0
- algo_cli/execution_guardrails.py +806 -0
- algo_cli/extensions_manifest.py +84 -0
- algo_cli/git_evidence.py +227 -0
- algo_cli/google_workspace.py +407 -0
- algo_cli/google_workspace_auth.py +523 -0
- algo_cli/harness.py +2587 -0
- algo_cli/identity.py +557 -0
- algo_cli/index_compute_lab.py +228 -0
- algo_cli/inference_harness.py +70 -0
- algo_cli/intelligence/__init__.py +1103 -0
- algo_cli/intelligence/acrobat_config.py +307 -0
- algo_cli/intelligence/acrobat_manifests.py +338 -0
- algo_cli/intelligence/acrobat_models.py +195 -0
- algo_cli/intelligence/acrobat_pipeline.py +295 -0
- algo_cli/intelligence/acrobat_runtime.py +302 -0
- algo_cli/intelligence/acrobat_security.py +261 -0
- algo_cli/intelligence/acrobat_workflows.py +226 -0
- algo_cli/intelligence/actionability.py +165 -0
- algo_cli/intelligence/adversarial_audit.py +136 -0
- algo_cli/intelligence/agent_arena.py +92 -0
- algo_cli/intelligence/agent_benchmark.py +236 -0
- algo_cli/intelligence/agent_runtime.py +171 -0
- algo_cli/intelligence/agents_as_tools.py +70 -0
- algo_cli/intelligence/artifact_binding.py +80 -0
- algo_cli/intelligence/autonomous_engineer.py +1976 -0
- algo_cli/intelligence/backpressure.py +99 -0
- algo_cli/intelligence/bloom_filter.py +186 -0
- algo_cli/intelligence/bonferroni.py +66 -0
- algo_cli/intelligence/boundary_compaction.py +98 -0
- algo_cli/intelligence/catalog_verifier.py +172 -0
- algo_cli/intelligence/cavecrew.py +118 -0
- algo_cli/intelligence/changelog.py +176 -0
- algo_cli/intelligence/checkpoint_resume.py +92 -0
- algo_cli/intelligence/circuit_breaker.py +88 -0
- algo_cli/intelligence/clarification_gate.py +101 -0
- algo_cli/intelligence/code_graph.py +180 -0
- algo_cli/intelligence/coderank.py +97 -0
- algo_cli/intelligence/consistent_hash.py +150 -0
- algo_cli/intelligence/consortium_synthesis.py +139 -0
- algo_cli/intelligence/construction/__init__.py +241 -0
- algo_cli/intelligence/construction/common.py +273 -0
- algo_cli/intelligence/construction/documents.py +496 -0
- algo_cli/intelligence/construction/labor_units.py +1395 -0
- algo_cli/intelligence/construction/payments.py +470 -0
- algo_cli/intelligence/construction/risk.py +784 -0
- algo_cli/intelligence/content_extractor.py +132 -0
- algo_cli/intelligence/context_adaptive.py +102 -0
- algo_cli/intelligence/context_ops.py +95 -0
- algo_cli/intelligence/count_min.py +145 -0
- algo_cli/intelligence/cow_state.py +103 -0
- algo_cli/intelligence/critic_loop.py +119 -0
- algo_cli/intelligence/cross_source.py +113 -0
- algo_cli/intelligence/daemon_mode.py +99 -0
- algo_cli/intelligence/dag_orchestration.py +151 -0
- algo_cli/intelligence/deep_research.py +155 -0
- algo_cli/intelligence/degenerate_detector.py +78 -0
- algo_cli/intelligence/delta_report.py +92 -0
- algo_cli/intelligence/discovery_event_log.py +92 -0
- algo_cli/intelligence/document_ingest.py +298 -0
- algo_cli/intelligence/dual_layer_validate.py +151 -0
- algo_cli/intelligence/echo_fidelity.py +73 -0
- algo_cli/intelligence/ema_tuning.py +104 -0
- algo_cli/intelligence/event_log.py +92 -0
- algo_cli/intelligence/evidence_graph.py +114 -0
- algo_cli/intelligence/extension_host.py +162 -0
- algo_cli/intelligence/extension_manifest.py +115 -0
- algo_cli/intelligence/falsification_suite.py +178 -0
- algo_cli/intelligence/finance/__init__.py +169 -0
- algo_cli/intelligence/finance/anomalies.py +135 -0
- algo_cli/intelligence/finance/ap_ar.py +351 -0
- algo_cli/intelligence/finance/cash.py +162 -0
- algo_cli/intelligence/finance/close.py +332 -0
- algo_cli/intelligence/finance/common.py +244 -0
- algo_cli/intelligence/finance/construction.py +135 -0
- algo_cli/intelligence/finance/controls.py +172 -0
- algo_cli/intelligence/finance/evidence.py +119 -0
- algo_cli/intelligence/finance/exceptions.py +157 -0
- algo_cli/intelligence/finance/reconciliations.py +254 -0
- algo_cli/intelligence/finance/revenue.py +109 -0
- algo_cli/intelligence/finance/tax.py +74 -0
- algo_cli/intelligence/finance/workpapers.py +111 -0
- algo_cli/intelligence/finding_record.py +120 -0
- algo_cli/intelligence/flow_dag.py +267 -0
- algo_cli/intelligence/gatherer.py +223 -0
- algo_cli/intelligence/golden_master.py +98 -0
- algo_cli/intelligence/graph_rag.py +195 -0
- algo_cli/intelligence/group_chat.py +143 -0
- algo_cli/intelligence/hash_dedup.py +145 -0
- algo_cli/intelligence/hyperloglog.py +128 -0
- algo_cli/intelligence/incremental_index.py +316 -0
- algo_cli/intelligence/index_store.py +16 -0
- algo_cli/intelligence/iteration_plan.py +133 -0
- algo_cli/intelligence/kernel_plugins.py +167 -0
- algo_cli/intelligence/lesson_catalog.py +135 -0
- algo_cli/intelligence/llm_fallback.py +169 -0
- algo_cli/intelligence/log2_histogram.py +267 -0
- algo_cli/intelligence/lsp_integration.py +147 -0
- algo_cli/intelligence/memory_evolution.py +117 -0
- algo_cli/intelligence/minhash_lsh.py +182 -0
- algo_cli/intelligence/multi_model_score.py +174 -0
- algo_cli/intelligence/multi_tier_grade.py +211 -0
- algo_cli/intelligence/negative_controls.py +113 -0
- algo_cli/intelligence/numeric_clamp.py +63 -0
- algo_cli/intelligence/occ_editor.py +66 -0
- algo_cli/intelligence/output_normalize.py +112 -0
- algo_cli/intelligence/parallel_delegation.py +98 -0
- algo_cli/intelligence/parallel_fanout.py +104 -0
- algo_cli/intelligence/permission_modes.py +105 -0
- algo_cli/intelligence/pre_push_gate.py +68 -0
- algo_cli/intelligence/prefetch.py +171 -0
- algo_cli/intelligence/process_framework.py +217 -0
- algo_cli/intelligence/project_graph.py +387 -0
- algo_cli/intelligence/query_expansion.py +146 -0
- algo_cli/intelligence/ralph_loop.py +117 -0
- algo_cli/intelligence/rate_limiter.py +153 -0
- algo_cli/intelligence/refactor_transaction.py +94 -0
- algo_cli/intelligence/research_workspace.py +108 -0
- algo_cli/intelligence/retraction_ledger.py +72 -0
- algo_cli/intelligence/saga_pattern.py +88 -0
- algo_cli/intelligence/session_fork.py +100 -0
- algo_cli/intelligence/shadow_editor.py +67 -0
- algo_cli/intelligence/shell_session.py +213 -0
- algo_cli/intelligence/source_registry.py +143 -0
- algo_cli/intelligence/spawn_scales.py +99 -0
- algo_cli/intelligence/stat_stability.py +104 -0
- algo_cli/intelligence/structural_validator.py +148 -0
- algo_cli/intelligence/subagent_spawner.py +111 -0
- algo_cli/intelligence/symmetric_verify.py +70 -0
- algo_cli/intelligence/task_classifier.py +129 -0
- algo_cli/intelligence/team_execution.py +122 -0
- algo_cli/intelligence/tiered_access.py +121 -0
- algo_cli/intelligence/utility_registry.py +159 -0
- algo_cli/intuition_engine.py +560 -0
- algo_cli/intuition_injector.py +82 -0
- algo_cli/kernels/__init__.py +5 -0
- algo_cli/kernels/manifest.py +763 -0
- algo_cli/main.py +3903 -0
- algo_cli/memory_candidates.py +541 -0
- algo_cli/memory_echo_veil.py +394 -0
- algo_cli/memory_runtime.py +112 -0
- algo_cli/model_info.py +548 -0
- algo_cli/model_profile.py +160 -0
- algo_cli/model_routing.py +74 -0
- algo_cli/oneshot.py +331 -0
- algo_cli/perf_telemetry.py +389 -0
- algo_cli/plugins.py +245 -0
- algo_cli/private_event_store.py +654 -0
- algo_cli/quantization/__init__.py +24 -0
- algo_cli/quantization/lloyd_max.py +98 -0
- algo_cli/quantization/turbo_quant.py +308 -0
- algo_cli/reasoning/__init__.py +46 -0
- algo_cli/reasoning/combinatorial.py +356 -0
- algo_cli/reasoning/graph_of_thought.py +297 -0
- algo_cli/reasoning/mcts.py +220 -0
- algo_cli/reasoning/neuro_symbolic.py +250 -0
- algo_cli/reasoning/react.py +246 -0
- algo_cli/reasoning/reflexion.py +225 -0
- algo_cli/reasoning/tree_of_thought.py +241 -0
- algo_cli/reasoning_bridge.py +150 -0
- algo_cli/reconciliation.py +284 -0
- algo_cli/reflex.py +385 -0
- algo_cli/resources/docs/ALGO.md +13958 -0
- algo_cli/resources/docs/algo-cli-algorithm-evidence-contract.md +60 -0
- algo_cli/resources/docs/algo-cli-execution-verification-contract.md +59 -0
- algo_cli/resources/docs/algo-cli-memory-lifecycle-contract.md +72 -0
- algo_cli/resources/docs/harness-extension-cleanup-recommendation.md +41 -0
- algo_cli/resources/docs/index-compute-lab-integration.md +32 -0
- algo_cli/resources/docs/inference-harness-loop-blueprint-2026-06.md +55 -0
- algo_cli/resources/docs/main-split-map.md +35 -0
- algo_cli/resources/docs/privacy-and-context.md +48 -0
- algo_cli/resources/docs/reflex-loop-v0.2.md +354 -0
- algo_cli/resources/skills/README.md +26 -0
- algo_cli/resources/skills/algo-cli.md +59 -0
- algo_cli/resources/skills/edit-file-precision.md +49 -0
- algo_cli/resources/skills/harness-search-first.md +47 -0
- algo_cli/resources/skills/memory-recall-ritual.md +51 -0
- algo_cli/resources/skills/qol-algorithms.md +224 -0
- algo_cli/resources/skills/smart-error-recovery.md +56 -0
- algo_cli/resources/skills/tool-selection-cheatsheet.md +65 -0
- algo_cli/retrieval_algorithms.py +127 -0
- algo_cli/runtime_qos.py +236 -0
- algo_cli/runtime_services.py +320 -0
- algo_cli/session_commands.py +95 -0
- algo_cli/session_mode.py +113 -0
- algo_cli/skills.py +430 -0
- algo_cli/slash_dispatch.py +1265 -0
- algo_cli/small_context.py +206 -0
- algo_cli/spawn_budget.py +89 -0
- algo_cli/task_ledger.py +84 -0
- algo_cli/task_router.py +197 -0
- algo_cli/tool_context.py +94 -0
- algo_cli/tool_contract.py +99 -0
- algo_cli/tool_policy.py +357 -0
- algo_cli/tool_runtime.py +647 -0
- algo_cli/tools.py +3056 -0
- algo_cli/url_scheme.py +174 -0
- algo_cli/verify.py +154 -0
- algo_cli/version_manifest.py +178 -0
- algo_cli/vision_screenshot_verify.py +76 -0
- algo_cli/workspace_resolver.py +68 -0
- algo_cli/x_account.py +209 -0
- algo_cli/xai_auth.py +374 -0
- algo_cli/xai_client.py +600 -0
- algo_cli_runtime-0.14.0.dist-info/METADATA +369 -0
- algo_cli_runtime-0.14.0.dist-info/RECORD +237 -0
- algo_cli_runtime-0.14.0.dist-info/WHEEL +4 -0
- algo_cli_runtime-0.14.0.dist-info/entry_points.txt +3 -0
- algo_cli_runtime-0.14.0.dist-info/licenses/LICENSE +21 -0
- ollama_cli/__init__.py +67 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"""B41. Pseudoterminal Boundary + VT Parser/Emitter (Windows Terminal Pattern).
|
|
2
|
+
|
|
3
|
+
Wraps shell command execution with a session abstraction: process boundary,
|
|
4
|
+
streaming stdout/stderr frames, ANSI/VT normalization, command replay
|
|
5
|
+
metadata, and timeout/cancellation.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import re
|
|
11
|
+
import time
|
|
12
|
+
import uuid
|
|
13
|
+
from dataclasses import dataclass, field
|
|
14
|
+
from typing import Any
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# ── ANSI/VT normalization ─────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
# Match ANSI escape sequences
|
|
20
|
+
_ANSI_RE = re.compile(r"\x1b\[[0-9;]*[a-zA-Z]")
|
|
21
|
+
# Match other control chars (except \n, \r, \t)
|
|
22
|
+
_CTRL_RE = re.compile(r"[\x00-\x08\x0b\x0c\x0e-\x1f]")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def strip_ansi(text: str) -> str:
|
|
26
|
+
"""Remove ANSI escape sequences."""
|
|
27
|
+
return _ANSI_RE.sub("", text)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def normalize_vt(text: str) -> str:
|
|
31
|
+
"""Remove ANSI escapes and control characters, keep newlines/tabs."""
|
|
32
|
+
text = _ANSI_RE.sub("", text)
|
|
33
|
+
text = _CTRL_RE.sub("", text)
|
|
34
|
+
return text
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def has_ansi(text: str) -> bool:
|
|
38
|
+
"""Check if text contains ANSI escape sequences."""
|
|
39
|
+
return bool(_ANSI_RE.search(text))
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# ── streaming frames ──────────────────────────────────────────────────
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
@dataclass
|
|
46
|
+
class OutputFrame:
|
|
47
|
+
"""A single chunk of process output."""
|
|
48
|
+
stream: str # "stdout" or "stderr"
|
|
49
|
+
data: str
|
|
50
|
+
raw_bytes: bytes = b""
|
|
51
|
+
timestamp: float = field(default_factory=time.time)
|
|
52
|
+
frame_index: int = 0
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
@dataclass
|
|
56
|
+
class CommandRecord:
|
|
57
|
+
"""Metadata for a executed command (for replay)."""
|
|
58
|
+
id: str
|
|
59
|
+
command: str
|
|
60
|
+
cwd: str = ""
|
|
61
|
+
started_at: float = field(default_factory=time.time)
|
|
62
|
+
finished_at: float | None = None
|
|
63
|
+
exit_code: int | None = None
|
|
64
|
+
frames: list[OutputFrame] = field(default_factory=list)
|
|
65
|
+
cancelled: bool = False
|
|
66
|
+
timeout_hit: bool = False
|
|
67
|
+
|
|
68
|
+
@property
|
|
69
|
+
def duration_ms(self) -> float:
|
|
70
|
+
end = self.finished_at or time.time()
|
|
71
|
+
return (end - self.started_at) * 1000
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def raw_output(self) -> str:
|
|
75
|
+
"""Raw output with ANSI preserved."""
|
|
76
|
+
return "".join(f.data for f in self.frames)
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def normalized_output(self) -> str:
|
|
80
|
+
"""Output with ANSI/control chars stripped."""
|
|
81
|
+
return normalize_vt(self.raw_output)
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def stdout(self) -> str:
|
|
85
|
+
return normalize_vt("".join(f.data for f in self.frames if f.stream == "stdout"))
|
|
86
|
+
|
|
87
|
+
@property
|
|
88
|
+
def stderr(self) -> str:
|
|
89
|
+
return normalize_vt("".join(f.data for f in self.frames if f.stream == "stderr"))
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
# ── shell session ─────────────────────────────────────────────────────
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class ShellSession:
|
|
96
|
+
"""Pseudoterminal boundary for shell command execution.
|
|
97
|
+
|
|
98
|
+
Wraps subprocess execution with:
|
|
99
|
+
- streaming output frames
|
|
100
|
+
- raw + normalized output preservation
|
|
101
|
+
- timeout/cancellation
|
|
102
|
+
- command replay metadata
|
|
103
|
+
- ANSI/VT normalization
|
|
104
|
+
"""
|
|
105
|
+
|
|
106
|
+
def __init__(self, cwd: str = "", default_timeout: int = 120):
|
|
107
|
+
self.cwd = cwd
|
|
108
|
+
self.default_timeout = default_timeout
|
|
109
|
+
self.history: list[CommandRecord] = []
|
|
110
|
+
self._cancelled_ids: set[str] = set()
|
|
111
|
+
|
|
112
|
+
def execute(self, command: str, timeout: int | None = None) -> CommandRecord:
|
|
113
|
+
"""Execute a command and return its record.
|
|
114
|
+
|
|
115
|
+
This is a synchronous wrapper. For real streaming, use execute_streaming.
|
|
116
|
+
"""
|
|
117
|
+
import subprocess
|
|
118
|
+
|
|
119
|
+
rec = CommandRecord(id=str(uuid.uuid4()), command=command, cwd=self.cwd)
|
|
120
|
+
effective_timeout = timeout or self.default_timeout
|
|
121
|
+
|
|
122
|
+
try:
|
|
123
|
+
proc = subprocess.run(
|
|
124
|
+
command,
|
|
125
|
+
cwd=self.cwd or None,
|
|
126
|
+
capture_output=True,
|
|
127
|
+
text=True,
|
|
128
|
+
timeout=effective_timeout,
|
|
129
|
+
shell=True,
|
|
130
|
+
)
|
|
131
|
+
rec.frames.append(OutputFrame(
|
|
132
|
+
stream="stdout", data=proc.stdout,
|
|
133
|
+
raw_bytes=proc.stdout.encode("utf-8", errors="replace"),
|
|
134
|
+
frame_index=0,
|
|
135
|
+
))
|
|
136
|
+
rec.frames.append(OutputFrame(
|
|
137
|
+
stream="stderr", data=proc.stderr,
|
|
138
|
+
raw_bytes=proc.stderr.encode("utf-8", errors="replace"),
|
|
139
|
+
frame_index=1,
|
|
140
|
+
))
|
|
141
|
+
rec.exit_code = proc.returncode
|
|
142
|
+
rec.finished_at = time.time()
|
|
143
|
+
except subprocess.TimeoutExpired as e:
|
|
144
|
+
rec.timeout_hit = True
|
|
145
|
+
rec.exit_code = -1
|
|
146
|
+
rec.finished_at = time.time()
|
|
147
|
+
if e.stdout:
|
|
148
|
+
rec.frames.append(OutputFrame(stream="stdout", data=e.stdout.decode("utf-8", errors="replace") if isinstance(e.stdout, bytes) else str(e.stdout), frame_index=0))
|
|
149
|
+
if e.stderr:
|
|
150
|
+
rec.frames.append(OutputFrame(stream="stderr", data=e.stderr.decode("utf-8", errors="replace") if isinstance(e.stderr, bytes) else str(e.stderr), frame_index=1))
|
|
151
|
+
except Exception as e:
|
|
152
|
+
rec.exit_code = -1
|
|
153
|
+
rec.finished_at = time.time()
|
|
154
|
+
rec.frames.append(OutputFrame(stream="stderr", data=str(e), frame_index=0))
|
|
155
|
+
|
|
156
|
+
self.history.append(rec)
|
|
157
|
+
return rec
|
|
158
|
+
|
|
159
|
+
def cancel(self, command_id: str) -> None:
|
|
160
|
+
"""Mark a command as cancelled (for async execution)."""
|
|
161
|
+
self._cancelled_ids.add(command_id)
|
|
162
|
+
|
|
163
|
+
def is_cancelled(self, command_id: str) -> bool:
|
|
164
|
+
return command_id in self._cancelled_ids
|
|
165
|
+
|
|
166
|
+
def replay(self, command_id: str) -> CommandRecord | None:
|
|
167
|
+
"""Get a past command record for replay/inspection."""
|
|
168
|
+
for rec in self.history:
|
|
169
|
+
if rec.id == command_id:
|
|
170
|
+
return rec
|
|
171
|
+
return None
|
|
172
|
+
|
|
173
|
+
def recent(self, n: int = 10) -> list[CommandRecord]:
|
|
174
|
+
"""Get the N most recent command records."""
|
|
175
|
+
return self.history[-n:]
|
|
176
|
+
|
|
177
|
+
def stats(self) -> dict[str, Any]:
|
|
178
|
+
total = len(self.history)
|
|
179
|
+
succeeded = sum(1 for r in self.history if r.exit_code == 0)
|
|
180
|
+
failed = sum(1 for r in self.history if r.exit_code is not None and r.exit_code != 0)
|
|
181
|
+
timeouts = sum(1 for r in self.history if r.timeout_hit)
|
|
182
|
+
return {
|
|
183
|
+
"total": total,
|
|
184
|
+
"succeeded": succeeded,
|
|
185
|
+
"failed": failed,
|
|
186
|
+
"timeouts": timeouts,
|
|
187
|
+
"avg_duration_ms": sum(r.duration_ms for r in self.history) / max(total, 1),
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
# ── shell guardrail parser ────────────────────────────────────────────
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
_BLOCKED_PATTERNS = [
|
|
195
|
+
(r"<<\s*['\"]?EOF", "heredoc not supported in cmd.exe"),
|
|
196
|
+
(r"<<\s*['\"]?PY", "heredoc not supported in cmd.exe"),
|
|
197
|
+
(r"python\s+-c\s+\"[^\"]*\\n", "literal \\n in python -c not supported in cmd.exe"),
|
|
198
|
+
(r"\bcat\s+<<", "cat heredoc not supported in cmd.exe"),
|
|
199
|
+
]
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def check_shell_safety(command: str, shell: str = "cmd") -> list[str]:
|
|
203
|
+
"""Check a command for shell-specific safety issues.
|
|
204
|
+
|
|
205
|
+
Returns a list of warning strings (empty if safe).
|
|
206
|
+
"""
|
|
207
|
+
if shell != "cmd":
|
|
208
|
+
return []
|
|
209
|
+
warnings: list[str] = []
|
|
210
|
+
for pattern, message in _BLOCKED_PATTERNS:
|
|
211
|
+
if re.search(pattern, command):
|
|
212
|
+
warnings.append(message)
|
|
213
|
+
return warnings
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"""B42. Source Registry + Policy-Aware Resolution (WinGet Pattern).
|
|
2
|
+
|
|
3
|
+
Manages multiple harness/plugin/model/document sources with priority,
|
|
4
|
+
trust levels, enabled flags, and policy locks. Higher-priority trusted
|
|
5
|
+
sources win resolution conflicts.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from dataclasses import dataclass, field
|
|
11
|
+
from datetime import datetime
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class SourceType:
|
|
16
|
+
HARNESS = "harness"
|
|
17
|
+
PLUGIN = "plugin"
|
|
18
|
+
MODEL = "model"
|
|
19
|
+
DOCUMENT = "document"
|
|
20
|
+
PROJECT = "project"
|
|
21
|
+
KNOWLEDGE_GRAPH = "knowledge_graph"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class Source:
|
|
26
|
+
"""A registered content source."""
|
|
27
|
+
|
|
28
|
+
source_id: str
|
|
29
|
+
source_type: str
|
|
30
|
+
path: str = ""
|
|
31
|
+
priority: int = 100 # lower = higher priority
|
|
32
|
+
trust_level: str = "trusted" # "trusted", "untrusted", "blocked"
|
|
33
|
+
enabled: bool = True
|
|
34
|
+
last_refresh: str = ""
|
|
35
|
+
policy_locked: bool = False
|
|
36
|
+
metadata: dict[str, Any] = field(default_factory=dict)
|
|
37
|
+
|
|
38
|
+
def can_resolve(self) -> bool:
|
|
39
|
+
return self.enabled and self.trust_level != "blocked"
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
@dataclass
|
|
43
|
+
class SourceRecord:
|
|
44
|
+
"""A record retrieved from a source, with provenance."""
|
|
45
|
+
source_id: str
|
|
46
|
+
record_id: str
|
|
47
|
+
content: Any
|
|
48
|
+
trust_level: str = "trusted"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class SourceRegistry:
|
|
52
|
+
"""Policy-aware source registry with priority resolution."""
|
|
53
|
+
|
|
54
|
+
def __init__(self) -> None:
|
|
55
|
+
self._sources: dict[str, Source] = {}
|
|
56
|
+
|
|
57
|
+
def add(self, source: Source) -> None:
|
|
58
|
+
self._sources[source.source_id] = source
|
|
59
|
+
|
|
60
|
+
def remove(self, source_id: str) -> bool:
|
|
61
|
+
return self._sources.pop(source_id, None) is not None
|
|
62
|
+
|
|
63
|
+
def get(self, source_id: str) -> Source | None:
|
|
64
|
+
return self._sources.get(source_id)
|
|
65
|
+
|
|
66
|
+
def list_all(self) -> list[Source]:
|
|
67
|
+
return list(self._sources.values())
|
|
68
|
+
|
|
69
|
+
def list_enabled(self) -> list[Source]:
|
|
70
|
+
return [s for s in self._sources.values() if s.enabled]
|
|
71
|
+
|
|
72
|
+
def list_by_type(self, source_type: str) -> list[Source]:
|
|
73
|
+
return [s for s in self._sources.values() if s.source_type == source_type]
|
|
74
|
+
|
|
75
|
+
def resolve(self, record_id: str, candidates: list[SourceRecord]) -> SourceRecord | None:
|
|
76
|
+
"""Resolve a record from multiple sources by priority/trust.
|
|
77
|
+
|
|
78
|
+
Higher-priority (lower number) trusted sources win.
|
|
79
|
+
"""
|
|
80
|
+
enabled_sources = {s.source_id: s for s in self._sources.values() if s.can_resolve()}
|
|
81
|
+
best: SourceRecord | None = None
|
|
82
|
+
best_priority = 999
|
|
83
|
+
for rec in candidates:
|
|
84
|
+
src = enabled_sources.get(rec.source_id)
|
|
85
|
+
if not src:
|
|
86
|
+
continue
|
|
87
|
+
if src.priority < best_priority:
|
|
88
|
+
best = rec
|
|
89
|
+
best_priority = src.priority
|
|
90
|
+
return best
|
|
91
|
+
|
|
92
|
+
def disable(self, source_id: str) -> bool:
|
|
93
|
+
src = self._sources.get(source_id)
|
|
94
|
+
if src and not src.policy_locked:
|
|
95
|
+
src.enabled = False
|
|
96
|
+
return True
|
|
97
|
+
return False
|
|
98
|
+
|
|
99
|
+
def enable(self, source_id: str) -> bool:
|
|
100
|
+
src = self._sources.get(source_id)
|
|
101
|
+
if src:
|
|
102
|
+
src.enabled = True
|
|
103
|
+
return True
|
|
104
|
+
return False
|
|
105
|
+
|
|
106
|
+
def lock_policy(self, source_id: str) -> bool:
|
|
107
|
+
src = self._sources.get(source_id)
|
|
108
|
+
if src:
|
|
109
|
+
src.policy_locked = True
|
|
110
|
+
return True
|
|
111
|
+
return False
|
|
112
|
+
|
|
113
|
+
def refresh(self, source_id: str) -> bool:
|
|
114
|
+
src = self._sources.get(source_id)
|
|
115
|
+
if src:
|
|
116
|
+
src.last_refresh = datetime.now().isoformat()
|
|
117
|
+
return True
|
|
118
|
+
return False
|
|
119
|
+
|
|
120
|
+
def health(self) -> list[dict[str, Any]]:
|
|
121
|
+
return [
|
|
122
|
+
{
|
|
123
|
+
"source_id": s.source_id,
|
|
124
|
+
"type": s.source_type,
|
|
125
|
+
"enabled": s.enabled,
|
|
126
|
+
"trust": s.trust_level,
|
|
127
|
+
"priority": s.priority,
|
|
128
|
+
"last_refresh": s.last_refresh,
|
|
129
|
+
"policy_locked": s.policy_locked,
|
|
130
|
+
}
|
|
131
|
+
for s in self._sources.values()
|
|
132
|
+
]
|
|
133
|
+
|
|
134
|
+
def conflicts(self) -> list[dict[str, Any]]:
|
|
135
|
+
"""Detect sources with same type and priority."""
|
|
136
|
+
by_key: dict[tuple[str, int], list[str]] = {}
|
|
137
|
+
for s in self._sources.values():
|
|
138
|
+
key = (s.source_type, s.priority)
|
|
139
|
+
by_key.setdefault(key, []).append(s.source_id)
|
|
140
|
+
return [
|
|
141
|
+
{"type": k[0], "priority": k[1], "sources": v}
|
|
142
|
+
for k, v in by_key.items() if len(v) > 1
|
|
143
|
+
]
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"""B76. Three Scales of Spawning.
|
|
2
|
+
|
|
3
|
+
Virtual File (2-4 agents) → Git Worktree (10-100) → Cloud Worker (100+).
|
|
4
|
+
Source: awesome-agentic-patterns.
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from enum import Enum, auto
|
|
10
|
+
from typing import Any
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class SpawnScale(Enum):
|
|
14
|
+
VIRTUAL_FILE = auto() # 2-4 agents, in-memory isolation
|
|
15
|
+
GIT_WORKTREE = auto() # 10-100 agents, filesystem isolation
|
|
16
|
+
CLOUD_WORKER = auto() # 100+ agents, container isolation
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@dataclass
|
|
20
|
+
class ScaleConfig:
|
|
21
|
+
scale: SpawnScale
|
|
22
|
+
max_agents: int
|
|
23
|
+
isolation_level: str # "memory", "filesystem", "container"
|
|
24
|
+
cost_per_agent: float # relative cost
|
|
25
|
+
setup_time_s: float # time to spawn one agent
|
|
26
|
+
cleanup_required: bool
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
DEFAULT_CONFIGS: dict[SpawnScale, ScaleConfig] = {
|
|
30
|
+
SpawnScale.VIRTUAL_FILE: ScaleConfig(
|
|
31
|
+
scale=SpawnScale.VIRTUAL_FILE,
|
|
32
|
+
max_agents=4,
|
|
33
|
+
isolation_level="memory",
|
|
34
|
+
cost_per_agent=0.1,
|
|
35
|
+
setup_time_s=0.01,
|
|
36
|
+
cleanup_required=False,
|
|
37
|
+
),
|
|
38
|
+
SpawnScale.GIT_WORKTREE: ScaleConfig(
|
|
39
|
+
scale=SpawnScale.GIT_WORKTREE,
|
|
40
|
+
max_agents=100,
|
|
41
|
+
isolation_level="filesystem",
|
|
42
|
+
cost_per_agent=0.5,
|
|
43
|
+
setup_time_s=0.5,
|
|
44
|
+
cleanup_required=True,
|
|
45
|
+
),
|
|
46
|
+
SpawnScale.CLOUD_WORKER: ScaleConfig(
|
|
47
|
+
scale=SpawnScale.CLOUD_WORKER,
|
|
48
|
+
max_agents=1000,
|
|
49
|
+
isolation_level="container",
|
|
50
|
+
cost_per_agent=2.0,
|
|
51
|
+
setup_time_s=5.0,
|
|
52
|
+
cleanup_required=True,
|
|
53
|
+
),
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class SpawnScaleSelector:
|
|
58
|
+
"""Select the appropriate spawning scale based on requirements."""
|
|
59
|
+
|
|
60
|
+
def select(self, num_agents: int, needs_filesystem: bool = False,
|
|
61
|
+
needs_network: bool = False, budget: float = 1.0) -> SpawnScale:
|
|
62
|
+
"""Choose the minimal scale that meets requirements."""
|
|
63
|
+
if num_agents <= 4 and not needs_filesystem and not needs_network:
|
|
64
|
+
return SpawnScale.VIRTUAL_FILE
|
|
65
|
+
if num_agents <= 100 and not needs_network:
|
|
66
|
+
return SpawnScale.GIT_WORKTREE
|
|
67
|
+
return SpawnScale.CLOUD_WORKER
|
|
68
|
+
|
|
69
|
+
def get_config(self, scale: SpawnScale) -> ScaleConfig:
|
|
70
|
+
return DEFAULT_CONFIGS[scale]
|
|
71
|
+
|
|
72
|
+
def estimate_cost(self, scale: SpawnScale, num_agents: int) -> float:
|
|
73
|
+
config = self.get_config(scale)
|
|
74
|
+
return config.cost_per_agent * num_agents
|
|
75
|
+
|
|
76
|
+
def validate(self, scale: SpawnScale, num_agents: int) -> list[str]:
|
|
77
|
+
"""Check if the scale can handle the requested agent count."""
|
|
78
|
+
issues: list[str] = []
|
|
79
|
+
config = self.get_config(scale)
|
|
80
|
+
if num_agents > config.max_agents:
|
|
81
|
+
issues.append(f"Too many agents: {num_agents} > {config.max_agents} for {scale.name}")
|
|
82
|
+
return issues
|
|
83
|
+
|
|
84
|
+
def recommend(self, num_agents: int, needs_filesystem: bool = False,
|
|
85
|
+
needs_network: bool = False, budget: float = 1.0) -> dict[str, Any]:
|
|
86
|
+
"""Get a recommendation with cost estimate."""
|
|
87
|
+
scale = self.select(num_agents, needs_filesystem, needs_network, budget)
|
|
88
|
+
config = self.get_config(scale)
|
|
89
|
+
cost = self.estimate_cost(scale, num_agents)
|
|
90
|
+
issues = self.validate(scale, num_agents)
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
"scale": scale.name,
|
|
94
|
+
"isolation": config.isolation_level,
|
|
95
|
+
"estimated_cost": cost,
|
|
96
|
+
"setup_time_s": config.setup_time_s * num_agents,
|
|
97
|
+
"cleanup_required": config.cleanup_required,
|
|
98
|
+
"issues": issues,
|
|
99
|
+
}
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"""H19 — Statistical Stability Guard.
|
|
2
|
+
|
|
3
|
+
Warn when sample sizes are too small for stable results.
|
|
4
|
+
Mined from GLOSSOPETRAE VALIDATION.md D4 (3-seed default yields ±15pt swing).
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import math
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class StabilityReport:
|
|
14
|
+
"""Report on statistical stability of a measurement."""
|
|
15
|
+
|
|
16
|
+
sample_size: int
|
|
17
|
+
mean: float
|
|
18
|
+
std_dev: float
|
|
19
|
+
margin_of_error: float
|
|
20
|
+
confidence_level: float
|
|
21
|
+
is_stable: bool
|
|
22
|
+
recommended_sample_size: int
|
|
23
|
+
warning: str = ""
|
|
24
|
+
|
|
25
|
+
def to_dict(self) -> dict[str, object]:
|
|
26
|
+
return {
|
|
27
|
+
"sample_size": self.sample_size,
|
|
28
|
+
"mean": self.mean,
|
|
29
|
+
"std_dev": self.std_dev,
|
|
30
|
+
"margin_of_error": self.margin_of_error,
|
|
31
|
+
"confidence_level": self.confidence_level,
|
|
32
|
+
"is_stable": self.is_stable,
|
|
33
|
+
"recommended_sample_size": self.recommended_sample_size,
|
|
34
|
+
"warning": self.warning,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# t-distribution critical values (two-tailed, 95% confidence)
|
|
39
|
+
_T_VALUES = {
|
|
40
|
+
1: 12.706, 2: 4.303, 3: 3.182, 4: 2.776, 5: 2.571,
|
|
41
|
+
6: 2.447, 7: 2.365, 8: 2.306, 9: 2.262, 10: 2.228,
|
|
42
|
+
15: 2.131, 20: 2.086, 25: 2.060, 30: 2.042, 40: 2.021,
|
|
43
|
+
50: 2.009, 100: 1.984, 200: 1.972, float("inf"): 1.960,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _t_value(df: int) -> float:
|
|
48
|
+
if df in _T_VALUES:
|
|
49
|
+
return _T_VALUES[df]
|
|
50
|
+
if df > 200:
|
|
51
|
+
return _T_VALUES[float("inf")]
|
|
52
|
+
# Find closest key
|
|
53
|
+
closest = min(_T_VALUES.keys(), key=lambda k: abs(k - df) if k != float("inf") else abs(200 - df))
|
|
54
|
+
return _T_VALUES[closest]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class StatisticalStabilityGuard:
|
|
58
|
+
"""Check if sample sizes are large enough for stable results."""
|
|
59
|
+
|
|
60
|
+
def __init__(self, target_margin: float = 0.02, confidence: float = 0.95) -> None:
|
|
61
|
+
self.target_margin = target_margin
|
|
62
|
+
self.confidence = confidence
|
|
63
|
+
|
|
64
|
+
def evaluate(self, values: list[float]) -> StabilityReport:
|
|
65
|
+
n = len(values)
|
|
66
|
+
if n == 0:
|
|
67
|
+
return StabilityReport(
|
|
68
|
+
sample_size=0, mean=0.0, std_dev=0.0, margin_of_error=float("inf"),
|
|
69
|
+
confidence_level=self.confidence, is_stable=False,
|
|
70
|
+
recommended_sample_size=1, warning="No samples",
|
|
71
|
+
)
|
|
72
|
+
mean = sum(values) / n
|
|
73
|
+
if n == 1:
|
|
74
|
+
return StabilityReport(
|
|
75
|
+
sample_size=1, mean=mean, std_dev=0.0, margin_of_error=float("inf"),
|
|
76
|
+
confidence_level=self.confidence, is_stable=False,
|
|
77
|
+
recommended_sample_size=30, warning="Single sample — cannot estimate variance",
|
|
78
|
+
)
|
|
79
|
+
variance = sum((v - mean) ** 2 for v in values) / (n - 1)
|
|
80
|
+
std_dev = math.sqrt(variance)
|
|
81
|
+
t = _t_value(n - 1)
|
|
82
|
+
margin = t * std_dev / math.sqrt(n)
|
|
83
|
+
# Recommended sample size for target margin
|
|
84
|
+
if std_dev > 0 and margin > 0:
|
|
85
|
+
recommended = int(math.ceil((t * std_dev / self.target_margin) ** 2))
|
|
86
|
+
else:
|
|
87
|
+
recommended = n
|
|
88
|
+
is_stable = margin <= self.target_margin
|
|
89
|
+
warning = ""
|
|
90
|
+
if not is_stable:
|
|
91
|
+
warning = (
|
|
92
|
+
f"Margin of error {margin:.4f} exceeds target {self.target_margin:.4f}. "
|
|
93
|
+
f"Need ~{recommended} samples (have {n})."
|
|
94
|
+
)
|
|
95
|
+
return StabilityReport(
|
|
96
|
+
sample_size=n,
|
|
97
|
+
mean=mean,
|
|
98
|
+
std_dev=std_dev,
|
|
99
|
+
margin_of_error=margin,
|
|
100
|
+
confidence_level=self.confidence,
|
|
101
|
+
is_stable=is_stable,
|
|
102
|
+
recommended_sample_size=max(recommended, n),
|
|
103
|
+
warning=warning,
|
|
104
|
+
)
|