@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,105 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import type {
3
+ ICommandHostContext,
4
+ IEditCheckpointRestoreResult,
5
+ } from '@robota-sdk/agent-framework';
6
+ import { SystemCommandExecutor } from '@robota-sdk/agent-framework';
7
+ import { createLanguageCommandModule } from '../language-command-module.js';
8
+
9
+ function createCheckpointResult(): IEditCheckpointRestoreResult {
10
+ return {
11
+ target: {
12
+ id: 'checkpoint_1',
13
+ sessionId: 'session_1',
14
+ sequence: 1,
15
+ prompt: 'edit files',
16
+ createdAt: '2026-05-03T00:00:00.000Z',
17
+ fileCount: 1,
18
+ },
19
+ restoredCheckpointCount: 0,
20
+ restoredFileCount: 0,
21
+ removedCheckpointCount: 0,
22
+ };
23
+ }
24
+
25
+ const commandHostContext: ICommandHostContext = {
26
+ getSession: () => {
27
+ throw new Error('language command should not read session runtime');
28
+ },
29
+ getContextState: () => ({
30
+ usedTokens: 0,
31
+ maxTokens: 1,
32
+ usedPercentage: 0,
33
+ remainingPercentage: 100,
34
+ }),
35
+ getAutoCompactThreshold: () => 0.835,
36
+ compactContext: async () => undefined,
37
+ getCwd: () => '/workspace',
38
+ listEditCheckpoints: () => [],
39
+ restoreEditCheckpoint: async () => createCheckpointResult(),
40
+ rollbackEditCheckpoint: async () => createCheckpointResult(),
41
+ getUsedMemoryReferences: () => [],
42
+ recordMemoryEvent: () => undefined,
43
+ listBackgroundTasks: () => [],
44
+ readBackgroundTaskLog: async () => ({ taskId: 'task_1', lines: [] }),
45
+ cancelBackgroundTask: async () => undefined,
46
+ closeBackgroundTask: async () => undefined,
47
+ };
48
+
49
+ describe('createLanguageCommandModule', () => {
50
+ it('provides language metadata and executable command from one module owner', () => {
51
+ const module = createLanguageCommandModule();
52
+ const command = module.systemCommands?.[0];
53
+ const entry = module.commandSources?.[0]?.getCommands()[0];
54
+
55
+ expect(module.name).toBe('agent-command-language');
56
+ expect(entry).toEqual(
57
+ expect.objectContaining({
58
+ name: 'language',
59
+ description: 'Set response language',
60
+ argumentHint: '<code>',
61
+ source: 'language',
62
+ modelInvocable: false,
63
+ }),
64
+ );
65
+ expect(entry?.subcommands?.map((subcommand) => subcommand.name)).toEqual([
66
+ 'ko',
67
+ 'en',
68
+ 'ja',
69
+ 'zh',
70
+ ]);
71
+ expect(command).toEqual(
72
+ expect.objectContaining({
73
+ name: 'language',
74
+ description: 'Set response language',
75
+ argumentHint: '<code>',
76
+ lifecycle: 'inline',
77
+ modelInvocable: false,
78
+ }),
79
+ );
80
+ expect(command?.subcommands).toEqual(entry?.subcommands);
81
+ });
82
+
83
+ it('requests language changes through a typed command effect', async () => {
84
+ const executor = new SystemCommandExecutor([
85
+ ...(createLanguageCommandModule().systemCommands ?? []),
86
+ ]);
87
+
88
+ const result = await executor.execute('language', commandHostContext, 'ko');
89
+
90
+ expect(result?.success).toBe(true);
91
+ expect(result?.data?.language).toBe('ko');
92
+ expect(result?.effects).toEqual([{ type: 'language-change-requested', language: 'ko' }]);
93
+ });
94
+
95
+ it('shows usage when no language code is provided', async () => {
96
+ const executor = new SystemCommandExecutor([
97
+ ...(createLanguageCommandModule().systemCommands ?? []),
98
+ ]);
99
+
100
+ const result = await executor.execute('language', commandHostContext, '');
101
+
102
+ expect(result?.success).toBe(false);
103
+ expect(result?.message).toBe('Usage: language <code> (e.g., ko, en, ja, zh)');
104
+ });
105
+ });
@@ -0,0 +1,6 @@
1
+ export {
2
+ createLanguageCommandEntry,
3
+ createLanguageCommandModule,
4
+ LanguageCommandSource,
5
+ } from './language-command-module.js';
6
+ export { executeLanguageCommand } from './language-command.js';
@@ -0,0 +1,56 @@
1
+ import type {
2
+ ICommand,
3
+ ICommandModule,
4
+ ICommandSource,
5
+ ISystemCommand,
6
+ } from '@robota-sdk/agent-framework';
7
+ import {
8
+ buildLanguageCommandSubcommands,
9
+ LANGUAGE_COMMAND_ARGUMENT_HINT,
10
+ LANGUAGE_COMMAND_DESCRIPTION,
11
+ } from '@robota-sdk/agent-framework';
12
+ import { executeLanguageCommand } from './language-command.js';
13
+
14
+ export function createLanguageCommandEntry(): ICommand {
15
+ return {
16
+ name: 'language',
17
+ displayName: 'Language',
18
+ description: LANGUAGE_COMMAND_DESCRIPTION,
19
+ source: 'language',
20
+ argumentHint: LANGUAGE_COMMAND_ARGUMENT_HINT,
21
+ subcommands: buildLanguageCommandSubcommands('language'),
22
+ modelInvocable: false,
23
+ };
24
+ }
25
+
26
+ function createLanguageSystemCommand(): ISystemCommand {
27
+ const entry = createLanguageCommandEntry();
28
+ return {
29
+ name: entry.name,
30
+ displayName: entry.displayName,
31
+ description: entry.description,
32
+ requiresPermission: false,
33
+ userInvocable: true,
34
+ modelInvocable: false,
35
+ argumentHint: entry.argumentHint,
36
+ subcommands: entry.subcommands,
37
+ lifecycle: 'inline',
38
+ execute: executeLanguageCommand,
39
+ };
40
+ }
41
+
42
+ export class LanguageCommandSource implements ICommandSource {
43
+ readonly name = 'language';
44
+
45
+ getCommands(): ICommand[] {
46
+ return [createLanguageCommandEntry()];
47
+ }
48
+ }
49
+
50
+ export function createLanguageCommandModule(): ICommandModule {
51
+ return {
52
+ name: 'agent-command-language',
53
+ commandSources: [new LanguageCommandSource()],
54
+ systemCommands: [createLanguageSystemCommand()],
55
+ };
56
+ }
@@ -0,0 +1,22 @@
1
+ import type { ICommandHostContext, ICommandResult } from '@robota-sdk/agent-framework';
2
+ import { formatLanguageUsageMessage, parseLanguageArgument } from '@robota-sdk/agent-framework';
3
+
4
+ export function executeLanguageCommand(
5
+ _context: ICommandHostContext,
6
+ args: string,
7
+ ): ICommandResult {
8
+ const language = parseLanguageArgument(args);
9
+ if (language === undefined) {
10
+ return {
11
+ message: formatLanguageUsageMessage(),
12
+ success: false,
13
+ };
14
+ }
15
+
16
+ return {
17
+ message: `Language set to "${language}".`,
18
+ success: true,
19
+ data: { language },
20
+ effects: [{ type: 'language-change-requested', language }],
21
+ };
22
+ }
@@ -0,0 +1,272 @@
1
+ import { afterEach, describe, expect, it, vi } from 'vitest';
2
+ import { existsSync, mkdirSync, readFileSync, rmSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { tmpdir } from 'node:os';
5
+ import {
6
+ InteractiveSession,
7
+ SystemCommandExecutor,
8
+ createCommandPendingMemoryStore,
9
+ } from '@robota-sdk/agent-framework';
10
+ import { MemoryCommandSource, createMemoryCommandModule, executeMemoryCommand } from '../index.js';
11
+
12
+ const TMP_BASE = join(tmpdir(), `robota-command-memory-${process.pid}`);
13
+
14
+ function makeProject(): string {
15
+ const dir = join(TMP_BASE, Math.random().toString(36).slice(2));
16
+ mkdirSync(dir, { recursive: true });
17
+ return dir;
18
+ }
19
+
20
+ function createMockRuntimeSession() {
21
+ return {
22
+ run: vi.fn().mockResolvedValue('mock response'),
23
+ abort: vi.fn(),
24
+ clearHistory: vi.fn(),
25
+ compact: vi.fn().mockResolvedValue(undefined),
26
+ injectMessage: vi.fn(),
27
+ getHistory: vi.fn().mockReturnValue([]),
28
+ getContextState: vi.fn().mockReturnValue({
29
+ usedTokens: 5000,
30
+ maxTokens: 200000,
31
+ usedPercentage: 2.5,
32
+ remainingPercentage: 97.5,
33
+ }),
34
+ getPermissionMode: vi.fn().mockReturnValue('default'),
35
+ setPermissionMode: vi.fn(),
36
+ getSessionId: vi.fn().mockReturnValue('test-session-id'),
37
+ getMessageCount: vi.fn().mockReturnValue(5),
38
+ getSessionAllowedTools: vi.fn().mockReturnValue([]),
39
+ getAutoCompactThreshold: vi.fn().mockReturnValue(0.835),
40
+ setAutoCompactThreshold: vi.fn(),
41
+ getSystemMessage: vi.fn().mockReturnValue('mock system prompt'),
42
+ getToolSchemas: vi.fn().mockReturnValue([]),
43
+ };
44
+ }
45
+
46
+ function createInteractiveSession(cwd = makeProject()): InteractiveSession {
47
+ return new InteractiveSession({
48
+ cwd,
49
+ session: createMockRuntimeSession() as never,
50
+ commandModules: [createMemoryCommandModule()],
51
+ });
52
+ }
53
+
54
+ function seedPendingMemory(cwd: string): void {
55
+ const pendingStore = createCommandPendingMemoryStore(
56
+ cwd,
57
+ () => new Date('2026-05-02T00:00:00.000Z'),
58
+ );
59
+ pendingStore.upsert(
60
+ {
61
+ id: 'mem_123',
62
+ type: 'project',
63
+ topic: 'build',
64
+ text: 'Use pnpm for package scripts.',
65
+ sourceMessageIds: ['turn-1:user'],
66
+ confidence: 0.9,
67
+ createdAt: '2026-05-02T00:00:00.000Z',
68
+ reason: 'explicit-memory-cue',
69
+ },
70
+ 'pending',
71
+ 'approval-required',
72
+ );
73
+ }
74
+
75
+ afterEach(() => {
76
+ if (existsSync(TMP_BASE)) rmSync(TMP_BASE, { recursive: true, force: true });
77
+ });
78
+
79
+ describe('createMemoryCommandModule', () => {
80
+ it('contributes write-safe model-invocable memory metadata and executable command', () => {
81
+ const module = createMemoryCommandModule();
82
+ const commands = module.commandSources?.flatMap((source) => source.getCommands()) ?? [];
83
+
84
+ expect(module.name).toBe('agent-command-memory');
85
+ expect(commands.map((command) => command.name)).toEqual(['memory']);
86
+ expect(commands[0]?.source).toBe('memory');
87
+ expect(commands[0]?.modelInvocable).toBe(true);
88
+ expect(commands[0]?.safety).toBe('write');
89
+ expect(commands[0]?.subcommands?.map((command) => command.name)).toEqual([
90
+ 'list',
91
+ 'show',
92
+ 'add',
93
+ 'pending',
94
+ 'approve',
95
+ 'reject',
96
+ 'used',
97
+ ]);
98
+ expect(module.systemCommands?.map((command) => command.name)).toEqual(['memory']);
99
+ expect(module.systemCommands?.[0]?.userInvocable).toBe(true);
100
+ });
101
+
102
+ it('provides a stable command source', () => {
103
+ const source = new MemoryCommandSource();
104
+
105
+ expect(source.name).toBe('memory');
106
+ expect(source.getCommands()).toHaveLength(1);
107
+ });
108
+
109
+ it('exposes the command as a model-invocable descriptor', () => {
110
+ const executor = new SystemCommandExecutor([
111
+ ...(createMemoryCommandModule().systemCommands ?? []),
112
+ ]);
113
+ const descriptor = executor
114
+ .listModelInvocableCommands()
115
+ .find((command) => command.name === 'memory');
116
+
117
+ expect(executor.isModelInvocable('memory')).toBe(true);
118
+ expect(descriptor).toEqual(
119
+ expect.objectContaining({
120
+ name: 'memory',
121
+ kind: 'builtin-command',
122
+ userInvocable: true,
123
+ modelInvocable: true,
124
+ argumentHint:
125
+ 'list | show [topic] | add <user|feedback|project|reference> <topic> <text> | pending | approve <id> | reject <id> | used',
126
+ safety: 'write',
127
+ }),
128
+ );
129
+ expect(descriptor?.description).toContain(
130
+ 'inspect project memory when stored context may help',
131
+ );
132
+ });
133
+ });
134
+
135
+ describe('executeMemoryCommand', () => {
136
+ it('lists configured memory paths', async () => {
137
+ const cwd = makeProject();
138
+ const session = createInteractiveSession(cwd);
139
+
140
+ const result = await session.executeCommand('memory', 'list');
141
+
142
+ expect(result?.success).toBe(true);
143
+ expect(result?.message).toContain(join(cwd, '.robota', 'memory', 'MEMORY.md'));
144
+ });
145
+
146
+ it('persists index and topic entries through slash invocation', async () => {
147
+ const cwd = makeProject();
148
+ const session = createInteractiveSession(cwd);
149
+
150
+ const result = await session.executeCommand(
151
+ 'memory',
152
+ 'add project build Use pnpm for scripts.',
153
+ );
154
+
155
+ expect(result?.success).toBe(true);
156
+ expect(readFileSync(join(cwd, '.robota', 'memory', 'MEMORY.md'), 'utf8')).toContain(
157
+ '(project/build) Use pnpm for scripts.',
158
+ );
159
+ });
160
+
161
+ it('uses the same handler for model invocation', async () => {
162
+ const cwd = makeProject();
163
+ const session = createInteractiveSession(cwd);
164
+
165
+ const result = await session.executeModelCommand(
166
+ 'memory',
167
+ 'add project build Use pnpm for package scripts.',
168
+ );
169
+
170
+ expect(result?.success).toBe(true);
171
+ expect(readFileSync(join(cwd, '.robota', 'memory', 'MEMORY.md'), 'utf8')).toContain(
172
+ '(project/build) Use pnpm for package scripts.',
173
+ );
174
+ });
175
+
176
+ it('rejects sensitive content before writing files', async () => {
177
+ const cwd = makeProject();
178
+ const session = createInteractiveSession(cwd);
179
+
180
+ const result = await session.executeCommand(
181
+ 'memory',
182
+ 'add project secrets api key is sk-test-secret',
183
+ );
184
+
185
+ expect(result?.success).toBe(false);
186
+ expect(result?.message).toContain('sensitive');
187
+ expect(existsSync(join(cwd, '.robota', 'memory', 'MEMORY.md'))).toBe(false);
188
+ });
189
+
190
+ it('lists queued automatic memory candidates', async () => {
191
+ const cwd = makeProject();
192
+ seedPendingMemory(cwd);
193
+ const session = createInteractiveSession(cwd);
194
+
195
+ const result = await session.executeCommand('memory', 'pending');
196
+
197
+ expect(result?.success).toBe(true);
198
+ expect(result?.message).toContain('mem_123');
199
+ expect(result?.message).toContain('project/build');
200
+ expect(result?.message).toContain('Use pnpm for package scripts.');
201
+ });
202
+
203
+ it('approves and saves a pending candidate while recording audit events', async () => {
204
+ const cwd = makeProject();
205
+ seedPendingMemory(cwd);
206
+ const session = createInteractiveSession(cwd);
207
+ const recordMemoryEvent = vi.spyOn(session, 'recordMemoryEvent');
208
+
209
+ const result = await session.executeCommand('memory', 'approve mem_123');
210
+
211
+ expect(result?.success).toBe(true);
212
+ expect(result?.message).toContain('Saved memory candidate mem_123');
213
+ expect(readFileSync(join(cwd, '.robota', 'memory', 'MEMORY.md'), 'utf8')).toContain(
214
+ '(project/build) Use pnpm for package scripts.',
215
+ );
216
+ expect(createCommandPendingMemoryStore(cwd).get('mem_123')?.status).toBe('saved');
217
+ expect(recordMemoryEvent).toHaveBeenCalledWith(
218
+ expect.objectContaining({ type: 'memory_candidate_approved', candidateId: 'mem_123' }),
219
+ );
220
+ expect(recordMemoryEvent).toHaveBeenCalledWith(
221
+ expect.objectContaining({ type: 'memory_candidate_saved', candidateId: 'mem_123' }),
222
+ );
223
+ });
224
+
225
+ it('rejects a pending candidate while recording an audit event', async () => {
226
+ const cwd = makeProject();
227
+ seedPendingMemory(cwd);
228
+ const session = createInteractiveSession(cwd);
229
+ const recordMemoryEvent = vi.spyOn(session, 'recordMemoryEvent');
230
+
231
+ const result = await session.executeCommand('memory', 'reject mem_123');
232
+
233
+ expect(result?.success).toBe(true);
234
+ expect(result?.message).toContain('Rejected memory candidate mem_123');
235
+ expect(createCommandPendingMemoryStore(cwd).get('mem_123')?.status).toBe('rejected');
236
+ expect(recordMemoryEvent).toHaveBeenCalledWith(
237
+ expect.objectContaining({ type: 'memory_candidate_rejected', candidateId: 'mem_123' }),
238
+ );
239
+ });
240
+
241
+ it('reports references from the current turn', async () => {
242
+ const cwd = makeProject();
243
+ const session = createInteractiveSession(cwd);
244
+ vi.spyOn(session, 'getUsedMemoryReferences').mockReturnValue([
245
+ {
246
+ topic: 'build',
247
+ path: join(cwd, '.robota', 'memory', 'topics', 'build.md'),
248
+ score: 5,
249
+ truncated: false,
250
+ },
251
+ ]);
252
+
253
+ const result = await session.executeCommand('memory', 'used');
254
+
255
+ expect(result?.success).toBe(true);
256
+ expect(result?.message).toContain('build');
257
+ expect(result?.message).toContain(join(cwd, '.robota', 'memory', 'topics', 'build.md'));
258
+ });
259
+
260
+ it('returns usage for invalid arguments without mutating state', async () => {
261
+ const cwd = makeProject();
262
+ const session = createInteractiveSession(cwd);
263
+
264
+ const result = await executeMemoryCommand(session, 'add project missing-text');
265
+ const unknownResult = await executeMemoryCommand(session, 'unknown');
266
+
267
+ expect(result.success).toBe(false);
268
+ expect(result.message).toContain('Usage: memory');
269
+ expect(unknownResult.success).toBe(false);
270
+ expect(existsSync(join(cwd, '.robota', 'memory', 'MEMORY.md'))).toBe(false);
271
+ });
272
+ });
@@ -0,0 +1,6 @@
1
+ export {
2
+ MemoryCommandSource,
3
+ createMemoryCommandEntry,
4
+ createMemoryCommandModule,
5
+ } from './memory-command-module.js';
6
+ export { executeMemoryCommand } from './memory-command.js';
@@ -0,0 +1,57 @@
1
+ import type {
2
+ ICommand,
3
+ ICommandModule,
4
+ ICommandSource,
5
+ ISystemCommand,
6
+ } from '@robota-sdk/agent-framework';
7
+ import {
8
+ MEMORY_COMMAND_ARGUMENT_HINT,
9
+ MEMORY_COMMAND_DESCRIPTION,
10
+ buildMemoryCommandSubcommands,
11
+ } from '@robota-sdk/agent-framework';
12
+ import { executeMemoryCommand } from './memory-command.js';
13
+
14
+ export function createMemoryCommandEntry(): ICommand {
15
+ return {
16
+ name: 'memory',
17
+ displayName: 'Memory',
18
+ description: MEMORY_COMMAND_DESCRIPTION,
19
+ source: 'memory',
20
+ argumentHint: MEMORY_COMMAND_ARGUMENT_HINT,
21
+ modelInvocable: true,
22
+ safety: 'write',
23
+ subcommands: buildMemoryCommandSubcommands(),
24
+ };
25
+ }
26
+
27
+ function createMemorySystemCommand(): ISystemCommand {
28
+ const entry = createMemoryCommandEntry();
29
+ return {
30
+ name: entry.name,
31
+ displayName: entry.displayName,
32
+ description: entry.description,
33
+ requiresPermission: false,
34
+ userInvocable: true,
35
+ modelInvocable: true,
36
+ argumentHint: entry.argumentHint,
37
+ safety: entry.safety,
38
+ subcommands: entry.subcommands,
39
+ execute: executeMemoryCommand,
40
+ };
41
+ }
42
+
43
+ export class MemoryCommandSource implements ICommandSource {
44
+ readonly name = 'memory';
45
+
46
+ getCommands(): ICommand[] {
47
+ return [createMemoryCommandEntry()];
48
+ }
49
+ }
50
+
51
+ export function createMemoryCommandModule(): ICommandModule {
52
+ return {
53
+ name: 'agent-command-memory',
54
+ commandSources: [new MemoryCommandSource()],
55
+ systemCommands: [createMemorySystemCommand()],
56
+ };
57
+ }