nc1709 1.15.4__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 (86) hide show
  1. nc1709/__init__.py +13 -0
  2. nc1709/agent/__init__.py +36 -0
  3. nc1709/agent/core.py +505 -0
  4. nc1709/agent/mcp_bridge.py +245 -0
  5. nc1709/agent/permissions.py +298 -0
  6. nc1709/agent/tools/__init__.py +21 -0
  7. nc1709/agent/tools/base.py +440 -0
  8. nc1709/agent/tools/bash_tool.py +367 -0
  9. nc1709/agent/tools/file_tools.py +454 -0
  10. nc1709/agent/tools/notebook_tools.py +516 -0
  11. nc1709/agent/tools/search_tools.py +322 -0
  12. nc1709/agent/tools/task_tool.py +284 -0
  13. nc1709/agent/tools/web_tools.py +555 -0
  14. nc1709/agents/__init__.py +17 -0
  15. nc1709/agents/auto_fix.py +506 -0
  16. nc1709/agents/test_generator.py +507 -0
  17. nc1709/checkpoints.py +372 -0
  18. nc1709/cli.py +3380 -0
  19. nc1709/cli_ui.py +1080 -0
  20. nc1709/cognitive/__init__.py +149 -0
  21. nc1709/cognitive/anticipation.py +594 -0
  22. nc1709/cognitive/context_engine.py +1046 -0
  23. nc1709/cognitive/council.py +824 -0
  24. nc1709/cognitive/learning.py +761 -0
  25. nc1709/cognitive/router.py +583 -0
  26. nc1709/cognitive/system.py +519 -0
  27. nc1709/config.py +155 -0
  28. nc1709/custom_commands.py +300 -0
  29. nc1709/executor.py +333 -0
  30. nc1709/file_controller.py +354 -0
  31. nc1709/git_integration.py +308 -0
  32. nc1709/github_integration.py +477 -0
  33. nc1709/image_input.py +446 -0
  34. nc1709/linting.py +519 -0
  35. nc1709/llm_adapter.py +667 -0
  36. nc1709/logger.py +192 -0
  37. nc1709/mcp/__init__.py +18 -0
  38. nc1709/mcp/client.py +370 -0
  39. nc1709/mcp/manager.py +407 -0
  40. nc1709/mcp/protocol.py +210 -0
  41. nc1709/mcp/server.py +473 -0
  42. nc1709/memory/__init__.py +20 -0
  43. nc1709/memory/embeddings.py +325 -0
  44. nc1709/memory/indexer.py +474 -0
  45. nc1709/memory/sessions.py +432 -0
  46. nc1709/memory/vector_store.py +451 -0
  47. nc1709/models/__init__.py +86 -0
  48. nc1709/models/detector.py +377 -0
  49. nc1709/models/formats.py +315 -0
  50. nc1709/models/manager.py +438 -0
  51. nc1709/models/registry.py +497 -0
  52. nc1709/performance/__init__.py +343 -0
  53. nc1709/performance/cache.py +705 -0
  54. nc1709/performance/pipeline.py +611 -0
  55. nc1709/performance/tiering.py +543 -0
  56. nc1709/plan_mode.py +362 -0
  57. nc1709/plugins/__init__.py +17 -0
  58. nc1709/plugins/agents/__init__.py +18 -0
  59. nc1709/plugins/agents/django_agent.py +912 -0
  60. nc1709/plugins/agents/docker_agent.py +623 -0
  61. nc1709/plugins/agents/fastapi_agent.py +887 -0
  62. nc1709/plugins/agents/git_agent.py +731 -0
  63. nc1709/plugins/agents/nextjs_agent.py +867 -0
  64. nc1709/plugins/base.py +359 -0
  65. nc1709/plugins/manager.py +411 -0
  66. nc1709/plugins/registry.py +337 -0
  67. nc1709/progress.py +443 -0
  68. nc1709/prompts/__init__.py +22 -0
  69. nc1709/prompts/agent_system.py +180 -0
  70. nc1709/prompts/task_prompts.py +340 -0
  71. nc1709/prompts/unified_prompt.py +133 -0
  72. nc1709/reasoning_engine.py +541 -0
  73. nc1709/remote_client.py +266 -0
  74. nc1709/shell_completions.py +349 -0
  75. nc1709/slash_commands.py +649 -0
  76. nc1709/task_classifier.py +408 -0
  77. nc1709/version_check.py +177 -0
  78. nc1709/web/__init__.py +8 -0
  79. nc1709/web/server.py +950 -0
  80. nc1709/web/templates/index.html +1127 -0
  81. nc1709-1.15.4.dist-info/METADATA +858 -0
  82. nc1709-1.15.4.dist-info/RECORD +86 -0
  83. nc1709-1.15.4.dist-info/WHEEL +5 -0
  84. nc1709-1.15.4.dist-info/entry_points.txt +2 -0
  85. nc1709-1.15.4.dist-info/licenses/LICENSE +9 -0
  86. nc1709-1.15.4.dist-info/top_level.txt +1 -0
@@ -0,0 +1,337 @@
1
+ """
2
+ Plugin Registry for NC1709
3
+ Discovers and catalogs available plugins
4
+ """
5
+ import importlib
6
+ import importlib.util
7
+ import sys
8
+ from pathlib import Path
9
+ from typing import Dict, List, Optional, Type, Set
10
+ from dataclasses import dataclass, field
11
+
12
+ from .base import Plugin, PluginMetadata, PluginCapability
13
+
14
+
15
+ @dataclass
16
+ class PluginInfo:
17
+ """Information about a registered plugin"""
18
+ plugin_class: Type[Plugin]
19
+ metadata: PluginMetadata
20
+ module_path: str
21
+ is_builtin: bool = False
22
+
23
+
24
+ class PluginRegistry:
25
+ """
26
+ Registry for discovering and cataloging plugins.
27
+
28
+ Handles plugin discovery from:
29
+ - Built-in plugins (nc1709/plugins/agents/)
30
+ - User plugins (~/.nc1709/plugins/)
31
+ - Project plugins (.nc1709/plugins/)
32
+ """
33
+
34
+ def __init__(self):
35
+ """Initialize the registry"""
36
+ self._plugins: Dict[str, PluginInfo] = {}
37
+ self._discovery_paths: List[Path] = []
38
+ self._capabilities_index: Dict[PluginCapability, Set[str]] = {}
39
+
40
+ @property
41
+ def plugins(self) -> Dict[str, PluginInfo]:
42
+ """Get all registered plugins"""
43
+ return self._plugins.copy()
44
+
45
+ def register(
46
+ self,
47
+ plugin_class: Type[Plugin],
48
+ module_path: str = "",
49
+ is_builtin: bool = False
50
+ ) -> bool:
51
+ """Register a plugin class
52
+
53
+ Args:
54
+ plugin_class: The Plugin class to register
55
+ module_path: Path to the module file
56
+ is_builtin: Whether this is a built-in plugin
57
+
58
+ Returns:
59
+ True if registered successfully
60
+ """
61
+ try:
62
+ # Create temporary instance to get metadata
63
+ temp_instance = plugin_class.__new__(plugin_class)
64
+ Plugin.__init__(temp_instance, {})
65
+
66
+ # Get metadata (may need to handle abstract property)
67
+ if hasattr(plugin_class, 'METADATA'):
68
+ metadata = plugin_class.METADATA
69
+ else:
70
+ metadata = temp_instance.metadata
71
+
72
+ plugin_name = metadata.name
73
+
74
+ # Check for duplicates
75
+ if plugin_name in self._plugins:
76
+ existing = self._plugins[plugin_name]
77
+ # Allow override only if existing is not builtin
78
+ if existing.is_builtin and not is_builtin:
79
+ return False
80
+
81
+ # Register plugin
82
+ self._plugins[plugin_name] = PluginInfo(
83
+ plugin_class=plugin_class,
84
+ metadata=metadata,
85
+ module_path=module_path,
86
+ is_builtin=is_builtin
87
+ )
88
+
89
+ # Index by capabilities
90
+ for capability in metadata.capabilities:
91
+ if capability not in self._capabilities_index:
92
+ self._capabilities_index[capability] = set()
93
+ self._capabilities_index[capability].add(plugin_name)
94
+
95
+ return True
96
+
97
+ except Exception as e:
98
+ print(f"Failed to register plugin {plugin_class}: {e}")
99
+ return False
100
+
101
+ def unregister(self, plugin_name: str) -> bool:
102
+ """Unregister a plugin
103
+
104
+ Args:
105
+ plugin_name: Name of plugin to unregister
106
+
107
+ Returns:
108
+ True if unregistered
109
+ """
110
+ if plugin_name not in self._plugins:
111
+ return False
112
+
113
+ info = self._plugins[plugin_name]
114
+
115
+ # Remove from capabilities index
116
+ for capability in info.metadata.capabilities:
117
+ if capability in self._capabilities_index:
118
+ self._capabilities_index[capability].discard(plugin_name)
119
+
120
+ del self._plugins[plugin_name]
121
+ return True
122
+
123
+ def get(self, plugin_name: str) -> Optional[PluginInfo]:
124
+ """Get plugin info by name
125
+
126
+ Args:
127
+ plugin_name: Plugin name
128
+
129
+ Returns:
130
+ PluginInfo or None
131
+ """
132
+ return self._plugins.get(plugin_name)
133
+
134
+ def find_by_capability(self, capability: PluginCapability) -> List[PluginInfo]:
135
+ """Find plugins with a specific capability
136
+
137
+ Args:
138
+ capability: The capability to search for
139
+
140
+ Returns:
141
+ List of matching PluginInfo
142
+ """
143
+ plugin_names = self._capabilities_index.get(capability, set())
144
+ return [self._plugins[name] for name in plugin_names if name in self._plugins]
145
+
146
+ def find_by_keyword(self, keyword: str) -> List[PluginInfo]:
147
+ """Find plugins matching a keyword
148
+
149
+ Args:
150
+ keyword: Keyword to search
151
+
152
+ Returns:
153
+ List of matching PluginInfo
154
+ """
155
+ keyword_lower = keyword.lower()
156
+ results = []
157
+
158
+ for info in self._plugins.values():
159
+ # Check name
160
+ if keyword_lower in info.metadata.name.lower():
161
+ results.append(info)
162
+ continue
163
+
164
+ # Check description
165
+ if keyword_lower in info.metadata.description.lower():
166
+ results.append(info)
167
+ continue
168
+
169
+ # Check keywords
170
+ if any(keyword_lower in kw.lower() for kw in info.metadata.keywords):
171
+ results.append(info)
172
+
173
+ return results
174
+
175
+ def add_discovery_path(self, path: Path) -> None:
176
+ """Add a path for plugin discovery
177
+
178
+ Args:
179
+ path: Directory containing plugins
180
+ """
181
+ if path.is_dir() and path not in self._discovery_paths:
182
+ self._discovery_paths.append(path)
183
+
184
+ def discover(self, include_user: bool = True, include_project: bool = True) -> int:
185
+ """Discover and register plugins from configured paths
186
+
187
+ Args:
188
+ include_user: Include user plugins (~/.nc1709/plugins)
189
+ include_project: Include project plugins (.nc1709/plugins)
190
+
191
+ Returns:
192
+ Number of plugins discovered
193
+ """
194
+ count = 0
195
+
196
+ # Built-in plugins
197
+ builtin_path = Path(__file__).parent / "agents"
198
+ if builtin_path.is_dir():
199
+ count += self._discover_from_path(builtin_path, is_builtin=True)
200
+
201
+ # User plugins
202
+ if include_user:
203
+ user_path = Path.home() / ".nc1709" / "plugins"
204
+ if user_path.is_dir():
205
+ count += self._discover_from_path(user_path, is_builtin=False)
206
+
207
+ # Project plugins
208
+ if include_project:
209
+ project_path = Path.cwd() / ".nc1709" / "plugins"
210
+ if project_path.is_dir():
211
+ count += self._discover_from_path(project_path, is_builtin=False)
212
+
213
+ # Custom discovery paths
214
+ for path in self._discovery_paths:
215
+ count += self._discover_from_path(path, is_builtin=False)
216
+
217
+ return count
218
+
219
+ def _discover_from_path(self, path: Path, is_builtin: bool = False) -> int:
220
+ """Discover plugins from a directory
221
+
222
+ Args:
223
+ path: Directory to scan
224
+ is_builtin: Whether these are built-in plugins
225
+
226
+ Returns:
227
+ Number of plugins discovered
228
+ """
229
+ count = 0
230
+
231
+ for file_path in path.glob("*.py"):
232
+ if file_path.name.startswith("_"):
233
+ continue
234
+
235
+ try:
236
+ plugin_class = self._load_plugin_from_file(file_path)
237
+ if plugin_class:
238
+ if self.register(plugin_class, str(file_path), is_builtin):
239
+ count += 1
240
+ except Exception as e:
241
+ print(f"Error loading plugin from {file_path}: {e}")
242
+
243
+ return count
244
+
245
+ def _load_plugin_from_file(self, file_path: Path) -> Optional[Type[Plugin]]:
246
+ """Load a plugin class from a Python file
247
+
248
+ Args:
249
+ file_path: Path to the .py file
250
+
251
+ Returns:
252
+ Plugin class or None
253
+ """
254
+ module_name = f"nc1709_plugin_{file_path.stem}"
255
+
256
+ spec = importlib.util.spec_from_file_location(module_name, file_path)
257
+ if spec is None or spec.loader is None:
258
+ return None
259
+
260
+ module = importlib.util.module_from_spec(spec)
261
+ sys.modules[module_name] = module
262
+
263
+ try:
264
+ spec.loader.exec_module(module)
265
+ except Exception as e:
266
+ del sys.modules[module_name]
267
+ raise e
268
+
269
+ # Find Plugin subclass in module
270
+ for attr_name in dir(module):
271
+ attr = getattr(module, attr_name)
272
+ if (
273
+ isinstance(attr, type) and
274
+ issubclass(attr, Plugin) and
275
+ attr is not Plugin and
276
+ not attr.__name__.startswith("_")
277
+ ):
278
+ return attr
279
+
280
+ return None
281
+
282
+ def list_all(self) -> List[Dict]:
283
+ """List all registered plugins
284
+
285
+ Returns:
286
+ List of plugin summaries
287
+ """
288
+ return [
289
+ {
290
+ "name": info.metadata.name,
291
+ "version": info.metadata.version,
292
+ "description": info.metadata.description,
293
+ "capabilities": [c.value for c in info.metadata.capabilities],
294
+ "builtin": info.is_builtin
295
+ }
296
+ for info in self._plugins.values()
297
+ ]
298
+
299
+ def get_dependencies(self, plugin_name: str) -> List[str]:
300
+ """Get plugin dependencies
301
+
302
+ Args:
303
+ plugin_name: Plugin name
304
+
305
+ Returns:
306
+ List of dependency plugin names
307
+ """
308
+ info = self._plugins.get(plugin_name)
309
+ if info:
310
+ return info.metadata.dependencies.copy()
311
+ return []
312
+
313
+ def resolve_dependencies(self, plugin_name: str) -> List[str]:
314
+ """Resolve plugin dependencies in load order
315
+
316
+ Args:
317
+ plugin_name: Plugin name
318
+
319
+ Returns:
320
+ List of plugins in order they should be loaded
321
+ """
322
+ resolved = []
323
+ seen = set()
324
+
325
+ def resolve(name: str):
326
+ if name in seen:
327
+ return
328
+ seen.add(name)
329
+
330
+ deps = self.get_dependencies(name)
331
+ for dep in deps:
332
+ resolve(dep)
333
+
334
+ resolved.append(name)
335
+
336
+ resolve(plugin_name)
337
+ return resolved