New modules:
- server/mailer.mjs: nodemailer transport wrapper
- server/mail_perms.mjs: runtime permission store, persisted to disk
New actions:
- send-email: checks (caller, to, topic) permission before sending
- set-mail-permission: grant/revoke permissions, gated by canApprove
- get-mail-permissions: list current permissions
Handler signature extended to handler(params, ctx) where ctx carries
caller, users, mail_perm_store and mailer_send. Existing handlers
ignore ctx so the change is backwards-compatible.
SMTP config lives in secrets.json under optional 'smtp' key.
Mail permissions path via --mail-perms or CONDUIT_MAIL_PERMS.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each request logs timestamp, method, path and user. Queue entries log
a single line on enqueue and on resolve. Drop the verbose approve/deny
curl instructions from queue output.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Overrides CONDUIT_URL env var. Resolved through load_client_config and
threaded into create_conduit_client as base_url parameter.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Move resolve_queue_item into conduit.mjs factory and have ccc-queue
import from there instead of index.mjs, which auto-executes main().
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
--create <names> generates secrets.json with random 32-byte hex secrets
--filter <names> extracts a subset of users into filtered-secrets.json
--input/--output override default file paths
Removes hardcoded user/agent assumptions from secrets.example.json.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- bin/ccc-server, ccc-client, ccc-queue wired up via package.json bin
- client/config.mjs: shared secrets/user resolution from CLI args or
CCC_SECRETS/CCC_USER env vars
- ccc-queue: blessed TUI with two-pane layout (list + detail), polls
every 2s, y/n to approve/deny selected item, r to refresh, q to quit
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Remaining args after --secrets/--user are space-joined and parsed as
JSON, so the full action payload is expressed directly rather than
through a custom key=value scheme.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
spawnSync was blocking the event loop until the subprocess exited, so
opening a browser would freeze the server until it closed. Replace with
spawn + unref (detached, stdio ignored) and remove the now-pointless
awaits and async keywords from action handlers.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Parse the URL and reject anything that isn't http/https before passing
to xdg-open, blocking file://, javascript:// and other schemes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Maps container paths to host paths using the docker-compose volume layout
(/workspace -> CONDUIT_HOST_WORKSPACE, /home/claude -> CONDUIT_HOST_HOME).
Relative paths resolve against CONTAINER_PATH. Paths outside all known
volumes throw rather than silently pass through.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Each request is signed with HMAC-SHA256 over timestamp+body using a
per-user secret loaded from a --secrets file (never env vars or git).
Users have a canApprove list controlling who may approve queued actions.
Queue entries track submitted_by for permission checks on approve/deny.
Also renames all identifiers to snake_case throughout the codebase.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Move resolvePath and exec out of index.mjs into server/helpers.mjs so
actions can import them directly rather than receiving them as arguments.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Supervised action bridge between Claude Code and the host system.
Server accepts structured action requests, applies per-action policies
(auto-accept/auto-deny/queue), and executes approved actions via typed
handlers. Client provides CLI and module interfaces for calling the API.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>