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.
Files changed (221) hide show
  1. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/PKG-INFO +13 -4
  2. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/README.md +8 -3
  3. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/pyproject.toml +7 -1
  4. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/__init__.py +21 -0
  5. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/__init__.py +4 -0
  6. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/config.py +13 -0
  7. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/data/binary_info.yaml +1 -0
  8. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/data/effect_overrides.yaml +41 -0
  9. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/data/recommendation_rules.yaml +31 -0
  10. traceforge_toolkit-0.1.1/src/traceforge/classify/data/tool_display.yaml +30 -0
  11. traceforge_toolkit-0.1.1/src/traceforge/classify/hazards.py +126 -0
  12. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/shell.py +3 -0
  13. traceforge_toolkit-0.1.1/src/traceforge/classify/tool_display.py +113 -0
  14. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/cli/__init__.py +0 -2
  15. traceforge_toolkit-0.1.1/src/traceforge/cli/gate_cmd.py +60 -0
  16. traceforge_toolkit-0.1.1/src/traceforge/cli/init_cmd.py +334 -0
  17. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/cli/watch.py +53 -9
  18. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/config/models.py +100 -0
  19. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/enricher.py +165 -22
  20. traceforge_toolkit-0.1.1/src/traceforge/gate/client.py +264 -0
  21. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/gate/registry.py +34 -9
  22. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/gate/server.py +37 -1
  23. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/assessor.py +24 -2
  24. traceforge_toolkit-0.1.1/src/traceforge/governance/budget.py +133 -0
  25. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/pipeline.py +488 -39
  26. traceforge_toolkit-0.1.1/src/traceforge/governance/rules.py +742 -0
  27. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/shield.py +220 -25
  28. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/state.py +119 -0
  29. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/types.py +35 -1
  30. traceforge_toolkit-0.1.1/src/traceforge/mappings/langchain.yaml +185 -0
  31. traceforge_toolkit-0.1.1/src/traceforge/mappings/semantic_kernel.yaml +129 -0
  32. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/migrations/models.py +16 -0
  33. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/migrations/versions/0001_initial.py +19 -0
  34. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/pipeline.py +144 -12
  35. traceforge_toolkit-0.1.1/src/traceforge/progress.py +128 -0
  36. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sdk/__init__.py +2 -0
  37. traceforge_toolkit-0.1.1/src/traceforge/sdk/observe.py +541 -0
  38. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sdk/pipeline.py +79 -0
  39. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sinks/base.py +29 -1
  40. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sinks/callback.py +51 -1
  41. traceforge_toolkit-0.1.1/src/traceforge/sinks/sqlite_output.py +479 -0
  42. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sources/__init__.py +5 -0
  43. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sources/auto_detect.py +15 -0
  44. traceforge_toolkit-0.1.1/src/traceforge/sources/queue.py +132 -0
  45. traceforge_toolkit-0.1.1/src/traceforge/sources/sdk_live.py +403 -0
  46. traceforge_toolkit-0.1.1/src/traceforge/telemetry/attribution.py +358 -0
  47. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/title/_resolve.py +32 -7
  48. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/types.py +87 -0
  49. traceforge_toolkit-0.1.0/src/traceforge/cli/download_cmd.py +0 -74
  50. traceforge_toolkit-0.1.0/src/traceforge/cli/gate_cmd.py +0 -30
  51. traceforge_toolkit-0.1.0/src/traceforge/cli/init_cmd.py +0 -86
  52. traceforge_toolkit-0.1.0/src/traceforge/gate/client.py +0 -145
  53. traceforge_toolkit-0.1.0/src/traceforge/governance/budget.py +0 -59
  54. traceforge_toolkit-0.1.0/src/traceforge/governance/rules.py +0 -368
  55. traceforge_toolkit-0.1.0/src/traceforge/sinks/sqlite_output.py +0 -234
  56. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/.gitignore +0 -0
  57. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/LICENSE +0 -0
  58. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/__main__.py +0 -0
  59. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/_generated.py +0 -0
  60. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/adapters/__init__.py +0 -0
  61. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/adapters/base.py +0 -0
  62. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/adapters/genai_otel.py +0 -0
  63. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/adapters/mapped_json.py +0 -0
  64. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/adapters/otel.py +0 -0
  65. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/boundary/__init__.py +0 -0
  66. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/boundary/data/boundary-model.joblib +0 -0
  67. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/boundary/decode.py +0 -0
  68. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/boundary/features.py +0 -0
  69. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/boundary/inference.py +0 -0
  70. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/boundary/inferencer.py +0 -0
  71. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/cmd.py +0 -0
  72. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/coding.py +0 -0
  73. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/core.py +0 -0
  74. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/data/canonical_tools.yaml +0 -0
  75. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/data/mcp_profiles.yaml +0 -0
  76. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/data/risk.yaml +0 -0
  77. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/data/shell_defaults.yaml +0 -0
  78. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/data/shell_rules.yaml +0 -0
  79. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/data/tool_classifications.yaml +0 -0
  80. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/data/verb_inference.yaml +0 -0
  81. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/mcp.py +0 -0
  82. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/phases.py +0 -0
  83. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/powershell.py +0 -0
  84. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/registry.py +0 -0
  85. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/risk.py +0 -0
  86. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/rules.py +0 -0
  87. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/schema.yaml +0 -0
  88. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/tools.py +0 -0
  89. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/classify/workflow.py +0 -0
  90. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/cli/config_cmd.py +0 -0
  91. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/cli/detect.py +0 -0
  92. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/cli/factory.py +0 -0
  93. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/cli/replay.py +0 -0
  94. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/cli/runner.py +0 -0
  95. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/cli/score.py +0 -0
  96. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/cli/status.py +0 -0
  97. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/config/__init__.py +0 -0
  98. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/config/defaults.py +0 -0
  99. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/config/loader.py +0 -0
  100. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/config/mappings.py +0 -0
  101. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/formatting/__init__.py +0 -0
  102. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/formatting/budget.py +0 -0
  103. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/formatting/density.py +0 -0
  104. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/gate/__init__.py +0 -0
  105. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/gate/external.py +0 -0
  106. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/gates/__init__.py +0 -0
  107. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/gates/pii.py +0 -0
  108. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/gates/pii_patterns.yaml +0 -0
  109. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/__init__.py +0 -0
  110. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/canonical.py +0 -0
  111. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/codec.py +0 -0
  112. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/context.py +0 -0
  113. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/drift.py +0 -0
  114. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/emitter.py +0 -0
  115. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/envelope.py +0 -0
  116. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/ifc.py +0 -0
  117. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/integrity.py +0 -0
  118. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/labeler.py +0 -0
  119. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/mcp_drift.py +0 -0
  120. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/monitor.py +0 -0
  121. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/observer.py +0 -0
  122. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/persistence.py +0 -0
  123. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/phase1.py +0 -0
  124. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/pii.py +0 -0
  125. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/registry.py +0 -0
  126. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/results.py +0 -0
  127. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/risk_wrapper.py +0 -0
  128. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/governance/scorer.py +0 -0
  129. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/__init__.py +0 -0
  130. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/aider.yaml +0 -0
  131. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/aider_markdown.yaml +0 -0
  132. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/amazonq.yaml +0 -0
  133. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/antigravity.yaml +0 -0
  134. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/claude.yaml +0 -0
  135. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/cline.yaml +0 -0
  136. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/codex.yaml +0 -0
  137. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/continue_dev.yaml +0 -0
  138. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/copilot.yaml +0 -0
  139. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/copilot_markdown.yaml +0 -0
  140. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/copilot_vscode.yaml +0 -0
  141. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/crewai.yaml +0 -0
  142. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/goose.yaml +0 -0
  143. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/langgraph.yaml +0 -0
  144. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/maf.yaml +0 -0
  145. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/maf_transcript.yaml +0 -0
  146. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/openai_agents.yaml +0 -0
  147. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/opencode.yaml +0 -0
  148. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/openhands.yaml +0 -0
  149. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/pydantic_ai.yaml +0 -0
  150. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/smolagents.yaml +0 -0
  151. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/mappings/sweagent.yaml +0 -0
  152. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/migrations/__init__.py +0 -0
  153. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/migrations/env.py +0 -0
  154. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/migrations/runner.py +0 -0
  155. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/migrations/script.py.mako +0 -0
  156. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/migrations/versions/__init__.py +0 -0
  157. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/models.py +0 -0
  158. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/parsers/__init__.py +0 -0
  159. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/parsers/aider.py +0 -0
  160. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/parsers/base.py +0 -0
  161. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/parsers/copilot.py +0 -0
  162. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/phase/__init__.py +0 -0
  163. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/phase/data/phase-model.joblib +0 -0
  164. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/phase/data/potion-base-8M/README.md +0 -0
  165. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/phase/data/potion-base-8M/config.json +0 -0
  166. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/phase/data/potion-base-8M/model.safetensors +0 -0
  167. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/phase/data/potion-base-8M/modules.json +0 -0
  168. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/phase/data/potion-base-8M/tokenizer.json +0 -0
  169. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/phase/event_rows.py +0 -0
  170. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/phase/features.py +0 -0
  171. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/phase/inference.py +0 -0
  172. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/phase/inferencer.py +0 -0
  173. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/phase/segmentation.py +0 -0
  174. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/__init__.py +0 -0
  175. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/amazonq.py +0 -0
  176. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/antigravity.py +0 -0
  177. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/claude.py +0 -0
  178. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/cline.py +0 -0
  179. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/codex.py +0 -0
  180. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/continue_dev.py +0 -0
  181. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/copilot_vscode.py +0 -0
  182. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/goose.py +0 -0
  183. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/maf_transcript.py +0 -0
  184. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/openai_agents.py +0 -0
  185. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/opencode.py +0 -0
  186. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/openhands.py +0 -0
  187. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/pydantic_ai.py +0 -0
  188. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/registry.py +0 -0
  189. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/preprocessors/smolagents.py +0 -0
  190. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/py.typed +0 -0
  191. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sdk/gate_policy.py +0 -0
  192. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sdk/gate_types.py +0 -0
  193. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sdk/verdict.py +0 -0
  194. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sinks/__init__.py +0 -0
  195. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sinks/console.py +0 -0
  196. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sinks/factory.py +0 -0
  197. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sinks/jsonl.py +0 -0
  198. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sinks/otel_exporter.py +0 -0
  199. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sinks/parquet.py +0 -0
  200. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sinks/s3.py +0 -0
  201. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sinks/webhook.py +0 -0
  202. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sources/base.py +0 -0
  203. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sources/file_poll.py +0 -0
  204. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sources/file_watch.py +0 -0
  205. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sources/http_poll.py +0 -0
  206. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sources/replay.py +0 -0
  207. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sources/sqlite.py +0 -0
  208. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/sources/sse.py +0 -0
  209. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/telemetry/__init__.py +0 -0
  210. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/title/__init__.py +0 -0
  211. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/title/context.py +0 -0
  212. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/title/data/boilerplate_files.json +0 -0
  213. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/title/heuristics.py +0 -0
  214. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/title/hygiene.py +0 -0
  215. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/title/inference.py +0 -0
  216. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/title/inferencer.py +0 -0
  217. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/title/naming.py +0 -0
  218. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/trace.py +0 -0
  219. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/tracking/__init__.py +0 -0
  220. {traceforge_toolkit-0.1.0 → traceforge_toolkit-0.1.1}/src/traceforge/tracking/models.py +0 -0
  221. {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.0
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
  [![Lint](https://github.com/dfinson/traceforge/actions/workflows/ci-lint.yml/badge.svg)](https://github.com/dfinson/traceforge/actions/workflows/ci-lint.yml)
62
66
  [![Test](https://github.com/dfinson/traceforge/actions/workflows/ci-test.yml/badge.svg)](https://github.com/dfinson/traceforge/actions/workflows/ci-test.yml)
63
- [![PyPI](https://img.shields.io/badge/PyPI-coming%20soon-FF9921)](https://pypi.org/project/traceforge/)
67
+ [![PyPI](https://img.shields.io/pypi/v/traceforge-toolkit?color=FF9921&label=PyPI)](https://pypi.org/project/traceforge-toolkit/)
64
68
  [![Python](https://img.shields.io/badge/python-3.11%20|%203.12%20|%203.13-256EF3)](https://github.com/dfinson/traceforge)
65
69
  [![License: MIT](https://img.shields.io/badge/license-MIT-7359AE.svg)](LICENSE)
66
70
  [![Docs](https://img.shields.io/badge/docs-traceforge-FF9921)](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`, `download-model`).
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
- 🚧 **Under active development**: not yet published to PyPI. The pipeline is feature-complete:
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
  [![Lint](https://github.com/dfinson/traceforge/actions/workflows/ci-lint.yml/badge.svg)](https://github.com/dfinson/traceforge/actions/workflows/ci-lint.yml)
8
8
  [![Test](https://github.com/dfinson/traceforge/actions/workflows/ci-test.yml/badge.svg)](https://github.com/dfinson/traceforge/actions/workflows/ci-test.yml)
9
- [![PyPI](https://img.shields.io/badge/PyPI-coming%20soon-FF9921)](https://pypi.org/project/traceforge/)
9
+ [![PyPI](https://img.shields.io/pypi/v/traceforge-toolkit?color=FF9921&label=PyPI)](https://pypi.org/project/traceforge-toolkit/)
10
10
  [![Python](https://img.shields.io/badge/python-3.11%20|%203.12%20|%203.13-256EF3)](https://github.com/dfinson/traceforge)
11
11
  [![License: MIT](https://img.shields.io/badge/license-MIT-7359AE.svg)](LICENSE)
12
12
  [![Docs](https://img.shields.io/badge/docs-traceforge-FF9921)](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`, `download-model`).
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
- 🚧 **Under active development**: not yet published to PyPI. The pipeline is feature-complete:
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.0"
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():
@@ -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)