@vellumai/assistant 0.3.23 → 0.3.24
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/package.json +1 -1
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +0 -84
- package/src/__tests__/approval-primitive.test.ts +72 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -4
- package/src/__tests__/ipc-snapshot.test.ts +0 -42
- package/src/__tests__/skill-feature-flags-integration.test.ts +0 -4
- package/src/__tests__/tool-approval-handler.test.ts +94 -5
- package/src/cli/mcp.ts +20 -0
- package/src/config/bundled-skills/google-oauth-setup/SKILL.md +13 -8
- package/src/config/bundled-skills/reminder/SKILL.md +7 -6
- package/src/config/bundled-skills/time-based-actions/SKILL.md +7 -6
- package/src/config/system-prompt.ts +0 -72
- package/src/config/vellum-skills/slack-oauth-setup/SKILL.md +14 -6
- package/src/daemon/handlers/config.ts +0 -4
- package/src/daemon/handlers/navigate-settings.ts +0 -1
- package/src/daemon/ipc-contract-inventory.json +0 -10
- package/src/daemon/ipc-contract.ts +0 -4
- package/src/daemon/session-process.ts +2 -2
- package/src/permissions/checker.ts +4 -4
- package/src/runtime/routes/inbound-message-handler.ts +2 -2
- package/src/runtime/routes/ingress-routes.ts +7 -2
- package/src/tools/executor.ts +2 -2
- package/src/tools/system/navigate-settings.ts +0 -1
- package/src/tools/tool-approval-handler.ts +2 -33
- package/src/daemon/handlers/config-parental.ts +0 -164
- package/src/daemon/ipc-contract/parental-control.ts +0 -109
- package/src/security/parental-control-store.ts +0 -184
|
@@ -14,7 +14,6 @@
|
|
|
14
14
|
* config-twilio.ts — Twilio SMS/voice configuration
|
|
15
15
|
* config-channels.ts — Channel guardian & readiness
|
|
16
16
|
* config-tools.ts — Env vars, tool permission simulation, tool names
|
|
17
|
-
* config-parental.ts — Parental control PIN + content/tool restrictions
|
|
18
17
|
*/
|
|
19
18
|
|
|
20
19
|
// Re-export individual handlers for direct import by tests and other modules
|
|
@@ -23,7 +22,6 @@ export { handleHeartbeatChecklistRead, handleHeartbeatChecklistWrite,handleHeart
|
|
|
23
22
|
export { computeGatewayTarget, handleIngressConfig, syncTwilioWebhooks,triggerGatewayReconcile } from './config-ingress.js';
|
|
24
23
|
export { handleTwitterIntegrationConfig,handleVercelApiConfig } from './config-integrations.js';
|
|
25
24
|
export { handleImageGenModelSet,handleModelGet, handleModelSet } from './config-model.js';
|
|
26
|
-
export { handleParentalControlGet, handleParentalControlSetPin, handleParentalControlUpdate,handleParentalControlVerifyPin } from './config-parental.js';
|
|
27
25
|
export { handlePlatformConfig } from './config-platform.js';
|
|
28
26
|
export { handleReminderCancel,handleRemindersList, handleScheduleRemove, handleScheduleRunNow, handleSchedulesList, handleScheduleToggle } from './config-scheduling.js';
|
|
29
27
|
export { handleShareToSlack, handleSlackWebhookConfig } from './config-slack.js';
|
|
@@ -39,7 +37,6 @@ import { heartbeatHandlers } from './config-heartbeat.js';
|
|
|
39
37
|
import { ingressHandlers } from './config-ingress.js';
|
|
40
38
|
import { integrationHandlers } from './config-integrations.js';
|
|
41
39
|
import { modelHandlers } from './config-model.js';
|
|
42
|
-
import { parentalControlHandlers } from './config-parental.js';
|
|
43
40
|
import { platformHandlers } from './config-platform.js';
|
|
44
41
|
import { schedulingHandlers } from './config-scheduling.js';
|
|
45
42
|
import { slackHandlers } from './config-slack.js';
|
|
@@ -61,7 +58,6 @@ export const configHandlers = {
|
|
|
61
58
|
...twilioHandlers,
|
|
62
59
|
...channelHandlers,
|
|
63
60
|
...toolHandlers,
|
|
64
|
-
...parentalControlHandlers,
|
|
65
61
|
...heartbeatHandlers,
|
|
66
62
|
...voiceHandlers,
|
|
67
63
|
};
|
|
@@ -11,7 +11,6 @@
|
|
|
11
11
|
"_MessagesClientMessages",
|
|
12
12
|
"_NotificationsClientMessages",
|
|
13
13
|
"_PairingClientMessages",
|
|
14
|
-
"_ParentalControlClientMessages",
|
|
15
14
|
"_SchedulesClientMessages",
|
|
16
15
|
"_SessionsClientMessages",
|
|
17
16
|
"_SettingsClientMessages",
|
|
@@ -36,7 +35,6 @@
|
|
|
36
35
|
"_MessagesServerMessages",
|
|
37
36
|
"_NotificationsServerMessages",
|
|
38
37
|
"_PairingServerMessages",
|
|
39
|
-
"_ParentalControlServerMessages",
|
|
40
38
|
"_SchedulesServerMessages",
|
|
41
39
|
"_SessionsServerMessages",
|
|
42
40
|
"_SettingsServerMessages",
|
|
@@ -117,10 +115,6 @@
|
|
|
117
115
|
"oauth_connect_start",
|
|
118
116
|
"open_bundle",
|
|
119
117
|
"pairing_approval_response",
|
|
120
|
-
"parental_control_get",
|
|
121
|
-
"parental_control_set_pin",
|
|
122
|
-
"parental_control_update",
|
|
123
|
-
"parental_control_verify_pin",
|
|
124
118
|
"ping",
|
|
125
119
|
"platform_config",
|
|
126
120
|
"publish_page",
|
|
@@ -281,10 +275,6 @@
|
|
|
281
275
|
"open_bundle_response",
|
|
282
276
|
"open_url",
|
|
283
277
|
"pairing_approval_request",
|
|
284
|
-
"parental_control_get_response",
|
|
285
|
-
"parental_control_set_pin_response",
|
|
286
|
-
"parental_control_update_response",
|
|
287
|
-
"parental_control_verify_pin_response",
|
|
288
278
|
"platform_config_response",
|
|
289
279
|
"pong",
|
|
290
280
|
"publish_page_response",
|
|
@@ -25,7 +25,6 @@ export * from './ipc-contract/memory.js';
|
|
|
25
25
|
export * from './ipc-contract/messages.js';
|
|
26
26
|
export * from './ipc-contract/notifications.js';
|
|
27
27
|
export * from './ipc-contract/pairing.js';
|
|
28
|
-
export * from './ipc-contract/parental-control.js';
|
|
29
28
|
export * from './ipc-contract/schedules.js';
|
|
30
29
|
export * from './ipc-contract/sessions.js';
|
|
31
30
|
export * from './ipc-contract/settings.js';
|
|
@@ -50,7 +49,6 @@ import type { _MemoryServerMessages } from './ipc-contract/memory.js';
|
|
|
50
49
|
import type { _MessagesClientMessages, _MessagesServerMessages } from './ipc-contract/messages.js';
|
|
51
50
|
import type { _NotificationsClientMessages, _NotificationsServerMessages } from './ipc-contract/notifications.js';
|
|
52
51
|
import type { _PairingClientMessages, _PairingServerMessages } from './ipc-contract/pairing.js';
|
|
53
|
-
import type { _ParentalControlClientMessages, _ParentalControlServerMessages } from './ipc-contract/parental-control.js';
|
|
54
52
|
import type { _SchedulesClientMessages, _SchedulesServerMessages } from './ipc-contract/schedules.js';
|
|
55
53
|
import type { _SessionsClientMessages, _SessionsServerMessages } from './ipc-contract/sessions.js';
|
|
56
54
|
import type { _SettingsClientMessages, _SettingsServerMessages } from './ipc-contract/settings.js';
|
|
@@ -89,7 +87,6 @@ export type ClientMessage =
|
|
|
89
87
|
| _WorkspaceClientMessages
|
|
90
88
|
| _SchedulesClientMessages
|
|
91
89
|
| _DiagnosticsClientMessages
|
|
92
|
-
| _ParentalControlClientMessages
|
|
93
90
|
| _InboxClientMessages
|
|
94
91
|
| _PairingClientMessages
|
|
95
92
|
| _NotificationsClientMessages
|
|
@@ -116,7 +113,6 @@ export type ServerMessage =
|
|
|
116
113
|
| _SchedulesServerMessages
|
|
117
114
|
| _SettingsServerMessages
|
|
118
115
|
| _DiagnosticsServerMessages
|
|
119
|
-
| _ParentalControlServerMessages
|
|
120
116
|
| _InboxServerMessages
|
|
121
117
|
| _PairingServerMessages
|
|
122
118
|
| _NotificationsServerMessages
|
|
@@ -576,9 +576,9 @@ export async function processMessage(
|
|
|
576
576
|
|
|
577
577
|
let stateApplied = true;
|
|
578
578
|
if (turnResult.disposition === 'call_back' || turnResult.disposition === 'message_back') {
|
|
579
|
-
stateApplied = progressFollowupState(request.id, 'dispatching', turnResult.disposition) !==
|
|
579
|
+
stateApplied = progressFollowupState(request.id, 'dispatching', turnResult.disposition) !== null;
|
|
580
580
|
} else if (turnResult.disposition === 'decline') {
|
|
581
|
-
stateApplied = finalizeFollowup(request.id, 'declined') !==
|
|
581
|
+
stateApplied = finalizeFollowup(request.id, 'declined') !== null;
|
|
582
582
|
}
|
|
583
583
|
|
|
584
584
|
if (!stateApplied) {
|
|
@@ -398,10 +398,10 @@ async function classifyRiskUncached(toolName: string, input: Record<string, unkn
|
|
|
398
398
|
if (HIGH_RISK_PROGRAMS.has(prog)) return RiskLevel.High;
|
|
399
399
|
|
|
400
400
|
if (prog === 'rm') {
|
|
401
|
-
//
|
|
402
|
-
//
|
|
403
|
-
//
|
|
404
|
-
if (isRmOfKnownSafeFile(seg.args)) {
|
|
401
|
+
// Only downgrade rm of known safe workspace files for sandboxed bash.
|
|
402
|
+
// host_bash has a global allow rule that would auto-approve Medium-risk
|
|
403
|
+
// commands, so rm on the host must always require explicit approval.
|
|
404
|
+
if (toolName === 'bash' && isRmOfKnownSafeFile(seg.args)) {
|
|
405
405
|
maxRisk = RiskLevel.Medium;
|
|
406
406
|
continue;
|
|
407
407
|
}
|
|
@@ -1087,9 +1087,9 @@ export async function handleChannelInbound(
|
|
|
1087
1087
|
|
|
1088
1088
|
let stateApplied = true;
|
|
1089
1089
|
if (turnResult.disposition === 'call_back' || turnResult.disposition === 'message_back') {
|
|
1090
|
-
stateApplied = progressFollowupState(request.id, 'dispatching', turnResult.disposition) !==
|
|
1090
|
+
stateApplied = progressFollowupState(request.id, 'dispatching', turnResult.disposition) !== null;
|
|
1091
1091
|
} else if (turnResult.disposition === 'decline') {
|
|
1092
|
-
stateApplied = finalizeFollowup(request.id, 'declined') !==
|
|
1092
|
+
stateApplied = finalizeFollowup(request.id, 'declined') !== null;
|
|
1093
1093
|
}
|
|
1094
1094
|
|
|
1095
1095
|
if (!stateApplied) {
|
|
@@ -93,8 +93,13 @@ export async function handleRevokeMember(req: Request, memberId: string): Promis
|
|
|
93
93
|
* POST /v1/ingress/members/:id/block
|
|
94
94
|
*/
|
|
95
95
|
export async function handleBlockMember(req: Request, memberId: string): Promise<Response> {
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
let reason: string | undefined;
|
|
97
|
+
try {
|
|
98
|
+
const body = (await req.json()) as Record<string, unknown>;
|
|
99
|
+
reason = body.reason as string | undefined;
|
|
100
|
+
} catch {
|
|
101
|
+
// Body is optional — callers may omit it entirely
|
|
102
|
+
}
|
|
98
103
|
|
|
99
104
|
const result = blockIngressMember(memberId, reason);
|
|
100
105
|
|
package/src/tools/executor.ts
CHANGED
|
@@ -56,8 +56,8 @@ export class ToolExecutor {
|
|
|
56
56
|
startedAtMs: startTime,
|
|
57
57
|
});
|
|
58
58
|
|
|
59
|
-
// Run pre-execution approval gates (abort,
|
|
60
|
-
//
|
|
59
|
+
// Run pre-execution approval gates (abort, guardian policy,
|
|
60
|
+
// allowed-tool-set, task-run preflight, tool registry lookup).
|
|
61
61
|
const gateResult = await this.approvalHandler.checkPreExecutionGates(
|
|
62
62
|
name, input, context, executionTarget, riskLevel, startTime,
|
|
63
63
|
(event) => emitLifecycleEvent(context, event),
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { consumeGrantForInvocation } from '../approvals/approval-primitive.js';
|
|
2
|
-
import { isToolBlocked } from '../security/parental-control-store.js';
|
|
3
2
|
import { computeToolApprovalDigest } from '../security/tool-approval-digest.js';
|
|
4
3
|
import { getTaskRunRules } from '../tasks/ephemeral-permissions.js';
|
|
5
4
|
import { getLogger } from '../util/logger.js';
|
|
@@ -40,8 +39,8 @@ export type PreExecutionGateResult =
|
|
|
40
39
|
| { allowed: false; result: ToolExecutionResult };
|
|
41
40
|
|
|
42
41
|
/**
|
|
43
|
-
* Handles pre-execution approval gates: abort checks,
|
|
44
|
-
*
|
|
42
|
+
* Handles pre-execution approval gates: abort checks, guardian policy,
|
|
43
|
+
* allowed-tool-set gating, and task-run preflight checks.
|
|
45
44
|
* These run before the interactive permission prompt flow.
|
|
46
45
|
*/
|
|
47
46
|
export class ToolApprovalHandler {
|
|
@@ -81,36 +80,6 @@ export class ToolApprovalHandler {
|
|
|
81
80
|
return { allowed: false, result: { content: 'Cancelled', isError: true } };
|
|
82
81
|
}
|
|
83
82
|
|
|
84
|
-
// Reject tools blocked by parental control settings before any permission check.
|
|
85
|
-
if (isToolBlocked(name)) {
|
|
86
|
-
log.warn(
|
|
87
|
-
{
|
|
88
|
-
toolName: name,
|
|
89
|
-
sessionId: context.sessionId,
|
|
90
|
-
conversationId: context.conversationId,
|
|
91
|
-
principal: context.principal,
|
|
92
|
-
reason: 'blocked_by_parental_controls',
|
|
93
|
-
},
|
|
94
|
-
'Parental control blocked tool invocation',
|
|
95
|
-
);
|
|
96
|
-
const durationMs = Date.now() - startTime;
|
|
97
|
-
emitLifecycleEvent({
|
|
98
|
-
type: 'permission_denied',
|
|
99
|
-
toolName: name,
|
|
100
|
-
executionTarget,
|
|
101
|
-
input,
|
|
102
|
-
workingDir: context.workingDir,
|
|
103
|
-
sessionId: context.sessionId,
|
|
104
|
-
conversationId: context.conversationId,
|
|
105
|
-
requestId: context.requestId,
|
|
106
|
-
riskLevel,
|
|
107
|
-
decision: 'deny',
|
|
108
|
-
reason: 'Blocked by parental control settings',
|
|
109
|
-
durationMs,
|
|
110
|
-
});
|
|
111
|
-
return { allowed: false, result: { content: 'This tool is blocked by parental control settings.', isError: true } };
|
|
112
|
-
}
|
|
113
|
-
|
|
114
83
|
// Reject tool invocations targeting guardian control-plane endpoints from non-guardian actors.
|
|
115
84
|
const guardianCheck = enforceGuardianOnlyPolicy(name, input, context.guardianActorRole);
|
|
116
85
|
if (guardianCheck.denied) {
|
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
import * as net from 'node:net';
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
clearPIN,
|
|
5
|
-
getParentalControlSettings,
|
|
6
|
-
hasPIN,
|
|
7
|
-
setPIN,
|
|
8
|
-
updateParentalControlSettings,
|
|
9
|
-
verifyPIN,
|
|
10
|
-
} from '../../security/parental-control-store.js';
|
|
11
|
-
import { getLogger } from '../../util/logger.js';
|
|
12
|
-
import type {
|
|
13
|
-
ParentalControlGetRequest,
|
|
14
|
-
ParentalControlSetPinRequest,
|
|
15
|
-
ParentalControlUpdateRequest,
|
|
16
|
-
ParentalControlVerifyPinRequest,
|
|
17
|
-
} from '../ipc-protocol.js';
|
|
18
|
-
import { defineHandlers, type HandlerContext } from './shared.js';
|
|
19
|
-
|
|
20
|
-
const log = getLogger('parental-control');
|
|
21
|
-
|
|
22
|
-
function sendGetResponse(socket: net.Socket, ctx: HandlerContext): void {
|
|
23
|
-
const settings = getParentalControlSettings();
|
|
24
|
-
ctx.send(socket, {
|
|
25
|
-
type: 'parental_control_get_response',
|
|
26
|
-
enabled: settings.enabled,
|
|
27
|
-
has_pin: hasPIN(),
|
|
28
|
-
content_restrictions: settings.contentRestrictions,
|
|
29
|
-
blocked_tool_categories: settings.blockedToolCategories,
|
|
30
|
-
});
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export function handleParentalControlGet(
|
|
34
|
-
_msg: ParentalControlGetRequest,
|
|
35
|
-
socket: net.Socket,
|
|
36
|
-
ctx: HandlerContext,
|
|
37
|
-
): void {
|
|
38
|
-
sendGetResponse(socket, ctx);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function handleParentalControlVerifyPin(
|
|
42
|
-
msg: ParentalControlVerifyPinRequest,
|
|
43
|
-
socket: net.Socket,
|
|
44
|
-
ctx: HandlerContext,
|
|
45
|
-
): void {
|
|
46
|
-
const verified = verifyPIN(msg.pin);
|
|
47
|
-
ctx.send(socket, {
|
|
48
|
-
type: 'parental_control_verify_pin_response',
|
|
49
|
-
verified,
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export function handleParentalControlSetPin(
|
|
54
|
-
msg: ParentalControlSetPinRequest,
|
|
55
|
-
socket: net.Socket,
|
|
56
|
-
ctx: HandlerContext,
|
|
57
|
-
): void {
|
|
58
|
-
try {
|
|
59
|
-
const pinExists = hasPIN();
|
|
60
|
-
|
|
61
|
-
if (msg.clear) {
|
|
62
|
-
// Clearing the PIN — must verify current PIN first
|
|
63
|
-
if (pinExists) {
|
|
64
|
-
if (!msg.current_pin || !verifyPIN(msg.current_pin)) {
|
|
65
|
-
ctx.send(socket, {
|
|
66
|
-
type: 'parental_control_set_pin_response',
|
|
67
|
-
success: false,
|
|
68
|
-
error: 'Current PIN is incorrect',
|
|
69
|
-
});
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
clearPIN();
|
|
74
|
-
ctx.send(socket, {
|
|
75
|
-
type: 'parental_control_set_pin_response',
|
|
76
|
-
success: true,
|
|
77
|
-
});
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (!msg.new_pin) {
|
|
82
|
-
ctx.send(socket, {
|
|
83
|
-
type: 'parental_control_set_pin_response',
|
|
84
|
-
success: false,
|
|
85
|
-
error: 'new_pin is required',
|
|
86
|
-
});
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (pinExists) {
|
|
91
|
-
// Changing existing PIN — must verify current PIN first
|
|
92
|
-
if (!msg.current_pin || !verifyPIN(msg.current_pin)) {
|
|
93
|
-
ctx.send(socket, {
|
|
94
|
-
type: 'parental_control_set_pin_response',
|
|
95
|
-
success: false,
|
|
96
|
-
error: 'Current PIN is incorrect',
|
|
97
|
-
});
|
|
98
|
-
return;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
setPIN(msg.new_pin);
|
|
103
|
-
ctx.send(socket, {
|
|
104
|
-
type: 'parental_control_set_pin_response',
|
|
105
|
-
success: true,
|
|
106
|
-
});
|
|
107
|
-
} catch (err) {
|
|
108
|
-
log.error({ err }, 'Failed to set parental control PIN');
|
|
109
|
-
ctx.send(socket, {
|
|
110
|
-
type: 'parental_control_set_pin_response',
|
|
111
|
-
success: false,
|
|
112
|
-
error: err instanceof Error ? err.message : 'Internal error',
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
export function handleParentalControlUpdate(
|
|
118
|
-
msg: ParentalControlUpdateRequest,
|
|
119
|
-
socket: net.Socket,
|
|
120
|
-
ctx: HandlerContext,
|
|
121
|
-
): void {
|
|
122
|
-
const settings = getParentalControlSettings();
|
|
123
|
-
const pinExists = hasPIN();
|
|
124
|
-
|
|
125
|
-
// Require PIN verification when parental mode is already enabled
|
|
126
|
-
if (settings.enabled && pinExists) {
|
|
127
|
-
if (!msg.pin || !verifyPIN(msg.pin)) {
|
|
128
|
-
ctx.send(socket, {
|
|
129
|
-
type: 'parental_control_update_response',
|
|
130
|
-
success: false,
|
|
131
|
-
error: 'PIN required to change parental control settings',
|
|
132
|
-
enabled: settings.enabled,
|
|
133
|
-
has_pin: pinExists,
|
|
134
|
-
content_restrictions: settings.contentRestrictions,
|
|
135
|
-
blocked_tool_categories: settings.blockedToolCategories,
|
|
136
|
-
});
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const updated = updateParentalControlSettings({
|
|
142
|
-
enabled: msg.enabled,
|
|
143
|
-
contentRestrictions: msg.content_restrictions,
|
|
144
|
-
blockedToolCategories: msg.blocked_tool_categories,
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
log.info({ enabled: updated.enabled }, 'Parental control settings updated');
|
|
148
|
-
|
|
149
|
-
ctx.send(socket, {
|
|
150
|
-
type: 'parental_control_update_response',
|
|
151
|
-
success: true,
|
|
152
|
-
enabled: updated.enabled,
|
|
153
|
-
has_pin: hasPIN(),
|
|
154
|
-
content_restrictions: updated.contentRestrictions,
|
|
155
|
-
blocked_tool_categories: updated.blockedToolCategories,
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
export const parentalControlHandlers = defineHandlers({
|
|
160
|
-
parental_control_get: handleParentalControlGet,
|
|
161
|
-
parental_control_verify_pin: handleParentalControlVerifyPin,
|
|
162
|
-
parental_control_set_pin: handleParentalControlSetPin,
|
|
163
|
-
parental_control_update: handleParentalControlUpdate,
|
|
164
|
-
});
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
// Parental control IPC types.
|
|
2
|
-
//
|
|
3
|
-
// The parental control system lets a parent or guardian lock the assistant
|
|
4
|
-
// behind a 6-digit PIN and configure per-topic content restrictions and
|
|
5
|
-
// per-category tool blocks. All mutating operations require the PIN when
|
|
6
|
-
// one has been set.
|
|
7
|
-
|
|
8
|
-
// === Shared data types ===
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Topics that can be individually blocked.
|
|
12
|
-
* All unlisted topics are allowed.
|
|
13
|
-
*/
|
|
14
|
-
export type ParentalContentTopic =
|
|
15
|
-
| 'violence'
|
|
16
|
-
| 'adult_content'
|
|
17
|
-
| 'political'
|
|
18
|
-
| 'gambling'
|
|
19
|
-
| 'drugs';
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Broad tool categories that can be disabled for age-appropriate use.
|
|
23
|
-
* When a category is blocked, individual tool invocations within that
|
|
24
|
-
* category are rejected before the permission pipeline runs.
|
|
25
|
-
*/
|
|
26
|
-
export type ParentalToolCategory =
|
|
27
|
-
| 'computer_use'
|
|
28
|
-
| 'network'
|
|
29
|
-
| 'shell'
|
|
30
|
-
| 'file_write';
|
|
31
|
-
|
|
32
|
-
// === Client → Server ===
|
|
33
|
-
|
|
34
|
-
/** Retrieve the current parental control settings and PIN status. */
|
|
35
|
-
export interface ParentalControlGetRequest {
|
|
36
|
-
type: 'parental_control_get';
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/** Verify a PIN attempt without changing any state. Useful to gate an unlock-settings flow before showing the full panel. */
|
|
40
|
-
export interface ParentalControlVerifyPinRequest {
|
|
41
|
-
type: 'parental_control_verify_pin';
|
|
42
|
-
pin: string;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/** Set, change, or clear the parental control PIN. To set for the first time provide only new_pin. To change provide current_pin and new_pin. To clear provide current_pin and set clear:true. */
|
|
46
|
-
export interface ParentalControlSetPinRequest {
|
|
47
|
-
type: 'parental_control_set_pin';
|
|
48
|
-
current_pin?: string;
|
|
49
|
-
new_pin?: string;
|
|
50
|
-
clear?: boolean;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/** Update parental control settings. Requires the PIN when parental mode is already enabled. */
|
|
54
|
-
export interface ParentalControlUpdateRequest {
|
|
55
|
-
type: 'parental_control_update';
|
|
56
|
-
/** Current PIN — required when parental mode is already enabled. */
|
|
57
|
-
pin?: string;
|
|
58
|
-
/** Enable or disable parental control mode. */
|
|
59
|
-
enabled?: boolean;
|
|
60
|
-
/** Full replacement list of blocked content topics. */
|
|
61
|
-
content_restrictions?: ParentalContentTopic[];
|
|
62
|
-
/** Full replacement list of blocked tool categories. */
|
|
63
|
-
blocked_tool_categories?: ParentalToolCategory[];
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// === Server → Client ===
|
|
67
|
-
|
|
68
|
-
export interface ParentalControlGetResponse {
|
|
69
|
-
type: 'parental_control_get_response';
|
|
70
|
-
enabled: boolean;
|
|
71
|
-
has_pin: boolean;
|
|
72
|
-
content_restrictions: ParentalContentTopic[];
|
|
73
|
-
blocked_tool_categories: ParentalToolCategory[];
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
export interface ParentalControlVerifyPinResponse {
|
|
77
|
-
type: 'parental_control_verify_pin_response';
|
|
78
|
-
verified: boolean;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export interface ParentalControlSetPinResponse {
|
|
82
|
-
type: 'parental_control_set_pin_response';
|
|
83
|
-
success: boolean;
|
|
84
|
-
error?: string;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export interface ParentalControlUpdateResponse {
|
|
88
|
-
type: 'parental_control_update_response';
|
|
89
|
-
success: boolean;
|
|
90
|
-
error?: string;
|
|
91
|
-
enabled: boolean;
|
|
92
|
-
has_pin: boolean;
|
|
93
|
-
content_restrictions: ParentalContentTopic[];
|
|
94
|
-
blocked_tool_categories: ParentalToolCategory[];
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// --- Domain-level union aliases (consumed by the barrel file) ---
|
|
98
|
-
|
|
99
|
-
export type _ParentalControlClientMessages =
|
|
100
|
-
| ParentalControlGetRequest
|
|
101
|
-
| ParentalControlVerifyPinRequest
|
|
102
|
-
| ParentalControlSetPinRequest
|
|
103
|
-
| ParentalControlUpdateRequest;
|
|
104
|
-
|
|
105
|
-
export type _ParentalControlServerMessages =
|
|
106
|
-
| ParentalControlGetResponse
|
|
107
|
-
| ParentalControlVerifyPinResponse
|
|
108
|
-
| ParentalControlSetPinResponse
|
|
109
|
-
| ParentalControlUpdateResponse;
|