sentarc-coding-agent 0.1.0__tar.gz

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 (71) hide show
  1. sentarc_coding_agent-0.1.0/PKG-INFO +16 -0
  2. sentarc_coding_agent-0.1.0/README.md +39 -0
  3. sentarc_coding_agent-0.1.0/pyproject.toml +41 -0
  4. sentarc_coding_agent-0.1.0/sentarc_coding_agent.egg-info/PKG-INFO +16 -0
  5. sentarc_coding_agent-0.1.0/sentarc_coding_agent.egg-info/SOURCES.txt +69 -0
  6. sentarc_coding_agent-0.1.0/sentarc_coding_agent.egg-info/dependency_links.txt +1 -0
  7. sentarc_coding_agent-0.1.0/sentarc_coding_agent.egg-info/entry_points.txt +2 -0
  8. sentarc_coding_agent-0.1.0/sentarc_coding_agent.egg-info/requires.txt +12 -0
  9. sentarc_coding_agent-0.1.0/sentarc_coding_agent.egg-info/top_level.txt +1 -0
  10. sentarc_coding_agent-0.1.0/setup.cfg +4 -0
  11. sentarc_coding_agent-0.1.0/src/__init__.py +33 -0
  12. sentarc_coding_agent-0.1.0/src/cli/__init__.py +218 -0
  13. sentarc_coding_agent-0.1.0/src/cli/args.py +218 -0
  14. sentarc_coding_agent-0.1.0/src/cli/config_selector.py +17 -0
  15. sentarc_coding_agent-0.1.0/src/cli/file_processor.py +59 -0
  16. sentarc_coding_agent-0.1.0/src/cli/list_models.py +27 -0
  17. sentarc_coding_agent-0.1.0/src/cli/session_picker.py +49 -0
  18. sentarc_coding_agent-0.1.0/src/cli.py +0 -0
  19. sentarc_coding_agent-0.1.0/src/config.py +103 -0
  20. sentarc_coding_agent-0.1.0/src/core/__init__.py +1 -0
  21. sentarc_coding_agent-0.1.0/src/core/agent_session.py +174 -0
  22. sentarc_coding_agent-0.1.0/src/core/auth_storage.py +52 -0
  23. sentarc_coding_agent-0.1.0/src/core/bash_executor.py +23 -0
  24. sentarc_coding_agent-0.1.0/src/core/compaction/__init__.py +1 -0
  25. sentarc_coding_agent-0.1.0/src/core/compaction/compaction.py +272 -0
  26. sentarc_coding_agent-0.1.0/src/core/compaction/utils.py +205 -0
  27. sentarc_coding_agent-0.1.0/src/core/extensions/__init__.py +1 -0
  28. sentarc_coding_agent-0.1.0/src/core/extensions/loader.py +125 -0
  29. sentarc_coding_agent-0.1.0/src/core/extensions/runner.py +57 -0
  30. sentarc_coding_agent-0.1.0/src/core/extensions/types.py +54 -0
  31. sentarc_coding_agent-0.1.0/src/core/messages.py +140 -0
  32. sentarc_coding_agent-0.1.0/src/core/model_registry.py +44 -0
  33. sentarc_coding_agent-0.1.0/src/core/model_resolver.py +51 -0
  34. sentarc_coding_agent-0.1.0/src/core/prompt_templates.py +89 -0
  35. sentarc_coding_agent-0.1.0/src/core/session_manager.py +641 -0
  36. sentarc_coding_agent-0.1.0/src/core/settings_manager.py +54 -0
  37. sentarc_coding_agent-0.1.0/src/core/skills.py +284 -0
  38. sentarc_coding_agent-0.1.0/src/core/slash_commands.py +137 -0
  39. sentarc_coding_agent-0.1.0/src/core/system_prompt.py +152 -0
  40. sentarc_coding_agent-0.1.0/src/core/tools/__init__.py +86 -0
  41. sentarc_coding_agent-0.1.0/src/core/tools/bash.py +244 -0
  42. sentarc_coding_agent-0.1.0/src/core/tools/edit.py +131 -0
  43. sentarc_coding_agent-0.1.0/src/core/tools/edit_diff.py +126 -0
  44. sentarc_coding_agent-0.1.0/src/core/tools/find.py +231 -0
  45. sentarc_coding_agent-0.1.0/src/core/tools/grep.py +336 -0
  46. sentarc_coding_agent-0.1.0/src/core/tools/ls.py +118 -0
  47. sentarc_coding_agent-0.1.0/src/core/tools/path_utils.py +85 -0
  48. sentarc_coding_agent-0.1.0/src/core/tools/read.py +165 -0
  49. sentarc_coding_agent-0.1.0/src/core/tools/truncate.py +238 -0
  50. sentarc_coding_agent-0.1.0/src/core/tools/write.py +65 -0
  51. sentarc_coding_agent-0.1.0/src/modes/__init__.py +6 -0
  52. sentarc_coding_agent-0.1.0/src/modes/interactive/__init__.py +5 -0
  53. sentarc_coding_agent-0.1.0/src/modes/interactive/components/__init__.py +12 -0
  54. sentarc_coding_agent-0.1.0/src/modes/interactive/components/assistant_message.py +38 -0
  55. sentarc_coding_agent-0.1.0/src/modes/interactive/components/footer.py +57 -0
  56. sentarc_coding_agent-0.1.0/src/modes/interactive/components/tool_execution.py +47 -0
  57. sentarc_coding_agent-0.1.0/src/modes/interactive/components/user_message.py +29 -0
  58. sentarc_coding_agent-0.1.0/src/modes/interactive/interactive_mode.py +184 -0
  59. sentarc_coding_agent-0.1.0/src/modes/interactive/theme.py +56 -0
  60. sentarc_coding_agent-0.1.0/src/modes/print_mode.py +68 -0
  61. sentarc_coding_agent-0.1.0/src/modes/rpc/__init__.py +5 -0
  62. sentarc_coding_agent-0.1.0/src/modes/rpc/jsonl.py +37 -0
  63. sentarc_coding_agent-0.1.0/src/modes/rpc/rpc_mode.py +131 -0
  64. sentarc_coding_agent-0.1.0/src/modes/rpc/rpc_types.py +104 -0
  65. sentarc_coding_agent-0.1.0/src/utils/__init__.py +1 -0
  66. sentarc_coding_agent-0.1.0/src/utils/frontmatter.py +50 -0
  67. sentarc_coding_agent-0.1.0/src/utils/git.py +44 -0
  68. sentarc_coding_agent-0.1.0/src/utils/shell.py +26 -0
  69. sentarc_coding_agent-0.1.0/tests/test_path_utils.py +75 -0
  70. sentarc_coding_agent-0.1.0/tests/test_system_prompt.py +94 -0
  71. sentarc_coding_agent-0.1.0/tests/test_truncate.py +130 -0
@@ -0,0 +1,16 @@
1
+ Metadata-Version: 2.4
2
+ Name: sentarc-coding-agent
3
+ Version: 0.1.0
4
+ Summary: Sentarc coding agent CLI (arc command)
5
+ Requires-Python: >=3.11
6
+ Requires-Dist: sentarc-ai
7
+ Requires-Dist: sentarc-agent
8
+ Requires-Dist: pathspec>=0.12.0
9
+ Requires-Dist: python-frontmatter>=1.0.0
10
+ Requires-Dist: Pillow>=10.0.0
11
+ Requires-Dist: pyperclip>=1.9.0
12
+ Requires-Dist: pyyaml>=6.0.0
13
+ Requires-Dist: filetype>=1.2.0
14
+ Provides-Extra: dev
15
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
16
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
@@ -0,0 +1,39 @@
1
+ # sentarc-coding-agent
2
+
3
+ Sentarc coding agent CLI — the `arc` command.
4
+
5
+ ## Usage
6
+
7
+ ```bash
8
+ arc [options] [@files...] [messages...]
9
+ ```
10
+
11
+ ## Options
12
+
13
+ - `--provider <name>` — Provider name (default: google)
14
+ - `--model <pattern>` — Model pattern or ID
15
+ - `--api-key <key>` — API key
16
+ - `--system-prompt <text>` — Custom system prompt
17
+ - `--append-system-prompt <text>` — Append to system prompt
18
+ - `--mode <mode>` — Output mode: text (default), json, rpc
19
+ - `--print, -p` — Non-interactive mode
20
+ - `--continue, -c` — Continue previous session
21
+ - `--resume, -r` — Select a session to resume
22
+ - `--session <path>` — Use specific session file
23
+ - `--no-session` — Don't save session
24
+ - `--tools <tools>` — Comma-separated tool names (read,bash,edit,write,grep,find,ls)
25
+ - `--no-tools` — Disable all tools
26
+ - `--thinking <level>` — Thinking level: off, minimal, low, medium, high, xhigh
27
+ - `--list-models [search]` — List available models
28
+ - `--help, -h` — Show help
29
+ - `--version, -v` — Show version
30
+
31
+ ## Available Tools (default: read, bash, edit, write)
32
+
33
+ - `read` — Read file contents
34
+ - `bash` — Execute bash commands
35
+ - `edit` — Edit files with find/replace
36
+ - `write` — Write files (creates/overwrites)
37
+ - `grep` — Search file contents (read-only)
38
+ - `find` — Find files by glob pattern (read-only)
39
+ - `ls` — List directory contents (read-only)
@@ -0,0 +1,41 @@
1
+ [project]
2
+ name = "sentarc-coding-agent"
3
+ version = "0.1.0"
4
+ description = "Sentarc coding agent CLI (arc command)"
5
+ requires-python = ">=3.11"
6
+ dependencies = [
7
+ "sentarc-ai",
8
+ "sentarc-agent",
9
+ "pathspec>=0.12.0",
10
+ "python-frontmatter>=1.0.0",
11
+ "Pillow>=10.0.0",
12
+ "pyperclip>=1.9.0",
13
+ "pyyaml>=6.0.0",
14
+ "filetype>=1.2.0",
15
+ ]
16
+
17
+ [project.optional-dependencies]
18
+ dev = ["pytest>=7.0.0", "pytest-asyncio>=0.21.0"]
19
+
20
+ [project.scripts]
21
+ arc = "sentarc_coding_agent.cli:main"
22
+
23
+ [build-system]
24
+ requires = ["setuptools>=68"]
25
+ build-backend = "setuptools.build_meta"
26
+
27
+ [tool.setuptools]
28
+ package-dir = {"sentarc_coding_agent" = "src"}
29
+ packages = [
30
+ "sentarc_coding_agent",
31
+ "sentarc_coding_agent.cli",
32
+ "sentarc_coding_agent.core",
33
+ "sentarc_coding_agent.core.tools",
34
+ "sentarc_coding_agent.core.compaction",
35
+ "sentarc_coding_agent.core.extensions",
36
+ "sentarc_coding_agent.modes",
37
+ "sentarc_coding_agent.modes.interactive",
38
+ "sentarc_coding_agent.modes.interactive.components",
39
+ "sentarc_coding_agent.modes.rpc",
40
+ "sentarc_coding_agent.utils",
41
+ ]
@@ -0,0 +1,16 @@
1
+ Metadata-Version: 2.4
2
+ Name: sentarc-coding-agent
3
+ Version: 0.1.0
4
+ Summary: Sentarc coding agent CLI (arc command)
5
+ Requires-Python: >=3.11
6
+ Requires-Dist: sentarc-ai
7
+ Requires-Dist: sentarc-agent
8
+ Requires-Dist: pathspec>=0.12.0
9
+ Requires-Dist: python-frontmatter>=1.0.0
10
+ Requires-Dist: Pillow>=10.0.0
11
+ Requires-Dist: pyperclip>=1.9.0
12
+ Requires-Dist: pyyaml>=6.0.0
13
+ Requires-Dist: filetype>=1.2.0
14
+ Provides-Extra: dev
15
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
16
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
@@ -0,0 +1,69 @@
1
+ README.md
2
+ pyproject.toml
3
+ sentarc_coding_agent.egg-info/PKG-INFO
4
+ sentarc_coding_agent.egg-info/SOURCES.txt
5
+ sentarc_coding_agent.egg-info/dependency_links.txt
6
+ sentarc_coding_agent.egg-info/entry_points.txt
7
+ sentarc_coding_agent.egg-info/requires.txt
8
+ sentarc_coding_agent.egg-info/top_level.txt
9
+ src/__init__.py
10
+ src/cli.py
11
+ src/config.py
12
+ src/cli/__init__.py
13
+ src/cli/args.py
14
+ src/cli/config_selector.py
15
+ src/cli/file_processor.py
16
+ src/cli/list_models.py
17
+ src/cli/session_picker.py
18
+ src/core/__init__.py
19
+ src/core/agent_session.py
20
+ src/core/auth_storage.py
21
+ src/core/bash_executor.py
22
+ src/core/messages.py
23
+ src/core/model_registry.py
24
+ src/core/model_resolver.py
25
+ src/core/prompt_templates.py
26
+ src/core/session_manager.py
27
+ src/core/settings_manager.py
28
+ src/core/skills.py
29
+ src/core/slash_commands.py
30
+ src/core/system_prompt.py
31
+ src/core/compaction/__init__.py
32
+ src/core/compaction/compaction.py
33
+ src/core/compaction/utils.py
34
+ src/core/extensions/__init__.py
35
+ src/core/extensions/loader.py
36
+ src/core/extensions/runner.py
37
+ src/core/extensions/types.py
38
+ src/core/tools/__init__.py
39
+ src/core/tools/bash.py
40
+ src/core/tools/edit.py
41
+ src/core/tools/edit_diff.py
42
+ src/core/tools/find.py
43
+ src/core/tools/grep.py
44
+ src/core/tools/ls.py
45
+ src/core/tools/path_utils.py
46
+ src/core/tools/read.py
47
+ src/core/tools/truncate.py
48
+ src/core/tools/write.py
49
+ src/modes/__init__.py
50
+ src/modes/print_mode.py
51
+ src/modes/interactive/__init__.py
52
+ src/modes/interactive/interactive_mode.py
53
+ src/modes/interactive/theme.py
54
+ src/modes/interactive/components/__init__.py
55
+ src/modes/interactive/components/assistant_message.py
56
+ src/modes/interactive/components/footer.py
57
+ src/modes/interactive/components/tool_execution.py
58
+ src/modes/interactive/components/user_message.py
59
+ src/modes/rpc/__init__.py
60
+ src/modes/rpc/jsonl.py
61
+ src/modes/rpc/rpc_mode.py
62
+ src/modes/rpc/rpc_types.py
63
+ src/utils/__init__.py
64
+ src/utils/frontmatter.py
65
+ src/utils/git.py
66
+ src/utils/shell.py
67
+ tests/test_path_utils.py
68
+ tests/test_system_prompt.py
69
+ tests/test_truncate.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ arc = sentarc_coding_agent.cli:main
@@ -0,0 +1,12 @@
1
+ sentarc-ai
2
+ sentarc-agent
3
+ pathspec>=0.12.0
4
+ python-frontmatter>=1.0.0
5
+ Pillow>=10.0.0
6
+ pyperclip>=1.9.0
7
+ pyyaml>=6.0.0
8
+ filetype>=1.2.0
9
+
10
+ [dev]
11
+ pytest>=7.0.0
12
+ pytest-asyncio>=0.21.0
@@ -0,0 +1 @@
1
+ sentarc_coding_agent
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,33 @@
1
+ """sentarc-coding-agent — Interactive coding agent CLI."""
2
+
3
+ __version__ = "0.1.0"
4
+
5
+ from sentarc_coding_agent.config import (
6
+ APP_NAME,
7
+ CONFIG_DIR_NAME,
8
+ VERSION,
9
+ get_agent_dir,
10
+ get_sessions_dir,
11
+ get_models_path,
12
+ get_auth_path,
13
+ get_settings_path,
14
+ )
15
+ from sentarc_coding_agent.core.tools import (
16
+ create_all_tools,
17
+ create_coding_tools,
18
+ create_read_only_tools,
19
+ )
20
+
21
+ __all__ = [
22
+ "APP_NAME",
23
+ "CONFIG_DIR_NAME",
24
+ "VERSION",
25
+ "get_agent_dir",
26
+ "get_sessions_dir",
27
+ "get_models_path",
28
+ "get_auth_path",
29
+ "get_settings_path",
30
+ "create_all_tools",
31
+ "create_coding_tools",
32
+ "create_read_only_tools",
33
+ ]
@@ -0,0 +1,218 @@
1
+ """CLI entry point for sentarc-coding-agent."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ import os
7
+ import sys
8
+ from typing import List, Optional
9
+
10
+
11
+ def main(argv: Optional[List[str]] = None) -> None:
12
+ """Main entry point — parse args and dispatch to appropriate mode."""
13
+ if argv is None:
14
+ argv = sys.argv[1:]
15
+ try:
16
+ asyncio.run(_main_async(argv))
17
+ except KeyboardInterrupt:
18
+ sys.exit(0)
19
+
20
+
21
+ async def _main_async(argv: List[str]) -> None:
22
+ from sentarc_coding_agent.cli.args import parse_args, print_help
23
+ from sentarc_coding_agent.config import VERSION, APP_NAME, get_agent_dir, get_custom_themes_dir
24
+ from sentarc_coding_agent.core.tools import create_tools, TOOL_NAMES
25
+ from sentarc_coding_agent.core.system_prompt import build_system_prompt
26
+ from sentarc_coding_agent.core.model_resolver import resolve_model
27
+ from sentarc_coding_agent.core.settings_manager import load_settings
28
+ from sentarc_coding_agent.core.skills import load_skills
29
+ from sentarc_coding_agent.core.extensions.loader import discover_extensions
30
+ from sentarc_coding_agent.core.messages import convert_to_llm
31
+
32
+ args = parse_args(argv)
33
+
34
+ # --- Simple flag handling ---
35
+ if args.get("help"):
36
+ print_help()
37
+ return
38
+
39
+ if args.get("version"):
40
+ print(f"{APP_NAME} {VERSION}")
41
+ return
42
+
43
+ if args.get("list_models") is not None:
44
+ from sentarc_coding_agent.cli.list_models import list_models
45
+ search = args["list_models"] if isinstance(args["list_models"], str) else None
46
+ list_models(search)
47
+ return
48
+
49
+ # --- Load settings ---
50
+ settings = load_settings()
51
+
52
+ # --- Resolve model ---
53
+ provider = args.get("provider") or settings.provider or "google"
54
+ model_spec = args.get("model") or settings.model or "gemini-2.5-flash"
55
+ resolved_provider, model_id, model_thinking = resolve_model(provider, model_spec)
56
+ thinking_level = args.get("thinking") or model_thinking or settings.thinking or "off"
57
+
58
+ try:
59
+ from sentarc_ai.models import get_model
60
+ model_def = get_model(resolved_provider, model_id)
61
+ except Exception as e:
62
+ print(f"Error: Could not resolve model {resolved_provider}/{model_id}: {e}", file=sys.stderr)
63
+ sys.exit(1)
64
+
65
+ # --- Build tools ---
66
+ cwd = os.getcwd()
67
+ no_tools = args.get("no_tools", False)
68
+ if no_tools:
69
+ tool_names: List[str] = []
70
+ elif args.get("tools"):
71
+ tool_names = args["tools"]
72
+ else:
73
+ tool_names = list(settings.tools or ["read", "bash", "edit", "write"])
74
+
75
+ tools = create_tools(cwd, tool_names) if tool_names else []
76
+
77
+ # --- Load skills ---
78
+ skills: list = []
79
+ if not args.get("no_skills"):
80
+ try:
81
+ skill_paths = args.get("skills") or []
82
+ loaded_skills, _ = load_skills(cwd=cwd, skill_paths=skill_paths)
83
+ skills = loaded_skills
84
+ except Exception:
85
+ pass
86
+
87
+ # --- Load context files ---
88
+ context_files: list = []
89
+ if args.get("file_args"):
90
+ try:
91
+ from sentarc_coding_agent.cli.file_processor import load_file_args
92
+ context_files = [
93
+ f for f in load_file_args(args["file_args"], cwd)
94
+ if f.get("type") == "text"
95
+ ]
96
+ except Exception as e:
97
+ print(f"Warning: Could not load context files: {e}", file=sys.stderr)
98
+
99
+ # --- Build system prompt ---
100
+ custom_prompt = args.get("system_prompt")
101
+ append_prompt = args.get("append_system_prompt")
102
+ system_prompt = build_system_prompt(
103
+ custom_prompt=custom_prompt,
104
+ selected_tools=None if no_tools else tool_names,
105
+ append_system_prompt=append_prompt,
106
+ cwd=cwd,
107
+ context_files=context_files if context_files else None,
108
+ skills=skills if skills else None,
109
+ )
110
+
111
+ # --- Load extensions ---
112
+ all_agent_tools = list(tools)
113
+ if not args.get("no_extensions"):
114
+ try:
115
+ agent_dir = get_agent_dir()
116
+ extension_paths = args.get("extensions") or []
117
+ extensions = discover_extensions(
118
+ extension_paths=extension_paths,
119
+ agent_dir=agent_dir,
120
+ )
121
+ for ext in extensions:
122
+ custom = getattr(ext, "custom_tools", None)
123
+ if custom:
124
+ all_agent_tools.extend(custom)
125
+ except Exception:
126
+ pass
127
+
128
+ # --- Create agent ---
129
+ try:
130
+ from sentarc_agent.agent import Agent
131
+ from sentarc_agent.types import AgentOptions
132
+ except ImportError as e:
133
+ print(f"Error: sentarc-agent not available: {e}", file=sys.stderr)
134
+ sys.exit(1)
135
+
136
+ agent = Agent(AgentOptions(
137
+ convert_to_llm=convert_to_llm,
138
+ initial_state={
139
+ "system_prompt": system_prompt,
140
+ "model": model_def,
141
+ "thinking_level": thinking_level,
142
+ "tools": all_agent_tools,
143
+ },
144
+ ))
145
+
146
+ # --- Set up session ---
147
+ from sentarc_coding_agent.core.session_manager import SessionManager
148
+
149
+ session: Optional[SessionManager] = None
150
+ no_session = args.get("no_session", False)
151
+ if not no_session:
152
+ session_file = args.get("session")
153
+ if args.get("resume"):
154
+ from sentarc_coding_agent.cli.session_picker import select_session_interactive
155
+ session_id = select_session_interactive()
156
+ if session_id:
157
+ try:
158
+ session = SessionManager.open(session_id)
159
+ except Exception:
160
+ session = SessionManager.create(cwd)
161
+ else:
162
+ session = SessionManager.create(cwd)
163
+ elif args.get("continue"):
164
+ session = SessionManager.continue_recent(cwd)
165
+ elif session_file:
166
+ session = SessionManager.open(session_file)
167
+ else:
168
+ session = SessionManager.create(cwd)
169
+
170
+ # Load session history into agent state
171
+ if session:
172
+ context = session.build_session_context()
173
+ history = context.get("messages", [])
174
+ if history:
175
+ agent._state.messages = history
176
+ session_thinking = context.get("thinkingLevel")
177
+ if session_thinking and not args.get("thinking"):
178
+ agent._state.thinking_level = session_thinking
179
+
180
+ # --- Determine mode and run ---
181
+ mode = args.get("mode")
182
+ messages: List[str] = args.get("messages", [])
183
+ has_messages = bool(messages)
184
+ is_print = args.get("print", False) or has_messages
185
+
186
+ if mode == "rpc":
187
+ from sentarc_coding_agent.modes.rpc.rpc_mode import run_rpc_mode
188
+ await run_rpc_mode(agent)
189
+
190
+ elif is_print or mode == "json":
191
+ from sentarc_coding_agent.modes.print_mode import PrintModeOptions, run_print_mode
192
+ initial_msg = messages[0] if messages else None
193
+ extra_msgs = messages[1:] if len(messages) > 1 else []
194
+ opts = PrintModeOptions(
195
+ mode=mode if mode in ("text", "json") else "text",
196
+ initial_message=initial_msg,
197
+ messages=extra_msgs,
198
+ )
199
+ await run_print_mode(agent, opts)
200
+
201
+ else:
202
+ # Interactive TUI mode
203
+ try:
204
+ from sentarc_coding_agent.modes.interactive.interactive_mode import run_interactive_mode
205
+ from sentarc_coding_agent.modes.interactive.theme import load_theme
206
+ from pathlib import Path
207
+
208
+ themes_dir = Path(get_custom_themes_dir())
209
+ theme = load_theme("dark", themes_dir)
210
+ await run_interactive_mode(agent, theme=theme)
211
+ except ImportError:
212
+ # Fallback: basic stdin loop
213
+ from sentarc_coding_agent.core.agent_session import run_agent_session
214
+ await run_agent_session(args)
215
+
216
+
217
+ if __name__ == "__main__":
218
+ main()
@@ -0,0 +1,218 @@
1
+ """
2
+ CLI argument parsing and help display.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ import sys
8
+ from typing import Any, Dict, List, Optional
9
+
10
+ from sentarc_coding_agent.config import APP_NAME, CONFIG_DIR_NAME, ENV_AGENT_DIR
11
+
12
+ VALID_THINKING_LEVELS = ("off", "minimal", "low", "medium", "high", "xhigh")
13
+ VALID_MODES = ("text", "json", "rpc")
14
+ VALID_TOOLS = ("read", "bash", "edit", "write", "grep", "find", "ls")
15
+
16
+
17
+ def is_valid_thinking_level(level: str) -> bool:
18
+ return level in VALID_THINKING_LEVELS
19
+
20
+
21
+ def parse_args(
22
+ argv: List[str],
23
+ extension_flags: Optional[Dict[str, str]] = None,
24
+ ) -> Dict[str, Any]:
25
+ """
26
+ Parse CLI arguments, mirroring the TypeScript parseArgs() function.
27
+ Returns a dict with the same keys as the TS Args interface (snake_case).
28
+ """
29
+ result: Dict[str, Any] = {
30
+ "messages": [],
31
+ "file_args": [],
32
+ "unknown_flags": {},
33
+ }
34
+
35
+ i = 0
36
+ while i < len(argv):
37
+ arg = argv[i]
38
+
39
+ if arg in ("--help", "-h"):
40
+ result["help"] = True
41
+ elif arg in ("--version", "-v"):
42
+ result["version"] = True
43
+ elif arg == "--mode" and i + 1 < len(argv):
44
+ i += 1
45
+ mode = argv[i]
46
+ if mode in VALID_MODES:
47
+ result["mode"] = mode
48
+ elif arg in ("--continue", "-c"):
49
+ result["continue"] = True
50
+ elif arg in ("--resume", "-r"):
51
+ result["resume"] = True
52
+ elif arg == "--provider" and i + 1 < len(argv):
53
+ i += 1
54
+ result["provider"] = argv[i]
55
+ elif arg == "--model" and i + 1 < len(argv):
56
+ i += 1
57
+ result["model"] = argv[i]
58
+ elif arg == "--api-key" and i + 1 < len(argv):
59
+ i += 1
60
+ result["api_key"] = argv[i]
61
+ elif arg == "--system-prompt" and i + 1 < len(argv):
62
+ i += 1
63
+ result["system_prompt"] = argv[i]
64
+ elif arg == "--append-system-prompt" and i + 1 < len(argv):
65
+ i += 1
66
+ result["append_system_prompt"] = argv[i]
67
+ elif arg == "--no-session":
68
+ result["no_session"] = True
69
+ elif arg == "--session" and i + 1 < len(argv):
70
+ i += 1
71
+ result["session"] = argv[i]
72
+ elif arg == "--session-dir" and i + 1 < len(argv):
73
+ i += 1
74
+ result["session_dir"] = argv[i]
75
+ elif arg == "--models" and i + 1 < len(argv):
76
+ i += 1
77
+ result["models"] = [s.strip() for s in argv[i].split(",")]
78
+ elif arg == "--no-tools":
79
+ result["no_tools"] = True
80
+ elif arg == "--tools" and i + 1 < len(argv):
81
+ i += 1
82
+ tool_names = [s.strip() for s in argv[i].split(",")]
83
+ valid: List[str] = []
84
+ for name in tool_names:
85
+ if name in VALID_TOOLS:
86
+ valid.append(name)
87
+ else:
88
+ print(
89
+ f"Warning: Unknown tool \"{name}\". Valid tools: {', '.join(VALID_TOOLS)}",
90
+ file=sys.stderr,
91
+ )
92
+ result["tools"] = valid
93
+ elif arg == "--thinking" and i + 1 < len(argv):
94
+ i += 1
95
+ level = argv[i]
96
+ if is_valid_thinking_level(level):
97
+ result["thinking"] = level
98
+ else:
99
+ print(
100
+ f"Warning: Invalid thinking level \"{level}\". Valid values: {', '.join(VALID_THINKING_LEVELS)}",
101
+ file=sys.stderr,
102
+ )
103
+ elif arg in ("--print", "-p"):
104
+ result["print"] = True
105
+ elif arg == "--export" and i + 1 < len(argv):
106
+ i += 1
107
+ result["export"] = argv[i]
108
+ elif arg in ("--extension", "-e") and i + 1 < len(argv):
109
+ i += 1
110
+ result.setdefault("extensions", []).append(argv[i])
111
+ elif arg in ("--no-extensions", "-ne"):
112
+ result["no_extensions"] = True
113
+ elif arg == "--skill" and i + 1 < len(argv):
114
+ i += 1
115
+ result.setdefault("skills", []).append(argv[i])
116
+ elif arg == "--prompt-template" and i + 1 < len(argv):
117
+ i += 1
118
+ result.setdefault("prompt_templates", []).append(argv[i])
119
+ elif arg == "--theme" and i + 1 < len(argv):
120
+ i += 1
121
+ result.setdefault("themes", []).append(argv[i])
122
+ elif arg in ("--no-skills", "-ns"):
123
+ result["no_skills"] = True
124
+ elif arg in ("--no-prompt-templates", "-np"):
125
+ result["no_prompt_templates"] = True
126
+ elif arg == "--no-themes":
127
+ result["no_themes"] = True
128
+ elif arg == "--list-models":
129
+ # Check if next arg is a search pattern (not a flag or file arg)
130
+ if i + 1 < len(argv) and not argv[i + 1].startswith("-") and not argv[i + 1].startswith("@"):
131
+ i += 1
132
+ result["list_models"] = argv[i]
133
+ else:
134
+ result["list_models"] = True
135
+ elif arg == "--verbose":
136
+ result["verbose"] = True
137
+ elif arg == "--offline":
138
+ result["offline"] = True
139
+ elif arg.startswith("@"):
140
+ result["file_args"].append(arg[1:]) # Remove @ prefix
141
+ elif arg.startswith("--") and extension_flags:
142
+ flag_name = arg[2:]
143
+ flag_type = extension_flags.get(flag_name)
144
+ if flag_type == "boolean":
145
+ result["unknown_flags"][flag_name] = True
146
+ elif flag_type == "string" and i + 1 < len(argv):
147
+ i += 1
148
+ result["unknown_flags"][flag_name] = argv[i]
149
+ elif not arg.startswith("-"):
150
+ result["messages"].append(arg)
151
+
152
+ i += 1
153
+
154
+ return result
155
+
156
+
157
+ def print_help() -> None:
158
+ """Print help text."""
159
+ print(f"""{APP_NAME} - AI coding assistant with read, bash, edit, write tools
160
+
161
+ Usage:
162
+ {APP_NAME} [options] [@files...] [messages...]
163
+
164
+ Options:
165
+ --provider <name> Provider name (default: google)
166
+ --model <pattern> Model pattern or ID
167
+ --api-key <key> API key
168
+ --system-prompt <text> System prompt
169
+ --append-system-prompt <text> Append to system prompt
170
+ --mode <mode> Output mode: text (default), json, rpc
171
+ --print, -p Non-interactive mode
172
+ --continue, -c Continue previous session
173
+ --resume, -r Select a session to resume
174
+ --session <path> Use specific session file
175
+ --session-dir <dir> Directory for session storage
176
+ --no-session Don't save session
177
+ --models <patterns> Comma-separated model patterns for cycling
178
+ --no-tools Disable all built-in tools
179
+ --tools <tools> Comma-separated list of tools to enable
180
+ Available: read, bash, edit, write, grep, find, ls
181
+ --thinking <level> Set thinking level: off, minimal, low, medium, high, xhigh
182
+ --extension, -e <path> Load an extension file
183
+ --no-extensions, -ne Disable extension discovery
184
+ --skill <path> Load a skill file or directory
185
+ --no-skills, -ns Disable skills discovery
186
+ --prompt-template <path> Load a prompt template
187
+ --no-prompt-templates, -np Disable prompt template discovery
188
+ --theme <path> Load a theme
189
+ --no-themes Disable theme discovery
190
+ --export <file> Export session file to HTML and exit
191
+ --list-models [search] List available models
192
+ --verbose Force verbose startup
193
+ --offline Disable startup network operations
194
+ --help, -h Show this help
195
+ --version, -v Show version number
196
+
197
+ Examples:
198
+ # Interactive mode
199
+ {APP_NAME}
200
+
201
+ # Non-interactive mode
202
+ {APP_NAME} -p "List all .py files in src/"
203
+
204
+ # Include files in message
205
+ {APP_NAME} @prompt.md "What does this do?"
206
+
207
+ # Continue previous session
208
+ {APP_NAME} --continue "What did we discuss?"
209
+
210
+ # Use different model
211
+ {APP_NAME} --provider openai --model gpt-4o "Help me refactor"
212
+
213
+ Environment Variables:
214
+ ANTHROPIC_API_KEY - Anthropic Claude API key
215
+ OPENAI_API_KEY - OpenAI GPT API key
216
+ GEMINI_API_KEY - Google Gemini API key
217
+ {ENV_AGENT_DIR:<32} - Session storage directory (default: ~/{CONFIG_DIR_NAME}/agent)
218
+ """)