Skip to main content

cccc_sdk/
voice.rs

1use serde::{Deserialize, Serialize};
2use serde_json::{json, Map, Value};
3
4use crate::{CCCCClient, Result};
5
6#[derive(Clone, Debug, Deserialize, Serialize)]
7pub struct VoiceDocumentFolder {
8    pub folder_id: String,
9    pub name: String,
10}
11
12/// Stored index, including archived documents but excluding deleted entries.
13#[derive(Clone, Debug, Deserialize, Serialize)]
14pub struct VoiceDocumentLibrary {
15    pub folders: Vec<VoiceDocumentFolder>,
16    pub root_order: Vec<String>,
17    pub documents: Vec<Map<String, Value>>,
18}
19
20/// Library metadata changes never move Markdown files. Restore preserves folders.
21#[derive(Clone, Debug, Serialize)]
22#[serde(tag = "action", rename_all = "snake_case")]
23pub enum VoiceDocumentLibraryAction {
24    CreateFolder {
25        name: String,
26    },
27    RenameFolder {
28        folder_id: String,
29        name: String,
30    },
31    RemoveFolder {
32        folder_id: String,
33    },
34    /// Mixed folder:<id> / document:<path> keys; an empty list clears ordering.
35    ReorderRoot {
36        root_order: Vec<String>,
37    },
38    Rename {
39        document_path: String,
40        name: String,
41    },
42    /// An empty folder_id moves the document to root.
43    Move {
44        document_path: String,
45        folder_id: String,
46    },
47    Restore {
48        document_path: String,
49    },
50}
51
52impl CCCCClient {
53    /// Read the stored library without workspace discovery or content reconciliation.
54    pub fn assistant_voice_document_library(&self, group_id: &str) -> Result<VoiceDocumentLibrary> {
55        let result = self.call(
56            "assistant_voice_document_library",
57            Map::from_iter([("group_id".into(), json!(group_id))]),
58        )?;
59        Ok(serde_json::from_value(Value::Object(result))?)
60    }
61
62    /// The daemon enforces writer permission; omitted `by` means the local user.
63    pub fn assistant_voice_document_library_update(
64        &self,
65        group_id: &str,
66        action: &VoiceDocumentLibraryAction,
67        by: Option<&str>,
68    ) -> Result<VoiceDocumentLibrary> {
69        let mut args: Map<String, Value> = serde_json::from_value(serde_json::to_value(action)?)?;
70        args.insert("group_id".into(), json!(group_id));
71        args.insert("by".into(), json!(by.unwrap_or("user")));
72        let result = self.call("assistant_voice_document_library_update", args)?;
73        Ok(serde_json::from_value(Value::Object(result))?)
74    }
75
76    /// Permanently delete the Markdown file. Archive instead to retain the file.
77    pub fn assistant_voice_document_delete(
78        &self,
79        group_id: &str,
80        document_path: &str,
81        by: Option<&str>,
82    ) -> Result<Map<String, Value>> {
83        self.call(
84            "assistant_voice_document_delete",
85            Map::from_iter([
86                ("group_id".into(), json!(group_id)),
87                ("document_path".into(), json!(document_path)),
88                ("by".into(), json!(by.unwrap_or("user"))),
89            ]),
90        )
91    }
92}