ghostcode-canary 0.1.25-canary.0

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 (50) hide show
  1. package/LICENSE +201 -0
  2. package/PAT.txt +1 -0
  3. package/README.md +95 -0
  4. package/cli.js +92 -0
  5. package/error/err1.txt +12 -0
  6. package/package.json +31 -0
  7. package/setup.js +67 -0
  8. package/src/ghostcode/__init__.py +3 -0
  9. package/src/ghostcode/__main__.py +3 -0
  10. package/src/ghostcode/_version.py +17 -0
  11. package/src/ghostcode/agents/__init__.py +20 -0
  12. package/src/ghostcode/agents/code.py +104 -0
  13. package/src/ghostcode/agents/explore.py +50 -0
  14. package/src/ghostcode/ai/__init__.py +0 -0
  15. package/src/ghostcode/ai/anthropic_client.py +8 -0
  16. package/src/ghostcode/ai/base.py +33 -0
  17. package/src/ghostcode/ai/factory.py +38 -0
  18. package/src/ghostcode/ai/groq_client.py +7 -0
  19. package/src/ghostcode/ai/nvidia_client.py +7 -0
  20. package/src/ghostcode/ai/ollama_client.py +7 -0
  21. package/src/ghostcode/ai/openai_client.py +7 -0
  22. package/src/ghostcode/ai/openai_compat.py +139 -0
  23. package/src/ghostcode/ai/opencode_go_client.py +7 -0
  24. package/src/ghostcode/ai/opencode_zen_client.py +7 -0
  25. package/src/ghostcode/ai/openrouter_client.py +7 -0
  26. package/src/ghostcode/ai/registry.py +169 -0
  27. package/src/ghostcode/app.py +148 -0
  28. package/src/ghostcode/config.py +24 -0
  29. package/src/ghostcode/core/__init__.py +5 -0
  30. package/src/ghostcode/core/commands.py +55 -0
  31. package/src/ghostcode/core/file_ops.py +127 -0
  32. package/src/ghostcode/core/hooks.py +122 -0
  33. package/src/ghostcode/core/memory.py +137 -0
  34. package/src/ghostcode/core/prompt.py +73 -0
  35. package/src/ghostcode/core/reminders.py +61 -0
  36. package/src/ghostcode/core/security.py +119 -0
  37. package/src/ghostcode/core/tasks.py +125 -0
  38. package/src/ghostcode/tools/__init__.py +2 -0
  39. package/src/ghostcode/tools/defs.py +325 -0
  40. package/src/ghostcode/tools/executor.py +261 -0
  41. package/src/ghostcode/tui/__init__.py +0 -0
  42. package/src/ghostcode/tui/app.py +12 -0
  43. package/src/ghostcode/tui/dialogs.py +241 -0
  44. package/src/ghostcode/tui/screens.py +799 -0
  45. package/src/ghostcode/tui/widgets.py +32 -0
  46. package/src/ghostcode/utils/__init__.py +0 -0
  47. package/src/ghostcode/utils/config_loader.py +102 -0
  48. package/src/ghostcode/utils/logger.py +16 -0
  49. package/src/pyproject.toml +18 -0
  50. package/token.txt +1 -0
@@ -0,0 +1,32 @@
1
+ import re
2
+
3
+ from rich.markdown import Markdown
4
+ from textual.widgets import Static
5
+
6
+
7
+ CODE_BLOCK_RE = re.compile(r"```(\w+)?\n(.*?)```", re.DOTALL)
8
+
9
+
10
+ def render_chat_content(content: str) -> Markdown:
11
+ return Markdown(content, code_theme="monokai")
12
+
13
+
14
+ def dim_text(text: str) -> str:
15
+ return text.replace("[dim]", "").replace("[/dim]", "")
16
+
17
+
18
+ class Message(Static):
19
+ def __init__(self, role: str, content: str, *args, **kwargs):
20
+ self.role = role
21
+ self.content = content
22
+ super().__init__(*args, **kwargs)
23
+ self.update(render_chat_content(content))
24
+
25
+ def on_mount(self):
26
+ self.styles.margin = (0, 1)
27
+ if self.role == "user":
28
+ self.styles.background = "$surface"
29
+ self.styles.border = ("round", "$primary")
30
+ else:
31
+ self.styles.background = "$background"
32
+ self.styles.border = ("round", "$success")
File without changes
@@ -0,0 +1,102 @@
1
+ import json
2
+ import os
3
+ from pathlib import Path
4
+
5
+ from dotenv import load_dotenv
6
+
7
+ CONFIG_DIR = Path.home() / ".ghostcode"
8
+ CONFIG_PATH = CONFIG_DIR / "config.json"
9
+
10
+
11
+ def ensure_config():
12
+ CONFIG_DIR.mkdir(parents=True, exist_ok=True)
13
+ if not CONFIG_PATH.exists():
14
+ CONFIG_PATH.write_text(json.dumps({
15
+ "default_provider": "nvidia",
16
+ "api_keys": {},
17
+ }, indent=2))
18
+
19
+
20
+ def load_config() -> dict:
21
+ ensure_config()
22
+ return json.loads(CONFIG_PATH.read_text())
23
+
24
+
25
+ def save_config(cfg: dict):
26
+ CONFIG_DIR.mkdir(parents=True, exist_ok=True)
27
+ CONFIG_PATH.write_text(json.dumps(cfg, indent=2))
28
+
29
+
30
+ def get_api_key(provider: str) -> str:
31
+ cfg = load_config()
32
+ return cfg.get("api_keys", {}).get(provider.lower(), "")
33
+
34
+
35
+ def set_api_key(provider: str, key: str):
36
+ cfg = load_config()
37
+ cfg.setdefault("api_keys", {})
38
+ cfg["api_keys"][provider.lower()] = key
39
+ save_config(cfg)
40
+
41
+
42
+ def get_default_provider() -> str:
43
+ cfg = load_config()
44
+ return cfg.get("default_provider", "nvidia")
45
+
46
+
47
+ def set_default_provider(provider: str):
48
+ cfg = load_config()
49
+ cfg["default_provider"] = provider
50
+ save_config(cfg)
51
+
52
+
53
+ def get_last_model(provider: str) -> str | None:
54
+ cfg = load_config()
55
+ return cfg.get("models", {}).get(provider.lower())
56
+
57
+
58
+ def set_last_model(provider: str, model: str):
59
+ cfg = load_config()
60
+ cfg.setdefault("models", {})
61
+ cfg["models"][provider.lower()] = model
62
+ save_config(cfg)
63
+
64
+
65
+ def find_and_load_env():
66
+ paths = [
67
+ Path(".env"),
68
+ CONFIG_DIR / ".env",
69
+ Path(__file__).resolve().parent.parent.parent / ".env",
70
+ ]
71
+ for p in paths:
72
+ if p.exists():
73
+ load_dotenv(p)
74
+ return str(p)
75
+ return None
76
+
77
+
78
+ def migrate_env_keys_to_config():
79
+ key_map = {
80
+ "NVIDIA_API_KEY": "nvidia",
81
+ "OPENAI_API_KEY": "openai",
82
+ "GROQ_API_KEY": "groq",
83
+ "ANTHROPIC_API_KEY": "anthropic",
84
+ "OPENROUTER_API_KEY": "openrouter",
85
+ }
86
+ cfg = load_config()
87
+ changed = False
88
+ for env_var, provider_id in key_map.items():
89
+ val = os.getenv(env_var, "")
90
+ if val and provider_id not in cfg.get("api_keys", {}):
91
+ cfg.setdefault("api_keys", {})
92
+ cfg["api_keys"][provider_id] = val
93
+ changed = True
94
+ opencode_key = os.getenv("OPENCODE_API_KEY", "")
95
+ if opencode_key:
96
+ for pid in ("opencode-zen", "opencode-go"):
97
+ if pid not in cfg.get("api_keys", {}):
98
+ cfg.setdefault("api_keys", {})
99
+ cfg["api_keys"][pid] = opencode_key
100
+ changed = True
101
+ if changed:
102
+ save_config(cfg)
@@ -0,0 +1,16 @@
1
+ import logging
2
+ import sys
3
+
4
+
5
+ def setup_logger(name: str = "ghostcode", level: str = "WARNING") -> logging.Logger:
6
+ logger = logging.getLogger(name)
7
+ logger.setLevel(getattr(logging, level.upper(), logging.WARNING))
8
+
9
+ if not logger.handlers:
10
+ handler = logging.StreamHandler(sys.stderr)
11
+ handler.setFormatter(logging.Formatter(
12
+ "%(asctime)s [%(levelname)s] %(name)s: %(message)s"
13
+ ))
14
+ logger.addHandler(handler)
15
+
16
+ return logger
@@ -0,0 +1,18 @@
1
+ [project]
2
+ name = "ghostcode-cli"
3
+ version = "0.1.25"
4
+ requires-python = ">=3.8"
5
+ dependencies = [
6
+ "textual>=8.0.0",
7
+ "httpx>=0.28.0",
8
+ "python-dotenv>=1.0.0",
9
+ "pygments>=2.15.0",
10
+ ]
11
+
12
+ [tool.setuptools.packages.find]
13
+ where = ["."]
14
+ include = ["ghostcode*"]
15
+
16
+ [build-system]
17
+ requires = ["setuptools>=64", "wheel"]
18
+ build-backend = "setuptools.build_meta"
package/token.txt ADDED
@@ -0,0 +1 @@
1
+ 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