@pellux/goodvibes-agent 1.0.2 → 1.0.4
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 +13 -0
- package/README.md +2 -2
- package/dist/package/main.js +1139 -390
- package/docs/README.md +2 -2
- package/docs/getting-started.md +2 -2
- package/docs/tools-and-commands.md +9 -3
- package/package.json +1 -1
- package/src/cli/help.ts +26 -0
- package/src/tools/agent-harness-cli-metadata.ts +152 -0
- package/src/tools/agent-harness-keybinding-metadata.ts +262 -0
- package/src/tools/agent-harness-metadata.ts +108 -0
- package/src/tools/agent-harness-model-tool-catalog.ts +36 -0
- package/src/tools/agent-harness-panel-metadata.ts +121 -0
- package/src/tools/agent-harness-tool.ts +112 -87
- package/src/version.ts +1 -1
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { ToolRegistry } from '@pellux/goodvibes-sdk/platform/tools';
|
|
2
|
+
|
|
3
|
+
export interface AgentHarnessModelToolCatalogArgs {
|
|
4
|
+
readonly query?: unknown;
|
|
5
|
+
readonly includeParameters?: unknown;
|
|
6
|
+
readonly limit?: unknown;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
function readString(value: unknown): string {
|
|
10
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function readLimit(value: unknown, fallback: number): number {
|
|
14
|
+
const parsed = typeof value === 'string' && value.trim() ? Number(value) : value;
|
|
15
|
+
if (typeof parsed !== 'number' || !Number.isFinite(parsed)) return fallback;
|
|
16
|
+
return Math.max(1, Math.min(500, Math.trunc(parsed)));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function listHarnessModelTools(toolRegistry: ToolRegistry, args: AgentHarnessModelToolCatalogArgs): readonly Record<string, unknown>[] {
|
|
20
|
+
const query = readString(args.query).toLowerCase();
|
|
21
|
+
const includeParameters = args.includeParameters === true;
|
|
22
|
+
const limit = readLimit(args.limit, 200);
|
|
23
|
+
return toolRegistry.getToolDefinitions()
|
|
24
|
+
.filter((tool) => !query || [tool.name, tool.description, ...(tool.sideEffects ?? [])].join('\n').toLowerCase().includes(query))
|
|
25
|
+
.sort((a, b) => a.name.localeCompare(b.name))
|
|
26
|
+
.slice(0, limit)
|
|
27
|
+
.map((tool) => ({
|
|
28
|
+
name: tool.name,
|
|
29
|
+
description: tool.description,
|
|
30
|
+
sideEffects: tool.sideEffects ?? [],
|
|
31
|
+
concurrency: tool.concurrency ?? 'parallel',
|
|
32
|
+
supportsProgress: tool.supportsProgress ?? false,
|
|
33
|
+
supportsStreamingOutput: tool.supportsStreamingOutput ?? false,
|
|
34
|
+
...(includeParameters ? { parameters: tool.parameters } : {}),
|
|
35
|
+
}));
|
|
36
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import type { CommandContext } from '../input/command-registry.ts';
|
|
2
|
+
import { agentWorkspaceCategoryForPanel, agentWorkspaceCommandForPanel } from '../input/agent-workspace-panel-route.ts';
|
|
3
|
+
import type { PanelRegistration } from '../panels/types.ts';
|
|
4
|
+
|
|
5
|
+
export interface AgentHarnessPanelArgs {
|
|
6
|
+
readonly query?: unknown;
|
|
7
|
+
readonly panelId?: unknown;
|
|
8
|
+
readonly category?: unknown;
|
|
9
|
+
readonly limit?: unknown;
|
|
10
|
+
readonly pane?: unknown;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function readString(value: unknown): string {
|
|
14
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function readLimit(value: unknown, fallback: number): number {
|
|
18
|
+
const parsed = typeof value === 'string' && value.trim() ? Number(value) : value;
|
|
19
|
+
if (typeof parsed !== 'number' || !Number.isFinite(parsed)) return fallback;
|
|
20
|
+
return Math.max(1, Math.min(500, Math.trunc(parsed)));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function panelManager(context: CommandContext) {
|
|
24
|
+
return context.workspace.panelManager ?? null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function panelMatches(panel: Record<string, unknown>, query: string): boolean {
|
|
28
|
+
if (!query) return true;
|
|
29
|
+
return [
|
|
30
|
+
panel.id,
|
|
31
|
+
panel.name,
|
|
32
|
+
panel.category,
|
|
33
|
+
panel.description,
|
|
34
|
+
panel.workspaceRoute,
|
|
35
|
+
].map((value) => String(value ?? '')).join('\n').toLowerCase().includes(query.toLowerCase());
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function describePanelRegistration(context: CommandContext, registration: PanelRegistration): Record<string, unknown> {
|
|
39
|
+
const manager = panelManager(context);
|
|
40
|
+
const openPanel = manager?.getPanel(registration.id) ?? null;
|
|
41
|
+
const pane = manager?.getPaneOf(registration.id) ?? null;
|
|
42
|
+
const activePanel = manager?.getActivePanel() ?? null;
|
|
43
|
+
return {
|
|
44
|
+
id: registration.id,
|
|
45
|
+
name: registration.name,
|
|
46
|
+
icon: registration.icon,
|
|
47
|
+
category: registration.category,
|
|
48
|
+
description: registration.description,
|
|
49
|
+
preload: registration.preload === true,
|
|
50
|
+
open: openPanel !== null,
|
|
51
|
+
pane,
|
|
52
|
+
active: activePanel?.id === registration.id,
|
|
53
|
+
focused: activePanel?.id === registration.id,
|
|
54
|
+
workspaceRoute: {
|
|
55
|
+
categoryId: agentWorkspaceCategoryForPanel(registration.id),
|
|
56
|
+
command: agentWorkspaceCommandForPanel(registration.id),
|
|
57
|
+
},
|
|
58
|
+
policy: {
|
|
59
|
+
effect: 'ui-navigation',
|
|
60
|
+
confirmation: 'agent_harness mode:"open_panel" requires confirm:true and explicitUserRequest.',
|
|
61
|
+
boundary: 'Panels are Agent/TUI operator views. The model can inspect panel catalog/open state; panel routing uses the existing Agent workspace bridge and does not mutate connected-host lifecycle.',
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function totalHarnessPanels(context: CommandContext): number {
|
|
67
|
+
return panelManager(context)?.getRegisteredTypes().length ?? 0;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function listHarnessPanels(context: CommandContext, args: AgentHarnessPanelArgs): readonly Record<string, unknown>[] {
|
|
71
|
+
const manager = panelManager(context);
|
|
72
|
+
if (!manager) return [];
|
|
73
|
+
const query = readString(args.query);
|
|
74
|
+
const category = readString(args.category);
|
|
75
|
+
const limit = readLimit(args.limit, 200);
|
|
76
|
+
return manager.getRegisteredTypes()
|
|
77
|
+
.map((registration) => describePanelRegistration(context, registration))
|
|
78
|
+
.filter((panel) => !category || panel.category === category)
|
|
79
|
+
.filter((panel) => panelMatches(panel, query))
|
|
80
|
+
.sort((a, b) => String(a.id).localeCompare(String(b.id)))
|
|
81
|
+
.slice(0, limit);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function describeHarnessPanel(context: CommandContext, args: AgentHarnessPanelArgs): Record<string, unknown> | null {
|
|
85
|
+
const manager = panelManager(context);
|
|
86
|
+
if (!manager) return null;
|
|
87
|
+
const panelId = readString(args.panelId || args.query);
|
|
88
|
+
if (!panelId) return null;
|
|
89
|
+
const registration = manager.getRegisteredTypes().find((panel) => (
|
|
90
|
+
panel.id === panelId
|
|
91
|
+
|| panel.name.toLowerCase() === panelId.toLowerCase()
|
|
92
|
+
));
|
|
93
|
+
return registration ? describePanelRegistration(context, registration) : null;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function openHarnessPanel(context: CommandContext, args: AgentHarnessPanelArgs): Record<string, unknown> {
|
|
97
|
+
const panel = describeHarnessPanel(context, args);
|
|
98
|
+
if (!panel) {
|
|
99
|
+
return {
|
|
100
|
+
status: 'unknown_panel',
|
|
101
|
+
panelId: readString(args.panelId || args.query) || '<missing>',
|
|
102
|
+
availablePanels: listHarnessPanels(context, { limit: 50 }).map((entry) => entry.id),
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
const requestedPane = readString(args.pane);
|
|
106
|
+
const pane = requestedPane === 'bottom' || requestedPane === 'top' ? requestedPane : undefined;
|
|
107
|
+
if (!context.showPanel) {
|
|
108
|
+
return {
|
|
109
|
+
status: 'route_unavailable',
|
|
110
|
+
panel,
|
|
111
|
+
note: 'The current runtime did not provide showPanel. Use the returned workspaceRoute from the TUI.',
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
context.showPanel(String(panel.id), pane);
|
|
115
|
+
return {
|
|
116
|
+
status: 'routed',
|
|
117
|
+
panel,
|
|
118
|
+
pane: pane ?? 'default',
|
|
119
|
+
note: 'Panel routing was handed to the current Agent shell bridge.',
|
|
120
|
+
};
|
|
121
|
+
}
|
|
@@ -17,11 +17,13 @@ import type {
|
|
|
17
17
|
AgentWorkspaceRuntimeSnapshot,
|
|
18
18
|
} from '../input/agent-workspace-types.ts';
|
|
19
19
|
import { parseSlashCommand } from '../input/slash-command-parser.ts';
|
|
20
|
+
import { blockedHarnessCliCommandTokens, describeHarnessCliCommand, listHarnessCliCommands, totalHarnessCliCommands } from './agent-harness-cli-metadata.ts';
|
|
21
|
+
import { describeHarnessKeybinding, listHarnessKeybindings, listHarnessShortcuts, resetHarnessKeybinding, setHarnessKeybinding, totalHarnessKeybindings, totalHarnessShortcuts } from './agent-harness-keybinding-metadata.ts';
|
|
22
|
+
import { describeHarnessPanel, listHarnessPanels, openHarnessPanel, totalHarnessPanels } from './agent-harness-panel-metadata.ts';
|
|
20
23
|
import { describeLocalWorkspaceModelExecution, runLocalWorkspaceAction } from './agent-harness-local-operations.ts';
|
|
24
|
+
import { listHarnessModelTools } from './agent-harness-model-tool-catalog.ts';
|
|
21
25
|
import {
|
|
22
|
-
|
|
23
|
-
connectedHostCapabilityMap,
|
|
24
|
-
connectedHostRouteFamilies,
|
|
26
|
+
connectedHostSummary,
|
|
25
27
|
describeCommandPolicy,
|
|
26
28
|
settingsPolicySummary,
|
|
27
29
|
} from './agent-harness-metadata.ts';
|
|
@@ -32,35 +34,31 @@ import {
|
|
|
32
34
|
resetHarnessSetting,
|
|
33
35
|
setHarnessSetting,
|
|
34
36
|
} from '../agent/harness-control.ts';
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
| 'reset_setting'
|
|
46
|
-
| 'workspace'
|
|
47
|
-
| 'workspace_categories'
|
|
48
|
-
| 'workspace_actions'
|
|
49
|
-
| 'workspace_action'
|
|
50
|
-
| 'run_workspace_action'
|
|
51
|
-
| 'tools'
|
|
52
|
-
| 'connected_host';
|
|
37
|
+
|
|
38
|
+
const MODES = [
|
|
39
|
+
'summary', 'cli_commands', 'cli_command', 'panels', 'panel', 'open_panel',
|
|
40
|
+
'shortcuts', 'keybindings', 'keybinding', 'set_keybinding', 'reset_keybinding',
|
|
41
|
+
'commands', 'command', 'run_command', 'settings', 'get_setting', 'set_setting',
|
|
42
|
+
'reset_setting', 'workspace', 'workspace_categories', 'workspace_actions',
|
|
43
|
+
'workspace_action', 'run_workspace_action', 'tools', 'connected_host',
|
|
44
|
+
] as const;
|
|
45
|
+
|
|
46
|
+
type AgentHarnessMode = typeof MODES[number];
|
|
53
47
|
|
|
54
48
|
interface AgentHarnessToolArgs {
|
|
55
49
|
readonly mode?: unknown;
|
|
56
50
|
readonly query?: unknown;
|
|
57
51
|
readonly command?: unknown;
|
|
52
|
+
readonly cliCommand?: unknown;
|
|
58
53
|
readonly commandName?: unknown;
|
|
59
54
|
readonly args?: unknown;
|
|
60
55
|
readonly categoryId?: unknown;
|
|
56
|
+
readonly panelId?: unknown;
|
|
61
57
|
readonly actionId?: unknown;
|
|
62
58
|
readonly recordId?: unknown;
|
|
63
59
|
readonly fields?: unknown;
|
|
60
|
+
readonly combo?: unknown;
|
|
61
|
+
readonly combos?: unknown;
|
|
64
62
|
readonly key?: unknown;
|
|
65
63
|
readonly value?: unknown;
|
|
66
64
|
readonly category?: unknown;
|
|
@@ -68,6 +66,7 @@ interface AgentHarnessToolArgs {
|
|
|
68
66
|
readonly includeHidden?: unknown;
|
|
69
67
|
readonly includeParameters?: unknown;
|
|
70
68
|
readonly limit?: unknown;
|
|
69
|
+
readonly pane?: unknown;
|
|
71
70
|
readonly confirm?: unknown;
|
|
72
71
|
readonly explicitUserRequest?: unknown;
|
|
73
72
|
}
|
|
@@ -83,24 +82,6 @@ interface WorkspaceEditorContext {
|
|
|
83
82
|
readonly selectedRoutine: AgentWorkspaceLocalLibraryItem | null;
|
|
84
83
|
}
|
|
85
84
|
|
|
86
|
-
const MODES: readonly AgentHarnessMode[] = [
|
|
87
|
-
'summary',
|
|
88
|
-
'commands',
|
|
89
|
-
'command',
|
|
90
|
-
'run_command',
|
|
91
|
-
'settings',
|
|
92
|
-
'get_setting',
|
|
93
|
-
'set_setting',
|
|
94
|
-
'reset_setting',
|
|
95
|
-
'workspace',
|
|
96
|
-
'workspace_categories',
|
|
97
|
-
'workspace_actions',
|
|
98
|
-
'workspace_action',
|
|
99
|
-
'run_workspace_action',
|
|
100
|
-
'tools',
|
|
101
|
-
'connected_host',
|
|
102
|
-
];
|
|
103
|
-
|
|
104
85
|
function isMode(value: unknown): value is AgentHarnessMode {
|
|
105
86
|
return typeof value === 'string' && MODES.includes(value as AgentHarnessMode);
|
|
106
87
|
}
|
|
@@ -132,9 +113,14 @@ function output(value: unknown): { readonly success: true; readonly output: stri
|
|
|
132
113
|
};
|
|
133
114
|
}
|
|
134
115
|
|
|
135
|
-
function error(message: string): { readonly success: false; readonly error: string } {
|
|
136
|
-
|
|
137
|
-
|
|
116
|
+
function error(message: string): { readonly success: false; readonly error: string } { return { success: false, error: message }; }
|
|
117
|
+
|
|
118
|
+
const KEY_COMBO_PARAMETER_SCHEMA = {
|
|
119
|
+
type: 'object',
|
|
120
|
+
properties: { key: { type: 'string' }, ctrl: { type: 'boolean' }, shift: { type: 'boolean' }, alt: { type: 'boolean' } },
|
|
121
|
+
required: ['key'],
|
|
122
|
+
additionalProperties: false,
|
|
123
|
+
} as const;
|
|
138
124
|
|
|
139
125
|
function commandMatches(command: SlashCommand, query: string): boolean {
|
|
140
126
|
if (!query) return true;
|
|
@@ -307,28 +293,6 @@ function listCommands(commandRegistry: CommandRegistry, args: AgentHarnessToolAr
|
|
|
307
293
|
.map(describeCommand);
|
|
308
294
|
}
|
|
309
295
|
|
|
310
|
-
function listTools(toolRegistry: ToolRegistry, args: AgentHarnessToolArgs): readonly Record<string, unknown>[] {
|
|
311
|
-
const query = readString(args.query).toLowerCase();
|
|
312
|
-
const includeParameters = args.includeParameters === true;
|
|
313
|
-
const limit = readLimit(args.limit, 200);
|
|
314
|
-
return toolRegistry.getToolDefinitions()
|
|
315
|
-
.filter((tool) => {
|
|
316
|
-
if (!query) return true;
|
|
317
|
-
return [tool.name, tool.description, ...(tool.sideEffects ?? [])].join('\n').toLowerCase().includes(query);
|
|
318
|
-
})
|
|
319
|
-
.sort((a, b) => a.name.localeCompare(b.name))
|
|
320
|
-
.slice(0, limit)
|
|
321
|
-
.map((tool) => ({
|
|
322
|
-
name: tool.name,
|
|
323
|
-
description: tool.description,
|
|
324
|
-
sideEffects: tool.sideEffects ?? [],
|
|
325
|
-
concurrency: tool.concurrency ?? 'parallel',
|
|
326
|
-
supportsProgress: tool.supportsProgress ?? false,
|
|
327
|
-
supportsStreamingOutput: tool.supportsStreamingOutput ?? false,
|
|
328
|
-
...(includeParameters ? { parameters: tool.parameters } : {}),
|
|
329
|
-
}));
|
|
330
|
-
}
|
|
331
|
-
|
|
332
296
|
function requireConfirmedAction(args: AgentHarnessToolArgs, action: string): string | null {
|
|
333
297
|
const explicitUserRequest = readString(args.explicitUserRequest);
|
|
334
298
|
if (!explicitUserRequest) return `${action} requires explicitUserRequest with the user's exact request or a short faithful summary.`;
|
|
@@ -544,30 +508,14 @@ async function runWorkspaceAction(
|
|
|
544
508
|
});
|
|
545
509
|
}
|
|
546
510
|
|
|
547
|
-
function connectedHostSummary(context: CommandContext, toolRegistry: ToolRegistry): Record<string, unknown> {
|
|
548
|
-
const shellPaths = context.workspace.shellPaths;
|
|
549
|
-
const homeDirectory = shellPaths?.homeDirectory ?? context.platform.configManager.getHomeDirectory() ?? '';
|
|
550
|
-
const connection = resolveAgentConnectedHostConnection(context.platform.configManager, homeDirectory);
|
|
551
|
-
return {
|
|
552
|
-
baseUrl: connection.baseUrl,
|
|
553
|
-
operatorToken: connection.token ? 'configured' : 'missing',
|
|
554
|
-
tokenPath: connection.tokenPath,
|
|
555
|
-
ownership: 'external-connected-host',
|
|
556
|
-
lifecycle: 'GoodVibes Agent can use public connected-host operator routes, but does not start, stop, restart, install, expose, or mutate the host listener.',
|
|
557
|
-
routeFamilies: connectedHostRouteFamilies(),
|
|
558
|
-
capabilities: connectedHostCapabilityMap(toolRegistry),
|
|
559
|
-
blockedCapabilities: blockedConnectedHostCapabilities(),
|
|
560
|
-
};
|
|
561
|
-
}
|
|
562
|
-
|
|
563
511
|
export function createAgentHarnessTool(deps: AgentHarnessToolDeps): Tool {
|
|
564
512
|
return {
|
|
565
513
|
definition: {
|
|
566
514
|
name: 'agent_harness',
|
|
567
515
|
description: [
|
|
568
516
|
'Discover and operate the GoodVibes Agent harness from the main conversation.',
|
|
569
|
-
'Use this tool to inspect Agent workspace actions, slash commands with policy metadata, model tools, connected-host capabilities, and Agent settings, or to invoke a workspace action/command through the same in-process command registry the user uses in the TUI.',
|
|
570
|
-
'Discovery modes are read-only. Setting writes, resets, slash command invocation, and workspace action invocation require confirm:true plus explicitUserRequest.',
|
|
517
|
+
'Use this tool to inspect Agent workspace actions, built-in panels, top-level CLI mirrors, keybindings, slash commands with policy metadata, model tools, connected-host capabilities, and Agent settings, or to invoke a workspace action/command through the same in-process command registry the user uses in the TUI.',
|
|
518
|
+
'Discovery modes are read-only. Setting/keybinding writes, resets, slash command invocation, and workspace action invocation require confirm:true plus explicitUserRequest.',
|
|
571
519
|
'This tool preserves Agent product boundaries: connected-host lifecycle and listener posture stay externally owned, connected-host mode reports allowed and blocked route families, and secret-backed settings store raw values through the secret manager while config receives only a secret reference.',
|
|
572
520
|
].join(' '),
|
|
573
521
|
parameters: {
|
|
@@ -584,11 +532,15 @@ export function createAgentHarnessTool(deps: AgentHarnessToolDeps): Tool {
|
|
|
584
532
|
},
|
|
585
533
|
command: {
|
|
586
534
|
type: 'string',
|
|
587
|
-
description: 'Full slash command string for mode run_command, for example "/settings get provider.model".',
|
|
535
|
+
description: 'Full slash command string for mode run_command, for example "/settings get provider.model". In cli_command mode this may also hold a top-level CLI string such as "goodvibes-agent status --json".',
|
|
536
|
+
},
|
|
537
|
+
cliCommand: {
|
|
538
|
+
type: 'string',
|
|
539
|
+
description: 'Top-level CLI command string for mode cli_command, for example "goodvibes-agent status --json" or "profiles list". This mode is read-only metadata/parse inspection.',
|
|
588
540
|
},
|
|
589
541
|
commandName: {
|
|
590
542
|
type: 'string',
|
|
591
|
-
description: 'Slash command root without the leading slash for mode command or run_command.',
|
|
543
|
+
description: 'Slash command root without the leading slash for mode command or run_command, or a top-level CLI command token for cli_command.',
|
|
592
544
|
},
|
|
593
545
|
args: {
|
|
594
546
|
type: 'array',
|
|
@@ -599,15 +551,28 @@ export function createAgentHarnessTool(deps: AgentHarnessToolDeps): Tool {
|
|
|
599
551
|
type: 'string',
|
|
600
552
|
description: 'Agent workspace category id for workspace action filtering.',
|
|
601
553
|
},
|
|
554
|
+
panelId: {
|
|
555
|
+
type: 'string',
|
|
556
|
+
description: 'Built-in panel id for panel or open_panel modes.',
|
|
557
|
+
},
|
|
602
558
|
actionId: {
|
|
603
559
|
type: 'string',
|
|
604
|
-
description: 'Agent workspace action id for workspace_action or run_workspace_action.',
|
|
560
|
+
description: 'Agent workspace action id for workspace_action or run_workspace_action, or keybinding action id for keybinding/set_keybinding/reset_keybinding.',
|
|
605
561
|
},
|
|
606
562
|
fields: {
|
|
607
563
|
type: 'object',
|
|
608
564
|
additionalProperties: { type: 'string' },
|
|
609
565
|
description: 'Field values for run_workspace_action when the workspace action opens an editor form.',
|
|
610
566
|
},
|
|
567
|
+
combo: {
|
|
568
|
+
...KEY_COMBO_PARAMETER_SCHEMA,
|
|
569
|
+
description: 'Single key combo for set_keybinding, for example { "key": "g", "ctrl": true }.',
|
|
570
|
+
},
|
|
571
|
+
combos: {
|
|
572
|
+
type: 'array',
|
|
573
|
+
items: KEY_COMBO_PARAMETER_SCHEMA,
|
|
574
|
+
description: 'Multiple key combos for set_keybinding.',
|
|
575
|
+
},
|
|
611
576
|
recordId: {
|
|
612
577
|
type: 'string',
|
|
613
578
|
description: 'Selected Agent-local record id for selection-based local workspace operations.',
|
|
@@ -644,9 +609,14 @@ export function createAgentHarnessTool(deps: AgentHarnessToolDeps): Tool {
|
|
|
644
609
|
type: 'number',
|
|
645
610
|
description: 'Maximum catalog entries to return.',
|
|
646
611
|
},
|
|
612
|
+
pane: {
|
|
613
|
+
type: 'string',
|
|
614
|
+
enum: ['top', 'bottom'],
|
|
615
|
+
description: 'Preferred panel pane for open_panel when the current shell supports panel routing.',
|
|
616
|
+
},
|
|
647
617
|
confirm: {
|
|
648
618
|
type: 'boolean',
|
|
649
|
-
description: 'Required true for set_setting, reset_setting, run_command, and mutating run_workspace_action calls after an explicit user request.',
|
|
619
|
+
description: 'Required true for set_setting, reset_setting, run_command, open_panel, and mutating run_workspace_action calls after an explicit user request.',
|
|
650
620
|
},
|
|
651
621
|
explicitUserRequest: {
|
|
652
622
|
type: 'string',
|
|
@@ -665,12 +635,20 @@ export function createAgentHarnessTool(deps: AgentHarnessToolDeps): Tool {
|
|
|
665
635
|
try {
|
|
666
636
|
if (args.mode === 'summary') {
|
|
667
637
|
return output({
|
|
638
|
+
cliCommands: totalHarnessCliCommands(),
|
|
639
|
+
blockedCliCommandTokens: blockedHarnessCliCommandTokens(),
|
|
640
|
+
panels: totalHarnessPanels(deps.commandContext),
|
|
641
|
+
shortcuts: totalHarnessShortcuts(deps.commandContext),
|
|
642
|
+
keybindings: totalHarnessKeybindings(deps.commandContext),
|
|
668
643
|
commands: deps.commandRegistry.list().length,
|
|
669
644
|
settings: deps.commandContext.platform.configManager.getSchema().length,
|
|
670
645
|
workspaceCategories: AGENT_WORKSPACE_CATEGORIES.length,
|
|
671
646
|
workspaceActions: allWorkspaceActions().length,
|
|
672
647
|
tools: deps.toolRegistry.getToolDefinitions().length,
|
|
673
648
|
modelAccess: {
|
|
649
|
+
cliCommands: 'Use mode:"cli_commands" and mode:"cli_command" to inspect package CLI mirrors and their preferred in-process model routes. CLI modes are discovery-only.',
|
|
650
|
+
panels: 'Use mode:"panels" and mode:"panel" to inspect built-in panel catalog/open state; use mode:"open_panel" with confirm:true plus explicitUserRequest to route a visible panel/workspace change.',
|
|
651
|
+
shortcuts: 'Use mode:"shortcuts" to inspect fixed shortcuts plus configurable keybindings. Use mode:"set_keybinding" and mode:"reset_keybinding" with confirm:true plus explicitUserRequest to edit the same config file the user edits.',
|
|
674
652
|
slashCommands: 'Use mode:"commands" and mode:"command" to inspect; use mode:"run_command" with confirm:true plus explicitUserRequest to execute.',
|
|
675
653
|
workspace: 'Use mode:"workspace_actions" to list and mode:"workspace_action" for editor schemas; set includeParameters:true on workspace_actions to inline editor schemas.',
|
|
676
654
|
settings: 'Use mode:"settings", mode:"get_setting", mode:"set_setting", and mode:"reset_setting".',
|
|
@@ -681,6 +659,53 @@ export function createAgentHarnessTool(deps: AgentHarnessToolDeps): Tool {
|
|
|
681
659
|
connectedHost: connectedHostSummary(deps.commandContext, deps.toolRegistry),
|
|
682
660
|
});
|
|
683
661
|
}
|
|
662
|
+
if (args.mode === 'cli_commands') {
|
|
663
|
+
const commands = listHarnessCliCommands(args);
|
|
664
|
+
return output({
|
|
665
|
+
commands,
|
|
666
|
+
returned: commands.length,
|
|
667
|
+
total: totalHarnessCliCommands(),
|
|
668
|
+
blockedTokens: blockedHarnessCliCommandTokens(),
|
|
669
|
+
policy: 'CLI modes are read-only discovery. Use first-class model tools, workspace actions, settings modes, or confirmed slash-command mirrors for in-process operation.',
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
if (args.mode === 'cli_command') {
|
|
673
|
+
return output(describeHarnessCliCommand(args));
|
|
674
|
+
}
|
|
675
|
+
if (args.mode === 'panels') {
|
|
676
|
+
const panels = listHarnessPanels(deps.commandContext, args);
|
|
677
|
+
return output({
|
|
678
|
+
panels,
|
|
679
|
+
returned: panels.length,
|
|
680
|
+
total: totalHarnessPanels(deps.commandContext),
|
|
681
|
+
policy: 'Panel modes expose Agent/TUI operator view catalog and open state. open_panel is confirmation-gated and routes through the current Agent shell bridge.',
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
if (args.mode === 'panel') {
|
|
685
|
+
const panel = describeHarnessPanel(deps.commandContext, args);
|
|
686
|
+
return panel ? output(panel) : error(`Unknown panel ${readString(args.panelId || args.query) || '<missing>'}.`);
|
|
687
|
+
}
|
|
688
|
+
if (args.mode === 'open_panel') {
|
|
689
|
+
const confirmationError = requireConfirmedAction(args, 'Panel routing');
|
|
690
|
+
if (confirmationError) return error(confirmationError);
|
|
691
|
+
return output(openHarnessPanel(deps.commandContext, args));
|
|
692
|
+
}
|
|
693
|
+
if (args.mode === 'shortcuts') return output(listHarnessShortcuts(deps.commandContext, args));
|
|
694
|
+
if (args.mode === 'keybindings') return output(listHarnessKeybindings(deps.commandContext, args));
|
|
695
|
+
if (args.mode === 'keybinding') {
|
|
696
|
+
const binding = describeHarnessKeybinding(deps.commandContext, args);
|
|
697
|
+
return binding ? output(binding) : error(`Unknown keybinding action ${readString(args.actionId || args.key || args.query) || '<missing>'}.`);
|
|
698
|
+
}
|
|
699
|
+
if (args.mode === 'set_keybinding') {
|
|
700
|
+
const confirmationError = requireConfirmedAction(args, 'Keybinding mutation');
|
|
701
|
+
if (confirmationError) return error(confirmationError);
|
|
702
|
+
return output(setHarnessKeybinding(deps.commandContext, args));
|
|
703
|
+
}
|
|
704
|
+
if (args.mode === 'reset_keybinding') {
|
|
705
|
+
const confirmationError = requireConfirmedAction(args, 'Keybinding reset');
|
|
706
|
+
if (confirmationError) return error(confirmationError);
|
|
707
|
+
return output(resetHarnessKeybinding(deps.commandContext, args));
|
|
708
|
+
}
|
|
684
709
|
if (args.mode === 'commands') {
|
|
685
710
|
const commands = listCommands(deps.commandRegistry, args);
|
|
686
711
|
return output({ commands, returned: commands.length, total: deps.commandRegistry.list().length });
|
|
@@ -749,7 +774,7 @@ export function createAgentHarnessTool(deps: AgentHarnessToolDeps): Tool {
|
|
|
749
774
|
}
|
|
750
775
|
if (args.mode === 'run_workspace_action') return runWorkspaceAction(deps, args);
|
|
751
776
|
if (args.mode === 'tools') {
|
|
752
|
-
const tools =
|
|
777
|
+
const tools = listHarnessModelTools(deps.toolRegistry, args);
|
|
753
778
|
return output({ tools, returned: tools.length, total: deps.toolRegistry.getToolDefinitions().length });
|
|
754
779
|
}
|
|
755
780
|
if (args.mode === 'connected_host') return output(connectedHostSummary(deps.commandContext, deps.toolRegistry));
|
package/src/version.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { join } from 'node:path';
|
|
|
6
6
|
// The prebuild script updates the fallback value before compilation.
|
|
7
7
|
// Uses import.meta.dir (Bun) to locate package.json relative to this file,
|
|
8
8
|
// which is correct regardless of the process working directory.
|
|
9
|
-
let _version = '1.0.
|
|
9
|
+
let _version = '1.0.4';
|
|
10
10
|
let _sdkVersion = '0.33.35';
|
|
11
11
|
try {
|
|
12
12
|
const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', 'package.json'), 'utf-8')) as {
|