@robota-sdk/agent-command 3.0.0-beta.100
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/CHANGELOG.md +1351 -0
- package/LICENSE +661 -0
- package/README.md +100 -0
- package/dist/node/index.cjs +121 -0
- package/dist/node/index.d.cts +1053 -0
- package/dist/node/index.d.cts.map +1 -0
- package/dist/node/index.d.ts +1053 -0
- package/dist/node/index.d.ts.map +1 -0
- package/dist/node/index.js +122 -0
- package/dist/node/index.js.map +1 -0
- package/package.json +83 -0
- package/src/advisor/advisor-command-module.ts +47 -0
- package/src/advisor/advisor-command.test.ts +102 -0
- package/src/advisor/advisor-command.ts +55 -0
- package/src/advisor/advisor-cost-functional.test.ts +92 -0
- package/src/advisor/index.ts +6 -0
- package/src/agent/__tests__/agent-command.test.ts +597 -0
- package/src/agent/agent-command-module.ts +89 -0
- package/src/agent/agent-command-parser.ts +180 -0
- package/src/agent/agent-command.ts +255 -0
- package/src/agent/index.ts +7 -0
- package/src/background/__tests__/background-command-module.test.ts +261 -0
- package/src/background/background-command-module.ts +52 -0
- package/src/background/background-command.ts +65 -0
- package/src/background/index.ts +6 -0
- package/src/command-module-utils.test.ts +37 -0
- package/src/command-module-utils.ts +35 -0
- package/src/compact/__tests__/compact-command-module.test.ts +181 -0
- package/src/compact/compact-command-module.ts +59 -0
- package/src/compact/compact-command.ts +33 -0
- package/src/compact/index.ts +6 -0
- package/src/context/__tests__/context-command-module.test.ts +502 -0
- package/src/context/auto-compact-format.ts +25 -0
- package/src/context/context-breakdown.ts +295 -0
- package/src/context/context-command-module.ts +82 -0
- package/src/context/context-command.ts +291 -0
- package/src/context/index.ts +6 -0
- package/src/default/__tests__/__snapshots__/model-exposure.test.ts.snap +121 -0
- package/src/default/__tests__/default-command-modules.test.ts +192 -0
- package/src/default/__tests__/model-exposure.test.ts +269 -0
- package/src/default/__tests__/org-policy-forwarding.test.ts +106 -0
- package/src/default/__tests__/provider-environment-forwarding.test.ts +98 -0
- package/src/default/default-command-modules.ts +247 -0
- package/src/default/index.ts +5 -0
- package/src/devices/__tests__/devices-command-module.test.ts +299 -0
- package/src/devices/devices-command-module.ts +308 -0
- package/src/devices/devices-command-port.ts +143 -0
- package/src/devices/index.ts +14 -0
- package/src/doctor/__tests__/doctor-command-module.test.ts +145 -0
- package/src/doctor/__tests__/doctor-display-vocabulary.test.ts +38 -0
- package/src/doctor/__tests__/doctor-fixture.ts +146 -0
- package/src/doctor/__tests__/doctor-redaction.test.ts +29 -0
- package/src/doctor/__tests__/doctor-runner.test.ts +484 -0
- package/src/doctor/doctor-command-module.ts +132 -0
- package/src/doctor/doctor-extensions-probe.ts +323 -0
- package/src/doctor/doctor-node-deps.ts +88 -0
- package/src/doctor/doctor-redaction.ts +99 -0
- package/src/doctor/doctor-render.ts +70 -0
- package/src/doctor/doctor-repair.ts +136 -0
- package/src/doctor/doctor-runner.ts +122 -0
- package/src/doctor/doctor-settings-probe.ts +239 -0
- package/src/doctor/doctor-storage-probe.ts +187 -0
- package/src/doctor/doctor-types.ts +109 -0
- package/src/doctor/index.ts +32 -0
- package/src/editor/__tests__/editor-command-functional.test.ts +124 -0
- package/src/editor/editor-command-module.ts +53 -0
- package/src/editor/editor-command.ts +58 -0
- package/src/editor/index.ts +7 -0
- package/src/editor/resolve-editor.ts +21 -0
- package/src/effort/effort-command-module.ts +51 -0
- package/src/effort/effort-command.test.ts +203 -0
- package/src/effort/effort-command.ts +136 -0
- package/src/effort/index.ts +6 -0
- package/src/events/__tests__/events-command.test.ts +73 -0
- package/src/events/events-command-module.ts +49 -0
- package/src/events/events-command.ts +69 -0
- package/src/events/index.ts +2 -0
- package/src/exit/__tests__/exit-command-module.test.ts +61 -0
- package/src/exit/exit-command-module.ts +47 -0
- package/src/exit/exit-command.ts +26 -0
- package/src/exit/index.ts +6 -0
- package/src/fork/__tests__/fork-command.test.ts +184 -0
- package/src/fork/fork-command-module.ts +61 -0
- package/src/fork/fork-command.ts +162 -0
- package/src/fork/index.ts +8 -0
- package/src/git/__tests__/fake-git-port.ts +35 -0
- package/src/git/__tests__/git-command-module.test.ts +111 -0
- package/src/git/__tests__/git-commit.test.ts +185 -0
- package/src/git/git-command-module.ts +138 -0
- package/src/git/git-commit.ts +254 -0
- package/src/git/index.ts +20 -0
- package/src/goal/__tests__/goal-command.test.ts +80 -0
- package/src/goal/goal-command-module.ts +49 -0
- package/src/goal/goal-command.ts +69 -0
- package/src/goal/index.ts +6 -0
- package/src/handoff/__tests__/handoff-command-module.test.ts +25 -0
- package/src/handoff/__tests__/handoff-command.test.ts +218 -0
- package/src/handoff/handoff-command-module.ts +49 -0
- package/src/handoff/handoff-command.ts +187 -0
- package/src/handoff/index.ts +6 -0
- package/src/help/__tests__/help-command-module.test.ts +134 -0
- package/src/help/__tests__/help-command.test.ts +130 -0
- package/src/help/help-command-module.ts +47 -0
- package/src/help/help-command.ts +11 -0
- package/src/help/index.ts +6 -0
- package/src/index.ts +163 -0
- package/src/keybindings/__tests__/keybindings-command-module.test.ts +57 -0
- package/src/keybindings/index.ts +6 -0
- package/src/keybindings/keybindings-command-module.ts +88 -0
- package/src/language/__tests__/language-command-module.test.ts +126 -0
- package/src/language/index.ts +6 -0
- package/src/language/language-command-module.ts +55 -0
- package/src/language/language-command.ts +52 -0
- package/src/mcp-activation/__tests__/mcp-activation-command.test.ts +895 -0
- package/src/mcp-activation/__tests__/mcp-model-view.test.ts +242 -0
- package/src/mcp-activation/__tests__/mcp-skill-command.test.ts +141 -0
- package/src/mcp-activation/index.ts +12 -0
- package/src/mcp-activation/mcp-activation-command-module.ts +123 -0
- package/src/mcp-activation/mcp-activation-command.ts +662 -0
- package/src/mcp-activation/mcp-model-notice.ts +99 -0
- package/src/mcp-activation/mcp-model-status.ts +104 -0
- package/src/memory/__tests__/memory-command-module.test.ts +476 -0
- package/src/memory/__tests__/memory-command-unavailable.test.ts +63 -0
- package/src/memory/index.ts +6 -0
- package/src/memory/memory-command-module.ts +77 -0
- package/src/memory/memory-command.ts +326 -0
- package/src/mode/__tests__/mode-command-module.test.ts +230 -0
- package/src/mode/index.ts +6 -0
- package/src/mode/mode-command-module.ts +55 -0
- package/src/mode/mode-command.ts +67 -0
- package/src/model/__tests__/model-command-module.test.ts +80 -0
- package/src/model/__tests__/model-command.test.ts +265 -0
- package/src/model/index.ts +6 -0
- package/src/model/model-command-module.ts +56 -0
- package/src/model/model-command.ts +249 -0
- package/src/output-style/__tests__/output-style-command.test.ts +96 -0
- package/src/output-style/index.ts +6 -0
- package/src/output-style/output-style-command-module.ts +143 -0
- package/src/peers/__tests__/peers-command-module.test.ts +24 -0
- package/src/peers/__tests__/peers-command.test.ts +399 -0
- package/src/peers/index.ts +9 -0
- package/src/peers/peers-command-module.ts +49 -0
- package/src/peers/peers-command.ts +220 -0
- package/src/permissions/__tests__/permissions-command-module.test.ts +276 -0
- package/src/permissions/index.ts +6 -0
- package/src/permissions/permissions-command-module.ts +55 -0
- package/src/permissions/permissions-command.ts +89 -0
- package/src/plan/__tests__/plan-command.test.ts +129 -0
- package/src/plan/index.ts +9 -0
- package/src/plan/plan-command-module.ts +49 -0
- package/src/plan/plan-command.ts +92 -0
- package/src/plugin/__tests__/plugin-active-turn.test.ts +100 -0
- package/src/plugin/__tests__/plugin-command-module.test.ts +300 -0
- package/src/plugin/__tests__/plugin-host-boundary.test.ts +11 -0
- package/src/plugin/index.ts +7 -0
- package/src/plugin/plugin-command-module.ts +85 -0
- package/src/plugin/plugin-command.ts +271 -0
- package/src/preset/__tests__/host-supplied-preset-registry.test.ts +98 -0
- package/src/preset/__tests__/preset-command-module.test.ts +220 -0
- package/src/preset/index.ts +6 -0
- package/src/preset/preset-command-module.ts +80 -0
- package/src/preset/preset-command.ts +148 -0
- package/src/provider/__tests__/optional-provider-credentials.test.ts +130 -0
- package/src/provider/__tests__/org-policy.test.ts +174 -0
- package/src/provider/__tests__/provider-command-module.test.ts +884 -0
- package/src/provider/__tests__/provider-connection-setup.test.ts +567 -0
- package/src/provider/__tests__/provider-reference-switch.test.ts +113 -0
- package/src/provider/__tests__/provider-setup-flow.test.ts +244 -0
- package/src/provider/__tests__/provider-startup-host-settings.test.ts +16 -0
- package/src/provider/__tests__/scripted-interaction.ts +40 -0
- package/src/provider/index.ts +32 -0
- package/src/provider/provider-command-execution.ts +235 -0
- package/src/provider/provider-command-module.ts +82 -0
- package/src/provider/provider-command-profile-lifecycle.ts +239 -0
- package/src/provider/provider-command-profile-operations.ts +218 -0
- package/src/provider/provider-command-profile.ts +116 -0
- package/src/provider/provider-command-setup.ts +79 -0
- package/src/provider/provider-connection-setup.ts +287 -0
- package/src/provider/provider-connection-validation.ts +38 -0
- package/src/provider/provider-onboarding.ts +73 -0
- package/src/provider/provider-prompt-interaction.ts +28 -0
- package/src/provider/provider-setup-ask.ts +67 -0
- package/src/provider/provider-setup-flow.ts +326 -0
- package/src/provider/provider-startup.ts +225 -0
- package/src/remote-control/__tests__/remote-control-command-module.test.ts +36 -0
- package/src/remote-control/__tests__/remote-control-command.test.ts +216 -0
- package/src/remote-control/index.ts +8 -0
- package/src/remote-control/remote-control-command-module.ts +61 -0
- package/src/remote-control/remote-control-command.ts +138 -0
- package/src/reset/__tests__/reset-command-module.test.ts +63 -0
- package/src/reset/index.ts +2 -0
- package/src/reset/reset-command-module.ts +47 -0
- package/src/reset/reset-command.ts +10 -0
- package/src/rewind/__tests__/rewind-command-module.test.ts +287 -0
- package/src/rewind/index.ts +2 -0
- package/src/rewind/rewind-command-module.ts +56 -0
- package/src/rewind/rewind-command.ts +279 -0
- package/src/sandbox/__tests__/sandbox-command.test.ts +80 -0
- package/src/sandbox/index.ts +2 -0
- package/src/sandbox/sandbox-command-module.ts +56 -0
- package/src/sandbox/sandbox-command.ts +94 -0
- package/src/schedule/__tests__/loop-command-functional.test.ts +399 -0
- package/src/schedule/__tests__/loop-command.test.ts +594 -0
- package/src/schedule/__tests__/loop-jitter.test.ts +25 -0
- package/src/schedule/__tests__/monitor-model-permission-functional.test.ts +126 -0
- package/src/schedule/__tests__/schedule-command.test.ts +247 -0
- package/src/schedule/__tests__/schedule-redos.test.ts +114 -0
- package/src/schedule/index.ts +12 -0
- package/src/schedule/loop-command.ts +427 -0
- package/src/schedule/loop-jitter.ts +41 -0
- package/src/schedule/schedule-command-module.ts +184 -0
- package/src/schedule/schedule-command.ts +161 -0
- package/src/schedule/schedule-spec-parser.ts +70 -0
- package/src/session/__tests__/model-pricing.test.ts +66 -0
- package/src/session/__tests__/rename-host-persistence.test.ts +72 -0
- package/src/session/__tests__/session-command-module.test.ts +589 -0
- package/src/session/index.ts +17 -0
- package/src/session/model-pricing.ts +26 -0
- package/src/session/session-command-module.ts +197 -0
- package/src/session/session-command.ts +272 -0
- package/src/settings/index.ts +7 -0
- package/src/settings/settings-command-module.ts +47 -0
- package/src/shell/__tests__/resolve-shell-host.test.ts +11 -0
- package/src/shell/__tests__/shell-command-functional.test.ts +118 -0
- package/src/shell/index.ts +8 -0
- package/src/shell/resolve-shell.ts +25 -0
- package/src/shell/shell-command-module.ts +53 -0
- package/src/shell/shell-command.ts +48 -0
- package/src/shell/spawn-inherited.ts +32 -0
- package/src/skills/__tests__/skill-read-command.test.ts +64 -0
- package/src/skills/__tests__/skills-command-module.test.ts +200 -0
- package/src/skills/index.ts +7 -0
- package/src/skills/skill-read-command.ts +60 -0
- package/src/skills/skills-command-module.ts +76 -0
- package/src/skills/skills-command.ts +108 -0
- package/src/statusline/__tests__/statusline-command-module.test.ts +96 -0
- package/src/statusline/index.ts +6 -0
- package/src/statusline/statusline-command-module.ts +55 -0
- package/src/statusline/statusline-command.ts +80 -0
- package/src/terminal-client/__tests__/terminal-client-commands.test.ts +216 -0
- package/src/terminal-client/index.ts +5 -0
- package/src/terminal-client/terminal-client-commands.ts +109 -0
- package/src/theme/__tests__/theme-command.test.ts +204 -0
- package/src/theme/index.ts +12 -0
- package/src/theme/theme-command-module.ts +221 -0
- package/src/user-local/__tests__/user-local-command.test.ts +180 -0
- package/src/user-local/index.ts +13 -0
- package/src/user-local/user-local-command-constants.ts +5 -0
- package/src/user-local/user-local-command-module.ts +65 -0
- package/src/user-local/user-local-command.ts +214 -0
- package/src/user-local/user-local-memory-command.ts +160 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import type { ICommandHostContext, ICommandSessionRuntime } from '@robota-sdk/agent-framework';
|
|
2
|
+
import type { ICommandListEntry } from '@robota-sdk/agent-interface-command';
|
|
3
|
+
import { formatCommandHelpMessage } from '@robota-sdk/agent-framework';
|
|
4
|
+
import { describe, expect, it } from 'vitest';
|
|
5
|
+
import {
|
|
6
|
+
createTestCommandHost,
|
|
7
|
+
createTestSessionRuntime,
|
|
8
|
+
} from '@robota-sdk/agent-framework/testing';
|
|
9
|
+
|
|
10
|
+
function createCommandSessionRuntime() {
|
|
11
|
+
return createTestSessionRuntime({
|
|
12
|
+
clearHistory: () => undefined,
|
|
13
|
+
compact: async () => undefined,
|
|
14
|
+
getContextState: () => ({
|
|
15
|
+
maxTokens: 100,
|
|
16
|
+
usedTokens: 10,
|
|
17
|
+
usedPercentage: 10,
|
|
18
|
+
remainingPercentage: 90,
|
|
19
|
+
}),
|
|
20
|
+
getPermissionMode: () => 'default',
|
|
21
|
+
setPermissionMode: () => undefined,
|
|
22
|
+
getSessionId: () => 'session_1',
|
|
23
|
+
getMessageCount: () => 0,
|
|
24
|
+
getSessionAllowedTools: () => [],
|
|
25
|
+
getAutoCompactThreshold: () => false,
|
|
26
|
+
getFullHistory: () => [],
|
|
27
|
+
getHistory: () => [],
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function createCheckpoint() {
|
|
32
|
+
return {
|
|
33
|
+
id: 'checkpoint_1',
|
|
34
|
+
sessionId: 'session_1',
|
|
35
|
+
sequence: 1,
|
|
36
|
+
prompt: 'prompt',
|
|
37
|
+
createdAt: '2026-05-25T00:00:00.000Z',
|
|
38
|
+
fileCount: 0,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function buildContext(commands: ICommandListEntry[]) {
|
|
43
|
+
const checkpoint = createCheckpoint();
|
|
44
|
+
return createTestCommandHost({
|
|
45
|
+
overrides: {
|
|
46
|
+
getSession: () => createCommandSessionRuntime(),
|
|
47
|
+
getContextState: () => ({
|
|
48
|
+
maxTokens: 100,
|
|
49
|
+
usedTokens: 10,
|
|
50
|
+
usedPercentage: 10,
|
|
51
|
+
remainingPercentage: 90,
|
|
52
|
+
}),
|
|
53
|
+
getAutoCompactThreshold: () => 0.8,
|
|
54
|
+
compactContext: async () => undefined,
|
|
55
|
+
getCwd: () => '/workspace',
|
|
56
|
+
listCommands: () => commands,
|
|
57
|
+
listEditCheckpoints: () => [],
|
|
58
|
+
restoreEditCheckpoint: async () => ({
|
|
59
|
+
target: checkpoint,
|
|
60
|
+
restoredCheckpointCount: 0,
|
|
61
|
+
restoredFileCount: 0,
|
|
62
|
+
removedCheckpointCount: 0,
|
|
63
|
+
}),
|
|
64
|
+
rollbackEditCheckpoint: async () => ({
|
|
65
|
+
target: checkpoint,
|
|
66
|
+
restoredCheckpointCount: 0,
|
|
67
|
+
restoredFileCount: 0,
|
|
68
|
+
removedCheckpointCount: 0,
|
|
69
|
+
}),
|
|
70
|
+
getUsedMemoryReferences: () => [],
|
|
71
|
+
recordMemoryEvent: () => undefined,
|
|
72
|
+
listBackgroundTasks: () => [],
|
|
73
|
+
readBackgroundTaskLog: async (taskId) => ({ taskId, lines: [] }),
|
|
74
|
+
cancelBackgroundTask: async () => undefined,
|
|
75
|
+
closeBackgroundTask: async () => undefined,
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
describe('formatCommandHelpMessage — example field', () => {
|
|
81
|
+
it('TC-01: includes Example line for compact command', () => {
|
|
82
|
+
const context = buildContext([
|
|
83
|
+
{
|
|
84
|
+
name: 'compact',
|
|
85
|
+
displayName: 'Compact Context',
|
|
86
|
+
description: 'Compress context window',
|
|
87
|
+
example: '/compact Summarize the current context',
|
|
88
|
+
modelInvocable: true,
|
|
89
|
+
runner: 'runtime',
|
|
90
|
+
},
|
|
91
|
+
]);
|
|
92
|
+
|
|
93
|
+
const output = formatCommandHelpMessage(context);
|
|
94
|
+
|
|
95
|
+
expect(output).toContain('Example: /compact Summarize the current context');
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('TC-02: includes Example line for provider command', () => {
|
|
99
|
+
const context = buildContext([
|
|
100
|
+
{
|
|
101
|
+
name: 'provider',
|
|
102
|
+
displayName: 'Provider Setup',
|
|
103
|
+
description: 'Manage provider profiles',
|
|
104
|
+
example: '/provider switch production',
|
|
105
|
+
modelInvocable: true,
|
|
106
|
+
runner: 'runtime',
|
|
107
|
+
},
|
|
108
|
+
]);
|
|
109
|
+
|
|
110
|
+
const output = formatCommandHelpMessage(context);
|
|
111
|
+
|
|
112
|
+
expect(output).toContain('Example: /provider switch production');
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('TC-03: omits Example line for commands without example', () => {
|
|
116
|
+
const context = buildContext([
|
|
117
|
+
{
|
|
118
|
+
name: 'help',
|
|
119
|
+
displayName: 'Help',
|
|
120
|
+
description: 'Show available commands',
|
|
121
|
+
modelInvocable: true,
|
|
122
|
+
runner: 'runtime',
|
|
123
|
+
},
|
|
124
|
+
]);
|
|
125
|
+
|
|
126
|
+
const output = formatCommandHelpMessage(context);
|
|
127
|
+
|
|
128
|
+
expect(output).not.toContain('Example:');
|
|
129
|
+
});
|
|
130
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { HELP_COMMAND_DESCRIPTION } from '@robota-sdk/agent-framework';
|
|
2
|
+
|
|
3
|
+
import { executeHelpCommand } from './help-command.js';
|
|
4
|
+
|
|
5
|
+
import type { ICommandModule, ISystemCommand } from '@robota-sdk/agent-framework';
|
|
6
|
+
import type { ICommand, ICommandSource } from '@robota-sdk/agent-interface-command';
|
|
7
|
+
|
|
8
|
+
export function createHelpCommandEntry(): ICommand {
|
|
9
|
+
return {
|
|
10
|
+
name: 'help',
|
|
11
|
+
displayName: 'Help',
|
|
12
|
+
description: HELP_COMMAND_DESCRIPTION,
|
|
13
|
+
source: 'help',
|
|
14
|
+
// User-only: a listing for the user; the model already sees the commands it may run.
|
|
15
|
+
modelInvocable: false,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function createHelpSystemCommand(): ISystemCommand {
|
|
20
|
+
const entry = createHelpCommandEntry();
|
|
21
|
+
return {
|
|
22
|
+
name: entry.name,
|
|
23
|
+
displayName: entry.displayName,
|
|
24
|
+
description: entry.description,
|
|
25
|
+
requiresPermission: false,
|
|
26
|
+
userInvocable: true,
|
|
27
|
+
modelInvocable: false,
|
|
28
|
+
lifecycle: 'inline',
|
|
29
|
+
execute: executeHelpCommand,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export class HelpCommandSource implements ICommandSource {
|
|
34
|
+
readonly name = 'help';
|
|
35
|
+
|
|
36
|
+
getCommands(): ICommand[] {
|
|
37
|
+
return [createHelpCommandEntry()];
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function createHelpCommandModule(): ICommandModule {
|
|
42
|
+
return {
|
|
43
|
+
name: 'agent-command-help',
|
|
44
|
+
commandSources: [new HelpCommandSource()],
|
|
45
|
+
systemCommands: [createHelpSystemCommand()],
|
|
46
|
+
};
|
|
47
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { formatCommandHelpMessage } from '@robota-sdk/agent-framework';
|
|
2
|
+
|
|
3
|
+
import type { ICommandHostCatalog } from '@robota-sdk/agent-framework';
|
|
4
|
+
import type { ICommandResult } from '@robota-sdk/agent-interface-command';
|
|
5
|
+
|
|
6
|
+
export function executeHelpCommand(context: ICommandHostCatalog, _args: string): ICommandResult {
|
|
7
|
+
return {
|
|
8
|
+
success: true,
|
|
9
|
+
message: formatCommandHelpMessage(context),
|
|
10
|
+
};
|
|
11
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
export * from './agent/index.js';
|
|
2
|
+
export * from './default/index.js';
|
|
3
|
+
export * from './background/index.js';
|
|
4
|
+
export * from './goal/index.js';
|
|
5
|
+
// HANDOFF-001 (issue #1864). Named rather than `export *`: the star form is frozen pre-existing
|
|
6
|
+
// debt in this barrel, and `sdk-public-surface` lets it shrink but never grow.
|
|
7
|
+
export {
|
|
8
|
+
HandoffCommandSource,
|
|
9
|
+
createHandoffCommandEntry,
|
|
10
|
+
createHandoffCommandModule,
|
|
11
|
+
executeHandoffCommand,
|
|
12
|
+
} from './handoff/index.js';
|
|
13
|
+
export * from './plan/index.js';
|
|
14
|
+
export * from './compact/index.js';
|
|
15
|
+
export * from './context/index.js';
|
|
16
|
+
export * from './editor/index.js';
|
|
17
|
+
export {
|
|
18
|
+
createGitCommandEntry,
|
|
19
|
+
createGitCommandModule,
|
|
20
|
+
createGitProcess,
|
|
21
|
+
executeGitCommand,
|
|
22
|
+
gitEnvironment,
|
|
23
|
+
GitCommandSource,
|
|
24
|
+
type ICreateGitProcessOptions,
|
|
25
|
+
type IGitCommandModuleOptions,
|
|
26
|
+
type IGitProcessPort,
|
|
27
|
+
type IGitProcessRunOptions,
|
|
28
|
+
type TGitCommandContext,
|
|
29
|
+
type TGitProcessFailureReason,
|
|
30
|
+
type TGitProcessOutcome,
|
|
31
|
+
} from './git/index.js';
|
|
32
|
+
// OBSERVABILITY-1991: named rather than `export *` — the star form is frozen debt in this barrel.
|
|
33
|
+
export {
|
|
34
|
+
STORAGE_REPAIR_ID,
|
|
35
|
+
doctorRepairAllowlist,
|
|
36
|
+
DoctorCommandSource,
|
|
37
|
+
applyDoctorRepair,
|
|
38
|
+
buildDoctorReport,
|
|
39
|
+
collectSettingsSecrets,
|
|
40
|
+
createDoctorCommandEntry,
|
|
41
|
+
createDoctorCommandModule,
|
|
42
|
+
createNodeDoctorDeps,
|
|
43
|
+
isDoctorRepairId,
|
|
44
|
+
planDoctorRepair,
|
|
45
|
+
redactDiagnosticText,
|
|
46
|
+
renderDoctorReport,
|
|
47
|
+
type IDoctorDisplayVocabulary,
|
|
48
|
+
resolveCommandOnPath,
|
|
49
|
+
runDoctor,
|
|
50
|
+
type IDoctorCheck,
|
|
51
|
+
type IDoctorDeps,
|
|
52
|
+
type IDoctorEndpointProbeResult,
|
|
53
|
+
type IDoctorInputs,
|
|
54
|
+
type IDoctorPathFacts,
|
|
55
|
+
type IDoctorRepairPlan,
|
|
56
|
+
type IDoctorReport,
|
|
57
|
+
type TDoctorCheckStatus,
|
|
58
|
+
type TDoctorNotProbed,
|
|
59
|
+
type TDoctorRepairOutcome,
|
|
60
|
+
type TDoctorRepairPlanResult,
|
|
61
|
+
} from './doctor/index.js';
|
|
62
|
+
export {
|
|
63
|
+
EffortCommandSource,
|
|
64
|
+
createEffortCommandEntry,
|
|
65
|
+
createEffortCommandModule,
|
|
66
|
+
executeEffortCommand,
|
|
67
|
+
} from './effort/index.js';
|
|
68
|
+
export {
|
|
69
|
+
ADVISOR_SETTING_KEY,
|
|
70
|
+
AdvisorCommandSource,
|
|
71
|
+
createAdvisorCommandEntry,
|
|
72
|
+
createAdvisorCommandModule,
|
|
73
|
+
executeAdvisorCommand,
|
|
74
|
+
} from './advisor/index.js';
|
|
75
|
+
export * from './exit/index.js';
|
|
76
|
+
export * from './help/index.js';
|
|
77
|
+
export {
|
|
78
|
+
createDevicesCommandModule,
|
|
79
|
+
type IDeviceListEntry,
|
|
80
|
+
type IDevicesCommandPort,
|
|
81
|
+
type IDevicesInitResult,
|
|
82
|
+
type IDevicesAddResult,
|
|
83
|
+
type IDevicesJoinResult,
|
|
84
|
+
type IDevicesRecoverResult,
|
|
85
|
+
type IDevicesRevokeResult,
|
|
86
|
+
type IDevicesMeshStatus,
|
|
87
|
+
type IDevicesView,
|
|
88
|
+
type TDevicesOutcome,
|
|
89
|
+
type TDevicesRefusal,
|
|
90
|
+
} from './devices/index.js';
|
|
91
|
+
export {
|
|
92
|
+
createKeybindingsCommandEntry,
|
|
93
|
+
createKeybindingsCommandModule,
|
|
94
|
+
KeybindingsCommandSource,
|
|
95
|
+
type IKeybindingsFilePort,
|
|
96
|
+
} from './keybindings/index.js';
|
|
97
|
+
export {
|
|
98
|
+
createThemeCommandEntry,
|
|
99
|
+
createThemeCommandModule,
|
|
100
|
+
executeThemeCommand,
|
|
101
|
+
ThemeCommandSource,
|
|
102
|
+
} from './theme/index.js';
|
|
103
|
+
// Re-exported from the contract package so a composition root that depends on this package — the
|
|
104
|
+
// CLI — can name the port it injects without also depending on the interface package directly.
|
|
105
|
+
export type {
|
|
106
|
+
IThemeAppearanceState,
|
|
107
|
+
IThemeCatalogueEntry,
|
|
108
|
+
IThemeCataloguePort,
|
|
109
|
+
TReducedMotionOverride,
|
|
110
|
+
} from './theme/index.js';
|
|
111
|
+
export * from './language/index.js';
|
|
112
|
+
export * from './memory/index.js';
|
|
113
|
+
export {
|
|
114
|
+
createMCPActivationCommandEntry,
|
|
115
|
+
createMCPActivationCommandModule,
|
|
116
|
+
MCPActivationCommandSource,
|
|
117
|
+
} from './mcp-activation/mcp-activation-command-module.js';
|
|
118
|
+
export { executeMCPActivationCommand } from './mcp-activation/mcp-activation-command.js';
|
|
119
|
+
export {
|
|
120
|
+
mcpUnavailableServersNotice,
|
|
121
|
+
mcpUserActionCommand,
|
|
122
|
+
mcpUserActionNotice,
|
|
123
|
+
} from './mcp-activation/mcp-model-notice.js';
|
|
124
|
+
export type { TMCPUserAction, TMCPUserActionSurface } from './mcp-activation/mcp-model-notice.js';
|
|
125
|
+
export * from './mode/index.js';
|
|
126
|
+
export {
|
|
127
|
+
createModelCommandEntry,
|
|
128
|
+
createModelCommandModule,
|
|
129
|
+
ModelCommandSource,
|
|
130
|
+
} from './model/model-command-module.js';
|
|
131
|
+
export { executeModelCommand } from './model/model-command.js';
|
|
132
|
+
export {
|
|
133
|
+
createSandboxCommandModule,
|
|
134
|
+
executeSandboxCommand,
|
|
135
|
+
formatSandboxStatus,
|
|
136
|
+
SANDBOX_MODES,
|
|
137
|
+
SandboxCommandSource,
|
|
138
|
+
} from './sandbox/index.js';
|
|
139
|
+
export {
|
|
140
|
+
OutputStyleCommandSource,
|
|
141
|
+
createOutputStyleCommandEntry,
|
|
142
|
+
createOutputStyleCommandModule,
|
|
143
|
+
executeOutputStyleCommand,
|
|
144
|
+
} from './output-style/index.js';
|
|
145
|
+
export * from './permissions/index.js';
|
|
146
|
+
export * from './plugin/index.js';
|
|
147
|
+
export * from './preset/index.js';
|
|
148
|
+
export * from './shell/index.js';
|
|
149
|
+
export * from './provider/index.js';
|
|
150
|
+
export * from './remote-control/index.js';
|
|
151
|
+
export * from './reset/index.js';
|
|
152
|
+
export * from './rewind/index.js';
|
|
153
|
+
export * from './schedule/index.js';
|
|
154
|
+
export * from './session/index.js';
|
|
155
|
+
export * from './settings/index.js';
|
|
156
|
+
export * from './skills/index.js';
|
|
157
|
+
export * from './statusline/index.js';
|
|
158
|
+
export {
|
|
159
|
+
createTerminalClientCommands,
|
|
160
|
+
type ITerminalClientCommand,
|
|
161
|
+
type ITerminalClientCommandOptions,
|
|
162
|
+
} from './terminal-client/index.js';
|
|
163
|
+
export * from './user-local/index.js';
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import { scriptedSession } from '@robota-sdk/agent-framework/testing';
|
|
4
|
+
|
|
5
|
+
import { createKeybindingsCommandModule } from '../keybindings-command-module.js';
|
|
6
|
+
|
|
7
|
+
import type { ITerminalHandoff } from '@robota-sdk/agent-interface-session';
|
|
8
|
+
|
|
9
|
+
function handoff(enabled: boolean): ITerminalHandoff {
|
|
10
|
+
return {
|
|
11
|
+
canHandoffTerminal: enabled,
|
|
12
|
+
runWithTerminal: async (operation) => operation(),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
describe('/keybindings command', () => {
|
|
17
|
+
it('ensures and opens the exact capability-owned path', async () => {
|
|
18
|
+
const ensureFile = vi.fn().mockResolvedValue('/tmp/keybindings.json');
|
|
19
|
+
const previous = process.env.EDITOR;
|
|
20
|
+
process.env.EDITOR = 'true';
|
|
21
|
+
const session = scriptedSession({
|
|
22
|
+
turns: [{ text: 'unused' }],
|
|
23
|
+
terminalHandoff: handoff(true),
|
|
24
|
+
commandModules: [createKeybindingsCommandModule({ ensureFile })],
|
|
25
|
+
});
|
|
26
|
+
try {
|
|
27
|
+
const result = await session.command('keybindings', '');
|
|
28
|
+
expect(result).toMatchObject({
|
|
29
|
+
success: true,
|
|
30
|
+
message: 'Opened keybindings: /tmp/keybindings.json',
|
|
31
|
+
data: { path: '/tmp/keybindings.json' },
|
|
32
|
+
});
|
|
33
|
+
expect(ensureFile).toHaveBeenCalledTimes(1);
|
|
34
|
+
} finally {
|
|
35
|
+
await session.dispose();
|
|
36
|
+
if (previous === undefined) delete process.env.EDITOR;
|
|
37
|
+
else process.env.EDITOR = previous;
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('reports an unavailable terminal without creating a file', async () => {
|
|
42
|
+
const ensureFile = vi.fn().mockResolvedValue('/tmp/keybindings.json');
|
|
43
|
+
const session = scriptedSession({
|
|
44
|
+
turns: [{ text: 'unused' }],
|
|
45
|
+
terminalHandoff: handoff(false),
|
|
46
|
+
commandModules: [createKeybindingsCommandModule({ ensureFile })],
|
|
47
|
+
});
|
|
48
|
+
try {
|
|
49
|
+
const result = await session.command('keybindings', '');
|
|
50
|
+
expect(result?.success).toBe(false);
|
|
51
|
+
expect(result?.message).toMatch(/unavailable/i);
|
|
52
|
+
expect(ensureFile).not.toHaveBeenCalled();
|
|
53
|
+
} finally {
|
|
54
|
+
await session.dispose();
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
});
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { resolveEditor } from '../editor/resolve-editor.js';
|
|
2
|
+
import { spawnInherited } from '../shell/spawn-inherited.js';
|
|
3
|
+
|
|
4
|
+
import type {
|
|
5
|
+
ICommandHostTerminalHandoff,
|
|
6
|
+
ICommandHostWorkspace,
|
|
7
|
+
ICommandModule,
|
|
8
|
+
ISystemCommand,
|
|
9
|
+
} from '@robota-sdk/agent-framework';
|
|
10
|
+
import type { ICommand, ICommandResult, ICommandSource } from '@robota-sdk/agent-interface-command';
|
|
11
|
+
|
|
12
|
+
export interface IKeybindingsFilePort {
|
|
13
|
+
ensureFile(): Promise<string>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function createKeybindingsCommandEntry(): ICommand {
|
|
17
|
+
return {
|
|
18
|
+
name: 'keybindings',
|
|
19
|
+
displayName: 'Keybindings',
|
|
20
|
+
description: 'Open the contextual terminal keybindings file in $EDITOR',
|
|
21
|
+
source: 'keybindings',
|
|
22
|
+
// User-only: UI preference.
|
|
23
|
+
modelInvocable: false,
|
|
24
|
+
// Key bindings belong to the terminal the user sits at, so that terminal runs it, even when
|
|
25
|
+
// attached.
|
|
26
|
+
runner: 'client',
|
|
27
|
+
surfaces: ['terminal'],
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// A host without a terminal (the desktop app's sidecar) still answers, so the command is never
|
|
32
|
+
// "unknown" there — it says where key bindings live instead.
|
|
33
|
+
const KEYBINDINGS_UNAVAILABLE =
|
|
34
|
+
'Key bindings are available in an interactive terminal. Run /keybindings there.';
|
|
35
|
+
|
|
36
|
+
export async function executeKeybindingsCommand(
|
|
37
|
+
file: IKeybindingsFilePort | undefined,
|
|
38
|
+
context: ICommandHostTerminalHandoff & ICommandHostWorkspace,
|
|
39
|
+
): Promise<ICommandResult> {
|
|
40
|
+
if (!file) return { success: false, message: KEYBINDINGS_UNAVAILABLE };
|
|
41
|
+
if (!context.canHandoffTerminal()) {
|
|
42
|
+
return { success: false, message: 'Keybindings editor is unavailable here.' };
|
|
43
|
+
}
|
|
44
|
+
const path = await file.ensureFile();
|
|
45
|
+
const editor = resolveEditor();
|
|
46
|
+
const exitCode = await context.runWithTerminal(() =>
|
|
47
|
+
spawnInherited(editor.command, [...editor.args, path], context.getCwd()),
|
|
48
|
+
);
|
|
49
|
+
if (exitCode !== 0) {
|
|
50
|
+
return {
|
|
51
|
+
success: false,
|
|
52
|
+
message: `Keybindings editor exited with code ${exitCode}.`,
|
|
53
|
+
data: { path, exitCode },
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return { success: true, message: `Opened keybindings: ${path}`, data: { path } };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export class KeybindingsCommandSource implements ICommandSource {
|
|
60
|
+
readonly name = 'keybindings';
|
|
61
|
+
|
|
62
|
+
getCommands(): ICommand[] {
|
|
63
|
+
return [createKeybindingsCommandEntry()];
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function createKeybindingsCommandModule(
|
|
68
|
+
file: IKeybindingsFilePort | undefined,
|
|
69
|
+
): ICommandModule {
|
|
70
|
+
const entry = createKeybindingsCommandEntry();
|
|
71
|
+
const command: ISystemCommand = {
|
|
72
|
+
name: entry.name,
|
|
73
|
+
displayName: entry.displayName,
|
|
74
|
+
description: entry.description,
|
|
75
|
+
requiresPermission: false,
|
|
76
|
+
userInvocable: true,
|
|
77
|
+
modelInvocable: false,
|
|
78
|
+
runner: entry.runner,
|
|
79
|
+
surfaces: entry.surfaces,
|
|
80
|
+
lifecycle: 'inline',
|
|
81
|
+
execute: (context) => executeKeybindingsCommand(file, context),
|
|
82
|
+
};
|
|
83
|
+
return {
|
|
84
|
+
name: 'agent-command-keybindings',
|
|
85
|
+
commandSources: [new KeybindingsCommandSource()],
|
|
86
|
+
systemCommands: [command],
|
|
87
|
+
};
|
|
88
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
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
|
+
import { createTestCommandHost } from '@robota-sdk/agent-framework/testing';
|
|
9
|
+
|
|
10
|
+
function createCheckpointResult(): IEditCheckpointRestoreResult {
|
|
11
|
+
return {
|
|
12
|
+
target: {
|
|
13
|
+
id: 'checkpoint_1',
|
|
14
|
+
sessionId: 'session_1',
|
|
15
|
+
sequence: 1,
|
|
16
|
+
prompt: 'edit files',
|
|
17
|
+
createdAt: '2026-05-03T00:00:00.000Z',
|
|
18
|
+
fileCount: 1,
|
|
19
|
+
},
|
|
20
|
+
restoredCheckpointCount: 0,
|
|
21
|
+
restoredFileCount: 0,
|
|
22
|
+
removedCheckpointCount: 0,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const commandHostContext = createTestCommandHost({
|
|
27
|
+
overrides: {
|
|
28
|
+
getSession: () => {
|
|
29
|
+
throw new Error('language command should not read session runtime');
|
|
30
|
+
},
|
|
31
|
+
getContextState: () => ({
|
|
32
|
+
usedTokens: 0,
|
|
33
|
+
maxTokens: 1,
|
|
34
|
+
usedPercentage: 0,
|
|
35
|
+
remainingPercentage: 100,
|
|
36
|
+
}),
|
|
37
|
+
getAutoCompactThreshold: () => 0.835,
|
|
38
|
+
compactContext: async () => undefined,
|
|
39
|
+
getCwd: () => '/workspace',
|
|
40
|
+
listEditCheckpoints: () => [],
|
|
41
|
+
restoreEditCheckpoint: async () => createCheckpointResult(),
|
|
42
|
+
rollbackEditCheckpoint: async () => createCheckpointResult(),
|
|
43
|
+
getUsedMemoryReferences: () => [],
|
|
44
|
+
recordMemoryEvent: () => undefined,
|
|
45
|
+
listBackgroundTasks: () => [],
|
|
46
|
+
readBackgroundTaskLog: async () => ({ taskId: 'task_1', lines: [] }),
|
|
47
|
+
cancelBackgroundTask: async () => undefined,
|
|
48
|
+
closeBackgroundTask: async () => undefined,
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe('createLanguageCommandModule', () => {
|
|
53
|
+
it('provides language metadata and executable command from one module owner', () => {
|
|
54
|
+
const module = createLanguageCommandModule();
|
|
55
|
+
const command = module.systemCommands?.[0];
|
|
56
|
+
const entry = module.commandSources?.[0]?.getCommands()[0];
|
|
57
|
+
|
|
58
|
+
expect(module.name).toBe('agent-command-language');
|
|
59
|
+
expect(entry).toEqual(
|
|
60
|
+
expect.objectContaining({
|
|
61
|
+
name: 'language',
|
|
62
|
+
description: 'Set response language',
|
|
63
|
+
argumentHint: '<code>',
|
|
64
|
+
source: 'language',
|
|
65
|
+
modelInvocable: false,
|
|
66
|
+
}),
|
|
67
|
+
);
|
|
68
|
+
expect(entry?.subcommands?.map((subcommand) => subcommand.name)).toEqual([
|
|
69
|
+
'ko',
|
|
70
|
+
'en',
|
|
71
|
+
'ja',
|
|
72
|
+
'zh',
|
|
73
|
+
]);
|
|
74
|
+
expect(command).toEqual(
|
|
75
|
+
expect.objectContaining({
|
|
76
|
+
name: 'language',
|
|
77
|
+
description: 'Set response language',
|
|
78
|
+
argumentHint: '<code>',
|
|
79
|
+
lifecycle: 'inline',
|
|
80
|
+
modelInvocable: false,
|
|
81
|
+
}),
|
|
82
|
+
);
|
|
83
|
+
expect(command?.subcommands).toEqual(entry?.subcommands);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('requests language changes through a typed command effect', async () => {
|
|
87
|
+
const executor = new SystemCommandExecutor([
|
|
88
|
+
...(createLanguageCommandModule().systemCommands ?? []),
|
|
89
|
+
]);
|
|
90
|
+
|
|
91
|
+
const result = await executor.execute('language', commandHostContext, 'ko');
|
|
92
|
+
|
|
93
|
+
expect(result?.success).toBe(true);
|
|
94
|
+
expect(result?.data?.language).toBe('ko');
|
|
95
|
+
expect(result?.hostActions).toEqual([{ type: 'language-change', language: 'ko' }]);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('shows usage when no language code is provided', async () => {
|
|
99
|
+
const executor = new SystemCommandExecutor([
|
|
100
|
+
...(createLanguageCommandModule().systemCommands ?? []),
|
|
101
|
+
]);
|
|
102
|
+
|
|
103
|
+
const result = await executor.execute('language', commandHostContext, '');
|
|
104
|
+
|
|
105
|
+
expect(result?.success).toBe(false);
|
|
106
|
+
expect(result?.message).toBe('Usage: language <code> (e.g., ko, en, ja, zh)');
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it('asks the user to pick a language when none is provided (CMD-004)', async () => {
|
|
110
|
+
const executor = new SystemCommandExecutor([
|
|
111
|
+
...(createLanguageCommandModule().systemCommands ?? []),
|
|
112
|
+
]);
|
|
113
|
+
const contextWithAsk = createTestCommandHost({
|
|
114
|
+
overrides: {
|
|
115
|
+
...commandHostContext,
|
|
116
|
+
getUserInteraction: () => ({ ask: async () => ({ type: 'answer', values: ['ko'] }) }),
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
const result = await executor.execute('language', contextWithAsk, '');
|
|
121
|
+
|
|
122
|
+
expect(result?.success).toBe(true);
|
|
123
|
+
expect(result?.data?.language).toBe('ko');
|
|
124
|
+
expect(result?.hostActions).toEqual([{ type: 'language-change', language: 'ko' }]);
|
|
125
|
+
});
|
|
126
|
+
});
|