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,294 @@
1
+ """Copilot spawner implementation."""
2
+
3
+ import logging
4
+ import subprocess
5
+ import time
6
+ from typing import TYPE_CHECKING, Any
7
+
8
+ from .base import AIResult, BaseSpawner
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+ if TYPE_CHECKING:
13
+ from htmlgraph.sdk import SDK
14
+
15
+
16
+ class CopilotSpawner(BaseSpawner):
17
+ """Spawner for GitHub Copilot CLI."""
18
+
19
+ def _parse_and_track_events(
20
+ self, prompt: str, response: str, sdk: "SDK"
21
+ ) -> list[dict]:
22
+ """
23
+ Track Copilot execution (start and result only).
24
+
25
+ Args:
26
+ prompt: Original prompt
27
+ response: Response from Copilot
28
+ sdk: HtmlGraph SDK instance for tracking
29
+
30
+ Returns:
31
+ Synthetic events list for consistency
32
+ """
33
+ events = []
34
+
35
+ # Track start
36
+ start_event = {"type": "copilot_start", "prompt": prompt[:100]}
37
+ events.append(start_event)
38
+ self._track_activity(
39
+ sdk,
40
+ tool="copilot_start",
41
+ summary=f"Copilot started with prompt: {prompt[:80]}",
42
+ payload={"prompt_length": len(prompt)},
43
+ )
44
+
45
+ # Track result
46
+ result_event = {"type": "copilot_result", "response": response[:100]}
47
+ events.append(result_event)
48
+ self._track_activity(
49
+ sdk,
50
+ tool="copilot_result",
51
+ summary=f"Copilot completed: {response[:80]}",
52
+ payload={"response_length": len(response)},
53
+ )
54
+
55
+ return events
56
+
57
+ def spawn(
58
+ self,
59
+ prompt: str,
60
+ allow_tools: list[str] | None = None,
61
+ allow_all_tools: bool = False,
62
+ deny_tools: list[str] | None = None,
63
+ track_in_htmlgraph: bool = True,
64
+ timeout: int = 120,
65
+ tracker: Any = None,
66
+ parent_event_id: str | None = None,
67
+ ) -> AIResult:
68
+ """
69
+ Spawn GitHub Copilot in headless mode.
70
+
71
+ Args:
72
+ prompt: Task description for Copilot
73
+ allow_tools: Tools to auto-approve (e.g., ["shell(git)"])
74
+ allow_all_tools: Auto-approve all tools. Default: False
75
+ deny_tools: Tools to deny (--deny-tool). Default: None
76
+ track_in_htmlgraph: Enable HtmlGraph activity tracking. Default: True
77
+ timeout: Max seconds to wait
78
+ tracker: Optional SpawnerEventTracker for recording subprocess invocation
79
+ parent_event_id: Optional parent event ID for event hierarchy
80
+
81
+ Returns:
82
+ AIResult with response, error, and tracked events if tracking enabled
83
+ """
84
+ # Initialize tracking if enabled
85
+ sdk = None
86
+ tracked_events = []
87
+ if track_in_htmlgraph:
88
+ sdk = self._get_sdk()
89
+
90
+ # Publish live event: spawner starting
91
+ self._publish_live_event(
92
+ "spawner_start",
93
+ "copilot",
94
+ prompt=prompt,
95
+ )
96
+ start_time = time.time()
97
+
98
+ cmd = ["copilot", "-p", prompt]
99
+
100
+ # Add allow all tools flag
101
+ if allow_all_tools:
102
+ cmd.append("--allow-all-tools")
103
+
104
+ # Add tool permissions
105
+ if allow_tools:
106
+ for tool in allow_tools:
107
+ cmd.extend(["--allow-tool", tool])
108
+
109
+ # Add denied tools
110
+ if deny_tools:
111
+ for tool in deny_tools:
112
+ cmd.extend(["--deny-tool", tool])
113
+
114
+ # Track spawner start if SDK available
115
+ if sdk:
116
+ self._track_activity(
117
+ sdk,
118
+ tool="copilot_spawn_start",
119
+ summary=f"Spawning Copilot: {prompt[:80]}",
120
+ payload={"prompt_length": len(prompt)},
121
+ )
122
+
123
+ try:
124
+ # Publish live event: executing
125
+ self._publish_live_event(
126
+ "spawner_phase",
127
+ "copilot",
128
+ phase="executing",
129
+ details="Running Copilot CLI",
130
+ )
131
+
132
+ # Record subprocess invocation if tracker is available
133
+ subprocess_event_id = None
134
+ logger.warning(
135
+ f"DEBUG: tracker={tracker is not None}, parent_event_id={parent_event_id}"
136
+ )
137
+ if tracker and parent_event_id:
138
+ logger.debug("Recording subprocess invocation for Copilot...")
139
+ try:
140
+ subprocess_event = tracker.record_tool_call(
141
+ tool_name="subprocess.copilot",
142
+ tool_input={"cmd": cmd},
143
+ phase_event_id=parent_event_id,
144
+ spawned_agent="github-copilot",
145
+ )
146
+ if subprocess_event:
147
+ subprocess_event_id = subprocess_event.get("event_id")
148
+ logger.warning(
149
+ f"DEBUG: Subprocess event created for Copilot: {subprocess_event_id}"
150
+ )
151
+ else:
152
+ logger.debug("subprocess_event was None")
153
+ except Exception as e:
154
+ # Tracking failure should not break execution
155
+ logger.warning(
156
+ f"DEBUG: Exception recording Copilot subprocess: {e}"
157
+ )
158
+ pass
159
+ else:
160
+ logger.warning(
161
+ f"DEBUG: Skipping Copilot subprocess tracking - tracker={tracker is not None}, parent_event_id={parent_event_id}"
162
+ )
163
+
164
+ result = subprocess.run(
165
+ cmd,
166
+ capture_output=True,
167
+ text=True,
168
+ timeout=timeout,
169
+ )
170
+
171
+ # Complete subprocess invocation tracking
172
+ if tracker and subprocess_event_id:
173
+ try:
174
+ tracker.complete_tool_call(
175
+ event_id=subprocess_event_id,
176
+ output_summary=result.stdout[:500] if result.stdout else "",
177
+ success=result.returncode == 0,
178
+ )
179
+ except Exception:
180
+ # Tracking failure should not break execution
181
+ pass
182
+
183
+ # Publish live event: processing
184
+ self._publish_live_event(
185
+ "spawner_phase",
186
+ "copilot",
187
+ phase="processing",
188
+ details="Parsing Copilot response",
189
+ )
190
+
191
+ # Parse output: response is before stats block
192
+ lines = result.stdout.split("\n")
193
+
194
+ # Find where stats start (look for "Total usage est:" or "Usage by model")
195
+ stats_start = len(lines)
196
+ for i, line in enumerate(lines):
197
+ if "Total usage est" in line or "Usage by model" in line:
198
+ stats_start = i
199
+ break
200
+
201
+ # Response is everything before stats
202
+ response = "\n".join(lines[:stats_start]).strip()
203
+
204
+ # Try to extract token count from stats
205
+ tokens = None
206
+ for line in lines[stats_start:]:
207
+ # Look for token counts like "25.8k input, 5 output"
208
+ if "input" in line and "output" in line:
209
+ # Simple extraction: just note we found stats
210
+ # TODO: More sophisticated parsing if needed
211
+ tokens = 0 # Placeholder
212
+ break
213
+
214
+ # Track Copilot execution if SDK available
215
+ if sdk:
216
+ tracked_events = self._parse_and_track_events(prompt, response, sdk)
217
+
218
+ # Publish live event: complete
219
+ duration = time.time() - start_time
220
+ success = result.returncode == 0
221
+ self._publish_live_event(
222
+ "spawner_complete",
223
+ "copilot",
224
+ success=success,
225
+ duration=duration,
226
+ response=response[:200] if response else None,
227
+ tokens=tokens,
228
+ error=result.stderr if not success else None,
229
+ )
230
+ return AIResult(
231
+ success=success,
232
+ response=response,
233
+ tokens_used=tokens,
234
+ error=None if success else result.stderr,
235
+ raw_output=result.stdout,
236
+ tracked_events=tracked_events,
237
+ )
238
+
239
+ except FileNotFoundError:
240
+ duration = time.time() - start_time
241
+ self._publish_live_event(
242
+ "spawner_complete",
243
+ "copilot",
244
+ success=False,
245
+ duration=duration,
246
+ error="CLI not found",
247
+ )
248
+ return AIResult(
249
+ success=False,
250
+ response="",
251
+ tokens_used=None,
252
+ error="Copilot CLI not found. Install from: https://docs.github.com/en/copilot/using-github-copilot/using-github-copilot-in-the-command-line",
253
+ raw_output=None,
254
+ tracked_events=tracked_events,
255
+ )
256
+ except subprocess.TimeoutExpired as e:
257
+ duration = time.time() - start_time
258
+ self._publish_live_event(
259
+ "spawner_complete",
260
+ "copilot",
261
+ success=False,
262
+ duration=duration,
263
+ error=f"Timed out after {timeout} seconds",
264
+ )
265
+ return AIResult(
266
+ success=False,
267
+ response="",
268
+ tokens_used=None,
269
+ error=f"Timed out after {timeout} seconds",
270
+ raw_output={
271
+ "partial_stdout": e.stdout.decode() if e.stdout else None,
272
+ "partial_stderr": e.stderr.decode() if e.stderr else None,
273
+ }
274
+ if e.stdout or e.stderr
275
+ else None,
276
+ tracked_events=tracked_events,
277
+ )
278
+ except Exception as e:
279
+ duration = time.time() - start_time
280
+ self._publish_live_event(
281
+ "spawner_complete",
282
+ "copilot",
283
+ success=False,
284
+ duration=duration,
285
+ error=str(e),
286
+ )
287
+ return AIResult(
288
+ success=False,
289
+ response="",
290
+ tokens_used=None,
291
+ error=f"Unexpected error: {type(e).__name__}: {e}",
292
+ raw_output=None,
293
+ tracked_events=tracked_events,
294
+ )