@pellux/goodvibes-agent 1.0.4 → 1.0.5
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 +6 -0
- package/README.md +2 -2
- package/dist/package/main.js +498 -152
- package/docs/README.md +1 -1
- package/docs/getting-started.md +2 -2
- package/docs/tools-and-commands.md +5 -3
- package/package.json +1 -1
- package/src/tools/agent-harness-tool-schema.ts +127 -0
- package/src/tools/agent-harness-tool.ts +24 -122
- package/src/tools/agent-harness-ui-surface-metadata.ts +343 -0
- package/src/version.ts +1 -1
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
import type { CommandContext } from '../input/command-registry.ts';
|
|
2
|
+
|
|
3
|
+
type UiSurfaceKind = 'overlay' | 'modal' | 'workspace' | 'picker';
|
|
4
|
+
|
|
5
|
+
export interface AgentHarnessUiSurfaceArgs {
|
|
6
|
+
readonly query?: unknown;
|
|
7
|
+
readonly surfaceId?: unknown;
|
|
8
|
+
readonly categoryId?: unknown;
|
|
9
|
+
readonly category?: unknown;
|
|
10
|
+
readonly target?: unknown;
|
|
11
|
+
readonly key?: unknown;
|
|
12
|
+
readonly prefix?: unknown;
|
|
13
|
+
readonly limit?: unknown;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface UiSurfaceDefinition {
|
|
17
|
+
readonly id: string;
|
|
18
|
+
readonly label: string;
|
|
19
|
+
readonly kind: UiSurfaceKind;
|
|
20
|
+
readonly summary: string;
|
|
21
|
+
readonly command: string;
|
|
22
|
+
readonly preferredModelRoute: string;
|
|
23
|
+
readonly parameters?: readonly string[];
|
|
24
|
+
readonly available: (context: CommandContext) => boolean;
|
|
25
|
+
readonly open: (context: CommandContext, args: AgentHarnessUiSurfaceArgs) => Record<string, unknown>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function readString(value: unknown): string {
|
|
29
|
+
return typeof value === 'string' ? value.trim() : '';
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function readLimit(value: unknown, fallback: number): number {
|
|
33
|
+
const parsed = typeof value === 'string' && value.trim() ? Number(value) : value;
|
|
34
|
+
if (typeof parsed !== 'number' || !Number.isFinite(parsed)) return fallback;
|
|
35
|
+
return Math.max(1, Math.min(500, Math.trunc(parsed)));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function routeUnavailable(surface: UiSurfaceDefinition): Record<string, unknown> {
|
|
39
|
+
return {
|
|
40
|
+
status: 'route_unavailable',
|
|
41
|
+
surface: surface.id,
|
|
42
|
+
note: 'The current runtime did not provide the shell opener for this UI surface.',
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function opened(surface: UiSurfaceDefinition, extra: Record<string, unknown> = {}): Record<string, unknown> {
|
|
47
|
+
return {
|
|
48
|
+
status: 'opened',
|
|
49
|
+
surface: surface.id,
|
|
50
|
+
kind: surface.kind,
|
|
51
|
+
...extra,
|
|
52
|
+
note: 'UI routing was handed to the current Agent shell bridge.',
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function optionalModelTarget(args: AgentHarnessUiSurfaceArgs): 'main' | 'helper' | 'tool' | 'tts' | undefined {
|
|
57
|
+
const target = readString(args.target);
|
|
58
|
+
return target === 'main' || target === 'helper' || target === 'tool' || target === 'tts' ? target : undefined;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function optionalOnboardingMode(args: AgentHarnessUiSurfaceArgs): 'new' | 'edit' | 'reopen' | undefined {
|
|
62
|
+
const target = readString(args.target);
|
|
63
|
+
return target === 'new' || target === 'edit' || target === 'reopen' ? target : undefined;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function workspaceCategory(args: AgentHarnessUiSurfaceArgs): string | undefined {
|
|
67
|
+
return readString(args.categoryId || args.category || args.target) || undefined;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function settingsTarget(args: AgentHarnessUiSurfaceArgs): string | undefined {
|
|
71
|
+
return readString(args.target || args.key || args.prefix) || undefined;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const UI_SURFACES: readonly UiSurfaceDefinition[] = [
|
|
75
|
+
{
|
|
76
|
+
id: 'agent-workspace',
|
|
77
|
+
label: 'Agent Workspace',
|
|
78
|
+
kind: 'workspace',
|
|
79
|
+
summary: 'Fullscreen operator workspace with setup, knowledge, local state, channels, automation, and delegation routes.',
|
|
80
|
+
command: '/agent',
|
|
81
|
+
preferredModelRoute: 'Use workspace_actions/workspace_action/run_workspace_action for model operation; use open_ui_surface only to visibly navigate.',
|
|
82
|
+
parameters: ['categoryId'],
|
|
83
|
+
available: (context) => typeof context.openAgentWorkspace === 'function',
|
|
84
|
+
open: (context, args) => {
|
|
85
|
+
const surface = findSurfaceById('agent-workspace')!;
|
|
86
|
+
if (!context.openAgentWorkspace) return routeUnavailable(surface);
|
|
87
|
+
const categoryId = workspaceCategory(args);
|
|
88
|
+
context.openAgentWorkspace(categoryId);
|
|
89
|
+
return opened(surface, { categoryId: categoryId ?? 'default' });
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
id: 'settings',
|
|
94
|
+
label: 'Settings',
|
|
95
|
+
kind: 'modal',
|
|
96
|
+
summary: 'Fullscreen settings workspace for Agent-owned configuration, subscriptions, secrets, MCP, tools, and surface settings.',
|
|
97
|
+
command: '/settings',
|
|
98
|
+
preferredModelRoute: 'Use settings/get_setting/set_setting/reset_setting for model operation; use open_ui_surface only to visibly navigate.',
|
|
99
|
+
parameters: ['target', 'key', 'prefix'],
|
|
100
|
+
available: (context) => typeof context.openSettingsModal === 'function',
|
|
101
|
+
open: (context, args) => {
|
|
102
|
+
const surface = findSurfaceById('settings')!;
|
|
103
|
+
if (!context.openSettingsModal) return routeUnavailable(surface);
|
|
104
|
+
const target = settingsTarget(args);
|
|
105
|
+
context.openSettingsModal(target);
|
|
106
|
+
return opened(surface, { target: target ?? 'default' });
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
id: 'mcp-workspace',
|
|
111
|
+
label: 'MCP Workspace',
|
|
112
|
+
kind: 'workspace',
|
|
113
|
+
summary: 'MCP server setup, trust posture, and tool inventory workspace.',
|
|
114
|
+
command: '/mcp',
|
|
115
|
+
preferredModelRoute: 'Use workspace_actions, tools, and settings modes for model operation.',
|
|
116
|
+
available: (context) => typeof context.openMcpWorkspace === 'function',
|
|
117
|
+
open: (context) => {
|
|
118
|
+
const surface = findSurfaceById('mcp-workspace')!;
|
|
119
|
+
if (!context.openMcpWorkspace) return routeUnavailable(surface);
|
|
120
|
+
context.openMcpWorkspace();
|
|
121
|
+
return opened(surface);
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
id: 'model-picker',
|
|
126
|
+
label: 'Model Picker',
|
|
127
|
+
kind: 'picker',
|
|
128
|
+
summary: 'Interactive model picker for main, helper, tool, and TTS model routes.',
|
|
129
|
+
command: '/model',
|
|
130
|
+
preferredModelRoute: 'Use settings mode for direct provider.model changes, or run_command /model with confirmation when a concrete model id is known.',
|
|
131
|
+
parameters: ['target'],
|
|
132
|
+
available: (context) => typeof context.openModelPicker === 'function' || typeof context.openModelPickerWithTarget === 'function',
|
|
133
|
+
open: (context, args) => {
|
|
134
|
+
const surface = findSurfaceById('model-picker')!;
|
|
135
|
+
const target = optionalModelTarget(args);
|
|
136
|
+
if (target && context.openModelPickerWithTarget) {
|
|
137
|
+
const openedForTarget = context.openModelPickerWithTarget(target);
|
|
138
|
+
return opened(surface, { target, openedForTarget });
|
|
139
|
+
}
|
|
140
|
+
if (!context.openModelPicker) return routeUnavailable(surface);
|
|
141
|
+
context.openModelPicker();
|
|
142
|
+
return opened(surface, { target: 'main' });
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
id: 'provider-picker',
|
|
147
|
+
label: 'Provider Picker',
|
|
148
|
+
kind: 'picker',
|
|
149
|
+
summary: 'Interactive provider picker for model route setup.',
|
|
150
|
+
command: '/provider',
|
|
151
|
+
preferredModelRoute: 'Use settings mode for direct provider routing changes, or run confirmed slash-command mirrors for concrete provider changes.',
|
|
152
|
+
parameters: ['target'],
|
|
153
|
+
available: (context) => typeof context.openProviderPicker === 'function' || typeof context.openProviderModelPickerWithTarget === 'function',
|
|
154
|
+
open: (context, args) => {
|
|
155
|
+
const surface = findSurfaceById('provider-picker')!;
|
|
156
|
+
const target = optionalModelTarget(args);
|
|
157
|
+
if (target && context.openProviderModelPickerWithTarget) {
|
|
158
|
+
context.openProviderModelPickerWithTarget(target);
|
|
159
|
+
return opened(surface, { target });
|
|
160
|
+
}
|
|
161
|
+
if (!context.openProviderPicker) return routeUnavailable(surface);
|
|
162
|
+
context.openProviderPicker();
|
|
163
|
+
return opened(surface, { target: 'main' });
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
id: 'session-picker',
|
|
168
|
+
label: 'Session Picker',
|
|
169
|
+
kind: 'picker',
|
|
170
|
+
summary: 'Saved session browser and loader.',
|
|
171
|
+
command: '/sessions',
|
|
172
|
+
preferredModelRoute: 'Use session slash-command mirrors with confirmation for concrete save/load/export actions.',
|
|
173
|
+
available: (context) => typeof context.openSessionPicker === 'function',
|
|
174
|
+
open: (context) => {
|
|
175
|
+
const surface = findSurfaceById('session-picker')!;
|
|
176
|
+
if (!context.openSessionPicker) return routeUnavailable(surface);
|
|
177
|
+
context.openSessionPicker();
|
|
178
|
+
return opened(surface);
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
id: 'profile-picker',
|
|
183
|
+
label: 'Profile Picker',
|
|
184
|
+
kind: 'picker',
|
|
185
|
+
summary: 'Agent profile picker for local isolated profile selection.',
|
|
186
|
+
command: '/agent-profile',
|
|
187
|
+
preferredModelRoute: 'Use workspace profile actions or profile slash-command mirrors for concrete model operation.',
|
|
188
|
+
available: (context) => typeof context.openProfilePicker === 'function',
|
|
189
|
+
open: (context) => {
|
|
190
|
+
const surface = findSurfaceById('profile-picker')!;
|
|
191
|
+
if (!context.openProfilePicker) return routeUnavailable(surface);
|
|
192
|
+
context.openProfilePicker();
|
|
193
|
+
return opened(surface);
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
id: 'bookmark-modal',
|
|
198
|
+
label: 'Bookmarks',
|
|
199
|
+
kind: 'modal',
|
|
200
|
+
summary: 'Transcript bookmark browser.',
|
|
201
|
+
command: '/bookmarks',
|
|
202
|
+
preferredModelRoute: 'Use slash-command mirrors for concrete bookmark inspection; opening is visible navigation only.',
|
|
203
|
+
available: (context) => typeof context.openBookmarkModal === 'function',
|
|
204
|
+
open: (context) => {
|
|
205
|
+
const surface = findSurfaceById('bookmark-modal')!;
|
|
206
|
+
if (!context.openBookmarkModal) return routeUnavailable(surface);
|
|
207
|
+
context.openBookmarkModal();
|
|
208
|
+
return opened(surface);
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
id: 'context-inspector',
|
|
213
|
+
label: 'Context Inspector',
|
|
214
|
+
kind: 'modal',
|
|
215
|
+
summary: 'Context-window usage and token breakdown inspector.',
|
|
216
|
+
command: '/context',
|
|
217
|
+
preferredModelRoute: 'Use slash-command mirrors for text output; opening is visible navigation only.',
|
|
218
|
+
available: (context) => typeof context.openContextInspector === 'function',
|
|
219
|
+
open: (context) => {
|
|
220
|
+
const surface = findSurfaceById('context-inspector')!;
|
|
221
|
+
if (!context.openContextInspector) return routeUnavailable(surface);
|
|
222
|
+
context.openContextInspector();
|
|
223
|
+
return opened(surface);
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
{
|
|
227
|
+
id: 'help-overlay',
|
|
228
|
+
label: 'Help Overlay',
|
|
229
|
+
kind: 'overlay',
|
|
230
|
+
summary: 'Registry-driven command and shortcut help overlay.',
|
|
231
|
+
command: '/help',
|
|
232
|
+
preferredModelRoute: 'Use commands/command and shortcuts modes for model-readable discovery.',
|
|
233
|
+
available: (context) => typeof context.openHelpOverlay === 'function',
|
|
234
|
+
open: (context) => {
|
|
235
|
+
const surface = findSurfaceById('help-overlay')!;
|
|
236
|
+
if (!context.openHelpOverlay) return routeUnavailable(surface);
|
|
237
|
+
context.openHelpOverlay();
|
|
238
|
+
return opened(surface);
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
id: 'shortcuts-overlay',
|
|
243
|
+
label: 'Shortcuts Overlay',
|
|
244
|
+
kind: 'overlay',
|
|
245
|
+
summary: 'Keyboard shortcut reference overlay.',
|
|
246
|
+
command: '/shortcuts',
|
|
247
|
+
preferredModelRoute: 'Use shortcuts/keybindings modes for model-readable discovery and confirmed keybinding edits.',
|
|
248
|
+
available: (context) => typeof context.openShortcutsOverlay === 'function',
|
|
249
|
+
open: (context) => {
|
|
250
|
+
const surface = findSurfaceById('shortcuts-overlay')!;
|
|
251
|
+
if (!context.openShortcutsOverlay) return routeUnavailable(surface);
|
|
252
|
+
context.openShortcutsOverlay();
|
|
253
|
+
return opened(surface);
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
id: 'onboarding',
|
|
258
|
+
label: 'Onboarding Wizard',
|
|
259
|
+
kind: 'modal',
|
|
260
|
+
summary: 'First-run and setup review wizard for Agent readiness.',
|
|
261
|
+
command: '/setup',
|
|
262
|
+
preferredModelRoute: 'Use workspace setup actions and settings modes for concrete model operation.',
|
|
263
|
+
parameters: ['target=new|edit|reopen'],
|
|
264
|
+
available: (context) => typeof context.openOnboardingWizard === 'function',
|
|
265
|
+
open: (context, args) => {
|
|
266
|
+
const surface = findSurfaceById('onboarding')!;
|
|
267
|
+
if (!context.openOnboardingWizard) return routeUnavailable(surface);
|
|
268
|
+
const mode = optionalOnboardingMode(args);
|
|
269
|
+
context.openOnboardingWizard(mode);
|
|
270
|
+
return opened(surface, { mode: mode ?? 'default' });
|
|
271
|
+
},
|
|
272
|
+
},
|
|
273
|
+
];
|
|
274
|
+
|
|
275
|
+
function findSurfaceById(surfaceId: string): UiSurfaceDefinition | undefined {
|
|
276
|
+
return UI_SURFACES.find((surface) => surface.id === surfaceId);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function surfaceMatches(surface: Record<string, unknown>, query: string): boolean {
|
|
280
|
+
if (!query) return true;
|
|
281
|
+
return [
|
|
282
|
+
surface.id,
|
|
283
|
+
surface.label,
|
|
284
|
+
surface.kind,
|
|
285
|
+
surface.summary,
|
|
286
|
+
surface.command,
|
|
287
|
+
surface.preferredModelRoute,
|
|
288
|
+
].map((value) => String(value ?? '')).join('\n').toLowerCase().includes(query.toLowerCase());
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function describeSurface(context: CommandContext, surface: UiSurfaceDefinition): Record<string, unknown> {
|
|
292
|
+
return {
|
|
293
|
+
id: surface.id,
|
|
294
|
+
label: surface.label,
|
|
295
|
+
kind: surface.kind,
|
|
296
|
+
summary: surface.summary,
|
|
297
|
+
command: surface.command,
|
|
298
|
+
preferredModelRoute: surface.preferredModelRoute,
|
|
299
|
+
parameters: surface.parameters ?? [],
|
|
300
|
+
available: surface.available(context),
|
|
301
|
+
policy: {
|
|
302
|
+
effect: 'visible-ui-navigation',
|
|
303
|
+
confirmation: 'agent_harness mode:"open_ui_surface" requires confirm:true and explicitUserRequest.',
|
|
304
|
+
boundary: 'UI surface routing opens the same visible Agent shell surface the user can open. Use first-class model tools, settings modes, workspace actions, or confirmed slash-command mirrors for actual operations.',
|
|
305
|
+
},
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
export function totalHarnessUiSurfaces(): number {
|
|
310
|
+
return UI_SURFACES.length;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export function listHarnessUiSurfaces(context: CommandContext, args: AgentHarnessUiSurfaceArgs): readonly Record<string, unknown>[] {
|
|
314
|
+
const query = readString(args.query);
|
|
315
|
+
const limit = readLimit(args.limit, 200);
|
|
316
|
+
return UI_SURFACES
|
|
317
|
+
.map((surface) => describeSurface(context, surface))
|
|
318
|
+
.filter((surface) => surfaceMatches(surface, query))
|
|
319
|
+
.slice(0, limit);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
export function describeHarnessUiSurface(context: CommandContext, args: AgentHarnessUiSurfaceArgs): Record<string, unknown> | null {
|
|
323
|
+
const surfaceId = readString(args.surfaceId || args.query);
|
|
324
|
+
if (!surfaceId) return null;
|
|
325
|
+
const surface = UI_SURFACES.find((entry) => entry.id === surfaceId || entry.label.toLowerCase() === surfaceId.toLowerCase());
|
|
326
|
+
return surface ? describeSurface(context, surface) : null;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
export function openHarnessUiSurface(context: CommandContext, args: AgentHarnessUiSurfaceArgs): Record<string, unknown> {
|
|
330
|
+
const surfaceId = readString(args.surfaceId || args.query);
|
|
331
|
+
const surface = UI_SURFACES.find((entry) => entry.id === surfaceId || entry.label.toLowerCase() === surfaceId.toLowerCase());
|
|
332
|
+
if (!surface) {
|
|
333
|
+
return {
|
|
334
|
+
status: 'unknown_ui_surface',
|
|
335
|
+
surfaceId: surfaceId || '<missing>',
|
|
336
|
+
availableSurfaces: UI_SURFACES.map((entry) => entry.id),
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
return {
|
|
340
|
+
...surface.open(context, args),
|
|
341
|
+
descriptor: describeSurface(context, surface),
|
|
342
|
+
};
|
|
343
|
+
}
|
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.5';
|
|
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 {
|