create-keel-and-deck-app 0.1.0
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/index.js +76 -0
- package/package.json +23 -0
- package/template/index.html +12 -0
- package/template/package.json +41 -0
- package/template/src/App.tsx +193 -0
- package/template/src/hooks/use-session-events.ts +36 -0
- package/template/src/lib/tauri.ts +68 -0
- package/template/src/lib/types.ts +111 -0
- package/template/src/main.tsx +10 -0
- package/template/src/stores/agents.ts +65 -0
- package/template/src/stores/events.ts +27 -0
- package/template/src/stores/feeds.ts +34 -0
- package/template/src/stores/issues.ts +35 -0
- package/template/src/stores/memory.ts +30 -0
- package/template/src/stores/ui.ts +17 -0
- package/template/src/styles/globals.css +24 -0
- package/template/src-tauri/Cargo.toml +28 -0
- package/template/src-tauri/build.rs +3 -0
- package/template/src-tauri/capabilities/default.json +12 -0
- package/template/src-tauri/icons/.gitkeep +0 -0
- package/template/src-tauri/src/commands/channels.rs +119 -0
- package/template/src-tauri/src/commands/events.rs +43 -0
- package/template/src-tauri/src/commands/issues.rs +29 -0
- package/template/src-tauri/src/commands/memory.rs +52 -0
- package/template/src-tauri/src/commands/mod.rs +8 -0
- package/template/src-tauri/src/commands/projects.rs +38 -0
- package/template/src-tauri/src/commands/scheduler.rs +67 -0
- package/template/src-tauri/src/commands/sessions.rs +80 -0
- package/template/src-tauri/src/commands/workspace.rs +62 -0
- package/template/src-tauri/src/lib.rs +93 -0
- package/template/src-tauri/src/main.rs +6 -0
- package/template/src-tauri/src/workspace.rs +21 -0
- package/template/src-tauri/tauri.conf.json +30 -0
- package/template/tsconfig.json +21 -0
- package/template/vite.config.ts +17 -0
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
use keel_tauri::paths::expand_tilde;
|
|
2
|
+
use keel_tauri::state::AppState;
|
|
3
|
+
use serde::Serialize;
|
|
4
|
+
use tauri::State;
|
|
5
|
+
|
|
6
|
+
const KNOWN_FILES: &[(&str, &str)] = &[
|
|
7
|
+
("CLAUDE.md", "Agent instructions and behavior rules"),
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
#[derive(Serialize)]
|
|
11
|
+
pub struct WorkspaceFileInfo {
|
|
12
|
+
name: String,
|
|
13
|
+
description: String,
|
|
14
|
+
exists: bool,
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
#[tauri::command]
|
|
18
|
+
pub async fn list_workspace_files(
|
|
19
|
+
state: State<'_, AppState>,
|
|
20
|
+
project_id: String,
|
|
21
|
+
) -> Result<Vec<WorkspaceFileInfo>, String> {
|
|
22
|
+
let project = state
|
|
23
|
+
.db
|
|
24
|
+
.get_project(&project_id)
|
|
25
|
+
.await
|
|
26
|
+
.map_err(|e| e.to_string())?
|
|
27
|
+
.ok_or_else(|| "Project not found".to_string())?;
|
|
28
|
+
|
|
29
|
+
let dir = expand_tilde(&project.folder_path);
|
|
30
|
+
let files = KNOWN_FILES
|
|
31
|
+
.iter()
|
|
32
|
+
.map(|(name, desc)| WorkspaceFileInfo {
|
|
33
|
+
name: name.to_string(),
|
|
34
|
+
description: desc.to_string(),
|
|
35
|
+
exists: dir.join(name).exists(),
|
|
36
|
+
})
|
|
37
|
+
.collect();
|
|
38
|
+
|
|
39
|
+
Ok(files)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
#[tauri::command]
|
|
43
|
+
pub async fn read_workspace_file(
|
|
44
|
+
state: State<'_, AppState>,
|
|
45
|
+
project_id: String,
|
|
46
|
+
file_name: String,
|
|
47
|
+
) -> Result<String, String> {
|
|
48
|
+
let project = state
|
|
49
|
+
.db
|
|
50
|
+
.get_project(&project_id)
|
|
51
|
+
.await
|
|
52
|
+
.map_err(|e| e.to_string())?
|
|
53
|
+
.ok_or_else(|| "Project not found".to_string())?;
|
|
54
|
+
|
|
55
|
+
// Only allow reading known files
|
|
56
|
+
if !KNOWN_FILES.iter().any(|(name, _)| *name == file_name) {
|
|
57
|
+
return Err(format!("Unknown workspace file: {file_name}"));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
let path = expand_tilde(&project.folder_path).join(&file_name);
|
|
61
|
+
std::fs::read_to_string(&path).map_err(|e| format!("Failed to read {file_name}: {e}"))
|
|
62
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
mod commands;
|
|
2
|
+
mod workspace;
|
|
3
|
+
|
|
4
|
+
use keel_tauri::chat_session::ChatSessionState;
|
|
5
|
+
use keel_tauri::keel_db::Database;
|
|
6
|
+
use keel_tauri::keel_events::EventQueue;
|
|
7
|
+
use keel_tauri::keel_memory::MemoryStore;
|
|
8
|
+
use keel_tauri::keel_scheduler::Scheduler;
|
|
9
|
+
use keel_tauri::state::AppState;
|
|
10
|
+
use std::sync::Arc;
|
|
11
|
+
use tokio::sync::Mutex;
|
|
12
|
+
|
|
13
|
+
pub fn run() {
|
|
14
|
+
tauri::Builder::default()
|
|
15
|
+
.setup(|app| {
|
|
16
|
+
let data_dir = keel_tauri::keel_db::db::default_data_dir("{{APP_NAME_SNAKE}}");
|
|
17
|
+
let db_path = data_dir.join("{{APP_NAME_SNAKE}}.db");
|
|
18
|
+
|
|
19
|
+
let db = tauri::async_runtime::block_on(async {
|
|
20
|
+
Database::connect(&db_path)
|
|
21
|
+
.await
|
|
22
|
+
.expect("Failed to open database")
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// Initialize memory store with its own connection to the same DB.
|
|
26
|
+
let memory_dir = data_dir.join("memories");
|
|
27
|
+
let memory_store = tauri::async_runtime::block_on(async {
|
|
28
|
+
let mem_db = libsql::Builder::new_local(&db_path)
|
|
29
|
+
.build()
|
|
30
|
+
.await
|
|
31
|
+
.expect("Failed to open memory DB connection");
|
|
32
|
+
let mem_conn = Arc::new(
|
|
33
|
+
mem_db.connect().expect("Failed to connect for memory store"),
|
|
34
|
+
);
|
|
35
|
+
MemoryStore::new_with_markdown_dir(mem_conn, memory_dir)
|
|
36
|
+
.await
|
|
37
|
+
.expect("Failed to initialize memory store")
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Initialize event queue.
|
|
41
|
+
let (_event_queue, queue_handle) = EventQueue::new();
|
|
42
|
+
|
|
43
|
+
// Initialize scheduler with queue handle.
|
|
44
|
+
let scheduler = Scheduler::new(queue_handle.clone());
|
|
45
|
+
|
|
46
|
+
// Chat session state for --resume support.
|
|
47
|
+
let chat_session = ChatSessionState::default();
|
|
48
|
+
|
|
49
|
+
app.manage(AppState {
|
|
50
|
+
db,
|
|
51
|
+
event_queue: Some(queue_handle),
|
|
52
|
+
scheduler: Some(Arc::new(Mutex::new(scheduler))),
|
|
53
|
+
});
|
|
54
|
+
app.manage(memory_store);
|
|
55
|
+
app.manage(chat_session);
|
|
56
|
+
|
|
57
|
+
Ok(())
|
|
58
|
+
})
|
|
59
|
+
.invoke_handler(tauri::generate_handler![
|
|
60
|
+
// Projects (agents)
|
|
61
|
+
commands::projects::list_projects,
|
|
62
|
+
commands::projects::create_project,
|
|
63
|
+
// Issues
|
|
64
|
+
commands::issues::list_issues,
|
|
65
|
+
commands::issues::create_issue,
|
|
66
|
+
// Sessions
|
|
67
|
+
commands::sessions::start_session,
|
|
68
|
+
commands::sessions::load_chat_feed,
|
|
69
|
+
// Workspace
|
|
70
|
+
commands::workspace::list_workspace_files,
|
|
71
|
+
commands::workspace::read_workspace_file,
|
|
72
|
+
// Memory
|
|
73
|
+
commands::memory::list_memories,
|
|
74
|
+
commands::memory::create_memory,
|
|
75
|
+
commands::memory::delete_memory,
|
|
76
|
+
commands::memory::search_memories,
|
|
77
|
+
// Events
|
|
78
|
+
commands::events::list_events,
|
|
79
|
+
// Scheduler
|
|
80
|
+
commands::scheduler::add_heartbeat,
|
|
81
|
+
commands::scheduler::remove_heartbeat,
|
|
82
|
+
commands::scheduler::add_cron,
|
|
83
|
+
commands::scheduler::remove_cron,
|
|
84
|
+
// Channels
|
|
85
|
+
commands::channels::list_channels,
|
|
86
|
+
commands::channels::add_channel,
|
|
87
|
+
commands::channels::remove_channel,
|
|
88
|
+
commands::channels::connect_channel,
|
|
89
|
+
commands::channels::disconnect_channel,
|
|
90
|
+
])
|
|
91
|
+
.run(tauri::generate_context!())
|
|
92
|
+
.expect("error while running tauri application");
|
|
93
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
use keel_tauri::paths::expand_tilde;
|
|
2
|
+
use keel_tauri::workspace::seed_file;
|
|
3
|
+
|
|
4
|
+
const CLAUDE_MD_TEMPLATE: &str = r#"# {{APP_NAME_TITLE}} Agent
|
|
5
|
+
|
|
6
|
+
## Role
|
|
7
|
+
You are a helpful AI assistant.
|
|
8
|
+
|
|
9
|
+
## Rules
|
|
10
|
+
- Be concise and direct
|
|
11
|
+
- Ask before making destructive changes
|
|
12
|
+
- Explain your reasoning when making decisions
|
|
13
|
+
"#;
|
|
14
|
+
|
|
15
|
+
/// Seed workspace files for a new agent. Creates the folder and writes
|
|
16
|
+
/// CLAUDE.md if it doesn't already exist.
|
|
17
|
+
pub fn seed_workspace(folder_path: &str) {
|
|
18
|
+
let dir = expand_tilde(folder_path);
|
|
19
|
+
std::fs::create_dir_all(&dir).ok();
|
|
20
|
+
seed_file(&dir, "CLAUDE.md", CLAUDE_MD_TEMPLATE);
|
|
21
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://raw.githubusercontent.com/nickelpack/tauri/v2/crates/tauri-config-schema/schema.json",
|
|
3
|
+
"productName": "{{APP_NAME_TITLE}}",
|
|
4
|
+
"identifier": "com.{{APP_NAME_SNAKE}}.app",
|
|
5
|
+
"build": {
|
|
6
|
+
"frontendDist": "../dist",
|
|
7
|
+
"devUrl": "http://localhost:1420",
|
|
8
|
+
"beforeDevCommand": "pnpm dev",
|
|
9
|
+
"beforeBuildCommand": "pnpm build"
|
|
10
|
+
},
|
|
11
|
+
"app": {
|
|
12
|
+
"withGlobalTauri": false,
|
|
13
|
+
"windows": [
|
|
14
|
+
{
|
|
15
|
+
"title": "{{APP_NAME_TITLE}}",
|
|
16
|
+
"width": 1200,
|
|
17
|
+
"height": 800,
|
|
18
|
+
"minWidth": 800,
|
|
19
|
+
"minHeight": 600,
|
|
20
|
+
"decorations": true,
|
|
21
|
+
"transparent": false,
|
|
22
|
+
"titleBarStyle": "Overlay"
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"security": {
|
|
26
|
+
"csp": null,
|
|
27
|
+
"capabilities": ["default"]
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2021",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"lib": ["ES2021", "DOM", "DOM.Iterable"],
|
|
6
|
+
"module": "ESNext",
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"moduleResolution": "bundler",
|
|
9
|
+
"allowImportingTsExtensions": true,
|
|
10
|
+
"isolatedModules": true,
|
|
11
|
+
"moduleDetection": "force",
|
|
12
|
+
"noEmit": true,
|
|
13
|
+
"jsx": "react-jsx",
|
|
14
|
+
"strict": true,
|
|
15
|
+
"noUnusedLocals": true,
|
|
16
|
+
"noUnusedParameters": true,
|
|
17
|
+
"noFallthroughCasesInSwitch": true,
|
|
18
|
+
"noUncheckedSideEffectImports": true
|
|
19
|
+
},
|
|
20
|
+
"include": ["src"]
|
|
21
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { defineConfig } from "vite";
|
|
2
|
+
import react from "@vitejs/plugin-react";
|
|
3
|
+
import tailwindcss from "@tailwindcss/vite";
|
|
4
|
+
|
|
5
|
+
const host = process.env.TAURI_DEV_HOST;
|
|
6
|
+
|
|
7
|
+
export default defineConfig({
|
|
8
|
+
plugins: [react(), tailwindcss()],
|
|
9
|
+
clearScreen: false,
|
|
10
|
+
server: {
|
|
11
|
+
port: 1420,
|
|
12
|
+
strictPort: true,
|
|
13
|
+
host: host || false,
|
|
14
|
+
hmr: host ? { protocol: "ws", host, port: 1421 } : undefined,
|
|
15
|
+
watch: { ignored: ["**/src-tauri/**"] },
|
|
16
|
+
},
|
|
17
|
+
});
|