@pellux/goodvibes-agent 0.1.16 → 0.1.18
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 +8 -0
- package/package.json +1 -1
- package/src/tools/wrfc-agent-guard.ts +241 -0
- package/src/version.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to GoodVibes Agent will be recorded here.
|
|
4
4
|
|
|
5
|
+
## 0.1.18 - 2026-05-31
|
|
6
|
+
|
|
7
|
+
- 1fd7729 Restrict state tool mutations in agent runtime
|
|
8
|
+
|
|
9
|
+
## 0.1.17 - 2026-05-31
|
|
10
|
+
|
|
11
|
+
- f148186 Restrict fetch side effects in agent runtime
|
|
12
|
+
|
|
5
13
|
## 0.1.16 - 2026-05-31
|
|
6
14
|
|
|
7
15
|
- bea1197 Restrict MCP tool mutations in agent runtime
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pellux/goodvibes-agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.18",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Near-fork GoodVibes operator assistant with the GoodVibes TUI shell, renderer, input, fullscreen workspace, and daemon-connected Agent product brain.",
|
|
6
6
|
"type": "module",
|
|
@@ -26,6 +26,34 @@ type ModeToolArgs = {
|
|
|
26
26
|
readonly [key: string]: unknown;
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
+
type FetchToolArgs = {
|
|
30
|
+
readonly urls?: unknown;
|
|
31
|
+
readonly parallel?: unknown;
|
|
32
|
+
readonly sanitize_mode?: unknown;
|
|
33
|
+
readonly trusted_hosts?: unknown;
|
|
34
|
+
readonly [key: string]: unknown;
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
type StateToolArgs = {
|
|
38
|
+
readonly mode?: unknown;
|
|
39
|
+
readonly memoryAction?: unknown;
|
|
40
|
+
readonly hookAction?: unknown;
|
|
41
|
+
readonly modeAction?: unknown;
|
|
42
|
+
readonly analyticsAction?: unknown;
|
|
43
|
+
readonly values?: unknown;
|
|
44
|
+
readonly clearKeys?: unknown;
|
|
45
|
+
readonly memoryValue?: unknown;
|
|
46
|
+
readonly hookDefinition?: unknown;
|
|
47
|
+
readonly modeName?: unknown;
|
|
48
|
+
readonly analyticsTool?: unknown;
|
|
49
|
+
readonly analyticsArgs?: unknown;
|
|
50
|
+
readonly analyticsResult?: unknown;
|
|
51
|
+
readonly analyticsDuration?: unknown;
|
|
52
|
+
readonly analyticsTokens?: unknown;
|
|
53
|
+
readonly analyticsFormat?: unknown;
|
|
54
|
+
readonly [key: string]: unknown;
|
|
55
|
+
};
|
|
56
|
+
|
|
29
57
|
type AgentToolPolicyGuardOptions = {
|
|
30
58
|
readonly getLastUserMessage?: () => string | null;
|
|
31
59
|
};
|
|
@@ -51,9 +79,21 @@ const BLOCKED_MAIN_CONVERSATION_TOOL_NAME_SET = new Set<string>(BLOCKED_MAIN_CON
|
|
|
51
79
|
const READ_ONLY_REMOTE_TOOL_MODES = ['pools', 'contracts', 'artifacts', 'review'] as const;
|
|
52
80
|
const READ_ONLY_CHANNEL_TOOL_MODES = ['accounts', 'directory', 'resolve_target', 'capabilities', 'tools', 'agent_tools', 'actions'] as const;
|
|
53
81
|
const READ_ONLY_MCP_TOOL_MODES = ['servers', 'tools', 'schema', 'resources', 'security', 'auth'] as const;
|
|
82
|
+
const READ_ONLY_FETCH_METHODS = ['GET', 'HEAD', 'OPTIONS'] as const;
|
|
83
|
+
const READ_ONLY_STATE_TOOL_MODES = ['get', 'list', 'budget', 'context', 'memory', 'telemetry', 'hooks', 'mode', 'analytics'] as const;
|
|
84
|
+
const READ_ONLY_STATE_MEMORY_ACTIONS = ['list', 'get'] as const;
|
|
85
|
+
const READ_ONLY_STATE_HOOK_ACTIONS = ['list'] as const;
|
|
86
|
+
const READ_ONLY_STATE_MODE_ACTIONS = ['get', 'list'] as const;
|
|
87
|
+
const READ_ONLY_STATE_ANALYTICS_ACTIONS = ['summary', 'query', 'dashboard'] as const;
|
|
54
88
|
const READ_ONLY_REMOTE_TOOL_MODE_SET = new Set<string>(READ_ONLY_REMOTE_TOOL_MODES);
|
|
55
89
|
const READ_ONLY_CHANNEL_TOOL_MODE_SET = new Set<string>(READ_ONLY_CHANNEL_TOOL_MODES);
|
|
56
90
|
const READ_ONLY_MCP_TOOL_MODE_SET = new Set<string>(READ_ONLY_MCP_TOOL_MODES);
|
|
91
|
+
const READ_ONLY_FETCH_METHOD_SET = new Set<string>(READ_ONLY_FETCH_METHODS);
|
|
92
|
+
const READ_ONLY_STATE_TOOL_MODE_SET = new Set<string>(READ_ONLY_STATE_TOOL_MODES);
|
|
93
|
+
const READ_ONLY_STATE_MEMORY_ACTION_SET = new Set<string>(READ_ONLY_STATE_MEMORY_ACTIONS);
|
|
94
|
+
const READ_ONLY_STATE_HOOK_ACTION_SET = new Set<string>(READ_ONLY_STATE_HOOK_ACTIONS);
|
|
95
|
+
const READ_ONLY_STATE_MODE_ACTION_SET = new Set<string>(READ_ONLY_STATE_MODE_ACTIONS);
|
|
96
|
+
const READ_ONLY_STATE_ANALYTICS_ACTION_SET = new Set<string>(READ_ONLY_STATE_ANALYTICS_ACTIONS);
|
|
57
97
|
|
|
58
98
|
const LOCAL_AGENT_DENIAL = [
|
|
59
99
|
'GoodVibes Agent does not spawn local Engineer/Reviewer/Tester/Verifier roots or run local WRFC chains.',
|
|
@@ -91,6 +131,18 @@ const MCP_SECURITY_MUTATION_DENIAL = [
|
|
|
91
131
|
'MCP security mutations require an explicit Agent approval flow before they can run.',
|
|
92
132
|
].join(' ');
|
|
93
133
|
|
|
134
|
+
const FETCH_NETWORK_MUTATION_DENIAL = [
|
|
135
|
+
'GoodVibes Agent only performs serial, unauthenticated, read-only HTTP fetches from the main conversation.',
|
|
136
|
+
'Non-read methods, request bodies, custom auth/header/service credentials, trust overrides, raw unsanitized responses, and parallel fetch batches are disabled here.',
|
|
137
|
+
'Network writes or credentialed external calls require an explicit Agent approval flow before they can run.',
|
|
138
|
+
].join(' ');
|
|
139
|
+
|
|
140
|
+
const STATE_MUTATION_DENIAL = [
|
|
141
|
+
'GoodVibes Agent only inspects copied runtime state from the main conversation.',
|
|
142
|
+
'Arbitrary state set/clear, copied memory writes, hook mutation, output-mode mutation, and analytics writes are disabled here.',
|
|
143
|
+
'Use Agent-owned memory, skills, personas, routines, and explicit CLI/slash commands for intentional local state changes.',
|
|
144
|
+
].join(' ');
|
|
145
|
+
|
|
94
146
|
export function installAgentToolPolicyGuard(registry: ToolRegistry, options: AgentToolPolicyGuardOptions = {}): void {
|
|
95
147
|
const agentTool = registry.list().find((tool) => tool.definition.name === 'agent');
|
|
96
148
|
if (!agentTool) throw new Error('Agent tool policy guard could not find the agent tool.');
|
|
@@ -120,6 +172,10 @@ export function installAgentToolPolicyGuard(registry: ToolRegistry, options: Age
|
|
|
120
172
|
].join(' '),
|
|
121
173
|
denial: MCP_SECURITY_MUTATION_DENIAL,
|
|
122
174
|
});
|
|
175
|
+
} else if (tool.definition.name === 'fetch') {
|
|
176
|
+
wrapFetchToolForAgentPolicy(tool);
|
|
177
|
+
} else if (tool.definition.name === 'state') {
|
|
178
|
+
wrapStateToolForAgentPolicy(tool);
|
|
123
179
|
} else if (BLOCKED_MAIN_CONVERSATION_TOOL_NAME_SET.has(tool.definition.name)) {
|
|
124
180
|
wrapBlockedMainConversationToolForAgentPolicy(tool);
|
|
125
181
|
}
|
|
@@ -165,6 +221,26 @@ export function wrapExecToolForAgentPolicy(tool: Tool): void {
|
|
|
165
221
|
};
|
|
166
222
|
}
|
|
167
223
|
|
|
224
|
+
export function wrapFetchToolForAgentPolicy(tool: Tool): void {
|
|
225
|
+
narrowFetchToolDefinitionForAgentPolicy(tool);
|
|
226
|
+
const originalExecute = tool.execute.bind(tool);
|
|
227
|
+
tool.execute = async (args) => {
|
|
228
|
+
const denial = validateFetchToolInvocationForAgentPolicy(args as FetchToolArgs);
|
|
229
|
+
if (denial) return { success: false, error: denial };
|
|
230
|
+
return originalExecute(normalizeFetchToolInvocationForAgentPolicy(args as FetchToolArgs) as Parameters<Tool['execute']>[0]);
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
export function wrapStateToolForAgentPolicy(tool: Tool): void {
|
|
235
|
+
narrowStateToolDefinitionForAgentPolicy(tool);
|
|
236
|
+
const originalExecute = tool.execute.bind(tool);
|
|
237
|
+
tool.execute = async (args) => {
|
|
238
|
+
const denial = validateStateToolInvocationForAgentPolicy(args as StateToolArgs);
|
|
239
|
+
if (denial) return { success: false, error: denial };
|
|
240
|
+
return originalExecute(args);
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
|
|
168
244
|
export function validateExecToolInvocationForAgentPolicy(args: ExecToolArgs): string | null {
|
|
169
245
|
if (args.parallel === true) return BACKGROUND_EXEC_DENIAL;
|
|
170
246
|
if (Array.isArray(args.file_ops) && args.file_ops.length > 0) return BACKGROUND_EXEC_DENIAL;
|
|
@@ -187,6 +263,68 @@ export function validateExecToolInvocationForAgentPolicy(args: ExecToolArgs): st
|
|
|
187
263
|
return null;
|
|
188
264
|
}
|
|
189
265
|
|
|
266
|
+
export function validateFetchToolInvocationForAgentPolicy(args: FetchToolArgs): string | null {
|
|
267
|
+
if (args.parallel === true) return FETCH_NETWORK_MUTATION_DENIAL;
|
|
268
|
+
if (args.sanitize_mode === 'none') return FETCH_NETWORK_MUTATION_DENIAL;
|
|
269
|
+
if (isPresent(args.trusted_hosts)) return FETCH_NETWORK_MUTATION_DENIAL;
|
|
270
|
+
if (!Array.isArray(args.urls)) return null;
|
|
271
|
+
|
|
272
|
+
for (const urlArgs of args.urls) {
|
|
273
|
+
if (!isRecord(urlArgs)) continue;
|
|
274
|
+
const method = typeof urlArgs.method === 'string' ? urlArgs.method.toUpperCase() : 'GET';
|
|
275
|
+
if (!READ_ONLY_FETCH_METHOD_SET.has(method)) return FETCH_NETWORK_MUTATION_DENIAL;
|
|
276
|
+
if (isPresent(urlArgs.body) || isPresent(urlArgs.body_base64) || isPresent(urlArgs.body_type) || isPresent(urlArgs.body_data)) {
|
|
277
|
+
return FETCH_NETWORK_MUTATION_DENIAL;
|
|
278
|
+
}
|
|
279
|
+
if (isPresent(urlArgs.headers) || isPresent(urlArgs.auth) || isPresent(urlArgs.service) || isPresent(urlArgs.retry_on_auth)) {
|
|
280
|
+
return FETCH_NETWORK_MUTATION_DENIAL;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
export function normalizeFetchToolInvocationForAgentPolicy(args: FetchToolArgs): FetchToolArgs {
|
|
288
|
+
return { ...args, parallel: false };
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
export function validateStateToolInvocationForAgentPolicy(args: StateToolArgs): string | null {
|
|
292
|
+
if (isPresent(args.values) || isPresent(args.clearKeys)) return STATE_MUTATION_DENIAL;
|
|
293
|
+
if (typeof args.mode === 'string' && !READ_ONLY_STATE_TOOL_MODE_SET.has(args.mode)) return STATE_MUTATION_DENIAL;
|
|
294
|
+
|
|
295
|
+
if (args.mode === 'memory') {
|
|
296
|
+
const action = typeof args.memoryAction === 'string' ? args.memoryAction : 'list';
|
|
297
|
+
if (!READ_ONLY_STATE_MEMORY_ACTION_SET.has(action) || isPresent(args.memoryValue)) return STATE_MUTATION_DENIAL;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (args.mode === 'hooks') {
|
|
301
|
+
const action = typeof args.hookAction === 'string' ? args.hookAction : 'list';
|
|
302
|
+
if (!READ_ONLY_STATE_HOOK_ACTION_SET.has(action) || isPresent(args.hookDefinition)) return STATE_MUTATION_DENIAL;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (args.mode === 'mode') {
|
|
306
|
+
const action = typeof args.modeAction === 'string' ? args.modeAction : 'get';
|
|
307
|
+
if (!READ_ONLY_STATE_MODE_ACTION_SET.has(action) || isPresent(args.modeName)) return STATE_MUTATION_DENIAL;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
if (args.mode === 'analytics') {
|
|
311
|
+
const action = typeof args.analyticsAction === 'string' ? args.analyticsAction : 'summary';
|
|
312
|
+
if (!READ_ONLY_STATE_ANALYTICS_ACTION_SET.has(action)) return STATE_MUTATION_DENIAL;
|
|
313
|
+
if (
|
|
314
|
+
isPresent(args.analyticsTool)
|
|
315
|
+
|| isPresent(args.analyticsArgs)
|
|
316
|
+
|| isPresent(args.analyticsResult)
|
|
317
|
+
|| isPresent(args.analyticsDuration)
|
|
318
|
+
|| isPresent(args.analyticsTokens)
|
|
319
|
+
|| isPresent(args.analyticsFormat)
|
|
320
|
+
) {
|
|
321
|
+
return STATE_MUTATION_DENIAL;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
|
|
190
328
|
type ModeRestrictedToolPolicy = {
|
|
191
329
|
readonly allowedModes: readonly string[];
|
|
192
330
|
readonly modeSet: ReadonlySet<string>;
|
|
@@ -240,14 +378,30 @@ export const AGENT_EXEC_BACKGROUND_DENIAL_MESSAGE = BACKGROUND_EXEC_DENIAL;
|
|
|
240
378
|
export const AGENT_READ_ONLY_REMOTE_TOOL_MODES = READ_ONLY_REMOTE_TOOL_MODES;
|
|
241
379
|
export const AGENT_READ_ONLY_CHANNEL_TOOL_MODES = READ_ONLY_CHANNEL_TOOL_MODES;
|
|
242
380
|
export const AGENT_READ_ONLY_MCP_TOOL_MODES = READ_ONLY_MCP_TOOL_MODES;
|
|
381
|
+
export const AGENT_READ_ONLY_FETCH_METHODS = READ_ONLY_FETCH_METHODS;
|
|
382
|
+
export const AGENT_READ_ONLY_STATE_TOOL_MODES = READ_ONLY_STATE_TOOL_MODES;
|
|
383
|
+
export const AGENT_READ_ONLY_STATE_MEMORY_ACTIONS = READ_ONLY_STATE_MEMORY_ACTIONS;
|
|
384
|
+
export const AGENT_READ_ONLY_STATE_HOOK_ACTIONS = READ_ONLY_STATE_HOOK_ACTIONS;
|
|
385
|
+
export const AGENT_READ_ONLY_STATE_MODE_ACTIONS = READ_ONLY_STATE_MODE_ACTIONS;
|
|
386
|
+
export const AGENT_READ_ONLY_STATE_ANALYTICS_ACTIONS = READ_ONLY_STATE_ANALYTICS_ACTIONS;
|
|
243
387
|
export const AGENT_REMOTE_MUTATION_DENIAL_MESSAGE = REMOTE_MUTATION_DENIAL;
|
|
244
388
|
export const AGENT_CHANNEL_ACTION_DENIAL_MESSAGE = CHANNEL_ACTION_DENIAL;
|
|
245
389
|
export const AGENT_MCP_SECURITY_MUTATION_DENIAL_MESSAGE = MCP_SECURITY_MUTATION_DENIAL;
|
|
390
|
+
export const AGENT_FETCH_NETWORK_MUTATION_DENIAL_MESSAGE = FETCH_NETWORK_MUTATION_DENIAL;
|
|
391
|
+
export const AGENT_STATE_MUTATION_DENIAL_MESSAGE = STATE_MUTATION_DENIAL;
|
|
246
392
|
|
|
247
393
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
248
394
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
249
395
|
}
|
|
250
396
|
|
|
397
|
+
function isPresent(value: unknown): boolean {
|
|
398
|
+
if (value === undefined || value === null) return false;
|
|
399
|
+
if (typeof value === 'string') return value.length > 0;
|
|
400
|
+
if (Array.isArray(value)) return value.length > 0;
|
|
401
|
+
if (isRecord(value)) return Object.keys(value).length > 0;
|
|
402
|
+
return true;
|
|
403
|
+
}
|
|
404
|
+
|
|
251
405
|
function narrowAgentToolDefinitionForAgentPolicy(tool: Tool): void {
|
|
252
406
|
tool.definition.description = [
|
|
253
407
|
'Read-only local Agent inspection for GoodVibes Agent.',
|
|
@@ -293,6 +447,81 @@ function narrowExecToolDefinitionForAgentPolicy(tool: Tool): void {
|
|
|
293
447
|
}
|
|
294
448
|
}
|
|
295
449
|
|
|
450
|
+
function narrowFetchToolDefinitionForAgentPolicy(tool: Tool): void {
|
|
451
|
+
tool.definition.description = [
|
|
452
|
+
'Fetch public URLs for GoodVibes Agent with serial, read-only HTTP requests.',
|
|
453
|
+
'Only GET, HEAD, and OPTIONS are available in the main conversation.',
|
|
454
|
+
'Credentialed requests, request bodies, trust overrides, raw unsanitized responses, and parallel batches are disabled by Agent policy.',
|
|
455
|
+
].join(' ');
|
|
456
|
+
|
|
457
|
+
const properties = tool.definition.parameters.properties;
|
|
458
|
+
if (!isRecord(properties)) return;
|
|
459
|
+
delete properties.parallel;
|
|
460
|
+
delete properties.trusted_hosts;
|
|
461
|
+
|
|
462
|
+
const sanitizeModeProperty = properties.sanitize_mode;
|
|
463
|
+
if (isRecord(sanitizeModeProperty)) {
|
|
464
|
+
sanitizeModeProperty.enum = ['safe-text', 'strict'];
|
|
465
|
+
sanitizeModeProperty.description = 'Response sanitization mode. Raw unsanitized responses are disabled in GoodVibes Agent.';
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
const urlsProperty = properties.urls;
|
|
469
|
+
if (!isRecord(urlsProperty)) return;
|
|
470
|
+
const itemSchema = urlsProperty.items;
|
|
471
|
+
if (!isRecord(itemSchema)) return;
|
|
472
|
+
const urlProperties = itemSchema.properties;
|
|
473
|
+
if (!isRecord(urlProperties)) return;
|
|
474
|
+
|
|
475
|
+
const methodProperty = urlProperties.method;
|
|
476
|
+
if (isRecord(methodProperty)) {
|
|
477
|
+
methodProperty.enum = [...READ_ONLY_FETCH_METHODS];
|
|
478
|
+
methodProperty.description = 'Read-only HTTP method. GoodVibes Agent disables POST, PUT, PATCH, and DELETE in the main conversation.';
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
delete urlProperties.headers;
|
|
482
|
+
delete urlProperties.body;
|
|
483
|
+
delete urlProperties.body_base64;
|
|
484
|
+
delete urlProperties.body_type;
|
|
485
|
+
delete urlProperties.body_data;
|
|
486
|
+
delete urlProperties.retry_on_auth;
|
|
487
|
+
delete urlProperties.service;
|
|
488
|
+
delete urlProperties.auth;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
function narrowStateToolDefinitionForAgentPolicy(tool: Tool): void {
|
|
492
|
+
tool.definition.description = [
|
|
493
|
+
'Inspect copied runtime state for GoodVibes Agent.',
|
|
494
|
+
'State mutation, copied memory writes, hook changes, output-mode changes, and analytics writes are disabled in the main conversation.',
|
|
495
|
+
'Use Agent-owned commands for intentional memory, skill, persona, and routine changes.',
|
|
496
|
+
].join(' ');
|
|
497
|
+
|
|
498
|
+
const properties = tool.definition.parameters.properties;
|
|
499
|
+
if (!isRecord(properties)) return;
|
|
500
|
+
const modeProperty = properties.mode;
|
|
501
|
+
if (isRecord(modeProperty)) {
|
|
502
|
+
modeProperty.enum = [...READ_ONLY_STATE_TOOL_MODES];
|
|
503
|
+
modeProperty.description = 'Read-only copied runtime state mode. set and clear are disabled in GoodVibes Agent.';
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
delete properties.values;
|
|
507
|
+
delete properties.clearKeys;
|
|
508
|
+
delete properties.memoryValue;
|
|
509
|
+
delete properties.hookDefinition;
|
|
510
|
+
delete properties.hookName;
|
|
511
|
+
delete properties.modeName;
|
|
512
|
+
delete properties.analyticsTool;
|
|
513
|
+
delete properties.analyticsArgs;
|
|
514
|
+
delete properties.analyticsResult;
|
|
515
|
+
delete properties.analyticsDuration;
|
|
516
|
+
delete properties.analyticsTokens;
|
|
517
|
+
delete properties.analyticsFormat;
|
|
518
|
+
|
|
519
|
+
narrowStringEnumProperty(properties, 'memoryAction', READ_ONLY_STATE_MEMORY_ACTIONS, 'Read-only copied memory actions allowed by GoodVibes Agent.');
|
|
520
|
+
narrowStringEnumProperty(properties, 'hookAction', READ_ONLY_STATE_HOOK_ACTIONS, 'Read-only hook action allowed by GoodVibes Agent.');
|
|
521
|
+
narrowStringEnumProperty(properties, 'modeAction', READ_ONLY_STATE_MODE_ACTIONS, 'Read-only mode actions allowed by GoodVibes Agent.');
|
|
522
|
+
narrowStringEnumProperty(properties, 'analyticsAction', READ_ONLY_STATE_ANALYTICS_ACTIONS, 'Read-only analytics actions allowed by GoodVibes Agent.');
|
|
523
|
+
}
|
|
524
|
+
|
|
296
525
|
function narrowModeToolDefinitionForAgentPolicy(tool: Tool, allowedModes: readonly string[], description: string): void {
|
|
297
526
|
tool.definition.description = description;
|
|
298
527
|
|
|
@@ -313,6 +542,18 @@ function narrowModeToolDefinitionForAgentPolicy(tool: Tool, allowedModes: readon
|
|
|
313
542
|
}
|
|
314
543
|
}
|
|
315
544
|
|
|
545
|
+
function narrowStringEnumProperty(
|
|
546
|
+
properties: Record<string, unknown>,
|
|
547
|
+
key: string,
|
|
548
|
+
values: readonly string[],
|
|
549
|
+
description: string,
|
|
550
|
+
): void {
|
|
551
|
+
const property = properties[key];
|
|
552
|
+
if (!isRecord(property)) return;
|
|
553
|
+
property.enum = [...values];
|
|
554
|
+
property.description = description;
|
|
555
|
+
}
|
|
556
|
+
|
|
316
557
|
// Compatibility exports for copied TUI tests/imports during the near-fork phase.
|
|
317
558
|
export const installWrfcAgentToolGuard = installAgentToolPolicyGuard;
|
|
318
559
|
export const wrapWrfcAgentTool = wrapAgentToolForAgentPolicy;
|
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 = '0.1.
|
|
9
|
+
let _version = '0.1.18';
|
|
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 {
|