@pellux/goodvibes-agent 1.0.30 → 1.0.33

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 (63) hide show
  1. package/CHANGELOG.md +42 -1
  2. package/README.md +7 -5
  3. package/dist/package/main.js +7323 -2268
  4. package/docs/README.md +2 -2
  5. package/docs/channels-remote-and-api.md +6 -2
  6. package/docs/connected-host.md +26 -5
  7. package/docs/getting-started.md +30 -10
  8. package/docs/knowledge-artifacts-and-multimodal.md +16 -4
  9. package/docs/project-planning.md +2 -2
  10. package/docs/providers-and-routing.md +3 -2
  11. package/docs/release-and-publishing.md +15 -11
  12. package/docs/tools-and-commands.md +20 -8
  13. package/package.json +8 -3
  14. package/release/live-verification/live-verification.json +148 -0
  15. package/release/live-verification/live-verification.md +187 -0
  16. package/release/performance-snapshot.json +57 -0
  17. package/release/release-notes.md +28 -0
  18. package/release/release-readiness.json +581 -0
  19. package/src/cli/agent-knowledge-command.ts +5 -5
  20. package/src/cli/agent-knowledge-format.ts +11 -0
  21. package/src/cli/agent-knowledge-runtime.ts +92 -13
  22. package/src/cli/bundle-command.ts +5 -4
  23. package/src/cli/entrypoint.ts +5 -2
  24. package/src/cli/external-runtime.ts +2 -15
  25. package/src/cli/management.ts +4 -3
  26. package/src/input/commands/guidance-runtime.ts +1 -1
  27. package/src/input/commands/knowledge.ts +2 -2
  28. package/src/runtime/bootstrap.ts +2 -2
  29. package/src/runtime/connected-host-auth.ts +16 -0
  30. package/src/tools/agent-channel-send-tool.ts +5 -7
  31. package/src/tools/agent-harness-channel-metadata.ts +177 -0
  32. package/src/tools/agent-harness-connected-host-status.ts +1 -1
  33. package/src/tools/agent-harness-delegation-posture.ts +216 -0
  34. package/src/tools/agent-harness-keybinding-metadata.ts +57 -22
  35. package/src/tools/agent-harness-mcp-metadata.ts +246 -0
  36. package/src/tools/agent-harness-media-posture.ts +282 -0
  37. package/src/tools/agent-harness-metadata.ts +21 -4
  38. package/src/tools/agent-harness-model-routing.ts +501 -0
  39. package/src/tools/agent-harness-notification-metadata.ts +217 -0
  40. package/src/tools/agent-harness-operator-methods.ts +285 -0
  41. package/src/tools/agent-harness-pairing-posture.ts +265 -0
  42. package/src/tools/agent-harness-provider-account-metadata.ts +203 -0
  43. package/src/tools/agent-harness-release-evidence.ts +364 -0
  44. package/src/tools/agent-harness-release-readiness.ts +298 -0
  45. package/src/tools/agent-harness-security-posture.ts +646 -0
  46. package/src/tools/agent-harness-service-posture.ts +201 -0
  47. package/src/tools/agent-harness-session-metadata.ts +282 -0
  48. package/src/tools/agent-harness-setup-posture.ts +295 -0
  49. package/src/tools/agent-harness-tool-schema.ts +103 -27
  50. package/src/tools/agent-harness-tool.ts +209 -236
  51. package/src/tools/agent-harness-ui-surface-metadata.ts +1 -1
  52. package/src/tools/agent-harness-workspace-actions.ts +232 -0
  53. package/src/tools/agent-knowledge-ingest-tool.ts +6 -8
  54. package/src/tools/agent-knowledge-tool.ts +122 -23
  55. package/src/tools/agent-local-registry-tool.ts +4 -5
  56. package/src/tools/agent-media-generate-tool.ts +4 -6
  57. package/src/tools/agent-notify-tool.ts +5 -6
  58. package/src/tools/agent-operator-action-tool.ts +6 -8
  59. package/src/tools/agent-operator-briefing-tool.ts +3 -4
  60. package/src/tools/agent-reminder-schedule-tool.ts +6 -7
  61. package/src/tools/agent-tool-policy-guard.ts +8 -17
  62. package/src/tools/agent-work-plan-tool.ts +3 -4
  63. package/src/version.ts +2 -2
@@ -0,0 +1,282 @@
1
+ import { buildAgentWorkspaceVoiceMediaReadiness } from '../input/agent-workspace-voice-media.ts';
2
+ import type { AgentWorkspaceVoiceMediaProviderStatus } from '../input/agent-workspace-voice-media.ts';
3
+ import type { CommandContext } from '../input/command-registry.ts';
4
+
5
+ export interface AgentHarnessMediaArgs {
6
+ readonly mediaProviderId?: unknown;
7
+ readonly target?: unknown;
8
+ readonly query?: unknown;
9
+ readonly includeParameters?: unknown;
10
+ readonly limit?: unknown;
11
+ }
12
+
13
+ type MediaProviderResolution =
14
+ | { readonly status: 'found'; readonly provider: Record<string, unknown> }
15
+ | { readonly status: 'ambiguous'; readonly input: string; readonly candidates: readonly Record<string, unknown>[] }
16
+ | { readonly status: 'missing_lookup'; readonly usage: string };
17
+
18
+ interface RuntimeProviderStatus {
19
+ readonly id: string;
20
+ readonly state: string;
21
+ readonly configured: boolean;
22
+ readonly detail?: string;
23
+ }
24
+
25
+ function readString(value: unknown): string {
26
+ return typeof value === 'string' ? value.trim() : '';
27
+ }
28
+
29
+ function readLimit(value: unknown, fallback: number): number {
30
+ const parsed = typeof value === 'string' && value.trim() ? Number(value) : value;
31
+ if (typeof parsed !== 'number' || !Number.isFinite(parsed)) return fallback;
32
+ return Math.max(1, Math.min(500, Math.trunc(parsed)));
33
+ }
34
+
35
+ function readConfigBoolean(context: CommandContext, key: string, fallback: boolean): boolean {
36
+ try {
37
+ const value = (context.platform.configManager as { get(settingKey: string): unknown }).get(key);
38
+ if (typeof value === 'boolean') return value;
39
+ if (typeof value === 'string') {
40
+ const normalized = value.trim().toLowerCase();
41
+ if (normalized === 'true') return true;
42
+ if (normalized === 'false') return false;
43
+ }
44
+ return fallback;
45
+ } catch {
46
+ return fallback;
47
+ }
48
+ }
49
+
50
+ function readConfigString(context: CommandContext, key: string): string {
51
+ try {
52
+ const value = (context.platform.configManager as { get(settingKey: string): unknown }).get(key);
53
+ return typeof value === 'string' ? value.trim() : '';
54
+ } catch {
55
+ return '';
56
+ }
57
+ }
58
+
59
+ function providerSearchText(provider: AgentWorkspaceVoiceMediaProviderStatus, runtimeStatus?: RuntimeProviderStatus): string {
60
+ return [
61
+ provider.id,
62
+ provider.label,
63
+ provider.domain,
64
+ provider.setupState,
65
+ provider.nextStep,
66
+ ...provider.features,
67
+ ...provider.secretKeyOptions,
68
+ ...(runtimeStatus ? [runtimeStatus.state, runtimeStatus.configured ? 'configured' : 'unconfigured', runtimeStatus.detail ?? ''] : []),
69
+ ].join('\n').toLowerCase();
70
+ }
71
+
72
+ function describeProviderCandidate(provider: AgentWorkspaceVoiceMediaProviderStatus): Record<string, unknown> {
73
+ return {
74
+ mediaProviderId: `${provider.domain}:${provider.id}`,
75
+ id: provider.id,
76
+ domain: provider.domain,
77
+ label: provider.label,
78
+ setupState: provider.setupState,
79
+ selected: provider.selected,
80
+ };
81
+ }
82
+
83
+ function statusMap(statuses: readonly RuntimeProviderStatus[]): ReadonlyMap<string, RuntimeProviderStatus> {
84
+ return new Map(statuses.map((status) => [status.id, status]));
85
+ }
86
+
87
+ function describeProvider(
88
+ provider: AgentWorkspaceVoiceMediaProviderStatus,
89
+ runtimeStatus: RuntimeProviderStatus | undefined,
90
+ options: {
91
+ readonly includeParameters?: boolean;
92
+ readonly lookup?: Record<string, unknown>;
93
+ } = {},
94
+ ): Record<string, unknown> {
95
+ return {
96
+ mediaProviderId: `${provider.domain}:${provider.id}`,
97
+ id: provider.id,
98
+ label: provider.label,
99
+ domain: provider.domain,
100
+ features: provider.features,
101
+ setupState: provider.setupState,
102
+ selected: provider.selected,
103
+ configuredSecretKeyNames: provider.configuredSecretKeys,
104
+ missingSecretKeyNames: provider.missingSecretKeyOptions,
105
+ nextStep: provider.nextStep,
106
+ ...(runtimeStatus ? {
107
+ runtimeStatus: {
108
+ state: runtimeStatus.state,
109
+ configured: runtimeStatus.configured,
110
+ ...(runtimeStatus.detail ? { detail: runtimeStatus.detail } : {}),
111
+ },
112
+ } : {}),
113
+ ...(options.lookup ? { lookup: options.lookup } : {}),
114
+ ...(options.includeParameters ? {
115
+ modelRoutes: {
116
+ inspectPosture: 'agent_harness mode:"media_posture"',
117
+ inspectProvider: 'agent_harness mode:"media_provider"',
118
+ generateMedia: 'agent_media_generate with confirm:true and explicitUserRequest',
119
+ ttsSettings: 'agent_harness settings/get_setting/set_setting for tts.provider, tts.voice, tts.llmProvider, and tts.llmModel',
120
+ },
121
+ } : {}),
122
+ policy: {
123
+ effect: 'read-only',
124
+ values: 'Provider posture returns capability, setup, selected, health, and safe environment key names only; secret values and media payloads are never returned.',
125
+ mutation: 'Media generation, voice enable/disable, TTS setting changes, and bundle export stay explicit confirmation-gated tool, setting, workspace, or slash-command flows.',
126
+ },
127
+ };
128
+ }
129
+
130
+ async function readRuntimeStatuses(context: CommandContext): Promise<{
131
+ readonly voice: readonly RuntimeProviderStatus[];
132
+ readonly media: readonly RuntimeProviderStatus[];
133
+ }> {
134
+ const voice = await (async () => {
135
+ try {
136
+ return (await context.platform.voiceProviderRegistry?.status() ?? []).map((status) => ({
137
+ id: status.id,
138
+ state: status.state,
139
+ configured: status.configured,
140
+ ...(status.detail ? { detail: status.detail } : {}),
141
+ }));
142
+ } catch {
143
+ return [];
144
+ }
145
+ })();
146
+ const media = await (async () => {
147
+ try {
148
+ return (await context.platform.mediaProviderRegistry?.status() ?? []).map((status) => ({
149
+ id: status.id,
150
+ state: status.state,
151
+ configured: status.configured,
152
+ ...(status.detail ? { detail: status.detail } : {}),
153
+ }));
154
+ } catch {
155
+ return [];
156
+ }
157
+ })();
158
+ return { voice, media };
159
+ }
160
+
161
+ function buildReadiness(context: CommandContext) {
162
+ return buildAgentWorkspaceVoiceMediaReadiness({
163
+ context,
164
+ voiceProviders: context.platform.voiceProviderRegistry?.list() ?? [],
165
+ mediaProviders: context.platform.mediaProviderRegistry?.list() ?? [],
166
+ });
167
+ }
168
+
169
+ export function mediaPostureCatalogStatus(context: CommandContext): Record<string, unknown> {
170
+ const readiness = buildReadiness(context);
171
+ return {
172
+ modes: ['media_posture', 'media_provider'],
173
+ voiceProviders: readiness.voiceProviders.length,
174
+ mediaProviders: readiness.mediaProviders.length,
175
+ readyVoiceProviders: readiness.readyVoiceProviderCount,
176
+ readyMediaProviders: readiness.readyMediaProviderCount,
177
+ readOnly: true,
178
+ };
179
+ }
180
+
181
+ export async function mediaPostureSummary(context: CommandContext, args: AgentHarnessMediaArgs): Promise<Record<string, unknown>> {
182
+ const readiness = buildReadiness(context);
183
+ const runtimeStatuses = await readRuntimeStatuses(context);
184
+ const voiceStatuses = statusMap(runtimeStatuses.voice);
185
+ const mediaStatuses = statusMap(runtimeStatuses.media);
186
+ const providers = [
187
+ ...readiness.voiceProviders.map((provider) => ({ provider, runtimeStatus: voiceStatuses.get(provider.id) })),
188
+ ...readiness.mediaProviders.map((provider) => ({ provider, runtimeStatus: mediaStatuses.get(provider.id) })),
189
+ ];
190
+ const query = readString(args.query).toLowerCase();
191
+ const filtered = providers
192
+ .filter(({ provider, runtimeStatus }) => !query || providerSearchText(provider, runtimeStatus).includes(query))
193
+ .slice(0, readLimit(args.limit, 100));
194
+ return {
195
+ status: 'available',
196
+ summary: {
197
+ voiceProviders: readiness.voiceProviders.length,
198
+ mediaProviders: readiness.mediaProviders.length,
199
+ readyVoiceProviders: readiness.readyVoiceProviderCount,
200
+ readyMediaProviders: readiness.readyMediaProviderCount,
201
+ selectedTtsProviderStatus: readiness.selectedTtsProviderStatus,
202
+ selectedTtsProviderLabel: readiness.selectedTtsProviderLabel,
203
+ ttsVoiceConfigured: readiness.ttsVoiceConfigured,
204
+ ttsResponseRouteConfigured: readiness.ttsResponseRouteConfigured,
205
+ voiceSurfaceEnabled: readConfigBoolean(context, 'ui.voiceEnabled', false),
206
+ browserToolState: readiness.browserToolState,
207
+ artifactStoreAvailable: Boolean(context.platform.artifactStore),
208
+ ttsProviderSetting: readConfigString(context, 'tts.provider') || null,
209
+ ttsVoiceSettingConfigured: readConfigString(context, 'tts.voice').length > 0,
210
+ nextSteps: readiness.nextSteps,
211
+ },
212
+ providers: filtered.map(({ provider, runtimeStatus }) => describeProvider(provider, runtimeStatus, {
213
+ includeParameters: args.includeParameters === true,
214
+ })),
215
+ returned: filtered.length,
216
+ total: providers.length,
217
+ policy: 'Read-only voice/media posture. Media generation, voice enable/disable, TTS setting changes, and bundle export stay confirmation-gated through first-class tools, settings modes, workspace actions, or slash-command mirrors.',
218
+ modelAccess: {
219
+ mediaGenerateTool: 'agent_media_generate',
220
+ providerCatalogMode: 'media_posture',
221
+ singleProviderMode: 'media_provider',
222
+ ttsProviderPicker: 'open_ui_surface surfaceId:"tts-provider-picker"',
223
+ ttsVoicePicker: 'open_ui_surface surfaceId:"tts-voice-picker"',
224
+ commands: ['/media providers', '/voice review', '/tts <prompt>', '/image <path>'],
225
+ },
226
+ };
227
+ }
228
+
229
+ export async function describeHarnessMediaProvider(context: CommandContext, args: AgentHarnessMediaArgs): Promise<MediaProviderResolution> {
230
+ const mediaProviderId = readString(args.mediaProviderId);
231
+ const target = readString(args.target);
232
+ const query = readString(args.query);
233
+ const input = mediaProviderId || target || query;
234
+ if (!input) {
235
+ return {
236
+ status: 'missing_lookup',
237
+ usage: 'media_provider requires mediaProviderId, target, or query. Use mode:"media_posture" to inspect provider ids.',
238
+ };
239
+ }
240
+ const readiness = buildReadiness(context);
241
+ const runtimeStatuses = await readRuntimeStatuses(context);
242
+ const voiceStatuses = statusMap(runtimeStatuses.voice);
243
+ const mediaStatuses = statusMap(runtimeStatuses.media);
244
+ const providers = [
245
+ ...readiness.voiceProviders.map((provider) => ({ provider, runtimeStatus: voiceStatuses.get(provider.id) })),
246
+ ...readiness.mediaProviders.map((provider) => ({ provider, runtimeStatus: mediaStatuses.get(provider.id) })),
247
+ ];
248
+ const normalized = input.toLowerCase();
249
+ const exact = providers.find(({ provider }) => `${provider.domain}:${provider.id}` === input || provider.id === input);
250
+ if (exact) {
251
+ return {
252
+ status: 'found',
253
+ provider: describeProvider(exact.provider, exact.runtimeStatus, { includeParameters: true, lookup: { input, source: mediaProviderId ? 'mediaProviderId' : target ? 'target' : 'query', resolvedBy: 'id' } }),
254
+ };
255
+ }
256
+ const insensitive = providers.find(({ provider }) => `${provider.domain}:${provider.id}`.toLowerCase() === normalized || provider.id.toLowerCase() === normalized);
257
+ if (insensitive) {
258
+ return {
259
+ status: 'found',
260
+ provider: describeProvider(insensitive.provider, insensitive.runtimeStatus, { includeParameters: true, lookup: { input, source: mediaProviderId ? 'mediaProviderId' : target ? 'target' : 'query', resolvedBy: 'case-insensitive-id' } }),
261
+ };
262
+ }
263
+ const searched = providers.filter(({ provider, runtimeStatus }) => providerSearchText(provider, runtimeStatus).includes(normalized));
264
+ if (searched.length === 1) {
265
+ const found = searched[0]!;
266
+ return {
267
+ status: 'found',
268
+ provider: describeProvider(found.provider, found.runtimeStatus, { includeParameters: true, lookup: { input, source: mediaProviderId ? 'mediaProviderId' : target ? 'target' : 'query', resolvedBy: 'search' } }),
269
+ };
270
+ }
271
+ if (searched.length > 1) {
272
+ return {
273
+ status: 'ambiguous',
274
+ input,
275
+ candidates: searched.slice(0, 8).map(({ provider }) => describeProviderCandidate(provider)),
276
+ };
277
+ }
278
+ return {
279
+ status: 'missing_lookup',
280
+ usage: `Unknown media provider ${input}. Use mode:"media_posture" to inspect provider ids.`,
281
+ };
282
+ }
@@ -108,7 +108,7 @@ export function describeCommandPolicy(commandName: string): CommandExecutionPoli
108
108
  return {
109
109
  effect: 'read-only',
110
110
  confirmation,
111
- preferredModelTool: root === 'compat' ? 'agent_harness connected_host_status' : 'agent_harness connected_host_status/settings/tools/open_ui_surface',
111
+ preferredModelTool: root === 'compat' ? 'agent_harness service_posture/service_endpoint/connected_host_status' : 'agent_harness service_posture/service_endpoint/connected_host_status/settings/tools/open_ui_surface',
112
112
  boundary: 'Diagnostics and review commands inspect Agent, provider, MCP, security, and connected-host readiness without taking lifecycle ownership.',
113
113
  };
114
114
  }
@@ -346,7 +346,7 @@ export function describeCliCommandPolicy(commandName: string): CommandExecutionP
346
346
  return {
347
347
  effect: 'read-only',
348
348
  confirmation,
349
- preferredModelTool: root === 'tasks' ? 'agent_operator_briefing' : 'agent_harness connected_host/settings/tools',
349
+ preferredModelTool: root === 'tasks' ? 'agent_operator_briefing' : 'agent_harness service_posture/service_endpoint/connected_host_status/connected_host/settings/tools',
350
350
  boundary: 'Diagnostics and posture commands are readable from Agent-owned settings, provider, model, and connected-host capability surfaces without taking connected-host lifecycle ownership.',
351
351
  };
352
352
  }
@@ -431,8 +431,20 @@ export function connectedHostCapabilityMap(toolRegistry: ToolRegistry): readonly
431
431
  modelTools: ['agent_knowledge'],
432
432
  workspaceCategories: ['knowledge', 'research'],
433
433
  slashCommandFamilies: ['knowledge'],
434
- allowedActions: ['status', 'ask', 'search'],
435
- purpose: 'Read only isolated Agent Knowledge through the Agent route family.',
434
+ allowedActions: [
435
+ 'status',
436
+ 'ask',
437
+ 'search',
438
+ 'sources',
439
+ 'nodes',
440
+ 'issues',
441
+ 'item',
442
+ 'map',
443
+ 'connectors',
444
+ 'connector',
445
+ 'connector_doctor',
446
+ ],
447
+ purpose: 'Read isolated Agent Knowledge status, answers, search results, source/node/issue lists, items, map summaries, and connector diagnostics through the Agent route family.',
436
448
  }),
437
449
  withAvailability({
438
450
  id: 'agent-knowledge-ingest',
@@ -567,6 +579,8 @@ function connectedHostCapabilityDetail(entry: { readonly status: 'allowed' | 'bl
567
579
  status: 'allowed',
568
580
  capability: entry.capability,
569
581
  relatedRouteFamilies: relatedConnectedHostRouteFamilies(entry.capability),
582
+ operatorMethodMode: 'Use agent_harness mode:"operator_methods" for the public operator and Agent Knowledge method catalog. Use mode:"operator_method" for one method.',
583
+ servicePostureMode: 'Use agent_harness mode:"service_posture" for endpoint binding, network-facing posture, issue, and redacted-log diagnostics. Use mode:"service_endpoint" for one endpoint.',
570
584
  statusMode: 'Use agent_harness mode:"connected_host_status" for live read-only reachability, SDK compatibility, token posture, and Agent Knowledge route readiness.',
571
585
  boundary: 'Use only the listed first-class model tools, slash-command families, and workspace categories. Mutations still require explicit confirmation through those tools or command bridges.',
572
586
  };
@@ -577,6 +591,7 @@ function connectedHostCapabilityDetail(entry: { readonly status: 'allowed' | 'bl
577
591
  allowed: false,
578
592
  available: false,
579
593
  boundary: 'This connected-host surface is intentionally not exposed to the model as an Agent operation.',
594
+ servicePostureMode: 'Use agent_harness mode:"service_posture" or mode:"service_endpoint" only for read-only endpoint diagnostics.',
580
595
  statusMode: 'Use agent_harness mode:"connected_host_status" only for read-only readiness diagnostics.',
581
596
  };
582
597
  }
@@ -613,6 +628,8 @@ export function connectedHostSummary(context: CommandContext, toolRegistry: Tool
613
628
  tokenPath: connection.tokenPath,
614
629
  ownership: 'external-connected-host',
615
630
  lifecycle: 'GoodVibes Agent can use public connected-host operator routes, but does not start, stop, restart, install, expose, or mutate the host listener.',
631
+ servicePostureMode: 'Use agent_harness mode:"service_posture" for endpoint binding, network-facing posture, issue, and redacted-log diagnostics. Use mode:"service_endpoint" for one endpoint.',
632
+ operatorMethodMode: 'Use agent_harness mode:"operator_methods" for the public operator and Agent Knowledge method catalog. Use mode:"operator_method" for one method.',
616
633
  statusMode: 'Use agent_harness mode:"connected_host_status" for live read-only reachability, SDK compatibility, token posture, and Agent Knowledge route readiness.',
617
634
  routeFamilies: connectedHostRouteFamilies(),
618
635
  capabilities: connectedHostCapabilityMap(toolRegistry),