bone-agent 1.4.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/bin/bone.js +39 -0
  2. package/package.json +25 -39
  3. package/LICENSE +0 -21
  4. package/README.md +0 -201
  5. package/bin/npm-wrapper.js +0 -235
  6. package/bin/rg +0 -0
  7. package/bin/rg.exe +0 -0
  8. package/config.yaml.example +0 -144
  9. package/prompts/main/ask_questions.md +0 -31
  10. package/prompts/main/batch_independent_calls.md +0 -5
  11. package/prompts/main/casual_interactions.md +0 -11
  12. package/prompts/main/code_references.md +0 -8
  13. package/prompts/main/communication_style.md +0 -12
  14. package/prompts/main/context_reliability.md +0 -12
  15. package/prompts/main/conversational_tool_calling.md +0 -15
  16. package/prompts/main/dream.md +0 -50
  17. package/prompts/main/editing_pattern.md +0 -13
  18. package/prompts/main/error_handling.md +0 -6
  19. package/prompts/main/exploration_pattern.md +0 -21
  20. package/prompts/main/intro.md +0 -1
  21. package/prompts/main/obsidian.md +0 -16
  22. package/prompts/main/obsidian_project.md +0 -79
  23. package/prompts/main/professional_objectivity.md +0 -3
  24. package/prompts/main/skills.md +0 -3
  25. package/prompts/main/targeted_searching.md +0 -10
  26. package/prompts/main/task_lists_pattern.md +0 -8
  27. package/prompts/main/temp_folder.md +0 -9
  28. package/prompts/main/think_before_acting.md +0 -10
  29. package/prompts/main/tone_and_style.md +0 -4
  30. package/prompts/main/tool_preferences.md +0 -24
  31. package/prompts/main/trust_subagent_context.md +0 -21
  32. package/prompts/main/when_to_use_sub_agent.md +0 -7
  33. package/prompts/micro/ask_questions.md +0 -1
  34. package/prompts/micro/batch_independent_calls.md +0 -1
  35. package/prompts/micro/casual_interactions.md +0 -1
  36. package/prompts/micro/code_references.md +0 -1
  37. package/prompts/micro/communication_style.md +0 -1
  38. package/prompts/micro/context_reliability.md +0 -1
  39. package/prompts/micro/conversational_tool_calling.md +0 -1
  40. package/prompts/micro/editing_pattern.md +0 -1
  41. package/prompts/micro/error_handling.md +0 -1
  42. package/prompts/micro/exploration_pattern.md +0 -1
  43. package/prompts/micro/intro.md +0 -1
  44. package/prompts/micro/obsidian.md +0 -4
  45. package/prompts/micro/obsidian_project.md +0 -5
  46. package/prompts/micro/professional_objectivity.md +0 -1
  47. package/prompts/micro/skills.md +0 -1
  48. package/prompts/micro/targeted_searching.md +0 -1
  49. package/prompts/micro/task_lists_pattern.md +0 -1
  50. package/prompts/micro/temp_folder.md +0 -1
  51. package/prompts/micro/think_before_acting.md +0 -5
  52. package/prompts/micro/tone_and_style.md +0 -1
  53. package/prompts/micro/tool_preferences.md +0 -1
  54. package/prompts/micro/trust_subagent_context.md +0 -1
  55. package/prompts/micro/when_to_use_sub_agent.md +0 -1
  56. package/requirements.txt +0 -9
  57. package/src/__init__.py +0 -11
  58. package/src/core/__init__.py +0 -1
  59. package/src/core/agentic.py +0 -1085
  60. package/src/core/chat_manager.py +0 -1577
  61. package/src/core/config_manager.py +0 -260
  62. package/src/core/cron.py +0 -578
  63. package/src/core/cron_allowlist.py +0 -118
  64. package/src/core/memory.py +0 -145
  65. package/src/core/metadata.py +0 -75
  66. package/src/core/retry.py +0 -71
  67. package/src/core/skills.py +0 -463
  68. package/src/core/sub_agent.py +0 -376
  69. package/src/core/tool_approval.py +0 -220
  70. package/src/core/tool_feedback.py +0 -789
  71. package/src/exceptions.py +0 -79
  72. package/src/llm/__init__.py +0 -1
  73. package/src/llm/client.py +0 -176
  74. package/src/llm/codex_provider.py +0 -350
  75. package/src/llm/config.py +0 -536
  76. package/src/llm/prompts.py +0 -494
  77. package/src/llm/providers.py +0 -438
  78. package/src/llm/streaming.py +0 -163
  79. package/src/llm/token_tracker.py +0 -399
  80. package/src/tools/__init__.py +0 -151
  81. package/src/tools/constants.py +0 -59
  82. package/src/tools/create_file.py +0 -136
  83. package/src/tools/directory.py +0 -389
  84. package/src/tools/edit.py +0 -549
  85. package/src/tools/file_reader.py +0 -322
  86. package/src/tools/helpers/__init__.py +0 -99
  87. package/src/tools/helpers/base.py +0 -599
  88. package/src/tools/helpers/converters.py +0 -44
  89. package/src/tools/helpers/file_helpers.py +0 -189
  90. package/src/tools/helpers/formatters.py +0 -411
  91. package/src/tools/helpers/loader.py +0 -145
  92. package/src/tools/helpers/parallel_executor.py +0 -231
  93. package/src/tools/helpers/path_resolver.py +0 -283
  94. package/src/tools/helpers/plugin_manifest.py +0 -185
  95. package/src/tools/obsidian.py +0 -96
  96. package/src/tools/review_sub_agent.py +0 -190
  97. package/src/tools/rg_search.py +0 -477
  98. package/src/tools/search_plugins.py +0 -177
  99. package/src/tools/select_option.py +0 -600
  100. package/src/tools/shell.py +0 -302
  101. package/src/tools/sub_agent.py +0 -139
  102. package/src/tools/task_list.py +0 -269
  103. package/src/tools/web_search.py +0 -61
  104. package/src/ui/__init__.py +0 -1
  105. package/src/ui/banner.py +0 -87
  106. package/src/ui/commands.py +0 -3131
  107. package/src/ui/displays.py +0 -239
  108. package/src/ui/loader.py +0 -284
  109. package/src/ui/main.py +0 -643
  110. package/src/ui/prompt_utils.py +0 -113
  111. package/src/ui/setting_selector.py +0 -590
  112. package/src/ui/setup_wizard.py +0 -294
  113. package/src/ui/sub_agent_panel.py +0 -234
  114. package/src/ui/tool_confirmation.py +0 -226
  115. package/src/utils/__init__.py +0 -1
  116. package/src/utils/citation_parser.py +0 -199
  117. package/src/utils/editor.py +0 -207
  118. package/src/utils/gitignore_filter.py +0 -149
  119. package/src/utils/logger.py +0 -254
  120. package/src/utils/paths.py +0 -30
  121. package/src/utils/result_parsers.py +0 -108
  122. package/src/utils/safe_commands.py +0 -243
  123. package/src/utils/settings.py +0 -195
  124. package/src/utils/user_message_logger.py +0 -120
  125. package/src/utils/validation.py +0 -201
  126. package/src/utils/web_search.py +0 -173
@@ -1,260 +0,0 @@
1
-
2
-
3
- from pathlib import Path
4
- import shutil
5
- from typing import Dict, Any, Optional
6
- import logging
7
- import yaml
8
- from llm import config as llm_config
9
-
10
- logger = logging.getLogger(__name__)
11
-
12
-
13
- class ConfigManager:
14
-
15
- def __init__(self, config_path: Optional[Path] = None):
16
- self.config_path = config_path or llm_config.CONFIG_PATH
17
- self._cached_data = None
18
-
19
- def load(self, force_reload: bool = False) -> Dict[str, Any]:
20
- """Load configuration from file, using cache if available.
21
-
22
- Args:
23
- force_reload: If True, bypass cache and reload from disk
24
-
25
- Returns:
26
- Configuration dictionary
27
- """
28
- if not force_reload and self._cached_data is not None:
29
- return self._cached_data
30
-
31
- if not self.config_path.exists():
32
- self._cached_data = llm_config.generate_config_template()
33
- return self._cached_data
34
-
35
- try:
36
- with open(self.config_path, 'r', encoding='utf-8-sig') as f:
37
- self._cached_data = yaml.safe_load(f) or {}
38
-
39
- # Migrate legacy provider IDs to current names.
40
- old_provider = self._cached_data.get('LAST_PROVIDER')
41
- if old_provider in ('vmcode_proxy', 'vmcode_free', 'vmcode'):
42
- logger.info("Migrating provider name '%s' -> 'bone'", old_provider)
43
- self._cached_data['LAST_PROVIDER'] = 'bone'
44
- self.save(self._cached_data, create_backup=True)
45
- elif old_provider == 'codex_plan':
46
- logger.info("Migrating provider name '%s' -> 'codex'", old_provider)
47
- self._cached_data['LAST_PROVIDER'] = 'codex'
48
- self.save(self._cached_data, create_backup=True)
49
-
50
- return self._cached_data
51
- except yaml.YAMLError as e:
52
- logger.error(f"Failed to parse config file {self.config_path}: {e}")
53
- logger.warning("Using default configuration template")
54
- self._cached_data = llm_config.generate_config_template()
55
- return self._cached_data
56
-
57
- def save(self, config_data: Dict[str, Any], create_backup: bool = False):
58
- if create_backup and self.config_path.exists():
59
- backup_path = self.config_path.with_suffix('.backup')
60
- shutil.copy2(self.config_path, backup_path)
61
-
62
- with open(self.config_path, 'w', encoding='utf-8-sig') as f:
63
- yaml.dump(config_data, f, default_flow_style=False, sort_keys=False, allow_unicode=True)
64
-
65
- self._cached_data = config_data
66
- # Note: Config is read from disk on reload. Call reload_config() after changes.
67
-
68
- def update_field(self, key: str, value: Any, create_backup: bool = False) -> Optional[Path]:
69
- """Update a single configuration field.
70
-
71
- Args:
72
- key: Configuration key to update
73
- value: New value for the key
74
- create_backup: If True, create a backup before saving
75
-
76
- Returns:
77
- Backup path if backup was created, None otherwise
78
- """
79
- config_data = self.load(force_reload=True)
80
- config_data[key] = value
81
-
82
- backup_path = None
83
- if create_backup and self.config_path.exists():
84
- backup_path = self.config_path.with_suffix('.backup')
85
-
86
- self.save(config_data, create_backup=create_backup)
87
- return backup_path
88
-
89
- def set_provider(self, provider_name: str) -> Optional[Path]:
90
- return self.update_field('LAST_PROVIDER', provider_name)
91
-
92
- def _extract_model_pricing(self, model_name: str, config: Dict[str, Any] | None = None) -> Dict[str, float]:
93
- """Extract pricing for a model from MODEL_PRICES.
94
-
95
- Delegates to llm_config.get_model_cost() — single source of truth.
96
- """
97
- cost_in, cost_out = llm_config.get_model_cost(model_name, config=config)
98
- return {'in': cost_in, 'out': cost_out}
99
-
100
- def get_usage_costs(self, provider: str = None, model: str = None) -> Dict[str, float]:
101
- """Get usage costs for a specific model.
102
-
103
- Args:
104
- provider: Provider name (e.g., 'openrouter', 'glm', 'openai').
105
- If None, uses the last provider from config.
106
- model: Model name (e.g., 'minimax/minimax-m2.5', 'GLM-4.7').
107
- If None, uses the current model from the provider.
108
-
109
- Returns:
110
- Dict with 'in' and 'out' cost values per 1M tokens
111
- """
112
- config_data = self.load()
113
-
114
- if provider is None:
115
- provider = config_data.get('LAST_PROVIDER', 'glm')
116
-
117
- # Get model name from config if not provided
118
- if model is None:
119
- provider_model_map = {
120
- 'bone': 'BONE_PROXY_MODEL',
121
- 'codex': 'CODEX_PLAN_MODEL',
122
- 'openrouter': 'OPENROUTER_MODEL',
123
- 'glm': 'GLM_MODEL',
124
- 'glm_plan': 'GLM_PLAN_MODEL',
125
- 'openai': 'OPENAI_MODEL',
126
- 'gemini': 'GEMINI_MODEL',
127
- 'minimax': 'MINIMAX_MODEL',
128
- 'minimax_plan': 'MINIMAX_PLAN_MODEL',
129
- 'anthropic': 'ANTHROPIC_MODEL',
130
- 'kimi': 'KIMI_MODEL'
131
- }
132
- model_key = provider_model_map.get(provider.lower())
133
- if model_key:
134
- model = config_data.get(model_key, '')
135
-
136
- return self._extract_model_pricing(model, config=config_data)
137
-
138
- def set_model(self, provider_name: str, model: str) -> Optional[Path]:
139
- """Set model for a specific provider.
140
-
141
- Args:
142
- provider_name: Provider name (e.g., 'openrouter', 'glm', 'local', 'openai')
143
- model: Model name/path to set
144
-
145
- Returns:
146
- Backup path if backup was created, None otherwise
147
- """
148
- # Map provider names to their config keys
149
- provider_keys = {
150
- 'local': 'LOCAL_MODEL_PATH',
151
- 'bone': 'BONE_PROXY_MODEL',
152
- 'codex': 'CODEX_PLAN_MODEL',
153
- 'openrouter': 'OPENROUTER_MODEL',
154
- 'glm': 'GLM_MODEL',
155
- 'glm_plan': 'GLM_PLAN_MODEL',
156
- 'openai': 'OPENAI_MODEL',
157
- 'gemini': 'GEMINI_MODEL',
158
- 'minimax': 'MINIMAX_MODEL',
159
- 'minimax_plan': 'MINIMAX_PLAN_MODEL',
160
- 'anthropic': 'ANTHROPIC_MODEL',
161
- 'kimi': 'KIMI_MODEL'
162
- }
163
-
164
- if provider_name not in provider_keys:
165
- raise ValueError(f"Unknown provider: {provider_name}")
166
-
167
- key = provider_keys[provider_name]
168
- return self.update_field(key, model)
169
-
170
- def set_api_key(self, provider_name: str, api_key: str) -> Optional[Path]:
171
- """Set API key for a specific provider.
172
-
173
- Args:
174
- provider_name: Provider name (e.g., 'openrouter', 'glm', 'openai')
175
- api_key: API key to set
176
-
177
- Returns:
178
- Backup path if backup was created, None otherwise
179
- """
180
- # Map provider names to their config keys
181
- provider_keys = {
182
- 'openrouter': 'OPENROUTER_API_KEY',
183
- 'bone': 'BONE_PROXY_API_KEY',
184
- 'codex': 'CODEX_PLAN_API_KEY',
185
- 'glm': 'GLM_API_KEY',
186
- 'glm_plan': 'GLM_PLAN_API_KEY',
187
- 'openai': 'OPENAI_API_KEY',
188
- 'gemini': 'GEMINI_API_KEY',
189
- 'minimax': 'MINIMAX_API_KEY',
190
- 'minimax_plan': 'MINIMAX_PLAN_API_KEY',
191
- 'anthropic': 'ANTHROPIC_API_KEY',
192
- 'kimi': 'KIMI_API_KEY'
193
- }
194
-
195
- if provider_name not in provider_keys:
196
- raise ValueError(f"Unknown provider: {provider_name}")
197
-
198
- key = provider_keys[provider_name]
199
- return self.update_field(key, api_key)
200
-
201
- def get_model_price(self, model_name: str) -> Dict[str, float]:
202
- """Get pricing for a specific model.
203
-
204
- Args:
205
- model_name: Model name (e.g., 'minimax/minimax-m2.5', 'GLM-4.7')
206
-
207
- Returns:
208
- Dict with 'in' and 'out' cost values per 1M tokens
209
- """
210
- config_data = self.load()
211
- return self._extract_model_pricing(model_name, config=config_data)
212
-
213
- def set_model_price(self, model_name: str, cost_in: float, cost_out: float) -> Optional[Path]:
214
- """Set pricing for a specific model.
215
-
216
- Args:
217
- model_name: Model name (e.g., 'minimax/minimax-m2.5', 'GLM-4.7')
218
- cost_in: Cost per 1M input tokens
219
- cost_out: Cost per 1M output tokens
220
-
221
- Returns:
222
- Backup path if backup was created, None otherwise
223
- """
224
- config_data = self.load(force_reload=True)
225
-
226
- if 'MODEL_PRICES' not in config_data:
227
- config_data['MODEL_PRICES'] = {}
228
-
229
- config_data['MODEL_PRICES'][model_name] = {
230
- 'cost_in': cost_in,
231
- 'cost_out': cost_out
232
- }
233
-
234
- return self.save(config_data, create_backup=False)
235
-
236
- def list_model_prices(self) -> Dict[str, Dict[str, float]]:
237
- """Get all model-specific pricing.
238
-
239
- Returns:
240
- Dict mapping model names to their pricing (cost_in/cost_out per 1M tokens)
241
- """
242
- config_data = self.load()
243
- return config_data.get('MODEL_PRICES', {})
244
-
245
- def delete_model_price(self, model_name: str) -> Optional[Path]:
246
- """Delete pricing for a specific model.
247
-
248
- Args:
249
- model_name: Model name to remove from pricing
250
-
251
- Returns:
252
- Backup path if backup was created, None otherwise
253
- """
254
- config_data = self.load(force_reload=True)
255
-
256
- if 'MODEL_PRICES' in config_data and model_name in config_data['MODEL_PRICES']:
257
- del config_data['MODEL_PRICES'][model_name]
258
- return self.save(config_data, create_backup=False)
259
-
260
- return None