traceforge-toolkit 0.1.0__tar.gz → 0.1.1__tar.gz
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.
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/PKG-INFO +13 -4
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/README.md +8 -3
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/pyproject.toml +7 -1
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/__init__.py +21 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/__init__.py +4 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/config.py +13 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/data/binary_info.yaml +1 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/data/effect_overrides.yaml +41 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/data/recommendation_rules.yaml +31 -0
- traceforge_toolkit-0.1.1/src/traceforge/classify/data/tool_display.yaml +30 -0
- traceforge_toolkit-0.1.1/src/traceforge/classify/hazards.py +126 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/shell.py +3 -0
- traceforge_toolkit-0.1.1/src/traceforge/classify/tool_display.py +113 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/cli/__init__.py +0 -2
- traceforge_toolkit-0.1.1/src/traceforge/cli/gate_cmd.py +60 -0
- traceforge_toolkit-0.1.1/src/traceforge/cli/init_cmd.py +334 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/cli/watch.py +53 -9
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/config/models.py +100 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/enricher.py +165 -22
- traceforge_toolkit-0.1.1/src/traceforge/gate/client.py +264 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/gate/registry.py +34 -9
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/gate/server.py +37 -1
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/assessor.py +24 -2
- traceforge_toolkit-0.1.1/src/traceforge/governance/budget.py +133 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/pipeline.py +488 -39
- traceforge_toolkit-0.1.1/src/traceforge/governance/rules.py +742 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/shield.py +220 -25
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/state.py +119 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/types.py +35 -1
- traceforge_toolkit-0.1.1/src/traceforge/mappings/langchain.yaml +185 -0
- traceforge_toolkit-0.1.1/src/traceforge/mappings/semantic_kernel.yaml +129 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/migrations/models.py +16 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/migrations/versions/0001_initial.py +19 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/pipeline.py +144 -12
- traceforge_toolkit-0.1.1/src/traceforge/progress.py +128 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sdk/__init__.py +2 -0
- traceforge_toolkit-0.1.1/src/traceforge/sdk/observe.py +541 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sdk/pipeline.py +79 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sinks/base.py +29 -1
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sinks/callback.py +51 -1
- traceforge_toolkit-0.1.1/src/traceforge/sinks/sqlite_output.py +479 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sources/__init__.py +5 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sources/auto_detect.py +15 -0
- traceforge_toolkit-0.1.1/src/traceforge/sources/queue.py +132 -0
- traceforge_toolkit-0.1.1/src/traceforge/sources/sdk_live.py +403 -0
- traceforge_toolkit-0.1.1/src/traceforge/telemetry/attribution.py +358 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/title/_resolve.py +32 -7
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/types.py +87 -0
- traceforge_toolkit-0.1.0/src/traceforge/cli/download_cmd.py +0 -74
- traceforge_toolkit-0.1.0/src/traceforge/cli/gate_cmd.py +0 -30
- traceforge_toolkit-0.1.0/src/traceforge/cli/init_cmd.py +0 -86
- traceforge_toolkit-0.1.0/src/traceforge/gate/client.py +0 -145
- traceforge_toolkit-0.1.0/src/traceforge/governance/budget.py +0 -59
- traceforge_toolkit-0.1.0/src/traceforge/governance/rules.py +0 -368
- traceforge_toolkit-0.1.0/src/traceforge/sinks/sqlite_output.py +0 -234
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/.gitignore +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/LICENSE +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/__main__.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/_generated.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/adapters/__init__.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/adapters/base.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/adapters/genai_otel.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/adapters/mapped_json.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/adapters/otel.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/boundary/__init__.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/boundary/data/boundary-model.joblib +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/boundary/decode.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/boundary/features.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/boundary/inference.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/boundary/inferencer.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/cmd.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/coding.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/core.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/data/canonical_tools.yaml +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/data/mcp_profiles.yaml +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/data/risk.yaml +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/data/shell_defaults.yaml +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/data/shell_rules.yaml +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/data/tool_classifications.yaml +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/data/verb_inference.yaml +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/mcp.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/phases.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/powershell.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/registry.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/risk.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/rules.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/schema.yaml +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/tools.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/workflow.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/cli/config_cmd.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/cli/detect.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/cli/factory.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/cli/replay.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/cli/runner.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/cli/score.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/cli/status.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/config/__init__.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/config/defaults.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/config/loader.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/config/mappings.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/formatting/__init__.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/formatting/budget.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/formatting/density.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/gate/__init__.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/gate/external.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/gates/__init__.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/gates/pii.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/gates/pii_patterns.yaml +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/__init__.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/canonical.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/codec.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/context.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/drift.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/emitter.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/envelope.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/ifc.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/integrity.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/labeler.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/mcp_drift.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/monitor.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/observer.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/persistence.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/phase1.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/pii.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/registry.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/results.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/risk_wrapper.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/scorer.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/__init__.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/aider.yaml +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/aider_markdown.yaml +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/amazonq.yaml +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/antigravity.yaml +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/claude.yaml +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/cline.yaml +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/codex.yaml +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/continue_dev.yaml +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/copilot.yaml +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/copilot_markdown.yaml +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/copilot_vscode.yaml +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/crewai.yaml +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/goose.yaml +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/langgraph.yaml +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/maf.yaml +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/maf_transcript.yaml +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/openai_agents.yaml +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/opencode.yaml +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/openhands.yaml +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/pydantic_ai.yaml +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/smolagents.yaml +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/sweagent.yaml +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/migrations/__init__.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/migrations/env.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/migrations/runner.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/migrations/script.py.mako +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/migrations/versions/__init__.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/models.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/parsers/__init__.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/parsers/aider.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/parsers/base.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/parsers/copilot.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/phase/__init__.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/phase/data/phase-model.joblib +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/phase/data/potion-base-8M/README.md +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/phase/data/potion-base-8M/config.json +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/phase/data/potion-base-8M/model.safetensors +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/phase/data/potion-base-8M/modules.json +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/phase/data/potion-base-8M/tokenizer.json +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/phase/event_rows.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/phase/features.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/phase/inference.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/phase/inferencer.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/phase/segmentation.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/__init__.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/amazonq.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/antigravity.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/claude.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/cline.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/codex.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/continue_dev.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/copilot_vscode.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/goose.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/maf_transcript.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/openai_agents.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/opencode.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/openhands.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/pydantic_ai.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/registry.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/smolagents.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/py.typed +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sdk/gate_policy.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sdk/gate_types.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sdk/verdict.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sinks/__init__.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sinks/console.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sinks/factory.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sinks/jsonl.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sinks/otel_exporter.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sinks/parquet.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sinks/s3.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sinks/webhook.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sources/base.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sources/file_poll.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sources/file_watch.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sources/http_poll.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sources/replay.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sources/sqlite.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sources/sse.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/telemetry/__init__.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/title/__init__.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/title/context.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/title/data/boilerplate_files.json +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/title/heuristics.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/title/hygiene.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/title/inference.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/title/inferencer.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/title/naming.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/trace.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/tracking/__init__.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/tracking/models.py +0 -0
- {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/tracking/phase_tracker.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: traceforge-toolkit
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.1
|
|
4
4
|
Summary: Framework-agnostic, CPU-only pipeline that forges AI agent traces into classified, risk-scored, governed output
|
|
5
5
|
Project-URL: Homepage, https://github.com/dfinson/traceforge
|
|
6
6
|
Project-URL: Repository, https://github.com/dfinson/traceforge
|
|
@@ -44,6 +44,10 @@ Requires-Dist: tree-sitter-powershell>=0.24
|
|
|
44
44
|
Requires-Dist: tree-sitter>=0.24
|
|
45
45
|
Requires-Dist: tzdata>=2024.1; platform_system == 'Windows'
|
|
46
46
|
Requires-Dist: watchdog>=4.0
|
|
47
|
+
Provides-Extra: claude
|
|
48
|
+
Requires-Dist: claude-agent-sdk>=0.1; extra == 'claude'
|
|
49
|
+
Provides-Extra: copilot
|
|
50
|
+
Requires-Dist: github-copilot-sdk<0.4,>=0.3; extra == 'copilot'
|
|
47
51
|
Provides-Extra: dev
|
|
48
52
|
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
49
53
|
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
@@ -60,7 +64,7 @@ Description-Content-Type: text/markdown
|
|
|
60
64
|
|
|
61
65
|
[](https://github.com/dfinson/traceforge/actions/workflows/ci-lint.yml)
|
|
62
66
|
[](https://github.com/dfinson/traceforge/actions/workflows/ci-test.yml)
|
|
63
|
-
[](https://pypi.org/project/traceforge-toolkit/)
|
|
64
68
|
[](https://github.com/dfinson/traceforge)
|
|
65
69
|
[](LICENSE)
|
|
66
70
|
[](https://dfinson.github.io/traceforge/)
|
|
@@ -137,7 +141,12 @@ print(trace.risk_score, trace.suggested_action) # e.g. 72 escalate
|
|
|
137
141
|
```
|
|
138
142
|
|
|
139
143
|
See the **[Getting Started guide](https://dfinson.github.io/traceforge/docs/getting-started/installation)**
|
|
140
|
-
for the full CLI (`watch`, `replay`, `score`, `gate`, `init`, `detect`, `status`, `config
|
|
144
|
+
for the full CLI (`watch`, `replay`, `score`, `gate`, `init`, `detect`, `status`, `config`).
|
|
145
|
+
|
|
146
|
+
`traceforge init <agent>` injects the blocking preflight gate hook into a supported agent's own
|
|
147
|
+
native config — for Claude Code, a `PreToolUse` hook in `.claude/settings.json` that runs
|
|
148
|
+
`traceforge gate --stdin`. It does not scaffold `~/.traceforge/` (that config bootstrap happens
|
|
149
|
+
automatically on first config access).
|
|
141
150
|
|
|
142
151
|
## Features
|
|
143
152
|
|
|
@@ -179,7 +188,7 @@ the test suite, linting with `ruff`, and how to add a new agent framework mappin
|
|
|
179
188
|
|
|
180
189
|
## Status
|
|
181
190
|
|
|
182
|
-
|
|
191
|
+
✅ **Released**: available on PyPI as [`traceforge-toolkit`](https://pypi.org/project/traceforge-toolkit/) (`pip install traceforge-toolkit`). The pipeline is feature-complete:
|
|
183
192
|
sources, adapters, enricher, classification, risk scoring, live phase/boundary/title structuring,
|
|
184
193
|
the governance engine, all storage sinks, and the `traceforge` CLI all ship today.
|
|
185
194
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
[](https://github.com/dfinson/traceforge/actions/workflows/ci-lint.yml)
|
|
8
8
|
[](https://github.com/dfinson/traceforge/actions/workflows/ci-test.yml)
|
|
9
|
-
[](https://pypi.org/project/traceforge-toolkit/)
|
|
10
10
|
[](https://github.com/dfinson/traceforge)
|
|
11
11
|
[](LICENSE)
|
|
12
12
|
[](https://dfinson.github.io/traceforge/)
|
|
@@ -83,7 +83,12 @@ print(trace.risk_score, trace.suggested_action) # e.g. 72 escalate
|
|
|
83
83
|
```
|
|
84
84
|
|
|
85
85
|
See the **[Getting Started guide](https://dfinson.github.io/traceforge/docs/getting-started/installation)**
|
|
86
|
-
for the full CLI (`watch`, `replay`, `score`, `gate`, `init`, `detect`, `status`, `config
|
|
86
|
+
for the full CLI (`watch`, `replay`, `score`, `gate`, `init`, `detect`, `status`, `config`).
|
|
87
|
+
|
|
88
|
+
`traceforge init <agent>` injects the blocking preflight gate hook into a supported agent's own
|
|
89
|
+
native config — for Claude Code, a `PreToolUse` hook in `.claude/settings.json` that runs
|
|
90
|
+
`traceforge gate --stdin`. It does not scaffold `~/.traceforge/` (that config bootstrap happens
|
|
91
|
+
automatically on first config access).
|
|
87
92
|
|
|
88
93
|
## Features
|
|
89
94
|
|
|
@@ -125,7 +130,7 @@ the test suite, linting with `ruff`, and how to add a new agent framework mappin
|
|
|
125
130
|
|
|
126
131
|
## Status
|
|
127
132
|
|
|
128
|
-
|
|
133
|
+
✅ **Released**: available on PyPI as [`traceforge-toolkit`](https://pypi.org/project/traceforge-toolkit/) (`pip install traceforge-toolkit`). The pipeline is feature-complete:
|
|
129
134
|
sources, adapters, enricher, classification, risk scoring, live phase/boundary/title structuring,
|
|
130
135
|
the governance engine, all storage sinks, and the `traceforge` CLI all ship today.
|
|
131
136
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "traceforge-toolkit"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.1"
|
|
8
8
|
description = "Framework-agnostic, CPU-only pipeline that forges AI agent traces into classified, risk-scored, governed output"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -70,6 +70,12 @@ dev = [
|
|
|
70
70
|
s3 = [
|
|
71
71
|
"boto3>=1.28",
|
|
72
72
|
]
|
|
73
|
+
copilot = [
|
|
74
|
+
"github-copilot-sdk>=0.3,<0.4",
|
|
75
|
+
]
|
|
76
|
+
claude = [
|
|
77
|
+
"claude-agent-sdk>=0.1",
|
|
78
|
+
]
|
|
73
79
|
|
|
74
80
|
[project.scripts]
|
|
75
81
|
traceforge = "traceforge.cli:main"
|
|
@@ -20,14 +20,25 @@ from traceforge.classify import (
|
|
|
20
20
|
from traceforge.enricher import Enricher
|
|
21
21
|
from traceforge.parsers.aider import AiderPreParser
|
|
22
22
|
from traceforge.pipeline import EventPipeline
|
|
23
|
+
from traceforge.progress import ProgressEmitter
|
|
23
24
|
from traceforge.sinks.base import StorageSink
|
|
24
25
|
from traceforge.sinks.callback import CallbackSink
|
|
26
|
+
from traceforge.telemetry.attribution import (
|
|
27
|
+
DURATION_MS_ATTR,
|
|
28
|
+
Anomaly,
|
|
29
|
+
AttributionRollup,
|
|
30
|
+
Attributor,
|
|
31
|
+
build_attributor,
|
|
32
|
+
)
|
|
25
33
|
from traceforge.trace import EventTrace
|
|
26
34
|
from traceforge.types import (
|
|
27
35
|
KNOWN_KINDS,
|
|
36
|
+
TRACE_NATIVE_DIMENSIONS,
|
|
37
|
+
CostBreakdown,
|
|
28
38
|
EventKind,
|
|
29
39
|
EventMetadata,
|
|
30
40
|
IngestionMode,
|
|
41
|
+
ProgressUpdate,
|
|
31
42
|
SessionEvent,
|
|
32
43
|
TelemetrySpan,
|
|
33
44
|
TitleUpdate,
|
|
@@ -54,6 +65,8 @@ __all__ = [
|
|
|
54
65
|
"IngestionMode",
|
|
55
66
|
"KNOWN_KINDS",
|
|
56
67
|
"Phase",
|
|
68
|
+
"ProgressEmitter",
|
|
69
|
+
"ProgressUpdate",
|
|
57
70
|
"SessionEvent",
|
|
58
71
|
"StorageSink",
|
|
59
72
|
"TelemetrySpan",
|
|
@@ -69,4 +82,12 @@ __all__ = [
|
|
|
69
82
|
"is_known_kind",
|
|
70
83
|
"load_config",
|
|
71
84
|
"normalize_tool_name",
|
|
85
|
+
# Attribution (U11)
|
|
86
|
+
"Anomaly",
|
|
87
|
+
"AttributionRollup",
|
|
88
|
+
"Attributor",
|
|
89
|
+
"CostBreakdown",
|
|
90
|
+
"DURATION_MS_ATTR",
|
|
91
|
+
"TRACE_NATIVE_DIMENSIONS",
|
|
92
|
+
"build_attributor",
|
|
72
93
|
]
|
|
@@ -43,6 +43,7 @@ from traceforge.classify.shell import (
|
|
|
43
43
|
classify_shell,
|
|
44
44
|
)
|
|
45
45
|
from traceforge.classify.tools import classify_tool, normalize_tool_name
|
|
46
|
+
from traceforge.classify.tool_display import ToolDisplayProvider, ToolDisplayResolver
|
|
46
47
|
from traceforge.classify.workflow import Phase, Visibility
|
|
47
48
|
|
|
48
49
|
__all__ = [
|
|
@@ -87,6 +88,9 @@ __all__ = [
|
|
|
87
88
|
"McpServerProfile",
|
|
88
89
|
"McpToolOverride",
|
|
89
90
|
"normalize_tool_name",
|
|
91
|
+
# Tool display
|
|
92
|
+
"ToolDisplayProvider",
|
|
93
|
+
"ToolDisplayResolver",
|
|
90
94
|
# Risk scoring
|
|
91
95
|
"Confidence",
|
|
92
96
|
"RiskAssessment",
|
|
@@ -142,6 +142,11 @@ class ClassifyConfig(StrictModel):
|
|
|
142
142
|
verification_role_actions: dict[str, str] = Field(default_factory=dict)
|
|
143
143
|
transparent_wrappers: list[str] = Field(default_factory=list)
|
|
144
144
|
activity_defaults: dict[str, dict[str, str]] = Field(default_factory=dict)
|
|
145
|
+
# Canonical tool identity -> human-facing display label. Populates
|
|
146
|
+
# EventMetadata.tool_display at enrichment. Small generic default set; a
|
|
147
|
+
# consumer supplies its own vocabulary as an overlay via the config-override /
|
|
148
|
+
# traceforge.profiles entry-point chain (per-key override wins).
|
|
149
|
+
tool_display: dict[str, str] = Field(default_factory=dict)
|
|
145
150
|
|
|
146
151
|
@classmethod
|
|
147
152
|
def from_yaml(cls, path: str | Path) -> ClassifyConfig:
|
|
@@ -226,6 +231,7 @@ def _load_builtin_defaults() -> dict[str, Any]:
|
|
|
226
231
|
"mcp_profiles.yaml",
|
|
227
232
|
"shell_rules.yaml",
|
|
228
233
|
"tool_classifications.yaml",
|
|
234
|
+
"tool_display.yaml",
|
|
229
235
|
):
|
|
230
236
|
resource = data_dir / filename
|
|
231
237
|
try:
|
|
@@ -387,6 +393,7 @@ class ClassificationEngine:
|
|
|
387
393
|
__slots__ = (
|
|
388
394
|
"canonical_tools",
|
|
389
395
|
"tool_classifications",
|
|
396
|
+
"tool_display",
|
|
390
397
|
"verb_inference",
|
|
391
398
|
"effect_overrides",
|
|
392
399
|
"shell_rules",
|
|
@@ -414,6 +421,12 @@ class ClassificationEngine:
|
|
|
414
421
|
k.lower().replace("-", "_"): v for k, v in config.canonical_tools.items()
|
|
415
422
|
}
|
|
416
423
|
|
|
424
|
+
# Tool display labels — canonical tool identity -> human-facing label.
|
|
425
|
+
# Keys normalized like canonical_tools so lookup matches normalize_tool_name.
|
|
426
|
+
self.tool_display: dict[str, str] = {
|
|
427
|
+
k.lower().replace("-", "_"): v for k, v in config.tool_display.items()
|
|
428
|
+
}
|
|
429
|
+
|
|
417
430
|
# Tool classifications (with phase_map derived)
|
|
418
431
|
self.tool_classifications: dict[str, Classification] = {}
|
|
419
432
|
for name, tc in config.tool_classifications.items():
|
{traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/data/binary_info.yaml
RENAMED
|
@@ -206,6 +206,7 @@ binary_info:
|
|
|
206
206
|
invoke-webrequest: { role: retriever.api_client, default_effect: null, network: true }
|
|
207
207
|
nc: { role: retriever.api_client, default_effect: null, network: true }
|
|
208
208
|
ncat: { role: retriever.api_client, default_effect: null, network: true }
|
|
209
|
+
netcat: { role: retriever.api_client, default_effect: null, network: true }
|
|
209
210
|
nslookup: { role: retriever.api_client, default_effect: read_only, network: true }
|
|
210
211
|
ping: { role: retriever.api_client, default_effect: read_only, network: true }
|
|
211
212
|
socat: { role: retriever.api_client, default_effect: null, network: true }
|
|
@@ -83,6 +83,47 @@ effect_overrides:
|
|
|
83
83
|
mode: any_present
|
|
84
84
|
default_effect: read_only
|
|
85
85
|
|
|
86
|
+
# netcat family / socat: a bare connection transfers data (mutating sink).
|
|
87
|
+
# Listen mode (-l/-L/--listen/-k) and help/version are read-only. This lets a
|
|
88
|
+
# read-sensitive-then-network pipe (e.g. `cat secret | nc host port`) aggregate
|
|
89
|
+
# to a mutating effect and trip the mutating_with_network rule.
|
|
90
|
+
nc:
|
|
91
|
+
flag_effects:
|
|
92
|
+
- flags: ["-l", "-L", "--listen", "-k"]
|
|
93
|
+
effect: read_only
|
|
94
|
+
mode: any_present
|
|
95
|
+
- flags: ["-h", "--help", "-V", "--version"]
|
|
96
|
+
effect: read_only
|
|
97
|
+
mode: any_present
|
|
98
|
+
default_effect: mutating
|
|
99
|
+
|
|
100
|
+
ncat:
|
|
101
|
+
flag_effects:
|
|
102
|
+
- flags: ["-l", "-L", "--listen", "-k"]
|
|
103
|
+
effect: read_only
|
|
104
|
+
mode: any_present
|
|
105
|
+
- flags: ["-h", "--help", "-V", "--version"]
|
|
106
|
+
effect: read_only
|
|
107
|
+
mode: any_present
|
|
108
|
+
default_effect: mutating
|
|
109
|
+
|
|
110
|
+
netcat:
|
|
111
|
+
flag_effects:
|
|
112
|
+
- flags: ["-l", "-L", "--listen", "-k"]
|
|
113
|
+
effect: read_only
|
|
114
|
+
mode: any_present
|
|
115
|
+
- flags: ["-h", "--help", "-V", "--version"]
|
|
116
|
+
effect: read_only
|
|
117
|
+
mode: any_present
|
|
118
|
+
default_effect: mutating
|
|
119
|
+
|
|
120
|
+
socat:
|
|
121
|
+
flag_effects:
|
|
122
|
+
- flags: ["-h", "-hh", "-hhh", "--help", "-V", "--version"]
|
|
123
|
+
effect: read_only
|
|
124
|
+
mode: any_present
|
|
125
|
+
default_effect: mutating
|
|
126
|
+
|
|
86
127
|
# Git: subcmd determines effect
|
|
87
128
|
git:
|
|
88
129
|
subcmd_effects:
|
|
@@ -91,6 +91,37 @@ recommendation_rules:
|
|
|
91
91
|
recommend: warn
|
|
92
92
|
reason: content_integrity_mismatch
|
|
93
93
|
|
|
94
|
+
# ── Semantic hazard tags (classify/hazards.py) ──
|
|
95
|
+
# These escalate dangerous command shapes regardless of numeric risk score.
|
|
96
|
+
|
|
97
|
+
# Raw block-device write (dd of=/dev/sda, redirect into /dev/nvme0n1, ...)
|
|
98
|
+
- id: raw_device_write
|
|
99
|
+
when:
|
|
100
|
+
capability: [raw_device_write]
|
|
101
|
+
recommend: escalate
|
|
102
|
+
reason: raw_block_device_write
|
|
103
|
+
|
|
104
|
+
# Filesystem format / wipe (mkfs*, mke2fs, mkswap, wipefs, destructive parted)
|
|
105
|
+
- id: filesystem_format
|
|
106
|
+
when:
|
|
107
|
+
capability: [filesystem_format]
|
|
108
|
+
recommend: escalate
|
|
109
|
+
reason: filesystem_format
|
|
110
|
+
|
|
111
|
+
# Persistence-mechanism write (cron, systemd unit, shell rc file)
|
|
112
|
+
- id: persistence_write
|
|
113
|
+
when:
|
|
114
|
+
capability: [persistence_write]
|
|
115
|
+
recommend: escalate
|
|
116
|
+
reason: persistence_mechanism_write
|
|
117
|
+
|
|
118
|
+
# Fork bomb / resource-exhaustion pattern
|
|
119
|
+
- id: fork_bomb
|
|
120
|
+
when:
|
|
121
|
+
capability: [fork_bomb]
|
|
122
|
+
recommend: escalate
|
|
123
|
+
reason: fork_bomb_pattern
|
|
124
|
+
|
|
94
125
|
# Fallback risk score thresholds
|
|
95
126
|
- id: risk_critical
|
|
96
127
|
when:
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Tool display names — maps a canonical tool identity to a human-facing label.
|
|
2
|
+
#
|
|
3
|
+
# This populates ``EventMetadata.tool_display`` at enrichment time. Keys are the
|
|
4
|
+
# CANONICAL tool identity (the normalized form produced by ``normalize_tool_name``,
|
|
5
|
+
# e.g. every shell-family alias collapses to ``shell``, every read alias to
|
|
6
|
+
# ``view``), NOT the raw per-harness tool name.
|
|
7
|
+
#
|
|
8
|
+
# This is a SMALL, GENERAL default set covering the universal coding-agent tool
|
|
9
|
+
# taxonomy. It is an extension point: supply your own ``tool_display:`` section via
|
|
10
|
+
# the standard config-override chain (``.traceforge/config.yaml``, a
|
|
11
|
+
# ``TRACEFORGE_CONFIG`` file, or a ``traceforge.profiles`` entry point) to add or
|
|
12
|
+
# override labels with your own vocabulary. Per-key overrides win over these
|
|
13
|
+
# defaults; unknown tools resolve to None (the stub stays empty, unchanged).
|
|
14
|
+
|
|
15
|
+
tool_display:
|
|
16
|
+
shell: shell
|
|
17
|
+
view: read file
|
|
18
|
+
edit: edit file
|
|
19
|
+
create: create file
|
|
20
|
+
delete_file: delete file
|
|
21
|
+
grep: search
|
|
22
|
+
glob: find files
|
|
23
|
+
codebase_search: search codebase
|
|
24
|
+
web_fetch: fetch url
|
|
25
|
+
web_search: web search
|
|
26
|
+
web_browse: browse web
|
|
27
|
+
task: delegate task
|
|
28
|
+
ask_user: ask user
|
|
29
|
+
report_intent: report intent
|
|
30
|
+
think: think
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"""Semantic hazard detection for shell commands.
|
|
2
|
+
|
|
3
|
+
Adds high-signal *capability* tags for dangerous command shapes that the
|
|
4
|
+
structural classifier (effect × scope) does not by itself gate — raw block-device
|
|
5
|
+
writes, filesystem formats/wipes, persistence-mechanism writes, and fork bombs.
|
|
6
|
+
|
|
7
|
+
These tags are consumed by the governance recommendation rules
|
|
8
|
+
(``recommendation_rules.yaml``) to escalate the command regardless of its numeric
|
|
9
|
+
risk score. Detection is pure, deterministic regex/binary matching over the raw
|
|
10
|
+
command string and the already-parsed :class:`Classification`, so it introduces no
|
|
11
|
+
nondeterminism and no new scoring weight (the tags are not in
|
|
12
|
+
``risk.yaml: capability_weights``, so the numeric score is unchanged).
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import re
|
|
18
|
+
from typing import TYPE_CHECKING
|
|
19
|
+
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
from traceforge.classify.core import Classification
|
|
22
|
+
|
|
23
|
+
# ── Capability tag names (kept in sync with recommendation_rules.yaml) ──
|
|
24
|
+
RAW_DEVICE_WRITE = "raw_device_write"
|
|
25
|
+
FILESYSTEM_FORMAT = "filesystem_format"
|
|
26
|
+
PERSISTENCE_WRITE = "persistence_write"
|
|
27
|
+
FORK_BOMB = "fork_bomb"
|
|
28
|
+
|
|
29
|
+
# ── 1. Raw block-device write ───────────────────────────────────────────────
|
|
30
|
+
# dd ... of=/dev/sda, or a redirect (>, >>) into a physical block device.
|
|
31
|
+
# Physical device classes only — /dev/null, /dev/zero, /dev/urandom, /dev/tty
|
|
32
|
+
# are deliberately excluded so benign `> /dev/null` never trips.
|
|
33
|
+
_RAW_DEVICE_WRITE = re.compile(
|
|
34
|
+
r"(?:\bof=|>>?\s*)/dev/(?:sd|nvme|disk|hd|vd|mmcblk|xvd)\w*",
|
|
35
|
+
re.IGNORECASE,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
# ── 2. Filesystem format / wipe ─────────────────────────────────────────────
|
|
39
|
+
# Unambiguous formatter binaries (mkfs, mkfs.<fs>, mke2fs, mkswap, wipefs) plus
|
|
40
|
+
# destructive partition-table ops on parted/sfdisk/sgdisk. Read-only inspection
|
|
41
|
+
# (`parted -l`, `fdisk -l`, `parted <dev> print`) is NOT matched.
|
|
42
|
+
_FORMAT_BINARIES = frozenset({"mkfs", "mke2fs", "mkswap", "wipefs"})
|
|
43
|
+
_DISK_PARTITION_TOOLS = frozenset({"parted", "sfdisk", "sgdisk"})
|
|
44
|
+
_DISK_DESTRUCTIVE_OP = re.compile(
|
|
45
|
+
r"(?<!\S)(?:mklabel|mkpart|--zap-all|--zap|-Z|--delete|--new)\b",
|
|
46
|
+
re.IGNORECASE,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# ── 3. Persistence-mechanism write ──────────────────────────────────────────
|
|
50
|
+
# A write mechanism (redirect, tee, cp/mv/install/ln, or the crontab binary)
|
|
51
|
+
# targeting a known persistence location: cron, systemd units, or shell rc files.
|
|
52
|
+
_PERSIST_PATH = (
|
|
53
|
+
r"(?:"
|
|
54
|
+
r"/etc/cron(?:\.[a-z]+|tab|\.d)?"
|
|
55
|
+
r"|/var/spool/cron"
|
|
56
|
+
r"|/etc/systemd/|/run/systemd/|/lib/systemd/|/usr/lib/systemd/"
|
|
57
|
+
r"|/etc/profile(?:\.d)?|/etc/bash\.bashrc|/etc/zsh/|/etc/zprofile|/etc/zshrc"
|
|
58
|
+
r"|(?:~|\$HOME|/root|/home/[^/\s]+)/"
|
|
59
|
+
r"\.(?:bashrc|bash_profile|bash_login|profile|zshrc|zprofile|zlogin|zshenv)"
|
|
60
|
+
r"|(?:~|\$HOME|/root|/home/[^/\s]+)/\.config/(?:systemd|autostart)"
|
|
61
|
+
r")"
|
|
62
|
+
)
|
|
63
|
+
_PERSIST_REDIRECT = re.compile(r">>?\s*[\"']?" + _PERSIST_PATH)
|
|
64
|
+
_PERSIST_TEE = re.compile(r"\btee\b(?:\s+-{1,2}\S+)*\s+[\"']?" + _PERSIST_PATH)
|
|
65
|
+
_PERSIST_COPY = re.compile(r"\b(?:cp|mv|install|ln)\b[^\n]*?" + _PERSIST_PATH)
|
|
66
|
+
|
|
67
|
+
# ── 4. Fork bomb ────────────────────────────────────────────────────────────
|
|
68
|
+
# A function that recursively pipes itself into the background, then invokes
|
|
69
|
+
# itself: classic `:(){ :|:& };:` and named variants like `b(){ b|b& };b`.
|
|
70
|
+
_FORK_BOMB = re.compile(
|
|
71
|
+
r"(?P<n>[\w:.\-]+)\s*\(\)\s*\{(?P<body>[^{}]*)\}\s*;\s*(?P=n)",
|
|
72
|
+
re.DOTALL,
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _is_fork_bomb(command: str) -> bool:
|
|
77
|
+
for match in _FORK_BOMB.finditer(command):
|
|
78
|
+
name = match.group("n")
|
|
79
|
+
body = match.group("body")
|
|
80
|
+
if "|" in body and "&" in body and body.count(name) >= 2:
|
|
81
|
+
return True
|
|
82
|
+
return False
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _has_filesystem_format(command: str, binaries: tuple[str, ...]) -> bool:
|
|
86
|
+
for binary in binaries:
|
|
87
|
+
if binary in _FORMAT_BINARIES or binary.startswith("mkfs."):
|
|
88
|
+
return True
|
|
89
|
+
if any(tool in binaries for tool in _DISK_PARTITION_TOOLS):
|
|
90
|
+
return bool(_DISK_DESTRUCTIVE_OP.search(command))
|
|
91
|
+
return False
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _has_persistence_write(command: str, binaries: tuple[str, ...]) -> bool:
|
|
95
|
+
if "crontab" in binaries:
|
|
96
|
+
return True
|
|
97
|
+
return bool(
|
|
98
|
+
_PERSIST_REDIRECT.search(command)
|
|
99
|
+
or _PERSIST_TEE.search(command)
|
|
100
|
+
or _PERSIST_COPY.search(command)
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def detect_command_hazards(command: str, classification: Classification) -> set[str]:
|
|
105
|
+
"""Return semantic hazard capability tags for a shell command.
|
|
106
|
+
|
|
107
|
+
Pure and deterministic: matches the raw command string and the parsed
|
|
108
|
+
binaries. Tags are score-neutral (no ``capability_weights`` entry) and are
|
|
109
|
+
used only to drive escalation via the recommendation rules.
|
|
110
|
+
"""
|
|
111
|
+
hazards: set[str] = set()
|
|
112
|
+
if not command:
|
|
113
|
+
return hazards
|
|
114
|
+
|
|
115
|
+
binaries = classification.binaries or ()
|
|
116
|
+
|
|
117
|
+
if _RAW_DEVICE_WRITE.search(command):
|
|
118
|
+
hazards.add(RAW_DEVICE_WRITE)
|
|
119
|
+
if _has_filesystem_format(command, binaries):
|
|
120
|
+
hazards.add(FILESYSTEM_FORMAT)
|
|
121
|
+
if _has_persistence_write(command, binaries):
|
|
122
|
+
hazards.add(PERSISTENCE_WRITE)
|
|
123
|
+
if _is_fork_bomb(command):
|
|
124
|
+
hazards.add(FORK_BOMB)
|
|
125
|
+
|
|
126
|
+
return hazards
|
|
@@ -23,6 +23,7 @@ from traceforge.classify.coding import (
|
|
|
23
23
|
CodingMechanism,
|
|
24
24
|
ShellStructure,
|
|
25
25
|
)
|
|
26
|
+
from traceforge.classify.hazards import detect_command_hazards
|
|
26
27
|
from traceforge.classify.rules import (
|
|
27
28
|
SHELL_DELIVERY,
|
|
28
29
|
SHELL_SETUP,
|
|
@@ -476,6 +477,8 @@ def classify_shell(
|
|
|
476
477
|
cls = build_classification_from_commands(command_results, structure, "bash")
|
|
477
478
|
# Merge wrapper capabilities (e.g., elevated_privilege from sudo)
|
|
478
479
|
extra_caps: set[str] = set(all_wrapper_caps)
|
|
480
|
+
# Semantic hazard tags (raw-device write, fs format, persistence, fork bomb)
|
|
481
|
+
extra_caps |= detect_command_hazards(command, cls)
|
|
479
482
|
extra_effect: str | None = None
|
|
480
483
|
# Redirections (>, >>, 2>) indicate filesystem writes
|
|
481
484
|
if ShellStructure.REDIRECTED in structure:
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""Tool display resolution — populate ``EventMetadata.tool_display``.
|
|
2
|
+
|
|
3
|
+
The display string is the human-facing label for a tool call (e.g. ``"read file"``
|
|
4
|
+
for a ``view``-family tool). It is resolved at enrichment time from the canonical
|
|
5
|
+
tool identity via a layered chain:
|
|
6
|
+
|
|
7
|
+
1. Programmatic :class:`ToolDisplayProvider` objects (consumer-supplied extension
|
|
8
|
+
point) — first non-empty result wins. Lets a consumer compute a label
|
|
9
|
+
dynamically (e.g. per MCP server) beyond what a static map can express.
|
|
10
|
+
2. A static display map (canonical tool identity -> label). This is the
|
|
11
|
+
``tool_display`` section of :class:`~traceforge.classify.config.ClassifyConfig`:
|
|
12
|
+
the built-in generic defaults merged under consumer overrides through the same
|
|
13
|
+
config-override / ``traceforge.profiles`` entry-point chain used for
|
|
14
|
+
``tool_classifications`` / ``mcp_profiles`` / ``tool_overrides``. Per-key
|
|
15
|
+
overrides win over the defaults.
|
|
16
|
+
3. ``None`` — unknown tools degrade gracefully (the stub stays empty, as before).
|
|
17
|
+
|
|
18
|
+
Ship only GENERAL defaults here; a consumer supplies its own vocabulary as an
|
|
19
|
+
overlay. Nothing consumer-specific belongs in this module or the default data.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
from __future__ import annotations
|
|
23
|
+
|
|
24
|
+
import logging
|
|
25
|
+
from collections.abc import Mapping, Sequence
|
|
26
|
+
from typing import Protocol, runtime_checkable
|
|
27
|
+
|
|
28
|
+
logger = logging.getLogger(__name__)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _normalize_key(name: str) -> str:
|
|
32
|
+
"""Normalize a tool key to the canonical lookup form (lower, dashes -> underscores).
|
|
33
|
+
|
|
34
|
+
Mirrors the normalization applied to canonical tool names so map keys and the
|
|
35
|
+
resolved ``canonical`` argument compare equal regardless of casing/dashes.
|
|
36
|
+
"""
|
|
37
|
+
return name.lower().replace("-", "_")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@runtime_checkable
|
|
41
|
+
class ToolDisplayProvider(Protocol):
|
|
42
|
+
"""Extension point: resolve a display label for a tool call.
|
|
43
|
+
|
|
44
|
+
Consumers implement this to supply dynamic or domain-specific display logic
|
|
45
|
+
that a static map cannot express. It is consulted before the static display
|
|
46
|
+
map, so a provider can override the shipped defaults.
|
|
47
|
+
|
|
48
|
+
Return a non-empty label to claim the tool call, or ``None`` (or an empty
|
|
49
|
+
string) to defer to the next resolver in the chain (static map, then ``None``).
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
def display_for(self, canonical: str, raw: str) -> str | None:
|
|
53
|
+
"""Return a display label for the tool call, or ``None`` to defer.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
canonical: The normalized/canonical tool identity (e.g. ``"view"``).
|
|
57
|
+
raw: The original tool name as it appeared on the event (e.g.
|
|
58
|
+
``"read_file"`` or ``"mcp__server__search"``).
|
|
59
|
+
"""
|
|
60
|
+
...
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class ToolDisplayResolver:
|
|
64
|
+
"""Resolve a tool call to its display label from providers + a static map.
|
|
65
|
+
|
|
66
|
+
Immutable after construction. One resolver serves every tool call an
|
|
67
|
+
:class:`~traceforge.enricher.Enricher` observes.
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
__slots__ = ("_display_map", "_providers")
|
|
71
|
+
|
|
72
|
+
def __init__(
|
|
73
|
+
self,
|
|
74
|
+
display_map: Mapping[str, str] | None = None,
|
|
75
|
+
providers: Sequence[ToolDisplayProvider] | None = None,
|
|
76
|
+
) -> None:
|
|
77
|
+
"""
|
|
78
|
+
Args:
|
|
79
|
+
display_map: Canonical tool identity -> display label. Keys are
|
|
80
|
+
normalized on ingest, so callers may pass raw-cased keys.
|
|
81
|
+
providers: Optional programmatic providers, consulted in order before
|
|
82
|
+
the static map. The first non-empty result wins.
|
|
83
|
+
"""
|
|
84
|
+
self._display_map: dict[str, str] = {
|
|
85
|
+
_normalize_key(k): v for k, v in (display_map or {}).items()
|
|
86
|
+
}
|
|
87
|
+
self._providers: tuple[ToolDisplayProvider, ...] = tuple(providers or ())
|
|
88
|
+
|
|
89
|
+
def resolve(self, *, canonical: str, raw: str) -> str | None:
|
|
90
|
+
"""Resolve the display label for a tool call.
|
|
91
|
+
|
|
92
|
+
Args:
|
|
93
|
+
canonical: The normalized/canonical tool identity.
|
|
94
|
+
raw: The original tool name as it appeared on the event.
|
|
95
|
+
|
|
96
|
+
Returns:
|
|
97
|
+
The display label, or ``None`` when nothing matches (unknown tools
|
|
98
|
+
degrade gracefully — the stub stays empty).
|
|
99
|
+
"""
|
|
100
|
+
for provider in self._providers:
|
|
101
|
+
try:
|
|
102
|
+
result = provider.display_for(canonical, raw)
|
|
103
|
+
except Exception:
|
|
104
|
+
# A misbehaving consumer provider must never break enrichment;
|
|
105
|
+
# log and fall through to the next resolver.
|
|
106
|
+
logger.warning("ToolDisplayProvider %r raised; ignoring", provider, exc_info=True)
|
|
107
|
+
continue
|
|
108
|
+
if result:
|
|
109
|
+
return result
|
|
110
|
+
|
|
111
|
+
# Empty label is treated as "no display" so a map entry cannot force an
|
|
112
|
+
# empty string onto the stub.
|
|
113
|
+
return self._display_map.get(_normalize_key(canonical)) or None
|
|
@@ -14,7 +14,6 @@ from traceforge.cli.replay import replay
|
|
|
14
14
|
from traceforge.cli.status import status
|
|
15
15
|
from traceforge.cli.gate_cmd import gate
|
|
16
16
|
from traceforge.cli.init_cmd import init
|
|
17
|
-
from traceforge.cli.download_cmd import download_model
|
|
18
17
|
|
|
19
18
|
|
|
20
19
|
@click.group()
|
|
@@ -39,4 +38,3 @@ main.add_command(config)
|
|
|
39
38
|
main.add_command(status)
|
|
40
39
|
main.add_command(gate)
|
|
41
40
|
main.add_command(init)
|
|
42
|
-
main.add_command(download_model)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""traceforge gate — CLI command for cross-process gating relay."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
|
|
7
|
+
#: CLI / editor agents that expose an injectable, blocking preflight hook. The
|
|
8
|
+
#: injector (``traceforge init``) writes ``gate --stdin --agent <name>`` into each
|
|
9
|
+
#: agent's hook config, and ``--agent`` selects the matching deny-contract dialect
|
|
10
|
+
#: (JSON shape + exit code) — see ``traceforge.gate.client._output_deny``.
|
|
11
|
+
SUPPORTED_AGENTS: tuple[str, ...] = (
|
|
12
|
+
"claude-code",
|
|
13
|
+
"copilot-cli",
|
|
14
|
+
"codex",
|
|
15
|
+
"gemini",
|
|
16
|
+
"cline",
|
|
17
|
+
"cursor",
|
|
18
|
+
"amazon-q",
|
|
19
|
+
"opencode",
|
|
20
|
+
"openhands",
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@click.command("gate")
|
|
25
|
+
@click.option("--stdin", "from_stdin", is_flag=True, help="Read event JSON from stdin.")
|
|
26
|
+
@click.option(
|
|
27
|
+
"--agent",
|
|
28
|
+
"agent",
|
|
29
|
+
default=None,
|
|
30
|
+
type=click.Choice(SUPPORTED_AGENTS),
|
|
31
|
+
help="Translate the verdict into this agent's native hook deny contract "
|
|
32
|
+
"(shape + exit code). Defaults to the Claude Code dialect.",
|
|
33
|
+
)
|
|
34
|
+
@click.option(
|
|
35
|
+
"--format",
|
|
36
|
+
"output_format",
|
|
37
|
+
default=None,
|
|
38
|
+
type=click.Choice(["claude-code", "json"]),
|
|
39
|
+
help='Output format for the verdict (legacy; prefer --agent). "json" emits the raw verdict.',
|
|
40
|
+
)
|
|
41
|
+
def gate(from_stdin: bool, agent: str | None, output_format: str | None) -> None:
|
|
42
|
+
"""Relay a tool call event to the running Pipeline for gating.
|
|
43
|
+
|
|
44
|
+
Reads event JSON from stdin, looks up the Pipeline IPC server by session_id,
|
|
45
|
+
sends the event for scoring, and outputs the verdict in the target agent's
|
|
46
|
+
native hook dialect.
|
|
47
|
+
|
|
48
|
+
Typically invoked by agent hooks (e.g. Claude Code PreToolUse, Copilot CLI
|
|
49
|
+
preToolUse, Codex PreToolUse). ``--agent`` picks the deny contract; when it is
|
|
50
|
+
omitted the Claude Code dialect is used (also selectable via ``--format``).
|
|
51
|
+
"""
|
|
52
|
+
if not from_stdin:
|
|
53
|
+
raise click.UsageError("--stdin is required (only stdin mode is currently supported)")
|
|
54
|
+
|
|
55
|
+
# --agent is the primary selector; --format stays for backward compatibility.
|
|
56
|
+
dialect = agent or output_format or "claude-code"
|
|
57
|
+
|
|
58
|
+
from traceforge.gate.client import gate_from_stdin
|
|
59
|
+
|
|
60
|
+
gate_from_stdin(format=dialect)
|