@scemoon/cdh 1.0.9 → 1.0.10-beta.2
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.
- package/cdh/__pycache__/__init__.cpython-314.pyc +0 -0
- package/cdh/__pycache__/cli.cpython-314.pyc +0 -0
- package/cdh/__pycache__/cli_logging.cpython-314.pyc +0 -0
- package/cdh/__pycache__/config.cpython-314.pyc +0 -0
- package/cdh/__pycache__/project_loader.cpython-314.pyc +0 -0
- package/cdh/__pycache__/scaffold.cpython-314.pyc +0 -0
- package/cdh/__pycache__/session_store.cpython-314.pyc +0 -0
- package/cdh/trace/__pycache__/__init__.cpython-314.pyc +0 -0
- package/cdh/validators/__pycache__/__init__.cpython-314.pyc +0 -0
- package/cdh/validators/__pycache__/bdd.cpython-314.pyc +0 -0
- package/cdh/validators/__pycache__/dag.cpython-314.pyc +0 -0
- package/cdh/validators/__pycache__/ears.cpython-314.pyc +0 -0
- package/cdh/validators/__pycache__/fr_namespace.cpython-314.pyc +0 -0
- package/onecode/__init__.py +1 -1
- package/onecode/__pycache__/__init__.cpython-314.pyc +0 -0
- package/onecode/__pycache__/cli.cpython-314.pyc +0 -0
- package/onecode/__pycache__/commands.cpython-314.pyc +0 -0
- package/onecode/__pycache__/config.cpython-314.pyc +0 -0
- package/onecode/__pycache__/config_screen.cpython-314.pyc +0 -0
- package/onecode/__pycache__/migrate.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/__init__.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/cdh_loader.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/checkpoint.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/context.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/engine.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/hooks.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/onecode_agent_acp.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/permissions.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/permissions_store.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/session.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/turn_record.cpython-314.pyc +0 -0
- package/onecode/agent/agents/__pycache__/__init__.cpython-314.pyc +0 -0
- package/onecode/agent/agents/__pycache__/types.cpython-314.pyc +0 -0
- package/onecode/agent/engine.py +24 -4
- package/onecode/agent/tools/__pycache__/__init__.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/agent_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/apply_patch_tool.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/bash_tool.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/communication_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/config_tool.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/cron_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/errors.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/file_ops.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/file_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/git_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/lsp_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/mcp_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/permission_handler.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/permissions.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/protocol.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/registry.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/sandbox.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/schema_validation.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/skill_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/todo_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/web_tools.cpython-314.pyc +0 -0
- package/onecode/codebase/__pycache__/__init__.cpython-314.pyc +0 -0
- package/onecode/codebase/__pycache__/chunker.cpython-314.pyc +0 -0
- package/onecode/codebase/__pycache__/indexer.cpython-314.pyc +0 -0
- package/onecode/codebase/__pycache__/retriever.cpython-314.pyc +0 -0
- package/onecode/codebase/__pycache__/storage.cpython-314.pyc +0 -0
- package/onecode/codebase/__pycache__/tools.cpython-314.pyc +0 -0
- package/onecode/commands.py +245 -0
- package/onecode/config_screen.py +13 -13
- package/onecode/mcp/__pycache__/__init__.cpython-314.pyc +0 -0
- package/onecode/mcp/__pycache__/client.cpython-314.pyc +0 -0
- package/onecode/mcp/__pycache__/cloudbase.cpython-314.pyc +0 -0
- package/onecode/mcp/__pycache__/config.cpython-314.pyc +0 -0
- package/onecode/mcp/__pycache__/manager.cpython-314.pyc +0 -0
- package/onecode/mcp/__pycache__/oauth.cpython-314.pyc +0 -0
- package/onecode/memory/__pycache__/__init__.cpython-314.pyc +0 -0
- package/onecode/memory/__pycache__/backend.cpython-314.pyc +0 -0
- package/onecode/memory/__pycache__/pyramid.cpython-314.pyc +0 -0
- package/onecode/memory/__pycache__/recall.cpython-314.pyc +0 -0
- package/onecode/models/__pycache__/__init__.cpython-314.pyc +0 -0
- package/onecode/models/__pycache__/errors.cpython-314.pyc +0 -0
- package/onecode/models/__pycache__/messages.cpython-314.pyc +0 -0
- package/onecode/models/__pycache__/ollama_manager.cpython-314.pyc +0 -0
- package/onecode/models/__pycache__/provider.cpython-314.pyc +0 -0
- package/onecode/models/__pycache__/registry.cpython-314.pyc +0 -0
- package/onecode/models/providers/__pycache__/__init__.cpython-314.pyc +0 -0
- package/onecode/models/providers/__pycache__/anthropic_provider.cpython-314.pyc +0 -0
- package/onecode/models/providers/__pycache__/deepseek_provider.cpython-314.pyc +0 -0
- package/onecode/models/providers/__pycache__/glm_provider.cpython-314.pyc +0 -0
- package/onecode/models/providers/__pycache__/minimax_provider.cpython-314.pyc +0 -0
- package/onecode/models/providers/__pycache__/minimaxi_provider.cpython-314.pyc +0 -0
- package/onecode/models/providers/__pycache__/ollama_provider.cpython-314.pyc +0 -0
- package/onecode/models/providers/__pycache__/openai_provider.cpython-314.pyc +0 -0
- package/onecode/skills/__pycache__/__init__.cpython-314.pyc +0 -0
- package/onecode/skills/__pycache__/argument_substitution.cpython-314.pyc +0 -0
- package/onecode/skills/__pycache__/bootstrap.cpython-314.pyc +0 -0
- package/onecode/skills/__pycache__/create.cpython-314.pyc +0 -0
- package/onecode/skills/__pycache__/frontmatter.cpython-314.pyc +0 -0
- package/onecode/skills/__pycache__/loader.cpython-314.pyc +0 -0
- package/onecode/skills/__pycache__/model.cpython-314.pyc +0 -0
- package/onecode/verification/__pycache__/__init__.cpython-314.pyc +0 -0
- package/onecode/verification/__pycache__/aggregation.cpython-314.pyc +0 -0
- package/onecode/verification/__pycache__/loop.cpython-314.pyc +0 -0
- package/onecode/verification/__pycache__/policy.cpython-314.pyc +0 -0
- package/onecode/verification/gates/__pycache__/__init__.cpython-314.pyc +0 -0
- package/onecode/verification/gates/__pycache__/base.cpython-314.pyc +0 -0
- package/onecode/verification/gates/__pycache__/lint_gate.cpython-314.pyc +0 -0
- package/onecode/verification/gates/__pycache__/test_gate.cpython-314.pyc +0 -0
- package/onecode/verification/gates/__pycache__/type_gate.cpython-314.pyc +0 -0
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/tui/__pycache__/__init__.cpython-314.pyc +0 -0
- package/tui/__pycache__/_loop.cpython-314.pyc +0 -0
- package/tui/__pycache__/_path_fuzzy_search.cpython-314.pyc +0 -0
- package/tui/__pycache__/_path_match.cpython-314.pyc +0 -0
- package/tui/__pycache__/agent.cpython-314.pyc +0 -0
- package/tui/__pycache__/agent_schema.cpython-314.pyc +0 -0
- package/tui/__pycache__/agents.cpython-314.pyc +0 -0
- package/tui/__pycache__/answer.cpython-314.pyc +0 -0
- package/tui/__pycache__/app.cpython-314.pyc +0 -0
- package/tui/__pycache__/atomic.cpython-314.pyc +0 -0
- package/tui/__pycache__/complete.cpython-314.pyc +0 -0
- package/tui/__pycache__/constants.cpython-314.pyc +0 -0
- package/tui/__pycache__/db.cpython-314.pyc +0 -0
- package/tui/__pycache__/dec.cpython-314.pyc +0 -0
- package/tui/__pycache__/directory.cpython-314.pyc +0 -0
- package/tui/__pycache__/directory_watcher.cpython-314.pyc +0 -0
- package/tui/__pycache__/format_path.cpython-314.pyc +0 -0
- package/tui/__pycache__/fuzzy.cpython-314.pyc +0 -0
- package/tui/__pycache__/fuzzy_index.cpython-314.pyc +0 -0
- package/tui/__pycache__/history.cpython-314.pyc +0 -0
- package/tui/__pycache__/jsonrpc.cpython-314.pyc +0 -0
- package/tui/__pycache__/menus.cpython-314.pyc +0 -0
- package/tui/__pycache__/message_log.cpython-314.pyc +0 -0
- package/tui/__pycache__/messages.cpython-314.pyc +0 -0
- package/tui/__pycache__/path_complete.cpython-314.pyc +0 -0
- package/tui/__pycache__/path_filter.cpython-314.pyc +0 -0
- package/tui/__pycache__/paths.cpython-314.pyc +0 -0
- package/tui/__pycache__/pill.cpython-314.pyc +0 -0
- package/tui/__pycache__/platform_commands.cpython-314.pyc +0 -0
- package/tui/__pycache__/protocol.cpython-314.pyc +0 -0
- package/tui/__pycache__/session_tracker.cpython-314.pyc +0 -0
- package/tui/__pycache__/settings.cpython-314.pyc +0 -0
- package/tui/__pycache__/settings_schema.cpython-314.pyc +0 -0
- package/tui/__pycache__/shell.cpython-314.pyc +0 -0
- package/tui/__pycache__/shell_read.cpython-314.pyc +0 -0
- package/tui/__pycache__/slash_command.cpython-314.pyc +0 -0
- package/tui/__pycache__/version.cpython-314.pyc +0 -0
- package/tui/acp/__pycache__/agent.cpython-314.pyc +0 -0
- package/tui/acp/__pycache__/api.cpython-314.pyc +0 -0
- package/tui/acp/__pycache__/encode_tool_call_id.cpython-314.pyc +0 -0
- package/tui/acp/__pycache__/event_tap.cpython-314.pyc +0 -0
- package/tui/acp/__pycache__/messages.cpython-314.pyc +0 -0
- package/tui/acp/__pycache__/prompt.cpython-314.pyc +0 -0
- package/tui/acp/__pycache__/protocol.cpython-314.pyc +0 -0
- package/tui/ansi/__pycache__/__init__.cpython-314.pyc +0 -0
- package/tui/ansi/__pycache__/_ansi.cpython-314.pyc +0 -0
- package/tui/ansi/__pycache__/_ansi_colors.cpython-314.pyc +0 -0
- package/tui/ansi/__pycache__/_control_codes.cpython-314.pyc +0 -0
- package/tui/ansi/__pycache__/_keys.cpython-314.pyc +0 -0
- package/tui/ansi/__pycache__/_sgr_styles.cpython-314.pyc +0 -0
- package/tui/ansi/__pycache__/_stream_parser.cpython-314.pyc +0 -0
- package/tui/app.py +10 -1
- package/tui/prompt/__pycache__/extract.cpython-314.pyc +0 -0
- package/tui/prompt/__pycache__/resource.cpython-314.pyc +0 -0
- package/tui/screens/__pycache__/__init__.cpython-314.pyc +0 -0
- package/tui/screens/__pycache__/diff_screen.cpython-314.pyc +0 -0
- package/tui/screens/__pycache__/main.cpython-314.pyc +0 -0
- package/tui/screens/__pycache__/sessions.cpython-314.pyc +0 -0
- package/tui/screens/sessions.py +1 -4
- package/tui/visuals/__pycache__/__init__.cpython-314.pyc +0 -0
- package/tui/visuals/__pycache__/columns.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/__init__.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/aidlc.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/ask_user.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/condensed_path.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/context_stats.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/conversation.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/diff_view.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/edit_field.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/flash.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/grid_select.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/highlighted_textarea.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/load_more.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/menu.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/modified_files.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/non_selectable_label.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/note.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/path_search.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/pending_prompts.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/plan.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/project_directory_tree.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/prompt.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/question.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/session_grid_select.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/session_summary.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/session_tabs.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/shell_terminal.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/side_bar.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/slash_complete.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/strike_text.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/terminal.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/throbber.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/user_input.cpython-314.pyc +0 -0
- package/tui/widgets/conversation.py +0 -1
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/onecode/__init__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "1.0.
|
|
1
|
+
__version__ = "1.0.10-beta.1"
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/onecode/agent/engine.py
CHANGED
|
@@ -1381,6 +1381,16 @@ class AgentEngine:
|
|
|
1381
1381
|
return json.dumps({"success": False, "error": f"{name} denied"})
|
|
1382
1382
|
if perm == AgentPermission.ASK:
|
|
1383
1383
|
return json.dumps({"success": False, "error": f"{name} requires approval", "requires_approval": True})
|
|
1384
|
+
if name == "Spawn" and self._is_plan_mode():
|
|
1385
|
+
agent_type = inp.get("agent_type", "general")
|
|
1386
|
+
if agent_type in ("build", "solo", "general"):
|
|
1387
|
+
return json.dumps({
|
|
1388
|
+
"success": False,
|
|
1389
|
+
"error": (
|
|
1390
|
+
f"Spawn({agent_type}) denied in plan mode. "
|
|
1391
|
+
"Use explore or scout for research."
|
|
1392
|
+
),
|
|
1393
|
+
})
|
|
1384
1394
|
return None
|
|
1385
1395
|
|
|
1386
1396
|
def hidden_tool_names(self) -> set[str]:
|
|
@@ -1455,17 +1465,24 @@ class AgentEngine:
|
|
|
1455
1465
|
logger.warning("Failed to save plan document: %s", e)
|
|
1456
1466
|
return None
|
|
1457
1467
|
|
|
1458
|
-
def _plan_handoff(self, plan_path: str | None) ->
|
|
1468
|
+
def _plan_handoff(self, plan_path: str | None) -> bool:
|
|
1459
1469
|
"""Switch from the plan agent to the execution agent after approval.
|
|
1460
1470
|
|
|
1461
1471
|
Keeps the approved task list (todos) and injects the approved plan
|
|
1462
1472
|
document into the execution agent's system context so it survives
|
|
1463
1473
|
compaction and stays the single source of truth.
|
|
1474
|
+
|
|
1475
|
+
Returns True if handoff was successful, False otherwise.
|
|
1464
1476
|
"""
|
|
1477
|
+
logger.info("_plan_handoff called: plan_path=%s, current_agent=%s",
|
|
1478
|
+
plan_path, self.current_agent.name)
|
|
1465
1479
|
try:
|
|
1466
1480
|
if self.current_agent.name != "plan":
|
|
1467
|
-
|
|
1481
|
+
logger.warning("_plan_handoff skipped: not in plan mode (current=%s)",
|
|
1482
|
+
self.current_agent.name)
|
|
1483
|
+
return False
|
|
1468
1484
|
self.set_agent("solo", keep_todos=True)
|
|
1485
|
+
logger.info("_plan_handoff: agent switched to solo, context updated")
|
|
1469
1486
|
plan_text = ""
|
|
1470
1487
|
if plan_path:
|
|
1471
1488
|
try:
|
|
@@ -1489,7 +1506,9 @@ class AgentEngine:
|
|
|
1489
1506
|
if not self.context.replace_system_section("<!-- APPROVED_PLAN -->", section):
|
|
1490
1507
|
self.context.insert_system_before_non_system(section)
|
|
1491
1508
|
except Exception as e:
|
|
1492
|
-
logger.
|
|
1509
|
+
logger.error("Plan handoff failed: %s", e, exc_info=True)
|
|
1510
|
+
return False
|
|
1511
|
+
return True
|
|
1493
1512
|
|
|
1494
1513
|
def _react_phase_text(self, round_no: int) -> str:
|
|
1495
1514
|
"""Per-round CoT guidance header; the plan agent has its own stages."""
|
|
@@ -2869,7 +2888,8 @@ class AgentEngine:
|
|
|
2869
2888
|
}
|
|
2870
2889
|
# Plan approved → hand off to the execution agent (keeps todos).
|
|
2871
2890
|
if plan_submit:
|
|
2872
|
-
self._plan_handoff(plan_path)
|
|
2891
|
+
if not self._plan_handoff(plan_path):
|
|
2892
|
+
logger.error("Plan handoff failed but continued execution")
|
|
2873
2893
|
# answer is a JSON string when multi-question, plain text otherwise
|
|
2874
2894
|
try:
|
|
2875
2895
|
parsed = json.loads(answer)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/onecode/commands.py
CHANGED
|
@@ -78,6 +78,7 @@ async def _status(conversation: "Conversation", parameters: str) -> None:
|
|
|
78
78
|
|
|
79
79
|
lines += [
|
|
80
80
|
"\n**What can I do here?**",
|
|
81
|
+
"- `/onecode:config` — open the TUI config editor",
|
|
81
82
|
"- `/onecode:provider [set <name|n>]` — show / change LLM provider",
|
|
82
83
|
"- `/onecode:model [set <name|n>]` — show / change LLM model",
|
|
83
84
|
"- `/onecode:skill list|enable|disable|add|remove [name]`",
|
|
@@ -619,6 +620,244 @@ async def _compact(conversation: "Conversation", parameters: str) -> None:
|
|
|
619
620
|
conversation.notify(f"Compaction failed: {e}", title="/onecode:compact", severity="error")
|
|
620
621
|
|
|
621
622
|
|
|
623
|
+
# ── config ─────────────────────────────────────────────────────────────
|
|
624
|
+
|
|
625
|
+
|
|
626
|
+
def _mask_api_key(v: str | None) -> str:
|
|
627
|
+
if not v:
|
|
628
|
+
return "(not set)"
|
|
629
|
+
if v.startswith("${") and v.endswith("}"):
|
|
630
|
+
return f"{v} (env ref)"
|
|
631
|
+
if len(v) <= 4:
|
|
632
|
+
return "***"
|
|
633
|
+
return v[:4] + "***" + v[-4:]
|
|
634
|
+
|
|
635
|
+
|
|
636
|
+
async def _config(conversation: "Conversation", parameters: str) -> None:
|
|
637
|
+
cfg = _load_cfg()
|
|
638
|
+
parts = parameters.strip().split()
|
|
639
|
+
sub = parts[0].lower() if parts else ""
|
|
640
|
+
rest = " ".join(parts[1:]) if len(parts) > 1 else ""
|
|
641
|
+
|
|
642
|
+
if sub in ("", "tui", "screen", "edit"):
|
|
643
|
+
conversation.app.push_screen("config")
|
|
644
|
+
return
|
|
645
|
+
|
|
646
|
+
if sub == "list":
|
|
647
|
+
import yaml
|
|
648
|
+
from onecode.config import _dataclass_to_dict
|
|
649
|
+
raw = _dataclass_to_dict(cfg)
|
|
650
|
+
for pid, pcfg in raw.get("providers", {}).items():
|
|
651
|
+
if pcfg.get("api_key"):
|
|
652
|
+
pcfg["api_key"] = _mask_api_key(pcfg["api_key"])
|
|
653
|
+
await _post(conversation, "**onecode config**\n\n```yaml\n" + yaml.dump(raw, default_flow_style=False) + "```")
|
|
654
|
+
return
|
|
655
|
+
|
|
656
|
+
if sub == "mode":
|
|
657
|
+
mode_parts = rest.strip().split()
|
|
658
|
+
mode_sub = mode_parts[0].lower() if mode_parts else ""
|
|
659
|
+
if mode_sub == "get" or mode_sub == "":
|
|
660
|
+
await _post(conversation, f"**mode** = `{cfg.default_mode}` (build | plan | solo)")
|
|
661
|
+
return
|
|
662
|
+
if mode_sub == "set":
|
|
663
|
+
if len(mode_parts) < 2:
|
|
664
|
+
conversation.notify("Usage: /onecode:config mode set <build|plan|solo>", title="/onecode:config mode set", severity="error")
|
|
665
|
+
return
|
|
666
|
+
value = mode_parts[1]
|
|
667
|
+
if value not in ("build", "plan", "solo"):
|
|
668
|
+
conversation.notify("Mode must be one of: build, plan, solo", title="/onecode:config mode set", severity="error")
|
|
669
|
+
return
|
|
670
|
+
cfg.default_mode = value
|
|
671
|
+
_save_cfg(cfg)
|
|
672
|
+
conversation.flash(f"onecode mode set to [b]{value}")
|
|
673
|
+
return
|
|
674
|
+
await _post(conversation, _HELP_CONFIG)
|
|
675
|
+
return
|
|
676
|
+
|
|
677
|
+
if sub == "model":
|
|
678
|
+
model_parts = rest.strip().split()
|
|
679
|
+
model_sub = model_parts[0].lower() if model_parts else ""
|
|
680
|
+
if model_sub == "get" or model_sub == "":
|
|
681
|
+
await _post(conversation, f"**model** = `{cfg.default_model}`")
|
|
682
|
+
return
|
|
683
|
+
if model_sub == "set":
|
|
684
|
+
if len(model_parts) < 2:
|
|
685
|
+
conversation.notify("Usage: /onecode:config model set <model-name>", title="/onecode:config model set", severity="error")
|
|
686
|
+
return
|
|
687
|
+
value = model_parts[1]
|
|
688
|
+
cfg.default_model = value
|
|
689
|
+
_save_cfg(cfg)
|
|
690
|
+
conversation.flash(f"onecode model set to [b]{value}")
|
|
691
|
+
return
|
|
692
|
+
await _post(conversation, _HELP_CONFIG)
|
|
693
|
+
return
|
|
694
|
+
|
|
695
|
+
if sub == "provider":
|
|
696
|
+
prov_parts = rest.strip().split()
|
|
697
|
+
prov_sub = prov_parts[0].lower() if prov_parts else ""
|
|
698
|
+
prov_rest = " ".join(prov_parts[1:]) if len(prov_parts) > 1 else ""
|
|
699
|
+
|
|
700
|
+
if prov_sub in ("", "get"):
|
|
701
|
+
await _post(conversation, f"**provider** = `{cfg.default_provider}`")
|
|
702
|
+
return
|
|
703
|
+
|
|
704
|
+
if prov_sub == "set":
|
|
705
|
+
if not prov_rest:
|
|
706
|
+
conversation.notify("Usage: /onecode:config provider set <name>", title="/onecode:config provider set", severity="error")
|
|
707
|
+
return
|
|
708
|
+
cfg.default_provider = prov_rest
|
|
709
|
+
_save_cfg(cfg)
|
|
710
|
+
conversation.flash(f"onecode provider set to [b]{prov_rest}")
|
|
711
|
+
return
|
|
712
|
+
|
|
713
|
+
if prov_sub == "list":
|
|
714
|
+
from onecode.models.provider import ProviderRegistry
|
|
715
|
+
from onecode.models.registry import ModelRegistry
|
|
716
|
+
try:
|
|
717
|
+
from onecode.models import providers as _ # noqa: F401
|
|
718
|
+
except ImportError:
|
|
719
|
+
pass
|
|
720
|
+
try:
|
|
721
|
+
ModelRegistry.initialize()
|
|
722
|
+
except Exception:
|
|
723
|
+
pass
|
|
724
|
+
registered = sorted(ProviderRegistry.list())
|
|
725
|
+
current = cfg.default_provider
|
|
726
|
+
lines = [f"**Available providers** ({len(registered)}):\n"]
|
|
727
|
+
for i, name in enumerate(registered, 1):
|
|
728
|
+
marker = " ← active" if name == current else ""
|
|
729
|
+
try:
|
|
730
|
+
models = ModelRegistry.list_by_provider(name)
|
|
731
|
+
except Exception:
|
|
732
|
+
models = []
|
|
733
|
+
if models:
|
|
734
|
+
model_names = sorted({m.id for m in models})
|
|
735
|
+
shown = ", ".join(model_names[:5])
|
|
736
|
+
if len(model_names) > 5:
|
|
737
|
+
shown += f", … (+{len(model_names) - 5})"
|
|
738
|
+
model_hint = f" models: {shown}"
|
|
739
|
+
else:
|
|
740
|
+
model_hint = " models: (any local)"
|
|
741
|
+
lines.append(f" `{i}) {name}`{marker}{model_hint}")
|
|
742
|
+
lines.append("\n*Switch with: `/onecode:config provider set <name>`*")
|
|
743
|
+
await _post(conversation, "\n".join(lines))
|
|
744
|
+
return
|
|
745
|
+
|
|
746
|
+
if prov_sub in ("api-key", "apikey", "key"):
|
|
747
|
+
key_parts = prov_rest.strip().split()
|
|
748
|
+
key_sub = key_parts[0].lower() if key_parts else ""
|
|
749
|
+
key_rest = " ".join(key_parts[1:]) if len(key_parts) > 1 else ""
|
|
750
|
+
|
|
751
|
+
if key_sub == "get":
|
|
752
|
+
if not key_rest:
|
|
753
|
+
conversation.notify("Usage: /onecode:config provider api-key get <provider>", title="/onecode:config provider api-key get", severity="error")
|
|
754
|
+
return
|
|
755
|
+
pcfg = cfg.providers.get(key_rest)
|
|
756
|
+
if pcfg:
|
|
757
|
+
await _post(conversation, f"**{key_rest} api-key** = `{_mask_api_key(pcfg.api_key)}`")
|
|
758
|
+
else:
|
|
759
|
+
await _post(conversation, f"**{key_rest} api-key** = `(not configured)`")
|
|
760
|
+
return
|
|
761
|
+
|
|
762
|
+
if key_sub == "set":
|
|
763
|
+
if len(key_parts) < 3:
|
|
764
|
+
conversation.notify("Usage: /onecode:config provider api-key set <provider> <key>", title="/onecode:config provider api-key set", severity="error")
|
|
765
|
+
return
|
|
766
|
+
provider_id = key_parts[1]
|
|
767
|
+
key_value = key_parts[2]
|
|
768
|
+
if provider_id not in cfg.providers:
|
|
769
|
+
from onecode.config import ProviderConfig
|
|
770
|
+
cfg.providers[provider_id] = ProviderConfig()
|
|
771
|
+
cfg.providers[provider_id].api_key = key_value
|
|
772
|
+
_save_cfg(cfg)
|
|
773
|
+
conversation.flash(f"onecode {provider_id} api-key set")
|
|
774
|
+
return
|
|
775
|
+
|
|
776
|
+
await _post(conversation, _HELP_CONFIG)
|
|
777
|
+
return
|
|
778
|
+
|
|
779
|
+
if prov_sub == "endpoint":
|
|
780
|
+
ep_parts = prov_rest.strip().split()
|
|
781
|
+
ep_sub = ep_parts[0].lower() if ep_parts else ""
|
|
782
|
+
ep_rest = " ".join(ep_parts[1:]) if len(ep_parts) > 1 else ""
|
|
783
|
+
|
|
784
|
+
if ep_sub == "get":
|
|
785
|
+
if not ep_rest:
|
|
786
|
+
conversation.notify("Usage: /onecode:config provider endpoint get <provider>", title="/onecode:config provider endpoint get", severity="error")
|
|
787
|
+
return
|
|
788
|
+
pcfg = cfg.providers.get(ep_rest)
|
|
789
|
+
if pcfg:
|
|
790
|
+
ep = pcfg.endpoint or "(default)"
|
|
791
|
+
await _post(conversation, f"**{ep_rest} endpoint** = `{ep}`")
|
|
792
|
+
else:
|
|
793
|
+
await _post(conversation, f"**{ep_rest} endpoint** = `(not configured)`")
|
|
794
|
+
return
|
|
795
|
+
|
|
796
|
+
if ep_sub == "set":
|
|
797
|
+
if len(ep_parts) < 3:
|
|
798
|
+
conversation.notify("Usage: /onecode:config provider endpoint set <provider> <url>", title="/onecode:config provider endpoint set", severity="error")
|
|
799
|
+
return
|
|
800
|
+
provider_id = ep_parts[1]
|
|
801
|
+
ep_value = ep_parts[2]
|
|
802
|
+
if provider_id not in cfg.providers:
|
|
803
|
+
from onecode.config import ProviderConfig
|
|
804
|
+
cfg.providers[provider_id] = ProviderConfig()
|
|
805
|
+
cfg.providers[provider_id].endpoint = ep_value
|
|
806
|
+
_save_cfg(cfg)
|
|
807
|
+
conversation.flash(f"onecode {provider_id} endpoint set")
|
|
808
|
+
return
|
|
809
|
+
|
|
810
|
+
await _post(conversation, _HELP_CONFIG)
|
|
811
|
+
return
|
|
812
|
+
|
|
813
|
+
await _post(conversation, _HELP_CONFIG)
|
|
814
|
+
return
|
|
815
|
+
|
|
816
|
+
if sub == "log-level":
|
|
817
|
+
ll_parts = rest.strip().split()
|
|
818
|
+
ll_sub = ll_parts[0].lower() if ll_parts else ""
|
|
819
|
+
if ll_sub == "get" or ll_sub == "":
|
|
820
|
+
await _post(conversation, f"**log-level** = `{cfg.log_level}` (debug | info | warn | error)")
|
|
821
|
+
return
|
|
822
|
+
if ll_sub == "set":
|
|
823
|
+
if len(ll_parts) < 2:
|
|
824
|
+
conversation.notify("Usage: /onecode:config log-level set <debug|info|warn|error>", title="/onecode:config log-level set", severity="error")
|
|
825
|
+
return
|
|
826
|
+
value = ll_parts[1]
|
|
827
|
+
if value not in ("debug", "info", "warn", "error"):
|
|
828
|
+
conversation.notify("Log level must be one of: debug, info, warn, error", title="/onecode:config log-level set", severity="error")
|
|
829
|
+
return
|
|
830
|
+
cfg.log_level = value
|
|
831
|
+
_save_cfg(cfg)
|
|
832
|
+
conversation.flash(f"onecode log-level set to [b]{value}")
|
|
833
|
+
return
|
|
834
|
+
await _post(conversation, _HELP_CONFIG)
|
|
835
|
+
return
|
|
836
|
+
|
|
837
|
+
await _post(conversation, _HELP_CONFIG)
|
|
838
|
+
|
|
839
|
+
|
|
840
|
+
_HELP_CONFIG = (
|
|
841
|
+
"**/onecode:config** — manage onecode configuration\n\n"
|
|
842
|
+
"**Sub-commands**\n"
|
|
843
|
+
"- `(none)` or `tui` — open the TUI config editor\n"
|
|
844
|
+
"- `list` — show full YAML configuration (api-key masked)\n"
|
|
845
|
+
"- `mode get|set <build|plan|solo>`\n"
|
|
846
|
+
"- `model get|set <model-name>`\n"
|
|
847
|
+
"- `provider get|set <name>` — get/set default provider\n"
|
|
848
|
+
"- `provider list` — list all available providers\n"
|
|
849
|
+
"- `provider api-key get|set <provider> <key>` — manage provider api-key\n"
|
|
850
|
+
"- `provider endpoint get|set <provider> <url>` — manage provider endpoint\n"
|
|
851
|
+
"- `log-level get|set <debug|info|warn|error>`\n\n"
|
|
852
|
+
"**Examples**\n"
|
|
853
|
+
"- `/onecode:config` — open config editor\n"
|
|
854
|
+
"- `/onecode:config list` — show full config\n"
|
|
855
|
+
"- `/onecode:config mode set solo`\n"
|
|
856
|
+
"- `/onecode:config provider api-key set openai sk-xxx`\n"
|
|
857
|
+
"- `/onecode:config provider endpoint set openai https://api.openai.com/v1`"
|
|
858
|
+
)
|
|
859
|
+
|
|
860
|
+
|
|
622
861
|
# ── registration ──────────────────────────────────────────────────────
|
|
623
862
|
|
|
624
863
|
|
|
@@ -670,4 +909,10 @@ def register_commands() -> None:
|
|
|
670
909
|
"Immediately compact context to reduce token usage",
|
|
671
910
|
_compact,
|
|
672
911
|
"(no args)",
|
|
912
|
+
)
|
|
913
|
+
platform_commands.register(
|
|
914
|
+
"config",
|
|
915
|
+
"Open config editor TUI, or manage mode/model/provider/api-key/endpoint/log-level",
|
|
916
|
+
_config,
|
|
917
|
+
"mode|model|provider|log-level [get|set <v>]",
|
|
673
918
|
)
|
package/onecode/config_screen.py
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from textual import on
|
|
4
|
-
from textual.app import
|
|
4
|
+
from textual.app import ComposeResult
|
|
5
5
|
from textual.binding import Binding
|
|
6
6
|
from textual.containers import Horizontal, Vertical
|
|
7
7
|
from textual.reactive import var
|
|
8
|
+
from textual.screen import ModalScreen
|
|
8
9
|
from textual.widget import Widget
|
|
9
10
|
from textual.widgets import Button, Label, Static
|
|
10
11
|
|
|
@@ -130,8 +131,7 @@ Button:disabled {
|
|
|
130
131
|
"""
|
|
131
132
|
|
|
132
133
|
|
|
133
|
-
class ConfigScreen(
|
|
134
|
-
TITLE = "CDH Configuration"
|
|
134
|
+
class ConfigScreen(ModalScreen):
|
|
135
135
|
CSS = CSS
|
|
136
136
|
|
|
137
137
|
BINDINGS = [
|
|
@@ -141,7 +141,6 @@ class ConfigScreen(App):
|
|
|
141
141
|
Binding("right", "go_enter", "Select"),
|
|
142
142
|
Binding("enter", "confirm", "Confirm"),
|
|
143
143
|
Binding("escape", "cancel", "Cancel"),
|
|
144
|
-
Binding("ctrl+q", "quit_app", "Quit"),
|
|
145
144
|
]
|
|
146
145
|
|
|
147
146
|
MODE_OPTIONS = [
|
|
@@ -178,7 +177,6 @@ class ConfigScreen(App):
|
|
|
178
177
|
with Horizontal(id="button-row"):
|
|
179
178
|
yield Button("Confirm (↵)", id="save")
|
|
180
179
|
yield Button("Cancel (ESC)", id="cancel")
|
|
181
|
-
yield Button("Quit (Ctrl+Q)", id="quit")
|
|
182
180
|
|
|
183
181
|
def on_mount(self) -> None:
|
|
184
182
|
self._build_menu()
|
|
@@ -461,26 +459,28 @@ class ConfigScreen(App):
|
|
|
461
459
|
def action_cancel(self) -> None:
|
|
462
460
|
if self.view != "menu":
|
|
463
461
|
self.action_go_back()
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
self.exit()
|
|
462
|
+
else:
|
|
463
|
+
self.dismiss()
|
|
467
464
|
|
|
468
465
|
def _on_click(self, event) -> None:
|
|
469
466
|
pass
|
|
470
467
|
|
|
471
468
|
@on(Button.Pressed, "#save")
|
|
472
469
|
def on_save(self) -> None:
|
|
473
|
-
self.notify("Configuration saved")
|
|
474
|
-
self.
|
|
470
|
+
self.app.notify("Configuration saved")
|
|
471
|
+
self.dismiss()
|
|
475
472
|
|
|
476
473
|
@on(Button.Pressed, "#cancel")
|
|
477
474
|
def on_cancel_button(self) -> None:
|
|
478
|
-
self.
|
|
475
|
+
self.dismiss()
|
|
479
476
|
|
|
480
477
|
@on(Button.Pressed, "#quit")
|
|
481
478
|
def on_quit(self) -> None:
|
|
482
|
-
self.
|
|
479
|
+
self.dismiss()
|
|
483
480
|
|
|
484
481
|
|
|
485
482
|
def main() -> None:
|
|
486
|
-
|
|
483
|
+
from textual.app import App
|
|
484
|
+
app = App()
|
|
485
|
+
app.push_screen(ConfigScreen())
|
|
486
|
+
app.run()
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|