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,1047 @@
|
|
|
1
|
+
"""Defensive ActionSpec registry and doctor checks for Algo CLI.
|
|
2
|
+
|
|
3
|
+
This registry is a first-pass source of truth for action/tool readiness,
|
|
4
|
+
approval risk, provider dependencies, and legacy visibility. It is diagnostic:
|
|
5
|
+
it does not weaken approval gates or execute actions.
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import ast
|
|
10
|
+
import json
|
|
11
|
+
import os
|
|
12
|
+
import shutil
|
|
13
|
+
import inspect
|
|
14
|
+
import textwrap
|
|
15
|
+
from dataclasses import asdict, dataclass, field
|
|
16
|
+
|
|
17
|
+
from .config import load_runtime_env
|
|
18
|
+
from typing import Any, Literal
|
|
19
|
+
from urllib.error import URLError
|
|
20
|
+
from urllib.request import urlopen
|
|
21
|
+
|
|
22
|
+
RiskLevel = Literal["low", "medium", "high"]
|
|
23
|
+
FindingStatus = Literal["ready", "degraded", "blocked"]
|
|
24
|
+
ActionKind = Literal["tool", "slash", "provider", "legacy", "kernel"]
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass(frozen=True)
|
|
28
|
+
class ActionSpec:
|
|
29
|
+
name: str
|
|
30
|
+
kind: ActionKind
|
|
31
|
+
description: str
|
|
32
|
+
group: str
|
|
33
|
+
tags: tuple[str, ...]
|
|
34
|
+
threat_detection_use: str
|
|
35
|
+
risk_level: RiskLevel
|
|
36
|
+
mutates_state: bool
|
|
37
|
+
requires_approval: bool
|
|
38
|
+
safe_retry: bool
|
|
39
|
+
requires_network: bool = False
|
|
40
|
+
requires_provider: str | None = None
|
|
41
|
+
requires_binary: tuple[str, ...] = ()
|
|
42
|
+
supported_os: tuple[str, ...] = ("windows", "linux", "macos")
|
|
43
|
+
prerequisites: tuple[str, ...] = ()
|
|
44
|
+
known_limitations: tuple[str, ...] = ()
|
|
45
|
+
archived: bool = False
|
|
46
|
+
archived_reason: str = ""
|
|
47
|
+
replacement: str = ""
|
|
48
|
+
|
|
49
|
+
def as_dict(self) -> dict[str, Any]:
|
|
50
|
+
return asdict(self)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@dataclass(frozen=True)
|
|
54
|
+
class DoctorFinding:
|
|
55
|
+
status: FindingStatus
|
|
56
|
+
area: str
|
|
57
|
+
message: str
|
|
58
|
+
recommendation: str = ""
|
|
59
|
+
|
|
60
|
+
def as_dict(self) -> dict[str, str]:
|
|
61
|
+
return asdict(self)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@dataclass(frozen=True)
|
|
65
|
+
class DoctorReport:
|
|
66
|
+
overall_status: FindingStatus
|
|
67
|
+
findings: tuple[DoctorFinding, ...] = field(default_factory=tuple)
|
|
68
|
+
|
|
69
|
+
def as_dict(self) -> dict[str, Any]:
|
|
70
|
+
return {
|
|
71
|
+
"overall_status": self.overall_status,
|
|
72
|
+
"findings": [finding.as_dict() for finding in self.findings],
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
def to_json(self) -> str:
|
|
76
|
+
return json.dumps(self.as_dict(), indent=2)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _spec(
|
|
80
|
+
name: str,
|
|
81
|
+
kind: ActionKind,
|
|
82
|
+
description: str,
|
|
83
|
+
group: str,
|
|
84
|
+
tags: tuple[str, ...],
|
|
85
|
+
threat_detection_use: str,
|
|
86
|
+
risk_level: RiskLevel,
|
|
87
|
+
mutates_state: bool,
|
|
88
|
+
requires_approval: bool,
|
|
89
|
+
safe_retry: bool,
|
|
90
|
+
**kwargs: Any,
|
|
91
|
+
) -> ActionSpec:
|
|
92
|
+
return ActionSpec(
|
|
93
|
+
name=name,
|
|
94
|
+
kind=kind,
|
|
95
|
+
description=description,
|
|
96
|
+
group=group,
|
|
97
|
+
tags=tags,
|
|
98
|
+
threat_detection_use=threat_detection_use,
|
|
99
|
+
risk_level=risk_level,
|
|
100
|
+
mutates_state=mutates_state,
|
|
101
|
+
requires_approval=requires_approval,
|
|
102
|
+
safe_retry=safe_retry,
|
|
103
|
+
**kwargs,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
ACTION_SPECS: tuple[ActionSpec, ...] = (
|
|
108
|
+
_spec(
|
|
109
|
+
"read_file", "tool", "Read a local text/PDF-adjacent file.", "read",
|
|
110
|
+
("file", "read-only", "local"),
|
|
111
|
+
"Supports evidence gathering without mutation.", "low", False, False, True,
|
|
112
|
+
),
|
|
113
|
+
_spec(
|
|
114
|
+
"write_file", "tool", "Create or overwrite a local file.", "write",
|
|
115
|
+
("file", "mutation", "approval"),
|
|
116
|
+
"Detects and gates workspace-changing file writes.", "high", True, True, False,
|
|
117
|
+
),
|
|
118
|
+
_spec(
|
|
119
|
+
"run_shell", "tool", "Run a shell command in the workspace.", "shell",
|
|
120
|
+
("shell", "mutation", "approval", "safe-mode"),
|
|
121
|
+
"Detects shell mutation risk and preserves safe-mode enforcement.", "high", True, True, False,
|
|
122
|
+
),
|
|
123
|
+
_spec(
|
|
124
|
+
"web_search", "tool", "Search the web through cloud tooling.", "web",
|
|
125
|
+
("web", "network", "provider"),
|
|
126
|
+
"Detects network/provider dependency before research actions.", "medium", False, False, True,
|
|
127
|
+
requires_network=True, requires_provider="ollama-cloud",
|
|
128
|
+
),
|
|
129
|
+
_spec(
|
|
130
|
+
"query_knowledge_graph", "tool", "Query index-compute-lab ranked associations.", "read",
|
|
131
|
+
("icl", "knowledge-graph", "read-only"),
|
|
132
|
+
"Detects local knowledge graph readiness for grounded context.", "low", False, False, True,
|
|
133
|
+
),
|
|
134
|
+
_spec(
|
|
135
|
+
"remember", "tool", "Store a durable user fact in local memory.", "memory",
|
|
136
|
+
("memory", "local", "mutation", "safe-retry"),
|
|
137
|
+
"Allows the runtime to retain an explicitly stated durable fact without exposing external state.",
|
|
138
|
+
"low", True, False, True,
|
|
139
|
+
),
|
|
140
|
+
_spec(
|
|
141
|
+
"append_lesson", "tool", "Append a durable lesson to local identity memory.", "memory",
|
|
142
|
+
("memory", "lesson", "local", "mutation", "safe-retry"),
|
|
143
|
+
"Allows same-turn retention of durable corrections and workflow lessons.",
|
|
144
|
+
"low", True, False, True,
|
|
145
|
+
),
|
|
146
|
+
_spec(
|
|
147
|
+
"model_delete", "tool", "Delete a local Ollama model.", "model",
|
|
148
|
+
("model", "destructive", "approval"),
|
|
149
|
+
"Detects destructive local model actions before execution.", "high", True, True, False,
|
|
150
|
+
requires_binary=("ollama",),
|
|
151
|
+
),
|
|
152
|
+
_spec(
|
|
153
|
+
"/safe", "slash", "Show or toggle safe mode.", "session",
|
|
154
|
+
("safety", "toggle"),
|
|
155
|
+
"Surfaces shell/file safety posture.", "medium", True, True, True,
|
|
156
|
+
),
|
|
157
|
+
_spec(
|
|
158
|
+
"/auto", "slash", "Show or toggle auto-approval.", "session",
|
|
159
|
+
("approval", "toggle"),
|
|
160
|
+
"Surfaces whether mutating actions may be auto-approved.", "high", True, True, True,
|
|
161
|
+
),
|
|
162
|
+
_spec(
|
|
163
|
+
"/memory-auto", "slash", "Show or toggle bounded automatic memory capture.", "memory",
|
|
164
|
+
("memory", "privacy", "toggle"),
|
|
165
|
+
"Exposes the deterministic durable-memory completion gate and its persisted opt-out.",
|
|
166
|
+
"medium", True, True, True,
|
|
167
|
+
),
|
|
168
|
+
_spec(
|
|
169
|
+
"/code-rag", "slash", "Show or toggle working-directory code retrieval.", "harness",
|
|
170
|
+
("code-rag", "privacy", "local-index", "toggle"),
|
|
171
|
+
"Requires explicit versioned consent before cwd snippets can enter model prompts.",
|
|
172
|
+
"medium", True, True, True,
|
|
173
|
+
known_limitations=(
|
|
174
|
+
"When enabled, retrieved snippets join the active provider request; /code-rag off purges persisted indexes.",
|
|
175
|
+
),
|
|
176
|
+
),
|
|
177
|
+
_spec(
|
|
178
|
+
"/actions", "slash", "Show available actions.", "session",
|
|
179
|
+
("registry", "read-only"),
|
|
180
|
+
"Exposes safe capability discovery.", "low", False, False, True,
|
|
181
|
+
),
|
|
182
|
+
_spec(
|
|
183
|
+
"/doctor", "slash", "Show provider, dependency, ICL, and safety readiness.", "session",
|
|
184
|
+
("doctor", "readiness", "threat-detection"),
|
|
185
|
+
"Detects missing credentials, unavailable providers, and unsafe posture.", "low", False, False, True,
|
|
186
|
+
),
|
|
187
|
+
_spec(
|
|
188
|
+
"/intelligence", "slash", "Run repository intelligence status/query/reindex commands.", "harness",
|
|
189
|
+
("intelligence", "project-graph", "read-only"),
|
|
190
|
+
"Exposes local project graph inspection through the agent runtime.", "low", False, False, True,
|
|
191
|
+
known_limitations=("The reindex subcommand persists .algo/index/project_graph.json and may require approval.",),
|
|
192
|
+
),
|
|
193
|
+
_spec(
|
|
194
|
+
"/intel", "slash", "Alias for /intelligence.", "harness",
|
|
195
|
+
("intelligence", "alias", "project-graph"),
|
|
196
|
+
"Keeps the short repository intelligence command discoverable for agent/runtime use.", "low", False, False, True,
|
|
197
|
+
replacement="/intelligence",
|
|
198
|
+
),
|
|
199
|
+
_spec(
|
|
200
|
+
"/intelagence", "slash", "Alias for /intelligence.", "harness",
|
|
201
|
+
("intelligence", "alias", "project-graph"),
|
|
202
|
+
"Keeps the misspelled runtime command discoverable for compatibility.", "low", False, False, True,
|
|
203
|
+
replacement="/intelligence",
|
|
204
|
+
),
|
|
205
|
+
_spec(
|
|
206
|
+
"/kernel", "slash", "Inspect promoted Algo CLI kernel specs.",
|
|
207
|
+
"kernel",
|
|
208
|
+
("kernel", "registry", "read-only"),
|
|
209
|
+
"Exposes productionized kernel metadata without executing intelligence workloads.", "low", False, False, True,
|
|
210
|
+
),
|
|
211
|
+
_spec(
|
|
212
|
+
"kernel.list", "kernel", "List promoted Algo CLI kernel specs.",
|
|
213
|
+
"kernel",
|
|
214
|
+
("kernel", "registry", "read-only"),
|
|
215
|
+
"Discovers promoted kernels without importing or executing workload modules.", "low", False, False, True,
|
|
216
|
+
),
|
|
217
|
+
_spec(
|
|
218
|
+
"kernel.show", "kernel", "Show one promoted Algo CLI kernel spec.",
|
|
219
|
+
"kernel",
|
|
220
|
+
("kernel", "registry", "read-only"),
|
|
221
|
+
"Inspects a named kernel contract without importing or executing workload modules.", "low", False, False, True,
|
|
222
|
+
),
|
|
223
|
+
_spec(
|
|
224
|
+
"agent.plan", "kernel", "Route and plan a bounded Agent Blocks run.",
|
|
225
|
+
"kernel",
|
|
226
|
+
("agent", "planning", "read-only"),
|
|
227
|
+
"Keeps task routing and block budgets visible before execution.", "low", False, False, True,
|
|
228
|
+
known_limitations=("Invoked through /agent and /route; not a standalone model-callable tool.",),
|
|
229
|
+
),
|
|
230
|
+
_spec(
|
|
231
|
+
"agent.delegate", "kernel", "Run a bounded 2-4 specialist agent team.",
|
|
232
|
+
"kernel",
|
|
233
|
+
("agent", "delegation", "approval", "multi-agent"),
|
|
234
|
+
"Gates multi-model fan-out and the integrating pipeline behind explicit approval.", "medium", True, True, False,
|
|
235
|
+
known_limitations=("Child specialists are read-only; the integration pipeline is the sole mutation owner.",),
|
|
236
|
+
),
|
|
237
|
+
_spec(
|
|
238
|
+
"agent.report", "kernel", "Inspect agent thread status and evidence.",
|
|
239
|
+
"kernel",
|
|
240
|
+
("agent", "thread", "report", "read-only"),
|
|
241
|
+
"Exposes bounded parent/child evidence without rerunning work.", "low", False, False, True,
|
|
242
|
+
known_limitations=("Invoked through /agent threads and /agent show.",),
|
|
243
|
+
),
|
|
244
|
+
_spec(
|
|
245
|
+
"agent.thread.resume", "kernel", "Resume or fork a persisted agent thread.",
|
|
246
|
+
"kernel",
|
|
247
|
+
("agent", "thread", "resume", "approval"),
|
|
248
|
+
"Requires approval before continuing a run that may reach mutation-capable integration blocks.", "medium", True, True, False,
|
|
249
|
+
known_limitations=("Invoked through /agent resume or /agent fork; recursive delegation remains blocked.",),
|
|
250
|
+
),
|
|
251
|
+
_spec(
|
|
252
|
+
"small_context.ledger.write", "kernel", "Write bounded optional context to a temporary ledger.",
|
|
253
|
+
"kernel",
|
|
254
|
+
("context", "small-model", "temporary", "local"),
|
|
255
|
+
"Preserves full optional context for compact models while keeping the live prompt bounded.",
|
|
256
|
+
"low", True, False, True,
|
|
257
|
+
known_limitations=("Writes only beneath the OS temporary directory and never replaces source files.",),
|
|
258
|
+
),
|
|
259
|
+
_spec(
|
|
260
|
+
"small_context.ledger.preview", "kernel", "Preview small-context ledger activation.",
|
|
261
|
+
"kernel",
|
|
262
|
+
("context", "small-model", "read-only"),
|
|
263
|
+
"Explains whether the current model window activates external context storage.",
|
|
264
|
+
"low", False, False, True,
|
|
265
|
+
),
|
|
266
|
+
_spec(
|
|
267
|
+
"extensions.manifest", "kernel", "Build an extension and helper readiness manifest.",
|
|
268
|
+
"kernel",
|
|
269
|
+
("extensions", "manifest", "read-only"),
|
|
270
|
+
"Reports plugin and helper-binary readiness without loading plugin code.",
|
|
271
|
+
"low", False, False, True,
|
|
272
|
+
),
|
|
273
|
+
_spec(
|
|
274
|
+
"vision.screenshot_verify", "kernel", "Verify screenshot-description evidence.",
|
|
275
|
+
"kernel",
|
|
276
|
+
("vision", "verification", "read-only"),
|
|
277
|
+
"Turns expected and forbidden visual terms into a structured pass/fail result.",
|
|
278
|
+
"low", False, False, True,
|
|
279
|
+
),
|
|
280
|
+
_spec(
|
|
281
|
+
"session_distribution.summarize", "kernel", "Summarize harness source concentration.",
|
|
282
|
+
"kernel",
|
|
283
|
+
("harness", "telemetry", "distribution", "read-only"),
|
|
284
|
+
"Flags heavy-tail concentration that can bias retrieval and evaluation results.",
|
|
285
|
+
"low", False, False, True,
|
|
286
|
+
),
|
|
287
|
+
_spec(
|
|
288
|
+
"benchmark.compare", "kernel", "Recompute the five-axis comparative harness rating.",
|
|
289
|
+
"kernel",
|
|
290
|
+
("benchmark", "competitive", "read-only", "fail-closed"),
|
|
291
|
+
"Rejects arithmetic errors, ties, stale competitor evidence, and unsupported leader claims.",
|
|
292
|
+
"low", False, False, True,
|
|
293
|
+
),
|
|
294
|
+
_spec(
|
|
295
|
+
"benchmark.report", "kernel", "Run the internal ten-gate harness readiness scorecard.",
|
|
296
|
+
"kernel",
|
|
297
|
+
("benchmark", "scorecard", "read-only", "evidence"),
|
|
298
|
+
"Surfaces retrieval, memory, maintenance, and benchmark regressions with structured evidence.",
|
|
299
|
+
"low", False, False, True,
|
|
300
|
+
),
|
|
301
|
+
_spec(
|
|
302
|
+
"benchmark.algorithm_effectiveness", "kernel", "Probe production-path algorithm effectiveness.",
|
|
303
|
+
"kernel",
|
|
304
|
+
("benchmark", "algorithm", "production-path", "read-only"),
|
|
305
|
+
"Requires receipts from every declared retrieval/cache/admission algorithm before readiness.",
|
|
306
|
+
"low", False, False, True,
|
|
307
|
+
),
|
|
308
|
+
_spec(
|
|
309
|
+
"repo.status", "kernel", "Inspect repository-intelligence readiness and exports.",
|
|
310
|
+
"kernel",
|
|
311
|
+
("repository", "intelligence", "status", "read-only"),
|
|
312
|
+
"Shows the active project root and graph capabilities without writing an index.",
|
|
313
|
+
"low", False, False, True,
|
|
314
|
+
),
|
|
315
|
+
_spec(
|
|
316
|
+
"repo.query", "kernel", "Build an in-memory project graph and query it.",
|
|
317
|
+
"kernel",
|
|
318
|
+
("repository", "intelligence", "query", "read-only"),
|
|
319
|
+
"Provides symbol/file evidence for runtime navigation without persisting graph state.",
|
|
320
|
+
"low", False, False, True,
|
|
321
|
+
),
|
|
322
|
+
_spec(
|
|
323
|
+
"repo.reindex", "kernel", "Persist the repository project graph index.",
|
|
324
|
+
"kernel",
|
|
325
|
+
("repository", "intelligence", "index", "mutation", "approval"),
|
|
326
|
+
"Refreshes local graph state and keeps model-triggered writes approval-gated.",
|
|
327
|
+
"medium", True, True, True,
|
|
328
|
+
),
|
|
329
|
+
_spec(
|
|
330
|
+
"harness.fusion.lexical_rank", "kernel", "Rank harness records with BM25 plus curated field boosts.",
|
|
331
|
+
"kernel",
|
|
332
|
+
("harness", "retrieval", "bm25", "lexical", "read-only"),
|
|
333
|
+
"Weights rare exact terms without discarding title, path, or canonical catalog priorities.",
|
|
334
|
+
"low", False, False, True,
|
|
335
|
+
),
|
|
336
|
+
_spec(
|
|
337
|
+
"harness.fusion.rank", "kernel", "Fuse BM25 and exact-vector rankings with Reciprocal Rank Fusion.",
|
|
338
|
+
"kernel",
|
|
339
|
+
("harness", "retrieval", "rrf", "fusion", "read-only"),
|
|
340
|
+
"Uses both exact lexical and semantic evidence for automatic prompt context and slash search.",
|
|
341
|
+
"low", False, False, True,
|
|
342
|
+
),
|
|
343
|
+
_spec(
|
|
344
|
+
"harness.fusion.explain", "kernel", "Expose lexical, vector, and RRF rank provenance.",
|
|
345
|
+
"kernel",
|
|
346
|
+
("harness", "retrieval", "provenance", "telemetry", "read-only"),
|
|
347
|
+
"Makes every fused result attributable to its contributing rankers and component scores.",
|
|
348
|
+
"low", False, False, True,
|
|
349
|
+
),
|
|
350
|
+
_spec(
|
|
351
|
+
"harness.index.refresh_changed", "kernel", "Refresh changed harness records and content-addressed code chunks.",
|
|
352
|
+
"kernel",
|
|
353
|
+
("harness", "index", "incremental", "content-hash", "mutation", "approval"),
|
|
354
|
+
"Reuses unchanged records and content-identical chunk embeddings before rebuilding sidecars.",
|
|
355
|
+
"medium", True, True, True,
|
|
356
|
+
),
|
|
357
|
+
_spec(
|
|
358
|
+
"harness.index.status", "kernel", "Inspect incremental index reuse and embedding readiness.",
|
|
359
|
+
"kernel",
|
|
360
|
+
("harness", "index", "incremental", "status", "read-only"),
|
|
361
|
+
"Surfaces record reuse, content-addressed embedding reuse, and rebuild work without mutation.",
|
|
362
|
+
"low", False, False, True,
|
|
363
|
+
),
|
|
364
|
+
_spec(
|
|
365
|
+
"chain.evaluate", "kernel", "Evaluate the ordered runtime tool policy chain.",
|
|
366
|
+
"kernel",
|
|
367
|
+
("policy", "chain", "enforcement", "read-only"),
|
|
368
|
+
"Fail-closes unknown tools, invalid capability tiers, and safe-mode shell mutations.",
|
|
369
|
+
"medium", False, False, True,
|
|
370
|
+
),
|
|
371
|
+
_spec(
|
|
372
|
+
"chain.audit", "kernel", "Record runtime policy-chain decisions in telemetry.",
|
|
373
|
+
"kernel",
|
|
374
|
+
("policy", "audit", "telemetry", "read-only"),
|
|
375
|
+
"Preserves tier, capability mask, and fired-rule evidence for every tool preflight.",
|
|
376
|
+
"low", False, False, True,
|
|
377
|
+
),
|
|
378
|
+
_spec(
|
|
379
|
+
"capability.mask", "kernel", "Compute a stable capability mask for a runtime tool.",
|
|
380
|
+
"kernel",
|
|
381
|
+
("policy", "capability", "mask", "read-only"),
|
|
382
|
+
"Maps tool requirements to stable read/write/shell/network/model capability bits.",
|
|
383
|
+
"low", False, False, True,
|
|
384
|
+
),
|
|
385
|
+
_spec(
|
|
386
|
+
"capability.tier", "kernel", "Assign the least-privileged runtime capability tier.",
|
|
387
|
+
"kernel",
|
|
388
|
+
("policy", "capability", "tier", "least-privilege"),
|
|
389
|
+
"Ensures each tool's capability mask fits its structural permission tier.",
|
|
390
|
+
"low", False, False, True,
|
|
391
|
+
),
|
|
392
|
+
_spec(
|
|
393
|
+
"runtime.qos.classify", "kernel", "Classify every model tool dispatch by runtime posture.",
|
|
394
|
+
"kernel",
|
|
395
|
+
("runtime", "qos", "dispatch", "telemetry"),
|
|
396
|
+
"Labels tool calls adaptive, interactive, or background before execution.",
|
|
397
|
+
"low", False, False, True,
|
|
398
|
+
),
|
|
399
|
+
_spec(
|
|
400
|
+
"runtime.qos.schedule", "kernel", "Order bounded tool batches by QoS class weight and estimated cost.",
|
|
401
|
+
"kernel",
|
|
402
|
+
("runtime", "qos", "scheduler", "bounded-batch"),
|
|
403
|
+
"Provides deterministic submission order; the queue primitive also exposes aging for persistent callers.",
|
|
404
|
+
"low", False, False, True,
|
|
405
|
+
known_limitations=(
|
|
406
|
+
"Typical batches that fit the worker pool start together; persistent cross-batch aging is not wired.",
|
|
407
|
+
),
|
|
408
|
+
),
|
|
409
|
+
_spec(
|
|
410
|
+
"runtime.log_path", "kernel", "Attach a stable named log destination to tool telemetry.",
|
|
411
|
+
"kernel",
|
|
412
|
+
("runtime", "qos", "logs", "sensitive-data"),
|
|
413
|
+
"Provides per-tool log destinations while suppressing credential-bearing tool logs.",
|
|
414
|
+
"low", False, False, True,
|
|
415
|
+
known_limitations=("The runtime records the destination as metadata; subprocess redirection remains tool-specific.",),
|
|
416
|
+
),
|
|
417
|
+
_spec(
|
|
418
|
+
"tool_sequence.score", "kernel", "Score recent runtime tool cadence from the bounded attempt ledger.",
|
|
419
|
+
"kernel",
|
|
420
|
+
("runtime", "quality", "verification", "read-only"),
|
|
421
|
+
"Surfaces verification-after-edit and test-repair cadence without inspecting private reasoning.",
|
|
422
|
+
"low", False, False, True,
|
|
423
|
+
known_limitations=("Private model reasoning is deliberately not persisted or scored by /selfcheck.",),
|
|
424
|
+
),
|
|
425
|
+
_spec(
|
|
426
|
+
"cache.tinylfu.admit", "kernel", "Protect hot embedding-cache entries from one-off scan pollution.",
|
|
427
|
+
"kernel",
|
|
428
|
+
("cache", "memory", "tinylfu", "bounded", "admission"),
|
|
429
|
+
"Uses recency plus bounded frequency evidence before evicting reusable query vectors.",
|
|
430
|
+
"low", False, False, True,
|
|
431
|
+
),
|
|
432
|
+
_spec(
|
|
433
|
+
"cache.tinylfu.stats", "kernel", "Expose bounded cache admission and hit-rate telemetry.",
|
|
434
|
+
"kernel",
|
|
435
|
+
("cache", "memory", "telemetry", "read-only"),
|
|
436
|
+
"Makes cache hit, rejection, eviction, and sketch-decay behavior measurable.",
|
|
437
|
+
"low", False, False, True,
|
|
438
|
+
),
|
|
439
|
+
_spec(
|
|
440
|
+
"performance.cusum.detect", "kernel", "Detect sustained runtime latency shifts with robust CUSUM.",
|
|
441
|
+
"kernel",
|
|
442
|
+
("performance", "telemetry", "regression", "cusum", "read-only"),
|
|
443
|
+
"Separates sustained regressions from isolated latency spikes using comparable event series.",
|
|
444
|
+
"low", False, False, True,
|
|
445
|
+
),
|
|
446
|
+
_spec(
|
|
447
|
+
"performance.cusum.selfcheck", "kernel", "Surface latency trend evidence in /selfcheck.",
|
|
448
|
+
"kernel",
|
|
449
|
+
("performance", "selfcheck", "diagnostics", "read-only"),
|
|
450
|
+
"Reports stable, improving, regressing, or insufficient-data state without model inference.",
|
|
451
|
+
"low", False, False, True,
|
|
452
|
+
),
|
|
453
|
+
_spec(
|
|
454
|
+
"ollama-cli-env", "legacy", "Legacy OLLAMA_CLI_* environment variables.", "legacy",
|
|
455
|
+
("legacy", "env", "deprecated"),
|
|
456
|
+
"Detects stale legacy configuration that may confuse model/provider routing.", "medium", False, False, True,
|
|
457
|
+
archived=True,
|
|
458
|
+
archived_reason="Algo CLI rebrand replaced OLLAMA_CLI_* names with ALGO_CLI_* names.",
|
|
459
|
+
replacement="Use ALGO_CLI_* environment variables and the algo-cli command.",
|
|
460
|
+
),
|
|
461
|
+
_spec(
|
|
462
|
+
"google_workspace.read", "provider", "Google Workspace access (read/write Drive/Docs/Sheets/Calendar plus Gmail read/draft creation) via OAuth.",
|
|
463
|
+
"provider",
|
|
464
|
+
("google-workspace", "oauth", "read-write", "network"),
|
|
465
|
+
"Provides Google Workspace access behind the /google-login OAuth flow; Gmail writes are limited to draft creation for user review.",
|
|
466
|
+
"medium", False, False, True,
|
|
467
|
+
requires_network=True,
|
|
468
|
+
requires_provider="google-workspace",
|
|
469
|
+
known_limitations=(
|
|
470
|
+
"Drive/Docs/Sheets/Calendar OAuth scopes are full read/write; CLI subcommands may expose write operations incrementally.",
|
|
471
|
+
"Gmail compose scope is used only for draft creation; direct send is not exposed.",
|
|
472
|
+
"Tokens stored in CONFIG_DIR/google_workspace_auth.json (POSIX 0600).",
|
|
473
|
+
),
|
|
474
|
+
),
|
|
475
|
+
_spec(
|
|
476
|
+
"/google-login", "slash", "Authenticate with Google Workspace (OAuth2 + PKCE).",
|
|
477
|
+
"provider",
|
|
478
|
+
("google-workspace", "oauth", "auth"),
|
|
479
|
+
"Detects missing GOOGLE_OAUTH_CLIENT_ID before starting the loopback flow.", "medium", True, True, True,
|
|
480
|
+
),
|
|
481
|
+
_spec(
|
|
482
|
+
"/google-logout", "slash", "Revoke Google Workspace tokens locally.",
|
|
483
|
+
"provider",
|
|
484
|
+
("google-workspace", "auth", "logout"),
|
|
485
|
+
"Clears local Google Workspace tokens and best-effort revokes at Google.", "medium", True, True, True,
|
|
486
|
+
),
|
|
487
|
+
_spec(
|
|
488
|
+
"/google-status", "slash", "Show Google Workspace auth state.",
|
|
489
|
+
"provider",
|
|
490
|
+
("google-workspace", "auth", "status"),
|
|
491
|
+
"Surfaces whether the user is authenticated and which scopes were granted.", "low", False, False, True,
|
|
492
|
+
),
|
|
493
|
+
_spec(
|
|
494
|
+
"/google", "slash", "Run Google Workspace commands (Drive/Docs/Sheets/Calendar read/write plus Gmail read/drafts).",
|
|
495
|
+
"provider",
|
|
496
|
+
("google-workspace", "command", "read-write", "gmail-drafts"),
|
|
497
|
+
"Dispatches to Google Workspace operations; Gmail direct send is not exposed.", "medium", False, False, True,
|
|
498
|
+
),
|
|
499
|
+
_spec(
|
|
500
|
+
"/plugins", "slash", "Show discovered and loaded plugins.",
|
|
501
|
+
"plugins",
|
|
502
|
+
("plugins", "discovery", "code-loading", "approval"),
|
|
503
|
+
"Lists plugin manifests; status mode imports plugin code and therefore remains approval-gated for model use.", "medium", True, True, False,
|
|
504
|
+
),
|
|
505
|
+
_spec(
|
|
506
|
+
"/credentials", "slash", "List credential helpers or check a named helper key with values redacted.",
|
|
507
|
+
"credentials",
|
|
508
|
+
("credentials", "auth", "read-only"),
|
|
509
|
+
"Surfaces registered credential helper backends and their status.", "low", False, False, True,
|
|
510
|
+
),
|
|
511
|
+
_spec(
|
|
512
|
+
"/url-scheme", "slash", "Parse an algo-cli:// deep link.",
|
|
513
|
+
"url-scheme",
|
|
514
|
+
("url-scheme", "deep-link", "read-only"),
|
|
515
|
+
"Parses and validates algo-cli:// URLs for deep-linking from other tools.", "low", False, False, True,
|
|
516
|
+
),
|
|
517
|
+
_spec(
|
|
518
|
+
"plugins_discover", "tool", "Discover plugins from ~/.algo_cli/plugins/ directory.",
|
|
519
|
+
"plugins",
|
|
520
|
+
("plugins", "discovery", "read-only"),
|
|
521
|
+
"Discovers plugin manifests from the plugins directory.", "low", False, False, True,
|
|
522
|
+
),
|
|
523
|
+
_spec(
|
|
524
|
+
"plugins_load", "tool", "Explicitly import a discovered experimental plugin.",
|
|
525
|
+
"plugins",
|
|
526
|
+
("plugins", "loading", "mutation"),
|
|
527
|
+
"Imports plugin code after approval and reports module load status.", "medium", True, True, False,
|
|
528
|
+
known_limitations=("Dynamic action, slash-command, and tool registration is not wired into the stable runtime.",),
|
|
529
|
+
),
|
|
530
|
+
_spec(
|
|
531
|
+
"version_manifest_build", "tool", "Build a version manifest with CLI, Python, platform, harness, and plugin versions.",
|
|
532
|
+
"version",
|
|
533
|
+
("version", "manifest", "read-only"),
|
|
534
|
+
"Assembles full system version state for debugging and reporting.", "low", False, False, True,
|
|
535
|
+
),
|
|
536
|
+
_spec(
|
|
537
|
+
"extensions_manifest_build", "tool", "Build an extension manifest with plugin/helper binary versions and status.",
|
|
538
|
+
"version",
|
|
539
|
+
("version", "manifest", "extensions", "read-only"),
|
|
540
|
+
"Assembles plugin/helper component state as a sibling to version_manifest_build.", "low", False, False, True,
|
|
541
|
+
),
|
|
542
|
+
_spec(
|
|
543
|
+
"runtime_qos_hint", "tool", "Classify a tool call's runtime QoS and named log destination.",
|
|
544
|
+
"runtime",
|
|
545
|
+
("runtime", "qos", "logs", "read-only"),
|
|
546
|
+
"Applies launchd-style POSIXSpawnType and StandardErrorPath patterns to tool calls.", "low", False, False, True,
|
|
547
|
+
),
|
|
548
|
+
_spec(
|
|
549
|
+
"screenshot_description_verify", "tool", "Verify a screenshot description against expected and forbidden terms.",
|
|
550
|
+
"vision",
|
|
551
|
+
("vision", "verification", "screenshot", "read-only"),
|
|
552
|
+
"Turns browser/vision screenshot descriptions into structured pass/fail evidence.", "low", False, False, True,
|
|
553
|
+
),
|
|
554
|
+
_spec(
|
|
555
|
+
"capability_mask_describe", "tool", "Describe a stable capability bit mask from a tier and/or capability names.",
|
|
556
|
+
"policy",
|
|
557
|
+
("policy", "capability", "bit-mask", "read-only"),
|
|
558
|
+
"Provides Apple audit_class-style stable numeric capability masks for tools and kernels.", "low", False, False, True,
|
|
559
|
+
),
|
|
560
|
+
_spec(
|
|
561
|
+
"small_context_ledger_preview", "tool", "Preview the small-context ledger activation decision for a model/window.",
|
|
562
|
+
"context",
|
|
563
|
+
("context", "small-model", "ledger", "read-only"),
|
|
564
|
+
"Shows whether a <75k context model will use the temp context-ledger refresh path.", "low", False, False, True,
|
|
565
|
+
),
|
|
566
|
+
_spec(
|
|
567
|
+
"credential_helpers_get", "tool", "Check a named helper for credential presence without exposing plaintext.",
|
|
568
|
+
"credentials",
|
|
569
|
+
("credentials", "auth", "read-only"),
|
|
570
|
+
"Retrieves secrets through pluggable credential backends.", "low", False, False, True,
|
|
571
|
+
),
|
|
572
|
+
_spec(
|
|
573
|
+
"credential_helpers_store", "tool", "Store a credential by named helper and key.",
|
|
574
|
+
"credentials",
|
|
575
|
+
("credentials", "auth", "mutation"),
|
|
576
|
+
"Stores secrets through pluggable credential backends.", "medium", True, True, False,
|
|
577
|
+
),
|
|
578
|
+
_spec(
|
|
579
|
+
"url_scheme_parse", "tool", "Parse an algo-cli:// deep link into an action descriptor.",
|
|
580
|
+
"url-scheme",
|
|
581
|
+
("url-scheme", "deep-link", "read-only"),
|
|
582
|
+
"Parses algo-cli:// URLs into structured action descriptors.", "low", False, False, True,
|
|
583
|
+
),
|
|
584
|
+
)
|
|
585
|
+
|
|
586
|
+
|
|
587
|
+
def list_action_specs(*, include_archived: bool = False) -> tuple[ActionSpec, ...]:
|
|
588
|
+
if include_archived:
|
|
589
|
+
return ACTION_SPECS
|
|
590
|
+
return tuple(spec for spec in ACTION_SPECS if not spec.archived)
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
_MUTATING_TOOL_NAMES = frozenset({
|
|
594
|
+
"run_shell",
|
|
595
|
+
"write_file",
|
|
596
|
+
"edit_file",
|
|
597
|
+
"batch_edit",
|
|
598
|
+
"update_user_profile",
|
|
599
|
+
"model_delete",
|
|
600
|
+
"model_create",
|
|
601
|
+
"model_copy",
|
|
602
|
+
"model_pull",
|
|
603
|
+
"harness_refresh",
|
|
604
|
+
"reindex_knowledge_graph",
|
|
605
|
+
"write_knowledge_graph_note",
|
|
606
|
+
"remember",
|
|
607
|
+
"append_lesson",
|
|
608
|
+
"plugins_load",
|
|
609
|
+
"credential_helpers_store",
|
|
610
|
+
"x_account_post",
|
|
611
|
+
"x_account_reply",
|
|
612
|
+
"x_account_post_action",
|
|
613
|
+
})
|
|
614
|
+
|
|
615
|
+
|
|
616
|
+
def _first_doc_line(obj: Any, fallback: str) -> str:
|
|
617
|
+
doc = inspect.getdoc(obj) or ""
|
|
618
|
+
first = doc.strip().splitlines()[0].strip() if doc.strip() else ""
|
|
619
|
+
return first or fallback
|
|
620
|
+
|
|
621
|
+
|
|
622
|
+
def _generated_tool_spec(name: str, fn: Any) -> ActionSpec:
|
|
623
|
+
mutates = name in _MUTATING_TOOL_NAMES
|
|
624
|
+
network = name.startswith("web_") or name.startswith("x_") or name in {
|
|
625
|
+
"model_pull",
|
|
626
|
+
"model_create",
|
|
627
|
+
}
|
|
628
|
+
provider = (
|
|
629
|
+
"ollama-cloud" if name.startswith("web_")
|
|
630
|
+
else "xai" if name == "x_search"
|
|
631
|
+
else "x-account" if name.startswith("x_account_")
|
|
632
|
+
else None
|
|
633
|
+
)
|
|
634
|
+
return _spec(
|
|
635
|
+
name,
|
|
636
|
+
"tool",
|
|
637
|
+
_first_doc_line(fn, f"Runtime callable tool: {name}."),
|
|
638
|
+
"runtime",
|
|
639
|
+
("generated", "runtime", "tool"),
|
|
640
|
+
"Generated runtime coverage spec; explicit ActionSpec can override risk metadata.",
|
|
641
|
+
"high" if mutates else "medium" if network else "low",
|
|
642
|
+
mutates,
|
|
643
|
+
mutates,
|
|
644
|
+
not mutates,
|
|
645
|
+
requires_network=network,
|
|
646
|
+
requires_provider=provider,
|
|
647
|
+
)
|
|
648
|
+
|
|
649
|
+
|
|
650
|
+
def _generated_slash_spec(command: str, description: str) -> ActionSpec:
|
|
651
|
+
from .tool_runtime import session_command_requires_approval
|
|
652
|
+
|
|
653
|
+
requires_approval = session_command_requires_approval(command)
|
|
654
|
+
return _spec(
|
|
655
|
+
command,
|
|
656
|
+
"slash",
|
|
657
|
+
description or f"Runtime slash command: {command}.",
|
|
658
|
+
"session",
|
|
659
|
+
("generated", "runtime", "slash"),
|
|
660
|
+
"Generated slash-command coverage spec; explicit ActionSpec can override risk metadata.",
|
|
661
|
+
"medium" if requires_approval else "low",
|
|
662
|
+
requires_approval,
|
|
663
|
+
requires_approval,
|
|
664
|
+
not requires_approval,
|
|
665
|
+
)
|
|
666
|
+
|
|
667
|
+
|
|
668
|
+
def effective_action_specs(*, include_archived: bool = False) -> tuple[ActionSpec, ...]:
|
|
669
|
+
"""Explicit ActionSpecs plus generated coverage specs for runtime tools/slash commands."""
|
|
670
|
+
from .slash_dispatch import SLASH_COMMANDS
|
|
671
|
+
from .tools import TOOL_MAP
|
|
672
|
+
|
|
673
|
+
specs = list(list_action_specs(include_archived=include_archived))
|
|
674
|
+
covered_tools = {spec.name for spec in specs if spec.kind == "tool"}
|
|
675
|
+
covered_slashes = {spec.name for spec in specs if spec.kind == "slash"}
|
|
676
|
+
for name, fn in sorted(TOOL_MAP.items()):
|
|
677
|
+
if name not in covered_tools:
|
|
678
|
+
specs.append(_generated_tool_spec(name, fn))
|
|
679
|
+
for command, description in SLASH_COMMANDS:
|
|
680
|
+
if command not in covered_slashes:
|
|
681
|
+
specs.append(_generated_slash_spec(command, description))
|
|
682
|
+
covered_slashes.add(command)
|
|
683
|
+
return tuple(specs)
|
|
684
|
+
|
|
685
|
+
|
|
686
|
+
def get_action_spec(name: str) -> ActionSpec:
|
|
687
|
+
normalized = name.strip().lower()
|
|
688
|
+
for spec in effective_action_specs(include_archived=True):
|
|
689
|
+
if spec.name.lower() == normalized:
|
|
690
|
+
return spec
|
|
691
|
+
raise KeyError(f"Unknown action spec: {name}")
|
|
692
|
+
|
|
693
|
+
|
|
694
|
+
def action_requires_approval(name: str) -> bool:
|
|
695
|
+
"""Resolve tool approval policy from curated specs, then generated mutation metadata."""
|
|
696
|
+
|
|
697
|
+
for spec in list_action_specs(include_archived=False):
|
|
698
|
+
if spec.kind == "tool" and spec.name == name:
|
|
699
|
+
return spec.requires_approval
|
|
700
|
+
return name in _MUTATING_TOOL_NAMES
|
|
701
|
+
|
|
702
|
+
|
|
703
|
+
def _declared_dispatch_commands() -> set[str]:
|
|
704
|
+
"""Extract literal top-level command branches from handle_command for diagnostics."""
|
|
705
|
+
|
|
706
|
+
from .slash_dispatch import handle_command
|
|
707
|
+
|
|
708
|
+
try:
|
|
709
|
+
tree = ast.parse(textwrap.dedent(inspect.getsource(handle_command)))
|
|
710
|
+
except (OSError, TypeError, IndentationError, SyntaxError):
|
|
711
|
+
return set()
|
|
712
|
+
commands: set[str] = set()
|
|
713
|
+
for node in ast.walk(tree):
|
|
714
|
+
if not isinstance(node, ast.Compare):
|
|
715
|
+
continue
|
|
716
|
+
if not isinstance(node.left, ast.Name) or node.left.id != "command":
|
|
717
|
+
continue
|
|
718
|
+
for operator, comparator in zip(node.ops, node.comparators):
|
|
719
|
+
if isinstance(operator, ast.Eq) and isinstance(comparator, ast.Constant):
|
|
720
|
+
if isinstance(comparator.value, str):
|
|
721
|
+
commands.add(comparator.value)
|
|
722
|
+
elif isinstance(operator, ast.In) and isinstance(comparator, (ast.Set, ast.Tuple, ast.List)):
|
|
723
|
+
commands.update(
|
|
724
|
+
item.value
|
|
725
|
+
for item in comparator.elts
|
|
726
|
+
if isinstance(item, ast.Constant) and isinstance(item.value, str)
|
|
727
|
+
)
|
|
728
|
+
return commands
|
|
729
|
+
|
|
730
|
+
|
|
731
|
+
def audit_action_registry_runtime() -> DoctorReport:
|
|
732
|
+
"""Check that declared tool/slash actions resolve to runnable runtime entries."""
|
|
733
|
+
from .slash_dispatch import SLASH_COMMANDS, SLASH_COMMAND_ALIASES
|
|
734
|
+
from .tools import TOOL_MAP
|
|
735
|
+
|
|
736
|
+
tool_names = set(TOOL_MAP)
|
|
737
|
+
slash_list = [command for command, _description in SLASH_COMMANDS]
|
|
738
|
+
slash_names = set(slash_list)
|
|
739
|
+
registered_tool_specs = [spec for spec in list_action_specs() if spec.kind == "tool"]
|
|
740
|
+
registered_slash_specs = [spec for spec in list_action_specs() if spec.kind == "slash"]
|
|
741
|
+
covered_specs = effective_action_specs()
|
|
742
|
+
covered_tool_specs = [spec for spec in covered_specs if spec.kind == "tool"]
|
|
743
|
+
covered_slash_specs = [spec for spec in covered_specs if spec.kind == "slash"]
|
|
744
|
+
generated_tool_specs = [spec for spec in covered_tool_specs if "generated" in spec.tags]
|
|
745
|
+
generated_slash_specs = [spec for spec in covered_slash_specs if "generated" in spec.tags]
|
|
746
|
+
missing_tools: list[str] = []
|
|
747
|
+
missing_slashes: list[str] = []
|
|
748
|
+
non_callable_tools: list[str] = []
|
|
749
|
+
non_callable_runtime_tools = sorted(name for name, fn in TOOL_MAP.items() if not callable(fn))
|
|
750
|
+
duplicate_slashes = sorted({command for command in slash_list if slash_list.count(command) > 1})
|
|
751
|
+
slash_roots = {command.split()[0] for command in slash_list}
|
|
752
|
+
dispatch_commands = _declared_dispatch_commands()
|
|
753
|
+
undispatched_slashes = sorted(
|
|
754
|
+
root
|
|
755
|
+
for root in slash_roots
|
|
756
|
+
if root not in dispatch_commands and root not in SLASH_COMMAND_ALIASES
|
|
757
|
+
)
|
|
758
|
+
broken_aliases = sorted(
|
|
759
|
+
source
|
|
760
|
+
for source, target in SLASH_COMMAND_ALIASES.items()
|
|
761
|
+
if source not in slash_roots or target not in dispatch_commands
|
|
762
|
+
)
|
|
763
|
+
|
|
764
|
+
for spec in registered_tool_specs + registered_slash_specs:
|
|
765
|
+
if spec.kind == "tool":
|
|
766
|
+
if spec.name not in tool_names:
|
|
767
|
+
missing_tools.append(spec.name)
|
|
768
|
+
elif not callable(TOOL_MAP.get(spec.name)):
|
|
769
|
+
non_callable_tools.append(spec.name)
|
|
770
|
+
elif spec.kind == "slash" and spec.name not in slash_names:
|
|
771
|
+
missing_slashes.append(spec.name)
|
|
772
|
+
|
|
773
|
+
findings: list[DoctorFinding] = []
|
|
774
|
+
if missing_tools:
|
|
775
|
+
findings.append(DoctorFinding(
|
|
776
|
+
"blocked",
|
|
777
|
+
"action-registry",
|
|
778
|
+
f"registered tool specs missing from TOOL_MAP: {', '.join(sorted(missing_tools))}",
|
|
779
|
+
"Add the tool to TOOL_MAP/ALL_TOOLS or remove/archive the ActionSpec.",
|
|
780
|
+
))
|
|
781
|
+
if non_callable_runtime_tools:
|
|
782
|
+
findings.append(DoctorFinding(
|
|
783
|
+
"blocked",
|
|
784
|
+
"action-registry",
|
|
785
|
+
f"runtime TOOL_MAP entries are not callable: {', '.join(non_callable_runtime_tools)}",
|
|
786
|
+
"Ensure every TOOL_MAP value is a callable function.",
|
|
787
|
+
))
|
|
788
|
+
if non_callable_tools:
|
|
789
|
+
findings.append(DoctorFinding(
|
|
790
|
+
"blocked",
|
|
791
|
+
"action-registry",
|
|
792
|
+
f"registered tool specs are not callable: {', '.join(sorted(non_callable_tools))}",
|
|
793
|
+
"Ensure the TOOL_MAP entry is a callable function.",
|
|
794
|
+
))
|
|
795
|
+
if missing_slashes:
|
|
796
|
+
findings.append(DoctorFinding(
|
|
797
|
+
"blocked",
|
|
798
|
+
"action-registry",
|
|
799
|
+
f"registered slash specs missing from SLASH_COMMANDS: {', '.join(sorted(missing_slashes))}",
|
|
800
|
+
"Add the command to SLASH_COMMANDS/handle_command or remove/archive the ActionSpec.",
|
|
801
|
+
))
|
|
802
|
+
if duplicate_slashes:
|
|
803
|
+
findings.append(DoctorFinding(
|
|
804
|
+
"blocked",
|
|
805
|
+
"action-registry",
|
|
806
|
+
f"duplicate slash commands declared: {', '.join(duplicate_slashes)}",
|
|
807
|
+
"Deduplicate SLASH_COMMANDS so completion/help/dispatch remain deterministic.",
|
|
808
|
+
))
|
|
809
|
+
if undispatched_slashes:
|
|
810
|
+
findings.append(DoctorFinding(
|
|
811
|
+
"blocked",
|
|
812
|
+
"action-registry",
|
|
813
|
+
f"slash commands declared but not dispatched: {', '.join(undispatched_slashes)}",
|
|
814
|
+
"Add a handle_command branch or remove the stale command from SLASH_COMMANDS.",
|
|
815
|
+
))
|
|
816
|
+
if broken_aliases:
|
|
817
|
+
findings.append(DoctorFinding(
|
|
818
|
+
"blocked",
|
|
819
|
+
"action-registry",
|
|
820
|
+
f"slash aliases have missing sources or dispatch targets: {', '.join(broken_aliases)}",
|
|
821
|
+
"Register each alias source and point it at a dispatched canonical command.",
|
|
822
|
+
))
|
|
823
|
+
|
|
824
|
+
if not findings:
|
|
825
|
+
findings.append(DoctorFinding(
|
|
826
|
+
"ready",
|
|
827
|
+
"action-registry",
|
|
828
|
+
f"runtime surface: {len(tool_names)} tools callable, {len(slash_names)} slash commands declared",
|
|
829
|
+
))
|
|
830
|
+
findings.append(DoctorFinding(
|
|
831
|
+
"ready",
|
|
832
|
+
"action-registry",
|
|
833
|
+
f"ActionSpec coverage: {len(covered_tool_specs)}/{len(tool_names)} tools covered "
|
|
834
|
+
f"({len(registered_tool_specs)} explicit, {len(generated_tool_specs)} generated), "
|
|
835
|
+
f"{len(covered_slash_specs)}/{len(slash_names)} slash commands covered "
|
|
836
|
+
f"({len(registered_slash_specs)} explicit, {len(generated_slash_specs)} generated)",
|
|
837
|
+
"Generated specs keep coverage complete; explicit specs carry curated risk/provider metadata.",
|
|
838
|
+
))
|
|
839
|
+
findings.append(DoctorFinding(
|
|
840
|
+
"ready",
|
|
841
|
+
"action-registry",
|
|
842
|
+
f"{len(registered_tool_specs)} explicit tool specs and {len(registered_slash_specs)} explicit slash specs resolve",
|
|
843
|
+
))
|
|
844
|
+
|
|
845
|
+
overall: FindingStatus = "blocked" if any(f.status == "blocked" for f in findings) else "ready"
|
|
846
|
+
return DoctorReport(overall, tuple(findings))
|
|
847
|
+
|
|
848
|
+
|
|
849
|
+
def render_action_registry_runtime_audit(report: DoctorReport) -> str:
|
|
850
|
+
lines = [f"Action registry runtime audit: {report.overall_status.upper()}"]
|
|
851
|
+
for finding in report.findings:
|
|
852
|
+
lines.append(f"- {finding.status.upper():8} {finding.area}: {finding.message}")
|
|
853
|
+
if finding.recommendation:
|
|
854
|
+
lines.append(f" recommendation: {finding.recommendation}")
|
|
855
|
+
return "\n".join(lines)
|
|
856
|
+
|
|
857
|
+
|
|
858
|
+
def _check_ollama_host(host: str) -> bool:
|
|
859
|
+
try:
|
|
860
|
+
with urlopen(f"{host.rstrip('/')}/api/tags", timeout=0.5) as response: # nosec: local readiness probe
|
|
861
|
+
return 200 <= int(response.status) < 300
|
|
862
|
+
except (OSError, URLError, ValueError):
|
|
863
|
+
return False
|
|
864
|
+
|
|
865
|
+
|
|
866
|
+
def build_doctor_report(cfg: Any) -> DoctorReport:
|
|
867
|
+
findings: list[DoctorFinding] = []
|
|
868
|
+
|
|
869
|
+
if shutil.which("ollama"):
|
|
870
|
+
findings.append(DoctorFinding("ready", "ollama", "ollama binary found"))
|
|
871
|
+
else:
|
|
872
|
+
findings.append(DoctorFinding(
|
|
873
|
+
"degraded", "ollama", "ollama binary not found on PATH",
|
|
874
|
+
"Install Ollama or ensure ollama is on PATH for local model operations.",
|
|
875
|
+
))
|
|
876
|
+
|
|
877
|
+
cloud = bool(getattr(cfg, "cloud", False))
|
|
878
|
+
host = str(getattr(cfg, "host", "http://localhost:11434"))
|
|
879
|
+
load_runtime_env(override=True)
|
|
880
|
+
has_ollama_api_key = bool(os.environ.get("OLLAMA_API_KEY", "").strip())
|
|
881
|
+
if cloud:
|
|
882
|
+
if has_ollama_api_key:
|
|
883
|
+
findings.append(DoctorFinding("ready", "ollama-cloud", "OLLAMA_API_KEY present"))
|
|
884
|
+
else:
|
|
885
|
+
findings.append(DoctorFinding(
|
|
886
|
+
"degraded", "ollama-cloud", "direct Cloud API disabled because OLLAMA_API_KEY is missing",
|
|
887
|
+
"Signed-in local Ollama can still run :cloud models; set OLLAMA_API_KEY only for direct API/web tools.",
|
|
888
|
+
))
|
|
889
|
+
else:
|
|
890
|
+
if _check_ollama_host(host):
|
|
891
|
+
findings.append(DoctorFinding("ready", "ollama-host", f"local Ollama host reachable: {host}"))
|
|
892
|
+
else:
|
|
893
|
+
findings.append(DoctorFinding(
|
|
894
|
+
"degraded", "ollama-host", f"local Ollama host not reachable: {host}",
|
|
895
|
+
"Start Ollama, run /login for local :cloud models, or set OLLAMA_API_KEY for direct API/web tools.",
|
|
896
|
+
))
|
|
897
|
+
|
|
898
|
+
if has_ollama_api_key:
|
|
899
|
+
findings.append(DoctorFinding(
|
|
900
|
+
"ready",
|
|
901
|
+
"web-tools",
|
|
902
|
+
"web_search/web_fetch configured via OLLAMA_API_KEY",
|
|
903
|
+
))
|
|
904
|
+
else:
|
|
905
|
+
findings.append(DoctorFinding(
|
|
906
|
+
"degraded",
|
|
907
|
+
"web-tools",
|
|
908
|
+
"web_search/web_fetch disabled because OLLAMA_API_KEY is missing",
|
|
909
|
+
"Set ALGO_CLI_ENV_FILE or ~/.algo_cli/env with OLLAMA_API_KEY, then rerun /doctor.",
|
|
910
|
+
))
|
|
911
|
+
|
|
912
|
+
# xAI subscription OAuth is an optional provider and deliberately ships
|
|
913
|
+
# without a third-party OAuth client identity. Its absence must not make a
|
|
914
|
+
# fresh local install look unhealthy.
|
|
915
|
+
try:
|
|
916
|
+
from . import xai_auth
|
|
917
|
+
|
|
918
|
+
xai_status = xai_auth.auth_status()
|
|
919
|
+
if not xai_status.get("client_configured"):
|
|
920
|
+
findings.append(DoctorFinding(
|
|
921
|
+
"ready",
|
|
922
|
+
"xai-oauth",
|
|
923
|
+
"optional xAI subscription OAuth is not configured (no bundled client id)",
|
|
924
|
+
"Set XAI_CLIENT_ID in ~/.algo_cli/env only if you want to enable this provider.",
|
|
925
|
+
))
|
|
926
|
+
elif xai_status.get("authenticated"):
|
|
927
|
+
findings.append(DoctorFinding(
|
|
928
|
+
"ready",
|
|
929
|
+
"xai-oauth",
|
|
930
|
+
f"optional xAI OAuth authenticated (expires in {int(xai_status.get('expires_in', 0))}s)",
|
|
931
|
+
))
|
|
932
|
+
else:
|
|
933
|
+
findings.append(DoctorFinding(
|
|
934
|
+
"ready",
|
|
935
|
+
"xai-oauth",
|
|
936
|
+
"optional xAI OAuth client configured; no active session",
|
|
937
|
+
"Run /xai-login if you want to use xAI models.",
|
|
938
|
+
))
|
|
939
|
+
except Exception as exc: # pragma: no cover - best-effort diagnostic
|
|
940
|
+
findings.append(DoctorFinding(
|
|
941
|
+
"degraded",
|
|
942
|
+
"xai-oauth",
|
|
943
|
+
f"xai_auth import failed: {exc}",
|
|
944
|
+
"Reinstall Algo CLI; the module is required for optional /xai-* commands.",
|
|
945
|
+
))
|
|
946
|
+
|
|
947
|
+
from . import index_compute_lab
|
|
948
|
+
|
|
949
|
+
root = index_compute_lab.resolve_lab_root()
|
|
950
|
+
icl_enabled = bool(getattr(cfg, "index_compute_lab_auto_inject", False))
|
|
951
|
+
if not icl_enabled:
|
|
952
|
+
findings.append(DoctorFinding(
|
|
953
|
+
"ready", "index-compute-lab", "optional index-compute-lab context is disabled",
|
|
954
|
+
"Use /icl on only when this local source is appropriate for the selected model provider.",
|
|
955
|
+
))
|
|
956
|
+
elif not root.exists():
|
|
957
|
+
findings.append(DoctorFinding(
|
|
958
|
+
"degraded", "index-compute-lab", f"enabled index-compute-lab root is missing: {root}",
|
|
959
|
+
"Set ALGO_CLI_INDEX_COMPUTE_LAB_ROOT or clone/build the lab.",
|
|
960
|
+
))
|
|
961
|
+
elif index_compute_lab.lab_available():
|
|
962
|
+
findings.append(DoctorFinding("ready", "index-compute-lab", "index-compute-lab graph ready"))
|
|
963
|
+
else:
|
|
964
|
+
findings.append(DoctorFinding(
|
|
965
|
+
"degraded", "index-compute-lab", "index-compute-lab root exists but query assets are missing",
|
|
966
|
+
"Need query.py, atoms/ranked-association-map.json, and atoms/alias-table.json.",
|
|
967
|
+
))
|
|
968
|
+
|
|
969
|
+
if bool(getattr(cfg, "safe_mode", True)):
|
|
970
|
+
findings.append(DoctorFinding("ready", "safety", "safe mode enabled"))
|
|
971
|
+
else:
|
|
972
|
+
findings.append(DoctorFinding(
|
|
973
|
+
"degraded", "safety", "safe mode disabled",
|
|
974
|
+
"Use /safe on before high-risk shell/file work.",
|
|
975
|
+
))
|
|
976
|
+
|
|
977
|
+
if bool(getattr(cfg, "auto_approve_active", getattr(cfg, "auto_mode", False))):
|
|
978
|
+
findings.append(DoctorFinding(
|
|
979
|
+
"degraded", "approval", "auto-approval enabled",
|
|
980
|
+
"Use /auto off when reviewing risky mutation paths.",
|
|
981
|
+
))
|
|
982
|
+
else:
|
|
983
|
+
findings.append(DoctorFinding("ready", "approval", "manual approval required for dangerous actions"))
|
|
984
|
+
|
|
985
|
+
legacy_env = sorted(k for k in os.environ if k.startswith("OLLAMA_CLI_"))
|
|
986
|
+
if legacy_env:
|
|
987
|
+
findings.append(DoctorFinding(
|
|
988
|
+
"degraded", "legacy", f"legacy OLLAMA_CLI_* env vars present: {', '.join(legacy_env)}",
|
|
989
|
+
"Rename to ALGO_CLI_* equivalents.",
|
|
990
|
+
))
|
|
991
|
+
|
|
992
|
+
# Google Workspace readiness
|
|
993
|
+
try:
|
|
994
|
+
from . import google_workspace_auth
|
|
995
|
+
status = google_workspace_auth.auth_status()
|
|
996
|
+
if not status.get("client_configured"):
|
|
997
|
+
findings.append(DoctorFinding(
|
|
998
|
+
"degraded", "google-workspace",
|
|
999
|
+
"GOOGLE_OAUTH_CLIENT_ID not set",
|
|
1000
|
+
"Create an OAuth client at https://console.cloud.google.com and export the id before /google-login.",
|
|
1001
|
+
))
|
|
1002
|
+
elif status.get("authenticated"):
|
|
1003
|
+
findings.append(DoctorFinding(
|
|
1004
|
+
"ready", "google-workspace",
|
|
1005
|
+
f"Google Workspace authenticated (expires in {int(status.get('expires_in', 0))}s)",
|
|
1006
|
+
))
|
|
1007
|
+
else:
|
|
1008
|
+
findings.append(DoctorFinding(
|
|
1009
|
+
"degraded", "google-workspace",
|
|
1010
|
+
"Google OAuth client configured but no active session",
|
|
1011
|
+
"Run /google-login to start the loopback flow.",
|
|
1012
|
+
))
|
|
1013
|
+
except Exception as exc: # pragma: no cover - best-effort diagnostic
|
|
1014
|
+
findings.append(DoctorFinding(
|
|
1015
|
+
"degraded", "google-workspace", f"google_workspace_auth import failed: {exc}",
|
|
1016
|
+
"Reinstall Algo CLI; the module is required for /google-* commands.",
|
|
1017
|
+
))
|
|
1018
|
+
|
|
1019
|
+
if any(f.status == "blocked" for f in findings):
|
|
1020
|
+
overall: FindingStatus = "blocked"
|
|
1021
|
+
elif any(f.status == "degraded" for f in findings):
|
|
1022
|
+
overall = "degraded"
|
|
1023
|
+
else:
|
|
1024
|
+
overall = "ready"
|
|
1025
|
+
return DoctorReport(overall, tuple(findings))
|
|
1026
|
+
|
|
1027
|
+
|
|
1028
|
+
def render_doctor(report: DoctorReport) -> str:
|
|
1029
|
+
lines = [f"Algo CLI doctor: {report.overall_status.upper()}"]
|
|
1030
|
+
for finding in report.findings:
|
|
1031
|
+
lines.append(f"- {finding.status.upper():8} {finding.area}: {finding.message}")
|
|
1032
|
+
if finding.recommendation:
|
|
1033
|
+
lines.append(f" recommendation: {finding.recommendation}")
|
|
1034
|
+
return "\n".join(lines)
|
|
1035
|
+
|
|
1036
|
+
|
|
1037
|
+
def render_action_registry(*, include_archived: bool = False) -> str:
|
|
1038
|
+
lines = ["Algo CLI ActionSpec registry:"]
|
|
1039
|
+
for spec in list_action_specs(include_archived=include_archived):
|
|
1040
|
+
status = "ARCHIVED" if spec.archived else "ACTIVE"
|
|
1041
|
+
mutation = "mutates" if spec.mutates_state else "read-only"
|
|
1042
|
+
approval = "approval" if spec.requires_approval else "no-approval"
|
|
1043
|
+
lines.append(f"- {spec.name} [{status}] ({spec.kind}/{spec.group}, {spec.risk_level}, {mutation}, {approval})")
|
|
1044
|
+
lines.append(f" {spec.description}")
|
|
1045
|
+
if spec.replacement:
|
|
1046
|
+
lines.append(f" replacement: {spec.replacement}")
|
|
1047
|
+
return "\n".join(lines)
|