htmlgraph 0.20.1__py3-none-any.whl → 0.27.5__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 (304) hide show
  1. htmlgraph/.htmlgraph/.session-warning-state.json +6 -0
  2. htmlgraph/.htmlgraph/agents.json +72 -0
  3. htmlgraph/.htmlgraph/htmlgraph.db +0 -0
  4. htmlgraph/__init__.py +51 -1
  5. htmlgraph/__init__.pyi +123 -0
  6. htmlgraph/agent_detection.py +26 -10
  7. htmlgraph/agent_registry.py +2 -1
  8. htmlgraph/analytics/__init__.py +8 -1
  9. htmlgraph/analytics/cli.py +86 -20
  10. htmlgraph/analytics/cost_analyzer.py +391 -0
  11. htmlgraph/analytics/cost_monitor.py +664 -0
  12. htmlgraph/analytics/cost_reporter.py +675 -0
  13. htmlgraph/analytics/cross_session.py +617 -0
  14. htmlgraph/analytics/dependency.py +10 -6
  15. htmlgraph/analytics/pattern_learning.py +771 -0
  16. htmlgraph/analytics/session_graph.py +707 -0
  17. htmlgraph/analytics/strategic/__init__.py +80 -0
  18. htmlgraph/analytics/strategic/cost_optimizer.py +611 -0
  19. htmlgraph/analytics/strategic/pattern_detector.py +876 -0
  20. htmlgraph/analytics/strategic/preference_manager.py +709 -0
  21. htmlgraph/analytics/strategic/suggestion_engine.py +747 -0
  22. htmlgraph/analytics/work_type.py +67 -27
  23. htmlgraph/analytics_index.py +53 -20
  24. htmlgraph/api/__init__.py +3 -0
  25. htmlgraph/api/cost_alerts_websocket.py +416 -0
  26. htmlgraph/api/main.py +2498 -0
  27. htmlgraph/api/static/htmx.min.js +1 -0
  28. htmlgraph/api/static/style-redesign.css +1344 -0
  29. htmlgraph/api/static/style.css +1079 -0
  30. htmlgraph/api/templates/dashboard-redesign.html +1366 -0
  31. htmlgraph/api/templates/dashboard.html +794 -0
  32. htmlgraph/api/templates/partials/activity-feed-hierarchical.html +326 -0
  33. htmlgraph/api/templates/partials/activity-feed.html +1100 -0
  34. htmlgraph/api/templates/partials/agents-redesign.html +317 -0
  35. htmlgraph/api/templates/partials/agents.html +317 -0
  36. htmlgraph/api/templates/partials/event-traces.html +373 -0
  37. htmlgraph/api/templates/partials/features-kanban-redesign.html +509 -0
  38. htmlgraph/api/templates/partials/features.html +578 -0
  39. htmlgraph/api/templates/partials/metrics-redesign.html +346 -0
  40. htmlgraph/api/templates/partials/metrics.html +346 -0
  41. htmlgraph/api/templates/partials/orchestration-redesign.html +443 -0
  42. htmlgraph/api/templates/partials/orchestration.html +198 -0
  43. htmlgraph/api/templates/partials/spawners.html +375 -0
  44. htmlgraph/api/templates/partials/work-items.html +613 -0
  45. htmlgraph/api/websocket.py +538 -0
  46. htmlgraph/archive/__init__.py +24 -0
  47. htmlgraph/archive/bloom.py +234 -0
  48. htmlgraph/archive/fts.py +297 -0
  49. htmlgraph/archive/manager.py +583 -0
  50. htmlgraph/archive/search.py +244 -0
  51. htmlgraph/atomic_ops.py +560 -0
  52. htmlgraph/attribute_index.py +2 -1
  53. htmlgraph/bounded_paths.py +539 -0
  54. htmlgraph/builders/base.py +57 -2
  55. htmlgraph/builders/bug.py +19 -3
  56. htmlgraph/builders/chore.py +19 -3
  57. htmlgraph/builders/epic.py +19 -3
  58. htmlgraph/builders/feature.py +27 -3
  59. htmlgraph/builders/insight.py +2 -1
  60. htmlgraph/builders/metric.py +2 -1
  61. htmlgraph/builders/pattern.py +2 -1
  62. htmlgraph/builders/phase.py +19 -3
  63. htmlgraph/builders/spike.py +29 -3
  64. htmlgraph/builders/track.py +42 -1
  65. htmlgraph/cigs/__init__.py +81 -0
  66. htmlgraph/cigs/autonomy.py +385 -0
  67. htmlgraph/cigs/cost.py +475 -0
  68. htmlgraph/cigs/messages_basic.py +472 -0
  69. htmlgraph/cigs/messaging.py +365 -0
  70. htmlgraph/cigs/models.py +771 -0
  71. htmlgraph/cigs/pattern_storage.py +427 -0
  72. htmlgraph/cigs/patterns.py +503 -0
  73. htmlgraph/cigs/posttool_analyzer.py +234 -0
  74. htmlgraph/cigs/reporter.py +818 -0
  75. htmlgraph/cigs/tracker.py +317 -0
  76. htmlgraph/cli/.htmlgraph/.session-warning-state.json +6 -0
  77. htmlgraph/cli/.htmlgraph/agents.json +72 -0
  78. htmlgraph/cli/.htmlgraph/htmlgraph.db +0 -0
  79. htmlgraph/cli/__init__.py +42 -0
  80. htmlgraph/cli/__main__.py +6 -0
  81. htmlgraph/cli/analytics.py +1424 -0
  82. htmlgraph/cli/base.py +685 -0
  83. htmlgraph/cli/constants.py +206 -0
  84. htmlgraph/cli/core.py +954 -0
  85. htmlgraph/cli/main.py +147 -0
  86. htmlgraph/cli/models.py +475 -0
  87. htmlgraph/cli/templates/__init__.py +1 -0
  88. htmlgraph/cli/templates/cost_dashboard.py +399 -0
  89. htmlgraph/cli/work/__init__.py +239 -0
  90. htmlgraph/cli/work/browse.py +115 -0
  91. htmlgraph/cli/work/features.py +568 -0
  92. htmlgraph/cli/work/orchestration.py +676 -0
  93. htmlgraph/cli/work/report.py +728 -0
  94. htmlgraph/cli/work/sessions.py +466 -0
  95. htmlgraph/cli/work/snapshot.py +559 -0
  96. htmlgraph/cli/work/tracks.py +486 -0
  97. htmlgraph/cli_commands/__init__.py +1 -0
  98. htmlgraph/cli_commands/feature.py +195 -0
  99. htmlgraph/cli_framework.py +115 -0
  100. htmlgraph/collections/__init__.py +2 -0
  101. htmlgraph/collections/base.py +197 -14
  102. htmlgraph/collections/bug.py +2 -1
  103. htmlgraph/collections/chore.py +2 -1
  104. htmlgraph/collections/epic.py +2 -1
  105. htmlgraph/collections/feature.py +2 -1
  106. htmlgraph/collections/insight.py +2 -1
  107. htmlgraph/collections/metric.py +2 -1
  108. htmlgraph/collections/pattern.py +2 -1
  109. htmlgraph/collections/phase.py +2 -1
  110. htmlgraph/collections/session.py +194 -0
  111. htmlgraph/collections/spike.py +13 -2
  112. htmlgraph/collections/task_delegation.py +241 -0
  113. htmlgraph/collections/todo.py +14 -1
  114. htmlgraph/collections/traces.py +487 -0
  115. htmlgraph/config/cost_models.json +56 -0
  116. htmlgraph/config.py +190 -0
  117. htmlgraph/context_analytics.py +2 -1
  118. htmlgraph/converter.py +116 -7
  119. htmlgraph/cost_analysis/__init__.py +5 -0
  120. htmlgraph/cost_analysis/analyzer.py +438 -0
  121. htmlgraph/dashboard.html +2246 -248
  122. htmlgraph/dashboard.html.backup +6592 -0
  123. htmlgraph/dashboard.html.bak +7181 -0
  124. htmlgraph/dashboard.html.bak2 +7231 -0
  125. htmlgraph/dashboard.html.bak3 +7232 -0
  126. htmlgraph/db/__init__.py +38 -0
  127. htmlgraph/db/queries.py +790 -0
  128. htmlgraph/db/schema.py +1788 -0
  129. htmlgraph/decorators.py +317 -0
  130. htmlgraph/dependency_models.py +2 -1
  131. htmlgraph/deploy.py +26 -27
  132. htmlgraph/docs/API_REFERENCE.md +841 -0
  133. htmlgraph/docs/HTTP_API.md +750 -0
  134. htmlgraph/docs/INTEGRATION_GUIDE.md +752 -0
  135. htmlgraph/docs/ORCHESTRATION_PATTERNS.md +717 -0
  136. htmlgraph/docs/README.md +532 -0
  137. htmlgraph/docs/__init__.py +77 -0
  138. htmlgraph/docs/docs_version.py +55 -0
  139. htmlgraph/docs/metadata.py +93 -0
  140. htmlgraph/docs/migrations.py +232 -0
  141. htmlgraph/docs/template_engine.py +143 -0
  142. htmlgraph/docs/templates/_sections/cli_reference.md.j2 +52 -0
  143. htmlgraph/docs/templates/_sections/core_concepts.md.j2 +29 -0
  144. htmlgraph/docs/templates/_sections/sdk_basics.md.j2 +69 -0
  145. htmlgraph/docs/templates/base_agents.md.j2 +78 -0
  146. htmlgraph/docs/templates/example_user_override.md.j2 +47 -0
  147. htmlgraph/docs/version_check.py +163 -0
  148. htmlgraph/edge_index.py +2 -1
  149. htmlgraph/error_handler.py +544 -0
  150. htmlgraph/event_log.py +86 -37
  151. htmlgraph/event_migration.py +2 -1
  152. htmlgraph/file_watcher.py +12 -8
  153. htmlgraph/find_api.py +2 -1
  154. htmlgraph/git_events.py +67 -9
  155. htmlgraph/hooks/.htmlgraph/.session-warning-state.json +6 -0
  156. htmlgraph/hooks/.htmlgraph/agents.json +72 -0
  157. htmlgraph/hooks/.htmlgraph/index.sqlite +0 -0
  158. htmlgraph/hooks/__init__.py +8 -0
  159. htmlgraph/hooks/bootstrap.py +169 -0
  160. htmlgraph/hooks/cigs_pretool_enforcer.py +354 -0
  161. htmlgraph/hooks/concurrent_sessions.py +208 -0
  162. htmlgraph/hooks/context.py +350 -0
  163. htmlgraph/hooks/drift_handler.py +525 -0
  164. htmlgraph/hooks/event_tracker.py +790 -99
  165. htmlgraph/hooks/git_commands.py +175 -0
  166. htmlgraph/hooks/installer.py +5 -1
  167. htmlgraph/hooks/orchestrator.py +327 -76
  168. htmlgraph/hooks/orchestrator_reflector.py +31 -4
  169. htmlgraph/hooks/post_tool_use_failure.py +32 -7
  170. htmlgraph/hooks/post_tool_use_handler.py +257 -0
  171. htmlgraph/hooks/posttooluse.py +92 -19
  172. htmlgraph/hooks/pretooluse.py +527 -7
  173. htmlgraph/hooks/prompt_analyzer.py +637 -0
  174. htmlgraph/hooks/session_handler.py +668 -0
  175. htmlgraph/hooks/session_summary.py +395 -0
  176. htmlgraph/hooks/state_manager.py +504 -0
  177. htmlgraph/hooks/subagent_detection.py +202 -0
  178. htmlgraph/hooks/subagent_stop.py +369 -0
  179. htmlgraph/hooks/task_enforcer.py +99 -4
  180. htmlgraph/hooks/validator.py +212 -91
  181. htmlgraph/ids.py +2 -1
  182. htmlgraph/learning.py +125 -100
  183. htmlgraph/mcp_server.py +2 -1
  184. htmlgraph/models.py +217 -18
  185. htmlgraph/operations/README.md +62 -0
  186. htmlgraph/operations/__init__.py +79 -0
  187. htmlgraph/operations/analytics.py +339 -0
  188. htmlgraph/operations/bootstrap.py +289 -0
  189. htmlgraph/operations/events.py +244 -0
  190. htmlgraph/operations/fastapi_server.py +231 -0
  191. htmlgraph/operations/hooks.py +350 -0
  192. htmlgraph/operations/initialization.py +597 -0
  193. htmlgraph/operations/initialization.py.backup +228 -0
  194. htmlgraph/operations/server.py +303 -0
  195. htmlgraph/orchestration/__init__.py +58 -0
  196. htmlgraph/orchestration/claude_launcher.py +179 -0
  197. htmlgraph/orchestration/command_builder.py +72 -0
  198. htmlgraph/orchestration/headless_spawner.py +281 -0
  199. htmlgraph/orchestration/live_events.py +377 -0
  200. htmlgraph/orchestration/model_selection.py +327 -0
  201. htmlgraph/orchestration/plugin_manager.py +140 -0
  202. htmlgraph/orchestration/prompts.py +137 -0
  203. htmlgraph/orchestration/spawner_event_tracker.py +383 -0
  204. htmlgraph/orchestration/spawners/__init__.py +16 -0
  205. htmlgraph/orchestration/spawners/base.py +194 -0
  206. htmlgraph/orchestration/spawners/claude.py +173 -0
  207. htmlgraph/orchestration/spawners/codex.py +435 -0
  208. htmlgraph/orchestration/spawners/copilot.py +294 -0
  209. htmlgraph/orchestration/spawners/gemini.py +471 -0
  210. htmlgraph/orchestration/subprocess_runner.py +36 -0
  211. htmlgraph/{orchestration.py → orchestration/task_coordination.py} +16 -8
  212. htmlgraph/orchestration.md +563 -0
  213. htmlgraph/orchestrator-system-prompt-optimized.txt +863 -0
  214. htmlgraph/orchestrator.py +2 -1
  215. htmlgraph/orchestrator_config.py +357 -0
  216. htmlgraph/orchestrator_mode.py +115 -4
  217. htmlgraph/parallel.py +2 -1
  218. htmlgraph/parser.py +86 -6
  219. htmlgraph/path_query.py +608 -0
  220. htmlgraph/pattern_matcher.py +636 -0
  221. htmlgraph/pydantic_models.py +476 -0
  222. htmlgraph/quality_gates.py +350 -0
  223. htmlgraph/query_builder.py +2 -1
  224. htmlgraph/query_composer.py +509 -0
  225. htmlgraph/reflection.py +443 -0
  226. htmlgraph/refs.py +344 -0
  227. htmlgraph/repo_hash.py +512 -0
  228. htmlgraph/repositories/__init__.py +292 -0
  229. htmlgraph/repositories/analytics_repository.py +455 -0
  230. htmlgraph/repositories/analytics_repository_standard.py +628 -0
  231. htmlgraph/repositories/feature_repository.py +581 -0
  232. htmlgraph/repositories/feature_repository_htmlfile.py +668 -0
  233. htmlgraph/repositories/feature_repository_memory.py +607 -0
  234. htmlgraph/repositories/feature_repository_sqlite.py +858 -0
  235. htmlgraph/repositories/filter_service.py +620 -0
  236. htmlgraph/repositories/filter_service_standard.py +445 -0
  237. htmlgraph/repositories/shared_cache.py +621 -0
  238. htmlgraph/repositories/shared_cache_memory.py +395 -0
  239. htmlgraph/repositories/track_repository.py +552 -0
  240. htmlgraph/repositories/track_repository_htmlfile.py +619 -0
  241. htmlgraph/repositories/track_repository_memory.py +508 -0
  242. htmlgraph/repositories/track_repository_sqlite.py +711 -0
  243. htmlgraph/sdk/__init__.py +398 -0
  244. htmlgraph/sdk/__init__.pyi +14 -0
  245. htmlgraph/sdk/analytics/__init__.py +19 -0
  246. htmlgraph/sdk/analytics/engine.py +155 -0
  247. htmlgraph/sdk/analytics/helpers.py +178 -0
  248. htmlgraph/sdk/analytics/registry.py +109 -0
  249. htmlgraph/sdk/base.py +484 -0
  250. htmlgraph/sdk/constants.py +216 -0
  251. htmlgraph/sdk/core.pyi +308 -0
  252. htmlgraph/sdk/discovery.py +120 -0
  253. htmlgraph/sdk/help/__init__.py +12 -0
  254. htmlgraph/sdk/help/mixin.py +699 -0
  255. htmlgraph/sdk/mixins/__init__.py +15 -0
  256. htmlgraph/sdk/mixins/attribution.py +113 -0
  257. htmlgraph/sdk/mixins/mixin.py +410 -0
  258. htmlgraph/sdk/operations/__init__.py +12 -0
  259. htmlgraph/sdk/operations/mixin.py +427 -0
  260. htmlgraph/sdk/orchestration/__init__.py +17 -0
  261. htmlgraph/sdk/orchestration/coordinator.py +203 -0
  262. htmlgraph/sdk/orchestration/spawner.py +204 -0
  263. htmlgraph/sdk/planning/__init__.py +19 -0
  264. htmlgraph/sdk/planning/bottlenecks.py +93 -0
  265. htmlgraph/sdk/planning/mixin.py +211 -0
  266. htmlgraph/sdk/planning/parallel.py +186 -0
  267. htmlgraph/sdk/planning/queue.py +210 -0
  268. htmlgraph/sdk/planning/recommendations.py +87 -0
  269. htmlgraph/sdk/planning/smart_planning.py +319 -0
  270. htmlgraph/sdk/session/__init__.py +19 -0
  271. htmlgraph/sdk/session/continuity.py +57 -0
  272. htmlgraph/sdk/session/handoff.py +110 -0
  273. htmlgraph/sdk/session/info.py +309 -0
  274. htmlgraph/sdk/session/manager.py +103 -0
  275. htmlgraph/sdk/strategic/__init__.py +26 -0
  276. htmlgraph/sdk/strategic/mixin.py +563 -0
  277. htmlgraph/server.py +295 -107
  278. htmlgraph/session_hooks.py +300 -0
  279. htmlgraph/session_manager.py +285 -3
  280. htmlgraph/session_registry.py +587 -0
  281. htmlgraph/session_state.py +436 -0
  282. htmlgraph/session_warning.py +2 -1
  283. htmlgraph/sessions/__init__.py +23 -0
  284. htmlgraph/sessions/handoff.py +756 -0
  285. htmlgraph/system_prompts.py +450 -0
  286. htmlgraph/templates/orchestration-view.html +350 -0
  287. htmlgraph/track_builder.py +33 -1
  288. htmlgraph/track_manager.py +38 -0
  289. htmlgraph/transcript.py +18 -5
  290. htmlgraph/validation.py +115 -0
  291. htmlgraph/watch.py +2 -1
  292. htmlgraph/work_type_utils.py +2 -1
  293. {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/dashboard.html +2246 -248
  294. {htmlgraph-0.20.1.dist-info → htmlgraph-0.27.5.dist-info}/METADATA +95 -64
  295. htmlgraph-0.27.5.dist-info/RECORD +337 -0
  296. {htmlgraph-0.20.1.dist-info → htmlgraph-0.27.5.dist-info}/entry_points.txt +1 -1
  297. htmlgraph/cli.py +0 -4839
  298. htmlgraph/sdk.py +0 -2359
  299. htmlgraph-0.20.1.dist-info/RECORD +0 -118
  300. {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/styles.css +0 -0
  301. {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/templates/AGENTS.md.template +0 -0
  302. {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/templates/CLAUDE.md.template +0 -0
  303. {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/templates/GEMINI.md.template +0 -0
  304. {htmlgraph-0.20.1.dist-info → htmlgraph-0.27.5.dist-info}/WHEEL +0 -0
@@ -0,0 +1,179 @@
1
+ from __future__ import annotations
2
+
3
+ """Claude Code launcher with multiple integration modes.
4
+
5
+ Coordinates launching Claude Code with various HtmlGraph integration options.
6
+ """
7
+
8
+ import argparse
9
+ import logging
10
+ import sys
11
+ from pathlib import Path
12
+
13
+ from htmlgraph.orchestration.command_builder import ClaudeCommandBuilder
14
+ from htmlgraph.orchestration.plugin_manager import PluginManager
15
+ from htmlgraph.orchestration.prompts import get_orchestrator_prompt
16
+ from htmlgraph.orchestration.subprocess_runner import SubprocessRunner
17
+
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ class ClaudeLauncher:
22
+ """Launch Claude Code with various HtmlGraph integration modes.
23
+
24
+ Supports four launch scenarios:
25
+ 1. --init: Orchestrator mode with plugin installation
26
+ 2. --continue: Resume last session with orchestrator rules
27
+ 3. --dev: Development mode with local plugin
28
+ 4. default: Minimal orchestrator rules
29
+ """
30
+
31
+ def __init__(self, args: argparse.Namespace) -> None:
32
+ """Initialize launcher with parsed arguments.
33
+
34
+ Args:
35
+ args: Parsed command-line arguments
36
+ """
37
+ self.args = args
38
+ self.interactive = not (args.quiet or args.format == "json")
39
+
40
+ def launch(self) -> None:
41
+ """Main entry point - routes to appropriate scenario.
42
+
43
+ Raises:
44
+ SystemExit: On error during launch
45
+ """
46
+ try:
47
+ if self.args.init:
48
+ self._launch_orchestrator_mode()
49
+ elif self.args.continue_session:
50
+ self._launch_resume_mode()
51
+ elif self.args.dev:
52
+ self._launch_dev_mode()
53
+ else:
54
+ self._launch_default_mode()
55
+ except Exception as e:
56
+ logger.warning(f"Error: Failed to start Claude Code: {e}")
57
+ sys.exit(1)
58
+
59
+ def _launch_orchestrator_mode(self) -> None:
60
+ """Launch with orchestrator prompt (--init).
61
+
62
+ Installs plugin, loads orchestrator system prompt, and starts Claude Code
63
+ in orchestrator mode with multi-AI delegation rules.
64
+ """
65
+ # Install plugin
66
+ PluginManager.install_or_update(verbose=self.interactive)
67
+
68
+ # Load prompt
69
+ prompt = get_orchestrator_prompt(include_dev_mode=False)
70
+
71
+ # Show banner
72
+ if self.interactive:
73
+ self._print_orchestrator_banner()
74
+
75
+ # Build command
76
+ cmd = ClaudeCommandBuilder().with_system_prompt(prompt).build()
77
+
78
+ # Execute
79
+ SubprocessRunner.run_claude_command(cmd)
80
+
81
+ def _launch_resume_mode(self) -> None:
82
+ """Resume last session with orchestrator rules (--continue).
83
+
84
+ Installs/updates marketplace plugin and resumes the last Claude Code
85
+ session with orchestrator system prompt. Uses marketplace plugin, NOT
86
+ local source (only --dev uses local source).
87
+ """
88
+ # Install/update marketplace plugin
89
+ PluginManager.install_or_update(verbose=self.interactive)
90
+
91
+ # Load prompt
92
+ prompt = get_orchestrator_prompt(include_dev_mode=False)
93
+
94
+ # Show status
95
+ if self.interactive:
96
+ logger.info("Resuming last Claude Code session...")
97
+ logger.info(" ✓ Multi-AI delegation rules injected")
98
+ logger.info(" ✓ Using marketplace plugin")
99
+
100
+ # Build command (no --plugin-dir, uses marketplace)
101
+ cmd = ClaudeCommandBuilder().with_resume().with_system_prompt(prompt).build()
102
+
103
+ # Execute
104
+ SubprocessRunner.run_claude_command(cmd)
105
+
106
+ def _launch_dev_mode(self) -> None:
107
+ """Launch with local plugin for development (--dev).
108
+
109
+ Loads plugin from local source directory for development/testing.
110
+ Changes to plugin files take effect after restart.
111
+ """
112
+ # Get and validate plugin directory
113
+ plugin_dir = PluginManager.get_plugin_dir()
114
+ PluginManager.validate_plugin_dir(plugin_dir)
115
+
116
+ # Load prompt with dev mode
117
+ prompt = get_orchestrator_prompt(include_dev_mode=True)
118
+
119
+ # Show banner
120
+ if self.interactive:
121
+ self._print_dev_mode_banner(plugin_dir)
122
+
123
+ # Build command
124
+ cmd = (
125
+ ClaudeCommandBuilder()
126
+ .with_plugin_dir(str(plugin_dir))
127
+ .with_system_prompt(prompt)
128
+ .build()
129
+ )
130
+
131
+ # Execute
132
+ SubprocessRunner.run_claude_command(cmd)
133
+
134
+ def _launch_default_mode(self) -> None:
135
+ """Launch with minimal orchestrator rules (default).
136
+
137
+ Starts Claude Code with basic multi-AI delegation rules but no plugin.
138
+ """
139
+ # Load prompt
140
+ prompt = get_orchestrator_prompt(include_dev_mode=False)
141
+
142
+ # Show status
143
+ if self.interactive:
144
+ logger.info("Starting Claude Code with multi-AI delegation rules...")
145
+
146
+ # Build command
147
+ cmd = ClaudeCommandBuilder().with_system_prompt(prompt).build()
148
+
149
+ # Execute
150
+ SubprocessRunner.run_claude_command(cmd)
151
+
152
+ def _print_orchestrator_banner(self) -> None:
153
+ """Print orchestrator mode banner."""
154
+ print("=" * 60)
155
+ logger.info("🤖 HtmlGraph Orchestrator Mode")
156
+ print("=" * 60)
157
+ logger.info("\nStarting Claude Code with orchestrator system prompt...")
158
+ logger.info("Key directives:")
159
+ logger.info(" ✓ Delegate to Gemini (FREE), Codex, Copilot first")
160
+ logger.info(" ✓ Use Task() only as fallback")
161
+ logger.info(" ✓ Create work items before delegating")
162
+ logger.info(" ✓ Track all work in .htmlgraph/")
163
+ print()
164
+
165
+ def _print_dev_mode_banner(self, plugin_dir: Path) -> None:
166
+ """Print development mode banner.
167
+
168
+ Args:
169
+ plugin_dir: Path to local plugin directory
170
+ """
171
+ print("=" * 60)
172
+ logger.info("🔧 HtmlGraph Development Mode")
173
+ print("=" * 60)
174
+ logger.info(f"\nLoading plugin from: {plugin_dir}")
175
+ logger.info(" ✓ Skills, agents, and hooks will be loaded from local files")
176
+ logger.info(" ✓ Orchestrator system prompt will be appended")
177
+ logger.info(" ✓ Multi-AI delegation rules will be injected")
178
+ logger.info(" ✓ Changes to plugin files will take effect after restart")
179
+ print()
@@ -0,0 +1,72 @@
1
+ from __future__ import annotations
2
+
3
+ """Command builder for Claude Code CLI invocations.
4
+
5
+ Provides fluent interface for constructing Claude CLI commands.
6
+ """
7
+
8
+
9
+ from typing import TYPE_CHECKING
10
+
11
+ if TYPE_CHECKING:
12
+ from pathlib import Path
13
+
14
+
15
+ class ClaudeCommandBuilder:
16
+ """Fluent builder for Claude Code CLI commands.
17
+
18
+ Example:
19
+ >>> builder = ClaudeCommandBuilder()
20
+ >>> cmd = builder.with_resume() \\
21
+ ... .with_plugin_dir("/path/to/plugin") \\
22
+ ... .with_system_prompt("System prompt text") \\
23
+ ... .build()
24
+ >>> # Result: ["claude", "--resume", "--plugin-dir", "/path/to/plugin",
25
+ ... # "--append-system-prompt", "System prompt text"]
26
+ """
27
+
28
+ def __init__(self) -> None:
29
+ """Initialize with base command."""
30
+ self._cmd: list[str] = ["claude"]
31
+
32
+ def with_resume(self) -> ClaudeCommandBuilder:
33
+ """Add --resume flag to resume last session.
34
+
35
+ Returns:
36
+ Self for method chaining
37
+ """
38
+ self._cmd.append("--resume")
39
+ return self
40
+
41
+ def with_plugin_dir(self, plugin_dir: str | Path) -> ClaudeCommandBuilder:
42
+ """Add --plugin-dir flag.
43
+
44
+ Args:
45
+ plugin_dir: Path to plugin directory
46
+
47
+ Returns:
48
+ Self for method chaining
49
+ """
50
+ self._cmd.extend(["--plugin-dir", str(plugin_dir)])
51
+ return self
52
+
53
+ def with_system_prompt(self, prompt: str) -> ClaudeCommandBuilder:
54
+ """Add --append-system-prompt flag.
55
+
56
+ Args:
57
+ prompt: System prompt text to append
58
+
59
+ Returns:
60
+ Self for method chaining
61
+ """
62
+ if prompt: # Only add if prompt is not empty
63
+ self._cmd.extend(["--append-system-prompt", prompt])
64
+ return self
65
+
66
+ def build(self) -> list[str]:
67
+ """Build the final command list.
68
+
69
+ Returns:
70
+ List of command arguments ready for subprocess.run()
71
+ """
72
+ return self._cmd
@@ -0,0 +1,281 @@
1
+ """Headless AI spawner for multi-AI orchestration.
2
+
3
+ import logging
4
+
5
+ logger = logging.getLogger(__name__)
6
+
7
+ This module provides backward compatibility by delegating to modular spawner implementations.
8
+ """
9
+
10
+ from typing import Any
11
+
12
+ from .spawners import (
13
+ AIResult,
14
+ ClaudeSpawner,
15
+ CodexSpawner,
16
+ CopilotSpawner,
17
+ GeminiSpawner,
18
+ )
19
+
20
+ # Re-export AIResult for backward compatibility
21
+ __all__ = ["HeadlessSpawner", "AIResult"]
22
+
23
+
24
+ class HeadlessSpawner:
25
+ """
26
+ Spawn AI agents in headless CLI mode.
27
+
28
+ Supports multiple AI CLIs:
29
+ - spawn_gemini(): Google Gemini (free tier)
30
+ - spawn_codex(): OpenAI Codex (ChatGPT Plus+)
31
+ - spawn_copilot(): GitHub Copilot (GitHub subscription)
32
+ - spawn_claude(): Claude Code (same login as Task tool)
33
+
34
+ spawn_claude() vs Task() Tool:
35
+ --------------------------------
36
+ Both use the same Claude Code authentication and billing, but:
37
+
38
+ spawn_claude():
39
+ - Isolated execution (no context sharing)
40
+ - Fresh session each call
41
+ - Best for: independent tasks, external scripts, parallel processing
42
+ - Cache miss on each call (higher token usage)
43
+
44
+ Task():
45
+ - Shared conversation context
46
+ - Builds on previous work
47
+ - Best for: orchestration, related sequential work
48
+ - Cache hits in session (5x cheaper for related work)
49
+
50
+ Example - When to use spawn_claude():
51
+ # Independent tasks in external script
52
+ spawner = HeadlessSpawner()
53
+ for file in files:
54
+ result = spawner.spawn_claude(f"Analyze {file} independently")
55
+ save_result(file, result)
56
+
57
+ Example - When to use Task() instead:
58
+ # Related tasks in orchestration workflow
59
+ Task(prompt="Analyze all files and compare them")
60
+ # Better: shares context, uses caching
61
+ """
62
+
63
+ def __init__(self) -> None:
64
+ """Initialize spawner with modular implementations."""
65
+ self._gemini_spawner = GeminiSpawner()
66
+ self._codex_spawner = CodexSpawner()
67
+ self._copilot_spawner = CopilotSpawner()
68
+ self._claude_spawner = ClaudeSpawner()
69
+
70
+ # Expose internal methods for backward compatibility with tests
71
+ def _parse_and_track_gemini_events(self, jsonl_output: str, sdk: Any) -> list[dict]:
72
+ """Parse and track Gemini events (delegates to GeminiSpawner)."""
73
+ return self._gemini_spawner._parse_and_track_events(jsonl_output, sdk)
74
+
75
+ def _parse_and_track_codex_events(self, jsonl_output: str, sdk: Any) -> list[dict]:
76
+ """Parse and track Codex events (delegates to CodexSpawner)."""
77
+ return self._codex_spawner._parse_and_track_events(jsonl_output, sdk)
78
+
79
+ def _parse_and_track_copilot_events(
80
+ self, prompt: str, response: str, sdk: Any
81
+ ) -> list[dict]:
82
+ """Parse and track Copilot events (delegates to CopilotSpawner)."""
83
+ return self._copilot_spawner._parse_and_track_events(prompt, response, sdk)
84
+
85
+ def _get_sdk(self) -> Any:
86
+ """Get SDK instance (delegates to base spawner implementation)."""
87
+ return self._gemini_spawner._get_sdk()
88
+
89
+ def spawn_gemini(
90
+ self,
91
+ prompt: str,
92
+ output_format: str = "stream-json",
93
+ model: str | None = None,
94
+ include_directories: list[str] | None = None,
95
+ track_in_htmlgraph: bool = True,
96
+ timeout: int = 120,
97
+ tracker: Any = None,
98
+ parent_event_id: str | None = None,
99
+ ) -> AIResult:
100
+ """
101
+ Spawn Gemini in headless mode.
102
+
103
+ Args:
104
+ prompt: Task description for Gemini
105
+ output_format: "json" or "stream-json" (enables real-time tracking)
106
+ model: Model selection. Default: None (recommended - lets CLI choose
107
+ thinking-compatible models). Older models may fail.
108
+ include_directories: Directories to include for context. Default: None
109
+ track_in_htmlgraph: Enable HtmlGraph activity tracking. Default: True
110
+ timeout: Max seconds to wait
111
+ tracker: Optional SpawnerEventTracker for recording subprocess invocation
112
+ parent_event_id: Optional parent event ID for event hierarchy
113
+
114
+ Returns:
115
+ AIResult with response, error, and tracked events if tracking enabled
116
+ """
117
+ return self._gemini_spawner.spawn(
118
+ prompt=prompt,
119
+ output_format=output_format,
120
+ model=model,
121
+ include_directories=include_directories,
122
+ track_in_htmlgraph=track_in_htmlgraph,
123
+ timeout=timeout,
124
+ tracker=tracker,
125
+ parent_event_id=parent_event_id,
126
+ )
127
+
128
+ def spawn_codex(
129
+ self,
130
+ prompt: str,
131
+ output_json: bool = True,
132
+ model: str | None = None,
133
+ sandbox: str | None = None,
134
+ full_auto: bool = True,
135
+ images: list[str] | None = None,
136
+ output_last_message: str | None = None,
137
+ output_schema: str | None = None,
138
+ skip_git_check: bool = False,
139
+ working_directory: str | None = None,
140
+ use_oss: bool = False,
141
+ bypass_approvals: bool = False,
142
+ track_in_htmlgraph: bool = True,
143
+ timeout: int = 120,
144
+ tracker: Any = None,
145
+ parent_event_id: str | None = None,
146
+ ) -> AIResult:
147
+ """
148
+ Spawn Codex in headless mode.
149
+
150
+ Args:
151
+ prompt: Task description for Codex
152
+ output_json: JSONL output flag (enables real-time tracking)
153
+ model: Model selection (e.g., "gpt-4-turbo"). Default: None
154
+ sandbox: Sandbox mode ("read-only", "workspace-write", or full)
155
+ full_auto: Enable full auto mode. Default: True (required headless)
156
+ images: List of image paths (--image). Default: None
157
+ output_last_message: Write last message to file. Default: None
158
+ output_schema: JSON schema for validation. Default: None
159
+ skip_git_check: Skip git repo check. Default: False
160
+ working_directory: Workspace directory (--cd). Default: None
161
+ use_oss: Use local Ollama provider (--oss). Default: False
162
+ bypass_approvals: Bypass approval checks. Default: False
163
+ track_in_htmlgraph: Enable HtmlGraph activity tracking. Default: True
164
+ timeout: Max seconds to wait
165
+ tracker: Optional SpawnerEventTracker for recording subprocess invocation
166
+ parent_event_id: Optional parent event ID for event hierarchy
167
+
168
+ Returns:
169
+ AIResult with response, error, and tracked events if tracking enabled
170
+ """
171
+ return self._codex_spawner.spawn(
172
+ prompt=prompt,
173
+ output_json=output_json,
174
+ model=model,
175
+ sandbox=sandbox,
176
+ full_auto=full_auto,
177
+ images=images,
178
+ output_last_message=output_last_message,
179
+ output_schema=output_schema,
180
+ skip_git_check=skip_git_check,
181
+ working_directory=working_directory,
182
+ use_oss=use_oss,
183
+ bypass_approvals=bypass_approvals,
184
+ track_in_htmlgraph=track_in_htmlgraph,
185
+ timeout=timeout,
186
+ tracker=tracker,
187
+ parent_event_id=parent_event_id,
188
+ )
189
+
190
+ def spawn_copilot(
191
+ self,
192
+ prompt: str,
193
+ allow_tools: list[str] | None = None,
194
+ allow_all_tools: bool = False,
195
+ deny_tools: list[str] | None = None,
196
+ track_in_htmlgraph: bool = True,
197
+ timeout: int = 120,
198
+ tracker: Any = None,
199
+ parent_event_id: str | None = None,
200
+ ) -> AIResult:
201
+ """
202
+ Spawn GitHub Copilot in headless mode.
203
+
204
+ Args:
205
+ prompt: Task description for Copilot
206
+ allow_tools: Tools to auto-approve (e.g., ["shell(git)"])
207
+ allow_all_tools: Auto-approve all tools. Default: False
208
+ deny_tools: Tools to deny (--deny-tool). Default: None
209
+ track_in_htmlgraph: Enable HtmlGraph activity tracking. Default: True
210
+ timeout: Max seconds to wait
211
+ tracker: Optional SpawnerEventTracker for recording subprocess invocation
212
+ parent_event_id: Optional parent event ID for event hierarchy
213
+
214
+ Returns:
215
+ AIResult with response, error, and tracked events if tracking enabled
216
+ """
217
+ return self._copilot_spawner.spawn(
218
+ prompt=prompt,
219
+ allow_tools=allow_tools,
220
+ allow_all_tools=allow_all_tools,
221
+ deny_tools=deny_tools,
222
+ track_in_htmlgraph=track_in_htmlgraph,
223
+ timeout=timeout,
224
+ tracker=tracker,
225
+ parent_event_id=parent_event_id,
226
+ )
227
+
228
+ def spawn_claude(
229
+ self,
230
+ prompt: str,
231
+ output_format: str = "json",
232
+ permission_mode: str = "bypassPermissions",
233
+ resume: str | None = None,
234
+ verbose: bool = False,
235
+ timeout: int = 300,
236
+ extra_args: list[str] | None = None,
237
+ ) -> AIResult:
238
+ """
239
+ Spawn Claude in headless mode.
240
+
241
+ NOTE: Uses same Claude Code authentication as Task() tool, but provides
242
+ isolated execution context. Each call creates a new session without shared
243
+ context. Best for independent tasks or external scripts.
244
+
245
+ For orchestration workflows with shared context, prefer Task() tool which
246
+ leverages prompt caching (5x cheaper for related work).
247
+
248
+ Args:
249
+ prompt: Task description for Claude
250
+ output_format: "text" or "json" (stream-json requires --verbose)
251
+ permission_mode: Permission handling mode:
252
+ - "bypassPermissions": Auto-approve all (default)
253
+ - "acceptEdits": Auto-approve edits only
254
+ - "dontAsk": Fail on permission prompts
255
+ - "default": Normal interactive prompts
256
+ - "plan": Plan mode (no execution)
257
+ - "delegate": Delegation mode
258
+ resume: Resume from previous session (--resume). Default: None
259
+ verbose: Enable verbose output (--verbose). Default: False
260
+ timeout: Max seconds (default: 300, Claude can be slow with initialization)
261
+ extra_args: Additional arguments to pass to Claude CLI
262
+
263
+ Returns:
264
+ AIResult with response or error
265
+
266
+ Example:
267
+ >>> spawner = HeadlessSpawner()
268
+ >>> result = spawner.spawn_claude("What is 2+2?")
269
+ >>> if result.success:
270
+ ... logger.info("%s", result.response) # "4"
271
+ ... logger.info(f"Cost: ${result.raw_output['total_cost_usd']}")
272
+ """
273
+ return self._claude_spawner.spawn(
274
+ prompt=prompt,
275
+ output_format=output_format,
276
+ permission_mode=permission_mode,
277
+ resume=resume,
278
+ verbose=verbose,
279
+ timeout=timeout,
280
+ extra_args=extra_args,
281
+ )