htmlgraph 0.23.4__py3-none-any.whl → 0.24.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. htmlgraph/__init__.py +5 -1
  2. htmlgraph/cigs/__init__.py +77 -0
  3. htmlgraph/cigs/autonomy.py +385 -0
  4. htmlgraph/cigs/cost.py +475 -0
  5. htmlgraph/cigs/messages_basic.py +472 -0
  6. htmlgraph/cigs/messaging.py +365 -0
  7. htmlgraph/cigs/models.py +771 -0
  8. htmlgraph/cigs/pattern_storage.py +427 -0
  9. htmlgraph/cigs/patterns.py +503 -0
  10. htmlgraph/cigs/posttool_analyzer.py +234 -0
  11. htmlgraph/cigs/tracker.py +317 -0
  12. htmlgraph/cli.py +325 -11
  13. htmlgraph/hooks/cigs_pretool_enforcer.py +350 -0
  14. htmlgraph/hooks/posttooluse.py +50 -2
  15. htmlgraph/hooks/task_enforcer.py +60 -4
  16. htmlgraph/models.py +14 -1
  17. htmlgraph/orchestration/headless_spawner.py +525 -35
  18. htmlgraph/orchestrator-system-prompt-optimized.txt +259 -53
  19. htmlgraph/reflection.py +442 -0
  20. htmlgraph/sdk.py +26 -9
  21. {htmlgraph-0.23.4.dist-info → htmlgraph-0.24.0.dist-info}/METADATA +2 -1
  22. {htmlgraph-0.23.4.dist-info → htmlgraph-0.24.0.dist-info}/RECORD +29 -17
  23. {htmlgraph-0.23.4.data → htmlgraph-0.24.0.data}/data/htmlgraph/dashboard.html +0 -0
  24. {htmlgraph-0.23.4.data → htmlgraph-0.24.0.data}/data/htmlgraph/styles.css +0 -0
  25. {htmlgraph-0.23.4.data → htmlgraph-0.24.0.data}/data/htmlgraph/templates/AGENTS.md.template +0 -0
  26. {htmlgraph-0.23.4.data → htmlgraph-0.24.0.data}/data/htmlgraph/templates/CLAUDE.md.template +0 -0
  27. {htmlgraph-0.23.4.data → htmlgraph-0.24.0.data}/data/htmlgraph/templates/GEMINI.md.template +0 -0
  28. {htmlgraph-0.23.4.dist-info → htmlgraph-0.24.0.dist-info}/WHEEL +0 -0
  29. {htmlgraph-0.23.4.dist-info → htmlgraph-0.24.0.dist-info}/entry_points.txt +0 -0
htmlgraph/cli.py CHANGED
@@ -1209,16 +1209,17 @@ def cmd_session_start_info(args: argparse.Namespace) -> None:
1209
1209
  print(json.dumps(info, indent=2, default=str))
1210
1210
  else:
1211
1211
  # Human-readable format
1212
- status = info["status"]
1212
+ status: dict = info["status"] # type: ignore
1213
1213
  print("=" * 80)
1214
1214
  print("SESSION START INFO")
1215
1215
  print("=" * 80)
1216
1216
 
1217
1217
  # Project status
1218
1218
  print(f"\nProject: {status.get('project_name', 'HtmlGraph')}")
1219
- print(f"Total nodes: {status.get('total_nodes', 0)}")
1220
- print(f"In progress: {status.get('in_progress_count', 0)}")
1221
- print(f"Completed: {status.get('done_count', 0)}")
1219
+ print(f"Total features: {status.get('total_features', 0)}")
1220
+ print(f"In progress: {status.get('wip_count', 0)}")
1221
+ by_status = status.get("by_status", {})
1222
+ print(f"Completed: {by_status.get('done', 0)}")
1222
1223
 
1223
1224
  # Active work item (validation status)
1224
1225
  active_work = info.get("active_work")
@@ -3012,6 +3013,201 @@ def cmd_orchestrator_reset_violations(args: argparse.Namespace) -> None:
3012
3013
  print("You can now continue with delegation workflow")
3013
3014
 
3014
3015
 
3016
+ def cmd_orchestrator_acknowledge_violation(args: argparse.Namespace) -> None:
3017
+ """Acknowledge circuit breaker violation and reset state."""
3018
+ from htmlgraph.orchestrator_mode import OrchestratorModeManager
3019
+
3020
+ manager = OrchestratorModeManager(args.graph_dir)
3021
+
3022
+ # Check if circuit breaker is triggered
3023
+ if not manager.is_circuit_breaker_triggered():
3024
+ print("ℹ️ No circuit breaker to acknowledge")
3025
+ print("Current violations:", manager.get_violation_count())
3026
+ return
3027
+
3028
+ # Reset violations and circuit breaker
3029
+ manager.reset_violations()
3030
+
3031
+ print("✓ Circuit breaker acknowledged and reset")
3032
+ print("Violation counter: cleared")
3033
+ print("You can now continue with delegation workflow")
3034
+
3035
+
3036
+ def cmd_cigs_status(args: argparse.Namespace) -> None:
3037
+ """Show current session CIGS status."""
3038
+ from pathlib import Path
3039
+
3040
+ from htmlgraph.cigs.autonomy import AutonomyRecommender
3041
+ from htmlgraph.cigs.pattern_storage import PatternStorage
3042
+ from htmlgraph.cigs.tracker import ViolationTracker
3043
+
3044
+ graph_dir = Path(args.graph_dir or ".htmlgraph")
3045
+
3046
+ # Get violation tracker
3047
+ tracker = ViolationTracker(graph_dir)
3048
+ summary = tracker.get_session_violations()
3049
+
3050
+ # Get pattern storage
3051
+ pattern_storage = PatternStorage(graph_dir)
3052
+ patterns = pattern_storage.get_anti_patterns()
3053
+
3054
+ # Get autonomy recommendation
3055
+ recommender = AutonomyRecommender()
3056
+ autonomy = recommender.recommend(summary, patterns)
3057
+
3058
+ # Print formatted status
3059
+ print("=== CIGS Status ===\n")
3060
+ print(f"Session: {summary.session_id}")
3061
+ print(f"Violations: {summary.total_violations}/3")
3062
+ print(f"Compliance Rate: {summary.compliance_rate:.1%}")
3063
+ print(f"Total Waste: {summary.total_waste_tokens} tokens")
3064
+ print(
3065
+ f"Circuit Breaker: {'🚨 TRIGGERED' if summary.circuit_breaker_triggered else 'Not triggered'}"
3066
+ )
3067
+
3068
+ if summary.violations_by_type:
3069
+ print("\nViolation Breakdown:")
3070
+ for vtype, count in summary.violations_by_type.items():
3071
+ print(f" • {vtype}: {count}")
3072
+
3073
+ print(f"\nAutonomy Level: {autonomy.level.upper()}")
3074
+ print(f"Messaging Intensity: {autonomy.messaging_intensity}")
3075
+ print(f"Enforcement Mode: {autonomy.enforcement_mode}")
3076
+
3077
+ if patterns:
3078
+ print(f"\nAnti-Patterns Detected: {len(patterns)}")
3079
+ for pattern in patterns[:3]:
3080
+ print(f" • {pattern.name} ({pattern.occurrence_count}x)")
3081
+
3082
+
3083
+ def cmd_cigs_summary(args: argparse.Namespace) -> None:
3084
+ """Show detailed session summary."""
3085
+ from pathlib import Path
3086
+
3087
+ from htmlgraph.cigs.tracker import ViolationTracker
3088
+
3089
+ graph_dir = Path(args.graph_dir or ".htmlgraph")
3090
+ tracker = ViolationTracker(graph_dir)
3091
+
3092
+ # Get session ID (default to current)
3093
+ session_id = args.session_id or tracker._session_id
3094
+
3095
+ if not session_id:
3096
+ print("⚠️ No active session. Specify --session-id to view past sessions.")
3097
+ return
3098
+
3099
+ summary = tracker.get_session_violations(session_id)
3100
+
3101
+ # Print detailed summary
3102
+ print("=== CIGS Session Summary ===\n")
3103
+ print(f"Session ID: {summary.session_id}")
3104
+ print("─" * 50)
3105
+ print(f"Total Violations: {summary.total_violations}")
3106
+ print(f"Compliance Rate: {summary.compliance_rate:.1%}")
3107
+ print(f"Total Waste: {summary.total_waste_tokens} tokens")
3108
+ print(
3109
+ f"Circuit Breaker: {'🚨 TRIGGERED' if summary.circuit_breaker_triggered else 'Not triggered'}"
3110
+ )
3111
+
3112
+ if summary.violations_by_type:
3113
+ print("\nViolation Breakdown:")
3114
+ for vtype, count in summary.violations_by_type.items():
3115
+ print(f" • {vtype}: {count}")
3116
+
3117
+ if summary.violations:
3118
+ print(f"\nRecent Violations ({len(summary.violations)}):")
3119
+ for v in summary.violations[-5:]:
3120
+ print(f" • {v.tool} - {v.violation_type} - {v.waste_tokens} tokens wasted")
3121
+ print(f" Should have: {v.should_have_delegated_to}")
3122
+
3123
+
3124
+ def cmd_cigs_patterns(args: argparse.Namespace) -> None:
3125
+ """List all detected patterns with occurrence counts."""
3126
+ from pathlib import Path
3127
+
3128
+ from htmlgraph.cigs.pattern_storage import PatternStorage
3129
+
3130
+ graph_dir = Path(args.graph_dir or ".htmlgraph")
3131
+ pattern_storage = PatternStorage(graph_dir)
3132
+
3133
+ # Get all patterns
3134
+ anti_patterns = pattern_storage.get_anti_patterns()
3135
+ good_patterns = pattern_storage.get_good_patterns()
3136
+
3137
+ # Print anti-patterns
3138
+ print("=== CIGS Pattern Analysis ===\n")
3139
+
3140
+ if anti_patterns:
3141
+ print("Anti-Patterns Detected:")
3142
+ print("─" * 50)
3143
+ for pattern in sorted(
3144
+ anti_patterns, key=lambda p: p.occurrence_count, reverse=True
3145
+ ):
3146
+ print(f"\n{pattern.name}")
3147
+ print(f" Occurrences: {pattern.occurrence_count}")
3148
+ print(f" Description: {pattern.description}")
3149
+ print(f" Sessions Affected: {len(pattern.sessions_affected)}")
3150
+
3151
+ if pattern.correct_approach:
3152
+ print(f" ✓ Fix: {pattern.correct_approach}")
3153
+
3154
+ if pattern.delegation_suggestion:
3155
+ print(f" 💡 Instead: {pattern.delegation_suggestion}")
3156
+ else:
3157
+ print("No anti-patterns detected yet.")
3158
+
3159
+ # Print good patterns
3160
+ if good_patterns:
3161
+ print("\n\nGood Patterns Observed:")
3162
+ print("─" * 50)
3163
+ for pattern in sorted(
3164
+ good_patterns, key=lambda p: p.occurrence_count, reverse=True
3165
+ ):
3166
+ print(f"\n{pattern.name}")
3167
+ print(f" Occurrences: {pattern.occurrence_count}")
3168
+ print(f" Description: {pattern.description}")
3169
+ print(f" Sessions Affected: {len(pattern.sessions_affected)}")
3170
+
3171
+
3172
+ def cmd_cigs_reset_violations(args: argparse.Namespace) -> None:
3173
+ """Reset violation count for current session."""
3174
+ from pathlib import Path
3175
+
3176
+ from htmlgraph.cigs.tracker import ViolationTracker
3177
+
3178
+ graph_dir = Path(args.graph_dir or ".htmlgraph")
3179
+ tracker = ViolationTracker(graph_dir)
3180
+
3181
+ # Get current session
3182
+ session_id = tracker._session_id
3183
+ if not session_id:
3184
+ print("⚠️ No active session")
3185
+ return
3186
+
3187
+ # Check current violations
3188
+ summary = tracker.get_session_violations()
3189
+
3190
+ if summary.total_violations == 0:
3191
+ print("ℹ️ No violations to reset")
3192
+ return
3193
+
3194
+ # Confirm reset
3195
+ if not args.yes:
3196
+ print(f"Current violations: {summary.total_violations}")
3197
+ print(f"Total waste: {summary.total_waste_tokens} tokens")
3198
+ response = input("\nReset violations for current session? [y/N]: ")
3199
+ if response.lower() not in ("y", "yes"):
3200
+ print("Reset cancelled")
3201
+ return
3202
+
3203
+ # Clear violations file
3204
+ tracker.clear_session_file()
3205
+
3206
+ print("✓ Violations reset for current session")
3207
+ print("Circuit breaker: cleared")
3208
+ print("Starting fresh for this session")
3209
+
3210
+
3015
3211
  def cmd_publish(args: argparse.Namespace) -> None:
3016
3212
  """Build and publish the package to PyPI (Interoperable)."""
3017
3213
  import shutil
@@ -3606,7 +3802,9 @@ def cmd_claude(args: argparse.Namespace) -> None:
3606
3802
  try:
3607
3803
  if args.init:
3608
3804
  # Load optimized orchestrator system prompt
3609
- prompt_file = Path(__file__).parent / "orchestrator_system_prompt.txt"
3805
+ prompt_file = (
3806
+ Path(__file__).parent / "orchestrator-system-prompt-optimized.txt"
3807
+ )
3610
3808
 
3611
3809
  if prompt_file.exists():
3612
3810
  system_prompt = prompt_file.read_text(encoding="utf-8")
@@ -3726,22 +3924,69 @@ def cmd_claude(args: argparse.Namespace) -> None:
3726
3924
  )
3727
3925
  sys.exit(1)
3728
3926
 
3927
+ # Load optimized orchestrator system prompt
3928
+ prompt_file = (
3929
+ Path(__file__).parent / "orchestrator-system-prompt-optimized.txt"
3930
+ )
3931
+
3932
+ if prompt_file.exists():
3933
+ system_prompt = prompt_file.read_text(encoding="utf-8")
3934
+ else:
3935
+ # Fallback: provide minimal orchestrator guidance
3936
+ system_prompt = textwrap.dedent(
3937
+ """
3938
+ You are an AI orchestrator for HtmlGraph project development.
3939
+
3940
+ CRITICAL DIRECTIVES:
3941
+ 1. DELEGATE to subagents - do not implement directly
3942
+ 2. CREATE work items before delegating (features, bugs, spikes)
3943
+ 3. USE SDK for tracking - all work must be tracked in .htmlgraph/
3944
+ 4. RESPECT dependencies - check blockers before starting
3945
+
3946
+ Key Rules:
3947
+ - Implementation work → delegate to general-purpose subagent
3948
+ - Research/exploration → delegate to explorer subagent
3949
+ - Testing/validation → delegate to test-runner subagent
3950
+ - Complex analysis → delegate to appropriate specialist
3951
+
3952
+ Always use:
3953
+ from htmlgraph import SDK
3954
+ sdk = SDK(agent='orchestrator')
3955
+
3956
+ See CLAUDE.md for complete orchestrator directives.
3957
+ """
3958
+ )
3959
+
3960
+ # Combine orchestrator prompt with orchestration rules
3961
+ combined_prompt = system_prompt
3962
+ if orchestration_rules:
3963
+ combined_prompt = f"{system_prompt}\n\n---\n\n{orchestration_rules}"
3964
+
3729
3965
  if args.quiet or args.format == "json":
3730
- cmd = ["claude", "--plugin-dir", str(plugin_dir)]
3966
+ cmd = [
3967
+ "claude",
3968
+ "--plugin-dir",
3969
+ str(plugin_dir),
3970
+ "--append-system-prompt",
3971
+ combined_prompt,
3972
+ ]
3731
3973
  else:
3732
3974
  print("=" * 60)
3733
3975
  print("🔧 HtmlGraph Development Mode")
3734
3976
  print("=" * 60)
3735
3977
  print(f"\nLoading plugin from: {plugin_dir}")
3736
3978
  print(" ✓ Skills, agents, and hooks will be loaded from local files")
3979
+ print(" ✓ Orchestrator system prompt will be appended")
3737
3980
  print(" ✓ Multi-AI delegation rules will be injected")
3738
3981
  print(" ✓ Changes to plugin files will take effect after restart")
3739
3982
  print()
3740
- cmd = ["claude", "--plugin-dir", str(plugin_dir)]
3741
-
3742
- # Add orchestration rules if available
3743
- if orchestration_rules:
3744
- cmd.extend(["--append-system-prompt", orchestration_rules])
3983
+ cmd = [
3984
+ "claude",
3985
+ "--plugin-dir",
3986
+ str(plugin_dir),
3987
+ "--append-system-prompt",
3988
+ combined_prompt,
3989
+ ]
3745
3990
 
3746
3991
  try:
3747
3992
  subprocess.run(cmd, check=False)
@@ -5177,6 +5422,61 @@ For more help: https://github.com/Shakes-tzd/htmlgraph
5177
5422
  "--graph-dir", "-g", default=".htmlgraph", help="Graph directory"
5178
5423
  )
5179
5424
 
5425
+ # orchestrator acknowledge-violation
5426
+ orchestrator_acknowledge_violation = orchestrator_subparsers.add_parser(
5427
+ "acknowledge-violation",
5428
+ help="Acknowledge circuit breaker violation and reset state",
5429
+ )
5430
+ orchestrator_acknowledge_violation.add_argument(
5431
+ "--graph-dir", "-g", default=".htmlgraph", help="Graph directory"
5432
+ )
5433
+
5434
+ # cigs (Computational Imperative Guidance System) with subcommands
5435
+ cigs_parser = subparsers.add_parser(
5436
+ "cigs", help="CIGS (Computational Imperative Guidance System) management"
5437
+ )
5438
+ cigs_subparsers = cigs_parser.add_subparsers(
5439
+ dest="cigs_command", help="CIGS command"
5440
+ )
5441
+
5442
+ # cigs status
5443
+ cigs_status = cigs_subparsers.add_parser(
5444
+ "status", help="Show current session CIGS status"
5445
+ )
5446
+ cigs_status.add_argument(
5447
+ "--graph-dir", "-g", default=".htmlgraph", help="Graph directory"
5448
+ )
5449
+
5450
+ # cigs summary
5451
+ cigs_summary = cigs_subparsers.add_parser(
5452
+ "summary", help="Show detailed session summary"
5453
+ )
5454
+ cigs_summary.add_argument(
5455
+ "--session-id", "-s", help="Session ID (defaults to current session)"
5456
+ )
5457
+ cigs_summary.add_argument(
5458
+ "--graph-dir", "-g", default=".htmlgraph", help="Graph directory"
5459
+ )
5460
+
5461
+ # cigs patterns
5462
+ cigs_patterns = cigs_subparsers.add_parser(
5463
+ "patterns", help="List all detected patterns"
5464
+ )
5465
+ cigs_patterns.add_argument(
5466
+ "--graph-dir", "-g", default=".htmlgraph", help="Graph directory"
5467
+ )
5468
+
5469
+ # cigs reset-violations
5470
+ cigs_reset_violations = cigs_subparsers.add_parser(
5471
+ "reset-violations", help="Reset violation count for current session"
5472
+ )
5473
+ cigs_reset_violations.add_argument(
5474
+ "--yes", "-y", action="store_true", help="Skip confirmation prompt"
5475
+ )
5476
+ cigs_reset_violations.add_argument(
5477
+ "--graph-dir", "-g", default=".htmlgraph", help="Graph directory"
5478
+ )
5479
+
5180
5480
  # install-gemini-extension
5181
5481
  subparsers.add_parser(
5182
5482
  "install-gemini-extension",
@@ -5438,9 +5738,23 @@ For more help: https://github.com/Shakes-tzd/htmlgraph
5438
5738
  cmd_orchestrator_set_level(args)
5439
5739
  elif args.orchestrator_command == "reset-violations":
5440
5740
  cmd_orchestrator_reset_violations(args)
5741
+ elif args.orchestrator_command == "acknowledge-violation":
5742
+ cmd_orchestrator_acknowledge_violation(args)
5441
5743
  else:
5442
5744
  orchestrator_parser.print_help()
5443
5745
  sys.exit(1)
5746
+ elif args.command == "cigs":
5747
+ if args.cigs_command == "status":
5748
+ cmd_cigs_status(args)
5749
+ elif args.cigs_command == "summary":
5750
+ cmd_cigs_summary(args)
5751
+ elif args.cigs_command == "patterns":
5752
+ cmd_cigs_patterns(args)
5753
+ elif args.cigs_command == "reset-violations":
5754
+ cmd_cigs_reset_violations(args)
5755
+ else:
5756
+ cigs_parser.print_help()
5757
+ sys.exit(1)
5444
5758
  elif args.command == "install-gemini-extension":
5445
5759
  cmd_install_gemini_extension(args)
5446
5760
  elif args.command == "claude":