yycode 0.3.3__tar.gz → 0.3.4__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.
- {yycode-0.3.3 → yycode-0.3.4}/PKG-INFO +2 -2
- {yycode-0.3.3 → yycode-0.3.4}/README.md +5 -3
- yycode-0.3.4/agent/app_paths.py +113 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/runtime/workflow_guard.py +0 -11
- {yycode-0.3.3 → yycode-0.3.4}/agent/session.py +9 -2
- {yycode-0.3.3 → yycode-0.3.4}/agent/tui/renderers.py +8 -14
- {yycode-0.3.3 → yycode-0.3.4}/agent/tui/state.py +1 -1
- yycode-0.3.4/agent/tui/styles.tcss +280 -0
- {yycode-0.3.3 → yycode-0.3.4}/main.py +38 -5
- {yycode-0.3.3 → yycode-0.3.4}/pyproject.toml +7 -3
- yycode-0.3.4/skills/drawio/styles/built-in/corporate.json +49 -0
- yycode-0.3.4/skills/drawio/styles/built-in/default.json +49 -0
- yycode-0.3.4/skills/drawio/styles/built-in/handdrawn.json +49 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_main_input.py +40 -4
- yycode-0.3.4/tests/test_packaging.py +40 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_skills.py +103 -10
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_tool_concurrency.py +41 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_tui_state.py +9 -8
- {yycode-0.3.3 → yycode-0.3.4}/yycode.egg-info/PKG-INFO +2 -2
- {yycode-0.3.3 → yycode-0.3.4}/yycode.egg-info/SOURCES.txt +5 -0
- {yycode-0.3.3 → yycode-0.3.4}/yycode.egg-info/requires.txt +1 -1
- yycode-0.3.3/agent/app_paths.py +0 -25
- {yycode-0.3.3 → yycode-0.3.4}/agent/__init__.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/acp/__init__.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/acp/approval_adapter.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/acp/content_adapter.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/acp/jsonrpc.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/acp/server.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/acp/session_manager.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/acp/update_adapter.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/approval.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/cancellation.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/change_snapshot.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/context_compressor.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/graph.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/llm_retry.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/logger.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/lsp/__init__.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/lsp/client.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/lsp/manager.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/lsp/types.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/message_context_manager.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/message_format.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/nodes/llm_node.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/nodes/state.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/nodes/task_guard_node.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/nodes/tools_node.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/plan_snapshot.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/providers/__init__.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/providers/anthropic_provider.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/providers/base.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/providers/openai_provider.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/providers/text_tool_calls.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/runtime/approval_service.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/runtime/context.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/runtime/tool_events.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/runtime/tool_executor.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/runtime/tool_output.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/runtime/tool_registry.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/runtime/tool_scheduler.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/runtime/workspace.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/runtime/workspace_tools.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/session_replay.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/session_store.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/skills.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/streaming.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/subagent.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/task_memory.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/todo_manager.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/tool_retry.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/tui/__init__.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/tui/app.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/tui/approval.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/tui/commands/__init__.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/tui/commands/base.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/tui/commands/clear.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/tui/commands/help.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/tui/commands/registry.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/tui/help_content.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/agent/tui/runner.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/setup.cfg +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/code_review.md +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/code_workflow.md +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/drawio/SKILL.md +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/drawio/agents/openai.yaml +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/drawio/assets/demo-erd.drawio +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/drawio/assets/demo-layered-cn.drawio +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/drawio/assets/demo-layered-cn.png +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/drawio/assets/demo-layered.drawio +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/drawio/assets/demo-layered.png +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/drawio/assets/demo-ml.drawio +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/drawio/assets/demo-ring-cn.drawio +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/drawio/assets/demo-ring-cn.png +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/drawio/assets/demo-ring.drawio +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/drawio/assets/demo-ring.png +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/drawio/assets/demo-sequence.drawio +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/drawio/assets/demo-star-cn.drawio +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/drawio/assets/demo-star-cn.png +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/drawio/assets/demo-star.drawio +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/drawio/assets/demo-star.png +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/drawio/assets/demo-uml-class.drawio +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/drawio/assets/microservices-example.drawio +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/drawio/assets/microservices-example.png +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/drawio/assets/workflow-cn.drawio +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/drawio/assets/workflow-cn.png +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/drawio/assets/workflow.drawio +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/drawio/assets/workflow.png +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/drawio/docs/index.html +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/drawio/docs/zh.html +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/drawio/references/style-extraction.md +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/drawio/styles/schema.json +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/plan.md +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/skills/ppt/SKILL.md +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_acp.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_anthropic_provider.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_apply_patch_tool.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_code_navigation_tools.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_compatibility_primitives.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_grep_tool.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_llm_retry.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_lsp_tools.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_message_context_manager.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_message_format.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_openai_provider_reasoning.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_safety.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_session_store.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_streaming.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_streaming_events.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_subagent.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_task_guard.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_task_memory.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_task_state.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_text_tool_calls.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_token_counting.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_tool_metadata.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_tui_approval.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_tui_commands.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_tui_runner.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_verify_tool.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_web_search_tool.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_workspace_tools.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tests/test_write_tools_diff.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tools/__init__.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tools/apply_patch.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tools/bash.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tools/diff_utils.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tools/edit_file.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tools/git_diff.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tools/git_show.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tools/grep.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tools/list_files.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tools/list_skills.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tools/load_skill.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tools/lsp_definition.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tools/lsp_diagnostics.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tools/lsp_document_symbols.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tools/lsp_hover.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tools/lsp_references.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tools/lsp_utils.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tools/lsp_workspace_symbols.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tools/read_file.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tools/read_many_files.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tools/safety.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tools/subagent.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tools/todo.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tools/verify.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tools/web_search.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tools/workspace.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tools/workspace_state.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/tools/write_file.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/utils/__init__.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/utils/retry.py +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/yycode.egg-info/dependency_links.txt +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/yycode.egg-info/entry_points.txt +0 -0
- {yycode-0.3.3 → yycode-0.3.4}/yycode.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: yycode
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.4
|
|
4
4
|
Summary: Terminal coding agent with TUI, plain input mode, tools, skills, and ACP support
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Requires-Dist: anthropic>=0.40.0
|
|
@@ -9,4 +9,4 @@ Requires-Dist: tiktoken>=0.12.0
|
|
|
9
9
|
Requires-Dist: langgraph>=0.2.0
|
|
10
10
|
Requires-Dist: langchain-core>=0.3.0
|
|
11
11
|
Requires-Dist: python-dotenv>=1.0.0
|
|
12
|
-
Requires-Dist: textual
|
|
12
|
+
Requires-Dist: textual==8.2.4
|
|
@@ -155,9 +155,11 @@ uv run python main.py -s # 查看当前工作区可恢复的 sessio
|
|
|
155
155
|
uv run python main.py -r <session-id> # 恢复指定 session
|
|
156
156
|
uv run python main.py -x <session-id> # 删除指定 session
|
|
157
157
|
uv run python main.py -t # 临时会话,不保存 messages
|
|
158
|
+
uv run python main.py --update-skills # 用内置 skills 覆盖同步用户数据目录中的同路径文件
|
|
158
159
|
uv run python main.py --acp # 启动 ACP stdio server
|
|
159
160
|
uv run python main.py acp # 同上,便于作为子命令使用
|
|
160
161
|
yycode --plain # 安装发行包后的普通终端输入模式
|
|
162
|
+
yycode --update-skills # 更新用户数据目录中的默认 skills,保留用户自定义文件
|
|
161
163
|
yycode --acp # 安装发行包后的 ACP stdio server
|
|
162
164
|
```
|
|
163
165
|
|
|
@@ -257,10 +259,10 @@ PyPI token 只应通过本地命令、CI secret 或凭据管理器使用,不
|
|
|
257
259
|
| `API_BASE` | 可选,自定义 API Base/Base URL | `https://api.openai.com/v1` |
|
|
258
260
|
| `AI_MODEL` | 模型名称 | Anthropic 默认 `claude-3-5-sonnet-20241022`,OpenAI 默认 `gpt-4o` |
|
|
259
261
|
| `YOYO_CONTEXT_WINDOW_TOKENS` | 可选,覆盖上下文窗口大小,用于 TUI/CLI 提示符统计;未设置时会按模型推断 | Claude `200000`,Doubao Code `224000`,GPT-4o/4.1/5 `128000` |
|
|
260
|
-
| `YOYO_APP_ROOT` | 可选,覆盖
|
|
261
|
-
| `YOYO_RUNTIME_DATA_DIR` |
|
|
262
|
+
| `YOYO_APP_ROOT` | 可选,覆盖 yycode 内置资源来源目录;通常不需要设置 | `/path/to/yycode-install` |
|
|
263
|
+
| `YOYO_RUNTIME_DATA_DIR` | 可选,覆盖用户数据目录;默认使用系统用户数据目录 | macOS: `~/Library/Application Support/yycode` |
|
|
262
264
|
| `YOYO_SESSION_DIR` | 可选,覆盖 session messages 保存目录 | `~/.yoyoagent/sessions` |
|
|
263
|
-
| `YOYO_SKILL_DIRS` |
|
|
265
|
+
| `YOYO_SKILL_DIRS` | 可选,额外技能目录,多个目录用逗号分隔;默认技能目录是用户数据目录下的 `skills` | `../shared-skills` |
|
|
264
266
|
| `YOYO_SILENT` / `YOYO_AUTO_APPROVE` | 可选,启用后自动批准高风险操作 | `true` |
|
|
265
267
|
|
|
266
268
|
高级重试配置:
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""Application-level path helpers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import shutil
|
|
7
|
+
import sys
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import NamedTuple
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def resolve_app_root(raw_app_root: str | Path | None = None) -> Path:
|
|
13
|
+
"""Resolve the yoyoagent application root directory."""
|
|
14
|
+
raw = raw_app_root or os.environ.get("YOYO_APP_ROOT")
|
|
15
|
+
if raw:
|
|
16
|
+
return Path(raw).expanduser().resolve()
|
|
17
|
+
return Path(__file__).resolve().parents[1]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def resolve_resource_root(raw_app_root: str | Path | None = None) -> Path:
|
|
21
|
+
"""Resolve the bundled yycode resource root for default files."""
|
|
22
|
+
raw = raw_app_root or os.environ.get("YOYO_APP_ROOT")
|
|
23
|
+
if raw:
|
|
24
|
+
return Path(raw).expanduser().resolve()
|
|
25
|
+
|
|
26
|
+
source_root = Path(__file__).resolve().parents[1]
|
|
27
|
+
if (source_root / "skills").is_dir():
|
|
28
|
+
return source_root
|
|
29
|
+
|
|
30
|
+
prefix_root = Path(sys.prefix).resolve()
|
|
31
|
+
if (prefix_root / "skills").is_dir():
|
|
32
|
+
return prefix_root
|
|
33
|
+
|
|
34
|
+
return source_root
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def resolve_runtime_data_dir(
|
|
38
|
+
app_root: Path,
|
|
39
|
+
raw_runtime_data_dir: str | Path | None = None,
|
|
40
|
+
) -> Path:
|
|
41
|
+
"""Resolve the user-editable runtime data directory for yycode-owned data."""
|
|
42
|
+
raw = raw_runtime_data_dir or os.environ.get("YOYO_RUNTIME_DATA_DIR")
|
|
43
|
+
if raw:
|
|
44
|
+
return Path(raw).expanduser().resolve()
|
|
45
|
+
return default_user_data_dir()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def default_user_data_dir() -> Path:
|
|
49
|
+
"""Return the default per-user yycode data directory."""
|
|
50
|
+
if sys.platform == "darwin":
|
|
51
|
+
return (Path.home() / "Library" / "Application Support" / "yycode").resolve()
|
|
52
|
+
if os.name == "nt":
|
|
53
|
+
base = os.environ.get("APPDATA")
|
|
54
|
+
if base:
|
|
55
|
+
return (Path(base).expanduser() / "yycode").resolve()
|
|
56
|
+
return (Path.home() / "AppData" / "Roaming" / "yycode").resolve()
|
|
57
|
+
base = os.environ.get("XDG_DATA_HOME")
|
|
58
|
+
if base:
|
|
59
|
+
return (Path(base).expanduser() / "yycode").resolve()
|
|
60
|
+
return (Path.home() / ".local" / "share" / "yycode").resolve()
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def ensure_default_skills_dir(runtime_data_dir: Path, resource_root: Path) -> Path:
|
|
64
|
+
"""Initialize the user-editable skills directory from bundled defaults if needed."""
|
|
65
|
+
skills_dir = runtime_data_dir / "skills"
|
|
66
|
+
if skills_dir.exists():
|
|
67
|
+
return skills_dir
|
|
68
|
+
|
|
69
|
+
bundled_skills = resource_root / "skills"
|
|
70
|
+
if bundled_skills.is_dir():
|
|
71
|
+
skills_dir.parent.mkdir(parents=True, exist_ok=True)
|
|
72
|
+
shutil.copytree(bundled_skills, skills_dir)
|
|
73
|
+
else:
|
|
74
|
+
skills_dir.mkdir(parents=True, exist_ok=True)
|
|
75
|
+
return skills_dir
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class SkillSyncResult(NamedTuple):
|
|
79
|
+
"""Summary of a bundled skill sync into the user data directory."""
|
|
80
|
+
|
|
81
|
+
source_dir: Path
|
|
82
|
+
target_dir: Path
|
|
83
|
+
copied: list[Path]
|
|
84
|
+
updated: list[Path]
|
|
85
|
+
skipped: list[Path]
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def sync_default_skills_dir(runtime_data_dir: Path, resource_root: Path) -> SkillSyncResult:
|
|
89
|
+
"""Copy bundled skills into user data, overwriting matching bundled files only."""
|
|
90
|
+
source_dir = resource_root / "skills"
|
|
91
|
+
target_dir = runtime_data_dir / "skills"
|
|
92
|
+
copied: list[Path] = []
|
|
93
|
+
updated: list[Path] = []
|
|
94
|
+
skipped: list[Path] = []
|
|
95
|
+
|
|
96
|
+
if not source_dir.is_dir():
|
|
97
|
+
target_dir.mkdir(parents=True, exist_ok=True)
|
|
98
|
+
return SkillSyncResult(source_dir, target_dir, copied, updated, skipped)
|
|
99
|
+
|
|
100
|
+
for source_path in sorted(path for path in source_dir.rglob("*") if path.is_file()):
|
|
101
|
+
relative_path = source_path.relative_to(source_dir)
|
|
102
|
+
target_path = target_dir / relative_path
|
|
103
|
+
target_path.parent.mkdir(parents=True, exist_ok=True)
|
|
104
|
+
if target_path.exists():
|
|
105
|
+
if target_path.read_bytes() == source_path.read_bytes():
|
|
106
|
+
skipped.append(relative_path)
|
|
107
|
+
continue
|
|
108
|
+
updated.append(relative_path)
|
|
109
|
+
else:
|
|
110
|
+
copied.append(relative_path)
|
|
111
|
+
shutil.copy2(source_path, target_path)
|
|
112
|
+
|
|
113
|
+
return SkillSyncResult(source_dir, target_dir, copied, updated, skipped)
|
|
@@ -171,17 +171,6 @@ class WorkflowGuard:
|
|
|
171
171
|
def after_batch_messages(self, tool_calls_data: list) -> list[HumanMessage]:
|
|
172
172
|
"""Return extra HumanMessages to append after a tools batch."""
|
|
173
173
|
additional_messages = []
|
|
174
|
-
todo_manager = self.runtime.todo_manager
|
|
175
|
-
if todo_manager.needs_reminder():
|
|
176
|
-
additional_messages.append(
|
|
177
|
-
HumanMessage(
|
|
178
|
-
content=todo_manager.consume_reminder_message(),
|
|
179
|
-
additional_kwargs={
|
|
180
|
-
"context_ephemeral": True,
|
|
181
|
-
"ephemeral_kind": "task_reminder",
|
|
182
|
-
},
|
|
183
|
-
)
|
|
184
|
-
)
|
|
185
174
|
if self.state.needs_verify and not any(tc.name == "verify" for tc in tool_calls_data):
|
|
186
175
|
additional_messages.append(
|
|
187
176
|
HumanMessage(
|
|
@@ -14,7 +14,12 @@ from langchain_core.messages import (
|
|
|
14
14
|
)
|
|
15
15
|
|
|
16
16
|
from agent.approval import ApprovalCallback, ApprovalDenied
|
|
17
|
-
from agent.app_paths import
|
|
17
|
+
from agent.app_paths import (
|
|
18
|
+
ensure_default_skills_dir,
|
|
19
|
+
resolve_app_root,
|
|
20
|
+
resolve_resource_root,
|
|
21
|
+
resolve_runtime_data_dir,
|
|
22
|
+
)
|
|
18
23
|
from agent.session_replay import ReplayEvent, build_session_replay
|
|
19
24
|
from agent.graph import build_graph
|
|
20
25
|
from agent.llm_retry import LLMCallError
|
|
@@ -65,7 +70,9 @@ class Session:
|
|
|
65
70
|
self.provider = provider
|
|
66
71
|
self.workdir = (workdir or Path.cwd()).expanduser().resolve()
|
|
67
72
|
self.app_root = resolve_app_root(app_root)
|
|
73
|
+
self.resource_root = resolve_resource_root(app_root)
|
|
68
74
|
self.runtime_data_dir = resolve_runtime_data_dir(self.app_root, runtime_data_dir)
|
|
75
|
+
self.default_skill_dir = ensure_default_skills_dir(self.runtime_data_dir, self.resource_root)
|
|
69
76
|
self.skill_dirs = self._resolve_skill_dirs(skill_dirs)
|
|
70
77
|
self.skill_registry = SkillRegistry(self.workdir, self.skill_dirs)
|
|
71
78
|
self.skill_catalog_prompt = self.skill_registry.format_skill_catalog_prompt()
|
|
@@ -114,7 +121,7 @@ class Session:
|
|
|
114
121
|
self.task_summary_memory_builder = TaskSummaryMemoryBuilder()
|
|
115
122
|
|
|
116
123
|
def _resolve_skill_dirs(self, skill_dirs: Optional[Iterable[str]]) -> list[str]:
|
|
117
|
-
default_dir = str(self.
|
|
124
|
+
default_dir = str(self.default_skill_dir)
|
|
118
125
|
if skill_dirs is None:
|
|
119
126
|
return [default_dir]
|
|
120
127
|
return [default_dir, *[str(path) for path in skill_dirs]]
|
|
@@ -423,9 +423,9 @@ def render_brand_text(state: TuiState | None = None, width: int = 100) -> str:
|
|
|
423
423
|
"""Render the compact app brand block."""
|
|
424
424
|
W = max(72, min(width, 180))
|
|
425
425
|
brand_line = (
|
|
426
|
-
"[bold #c9a6ff]
|
|
426
|
+
"[bold #c9a6ff]YYCode[/] "
|
|
427
427
|
"[#7f8794]code assistant[/] "
|
|
428
|
-
"[#3f4652]" + ("─" * max(4, W -
|
|
428
|
+
"[#3f4652]" + ("─" * max(4, W - 26)) + "[/]"
|
|
429
429
|
)
|
|
430
430
|
if state is None:
|
|
431
431
|
return brand_line
|
|
@@ -1275,7 +1275,7 @@ def _render_timeline_item(item: TimelineItem, state: TuiState | None = None, *,
|
|
|
1275
1275
|
if item.event_type == "context_compressed":
|
|
1276
1276
|
return f"{role_prefix}[#7f8794][context] {_safe_text(item.content)}[/]"
|
|
1277
1277
|
if item.event_type == "context_summarized":
|
|
1278
|
-
return f"{role_prefix}[#
|
|
1278
|
+
return f"{role_prefix}[#7f8794][context] {_safe_text(item.content)}[/]"
|
|
1279
1279
|
if item.event_type == "llm_waiting":
|
|
1280
1280
|
return _render_llm_waiting_item(item, role_prefix, state)
|
|
1281
1281
|
if item.event_type == "llm_timeout":
|
|
@@ -1598,19 +1598,13 @@ def _is_task_state_result(item: TimelineItem) -> bool:
|
|
|
1598
1598
|
|
|
1599
1599
|
def _render_task_state_summary(role_prefix: str, item: TimelineItem) -> str:
|
|
1600
1600
|
counts = _task_state_counts(item.content)
|
|
1601
|
-
|
|
1601
|
+
parts = [f"{role_prefix}[bold #8fd6a3]● Plan Progress[/]"]
|
|
1602
1602
|
if counts["total"]:
|
|
1603
|
-
|
|
1604
|
-
if counts["active"]:
|
|
1605
|
-
summary += " · current"
|
|
1606
|
-
lines = [
|
|
1607
|
-
f"{role_prefix}[bold #8fd6a3]● Task Plan[/]",
|
|
1608
|
-
f" [#7f8794]{_safe_text(summary)}[/]",
|
|
1609
|
-
]
|
|
1603
|
+
parts.append(f"[#7f8794]{counts['completed']}/{counts['total']} done[/]")
|
|
1610
1604
|
if counts["active"]:
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
return "
|
|
1605
|
+
parts.append(f"[#d7dae0]{_safe_text(counts['active'])}[/]")
|
|
1606
|
+
parts.append("[#7f8794][Ctrl+T][/]")
|
|
1607
|
+
return " [#7f8794]·[/] ".join(parts)
|
|
1614
1608
|
|
|
1615
1609
|
|
|
1616
1610
|
def _task_state_counts(content: str) -> dict[str, int | str]:
|
|
@@ -385,7 +385,7 @@ class TuiState:
|
|
|
385
385
|
continue
|
|
386
386
|
if item.event_type == "llm_waiting" and item.status in {"running", "retrying", "timeout", None}:
|
|
387
387
|
item.status = "completed"
|
|
388
|
-
item.title = "
|
|
388
|
+
item.title = "Thinking"
|
|
389
389
|
item.invalidate_render_cache()
|
|
390
390
|
return
|
|
391
391
|
if item.event_type in {"text_delta", "tool_start", "tool_result", "tool_end", "user_message"}:
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
Screen {
|
|
2
|
+
layout: vertical;
|
|
3
|
+
background: #101216;
|
|
4
|
+
color: #d7dae0;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
#root-layout {
|
|
8
|
+
height: 1fr;
|
|
9
|
+
width: 1fr;
|
|
10
|
+
margin: 0 0;
|
|
11
|
+
padding: 1 2;
|
|
12
|
+
background: #101216;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
#top-panel {
|
|
16
|
+
height: 3;
|
|
17
|
+
padding: 0 0;
|
|
18
|
+
color: #e6e8ee;
|
|
19
|
+
background: #101216;
|
|
20
|
+
margin-bottom: 1;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
#timeline-panel {
|
|
24
|
+
height: 1fr;
|
|
25
|
+
padding: 0 0;
|
|
26
|
+
background: #101216;
|
|
27
|
+
color: #d7dae0;
|
|
28
|
+
margin-bottom: 1;
|
|
29
|
+
border: none;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
#timeline-panel.selectable {
|
|
33
|
+
background: #101216;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
#timeline-panel.selectable:focus {
|
|
37
|
+
background: #121419;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
#skill-completion {
|
|
41
|
+
display: none;
|
|
42
|
+
height: auto;
|
|
43
|
+
max-height: 10;
|
|
44
|
+
margin-bottom: 1;
|
|
45
|
+
padding: 1 2;
|
|
46
|
+
border: round #3f4652;
|
|
47
|
+
background: #14171d;
|
|
48
|
+
color: #d7dae0;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
#input-shell {
|
|
52
|
+
height: 8;
|
|
53
|
+
background: #101216;
|
|
54
|
+
margin-top: 1;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
#input-shell.approving {
|
|
58
|
+
height: 6;
|
|
59
|
+
background: #101216;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
#input-top-rule,
|
|
63
|
+
#input-bottom-rule {
|
|
64
|
+
height: 1;
|
|
65
|
+
color: #3f4652;
|
|
66
|
+
background: #101216;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
#input-shell.approving #input-top-rule,
|
|
70
|
+
#input-shell.approving #input-bottom-rule {
|
|
71
|
+
color: #d7ba7d;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
#approval-inline {
|
|
75
|
+
display: none;
|
|
76
|
+
height: 5;
|
|
77
|
+
padding: 0 0;
|
|
78
|
+
background: transparent;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
#input-status-bar {
|
|
82
|
+
height: 1;
|
|
83
|
+
color: #d7dae0;
|
|
84
|
+
background: #101216;
|
|
85
|
+
padding: 0 0;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
#input-row {
|
|
89
|
+
height: 5;
|
|
90
|
+
background: #101216;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
#input-prompt {
|
|
94
|
+
height: 5;
|
|
95
|
+
color: #c9a6ff;
|
|
96
|
+
padding: 0 0;
|
|
97
|
+
width: 3;
|
|
98
|
+
background: #101216;
|
|
99
|
+
content-align: left top;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
#prompt-input {
|
|
103
|
+
height: 5;
|
|
104
|
+
border: none;
|
|
105
|
+
background: #101216;
|
|
106
|
+
color: #e6e8ee;
|
|
107
|
+
padding: 0 0;
|
|
108
|
+
width: 1fr;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
#help-dialog {
|
|
112
|
+
width: 1fr;
|
|
113
|
+
height: 1fr;
|
|
114
|
+
margin: 1 2;
|
|
115
|
+
padding: 1 2;
|
|
116
|
+
border: round #3f4652;
|
|
117
|
+
background: #101216;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
#help-body {
|
|
121
|
+
width: 1fr;
|
|
122
|
+
height: 1fr;
|
|
123
|
+
color: #d7dae0;
|
|
124
|
+
background: #101216;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
#task-plan-dialog {
|
|
128
|
+
width: 1fr;
|
|
129
|
+
height: 1fr;
|
|
130
|
+
margin: 1 2;
|
|
131
|
+
padding: 1 2;
|
|
132
|
+
border: round #3f4652;
|
|
133
|
+
background: #101216;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
#task-plan-body {
|
|
137
|
+
width: 1fr;
|
|
138
|
+
height: 1fr;
|
|
139
|
+
color: #d7dae0;
|
|
140
|
+
background: #101216;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
#timeline-text-dialog {
|
|
144
|
+
width: 1fr;
|
|
145
|
+
height: 1fr;
|
|
146
|
+
margin: 1 2;
|
|
147
|
+
padding: 1 2;
|
|
148
|
+
border: round #3f4652;
|
|
149
|
+
background: #101216;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
#timeline-text-header {
|
|
153
|
+
width: 1fr;
|
|
154
|
+
height: 1;
|
|
155
|
+
color: #7f8794;
|
|
156
|
+
background: #101216;
|
|
157
|
+
margin-bottom: 1;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
#timeline-text-body {
|
|
161
|
+
width: 1fr;
|
|
162
|
+
height: 1fr;
|
|
163
|
+
color: #d7dae0;
|
|
164
|
+
background: #101216;
|
|
165
|
+
scrollbar-size: 1 1;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
#changed-files-dialog {
|
|
169
|
+
width: 1fr;
|
|
170
|
+
height: 1fr;
|
|
171
|
+
margin: 1 2;
|
|
172
|
+
padding: 1 2;
|
|
173
|
+
border: round #3f4652;
|
|
174
|
+
background: #101216;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
#changed-files-header {
|
|
178
|
+
width: 1fr;
|
|
179
|
+
height: 1;
|
|
180
|
+
color: #d7dae0;
|
|
181
|
+
background: #101216;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
#changed-files-split {
|
|
185
|
+
width: 1fr;
|
|
186
|
+
height: 1fr;
|
|
187
|
+
background: #101216;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
#changed-files-list {
|
|
191
|
+
width: 36;
|
|
192
|
+
height: 1fr;
|
|
193
|
+
background: #101216;
|
|
194
|
+
color: #d7dae0;
|
|
195
|
+
scrollbar-size: 1 1;
|
|
196
|
+
margin-right: 1;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
#changed-files-diff {
|
|
200
|
+
width: 1fr;
|
|
201
|
+
height: 1fr;
|
|
202
|
+
color: #d7dae0;
|
|
203
|
+
background: #101216;
|
|
204
|
+
scrollbar-size: 1 1;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
#message-token-dialog {
|
|
208
|
+
width: 1fr;
|
|
209
|
+
height: 1fr;
|
|
210
|
+
margin: 1 2;
|
|
211
|
+
padding: 1 2;
|
|
212
|
+
border: round #3f4652;
|
|
213
|
+
background: #101216;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
#message-token-header {
|
|
217
|
+
width: 1fr;
|
|
218
|
+
height: 3;
|
|
219
|
+
padding: 0 1;
|
|
220
|
+
color: #d7dae0;
|
|
221
|
+
background: #14171d;
|
|
222
|
+
border: round #2f3540;
|
|
223
|
+
margin-bottom: 1;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
#message-token-split {
|
|
227
|
+
width: 1fr;
|
|
228
|
+
height: 1fr;
|
|
229
|
+
background: #101216;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
#message-token-list {
|
|
233
|
+
width: 52;
|
|
234
|
+
height: 1fr;
|
|
235
|
+
background: #101216;
|
|
236
|
+
color: #d7dae0;
|
|
237
|
+
scrollbar-size: 1 1;
|
|
238
|
+
margin-right: 1;
|
|
239
|
+
border: round #2f3540;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
#message-token-list:focus {
|
|
243
|
+
border: round #c9a6ff;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
#message-token-detail {
|
|
247
|
+
width: 1fr;
|
|
248
|
+
height: 1fr;
|
|
249
|
+
color: #d7dae0;
|
|
250
|
+
background: #101216;
|
|
251
|
+
scrollbar-size: 1 1;
|
|
252
|
+
border: round #2f3540;
|
|
253
|
+
padding: 1 2;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
#message-token-footer {
|
|
257
|
+
width: 1fr;
|
|
258
|
+
height: 1;
|
|
259
|
+
color: #7f8794;
|
|
260
|
+
background: #101216;
|
|
261
|
+
margin-top: 1;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
#approval-title {
|
|
265
|
+
width: 1fr;
|
|
266
|
+
height: 1;
|
|
267
|
+
color: #e6e8ee;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
#approval-detail {
|
|
271
|
+
width: 1fr;
|
|
272
|
+
height: 2;
|
|
273
|
+
color: #d7dae0;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
#approval-actions {
|
|
277
|
+
width: 1fr;
|
|
278
|
+
height: 1;
|
|
279
|
+
color: #7f8794;
|
|
280
|
+
}
|
|
@@ -14,7 +14,12 @@ from dotenv import load_dotenv
|
|
|
14
14
|
|
|
15
15
|
from agent import Session
|
|
16
16
|
from agent.approval import ApprovalRequest
|
|
17
|
-
from agent.app_paths import
|
|
17
|
+
from agent.app_paths import (
|
|
18
|
+
resolve_app_root,
|
|
19
|
+
resolve_resource_root,
|
|
20
|
+
resolve_runtime_data_dir,
|
|
21
|
+
sync_default_skills_dir,
|
|
22
|
+
)
|
|
18
23
|
from agent.logger import setup_logging
|
|
19
24
|
from agent.session_store import FileSessionStore
|
|
20
25
|
from agent.streaming import colorize_diff
|
|
@@ -221,11 +226,12 @@ Examples:
|
|
|
221
226
|
yycode -r bugfix-123
|
|
222
227
|
yycode -x bugfix-123
|
|
223
228
|
yycode ~/project -t
|
|
229
|
+
yycode --update-skills
|
|
224
230
|
yycode -a
|
|
225
231
|
yycode --plain
|
|
226
232
|
|
|
227
233
|
Session data:
|
|
228
|
-
Messages are saved by default under {
|
|
234
|
+
Messages are saved by default under {data_dir}/sessions/{workspace_hash}/{session_id}.json.
|
|
229
235
|
Use -s/--sessions to inspect saved sessions for WORKDIR.
|
|
230
236
|
Use -r/--resume ID to continue a previous conversation in the same workspace.
|
|
231
237
|
Use -x/--delete ID to delete a saved session for WORKDIR.
|
|
@@ -235,10 +241,10 @@ Environment:
|
|
|
235
241
|
API_KEY API key for the selected provider.
|
|
236
242
|
API_BASE Optional custom API base URL.
|
|
237
243
|
AI_MODEL Model name override.
|
|
238
|
-
YOYO_APP_ROOT
|
|
239
|
-
YOYO_RUNTIME_DATA_DIR
|
|
244
|
+
YOYO_APP_ROOT Bundled yycode resource root override.
|
|
245
|
+
YOYO_RUNTIME_DATA_DIR User data directory; skills, sessions, and logs live here.
|
|
240
246
|
YOYO_SESSION_DIR Session messages directory override.
|
|
241
|
-
YOYO_SKILL_DIRS Extra skill directories
|
|
247
|
+
YOYO_SKILL_DIRS Extra skill directories appended after {data_dir}/skills.
|
|
242
248
|
YOYO_CONTEXT_WINDOW_TOKENS Context window size override for token pressure.
|
|
243
249
|
YOYO_SILENT Auto-approve risky actions when truthy.
|
|
244
250
|
YOYO_AUTO_APPROVE Alias for YOYO_SILENT.
|
|
@@ -321,6 +327,11 @@ Environment:
|
|
|
321
327
|
metavar="ID",
|
|
322
328
|
help="Delete a persisted session id for WORKDIR and exit.",
|
|
323
329
|
)
|
|
330
|
+
parser.add_argument(
|
|
331
|
+
"--update-skills",
|
|
332
|
+
action="store_true",
|
|
333
|
+
help="Copy bundled skills into the user data skills directory, overwriting matching files.",
|
|
334
|
+
)
|
|
324
335
|
parser.add_argument(
|
|
325
336
|
"--no-persist",
|
|
326
337
|
dest="temp",
|
|
@@ -389,6 +400,25 @@ def delete_session_for_workdir(workdir: Path, session_id: str) -> str:
|
|
|
389
400
|
return f"Deleted session for workspace {workdir}: {session_id}"
|
|
390
401
|
|
|
391
402
|
|
|
403
|
+
def update_default_skills() -> str:
|
|
404
|
+
"""Overwrite user data skills with bundled defaults where bundled files exist."""
|
|
405
|
+
app_root = resolve_app_root()
|
|
406
|
+
resource_root = resolve_resource_root(app_root)
|
|
407
|
+
runtime_data_dir = resolve_runtime_data_dir(app_root)
|
|
408
|
+
result = sync_default_skills_dir(runtime_data_dir, resource_root)
|
|
409
|
+
lines = [
|
|
410
|
+
"Updated yycode skills.",
|
|
411
|
+
f"Source: {result.source_dir}",
|
|
412
|
+
f"Target: {result.target_dir}",
|
|
413
|
+
f"Copied: {len(result.copied)}",
|
|
414
|
+
f"Updated: {len(result.updated)}",
|
|
415
|
+
f"Unchanged: {len(result.skipped)}",
|
|
416
|
+
]
|
|
417
|
+
preserved_note = "User-created files without matching bundled paths were preserved."
|
|
418
|
+
lines.append(preserved_note)
|
|
419
|
+
return "\n".join(lines)
|
|
420
|
+
|
|
421
|
+
|
|
392
422
|
def create_session_store_for_workdir(workdir: Path) -> FileSessionStore:
|
|
393
423
|
"""Create the default file session store for a workspace."""
|
|
394
424
|
app_root = resolve_app_root()
|
|
@@ -420,6 +450,9 @@ def main() -> None:
|
|
|
420
450
|
parser = build_arg_parser()
|
|
421
451
|
args = parser.parse_args()
|
|
422
452
|
log_file_path = resolve_log_file_path()
|
|
453
|
+
if args.update_skills:
|
|
454
|
+
print(update_default_skills())
|
|
455
|
+
return
|
|
423
456
|
if args.acp or args.workdir == "acp":
|
|
424
457
|
setup_logging(debug=args.debug, log_to_file=args.log_file, log_file=log_file_path)
|
|
425
458
|
load_dotenv(override=True)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "yycode"
|
|
3
|
-
version = "0.3.
|
|
3
|
+
version = "0.3.4"
|
|
4
4
|
description = "Terminal coding agent with TUI, plain input mode, tools, skills, and ACP support"
|
|
5
5
|
requires-python = ">=3.10"
|
|
6
6
|
dependencies = [
|
|
@@ -10,7 +10,7 @@ dependencies = [
|
|
|
10
10
|
"langgraph>=0.2.0",
|
|
11
11
|
"langchain-core>=0.3.0",
|
|
12
12
|
"python-dotenv>=1.0.0",
|
|
13
|
-
"textual
|
|
13
|
+
"textual==8.2.4"
|
|
14
14
|
]
|
|
15
15
|
|
|
16
16
|
[project.scripts]
|
|
@@ -23,6 +23,9 @@ py-modules = ["main"]
|
|
|
23
23
|
include = ["agent*", "tools*", "utils*"]
|
|
24
24
|
exclude = ["sessions*", "output*", "tests*", "examples*", "docs*", "changes*"]
|
|
25
25
|
|
|
26
|
+
[tool.setuptools.package-data]
|
|
27
|
+
"agent.tui" = ["*.tcss"]
|
|
28
|
+
|
|
26
29
|
[tool.setuptools.data-files]
|
|
27
30
|
"skills" = ["skills/*.md"]
|
|
28
31
|
"skills/drawio" = ["skills/drawio/SKILL.md"]
|
|
@@ -31,7 +34,8 @@ exclude = ["sessions*", "output*", "tests*", "examples*", "docs*", "changes*"]
|
|
|
31
34
|
"skills/drawio/assets" = ["skills/drawio/assets/*"]
|
|
32
35
|
"skills/drawio/docs" = ["skills/drawio/docs/*"]
|
|
33
36
|
"skills/drawio/references" = ["skills/drawio/references/*"]
|
|
34
|
-
"skills/drawio/styles" = ["skills/drawio/styles
|
|
37
|
+
"skills/drawio/styles" = ["skills/drawio/styles/*.json"]
|
|
38
|
+
"skills/drawio/styles/built-in" = ["skills/drawio/styles/built-in/*.json"]
|
|
35
39
|
|
|
36
40
|
[tool.ruff]
|
|
37
41
|
line-length = 100
|