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.
- sentarc_coding_agent-0.1.0/PKG-INFO +16 -0
- sentarc_coding_agent-0.1.0/README.md +39 -0
- sentarc_coding_agent-0.1.0/pyproject.toml +41 -0
- sentarc_coding_agent-0.1.0/sentarc_coding_agent.egg-info/PKG-INFO +16 -0
- sentarc_coding_agent-0.1.0/sentarc_coding_agent.egg-info/SOURCES.txt +69 -0
- sentarc_coding_agent-0.1.0/sentarc_coding_agent.egg-info/dependency_links.txt +1 -0
- sentarc_coding_agent-0.1.0/sentarc_coding_agent.egg-info/entry_points.txt +2 -0
- sentarc_coding_agent-0.1.0/sentarc_coding_agent.egg-info/requires.txt +12 -0
- sentarc_coding_agent-0.1.0/sentarc_coding_agent.egg-info/top_level.txt +1 -0
- sentarc_coding_agent-0.1.0/setup.cfg +4 -0
- sentarc_coding_agent-0.1.0/src/__init__.py +33 -0
- sentarc_coding_agent-0.1.0/src/cli/__init__.py +218 -0
- sentarc_coding_agent-0.1.0/src/cli/args.py +218 -0
- sentarc_coding_agent-0.1.0/src/cli/config_selector.py +17 -0
- sentarc_coding_agent-0.1.0/src/cli/file_processor.py +59 -0
- sentarc_coding_agent-0.1.0/src/cli/list_models.py +27 -0
- sentarc_coding_agent-0.1.0/src/cli/session_picker.py +49 -0
- sentarc_coding_agent-0.1.0/src/cli.py +0 -0
- sentarc_coding_agent-0.1.0/src/config.py +103 -0
- sentarc_coding_agent-0.1.0/src/core/__init__.py +1 -0
- sentarc_coding_agent-0.1.0/src/core/agent_session.py +174 -0
- sentarc_coding_agent-0.1.0/src/core/auth_storage.py +52 -0
- sentarc_coding_agent-0.1.0/src/core/bash_executor.py +23 -0
- sentarc_coding_agent-0.1.0/src/core/compaction/__init__.py +1 -0
- sentarc_coding_agent-0.1.0/src/core/compaction/compaction.py +272 -0
- sentarc_coding_agent-0.1.0/src/core/compaction/utils.py +205 -0
- sentarc_coding_agent-0.1.0/src/core/extensions/__init__.py +1 -0
- sentarc_coding_agent-0.1.0/src/core/extensions/loader.py +125 -0
- sentarc_coding_agent-0.1.0/src/core/extensions/runner.py +57 -0
- sentarc_coding_agent-0.1.0/src/core/extensions/types.py +54 -0
- sentarc_coding_agent-0.1.0/src/core/messages.py +140 -0
- sentarc_coding_agent-0.1.0/src/core/model_registry.py +44 -0
- sentarc_coding_agent-0.1.0/src/core/model_resolver.py +51 -0
- sentarc_coding_agent-0.1.0/src/core/prompt_templates.py +89 -0
- sentarc_coding_agent-0.1.0/src/core/session_manager.py +641 -0
- sentarc_coding_agent-0.1.0/src/core/settings_manager.py +54 -0
- sentarc_coding_agent-0.1.0/src/core/skills.py +284 -0
- sentarc_coding_agent-0.1.0/src/core/slash_commands.py +137 -0
- sentarc_coding_agent-0.1.0/src/core/system_prompt.py +152 -0
- sentarc_coding_agent-0.1.0/src/core/tools/__init__.py +86 -0
- sentarc_coding_agent-0.1.0/src/core/tools/bash.py +244 -0
- sentarc_coding_agent-0.1.0/src/core/tools/edit.py +131 -0
- sentarc_coding_agent-0.1.0/src/core/tools/edit_diff.py +126 -0
- sentarc_coding_agent-0.1.0/src/core/tools/find.py +231 -0
- sentarc_coding_agent-0.1.0/src/core/tools/grep.py +336 -0
- sentarc_coding_agent-0.1.0/src/core/tools/ls.py +118 -0
- sentarc_coding_agent-0.1.0/src/core/tools/path_utils.py +85 -0
- sentarc_coding_agent-0.1.0/src/core/tools/read.py +165 -0
- sentarc_coding_agent-0.1.0/src/core/tools/truncate.py +238 -0
- sentarc_coding_agent-0.1.0/src/core/tools/write.py +65 -0
- sentarc_coding_agent-0.1.0/src/modes/__init__.py +6 -0
- sentarc_coding_agent-0.1.0/src/modes/interactive/__init__.py +5 -0
- sentarc_coding_agent-0.1.0/src/modes/interactive/components/__init__.py +12 -0
- sentarc_coding_agent-0.1.0/src/modes/interactive/components/assistant_message.py +38 -0
- sentarc_coding_agent-0.1.0/src/modes/interactive/components/footer.py +57 -0
- sentarc_coding_agent-0.1.0/src/modes/interactive/components/tool_execution.py +47 -0
- sentarc_coding_agent-0.1.0/src/modes/interactive/components/user_message.py +29 -0
- sentarc_coding_agent-0.1.0/src/modes/interactive/interactive_mode.py +184 -0
- sentarc_coding_agent-0.1.0/src/modes/interactive/theme.py +56 -0
- sentarc_coding_agent-0.1.0/src/modes/print_mode.py +68 -0
- sentarc_coding_agent-0.1.0/src/modes/rpc/__init__.py +5 -0
- sentarc_coding_agent-0.1.0/src/modes/rpc/jsonl.py +37 -0
- sentarc_coding_agent-0.1.0/src/modes/rpc/rpc_mode.py +131 -0
- sentarc_coding_agent-0.1.0/src/modes/rpc/rpc_types.py +104 -0
- sentarc_coding_agent-0.1.0/src/utils/__init__.py +1 -0
- sentarc_coding_agent-0.1.0/src/utils/frontmatter.py +50 -0
- sentarc_coding_agent-0.1.0/src/utils/git.py +44 -0
- sentarc_coding_agent-0.1.0/src/utils/shell.py +26 -0
- sentarc_coding_agent-0.1.0/tests/test_path_utils.py +75 -0
- sentarc_coding_agent-0.1.0/tests/test_system_prompt.py +94 -0
- 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 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
sentarc_coding_agent
|
|
@@ -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
|
+
""")
|