- server/policy_overrides.mjs: persistent group/action override store - Group toggle: disabling a group forces all its actions to auto-deny without touching individual overrides; re-enabling restores them intact - Action overrides: cycle auto-accept/queue/auto-deny/clear per action - Effective policy resolution in index.mjs: group > action override > hardcoded default - auth.mjs: add check_can_manage_policies (requires canApprove.length > 0) - Three new endpoints: GET /policies, POST /policies/group/:group, POST /policies/action/:action - client/conduit.mjs: get_policies, set_group_policy, set_action_policy - ccc-queue.mjs: policy view (Tab to switch); group/action panel with space/e/←/→ - actions.mjs: group fields on desktop/email/calendar actions; list-actions includes group - config.example.json: add policy_overrides key - Bump version to 1.3.0 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
72 lines
2.2 KiB
JavaScript
72 lines
2.2 KiB
JavaScript
// Conduit client module — import this when using conduit programmatically.
|
|
// Usage: const client = create_conduit_client("agent", secret); await client.call_action("list-actions");
|
|
|
|
import { sign_request } from "./auth.mjs";
|
|
|
|
const DEFAULT_URL = 'http://localhost:3015';
|
|
|
|
export function create_conduit_client(username, secret, base_url = process.env.CONDUIT_URL || DEFAULT_URL) {
|
|
function auth_headers(body_string) {
|
|
return sign_request(secret, username, body_string);
|
|
}
|
|
|
|
async function call_action(action, params = {}) {
|
|
const body_string = JSON.stringify({ action, ...params });
|
|
const res = await fetch(`${base_url}/action`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json", ...auth_headers(body_string) },
|
|
body: body_string,
|
|
});
|
|
return res.json();
|
|
}
|
|
|
|
async function list_actions() {
|
|
return call_action("list-actions");
|
|
}
|
|
|
|
async function get_queue() {
|
|
const res = await fetch(`${base_url}/queue`, {
|
|
headers: auth_headers(''),
|
|
});
|
|
return res.json();
|
|
}
|
|
|
|
async function resolve_queue_item(id, decision) {
|
|
const res = await fetch(`${base_url}/queue/${id}/${decision}`, {
|
|
method: 'POST',
|
|
headers: auth_headers(''),
|
|
});
|
|
return res.json();
|
|
}
|
|
|
|
async function get_policies() {
|
|
const res = await fetch(`${base_url}/policies`, {
|
|
headers: auth_headers(''),
|
|
});
|
|
return res.json();
|
|
}
|
|
|
|
async function set_group_policy(group, disabled) {
|
|
const body_string = JSON.stringify({ disabled });
|
|
const res = await fetch(`${base_url}/policies/group/${encodeURIComponent(group)}`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json', ...auth_headers(body_string) },
|
|
body: body_string,
|
|
});
|
|
return res.json();
|
|
}
|
|
|
|
// policy = null clears the override
|
|
async function set_action_policy(action, policy) {
|
|
const body_string = JSON.stringify({ policy });
|
|
const res = await fetch(`${base_url}/policies/action/${encodeURIComponent(action)}`, {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json', ...auth_headers(body_string) },
|
|
body: body_string,
|
|
});
|
|
return res.json();
|
|
}
|
|
|
|
return { call_action, list_actions, get_queue, resolve_queue_item, get_policies, set_group_policy, set_action_policy };
|
|
}
|