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
nc1709/mcp/server.py ADDED
@@ -0,0 +1,473 @@
1
+ """
2
+ MCP Server Implementation
3
+ Exposes NC1709 capabilities as an MCP server
4
+ """
5
+ import asyncio
6
+ import json
7
+ import sys
8
+ from typing import Dict, Any, Optional, List, Callable
9
+ from dataclasses import dataclass
10
+
11
+ from .protocol import (
12
+ MCPMessage, MCPTool, MCPResource, MCPPrompt,
13
+ MCPServerInfo, MCPErrorCode, MCPToolParameter
14
+ )
15
+
16
+
17
+ @dataclass
18
+ class ToolResult:
19
+ """Result from tool execution"""
20
+ content: List[Dict[str, Any]]
21
+ is_error: bool = False
22
+
23
+
24
+ class MCPServer:
25
+ """
26
+ MCP Server for NC1709.
27
+
28
+ Exposes NC1709's capabilities through the Model Context Protocol,
29
+ allowing external AI applications to use NC1709 as a tool provider.
30
+ """
31
+
32
+ def __init__(self, name: str = "nc1709", version: str = "1.0.0"):
33
+ """Initialize the MCP server
34
+
35
+ Args:
36
+ name: Server name
37
+ version: Server version
38
+ """
39
+ self.name = name
40
+ self.version = version
41
+ self._tools: Dict[str, MCPTool] = {}
42
+ self._resources: Dict[str, MCPResource] = {}
43
+ self._prompts: Dict[str, MCPPrompt] = {}
44
+ self._request_id = 0
45
+ self._initialized = False
46
+
47
+ @property
48
+ def server_info(self) -> MCPServerInfo:
49
+ """Get server information"""
50
+ return MCPServerInfo(
51
+ name=self.name,
52
+ version=self.version,
53
+ capabilities={
54
+ "tools": {"listChanged": True},
55
+ "resources": {"subscribe": False, "listChanged": True},
56
+ "prompts": {"listChanged": True}
57
+ }
58
+ )
59
+
60
+ def register_tool(
61
+ self,
62
+ name: str,
63
+ description: str,
64
+ handler: Callable,
65
+ parameters: Optional[List[MCPToolParameter]] = None
66
+ ) -> None:
67
+ """Register a tool with the server
68
+
69
+ Args:
70
+ name: Tool name
71
+ description: Tool description
72
+ handler: Function to handle tool calls
73
+ parameters: Tool parameters
74
+ """
75
+ tool = MCPTool(
76
+ name=name,
77
+ description=description,
78
+ parameters=parameters or [],
79
+ handler=handler
80
+ )
81
+ self._tools[name] = tool
82
+
83
+ def register_resource(
84
+ self,
85
+ uri: str,
86
+ name: str,
87
+ description: str = "",
88
+ mime_type: Optional[str] = None
89
+ ) -> None:
90
+ """Register a resource
91
+
92
+ Args:
93
+ uri: Resource URI
94
+ name: Resource name
95
+ description: Resource description
96
+ mime_type: MIME type
97
+ """
98
+ resource = MCPResource(
99
+ uri=uri,
100
+ name=name,
101
+ description=description,
102
+ mimeType=mime_type
103
+ )
104
+ self._resources[uri] = resource
105
+
106
+ def register_prompt(
107
+ self,
108
+ name: str,
109
+ description: str,
110
+ arguments: Optional[List[Dict]] = None
111
+ ) -> None:
112
+ """Register a prompt template
113
+
114
+ Args:
115
+ name: Prompt name
116
+ description: Prompt description
117
+ arguments: Prompt arguments
118
+ """
119
+ prompt = MCPPrompt(
120
+ name=name,
121
+ description=description,
122
+ arguments=arguments or []
123
+ )
124
+ self._prompts[name] = prompt
125
+
126
+ async def handle_message(self, message: MCPMessage) -> MCPMessage:
127
+ """Handle an incoming MCP message
128
+
129
+ Args:
130
+ message: Incoming message
131
+
132
+ Returns:
133
+ Response message
134
+ """
135
+ method = message.method
136
+ params = message.params or {}
137
+ msg_id = message.id
138
+
139
+ try:
140
+ if method == "initialize":
141
+ result = self._handle_initialize(params)
142
+ elif method == "tools/list":
143
+ result = self._handle_list_tools()
144
+ elif method == "tools/call":
145
+ result = await self._handle_call_tool(params)
146
+ elif method == "resources/list":
147
+ result = self._handle_list_resources()
148
+ elif method == "resources/read":
149
+ result = await self._handle_read_resource(params)
150
+ elif method == "prompts/list":
151
+ result = self._handle_list_prompts()
152
+ elif method == "prompts/get":
153
+ result = self._handle_get_prompt(params)
154
+ else:
155
+ return MCPMessage.error_response(
156
+ msg_id,
157
+ MCPErrorCode.METHOD_NOT_FOUND,
158
+ f"Unknown method: {method}"
159
+ )
160
+
161
+ return MCPMessage.response(msg_id, result)
162
+
163
+ except Exception as e:
164
+ return MCPMessage.error_response(
165
+ msg_id,
166
+ MCPErrorCode.INTERNAL_ERROR,
167
+ str(e)
168
+ )
169
+
170
+ def _handle_initialize(self, params: Dict[str, Any]) -> Dict[str, Any]:
171
+ """Handle initialization request"""
172
+ self._initialized = True
173
+ return {
174
+ "protocolVersion": "2024-11-05",
175
+ "serverInfo": self.server_info.to_dict(),
176
+ "capabilities": self.server_info.capabilities
177
+ }
178
+
179
+ def _handle_list_tools(self) -> Dict[str, Any]:
180
+ """Handle tools/list request"""
181
+ return {
182
+ "tools": [tool.to_dict() for tool in self._tools.values()]
183
+ }
184
+
185
+ async def _handle_call_tool(self, params: Dict[str, Any]) -> Dict[str, Any]:
186
+ """Handle tools/call request"""
187
+ tool_name = params.get("name")
188
+ arguments = params.get("arguments", {})
189
+
190
+ if tool_name not in self._tools:
191
+ raise ValueError(f"Tool not found: {tool_name}")
192
+
193
+ tool = self._tools[tool_name]
194
+
195
+ if tool.handler is None:
196
+ raise ValueError(f"Tool {tool_name} has no handler")
197
+
198
+ # Call the handler
199
+ if asyncio.iscoroutinefunction(tool.handler):
200
+ result = await tool.handler(**arguments)
201
+ else:
202
+ result = tool.handler(**arguments)
203
+
204
+ # Format result
205
+ if isinstance(result, ToolResult):
206
+ return {
207
+ "content": result.content,
208
+ "isError": result.is_error
209
+ }
210
+ elif isinstance(result, str):
211
+ return {
212
+ "content": [{"type": "text", "text": result}],
213
+ "isError": False
214
+ }
215
+ elif isinstance(result, dict):
216
+ return {
217
+ "content": [{"type": "text", "text": json.dumps(result, indent=2)}],
218
+ "isError": False
219
+ }
220
+ else:
221
+ return {
222
+ "content": [{"type": "text", "text": str(result)}],
223
+ "isError": False
224
+ }
225
+
226
+ def _handle_list_resources(self) -> Dict[str, Any]:
227
+ """Handle resources/list request"""
228
+ return {
229
+ "resources": [res.to_dict() for res in self._resources.values()]
230
+ }
231
+
232
+ async def _handle_read_resource(self, params: Dict[str, Any]) -> Dict[str, Any]:
233
+ """Handle resources/read request"""
234
+ uri = params.get("uri")
235
+
236
+ if uri not in self._resources:
237
+ raise ValueError(f"Resource not found: {uri}")
238
+
239
+ # Read resource content based on URI scheme
240
+ resource = self._resources[uri]
241
+
242
+ if uri.startswith("file://"):
243
+ file_path = uri[7:]
244
+ try:
245
+ with open(file_path, 'r') as f:
246
+ content = f.read()
247
+ return {
248
+ "contents": [{
249
+ "uri": uri,
250
+ "mimeType": resource.mimeType or "text/plain",
251
+ "text": content
252
+ }]
253
+ }
254
+ except Exception as e:
255
+ raise ValueError(f"Could not read file: {e}")
256
+
257
+ raise ValueError(f"Unsupported URI scheme: {uri}")
258
+
259
+ def _handle_list_prompts(self) -> Dict[str, Any]:
260
+ """Handle prompts/list request"""
261
+ return {
262
+ "prompts": [prompt.to_dict() for prompt in self._prompts.values()]
263
+ }
264
+
265
+ def _handle_get_prompt(self, params: Dict[str, Any]) -> Dict[str, Any]:
266
+ """Handle prompts/get request"""
267
+ name = params.get("name")
268
+ arguments = params.get("arguments", {})
269
+
270
+ if name not in self._prompts:
271
+ raise ValueError(f"Prompt not found: {name}")
272
+
273
+ prompt = self._prompts[name]
274
+
275
+ # Generate prompt messages based on template
276
+ # This is a simple implementation - could be enhanced
277
+ return {
278
+ "description": prompt.description,
279
+ "messages": [{
280
+ "role": "user",
281
+ "content": {
282
+ "type": "text",
283
+ "text": f"Prompt: {name}"
284
+ }
285
+ }]
286
+ }
287
+
288
+ async def run_stdio(self) -> None:
289
+ """Run the server using stdio transport"""
290
+ reader = asyncio.StreamReader()
291
+ protocol = asyncio.StreamReaderProtocol(reader)
292
+
293
+ await asyncio.get_event_loop().connect_read_pipe(
294
+ lambda: protocol, sys.stdin
295
+ )
296
+
297
+ writer_transport, writer_protocol = await asyncio.get_event_loop().connect_write_pipe(
298
+ asyncio.streams.FlowControlMixin, sys.stdout
299
+ )
300
+ writer = asyncio.StreamWriter(
301
+ writer_transport, writer_protocol, reader, asyncio.get_event_loop()
302
+ )
303
+
304
+ while True:
305
+ try:
306
+ line = await reader.readline()
307
+ if not line:
308
+ break
309
+
310
+ message = MCPMessage.from_json(line.decode())
311
+ response = await self.handle_message(message)
312
+
313
+ writer.write((response.to_json() + "\n").encode())
314
+ await writer.drain()
315
+
316
+ except Exception as e:
317
+ error_response = MCPMessage.error_response(
318
+ None,
319
+ MCPErrorCode.PARSE_ERROR,
320
+ str(e)
321
+ )
322
+ writer.write((error_response.to_json() + "\n").encode())
323
+ await writer.drain()
324
+
325
+ def create_default_tools(self) -> None:
326
+ """Register default NC1709 tools"""
327
+
328
+ # File read tool
329
+ self.register_tool(
330
+ name="read_file",
331
+ description="Read contents of a file",
332
+ handler=self._tool_read_file,
333
+ parameters=[
334
+ MCPToolParameter(
335
+ name="path",
336
+ type="string",
337
+ description="Path to the file to read",
338
+ required=True
339
+ )
340
+ ]
341
+ )
342
+
343
+ # File write tool
344
+ self.register_tool(
345
+ name="write_file",
346
+ description="Write contents to a file",
347
+ handler=self._tool_write_file,
348
+ parameters=[
349
+ MCPToolParameter(
350
+ name="path",
351
+ type="string",
352
+ description="Path to the file to write",
353
+ required=True
354
+ ),
355
+ MCPToolParameter(
356
+ name="content",
357
+ type="string",
358
+ description="Content to write",
359
+ required=True
360
+ )
361
+ ]
362
+ )
363
+
364
+ # Execute command tool
365
+ self.register_tool(
366
+ name="execute_command",
367
+ description="Execute a shell command",
368
+ handler=self._tool_execute_command,
369
+ parameters=[
370
+ MCPToolParameter(
371
+ name="command",
372
+ type="string",
373
+ description="Command to execute",
374
+ required=True
375
+ )
376
+ ]
377
+ )
378
+
379
+ # Search code tool
380
+ self.register_tool(
381
+ name="search_code",
382
+ description="Search for code patterns in the project",
383
+ handler=self._tool_search_code,
384
+ parameters=[
385
+ MCPToolParameter(
386
+ name="query",
387
+ type="string",
388
+ description="Search query",
389
+ required=True
390
+ ),
391
+ MCPToolParameter(
392
+ name="file_pattern",
393
+ type="string",
394
+ description="File pattern to search (e.g., *.py)",
395
+ required=False
396
+ )
397
+ ]
398
+ )
399
+
400
+ async def _tool_read_file(self, path: str) -> str:
401
+ """Read file contents"""
402
+ try:
403
+ with open(path, 'r') as f:
404
+ return f.read()
405
+ except Exception as e:
406
+ return ToolResult(
407
+ content=[{"type": "text", "text": f"Error reading file: {e}"}],
408
+ is_error=True
409
+ )
410
+
411
+ async def _tool_write_file(self, path: str, content: str) -> str:
412
+ """Write file contents"""
413
+ try:
414
+ with open(path, 'w') as f:
415
+ f.write(content)
416
+ return f"Successfully wrote to {path}"
417
+ except Exception as e:
418
+ return ToolResult(
419
+ content=[{"type": "text", "text": f"Error writing file: {e}"}],
420
+ is_error=True
421
+ )
422
+
423
+ async def _tool_execute_command(self, command: str) -> str:
424
+ """Execute a command"""
425
+ import subprocess
426
+
427
+ # Security check - block dangerous commands
428
+ dangerous = ["rm -rf", "sudo", "mkfs", "dd if=", "> /dev/"]
429
+ for d in dangerous:
430
+ if d in command:
431
+ return ToolResult(
432
+ content=[{"type": "text", "text": f"Command blocked for safety: contains '{d}'"}],
433
+ is_error=True
434
+ )
435
+
436
+ try:
437
+ result = subprocess.run(
438
+ command,
439
+ shell=True,
440
+ capture_output=True,
441
+ text=True,
442
+ timeout=30
443
+ )
444
+ output = result.stdout + result.stderr
445
+ return output if output else "Command completed with no output"
446
+ except subprocess.TimeoutExpired:
447
+ return ToolResult(
448
+ content=[{"type": "text", "text": "Command timed out"}],
449
+ is_error=True
450
+ )
451
+ except Exception as e:
452
+ return ToolResult(
453
+ content=[{"type": "text", "text": f"Error executing command: {e}"}],
454
+ is_error=True
455
+ )
456
+
457
+ async def _tool_search_code(self, query: str, file_pattern: str = "*") -> str:
458
+ """Search for code"""
459
+ import subprocess
460
+
461
+ try:
462
+ # Use grep for searching
463
+ cmd = f"grep -r -n '{query}' --include='{file_pattern}' ."
464
+ result = subprocess.run(
465
+ cmd,
466
+ shell=True,
467
+ capture_output=True,
468
+ text=True,
469
+ timeout=30
470
+ )
471
+ return result.stdout if result.stdout else "No matches found"
472
+ except Exception as e:
473
+ return f"Search error: {e}"
@@ -0,0 +1,20 @@
1
+ """
2
+ NC1709 Memory Module
3
+ Provides long-term memory and semantic search capabilities using vector databases
4
+ """
5
+
6
+ from .vector_store import VectorStore, MemoryEntry
7
+ from .embeddings import EmbeddingEngine, CodeChunker
8
+ from .indexer import ProjectIndexer
9
+ from .sessions import SessionManager, Session, Message
10
+
11
+ __all__ = [
12
+ "VectorStore",
13
+ "MemoryEntry",
14
+ "EmbeddingEngine",
15
+ "CodeChunker",
16
+ "ProjectIndexer",
17
+ "SessionManager",
18
+ "Session",
19
+ "Message"
20
+ ]