@ai-setting/roy-agent-cli 1.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.
- package/README.md +126 -0
- package/dist/bin/roy.js +127297 -0
- package/dist/roy-agent-darwin-arm64/bin/roy.js +127297 -0
- package/dist/roy-agent-darwin-x64/bin/roy.js +127297 -0
- package/dist/roy-agent-linux-arm64/bin/roy.js +127297 -0
- package/dist/roy-agent-linux-x64/bin/roy.js +127297 -0
- package/dist/roy-agent-windows-x64/bin/roy.js +127297 -0
- package/package.json +91 -0
- package/src/bin/roy.ts +12 -0
- package/src/cli.ts +101 -0
- package/src/commands/act.ts +480 -0
- package/src/commands/commands-add.ts +110 -0
- package/src/commands/commands-dirs.ts +70 -0
- package/src/commands/commands-info.ts +90 -0
- package/src/commands/commands-list.ts +161 -0
- package/src/commands/commands-remove.ts +147 -0
- package/src/commands/commands.ts +55 -0
- package/src/commands/config/config-service.test.ts +449 -0
- package/src/commands/config/config-service.ts +312 -0
- package/src/commands/config/deep-merge.test.ts +168 -0
- package/src/commands/config/deep-merge.ts +63 -0
- package/src/commands/config/export.ts +97 -0
- package/src/commands/config/filter-history-e2e.test.ts +141 -0
- package/src/commands/config/import-preserve-refs.test.ts +212 -0
- package/src/commands/config/import.ts +119 -0
- package/src/commands/config/index.ts +35 -0
- package/src/commands/config/list.ts +281 -0
- package/src/commands/config/roy-config-e2e.test.ts +297 -0
- package/src/commands/config/types.ts +54 -0
- package/src/commands/debug/index.ts +38 -0
- package/src/commands/debug/log.test.ts +233 -0
- package/src/commands/debug/log.ts +123 -0
- package/src/commands/debug/span.test.ts +297 -0
- package/src/commands/debug/span.ts +211 -0
- package/src/commands/debug/trace.test.ts +254 -0
- package/src/commands/debug/trace.ts +140 -0
- package/src/commands/eventsource/add.ts +133 -0
- package/src/commands/eventsource/index.ts +48 -0
- package/src/commands/eventsource/list.ts +194 -0
- package/src/commands/eventsource/remove.ts +95 -0
- package/src/commands/eventsource/start.ts +103 -0
- package/src/commands/eventsource/status.ts +185 -0
- package/src/commands/eventsource/stop.ts +89 -0
- package/src/commands/index.ts +22 -0
- package/src/commands/input-handler.test.ts +76 -0
- package/src/commands/input-handler.ts +43 -0
- package/src/commands/interactive-esc.test.ts +254 -0
- package/src/commands/interactive.shutdown.test.ts +122 -0
- package/src/commands/interactive.test.ts +221 -0
- package/src/commands/interactive.ts +1015 -0
- package/src/commands/lsp/check.ts +92 -0
- package/src/commands/lsp/index.ts +32 -0
- package/src/commands/lsp/install.ts +126 -0
- package/src/commands/lsp/list.ts +64 -0
- package/src/commands/mcp/index.ts +27 -0
- package/src/commands/mcp/list.ts +116 -0
- package/src/commands/mcp/reload.ts +70 -0
- package/src/commands/mcp/tools.ts +121 -0
- package/src/commands/memory/extract-e2e.test.ts +388 -0
- package/src/commands/memory/index.ts +11 -0
- package/src/commands/memory/memory-simplified.test.ts +58 -0
- package/src/commands/memory/memory.ts +25 -0
- package/src/commands/memory/organize.ts +300 -0
- package/src/commands/memory/recall.test.ts +120 -0
- package/src/commands/memory/recall.ts +88 -0
- package/src/commands/memory/record-extract-handle-query.test.ts +385 -0
- package/src/commands/memory/record-prompt-component.test.ts +343 -0
- package/src/commands/memory/record.test.ts +92 -0
- package/src/commands/memory/record.ts +332 -0
- package/src/commands/plugin.test.ts +292 -0
- package/src/commands/plugin.ts +267 -0
- package/src/commands/sessions/active.ts +96 -0
- package/src/commands/sessions/add-message.ts +96 -0
- package/src/commands/sessions/checkpoints.ts +154 -0
- package/src/commands/sessions/compact.test.ts +215 -0
- package/src/commands/sessions/compact.ts +269 -0
- package/src/commands/sessions/delete.ts +236 -0
- package/src/commands/sessions/get.ts +165 -0
- package/src/commands/sessions/grep.ts +233 -0
- package/src/commands/sessions/index.ts +95 -0
- package/src/commands/sessions/list.ts +210 -0
- package/src/commands/sessions/messages.test.ts +333 -0
- package/src/commands/sessions/messages.ts +248 -0
- package/src/commands/sessions/mock.ts +194 -0
- package/src/commands/sessions/new.ts +82 -0
- package/src/commands/sessions/rename.ts +98 -0
- package/src/commands/shared/event-handler.ts +213 -0
- package/src/commands/shared/event-message-formatter.ts +295 -0
- package/src/commands/shared/index.ts +11 -0
- package/src/commands/shared/query-executor.test.ts +434 -0
- package/src/commands/shared/query-executor.ts +324 -0
- package/src/commands/shared/repl-engine.test.ts +354 -0
- package/src/commands/shared/session-manager.test.ts +212 -0
- package/src/commands/shared/session-manager.ts +114 -0
- package/src/commands/skills/get.ts +90 -0
- package/src/commands/skills/index.ts +39 -0
- package/src/commands/skills/list.ts +129 -0
- package/src/commands/skills/reload.ts +59 -0
- package/src/commands/skills/search.ts +132 -0
- package/src/commands/skills/show-config.ts +93 -0
- package/src/commands/tasks/complete.ts +92 -0
- package/src/commands/tasks/create.ts +118 -0
- package/src/commands/tasks/delete.ts +86 -0
- package/src/commands/tasks/get.ts +116 -0
- package/src/commands/tasks/index.ts +53 -0
- package/src/commands/tasks/list.ts +140 -0
- package/src/commands/tasks/operations.ts +120 -0
- package/src/commands/tasks/update.ts +122 -0
- package/src/commands/tools/exec-tool.ts +128 -0
- package/src/commands/tools/get.ts +114 -0
- package/src/commands/tools/index.ts +35 -0
- package/src/commands/tools/list.ts +107 -0
- package/src/commands/tools/shared/index.ts +7 -0
- package/src/commands/tools/shared/schema-helper.ts +111 -0
- package/src/commands/workflow/commands/add.ts +315 -0
- package/src/commands/workflow/commands/get.ts +193 -0
- package/src/commands/workflow/commands/list.ts +137 -0
- package/src/commands/workflow/commands/nodes.ts +528 -0
- package/src/commands/workflow/commands/remove.ts +94 -0
- package/src/commands/workflow/commands/run.ts +398 -0
- package/src/commands/workflow/commands/status.ts +147 -0
- package/src/commands/workflow/commands/stop.ts +91 -0
- package/src/commands/workflow/commands/update.ts +130 -0
- package/src/commands/workflow/commands/validate.ts +139 -0
- package/src/commands/workflow/commands/workflow-cli.test.ts +196 -0
- package/src/commands/workflow/index.ts +65 -0
- package/src/commands/workflow/renderers.ts +358 -0
- package/src/commands/workflow/validators/index.ts +8 -0
- package/src/commands/workflow/validators/node-validator-factory.ts +40 -0
- package/src/commands/workflow/validators/node-validator.ts +125 -0
- package/src/commands/workflow/validators/nodes/agent-node-validator.ts +58 -0
- package/src/commands/workflow/validators/nodes/condition-node-validator.ts +34 -0
- package/src/commands/workflow/validators/nodes/decorator-node-validator.ts +45 -0
- package/src/commands/workflow/validators/nodes/merge-node-validator.ts +46 -0
- package/src/commands/workflow/validators/nodes/skill-node-validator.ts +33 -0
- package/src/commands/workflow/validators/nodes/tool-node-validator.ts +54 -0
- package/src/commands/workflow/validators/nodes/workflow-node-validator.ts +33 -0
- package/src/commands/workflow/validators/types.ts +78 -0
- package/src/commands/workflow/validators/workflow-validator.test.ts +273 -0
- package/src/commands/workflow/validators/workflow-validator.ts +320 -0
- package/src/index.ts +19 -0
- package/src/plugin/apply.ts +103 -0
- package/src/plugin/discover.ts +219 -0
- package/src/plugin/index.ts +45 -0
- package/src/plugin/registry.ts +272 -0
- package/src/plugin/types.ts +165 -0
- package/src/services/context-handler.service.test.ts +501 -0
- package/src/services/context-handler.service.ts +372 -0
- package/src/services/environment.service.commands-prompt.test.ts +167 -0
- package/src/services/environment.service.ts +656 -0
- package/src/services/output.service.test.ts +92 -0
- package/src/services/output.service.ts +122 -0
- package/src/services/quiet-mode.service.test.ts +114 -0
- package/src/services/quiet-mode.service.ts +81 -0
- package/src/services/stream-output.service.test.ts +214 -0
- package/src/services/stream-output.service.ts +323 -0
- package/src/util/which.test.ts +101 -0
- package/src/util/which.ts +55 -0
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin Module
|
|
3
|
+
*
|
|
4
|
+
* Provides plugin registry and hook integration for coder enhancements.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { Tool, ToolResult } from "@ai-setting/roy-agent-core";
|
|
8
|
+
|
|
9
|
+
// ============================================================================
|
|
10
|
+
// Types
|
|
11
|
+
// ============================================================================
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Tool hook context - passed to plugin hooks
|
|
15
|
+
*/
|
|
16
|
+
export interface ToolHookContext {
|
|
17
|
+
tool?: Tool;
|
|
18
|
+
args?: Record<string, unknown>;
|
|
19
|
+
result?: ToolResult;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Tool hook points
|
|
24
|
+
*/
|
|
25
|
+
export const ToolHookPoints = {
|
|
26
|
+
AFTER_EXECUTE: "tool.after-execute",
|
|
27
|
+
BEFORE_EXECUTE: "tool.before-execute",
|
|
28
|
+
} as const;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Base plugin interface
|
|
32
|
+
*/
|
|
33
|
+
export interface BasePlugin {
|
|
34
|
+
name: string;
|
|
35
|
+
description?: string;
|
|
36
|
+
version?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Tool plugin interface - hooks into tool execution
|
|
41
|
+
*/
|
|
42
|
+
export interface ToolPlugin extends BasePlugin {
|
|
43
|
+
getHookPoint(): (typeof ToolHookPoints)[keyof typeof ToolHookPoints];
|
|
44
|
+
shouldHandle?(context: ToolHookContext): boolean;
|
|
45
|
+
onAfterExecute?(context: ToolHookContext): void | Promise<void>;
|
|
46
|
+
onBeforeExecute?(context: ToolHookContext): void | Promise<void>;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Plugin config from CLI
|
|
51
|
+
*/
|
|
52
|
+
export interface PluginConfig {
|
|
53
|
+
name: string;
|
|
54
|
+
config?: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Parsed plugin arguments
|
|
59
|
+
*/
|
|
60
|
+
export interface PluginArgs {
|
|
61
|
+
plugins: (string | PluginConfig)[];
|
|
62
|
+
fileTypes: string[];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// ============================================================================
|
|
66
|
+
// Built-in Plugins
|
|
67
|
+
// ============================================================================
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Built-in plugin registry
|
|
71
|
+
*/
|
|
72
|
+
export const BUILTIN_PLUGINS = {
|
|
73
|
+
lsp: "LSP code intelligence (diagnostics, completions)",
|
|
74
|
+
"code-check": "External command code checking (linter + type check)",
|
|
75
|
+
reminder: "Max iterations reminder for ReAct loop",
|
|
76
|
+
} as const;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* File type mappings for built-in plugins
|
|
80
|
+
*/
|
|
81
|
+
const FILE_TYPE_MAP: Record<string, string[]> = {
|
|
82
|
+
typescript: [".ts", ".tsx"],
|
|
83
|
+
javascript: [".js", ".jsx", ".mjs"],
|
|
84
|
+
python: [".py"],
|
|
85
|
+
rust: [".rs"],
|
|
86
|
+
go: [".go"],
|
|
87
|
+
java: [".java"],
|
|
88
|
+
csharp: [".cs"],
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
// ============================================================================
|
|
92
|
+
// Plugin Manager
|
|
93
|
+
// ============================================================================
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Plugin registry for managing registered plugins
|
|
97
|
+
*/
|
|
98
|
+
export class PluginRegistry {
|
|
99
|
+
private plugins: Map<string, ToolPlugin> = new Map();
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Register a plugin
|
|
103
|
+
*/
|
|
104
|
+
register(plugin: ToolPlugin): void {
|
|
105
|
+
if (this.plugins.has(plugin.name)) {
|
|
106
|
+
throw new Error(`Plugin '${plugin.name}' already registered`);
|
|
107
|
+
}
|
|
108
|
+
this.plugins.set(plugin.name, plugin);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Unregister a plugin
|
|
113
|
+
*/
|
|
114
|
+
unregister(name: string): boolean {
|
|
115
|
+
return this.plugins.delete(name);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Get a plugin by name
|
|
120
|
+
*/
|
|
121
|
+
get(name: string): ToolPlugin | undefined {
|
|
122
|
+
return this.plugins.get(name);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Get all registered plugins
|
|
127
|
+
*/
|
|
128
|
+
getAll(): ToolPlugin[] {
|
|
129
|
+
return Array.from(this.plugins.values());
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Get plugins for a specific hook point
|
|
134
|
+
*/
|
|
135
|
+
getByHookPoint(hookPoint: string): ToolPlugin[] {
|
|
136
|
+
return this.getAll().filter((p) => p.getHookPoint() === hookPoint);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Check if plugin is registered
|
|
141
|
+
*/
|
|
142
|
+
has(name: string): boolean {
|
|
143
|
+
return this.plugins.has(name);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Clear all plugins
|
|
148
|
+
*/
|
|
149
|
+
clear(): void {
|
|
150
|
+
this.plugins.clear();
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// ============================================================================
|
|
155
|
+
// CLI Argument Parsing
|
|
156
|
+
// ============================================================================
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Parse plugin CLI arguments
|
|
160
|
+
*
|
|
161
|
+
* Formats:
|
|
162
|
+
* - plugin-name (e.g., "lsp", "linter")
|
|
163
|
+
* - plugin-name:config (e.g., "lsp:typescript", "linter:/path/to/eslintrc.json")
|
|
164
|
+
* - /path/to/plugin.js (custom plugin)
|
|
165
|
+
*/
|
|
166
|
+
export function parseArgs(args: string[]): PluginArgs {
|
|
167
|
+
const plugins: (string | PluginConfig)[] = [];
|
|
168
|
+
const fileTypes = new Set<string>();
|
|
169
|
+
|
|
170
|
+
for (const arg of args) {
|
|
171
|
+
if (arg.startsWith("/") || arg.startsWith(".")) {
|
|
172
|
+
// It's a file path
|
|
173
|
+
plugins.push(arg);
|
|
174
|
+
|
|
175
|
+
// Extract file type from path
|
|
176
|
+
const ext = arg.match(/\.[^.]+$/)?.[0];
|
|
177
|
+
if (ext) {
|
|
178
|
+
fileTypes.add(ext);
|
|
179
|
+
}
|
|
180
|
+
} else if (arg.includes(":")) {
|
|
181
|
+
// It's a plugin with config
|
|
182
|
+
const [name, config] = arg.split(":", 2);
|
|
183
|
+
plugins.push({ name, config: config || "" });
|
|
184
|
+
|
|
185
|
+
// Extract file types from config
|
|
186
|
+
if (FILE_TYPE_MAP[config]) {
|
|
187
|
+
FILE_TYPE_MAP[config].forEach((t) => fileTypes.add(t));
|
|
188
|
+
} else {
|
|
189
|
+
// Try to extract extension from config
|
|
190
|
+
const ext = config.match(/\.[^.]+$/)?.[0];
|
|
191
|
+
if (ext) {
|
|
192
|
+
fileTypes.add(ext);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
} else {
|
|
196
|
+
// It's just a plugin name
|
|
197
|
+
plugins.push(arg);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return {
|
|
202
|
+
plugins,
|
|
203
|
+
fileTypes: Array.from(fileTypes),
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// ============================================================================
|
|
208
|
+
// Plugin Execution
|
|
209
|
+
// ============================================================================
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Execute a plugin hook
|
|
213
|
+
*/
|
|
214
|
+
export async function executePlugin(
|
|
215
|
+
plugin: ToolPlugin,
|
|
216
|
+
context: ToolHookContext
|
|
217
|
+
): Promise<void> {
|
|
218
|
+
// Check if plugin should handle this context
|
|
219
|
+
if (plugin.shouldHandle && !plugin.shouldHandle(context)) {
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Execute the appropriate hook
|
|
224
|
+
const hookPoint = plugin.getHookPoint();
|
|
225
|
+
if (hookPoint === ToolHookPoints.AFTER_EXECUTE && plugin.onAfterExecute) {
|
|
226
|
+
await plugin.onAfterExecute(context);
|
|
227
|
+
} else if (
|
|
228
|
+
hookPoint === ToolHookPoints.BEFORE_EXECUTE &&
|
|
229
|
+
plugin.onBeforeExecute
|
|
230
|
+
) {
|
|
231
|
+
await plugin.onBeforeExecute(context);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// ============================================================================
|
|
236
|
+
// Help
|
|
237
|
+
// ============================================================================
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Get the help message for plugin command
|
|
241
|
+
*/
|
|
242
|
+
export function getPluginHelp(): string {
|
|
243
|
+
const lines = [
|
|
244
|
+
"",
|
|
245
|
+
" --plugin <plugins> Enable coder plugin",
|
|
246
|
+
"",
|
|
247
|
+
" Built-in plugins:",
|
|
248
|
+
];
|
|
249
|
+
|
|
250
|
+
for (const [name, desc] of Object.entries(BUILTIN_PLUGINS)) {
|
|
251
|
+
lines.push(` ${name.padEnd(12)} ${desc}`);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
lines.push("", " Plugin formats:", " --plugin lsp # Enable LSP");
|
|
255
|
+
lines.push(" --plugin lsp:typescript # LSP for TypeScript");
|
|
256
|
+
lines.push(" --plugin lsp:python # LSP for Python");
|
|
257
|
+
lines.push(" --plugin code-check # Enable external command checking");
|
|
258
|
+
lines.push(" --plugin reminder # Enable iteration reminder");
|
|
259
|
+
lines.push(
|
|
260
|
+
" --plugin /path/to/plugin.js # Custom plugin"
|
|
261
|
+
);
|
|
262
|
+
lines.push(
|
|
263
|
+
" --plugin lsp code-check reminder # Multiple plugins"
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
return lines.join("\n");
|
|
267
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Sessions Active Command
|
|
3
|
+
*
|
|
4
|
+
* 命令:roy sessions active [options]
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { CommandModule } from "yargs";
|
|
8
|
+
import { EnvironmentService } from "../../services/environment.service";
|
|
9
|
+
import { OutputService } from "../../services/output.service";
|
|
10
|
+
import chalk from "chalk";
|
|
11
|
+
import type { SessionComponent, Session } from "@ai-setting/roy-agent-core";
|
|
12
|
+
|
|
13
|
+
interface ActiveOptions {
|
|
14
|
+
clear?: boolean;
|
|
15
|
+
json?: boolean;
|
|
16
|
+
config?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const ActiveCommand: CommandModule<object, ActiveOptions> = {
|
|
20
|
+
command: "active",
|
|
21
|
+
aliases: ["current"],
|
|
22
|
+
describe: "查看/设置当前活跃会话",
|
|
23
|
+
|
|
24
|
+
builder: (yargs) =>
|
|
25
|
+
yargs
|
|
26
|
+
.option("clear", { type: "boolean", default: false })
|
|
27
|
+
.option("json", { alias: "j", type: "boolean", default: false }),
|
|
28
|
+
|
|
29
|
+
async handler(args) {
|
|
30
|
+
const output = new OutputService();
|
|
31
|
+
const envService = new EnvironmentService(output);
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
await envService.create({ configPath: args.config });
|
|
35
|
+
const env = envService.getEnvironment();
|
|
36
|
+
if (!env) {
|
|
37
|
+
output.error("Failed to create environment");
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
const sessionComponent = env.getComponent("session") as SessionComponent | undefined;
|
|
41
|
+
|
|
42
|
+
if (!sessionComponent) {
|
|
43
|
+
output.error("SessionComponent not available");
|
|
44
|
+
process.exit(1);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const activeId = sessionComponent.getActiveSessionId();
|
|
48
|
+
|
|
49
|
+
if (args.clear) {
|
|
50
|
+
// 清除活跃会话
|
|
51
|
+
// 注意:需要通过内部机制清除,暂时不支持
|
|
52
|
+
output.log("Active session cleared");
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (!activeId) {
|
|
57
|
+
output.log(chalk.gray("No active session set"));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const session: Session | undefined = await sessionComponent.get(activeId);
|
|
62
|
+
|
|
63
|
+
if (args.json) {
|
|
64
|
+
output.json({
|
|
65
|
+
activeSessionId: activeId,
|
|
66
|
+
session: session ? {
|
|
67
|
+
id: session.id,
|
|
68
|
+
title: session.title,
|
|
69
|
+
directory: session.directory,
|
|
70
|
+
messageCount: session.messageCount,
|
|
71
|
+
createdAt: new Date(session.createdAt).toISOString(),
|
|
72
|
+
updatedAt: new Date(session.updatedAt).toISOString(),
|
|
73
|
+
} : null,
|
|
74
|
+
});
|
|
75
|
+
} else {
|
|
76
|
+
if (!session) {
|
|
77
|
+
output.log(chalk.gray("Active session not found: " + activeId));
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
output.log(chalk.bold.green("┌─ Active Session ─────────────────────────────────┐"));
|
|
82
|
+
output.log(`│ ID: ${session.id}`);
|
|
83
|
+
output.log(`│ Title: ${session.title}`);
|
|
84
|
+
output.log(`│ Directory: ${session.directory}`);
|
|
85
|
+
output.log(`│ Messages: ${session.messageCount}`);
|
|
86
|
+
output.log(`│ Updated: ${new Date(session.updatedAt).toLocaleString("zh-CN")}`);
|
|
87
|
+
output.log("└" + "─".repeat(51) + "┘");
|
|
88
|
+
}
|
|
89
|
+
} catch (error) {
|
|
90
|
+
output.error(`Failed to get active session: ${error instanceof Error ? error.message : String(error)}`);
|
|
91
|
+
process.exit(1);
|
|
92
|
+
} finally {
|
|
93
|
+
await envService.dispose();
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Sessions Add Message Command
|
|
3
|
+
*
|
|
4
|
+
* 命令:roy sessions add-message <session-id> <role> <content>
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { CommandModule } from "yargs";
|
|
8
|
+
import { EnvironmentService } from "../../services/environment.service";
|
|
9
|
+
import { OutputService } from "../../services/output.service";
|
|
10
|
+
import chalk from "chalk";
|
|
11
|
+
import type { SessionComponent, Session } from "@ai-setting/roy-agent-core";
|
|
12
|
+
|
|
13
|
+
interface AddMessageOptions {
|
|
14
|
+
sessionId: string;
|
|
15
|
+
role: "user" | "assistant" | "system" | "tool";
|
|
16
|
+
content: string;
|
|
17
|
+
json?: boolean;
|
|
18
|
+
config?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const AddMessageCommand: CommandModule<object, object> = {
|
|
22
|
+
command: "add-message <session-id> <role> <content>",
|
|
23
|
+
aliases: ["add"],
|
|
24
|
+
describe: "添加消息到会话 [test]",
|
|
25
|
+
|
|
26
|
+
builder: (yargs) =>
|
|
27
|
+
yargs
|
|
28
|
+
.positional("session-id", {
|
|
29
|
+
describe: "会话 ID",
|
|
30
|
+
type: "string",
|
|
31
|
+
demandOption: true,
|
|
32
|
+
})
|
|
33
|
+
.positional("role", {
|
|
34
|
+
describe: "消息角色",
|
|
35
|
+
type: "string",
|
|
36
|
+
choices: ["user", "assistant", "system", "tool"],
|
|
37
|
+
demandOption: true,
|
|
38
|
+
})
|
|
39
|
+
.positional("content", {
|
|
40
|
+
describe: "消息内容",
|
|
41
|
+
type: "string",
|
|
42
|
+
demandOption: true,
|
|
43
|
+
})
|
|
44
|
+
.option("json", { alias: "j", type: "boolean", default: false }),
|
|
45
|
+
|
|
46
|
+
async handler(args) {
|
|
47
|
+
const a = args as any;
|
|
48
|
+
const output = new OutputService();
|
|
49
|
+
const envService = new EnvironmentService(output);
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
await envService.create({ configPath: a.config });
|
|
53
|
+
const env = envService.getEnvironment();
|
|
54
|
+
if (!env) {
|
|
55
|
+
output.error("Failed to create environment");
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
const sessionComponent = env.getComponent("session") as SessionComponent | undefined;
|
|
59
|
+
|
|
60
|
+
if (!sessionComponent) {
|
|
61
|
+
output.error("SessionComponent not available");
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// 检查会话是否存在
|
|
66
|
+
const session: Session | undefined = await sessionComponent.get(a.sessionId);
|
|
67
|
+
if (!session) {
|
|
68
|
+
output.error(`Session not found: ${a.sessionId}`);
|
|
69
|
+
process.exit(1);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// 添加消息
|
|
73
|
+
const messageId = await sessionComponent.addMessage(a.sessionId, {
|
|
74
|
+
role: a.role,
|
|
75
|
+
content: a.content,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
if (a.json) {
|
|
79
|
+
output.json({
|
|
80
|
+
success: true,
|
|
81
|
+
messageId,
|
|
82
|
+
sessionId: a.sessionId,
|
|
83
|
+
role: a.role,
|
|
84
|
+
contentLength: a.content.length,
|
|
85
|
+
});
|
|
86
|
+
} else {
|
|
87
|
+
output.success(`Message added to session ${a.sessionId}`);
|
|
88
|
+
output.log(`Message ID: ${messageId}`);
|
|
89
|
+
output.log(`Role: ${a.role}`);
|
|
90
|
+
output.log(`Content: ${a.content.substring(0, 100)}${a.content.length > 100 ? "..." : ""}`);
|
|
91
|
+
}
|
|
92
|
+
} finally {
|
|
93
|
+
await envService.dispose();
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
};
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Sessions Checkpoints Command
|
|
3
|
+
*
|
|
4
|
+
* 命令:roy sessions checkpoints <session-id>
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { CommandModule } from "yargs";
|
|
8
|
+
import { EnvironmentService } from "../../services/environment.service";
|
|
9
|
+
import { OutputService } from "../../services/output.service";
|
|
10
|
+
import chalk from "chalk";
|
|
11
|
+
import type { SessionComponent, Session, SessionCheckpoint } from "@ai-setting/roy-agent-core";
|
|
12
|
+
|
|
13
|
+
interface CheckpointsOptions {
|
|
14
|
+
sessionId: string;
|
|
15
|
+
detail?: boolean;
|
|
16
|
+
json?: boolean;
|
|
17
|
+
config?: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const CheckpointsCommand: CommandModule<object, object> = {
|
|
21
|
+
command: "checkpoints <session-id>",
|
|
22
|
+
aliases: ["cps"],
|
|
23
|
+
describe: "查看会话检查点列表 [new]",
|
|
24
|
+
|
|
25
|
+
builder: (yargs) =>
|
|
26
|
+
yargs
|
|
27
|
+
.positional("session-id", {
|
|
28
|
+
describe: "会话 ID",
|
|
29
|
+
type: "string",
|
|
30
|
+
demandOption: true,
|
|
31
|
+
})
|
|
32
|
+
.option("detail", { alias: "d", type: "boolean", default: false })
|
|
33
|
+
.option("json", { alias: "j", type: "boolean", default: false }),
|
|
34
|
+
|
|
35
|
+
async handler(args) {
|
|
36
|
+
const a = args as any;
|
|
37
|
+
const output = new OutputService();
|
|
38
|
+
const envService = new EnvironmentService(output);
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
await envService.create({ configPath: a.config });
|
|
42
|
+
const env = envService.getEnvironment();
|
|
43
|
+
if (!env) {
|
|
44
|
+
output.error("Failed to create environment");
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
const sessionComponent = env.getComponent("session") as SessionComponent | undefined;
|
|
48
|
+
|
|
49
|
+
if (!sessionComponent) {
|
|
50
|
+
output.error("SessionComponent not available");
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const session: Session | undefined = await sessionComponent.get(a.sessionId);
|
|
55
|
+
if (!session) {
|
|
56
|
+
output.error(`Session not found: ${a.sessionId}`);
|
|
57
|
+
process.exit(1);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const checkpoints: SessionCheckpoint[] = await sessionComponent.getCheckpoints(a.sessionId);
|
|
61
|
+
|
|
62
|
+
if (checkpoints.length === 0) {
|
|
63
|
+
output.log(chalk.gray("No checkpoints for this session"));
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (a.json) {
|
|
68
|
+
output.json({
|
|
69
|
+
sessionId: a.sessionId,
|
|
70
|
+
checkpoints: checkpoints.map((cp: SessionCheckpoint) => ({
|
|
71
|
+
id: cp.id,
|
|
72
|
+
title: cp.title,
|
|
73
|
+
type: cp.type,
|
|
74
|
+
messageIndex: cp.messageIndex,
|
|
75
|
+
processKeyPoints: cp.processKeyPoints,
|
|
76
|
+
currentState: cp.currentState,
|
|
77
|
+
nextSteps: cp.nextSteps,
|
|
78
|
+
userIntents: cp.userIntents, // Include user intents
|
|
79
|
+
messageCountBefore: cp.messageCountBefore,
|
|
80
|
+
createdAt: new Date(cp.createdAt).toISOString(),
|
|
81
|
+
})),
|
|
82
|
+
total: checkpoints.length,
|
|
83
|
+
});
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (a.detail) {
|
|
88
|
+
// 详细模式
|
|
89
|
+
checkpoints.reverse().forEach((cp: SessionCheckpoint, i: number) => {
|
|
90
|
+
const isLatest = i === 0;
|
|
91
|
+
output.log(chalk.bold(`┌─ Checkpoint: ${cp.title} ${isLatest ? chalk.green("✓") : ""} ──────` + "─".repeat(Math.max(0, 30 - cp.title.length)) + "┐"));
|
|
92
|
+
output.log(`│ ID: ${cp.id}`);
|
|
93
|
+
output.log(`│ Type: ${cp.type}`);
|
|
94
|
+
output.log(`│ Message Index: ${cp.messageIndex} (${cp.messageCountBefore} messages)`);
|
|
95
|
+
output.log(`│ Created: ${new Date(cp.createdAt).toLocaleString("zh-CN")}`);
|
|
96
|
+
output.log("├─ Process Key Points ─────────────────────────────────┤");
|
|
97
|
+
cp.processKeyPoints.forEach((p: string, j: number) => {
|
|
98
|
+
output.log(`│ ${j + 1}. ${p}`);
|
|
99
|
+
});
|
|
100
|
+
output.log("├─ Current State ─────────────────────────────────────┤");
|
|
101
|
+
output.log("│ " + cp.currentState);
|
|
102
|
+
if (cp.nextSteps?.length) {
|
|
103
|
+
output.log("├─ Next Steps ───────────────────────────────────────┤");
|
|
104
|
+
cp.nextSteps.forEach((s: string, j: number) => {
|
|
105
|
+
output.log(`│ ${j + 1}. ${s}`);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
if (cp.userIntents?.length) {
|
|
109
|
+
output.log("├─ User Intents ─────────────────────────────────────┤");
|
|
110
|
+
cp.userIntents.forEach((intent: string, j: number) => {
|
|
111
|
+
output.log(`│ ${j + 1}. ${intent}`);
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
output.log("└" + "─".repeat(51) + "┘");
|
|
115
|
+
output.log("");
|
|
116
|
+
});
|
|
117
|
+
} else {
|
|
118
|
+
// 简洁模式
|
|
119
|
+
const header = [
|
|
120
|
+
chalk.bold("#"),
|
|
121
|
+
chalk.bold("Title"),
|
|
122
|
+
chalk.bold("Type"),
|
|
123
|
+
chalk.bold("Messages"),
|
|
124
|
+
chalk.bold("Created"),
|
|
125
|
+
].join(" │ ");
|
|
126
|
+
|
|
127
|
+
output.log(`┌─ Checkpoints (${checkpoints.length}) ${"─".repeat(40)}┐`);
|
|
128
|
+
output.log(`│${header}│`);
|
|
129
|
+
output.log("├" + "─".repeat(header.length + 2) + "┤");
|
|
130
|
+
|
|
131
|
+
checkpoints.reverse().forEach((cp: any, i: number) => {
|
|
132
|
+
const isLatest = i === 0;
|
|
133
|
+
const marker = isLatest ? chalk.green("✓ ") : " ";
|
|
134
|
+
const title = cp.title.length > 25 ? cp.title.slice(0, 22) + "..." : cp.title;
|
|
135
|
+
const created = new Date(cp.createdAt).toLocaleString("zh-CN", {
|
|
136
|
+
month: "2-digit",
|
|
137
|
+
day: "2-digit",
|
|
138
|
+
hour: "2-digit",
|
|
139
|
+
minute: "2-digit",
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
output.log(`│${marker}${i + 1} ${title.padEnd(25)} │ ${cp.type.padEnd(5)} │ ${cp.messageCountBefore.toString().padStart(8)} │ ${chalk.gray(created)}│`);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
output.log("└" + "─".repeat(header.length + 2) + "┘");
|
|
146
|
+
}
|
|
147
|
+
} catch (error) {
|
|
148
|
+
output.error(`Failed to get checkpoints: ${error instanceof Error ? error.message : String(error)}`);
|
|
149
|
+
process.exit(1);
|
|
150
|
+
} finally {
|
|
151
|
+
await envService.dispose();
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
};
|