@robota-sdk/agent-command 3.0.0-beta.64

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 (95) hide show
  1. package/LICENSE +21 -0
  2. package/dist/node/index.cjs +30 -0
  3. package/dist/node/index.d.ts +293 -0
  4. package/dist/node/index.d.ts.map +1 -0
  5. package/dist/node/index.js +31 -0
  6. package/dist/node/index.js.map +1 -0
  7. package/package.json +48 -0
  8. package/src/agent/__tests__/agent-command.test.ts +504 -0
  9. package/src/agent/agent-command-module.ts +82 -0
  10. package/src/agent/agent-command-parser.ts +180 -0
  11. package/src/agent/agent-command.ts +235 -0
  12. package/src/agent/index.ts +7 -0
  13. package/src/background/__tests__/background-command-module.test.ts +255 -0
  14. package/src/background/background-command-module.ts +53 -0
  15. package/src/background/background-command.ts +63 -0
  16. package/src/background/index.ts +6 -0
  17. package/src/compact/__tests__/compact-command-module.test.ts +162 -0
  18. package/src/compact/compact-command-module.ts +51 -0
  19. package/src/compact/compact-command.ts +21 -0
  20. package/src/compact/index.ts +6 -0
  21. package/src/context/__tests__/context-command-module.test.ts +294 -0
  22. package/src/context/context-command-module.ts +54 -0
  23. package/src/context/context-command.ts +298 -0
  24. package/src/context/index.ts +6 -0
  25. package/src/exit/__tests__/exit-command-module.test.ts +35 -0
  26. package/src/exit/exit-command-module.ts +48 -0
  27. package/src/exit/exit-command.ts +10 -0
  28. package/src/exit/index.ts +6 -0
  29. package/src/help/__tests__/help-command-module.test.ts +106 -0
  30. package/src/help/help-command-module.ts +48 -0
  31. package/src/help/help-command.ts +9 -0
  32. package/src/help/index.ts +6 -0
  33. package/src/index.ts +20 -0
  34. package/src/language/__tests__/language-command-module.test.ts +105 -0
  35. package/src/language/index.ts +6 -0
  36. package/src/language/language-command-module.ts +56 -0
  37. package/src/language/language-command.ts +22 -0
  38. package/src/memory/__tests__/memory-command-module.test.ts +272 -0
  39. package/src/memory/index.ts +6 -0
  40. package/src/memory/memory-command-module.ts +57 -0
  41. package/src/memory/memory-command.ts +234 -0
  42. package/src/mode/__tests__/mode-command-module.test.ts +143 -0
  43. package/src/mode/index.ts +6 -0
  44. package/src/mode/mode-command-module.ts +56 -0
  45. package/src/mode/mode-command.ts +34 -0
  46. package/src/model/__tests__/model-command-module.test.ts +273 -0
  47. package/src/model/index.ts +6 -0
  48. package/src/model/model-command-module.ts +68 -0
  49. package/src/model/model-command.ts +40 -0
  50. package/src/permissions/__tests__/permissions-command-module.test.ts +164 -0
  51. package/src/permissions/index.ts +6 -0
  52. package/src/permissions/permissions-command-module.ts +56 -0
  53. package/src/permissions/permissions-command.ts +45 -0
  54. package/src/plugin/__tests__/plugin-command-module.test.ts +214 -0
  55. package/src/plugin/index.ts +7 -0
  56. package/src/plugin/plugin-command-module.ts +81 -0
  57. package/src/plugin/plugin-command.ts +230 -0
  58. package/src/provider/__tests__/provider-command-module.test.ts +488 -0
  59. package/src/provider/__tests__/provider-setup-flow.test.ts +43 -0
  60. package/src/provider/index.ts +30 -0
  61. package/src/provider/provider-command-execution.ts +150 -0
  62. package/src/provider/provider-command-module.ts +65 -0
  63. package/src/provider/provider-command-profile-lifecycle.ts +211 -0
  64. package/src/provider/provider-command-profile-operations.ts +198 -0
  65. package/src/provider/provider-command-profile.ts +109 -0
  66. package/src/provider/provider-command-setup.ts +104 -0
  67. package/src/provider/provider-setup-flow.ts +309 -0
  68. package/src/reset/__tests__/reset-command-module.test.ts +63 -0
  69. package/src/reset/index.ts +2 -0
  70. package/src/reset/reset-command-module.ts +49 -0
  71. package/src/reset/reset-command.ts +10 -0
  72. package/src/rewind/__tests__/rewind-command-module.test.ts +215 -0
  73. package/src/rewind/index.ts +2 -0
  74. package/src/rewind/rewind-command-module.ts +57 -0
  75. package/src/rewind/rewind-command.ts +184 -0
  76. package/src/session/__tests__/session-command-module.test.ts +339 -0
  77. package/src/session/index.ts +17 -0
  78. package/src/session/session-command-module.ts +168 -0
  79. package/src/session/session-command.ts +74 -0
  80. package/src/settings/index.ts +7 -0
  81. package/src/settings/settings-command-module.ts +50 -0
  82. package/src/skills/__tests__/skills-command-module.test.ts +157 -0
  83. package/src/skills/index.ts +6 -0
  84. package/src/skills/skills-command-module.ts +62 -0
  85. package/src/skills/skills-command.ts +110 -0
  86. package/src/statusline/__tests__/statusline-command-module.test.ts +95 -0
  87. package/src/statusline/index.ts +6 -0
  88. package/src/statusline/statusline-command-module.ts +56 -0
  89. package/src/statusline/statusline-command.ts +79 -0
  90. package/src/user-local/__tests__/user-local-command.test.ts +145 -0
  91. package/src/user-local/index.ts +13 -0
  92. package/src/user-local/user-local-command-constants.ts +5 -0
  93. package/src/user-local/user-local-command-module.ts +67 -0
  94. package/src/user-local/user-local-command.ts +205 -0
  95. package/src/user-local/user-local-memory-command.ts +147 -0
@@ -0,0 +1,339 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import type { ICommandHostContext, ICommandSessionRuntime } from '@robota-sdk/agent-framework';
3
+ import { InteractiveSession, SystemCommandExecutor } from '@robota-sdk/agent-framework';
4
+ import { createSessionCommandModule } from '../session-command-module.js';
5
+
6
+ function createRuntime(): ICommandSessionRuntime {
7
+ return {
8
+ clearHistory: vi.fn(),
9
+ compact: async () => undefined,
10
+ getContextState: () => ({
11
+ maxTokens: 100,
12
+ usedTokens: 0,
13
+ usedPercentage: 0,
14
+ remainingPercentage: 100,
15
+ }),
16
+ getPermissionMode: () => 'default',
17
+ setPermissionMode: () => undefined,
18
+ getSessionId: () => 'session_1',
19
+ getMessageCount: () => 5,
20
+ getSessionAllowedTools: () => [],
21
+ getAutoCompactThreshold: () => false,
22
+ };
23
+ }
24
+
25
+ function createCommandContext(): ICommandHostContext {
26
+ const runtime = createRuntime();
27
+ return {
28
+ getSession: () => runtime,
29
+ getContextState: () => runtime.getContextState(),
30
+ getAutoCompactThreshold: () => 0.835,
31
+ compactContext: async () => undefined,
32
+ getCwd: () => '/workspace',
33
+ listEditCheckpoints: () => [],
34
+ restoreEditCheckpoint: async () => {
35
+ throw new Error('not used');
36
+ },
37
+ rollbackEditCheckpoint: async () => {
38
+ throw new Error('not used');
39
+ },
40
+ getUsedMemoryReferences: () => [],
41
+ recordMemoryEvent: () => undefined,
42
+ listBackgroundTasks: () => [],
43
+ readBackgroundTaskLog: async (taskId) => ({ taskId, lines: [] }),
44
+ cancelBackgroundTask: async () => undefined,
45
+ closeBackgroundTask: async () => undefined,
46
+ };
47
+ }
48
+
49
+ describe('createSessionCommandModule', () => {
50
+ it('provides clear metadata and user-only executable command from one module owner', () => {
51
+ const module = createSessionCommandModule();
52
+ const command = module.systemCommands?.find((item) => item.name === 'clear');
53
+ const entry = module.commandSources?.[0]?.getCommands().find((item) => item.name === 'clear');
54
+
55
+ expect(module.name).toBe('agent-command-session');
56
+ expect(entry).toEqual(
57
+ expect.objectContaining({
58
+ name: 'clear',
59
+ description: 'Clear conversation history',
60
+ source: 'session',
61
+ modelInvocable: false,
62
+ }),
63
+ );
64
+ expect(command).toEqual(
65
+ expect.objectContaining({
66
+ name: 'clear',
67
+ lifecycle: 'inline',
68
+ userInvocable: true,
69
+ modelInvocable: false,
70
+ }),
71
+ );
72
+ });
73
+
74
+ it('provides rename metadata and user-only executable command from the same module owner', () => {
75
+ const module = createSessionCommandModule();
76
+ const command = module.systemCommands?.find((item) => item.name === 'rename');
77
+ const entry = module.commandSources?.[0]?.getCommands().find((item) => item.name === 'rename');
78
+
79
+ expect(module.commandSources?.[0]?.getCommands().map((item) => item.name)).toEqual([
80
+ 'clear',
81
+ 'rename',
82
+ 'resume',
83
+ 'cost',
84
+ 'validate-session',
85
+ ]);
86
+ expect(module.systemCommands?.map((item) => item.name)).toEqual([
87
+ 'clear',
88
+ 'rename',
89
+ 'resume',
90
+ 'cost',
91
+ 'validate-session',
92
+ ]);
93
+ expect(entry).toEqual(
94
+ expect.objectContaining({
95
+ name: 'rename',
96
+ description: 'Rename the current session',
97
+ source: 'session',
98
+ modelInvocable: false,
99
+ }),
100
+ );
101
+ expect(command).toEqual(
102
+ expect.objectContaining({
103
+ name: 'rename',
104
+ lifecycle: 'inline',
105
+ userInvocable: true,
106
+ modelInvocable: false,
107
+ }),
108
+ );
109
+ });
110
+
111
+ it('provides resume metadata and user-only executable command from the same module owner', () => {
112
+ const module = createSessionCommandModule();
113
+ const command = module.systemCommands?.find((item) => item.name === 'resume');
114
+ const entry = module.commandSources?.[0]?.getCommands().find((item) => item.name === 'resume');
115
+
116
+ expect(entry).toEqual(
117
+ expect.objectContaining({
118
+ name: 'resume',
119
+ description: 'Resume a previous session',
120
+ source: 'session',
121
+ modelInvocable: false,
122
+ }),
123
+ );
124
+ expect(command).toEqual(
125
+ expect.objectContaining({
126
+ name: 'resume',
127
+ lifecycle: 'inline',
128
+ userInvocable: true,
129
+ modelInvocable: false,
130
+ }),
131
+ );
132
+ });
133
+
134
+ it('provides cost metadata and user-only executable command from the same module owner', () => {
135
+ const module = createSessionCommandModule();
136
+ const command = module.systemCommands?.find((item) => item.name === 'cost');
137
+ const entry = module.commandSources?.[0]?.getCommands().find((item) => item.name === 'cost');
138
+
139
+ expect(entry).toEqual(
140
+ expect.objectContaining({
141
+ name: 'cost',
142
+ description: 'Show session info',
143
+ source: 'session',
144
+ modelInvocable: false,
145
+ }),
146
+ );
147
+ expect(command).toEqual(
148
+ expect.objectContaining({
149
+ name: 'cost',
150
+ lifecycle: 'inline',
151
+ userInvocable: true,
152
+ modelInvocable: false,
153
+ }),
154
+ );
155
+ });
156
+
157
+ it('provides validate-session metadata and user-only executable command from the same module owner', () => {
158
+ const module = createSessionCommandModule();
159
+ const command = module.systemCommands?.find((item) => item.name === 'validate-session');
160
+ const entry = module.commandSources?.[0]
161
+ ?.getCommands()
162
+ .find((item) => item.name === 'validate-session');
163
+
164
+ expect(entry).toEqual(
165
+ expect.objectContaining({
166
+ name: 'validate-session',
167
+ description: 'Validate current session replay log',
168
+ source: 'session',
169
+ modelInvocable: false,
170
+ }),
171
+ );
172
+ expect(command).toEqual(
173
+ expect.objectContaining({
174
+ name: 'validate-session',
175
+ lifecycle: 'inline',
176
+ userInvocable: true,
177
+ modelInvocable: false,
178
+ }),
179
+ );
180
+ });
181
+
182
+ it('clears conversation history through the session command API', async () => {
183
+ const clearConversationHistory = vi.fn();
184
+ const context = {
185
+ ...createCommandContext(),
186
+ clearConversationHistory,
187
+ };
188
+ const executor = new SystemCommandExecutor([
189
+ ...(createSessionCommandModule().systemCommands ?? []),
190
+ ]);
191
+
192
+ const result = await executor.execute('clear', context, '');
193
+
194
+ expect(clearConversationHistory).toHaveBeenCalledTimes(1);
195
+ expect(result).toEqual({
196
+ success: true,
197
+ message: 'Conversation cleared.',
198
+ effects: [{ type: 'conversation-history-cleared' }],
199
+ });
200
+ });
201
+
202
+ it('falls back to runtime clearHistory when the host has not implemented the richer API', async () => {
203
+ const runtime = createRuntime();
204
+ const context = {
205
+ ...createCommandContext(),
206
+ getSession: () => runtime,
207
+ };
208
+ const executor = new SystemCommandExecutor([
209
+ ...(createSessionCommandModule().systemCommands ?? []),
210
+ ]);
211
+
212
+ const result = await executor.execute('clear', context, '');
213
+
214
+ expect(runtime.clearHistory).toHaveBeenCalledTimes(1);
215
+ expect(result?.success).toBe(true);
216
+ });
217
+
218
+ it('clears InteractiveSession history when executed through a composed session', async () => {
219
+ const clearHistory = vi.fn();
220
+ const runtime = {
221
+ ...createRuntime(),
222
+ clearHistory,
223
+ run: vi.fn().mockResolvedValue('answer'),
224
+ abort: vi.fn(),
225
+ getHistory: vi.fn().mockReturnValue([]),
226
+ injectMessage: vi.fn(),
227
+ getSystemMessage: vi.fn().mockReturnValue('system'),
228
+ getToolSchemas: vi.fn().mockReturnValue([]),
229
+ };
230
+ const session = new InteractiveSession({
231
+ session: runtime as never,
232
+ commandModules: [createSessionCommandModule()],
233
+ });
234
+ await session.submit('hello');
235
+ expect(session.getFullHistory().length).toBeGreaterThan(0);
236
+
237
+ const result = await session.executeCommand('clear', '');
238
+
239
+ expect(result).toEqual({
240
+ success: true,
241
+ message: 'Conversation cleared.',
242
+ effects: [{ type: 'conversation-history-cleared' }],
243
+ });
244
+ expect(clearHistory).toHaveBeenCalledTimes(1);
245
+ expect(session.getFullHistory()).toEqual([]);
246
+ });
247
+
248
+ it('renames the current session through a typed host effect', async () => {
249
+ const executor = new SystemCommandExecutor([
250
+ ...(createSessionCommandModule().systemCommands ?? []),
251
+ ]);
252
+
253
+ const result = await executor.execute('rename', createCommandContext(), ' my-session ');
254
+
255
+ expect(result).toEqual({
256
+ success: true,
257
+ message: 'Session renamed to "my-session".',
258
+ data: { name: 'my-session' },
259
+ effects: [{ type: 'session-renamed', name: 'my-session' }],
260
+ });
261
+ });
262
+
263
+ it('returns usage when rename is missing a session name', async () => {
264
+ const executor = new SystemCommandExecutor([
265
+ ...(createSessionCommandModule().systemCommands ?? []),
266
+ ]);
267
+
268
+ const result = await executor.execute('rename', createCommandContext(), ' ');
269
+
270
+ expect(result).toEqual({
271
+ success: false,
272
+ message: 'Usage: rename <name>',
273
+ });
274
+ });
275
+
276
+ it('requests the host session picker through a typed effect', async () => {
277
+ const executor = new SystemCommandExecutor([
278
+ ...(createSessionCommandModule().systemCommands ?? []),
279
+ ]);
280
+
281
+ const result = await executor.execute('resume', createCommandContext(), '');
282
+
283
+ expect(result).toEqual({
284
+ success: true,
285
+ message: 'Opening session picker...',
286
+ data: { triggerResumePicker: true },
287
+ effects: [{ type: 'session-picker-requested' }],
288
+ });
289
+ });
290
+
291
+ it('shows session info through the session command API', async () => {
292
+ const executor = new SystemCommandExecutor([
293
+ ...(createSessionCommandModule().systemCommands ?? []),
294
+ ]);
295
+
296
+ const result = await executor.execute('cost', createCommandContext(), '');
297
+
298
+ expect(result).toEqual({
299
+ success: true,
300
+ message: 'Session: session_1\nMessages: 5',
301
+ data: { sessionId: 'session_1', messageCount: 5 },
302
+ });
303
+ });
304
+
305
+ it('validates the current session replay log through the SDK common API', async () => {
306
+ const executor = new SystemCommandExecutor([
307
+ ...(createSessionCommandModule().systemCommands ?? []),
308
+ ]);
309
+ const context = {
310
+ ...createCommandContext(),
311
+ validateCurrentSessionReplayLog: () => ({
312
+ logFile: '/workspace/.robota/logs/session_1.jsonl',
313
+ entryCount: 2,
314
+ validation: {
315
+ ok: false,
316
+ issues: [
317
+ {
318
+ code: 'PROVIDER_NATIVE_RAW_PAYLOAD_MISSING' as const,
319
+ message: 'Provider request exec-1:1 has no provider-native payload.',
320
+ executionId: 'exec-1',
321
+ round: 1,
322
+ },
323
+ ],
324
+ },
325
+ }),
326
+ };
327
+
328
+ const result = await executor.execute('validate-session', context, '');
329
+
330
+ expect(result?.success).toBe(false);
331
+ expect(result?.message).toContain('PROVIDER_NATIVE_RAW_PAYLOAD_MISSING');
332
+ expect(result?.data).toEqual({
333
+ logFile: '/workspace/.robota/logs/session_1.jsonl',
334
+ entryCount: 2,
335
+ issueCount: 1,
336
+ ok: false,
337
+ });
338
+ });
339
+ });
@@ -0,0 +1,17 @@
1
+ export {
2
+ executeClearCommand,
3
+ executeCostCommand,
4
+ executeRenameCommand,
5
+ executeResumeCommand,
6
+ executeValidateSessionCommand,
7
+ CLEAR_COMMAND_MESSAGE,
8
+ } from './session-command.js';
9
+ export {
10
+ SessionCommandSource,
11
+ createClearCommandEntry,
12
+ createCostCommandEntry,
13
+ createRenameCommandEntry,
14
+ createResumeCommandEntry,
15
+ createSessionCommandModule,
16
+ createValidateSessionCommandEntry,
17
+ } from './session-command-module.js';
@@ -0,0 +1,168 @@
1
+ import type {
2
+ ICommand,
3
+ ICommandModule,
4
+ ICommandSource,
5
+ ISystemCommand,
6
+ } from '@robota-sdk/agent-framework';
7
+ import {
8
+ CLEAR_COMMAND_DESCRIPTION,
9
+ COST_COMMAND_DESCRIPTION,
10
+ RENAME_COMMAND_DESCRIPTION,
11
+ RESUME_COMMAND_DESCRIPTION,
12
+ VALIDATE_SESSION_COMMAND_DESCRIPTION,
13
+ } from '@robota-sdk/agent-framework';
14
+ import {
15
+ executeClearCommand,
16
+ executeCostCommand,
17
+ executeRenameCommand,
18
+ executeResumeCommand,
19
+ executeValidateSessionCommand,
20
+ } from './session-command.js';
21
+
22
+ export function createClearCommandEntry(): ICommand {
23
+ return {
24
+ name: 'clear',
25
+ displayName: 'Clear History',
26
+ description: CLEAR_COMMAND_DESCRIPTION,
27
+ source: 'session',
28
+ modelInvocable: false,
29
+ };
30
+ }
31
+
32
+ export function createRenameCommandEntry(): ICommand {
33
+ return {
34
+ name: 'rename',
35
+ displayName: 'Rename Session',
36
+ description: RENAME_COMMAND_DESCRIPTION,
37
+ source: 'session',
38
+ modelInvocable: false,
39
+ };
40
+ }
41
+
42
+ export function createResumeCommandEntry(): ICommand {
43
+ return {
44
+ name: 'resume',
45
+ displayName: 'Resume Session',
46
+ description: RESUME_COMMAND_DESCRIPTION,
47
+ source: 'session',
48
+ modelInvocable: false,
49
+ };
50
+ }
51
+
52
+ export function createCostCommandEntry(): ICommand {
53
+ return {
54
+ name: 'cost',
55
+ displayName: 'Session Cost',
56
+ description: COST_COMMAND_DESCRIPTION,
57
+ source: 'session',
58
+ modelInvocable: false,
59
+ };
60
+ }
61
+
62
+ export function createValidateSessionCommandEntry(): ICommand {
63
+ return {
64
+ name: 'validate-session',
65
+ displayName: 'Validate Session',
66
+ description: VALIDATE_SESSION_COMMAND_DESCRIPTION,
67
+ source: 'session',
68
+ modelInvocable: false,
69
+ };
70
+ }
71
+
72
+ function createClearSystemCommand(): ISystemCommand {
73
+ const entry = createClearCommandEntry();
74
+ return {
75
+ name: entry.name,
76
+ displayName: entry.displayName,
77
+ description: entry.description,
78
+ requiresPermission: false,
79
+ userInvocable: true,
80
+ modelInvocable: false,
81
+ lifecycle: 'inline',
82
+ execute: executeClearCommand,
83
+ };
84
+ }
85
+
86
+ function createRenameSystemCommand(): ISystemCommand {
87
+ const entry = createRenameCommandEntry();
88
+ return {
89
+ name: entry.name,
90
+ displayName: entry.displayName,
91
+ description: entry.description,
92
+ requiresPermission: false,
93
+ userInvocable: true,
94
+ modelInvocable: false,
95
+ lifecycle: 'inline',
96
+ execute: executeRenameCommand,
97
+ };
98
+ }
99
+
100
+ function createResumeSystemCommand(): ISystemCommand {
101
+ const entry = createResumeCommandEntry();
102
+ return {
103
+ name: entry.name,
104
+ displayName: entry.displayName,
105
+ description: entry.description,
106
+ requiresPermission: false,
107
+ userInvocable: true,
108
+ modelInvocable: false,
109
+ lifecycle: 'inline',
110
+ execute: executeResumeCommand,
111
+ };
112
+ }
113
+
114
+ function createCostSystemCommand(): ISystemCommand {
115
+ const entry = createCostCommandEntry();
116
+ return {
117
+ name: entry.name,
118
+ displayName: entry.displayName,
119
+ description: entry.description,
120
+ requiresPermission: false,
121
+ userInvocable: true,
122
+ modelInvocable: false,
123
+ lifecycle: 'inline',
124
+ execute: executeCostCommand,
125
+ };
126
+ }
127
+
128
+ function createValidateSessionSystemCommand(): ISystemCommand {
129
+ const entry = createValidateSessionCommandEntry();
130
+ return {
131
+ name: entry.name,
132
+ displayName: entry.displayName,
133
+ description: entry.description,
134
+ requiresPermission: false,
135
+ userInvocable: true,
136
+ modelInvocable: false,
137
+ lifecycle: 'inline',
138
+ execute: executeValidateSessionCommand,
139
+ };
140
+ }
141
+
142
+ export class SessionCommandSource implements ICommandSource {
143
+ readonly name = 'session';
144
+
145
+ getCommands(): ICommand[] {
146
+ return [
147
+ createClearCommandEntry(),
148
+ createRenameCommandEntry(),
149
+ createResumeCommandEntry(),
150
+ createCostCommandEntry(),
151
+ createValidateSessionCommandEntry(),
152
+ ];
153
+ }
154
+ }
155
+
156
+ export function createSessionCommandModule(): ICommandModule {
157
+ return {
158
+ name: 'agent-command-session',
159
+ commandSources: [new SessionCommandSource()],
160
+ systemCommands: [
161
+ createClearSystemCommand(),
162
+ createRenameSystemCommand(),
163
+ createResumeSystemCommand(),
164
+ createCostSystemCommand(),
165
+ createValidateSessionSystemCommand(),
166
+ ],
167
+ };
168
+ }
@@ -0,0 +1,74 @@
1
+ import type { ICommandHostContext, ICommandResult } from '@robota-sdk/agent-framework';
2
+ import {
3
+ RENAME_COMMAND_USAGE,
4
+ clearConversationHistory,
5
+ createSessionPickerRequestedEffect,
6
+ createSessionRenamedEffect,
7
+ formatCommandSessionReplayValidationReport,
8
+ parseSessionNameArgument,
9
+ readCommandSessionInfo,
10
+ validateCommandSessionReplayLog,
11
+ } from '@robota-sdk/agent-framework';
12
+
13
+ export const CLEAR_COMMAND_MESSAGE = 'Conversation cleared.';
14
+
15
+ export function executeClearCommand(context: ICommandHostContext, _args: string): ICommandResult {
16
+ clearConversationHistory(context);
17
+ return {
18
+ success: true,
19
+ message: CLEAR_COMMAND_MESSAGE,
20
+ effects: [{ type: 'conversation-history-cleared' }],
21
+ };
22
+ }
23
+
24
+ export function executeRenameCommand(_context: ICommandHostContext, args: string): ICommandResult {
25
+ const name = parseSessionNameArgument(args);
26
+ if (name === undefined) {
27
+ return { success: false, message: RENAME_COMMAND_USAGE };
28
+ }
29
+
30
+ return {
31
+ success: true,
32
+ message: `Session renamed to "${name}".`,
33
+ data: { name },
34
+ effects: [createSessionRenamedEffect(name)],
35
+ };
36
+ }
37
+
38
+ export function executeResumeCommand(_context: ICommandHostContext, _args: string): ICommandResult {
39
+ return {
40
+ success: true,
41
+ message: 'Opening session picker...',
42
+ data: { triggerResumePicker: true },
43
+ effects: [createSessionPickerRequestedEffect()],
44
+ };
45
+ }
46
+
47
+ export function executeCostCommand(context: ICommandHostContext, _args: string): ICommandResult {
48
+ const sessionInfo = readCommandSessionInfo(context);
49
+ return {
50
+ success: true,
51
+ message: `Session: ${sessionInfo.sessionId}\nMessages: ${sessionInfo.messageCount}`,
52
+ data: {
53
+ sessionId: sessionInfo.sessionId,
54
+ messageCount: sessionInfo.messageCount,
55
+ },
56
+ };
57
+ }
58
+
59
+ export function executeValidateSessionCommand(
60
+ context: ICommandHostContext,
61
+ _args: string,
62
+ ): ICommandResult {
63
+ const report = validateCommandSessionReplayLog(context);
64
+ return {
65
+ success: report.validation.ok,
66
+ message: formatCommandSessionReplayValidationReport(report),
67
+ data: {
68
+ logFile: report.logFile,
69
+ entryCount: report.entryCount,
70
+ issueCount: report.validation.issues.length,
71
+ ok: report.validation.ok,
72
+ },
73
+ };
74
+ }
@@ -0,0 +1,7 @@
1
+ // @robota-sdk/agent-command-settings
2
+
3
+ export {
4
+ createSettingsCommandModule,
5
+ createSettingsCommandEntry,
6
+ SettingsCommandSource,
7
+ } from './settings-command-module.js';
@@ -0,0 +1,50 @@
1
+ import type {
2
+ ICommand,
3
+ ICommandModule,
4
+ ICommandSource,
5
+ ISystemCommand,
6
+ } from '@robota-sdk/agent-framework';
7
+
8
+ export function createSettingsCommandEntry(): ICommand {
9
+ return {
10
+ name: 'settings',
11
+ displayName: 'Settings',
12
+ description: 'Open transport settings — enable/disable transports and configure options',
13
+ source: 'settings',
14
+ modelInvocable: false,
15
+ };
16
+ }
17
+
18
+ function createSettingsSystemCommand(): ISystemCommand {
19
+ const entry = createSettingsCommandEntry();
20
+ return {
21
+ name: entry.name,
22
+ displayName: entry.displayName,
23
+ description: entry.description,
24
+ requiresPermission: false,
25
+ userInvocable: true,
26
+ modelInvocable: false,
27
+ lifecycle: 'inline',
28
+ execute: async () => ({
29
+ success: true,
30
+ message: 'Opening settings...',
31
+ effects: [{ type: 'settings-tui-requested' as const }],
32
+ }),
33
+ };
34
+ }
35
+
36
+ export class SettingsCommandSource implements ICommandSource {
37
+ readonly name = 'settings';
38
+
39
+ getCommands(): ICommand[] {
40
+ return [createSettingsCommandEntry()];
41
+ }
42
+ }
43
+
44
+ export function createSettingsCommandModule(): ICommandModule {
45
+ return {
46
+ name: 'agent-command-settings',
47
+ commandSources: [new SettingsCommandSource()],
48
+ systemCommands: [createSettingsSystemCommand()],
49
+ };
50
+ }