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,266 @@
1
+ """
2
+ NC1709 Remote Client
3
+ Connects to a remote NC1709 server for LLM access
4
+ """
5
+ import os
6
+ import json
7
+ from typing import Optional, Dict, Any
8
+ from urllib.request import Request, urlopen
9
+ from urllib.error import URLError, HTTPError
10
+
11
+
12
+ class RemoteClient:
13
+ """Client for connecting to remote NC1709 server"""
14
+
15
+ def __init__(
16
+ self,
17
+ server_url: Optional[str] = None,
18
+ api_key: Optional[str] = None
19
+ ):
20
+ """Initialize remote client
21
+
22
+ Args:
23
+ server_url: URL of the NC1709 server (or set NC1709_API_URL env var)
24
+ api_key: API key for authentication (or set NC1709_API_KEY env var)
25
+ """
26
+ self.server_url = (
27
+ server_url or
28
+ os.environ.get("NC1709_API_URL") or
29
+ os.environ.get("NC1709_SERVER_URL")
30
+ )
31
+ self.api_key = (
32
+ api_key or
33
+ os.environ.get("NC1709_API_KEY")
34
+ )
35
+
36
+ if not self.server_url:
37
+ raise ValueError(
38
+ "No server URL provided. Set NC1709_API_URL environment variable "
39
+ "or pass server_url parameter."
40
+ )
41
+
42
+ # Normalize URL
43
+ self.server_url = self.server_url.rstrip("/")
44
+
45
+ def _make_request(
46
+ self,
47
+ endpoint: str,
48
+ method: str = "GET",
49
+ data: Optional[Dict] = None
50
+ ) -> Dict[str, Any]:
51
+ """Make HTTP request to server
52
+
53
+ Args:
54
+ endpoint: API endpoint (e.g., "/api/remote/status")
55
+ method: HTTP method
56
+ data: JSON data for POST requests
57
+
58
+ Returns:
59
+ Response JSON
60
+ """
61
+ url = f"{self.server_url}{endpoint}"
62
+
63
+ headers = {
64
+ "Content-Type": "application/json",
65
+ "User-Agent": "nc1709-client/1.4.0"
66
+ }
67
+
68
+ if self.api_key:
69
+ headers["X-API-Key"] = self.api_key
70
+
71
+ body = json.dumps(data).encode("utf-8") if data else None
72
+
73
+ req = Request(url, data=body, headers=headers, method=method)
74
+
75
+ try:
76
+ with urlopen(req, timeout=120) as response:
77
+ return json.loads(response.read().decode("utf-8"))
78
+ except HTTPError as e:
79
+ error_body = e.read().decode("utf-8")
80
+ try:
81
+ error_json = json.loads(error_body)
82
+ detail = error_json.get("detail", error_body)
83
+ except json.JSONDecodeError:
84
+ detail = error_body
85
+
86
+ if e.code == 401:
87
+ raise ConnectionError(
88
+ f"Authentication failed: {detail}\n"
89
+ "Set NC1709_API_KEY environment variable with your API key."
90
+ )
91
+ raise ConnectionError(f"Server error ({e.code}): {detail}")
92
+ except URLError as e:
93
+ raise ConnectionError(
94
+ f"Cannot connect to NC1709 server at {self.server_url}\n"
95
+ f"Error: {e.reason}\n"
96
+ "Make sure the server is running and accessible."
97
+ )
98
+
99
+ def check_status(self) -> Dict[str, Any]:
100
+ """Check server status
101
+
102
+ Returns:
103
+ Server status information
104
+ """
105
+ return self._make_request("/api/remote/status")
106
+
107
+ def complete(
108
+ self,
109
+ prompt: str,
110
+ task_type: str = "general",
111
+ system_prompt: Optional[str] = None,
112
+ temperature: float = 0.7,
113
+ max_tokens: Optional[int] = None
114
+ ) -> str:
115
+ """Get LLM completion from remote server
116
+
117
+ Args:
118
+ prompt: User prompt
119
+ task_type: Task type (reasoning, coding, tools, general, fast)
120
+ system_prompt: Optional system prompt
121
+ temperature: Sampling temperature
122
+ max_tokens: Maximum tokens
123
+
124
+ Returns:
125
+ LLM response text
126
+ """
127
+ data = {
128
+ "prompt": prompt,
129
+ "task_type": task_type,
130
+ "temperature": temperature
131
+ }
132
+
133
+ if system_prompt:
134
+ data["system_prompt"] = system_prompt
135
+ if max_tokens:
136
+ data["max_tokens"] = max_tokens
137
+
138
+ result = self._make_request("/api/remote/complete", method="POST", data=data)
139
+ return result.get("response", "")
140
+
141
+ def chat(self, message: str) -> str:
142
+ """Send chat message to remote server (uses full reasoning engine)
143
+
144
+ Args:
145
+ message: User message
146
+
147
+ Returns:
148
+ Assistant response
149
+ """
150
+ data = {"message": message}
151
+ result = self._make_request("/api/remote/chat", method="POST", data=data)
152
+ return result.get("response", "")
153
+
154
+ def agent_chat(
155
+ self,
156
+ messages: list,
157
+ cwd: str,
158
+ tools: list = None
159
+ ) -> Dict[str, Any]:
160
+ """Send agent chat request - returns LLM response for local tool execution
161
+
162
+ This is the new architecture where:
163
+ - Server only runs LLM (thinking)
164
+ - Client executes tools locally
165
+
166
+ Args:
167
+ messages: Conversation history [{"role": "user/assistant", "content": "..."}]
168
+ cwd: Client's current working directory
169
+ tools: List of available tools on client
170
+
171
+ Returns:
172
+ Dict with 'response' (LLM output that may contain tool calls)
173
+ """
174
+ data = {
175
+ "messages": messages,
176
+ "cwd": cwd,
177
+ "tools": tools or []
178
+ }
179
+ return self._make_request("/api/remote/agent", method="POST", data=data)
180
+
181
+ def is_connected(self) -> bool:
182
+ """Check if connected to server
183
+
184
+ Returns:
185
+ True if server is reachable
186
+ """
187
+ try:
188
+ status = self.check_status()
189
+ return status.get("status") == "ok"
190
+ except Exception:
191
+ return False
192
+
193
+ def index_code(
194
+ self,
195
+ user_id: str,
196
+ files: list,
197
+ project_name: str = None
198
+ ) -> Dict[str, Any]:
199
+ """Index code files on the server's vector database
200
+
201
+ Args:
202
+ user_id: Unique user/session identifier
203
+ files: List of {"path": "...", "content": "...", "language": "..."}
204
+ project_name: Optional project name for grouping
205
+
206
+ Returns:
207
+ Indexing result with stats
208
+ """
209
+ data = {
210
+ "user_id": user_id,
211
+ "files": files,
212
+ "project_name": project_name
213
+ }
214
+ return self._make_request("/api/remote/index", method="POST", data=data)
215
+
216
+ def search_code(
217
+ self,
218
+ user_id: str,
219
+ query: str,
220
+ n_results: int = 5,
221
+ project_name: str = None
222
+ ) -> Dict[str, Any]:
223
+ """Search indexed code on the server
224
+
225
+ Args:
226
+ user_id: User identifier
227
+ query: Search query
228
+ n_results: Number of results to return
229
+ project_name: Optional project filter
230
+
231
+ Returns:
232
+ Search results
233
+ """
234
+ data = {
235
+ "user_id": user_id,
236
+ "query": query,
237
+ "n_results": n_results,
238
+ "project_name": project_name
239
+ }
240
+ return self._make_request("/api/remote/search", method="POST", data=data)
241
+
242
+
243
+ def get_remote_client() -> Optional[RemoteClient]:
244
+ """Get remote client if configured
245
+
246
+ Returns:
247
+ RemoteClient instance if NC1709_API_URL is set, None otherwise
248
+ """
249
+ if os.environ.get("NC1709_API_URL") or os.environ.get("NC1709_SERVER_URL"):
250
+ try:
251
+ return RemoteClient()
252
+ except ValueError:
253
+ return None
254
+ return None
255
+
256
+
257
+ def is_remote_mode() -> bool:
258
+ """Check if running in remote mode
259
+
260
+ Returns:
261
+ True if NC1709_API_URL is set
262
+ """
263
+ return bool(
264
+ os.environ.get("NC1709_API_URL") or
265
+ os.environ.get("NC1709_SERVER_URL")
266
+ )
@@ -0,0 +1,349 @@
1
+ """
2
+ Shell Completions Generator
3
+ Generates completion scripts for bash, zsh, and fish shells
4
+ """
5
+ import os
6
+ from typing import Optional
7
+
8
+
9
+ # Bash completion script
10
+ BASH_COMPLETION = '''
11
+ # NC1709 Bash Completion
12
+ # Add to ~/.bashrc or ~/.bash_profile:
13
+ # source <(nc1709 --completion bash)
14
+ # or: eval "$(nc1709 --completion bash)"
15
+
16
+ _nc1709_completions() {
17
+ local cur prev opts
18
+ COMPREPLY=()
19
+ cur="${COMP_WORDS[COMP_CWORD]}"
20
+ prev="${COMP_WORDS[COMP_CWORD-1]}"
21
+
22
+ # Main options
23
+ opts="--help --version --web --shell --config --resume --remote --api-key --serve --port --plugins --plugin --completion --mcp-serve"
24
+
25
+ # Shell commands (when in interactive mode)
26
+ shell_commands="help exit quit clear history config sessions index search plugins git docker mcp"
27
+
28
+ # Plugin commands
29
+ plugin_opts="git:status git:diff git:log git:branch git:commit git:push git:pull docker:ps docker:images docker:logs docker:compose_up docker:compose_down fastapi:scaffold nextjs:scaffold django:scaffold"
30
+
31
+ case "${prev}" in
32
+ --plugin)
33
+ COMPREPLY=( $(compgen -W "${plugin_opts}" -- ${cur}) )
34
+ return 0
35
+ ;;
36
+ --completion)
37
+ COMPREPLY=( $(compgen -W "bash zsh fish" -- ${cur}) )
38
+ return 0
39
+ ;;
40
+ --port)
41
+ COMPREPLY=()
42
+ return 0
43
+ ;;
44
+ --remote|--api-key)
45
+ COMPREPLY=()
46
+ return 0
47
+ ;;
48
+ --resume)
49
+ # Could add session completion here
50
+ COMPREPLY=()
51
+ return 0
52
+ ;;
53
+ esac
54
+
55
+ # Complete options or files
56
+ if [[ ${cur} == -* ]]; then
57
+ COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
58
+ else
59
+ # Complete files for potential file paths
60
+ COMPREPLY=( $(compgen -f -- ${cur}) )
61
+ fi
62
+
63
+ return 0
64
+ }
65
+
66
+ complete -F _nc1709_completions nc1709
67
+ '''
68
+
69
+
70
+ # Zsh completion script
71
+ ZSH_COMPLETION = '''
72
+ #compdef nc1709
73
+
74
+ # NC1709 Zsh Completion
75
+ # Add to ~/.zshrc:
76
+ # source <(nc1709 --completion zsh)
77
+ # or: eval "$(nc1709 --completion zsh)"
78
+ # or save to ~/.zsh/completions/_nc1709
79
+
80
+ _nc1709() {
81
+ local -a commands
82
+ local -a options
83
+ local -a plugins
84
+
85
+ options=(
86
+ '--help[Show help message]'
87
+ '--version[Show version]'
88
+ '--web[Start web dashboard]'
89
+ '--shell[Start interactive shell]'
90
+ '--config[Show configuration]'
91
+ '--resume[Resume session]:session_id:'
92
+ '--remote[Remote server URL]:url:'
93
+ '--api-key[API key for remote server]:key:'
94
+ '--serve[Enable remote access]'
95
+ '--port[Server port]:port:'
96
+ '--plugins[List available plugins]'
97
+ '--plugin[Run a plugin]:plugin:->plugins'
98
+ '--completion[Generate shell completion]:shell:(bash zsh fish)'
99
+ '--mcp-serve[Start MCP server]'
100
+ )
101
+
102
+ plugins=(
103
+ 'git\\:status:Show git status'
104
+ 'git\\:diff:Show git diff'
105
+ 'git\\:log:Show git log'
106
+ 'git\\:branch:List branches'
107
+ 'git\\:commit:Create commit'
108
+ 'git\\:push:Push to remote'
109
+ 'git\\:pull:Pull from remote'
110
+ 'docker\\:ps:List containers'
111
+ 'docker\\:images:List images'
112
+ 'docker\\:logs:View logs'
113
+ 'docker\\:compose_up:Start compose'
114
+ 'docker\\:compose_down:Stop compose'
115
+ 'fastapi\\:scaffold:Create FastAPI project'
116
+ 'nextjs\\:scaffold:Create Next.js project'
117
+ 'django\\:scaffold:Create Django project'
118
+ )
119
+
120
+ case $state in
121
+ plugins)
122
+ _describe 'plugin' plugins
123
+ ;;
124
+ *)
125
+ _arguments -s $options
126
+ ;;
127
+ esac
128
+ }
129
+
130
+ _nc1709 "$@"
131
+ '''
132
+
133
+
134
+ # Fish completion script
135
+ FISH_COMPLETION = '''
136
+ # NC1709 Fish Completion
137
+ # Add to ~/.config/fish/completions/nc1709.fish
138
+ # or: nc1709 --completion fish > ~/.config/fish/completions/nc1709.fish
139
+
140
+ # Main options
141
+ complete -c nc1709 -l help -d "Show help message"
142
+ complete -c nc1709 -l version -d "Show version"
143
+ complete -c nc1709 -l web -d "Start web dashboard"
144
+ complete -c nc1709 -l shell -d "Start interactive shell"
145
+ complete -c nc1709 -l config -d "Show configuration"
146
+ complete -c nc1709 -l resume -d "Resume session" -x
147
+ complete -c nc1709 -l remote -d "Remote server URL" -x
148
+ complete -c nc1709 -l api-key -d "API key for remote server" -x
149
+ complete -c nc1709 -l serve -d "Enable remote access"
150
+ complete -c nc1709 -l port -d "Server port" -x
151
+ complete -c nc1709 -l plugins -d "List available plugins"
152
+ complete -c nc1709 -l plugin -d "Run a plugin" -xa "
153
+ git:status\t'Show git status'
154
+ git:diff\t'Show git diff'
155
+ git:log\t'Show git log'
156
+ git:branch\t'List branches'
157
+ git:commit\t'Create commit'
158
+ git:push\t'Push to remote'
159
+ git:pull\t'Pull from remote'
160
+ docker:ps\t'List containers'
161
+ docker:images\t'List images'
162
+ docker:logs\t'View logs'
163
+ docker:compose_up\t'Start compose'
164
+ docker:compose_down\t'Stop compose'
165
+ fastapi:scaffold\t'Create FastAPI project'
166
+ nextjs:scaffold\t'Create Next.js project'
167
+ django:scaffold\t'Create Django project'
168
+ "
169
+ complete -c nc1709 -l completion -d "Generate shell completion" -xa "bash zsh fish"
170
+ complete -c nc1709 -l mcp-serve -d "Start MCP server"
171
+
172
+ # File completion for positional arguments
173
+ complete -c nc1709 -f -a "(__fish_complete_path)"
174
+ '''
175
+
176
+
177
+ def get_completion_script(shell: str) -> str:
178
+ """Get completion script for specified shell
179
+
180
+ Args:
181
+ shell: Shell type (bash, zsh, fish)
182
+
183
+ Returns:
184
+ Completion script content
185
+ """
186
+ scripts = {
187
+ "bash": BASH_COMPLETION,
188
+ "zsh": ZSH_COMPLETION,
189
+ "fish": FISH_COMPLETION
190
+ }
191
+
192
+ script = scripts.get(shell.lower())
193
+ if not script:
194
+ raise ValueError(f"Unknown shell: {shell}. Supported: bash, zsh, fish")
195
+
196
+ return script.strip()
197
+
198
+
199
+ def install_completions(shell: Optional[str] = None) -> str:
200
+ """Install completions for the detected or specified shell
201
+
202
+ Args:
203
+ shell: Shell type (auto-detect if None)
204
+
205
+ Returns:
206
+ Installation status message
207
+ """
208
+ if shell is None:
209
+ shell = detect_shell()
210
+
211
+ script = get_completion_script(shell)
212
+ home = os.path.expanduser("~")
213
+
214
+ if shell == "bash":
215
+ # Try to install to .bash_completion.d or .bashrc
216
+ completion_dir = os.path.join(home, ".bash_completion.d")
217
+ if os.path.isdir(completion_dir):
218
+ path = os.path.join(completion_dir, "nc1709")
219
+ with open(path, "w") as f:
220
+ f.write(script)
221
+ return f"Installed to {path}. Restart your shell to use completions."
222
+ else:
223
+ # Add to .bashrc
224
+ bashrc = os.path.join(home, ".bashrc")
225
+ source_line = '\n# NC1709 completions\neval "$(nc1709 --completion bash)"\n'
226
+ with open(bashrc, "a") as f:
227
+ f.write(source_line)
228
+ return f"Added to {bashrc}. Run 'source ~/.bashrc' or restart your shell."
229
+
230
+ elif shell == "zsh":
231
+ # Install to .zsh/completions or add to .zshrc
232
+ completion_dir = os.path.join(home, ".zsh", "completions")
233
+ os.makedirs(completion_dir, exist_ok=True)
234
+ path = os.path.join(completion_dir, "_nc1709")
235
+ with open(path, "w") as f:
236
+ f.write(script)
237
+
238
+ # Ensure completions dir is in fpath
239
+ zshrc = os.path.join(home, ".zshrc")
240
+ fpath_line = f'\nfpath=({completion_dir} $fpath)\nautoload -Uz compinit && compinit\n'
241
+
242
+ # Check if already added
243
+ try:
244
+ with open(zshrc, "r") as f:
245
+ content = f.read()
246
+ if completion_dir not in content:
247
+ with open(zshrc, "a") as f:
248
+ f.write(fpath_line)
249
+ except FileNotFoundError:
250
+ with open(zshrc, "w") as f:
251
+ f.write(fpath_line)
252
+
253
+ return f"Installed to {path}. Run 'source ~/.zshrc' or restart your shell."
254
+
255
+ elif shell == "fish":
256
+ # Install to fish completions directory
257
+ completion_dir = os.path.join(home, ".config", "fish", "completions")
258
+ os.makedirs(completion_dir, exist_ok=True)
259
+ path = os.path.join(completion_dir, "nc1709.fish")
260
+ with open(path, "w") as f:
261
+ f.write(script)
262
+ return f"Installed to {path}. Completions will be available in new fish sessions."
263
+
264
+ else:
265
+ raise ValueError(f"Cannot install completions for shell: {shell}")
266
+
267
+
268
+ def detect_shell() -> str:
269
+ """Detect the current shell
270
+
271
+ Returns:
272
+ Shell name (bash, zsh, or fish)
273
+ """
274
+ shell_path = os.environ.get("SHELL", "")
275
+ shell_name = os.path.basename(shell_path)
276
+
277
+ if "zsh" in shell_name:
278
+ return "zsh"
279
+ elif "fish" in shell_name:
280
+ return "fish"
281
+ else:
282
+ return "bash"
283
+
284
+
285
+ def print_installation_instructions(shell: str) -> None:
286
+ """Print installation instructions for a shell
287
+
288
+ Args:
289
+ shell: Shell type
290
+ """
291
+ instructions = {
292
+ "bash": """
293
+ # Bash Completion Installation
294
+
295
+ Option 1: Add to .bashrc (recommended)
296
+ echo 'eval "$(nc1709 --completion bash)"' >> ~/.bashrc
297
+ source ~/.bashrc
298
+
299
+ Option 2: Create completion file
300
+ nc1709 --completion bash > ~/.bash_completion.d/nc1709
301
+ # Requires bash-completion to be installed
302
+ """,
303
+ "zsh": """
304
+ # Zsh Completion Installation
305
+
306
+ Option 1: Add to .zshrc (simplest)
307
+ echo 'eval "$(nc1709 --completion zsh)"' >> ~/.zshrc
308
+ source ~/.zshrc
309
+
310
+ Option 2: Save to completions directory
311
+ mkdir -p ~/.zsh/completions
312
+ nc1709 --completion zsh > ~/.zsh/completions/_nc1709
313
+ # Add to .zshrc: fpath=(~/.zsh/completions $fpath)
314
+ # Then run: autoload -Uz compinit && compinit
315
+ """,
316
+ "fish": """
317
+ # Fish Completion Installation
318
+
319
+ nc1709 --completion fish > ~/.config/fish/completions/nc1709.fish
320
+
321
+ # Completions will be available immediately in new shells
322
+ """
323
+ }
324
+
325
+ print(instructions.get(shell, f"Unknown shell: {shell}"))
326
+
327
+
328
+ # Entry point for CLI
329
+ def handle_completion_command(args: list) -> None:
330
+ """Handle completion command from CLI
331
+
332
+ Args:
333
+ args: Command arguments (e.g., ['bash'] or ['--install', 'zsh'])
334
+ """
335
+ if not args:
336
+ # Print detected shell and instructions
337
+ shell = detect_shell()
338
+ print(f"Detected shell: {shell}")
339
+ print_installation_instructions(shell)
340
+ return
341
+
342
+ if args[0] == "--install":
343
+ shell = args[1] if len(args) > 1 else None
344
+ result = install_completions(shell)
345
+ print(result)
346
+ else:
347
+ # Print completion script
348
+ shell = args[0]
349
+ print(get_completion_script(shell))