-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathcommand_registry.cpp
More file actions
117 lines (103 loc) · 4.1 KB
/
Copy pathcommand_registry.cpp
File metadata and controls
117 lines (103 loc) · 4.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include "command_registry.hpp"
#include "opencode_command_registry.hpp"
#include "../skills/skill_activation.hpp"
#include "../skills/skill_commands.hpp"
#include "../skills/skill_registry.hpp"
#include "../utils/logger.hpp"
#include <chrono>
#include <exception>
#include <mutex>
#include <sstream>
namespace acecode {
namespace {
void notify_command_recognized(CommandContext& ctx,
const std::string& command_name) {
if (!ctx.on_command_recognized) return;
try {
ctx.on_command_recognized(command_name);
} catch (const std::exception& e) {
LOG_WARN(std::string("[commands] command observer failed: ") + e.what());
} catch (...) {
LOG_WARN("[commands] command observer failed with unknown exception");
}
}
} // namespace
void CommandRegistry::register_command(const SlashCommand& cmd) {
commands_[cmd.name] = cmd;
}
bool CommandRegistry::unregister_command(const std::string& name) {
auto it = commands_.find(name);
if (it == commands_.end()) return false;
commands_.erase(it);
return true;
}
bool CommandRegistry::dispatch(const std::string& input, CommandContext& ctx) {
if (input.empty() || input[0] != '/') return false;
// Parse: "/command args..."
std::string trimmed = input.substr(1); // remove leading '/'
std::string cmd_name;
std::string args;
size_t space_pos = trimmed.find(' ');
if (space_pos == std::string::npos) {
cmd_name = trimmed;
} else {
cmd_name = trimmed.substr(0, space_pos);
args = trimmed.substr(space_pos + 1);
}
auto it = commands_.find(cmd_name);
if (it == commands_.end()) {
if (!ctx.cwd.empty()) {
reload_opencode_commands(*this, ctx.config, ctx.cwd);
it = commands_.find(cmd_name);
if (it != commands_.end()) {
notify_command_recognized(ctx, cmd_name);
it->second.execute(ctx, args);
return true;
}
}
// 未命中:先就着磁盘重扫一次并重绑 skill 斜杠命令(会话进行中新写到磁盘的
// skill 才能第一次敲就用上,且回填 commands_ 让后续自动补全/`/help` 列得出),
// 然后再查一次。reload 走已测过的 reload_skill_commands(只动 skill key,
// 内建命令不受影响)。command_registry 即 *this。
if (ctx.skills) {
reload_skill_commands(*this, *ctx.skills);
it = commands_.find(cmd_name);
if (it != commands_.end()) {
notify_command_recognized(ctx, cmd_name);
it->second.execute(ctx, args);
return true;
}
}
if (ctx.skills) {
auto skill = ctx.skills->find(cmd_name);
if (skill) {
notify_command_recognized(ctx, cmd_name);
std::string message = build_skill_invocation_hint(*skill, args);
{
std::lock_guard<std::mutex> lk(ctx.state.mu);
ctx.state.conversation.push_back(
{"system", "[Invoking skill: " + skill->name + "]", false});
ctx.state.chat_follow_tail = true;
if (ctx.state.is_waiting) {
ctx.state.pending_queue.push_back(message);
return true;
}
ctx.state.thinking_start_time = std::chrono::steady_clock::now();
ctx.state.streaming_output_chars = 0;
ctx.state.turn_completion_tokens_confirmed = 0;
ctx.state.is_waiting = true;
}
submit_user_text(ctx, message);
return true;
}
}
ctx.state.conversation.push_back(
{"system", "Unknown command: /" + cmd_name + ". Type /help for available commands.", false});
ctx.state.chat_follow_tail = true;
return true; // consumed the input (even though command unknown)
}
notify_command_recognized(ctx, cmd_name);
it->second.execute(ctx, args);
return true;
}
} // namespace acecode