Add permission modes and container introspection backend
Permission modes: replaces the binary full_permissions flag with a PermissionMode enum (Plan/Default/AcceptEdits/Bypass). Flag mapping is defined once in PermissionMode::cli_args() and used by the terminal, the web terminal, and the scheduler: Plan -> --permission-mode plan Default -> (no flag) AcceptEdits -> --permission-mode acceptEdits Bypass -> --dangerously-skip-permissions Choices verified against `claude --permission-mode` on 2.1.226. full_permissions is retained and effective_permission_mode() falls back to it, so existing projects.json needs no migration. Bug fix: triple-c-task-runner ran `claude -p ... --dangerously-skip- permissions` unconditionally, ignoring the project's setting entirely. It now reads TRIPLE_C_PERMISSION_MODE, which is injected into the container, added to the reserved env blocklist, propagated through the entrypoint's cron env filter, and tracked by a new triple-c.permission-mode label so a change forces recreation. Introspection: new commands/inspect_commands.rs exposes read-only views into the container over docker exec — Claude sessions (parsed from ~/.claude/projects/<cwd>/<uuid>.jsonl), installed capabilities (skills, agents, commands, hooks, plugins, natively-configured MCP servers), and the triple-c-scheduler task list, logs and notifications. Task/session ids are validated against a strict allowlist and every parameterized call runs as a bare argv vector via bollard, so no shell is involved. Stopped containers return empty results rather than errors. No UI yet; that lands with the Project Home view. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import type { Project, ProjectPath, ContainerInfo, SiblingContainer, AppSettings, UpdateInfo, ImageUpdateInfo, FileEntry, WebTerminalInfo, SttStatus, InstallOptions } from "./types";
|
||||
import type { Project, ProjectPath, ContainerInfo, SiblingContainer, AppSettings, UpdateInfo, ImageUpdateInfo, FileEntry, WebTerminalInfo, SttStatus, InstallOptions, ClaudeSession, ContainerCapabilities, ScheduledTask, SchedulerNotification } from "./types";
|
||||
|
||||
// Docker
|
||||
export const checkDocker = () => invoke<boolean>("check_docker");
|
||||
@@ -107,3 +107,29 @@ export const transcribeAudio = (audioData: number[]) =>
|
||||
export const detectInstallOptions = () =>
|
||||
invoke<InstallOptions>("detect_install_options");
|
||||
export const runDockerInstall = () => invoke<void>("run_docker_install");
|
||||
|
||||
// Container introspection — sessions
|
||||
export const listClaudeSessions = (projectId: string) =>
|
||||
invoke<ClaudeSession[]>("list_claude_sessions", { projectId });
|
||||
export const resumeSessionCommand = (projectId: string, sessionId: string) =>
|
||||
invoke<string>("resume_session_command", { projectId, sessionId });
|
||||
|
||||
// Container introspection — capabilities
|
||||
export const listContainerCapabilities = (projectId: string) =>
|
||||
invoke<ContainerCapabilities>("list_container_capabilities", { projectId });
|
||||
|
||||
// Container introspection — scheduler
|
||||
export const listScheduledTasks = (projectId: string) =>
|
||||
invoke<ScheduledTask[]>("list_scheduled_tasks", { projectId });
|
||||
export const getScheduledTaskLog = (projectId: string, taskId: string, tailLines?: number) =>
|
||||
invoke<string>("get_scheduled_task_log", { projectId, taskId, tailLines });
|
||||
export const setScheduledTaskEnabled = (projectId: string, taskId: string, enabled: boolean) =>
|
||||
invoke<string>("set_scheduled_task_enabled", { projectId, taskId, enabled });
|
||||
export const runScheduledTaskNow = (projectId: string, taskId: string) =>
|
||||
invoke<string>("run_scheduled_task_now", { projectId, taskId });
|
||||
export const removeScheduledTask = (projectId: string, taskId: string) =>
|
||||
invoke<string>("remove_scheduled_task", { projectId, taskId });
|
||||
export const getSchedulerNotifications = (projectId: string) =>
|
||||
invoke<SchedulerNotification[]>("get_scheduler_notifications", { projectId });
|
||||
export const clearSchedulerNotifications = (projectId: string) =>
|
||||
invoke<void>("clear_scheduler_notifications", { projectId });
|
||||
|
||||
@@ -27,7 +27,11 @@ export interface Project {
|
||||
allow_docker_access: boolean;
|
||||
sandbox_mode_enabled: boolean;
|
||||
mission_control_enabled: boolean;
|
||||
/** Legacy binary permission flag; superseded by `permission_mode`, kept for
|
||||
* existing projects.json data. */
|
||||
full_permissions: boolean;
|
||||
/** null = not set → falls back to `full_permissions` (true → "bypass"). */
|
||||
permission_mode: PermissionMode | null;
|
||||
ssh_key_path: string | null;
|
||||
git_token: string | null;
|
||||
git_user_name: string | null;
|
||||
@@ -50,6 +54,9 @@ export type ProjectStatus =
|
||||
|
||||
export type Backend = "anthropic" | "bedrock" | "ollama" | "open_ai_compatible";
|
||||
|
||||
/** Mirrors Rust `PermissionMode` (serde camelCase). */
|
||||
export type PermissionMode = "plan" | "default" | "acceptEdits" | "bypass";
|
||||
|
||||
export type BedrockAuthMethod = "static_credentials" | "profile" | "bearer_token";
|
||||
|
||||
export interface BedrockConfig {
|
||||
@@ -220,3 +227,69 @@ export interface InstallOptions {
|
||||
manual_steps: string[];
|
||||
post_install_notes: string[];
|
||||
}
|
||||
|
||||
// Container introspection (read-only) — see src-tauri/src/commands/inspect_commands.rs
|
||||
|
||||
/** A Claude Code session transcript stored on the container's config volume. */
|
||||
export interface ClaudeSession {
|
||||
id: string;
|
||||
/** User-set display name (`claude -n <name>`), if any. */
|
||||
name: string | null;
|
||||
/** Claude's auto-generated title, else the session's last prompt. */
|
||||
summary: string | null;
|
||||
last_modified: string;
|
||||
size_bytes: number;
|
||||
message_count: number;
|
||||
cwd: string | null;
|
||||
}
|
||||
|
||||
export type CapabilityScope = "user" | "project";
|
||||
|
||||
export interface CapabilityItem {
|
||||
name: string;
|
||||
description: string | null;
|
||||
scope: CapabilityScope;
|
||||
}
|
||||
|
||||
export interface CapabilityGroup {
|
||||
count: number;
|
||||
items: CapabilityItem[];
|
||||
}
|
||||
|
||||
export interface ContainerCapabilities {
|
||||
skills: CapabilityGroup;
|
||||
agents: CapabilityGroup;
|
||||
commands: CapabilityGroup;
|
||||
/** One item per hook event; `count` totals the individual handlers. */
|
||||
hooks: CapabilityGroup;
|
||||
plugins: CapabilityGroup;
|
||||
mcp_servers: CapabilityGroup;
|
||||
}
|
||||
|
||||
export interface ScheduledTask {
|
||||
id: string;
|
||||
name: string;
|
||||
prompt: string;
|
||||
/** Cron expression (one-shot tasks are stored as cron too — see `at`). */
|
||||
schedule: string;
|
||||
task_type: "recurring" | "once";
|
||||
/** Original `--at` value (`"YYYY-MM-DD HH:MM"`) for one-shot tasks. */
|
||||
at: string | null;
|
||||
enabled: boolean;
|
||||
working_dir: string;
|
||||
created_at: string | null;
|
||||
last_run: string | null;
|
||||
/** Known only for enabled one-shot tasks; cron is not evaluated. */
|
||||
next_run: string | null;
|
||||
}
|
||||
|
||||
export interface SchedulerNotification {
|
||||
task_id: string;
|
||||
task_name: string | null;
|
||||
status: string | null;
|
||||
time: string | null;
|
||||
task_type: string | null;
|
||||
summary: string | null;
|
||||
body: string;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user